mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 17:36:47 +00:00
zebra: multiple vlan aware bridge data structure and related changes
Multiple vlan aware bridge data structure changes and its corresponding bridge handling changes. A new vlan-table is maintained for each bridge which records the zebra_l2_bridge_vlan entry. zebra_l2_bridge_vlan maps vlan to access_bd associated to this bridge. Existing zebra_evpn_access_bd structure is vlan aware which is now modified to be (vlan, bridge) aware. Whenever a new access_bd is instantiated, a corresponding entry is also recorded in the zebra l2 bridge for the vlan. When the access_bd is dereferenced or whenever a bridge is deleted, the association is cleaned up. Signed-off-by: Sharath Ramamurthy <sramamurthy@nvidia.com>
This commit is contained in:
parent
131a9a2eed
commit
239b26f932
@ -66,6 +66,7 @@ zebra_zebra_SOURCES = \
|
||||
zebra/zebra_errors.c \
|
||||
zebra/zebra_gr.c \
|
||||
zebra/zebra_l2.c \
|
||||
zebra/zebra_l2_bridge_if.c \
|
||||
zebra/zebra_evpn.c \
|
||||
zebra/zebra_evpn_mac.c \
|
||||
zebra/zebra_evpn_neigh.c \
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "zebra/if_netlink.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
#include "zebra/zebra_l2.h"
|
||||
#include "zebra/zebra_l2_bridge_if.h"
|
||||
#include "zebra/zebra_ns.h"
|
||||
#include "zebra/zebra_vrf.h"
|
||||
#include "zebra/zebra_vxlan.h"
|
||||
@ -522,7 +523,7 @@ static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p)
|
||||
{
|
||||
const struct zebra_evpn_access_bd *acc_bd = p;
|
||||
|
||||
return jhash_1word(acc_bd->vid, 0);
|
||||
return jhash_2words(acc_bd->vid, acc_bd->bridge_ifindex, 0);
|
||||
}
|
||||
|
||||
/* Compare two VLAN based broadcast domains */
|
||||
@ -537,16 +538,19 @@ static bool zebra_evpn_acc_vl_cmp(const void *p1, const void *p2)
|
||||
if (acc_bd1 == NULL || acc_bd2 == NULL)
|
||||
return false;
|
||||
|
||||
return (acc_bd1->vid == acc_bd2->vid);
|
||||
return ((acc_bd1->vid == acc_bd2->vid)
|
||||
&& (acc_bd1->bridge_ifindex == acc_bd2->bridge_ifindex));
|
||||
}
|
||||
|
||||
/* Lookup VLAN based broadcast domain */
|
||||
static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid)
|
||||
struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid,
|
||||
struct interface *br_if)
|
||||
{
|
||||
struct zebra_evpn_access_bd *acc_bd;
|
||||
struct zebra_evpn_access_bd tmp;
|
||||
|
||||
tmp.vid = vid;
|
||||
tmp.bridge_ifindex = br_if->ifindex;
|
||||
acc_bd = hash_lookup(zmh_info->evpn_vlan_table, &tmp);
|
||||
|
||||
return acc_bd;
|
||||
@ -562,11 +566,13 @@ zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if)
|
||||
struct interface *vlan_if;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("access vlan %d add", vid);
|
||||
zlog_debug("access vlan %d bridge %s add", vid, br_if->name);
|
||||
|
||||
acc_bd = XCALLOC(MTYPE_ZACC_BD, sizeof(struct zebra_evpn_access_bd));
|
||||
|
||||
acc_bd->vid = vid;
|
||||
acc_bd->bridge_ifindex = br_if->ifindex;
|
||||
acc_bd->bridge_zif = (struct zebra_if *)br_if->info;
|
||||
|
||||
/* Initialize the mbr list */
|
||||
acc_bd->mbr_zifs = list_new();
|
||||
@ -575,14 +581,12 @@ zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if)
|
||||
(void)hash_get(zmh_info->evpn_vlan_table, acc_bd, hash_alloc_intern);
|
||||
|
||||
/* check if an svi exists for the vlan */
|
||||
if (br_if) {
|
||||
vlan_if = zvni_map_to_svi(vid, br_if);
|
||||
if (vlan_if) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("vlan %d SVI %s set", vid,
|
||||
vlan_if->name);
|
||||
acc_bd->vlan_zif = vlan_if->info;
|
||||
}
|
||||
vlan_if = zvni_map_to_svi(vid, br_if);
|
||||
if (vlan_if) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("vlan %d bridge %s SVI %s set", vid,
|
||||
br_if->name, vlan_if->name);
|
||||
acc_bd->vlan_zif = vlan_if->info;
|
||||
}
|
||||
return acc_bd;
|
||||
}
|
||||
@ -623,10 +627,27 @@ static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd)
|
||||
if (!list_isempty(acc_bd->mbr_zifs) || acc_bd->vxlan_zif)
|
||||
return;
|
||||
|
||||
/* Remove this access_bd from bridge hash table */
|
||||
zebra_l2_bridge_if_vlan_access_bd_deref(acc_bd);
|
||||
|
||||
/* if there are no references free the EVI */
|
||||
zebra_evpn_acc_vl_free(acc_bd);
|
||||
}
|
||||
|
||||
static struct zebra_evpn_access_bd *
|
||||
zebra_evpn_acc_bd_alloc_on_ref(vlanid_t vid, struct interface *br_if)
|
||||
{
|
||||
struct zebra_evpn_access_bd *acc_bd = NULL;
|
||||
|
||||
assert(br_if && br_if->info);
|
||||
acc_bd = zebra_evpn_acc_vl_new(vid, br_if);
|
||||
if (acc_bd)
|
||||
/* Add this access_bd to bridge hash table */
|
||||
zebra_l2_bridge_if_vlan_access_bd_ref(acc_bd);
|
||||
|
||||
return acc_bd;
|
||||
}
|
||||
|
||||
/* called when a SVI is goes up/down */
|
||||
void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
|
||||
struct zebra_if *br_zif, bool is_up)
|
||||
@ -647,14 +668,14 @@ void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
|
||||
return;
|
||||
|
||||
vid = vlan_zif->l2info.vl.vid;
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid);
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid, tmp_br_zif->ifp);
|
||||
if (!acc_bd)
|
||||
return;
|
||||
|
||||
if (is_up) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("vlan %d SVI %s set", vid,
|
||||
vlan_zif->ifp->name);
|
||||
zlog_debug("vlan %d bridge %s SVI %s set", vid,
|
||||
tmp_br_zif->ifp->name, vlan_zif->ifp->name);
|
||||
|
||||
acc_bd->vlan_zif = vlan_zif;
|
||||
if (acc_bd->zevpn)
|
||||
@ -662,7 +683,8 @@ void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
|
||||
acc_bd->zevpn);
|
||||
} else if (acc_bd->vlan_zif) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("vlan %d SVI clear", vid);
|
||||
zlog_debug("vlan %d bridge %s SVI clear", vid,
|
||||
tmp_br_zif->ifp->name);
|
||||
acc_bd->vlan_zif = NULL;
|
||||
if (acc_bd->zevpn && acc_bd->zevpn->mac_table)
|
||||
zebra_evpn_mac_svi_del(vlan_zif->ifp, acc_bd->zevpn);
|
||||
@ -687,8 +709,9 @@ static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
|
||||
struct listnode *node;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("access vlan %d l2-vni %u set",
|
||||
acc_bd->vid, zevpn ? zevpn->vni : 0);
|
||||
zlog_debug("access vlan %d bridge %s l2-vni %u set",
|
||||
acc_bd->vid, acc_bd->bridge_zif->ifp->name,
|
||||
zevpn ? zevpn->vni : 0);
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
|
||||
if (!zif->es_info.es)
|
||||
@ -717,6 +740,7 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id,
|
||||
vni_t old_vni;
|
||||
struct zebra_evpn_access_bd *acc_bd;
|
||||
struct zebra_evpn *old_zevpn;
|
||||
struct interface *br_if;
|
||||
|
||||
if (!vid)
|
||||
return;
|
||||
@ -724,10 +748,14 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id,
|
||||
if (!vni_id)
|
||||
return;
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid);
|
||||
br_if = vxlan_zif->brslave_info.br_if;
|
||||
|
||||
if (!br_if)
|
||||
return;
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
|
||||
if (!acc_bd)
|
||||
acc_bd = zebra_evpn_acc_vl_new(vid,
|
||||
vxlan_zif->brslave_info.br_if);
|
||||
acc_bd = zebra_evpn_acc_bd_alloc_on_ref(vid, br_if);
|
||||
|
||||
old_vni = acc_bd->vni;
|
||||
|
||||
@ -745,8 +773,6 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id,
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("access vlan %d vni %u ref", acc_bd->vid, vni_id);
|
||||
|
||||
zlog_err("access vlan %d vni %u ref", acc_bd->vid, vni_id);
|
||||
|
||||
if (old_zevpn)
|
||||
zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
|
||||
|
||||
@ -758,6 +784,7 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id,
|
||||
void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
|
||||
struct zebra_if *vxlan_zif)
|
||||
{
|
||||
struct interface *br_if;
|
||||
struct zebra_evpn_access_bd *acc_bd;
|
||||
|
||||
if (!vid)
|
||||
@ -766,7 +793,11 @@ void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
|
||||
if (!vni_id)
|
||||
return;
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid);
|
||||
br_if = vxlan_zif->brslave_info.br_if;
|
||||
if (!br_if)
|
||||
return;
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
|
||||
if (!acc_bd)
|
||||
return;
|
||||
|
||||
@ -775,7 +806,8 @@ void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
|
||||
return;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("access vlan %d vni %u deref", acc_bd->vid, vni_id);
|
||||
zlog_debug("access vlan %d bridge %s vni %u deref", acc_bd->vid,
|
||||
br_if->name, vni_id);
|
||||
|
||||
if (acc_bd->zevpn)
|
||||
zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, acc_bd->zevpn);
|
||||
@ -788,10 +820,37 @@ void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
|
||||
zebra_evpn_acc_bd_free_on_deref(acc_bd);
|
||||
}
|
||||
|
||||
/* handle BridgeIf<->AccessBD cleanup */
|
||||
void zebra_evpn_access_bd_bridge_cleanup(vlanid_t vid, struct interface *br_if,
|
||||
struct zebra_evpn_access_bd *acc_bd)
|
||||
{
|
||||
struct zebra_evpn *zevpn;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("access bd vlan %d bridge %s cleanup", acc_bd->vid,
|
||||
br_if->name);
|
||||
|
||||
zevpn = acc_bd->zevpn;
|
||||
if (zevpn)
|
||||
zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, zevpn);
|
||||
|
||||
/* cleanup resources maintained against the ES */
|
||||
list_delete_all_node(acc_bd->mbr_zifs);
|
||||
|
||||
acc_bd->zevpn = NULL;
|
||||
acc_bd->vxlan_zif = NULL;
|
||||
acc_bd->vni = 0;
|
||||
acc_bd->bridge_zif = NULL;
|
||||
|
||||
/* if there are no other references the access_bd can be freed */
|
||||
zebra_evpn_acc_bd_free_on_deref(acc_bd);
|
||||
}
|
||||
|
||||
/* handle EVPN add/del */
|
||||
void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn,
|
||||
bool set)
|
||||
{
|
||||
struct interface *br_if;
|
||||
struct zebra_vxlan_vni *vni;
|
||||
struct zebra_evpn_access_bd *acc_bd;
|
||||
|
||||
@ -803,7 +862,11 @@ void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn,
|
||||
if (!vni)
|
||||
return;
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vni->access_vlan);
|
||||
br_if = zif->brslave_info.br_if;
|
||||
if (!br_if)
|
||||
return;
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vni->access_vlan, br_if);
|
||||
if (!acc_bd)
|
||||
return;
|
||||
|
||||
@ -825,21 +888,26 @@ void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn,
|
||||
/* handle addition of new VLAN members */
|
||||
void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
|
||||
{
|
||||
struct interface *br_if;
|
||||
struct zebra_evpn_access_bd *acc_bd;
|
||||
|
||||
if (!vid)
|
||||
return;
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid);
|
||||
br_if = zif->brslave_info.br_if;
|
||||
if (!br_if)
|
||||
return;
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
|
||||
if (!acc_bd)
|
||||
acc_bd = zebra_evpn_acc_vl_new(vid, zif->brslave_info.br_if);
|
||||
acc_bd = zebra_evpn_acc_bd_alloc_on_ref(vid, br_if);
|
||||
|
||||
if (listnode_lookup(acc_bd->mbr_zifs, zif))
|
||||
return;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("access vlan %d mbr %s ref",
|
||||
vid, zif->ifp->name);
|
||||
zlog_debug("access vlan %d bridge %s mbr %s ref", vid,
|
||||
br_if->name, zif->ifp->name);
|
||||
|
||||
listnode_add(acc_bd->mbr_zifs, zif);
|
||||
if (acc_bd->zevpn && zif->es_info.es)
|
||||
@ -849,13 +917,18 @@ void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
|
||||
/* handle deletion of VLAN members */
|
||||
void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
|
||||
{
|
||||
struct interface *br_if;
|
||||
struct zebra_evpn_access_bd *acc_bd;
|
||||
struct listnode *node;
|
||||
|
||||
if (!vid)
|
||||
return;
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid);
|
||||
br_if = zif->brslave_info.br_if;
|
||||
if (!br_if)
|
||||
return;
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
|
||||
if (!acc_bd)
|
||||
return;
|
||||
|
||||
@ -864,8 +937,8 @@ void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
|
||||
return;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||
zlog_debug("access vlan %d mbr %s deref",
|
||||
vid, zif->ifp->name);
|
||||
zlog_debug("access vlan %d bridge %s mbr %s deref", vid,
|
||||
br_if->name, zif->ifp->name);
|
||||
|
||||
list_delete_node(acc_bd->mbr_zifs, node);
|
||||
|
||||
@ -932,14 +1005,19 @@ static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty,
|
||||
if (json) {
|
||||
zebra_evpn_acc_vl_json_fill(acc_bd, json, true);
|
||||
} else {
|
||||
vty_out(vty, "VLAN: %u\n", acc_bd->vid);
|
||||
vty_out(vty, "VLAN: %s.%u\n", acc_bd->bridge_zif->ifp->name,
|
||||
acc_bd->vid);
|
||||
vty_out(vty, " VxLAN Interface: %s\n",
|
||||
acc_bd->vxlan_zif ?
|
||||
acc_bd->vxlan_zif->ifp->name : "-");
|
||||
vty_out(vty, " SVI: %s\n",
|
||||
acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-");
|
||||
vty_out(vty, " L2-VNI: %d\n",
|
||||
acc_bd->zevpn ? acc_bd->zevpn->vni : 0);
|
||||
if (acc_bd->zevpn)
|
||||
vty_out(vty, " L2-VNI: %d\n", acc_bd->zevpn->vni);
|
||||
else {
|
||||
vty_out(vty, " L2-VNI: 0\n");
|
||||
vty_out(vty, " L3-VNI: %d\n", acc_bd->vni);
|
||||
}
|
||||
vty_out(vty, " Member Count: %d\n",
|
||||
listcount(acc_bd->mbr_zifs));
|
||||
vty_out(vty, " Members: \n");
|
||||
@ -955,7 +1033,8 @@ static void zebra_evpn_acc_vl_show_entry(struct vty *vty,
|
||||
if (json) {
|
||||
zebra_evpn_acc_vl_json_fill(acc_bd, json, false);
|
||||
} else {
|
||||
vty_out(vty, "%-5u %-15s %-8d %-15s %u\n", acc_bd->vid,
|
||||
vty_out(vty, "%-5s.%-5u %-15s %-8d %-15s %u\n",
|
||||
acc_bd->bridge_zif->ifp->name, acc_bd->vid,
|
||||
acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-",
|
||||
acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
|
||||
acc_bd->vxlan_zif ? acc_bd->vxlan_zif->ifp->name : "-",
|
||||
@ -993,7 +1072,7 @@ void zebra_evpn_acc_vl_show(struct vty *vty, bool uj)
|
||||
wctx.detail = false;
|
||||
|
||||
if (!uj)
|
||||
vty_out(vty, "%-5s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
|
||||
vty_out(vty, "%-12s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
|
||||
"L2-VNI", "VXLAN-IF", "# Members");
|
||||
|
||||
hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
|
||||
@ -1022,7 +1101,8 @@ void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj)
|
||||
vty_json(vty, json_array);
|
||||
}
|
||||
|
||||
void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid)
|
||||
void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid,
|
||||
struct interface *br_if)
|
||||
{
|
||||
json_object *json = NULL;
|
||||
struct zebra_evpn_access_bd *acc_bd;
|
||||
@ -1030,12 +1110,13 @@ void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid)
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid);
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
|
||||
if (acc_bd) {
|
||||
zebra_evpn_acc_vl_show_entry_detail(vty, acc_bd, json);
|
||||
} else {
|
||||
if (!json)
|
||||
vty_out(vty, "VLAN %u not present\n", vid);
|
||||
vty_out(vty, "VLAN %s.%u not present\n", br_if->name,
|
||||
vid);
|
||||
}
|
||||
|
||||
if (uj)
|
||||
@ -1992,7 +2073,7 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
|
||||
return;
|
||||
|
||||
bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid);
|
||||
acc_bd = zebra_evpn_acc_vl_find(vid, zif->brslave_info.br_if);
|
||||
if (acc_bd->zevpn)
|
||||
zebra_evpn_local_es_evi_add(es, acc_bd->zevpn);
|
||||
}
|
||||
|
@ -179,6 +179,9 @@ struct zebra_evpn_es_vtep {
|
||||
struct zebra_evpn_access_bd {
|
||||
vlanid_t vid;
|
||||
|
||||
ifindex_t bridge_ifindex;
|
||||
struct zebra_if *bridge_zif; /* associated bridge */
|
||||
|
||||
vni_t vni; /* vni associated with the vxlan device */
|
||||
struct zebra_if *vxlan_zif; /* vxlan device */
|
||||
/* list of members associated with the BD i.e. (potential) ESs */
|
||||
@ -348,9 +351,12 @@ extern void zebra_evpn_interface_init(void);
|
||||
extern int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp);
|
||||
extern void zebra_evpn_acc_vl_show(struct vty *vty, bool uj);
|
||||
extern void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj);
|
||||
extern void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid);
|
||||
extern void zebra_evpn_if_es_print(struct vty *vty, json_object *json,
|
||||
struct zebra_if *zif);
|
||||
extern struct zebra_evpn_access_bd *
|
||||
zebra_evpn_acc_vl_find(vlanid_t vid, struct interface *br_if);
|
||||
extern void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid,
|
||||
struct interface *br_if);
|
||||
extern void zebra_evpn_es_cleanup(void);
|
||||
extern int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
|
||||
uint32_t duration, bool set_default);
|
||||
@ -376,6 +382,9 @@ extern void zebra_evpn_l2_nh_show(struct vty *vty, bool uj);
|
||||
extern void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
|
||||
struct zebra_if *br_zif, bool is_up);
|
||||
extern void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if);
|
||||
extern void
|
||||
zebra_evpn_access_bd_bridge_cleanup(vlanid_t vid, struct interface *br_if,
|
||||
struct zebra_evpn_access_bd *acc_bd);
|
||||
extern void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es,
|
||||
struct interface *ifp, bool bypass);
|
||||
extern void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS);
|
||||
|
384
zebra/zebra_l2_bridge_if.c
Normal file
384
zebra/zebra_l2_bridge_if.c
Normal file
@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Zebra L2 bridge interface handling
|
||||
*
|
||||
* Copyright (C) 2021 Cumulus Networks, Inc.
|
||||
* Sharath Ramamurthy
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "hash.h"
|
||||
#include "if.h"
|
||||
#include "jhash.h"
|
||||
#include "linklist.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "prefix.h"
|
||||
#include "stream.h"
|
||||
#include "table.h"
|
||||
#include "vlan.h"
|
||||
#include "vxlan.h"
|
||||
#ifdef GNU_LINUX
|
||||
#include <linux/neighbour.h>
|
||||
#endif
|
||||
|
||||
#include "zebra/zebra_router.h"
|
||||
#include "zebra/debug.h"
|
||||
#include "zebra/interface.h"
|
||||
#include "zebra/rib.h"
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/rt_netlink.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
#include "zebra/zebra_l2.h"
|
||||
#include "zebra/zebra_l2_bridge_if.h"
|
||||
#include "zebra/zebra_ns.h"
|
||||
#include "zebra/zebra_vrf.h"
|
||||
#include "zebra/zebra_vxlan.h"
|
||||
#include "zebra/zebra_vxlan_if.h"
|
||||
#include "zebra/zebra_evpn.h"
|
||||
#include "zebra/zebra_evpn_mac.h"
|
||||
#include "zebra/zebra_evpn_neigh.h"
|
||||
#include "zebra/zebra_vxlan_private.h"
|
||||
#include "zebra/zebra_evpn_mh.h"
|
||||
#include "zebra/zebra_evpn_vxlan.h"
|
||||
#include "zebra/zebra_router.h"
|
||||
|
||||
static unsigned int zebra_l2_bridge_vlan_hash_keymake(const void *p)
|
||||
{
|
||||
const struct zebra_l2_bridge_vlan *bvlan;
|
||||
|
||||
bvlan = (const struct zebra_l2_bridge_vlan *)p;
|
||||
return jhash(&bvlan->vid, sizeof(bvlan->vid), 0);
|
||||
}
|
||||
|
||||
static bool zebra_l2_bridge_vlan_hash_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
const struct zebra_l2_bridge_vlan *bv1;
|
||||
const struct zebra_l2_bridge_vlan *bv2;
|
||||
|
||||
bv1 = (const struct zebra_l2_bridge_vlan *)p1;
|
||||
bv2 = (const struct zebra_l2_bridge_vlan *)p2;
|
||||
|
||||
return (bv1->vid == bv2->vid);
|
||||
}
|
||||
|
||||
static int zebra_l2_bridge_if_vlan_walk_callback(struct hash_bucket *bucket,
|
||||
void *ctxt)
|
||||
{
|
||||
int ret;
|
||||
struct zebra_l2_bridge_vlan *bvlan;
|
||||
struct zebra_l2_bridge_if_ctx *ctx;
|
||||
|
||||
bvlan = (struct zebra_l2_bridge_vlan *)bucket->data;
|
||||
ctx = (struct zebra_l2_bridge_if_ctx *)ctxt;
|
||||
|
||||
ret = ctx->func(ctx->zif, bvlan, ctx->arg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void zebra_l2_bridge_if_vlan_iterate_callback(struct hash_bucket *bucket,
|
||||
void *ctxt)
|
||||
{
|
||||
struct zebra_l2_bridge_vlan *bvlan;
|
||||
struct zebra_l2_bridge_if_ctx *ctx;
|
||||
|
||||
bvlan = (struct zebra_l2_bridge_vlan *)bucket->data;
|
||||
ctx = (struct zebra_l2_bridge_if_ctx *)ctxt;
|
||||
|
||||
ctx->func(ctx->zif, bvlan, ctx->arg);
|
||||
}
|
||||
|
||||
static int zebra_l2_bridge_if_vlan_clean(struct zebra_if *zif,
|
||||
struct zebra_l2_bridge_vlan *bvlan,
|
||||
void *ctxt)
|
||||
{
|
||||
struct zebra_evpn_access_bd *acc_bd;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("access vlan %d bridge %s cleanup", bvlan->vid,
|
||||
zif->ifp->name);
|
||||
|
||||
acc_bd = zebra_evpn_acc_vl_find(bvlan->vid, zif->ifp);
|
||||
if (acc_bd)
|
||||
zebra_evpn_access_bd_bridge_cleanup(bvlan->vid, zif->ifp,
|
||||
acc_bd);
|
||||
|
||||
bvlan->access_bd = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zebra_l2_bridge_vlan_free(void *arg)
|
||||
{
|
||||
struct zebra_l2_bridge_vlan *bvl;
|
||||
|
||||
bvl = (struct zebra_l2_bridge_vlan *)arg;
|
||||
XFREE(MTYPE_TMP, bvl);
|
||||
}
|
||||
|
||||
static void *zebra_l2_bridge_vlan_alloc(void *p)
|
||||
{
|
||||
struct zebra_l2_bridge_vlan *bvlan;
|
||||
const struct zebra_l2_bridge_vlan *bvl;
|
||||
|
||||
bvl = (const struct zebra_l2_bridge_vlan *)p;
|
||||
bvlan = XCALLOC(MTYPE_TMP, sizeof(*bvlan));
|
||||
bvlan->vid = bvl->vid;
|
||||
bvlan->access_bd = bvl->access_bd;
|
||||
|
||||
return (void *)bvlan;
|
||||
}
|
||||
|
||||
static void zebra_l2_bridge_vlan_table_destroy(struct hash *vlan_table)
|
||||
{
|
||||
if (vlan_table) {
|
||||
hash_clean(vlan_table, zebra_l2_bridge_vlan_free);
|
||||
hash_free(vlan_table);
|
||||
}
|
||||
}
|
||||
|
||||
static struct hash *zebra_l2_bridge_vlan_table_create(void)
|
||||
{
|
||||
return hash_create(zebra_l2_bridge_vlan_hash_keymake,
|
||||
zebra_l2_bridge_vlan_hash_cmp,
|
||||
"Zebra L2 Bridge Vlan Table");
|
||||
}
|
||||
|
||||
static void zebra_l2_bridge_if_vlan_table_destroy(struct zebra_if *zif)
|
||||
{
|
||||
struct zebra_l2_bridge_if *br;
|
||||
|
||||
br = BRIDGE_FROM_ZEBRA_IF(zif);
|
||||
zebra_l2_bridge_if_vlan_iterate(zif, zebra_l2_bridge_if_vlan_clean,
|
||||
NULL);
|
||||
zebra_l2_bridge_vlan_table_destroy(br->vlan_table);
|
||||
br->vlan_table = NULL;
|
||||
}
|
||||
|
||||
static int zebra_l2_bridge_if_vlan_table_create(struct zebra_if *zif)
|
||||
{
|
||||
struct zebra_l2_bridge_if *br;
|
||||
|
||||
br = BRIDGE_FROM_ZEBRA_IF(zif);
|
||||
if (!br->vlan_table) {
|
||||
br->vlan_table = zebra_l2_bridge_vlan_table_create();
|
||||
if (!br->vlan_table)
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zebra_l2_bridge_if_vlan_del(struct interface *ifp, vlanid_t vid)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
struct zebra_l2_bridge_if *br;
|
||||
struct zebra_l2_bridge_vlan bvl;
|
||||
struct zebra_l2_bridge_vlan *bvlan;
|
||||
|
||||
zif = (struct zebra_if *)ifp->info;
|
||||
memset(&bvl, 0, sizeof(bvl));
|
||||
bvl.vid = vid;
|
||||
|
||||
br = BRIDGE_FROM_ZEBRA_IF(zif);
|
||||
bvlan = hash_release(br->vlan_table, &bvl);
|
||||
|
||||
if (bvlan)
|
||||
zebra_l2_bridge_vlan_free(bvlan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zebra_l2_bridge_if_vlan_update(struct interface *ifp,
|
||||
struct zebra_l2_bridge_vlan *bvl,
|
||||
int chgflags)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
struct zebra_l2_bridge_vlan *bvlan;
|
||||
|
||||
zif = (struct zebra_if *)ifp->info;
|
||||
bvlan = zebra_l2_bridge_if_vlan_find(zif, bvl->vid);
|
||||
|
||||
if (chgflags & ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE)
|
||||
bvlan->access_bd = bvl->access_bd;
|
||||
|
||||
if (!bvlan->access_bd)
|
||||
return zebra_l2_bridge_if_vlan_del(ifp, bvl->vid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zebra_l2_bridge_if_vlan_add(struct interface *ifp,
|
||||
struct zebra_l2_bridge_vlan *bvlan)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
struct zebra_l2_bridge_if *br;
|
||||
|
||||
zif = (struct zebra_if *)ifp->info;
|
||||
br = BRIDGE_FROM_ZEBRA_IF(zif);
|
||||
hash_get(br->vlan_table, (void *)bvlan, zebra_l2_bridge_vlan_alloc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct zebra_l2_bridge_vlan *
|
||||
zebra_l2_bridge_if_vlan_find(const struct zebra_if *zif, vlanid_t vid)
|
||||
{
|
||||
const struct zebra_l2_bridge_if *br;
|
||||
struct zebra_l2_bridge_vlan *bvl;
|
||||
struct zebra_l2_bridge_vlan bvlan;
|
||||
|
||||
br = BRIDGE_FROM_ZEBRA_IF(zif);
|
||||
memset(&bvlan, 0, sizeof(bvlan));
|
||||
bvlan.vid = vid;
|
||||
bvl = (struct zebra_l2_bridge_vlan *)hash_lookup(br->vlan_table,
|
||||
(void *)&bvlan);
|
||||
|
||||
/* TODO: For debugging. Remove later */
|
||||
if (bvl)
|
||||
assert(bvl->vid == vid);
|
||||
|
||||
return bvl;
|
||||
}
|
||||
|
||||
vni_t zebra_l2_bridge_if_vni_find(const struct zebra_if *zif, vlanid_t vid)
|
||||
{
|
||||
vni_t vni_id = 0;
|
||||
struct zebra_l2_bridge_vlan *bvlan;
|
||||
|
||||
bvlan = zebra_l2_bridge_if_vlan_find(zif, vid);
|
||||
if (bvlan && bvlan->access_bd && bvlan->access_bd->vni)
|
||||
vni_id = bvlan->access_bd->vni;
|
||||
|
||||
return vni_id;
|
||||
}
|
||||
|
||||
void zebra_l2_bridge_if_vlan_iterate(struct zebra_if *zif,
|
||||
int (*func)(struct zebra_if *zif,
|
||||
struct zebra_l2_bridge_vlan *,
|
||||
void *),
|
||||
void *arg)
|
||||
{
|
||||
struct zebra_l2_bridge_if *br;
|
||||
struct zebra_l2_bridge_if_ctx ctx;
|
||||
|
||||
br = BRIDGE_FROM_ZEBRA_IF(zif);
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.zif = zif;
|
||||
ctx.func = func;
|
||||
ctx.arg = arg;
|
||||
hash_iterate(br->vlan_table, zebra_l2_bridge_if_vlan_iterate_callback,
|
||||
&ctx);
|
||||
}
|
||||
|
||||
void zebra_l2_bridge_if_vlan_walk(struct zebra_if *zif,
|
||||
int (*func)(struct zebra_if *zif,
|
||||
struct zebra_l2_bridge_vlan *,
|
||||
void *),
|
||||
void *arg)
|
||||
{
|
||||
struct zebra_l2_bridge_if *br;
|
||||
struct zebra_l2_bridge_if_ctx ctx;
|
||||
|
||||
br = BRIDGE_FROM_ZEBRA_IF(zif);
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.zif = zif;
|
||||
ctx.func = func;
|
||||
ctx.arg = arg;
|
||||
hash_walk(br->vlan_table, zebra_l2_bridge_if_vlan_walk_callback, &ctx);
|
||||
}
|
||||
|
||||
int zebra_l2_bridge_if_vlan_access_bd_deref(struct zebra_evpn_access_bd *bd)
|
||||
{
|
||||
int chgflags = 0;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_l2_bridge_vlan bvl;
|
||||
struct zebra_l2_bridge_vlan *bvlan;
|
||||
|
||||
zif = bd->bridge_zif;
|
||||
if (!zif)
|
||||
return -1;
|
||||
|
||||
bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid);
|
||||
if (!bvlan)
|
||||
return 0;
|
||||
|
||||
memset(&bvl, 0, sizeof(bvl));
|
||||
bvl.vid = bd->vid;
|
||||
bvl.access_bd = NULL;
|
||||
chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE;
|
||||
return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags);
|
||||
}
|
||||
|
||||
int zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd)
|
||||
{
|
||||
int chgflags = 0;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_l2_bridge_vlan bvl;
|
||||
struct zebra_l2_bridge_vlan *bvlan;
|
||||
|
||||
zif = bd->bridge_zif;
|
||||
if (!zif)
|
||||
return -1;
|
||||
|
||||
if (!bd->vid)
|
||||
return -1;
|
||||
|
||||
memset(&bvl, 0, sizeof(bvl));
|
||||
bvl.vid = bd->vid;
|
||||
bvl.access_bd = bd;
|
||||
|
||||
bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid);
|
||||
if (!bvlan) {
|
||||
return zebra_l2_bridge_if_vlan_add(zif->ifp, &bvl);
|
||||
}
|
||||
|
||||
chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE;
|
||||
return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags);
|
||||
}
|
||||
|
||||
int zebra_l2_bridge_if_cleanup(struct interface *ifp)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
|
||||
if (!IS_ZEBRA_IF_BRIDGE(ifp))
|
||||
return 0;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("bridge %s cleanup", ifp->name);
|
||||
|
||||
zif = (struct zebra_if *)ifp->info;
|
||||
zebra_l2_bridge_if_vlan_table_destroy(zif);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zebra_l2_bridge_if_del(struct interface *ifp)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("bridge %s delete", ifp->name);
|
||||
|
||||
return zebra_l2_bridge_if_cleanup(ifp);
|
||||
}
|
||||
|
||||
int zebra_l2_bridge_if_add(struct interface *ifp)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
struct zebra_l2_bridge_if *br;
|
||||
|
||||
zif = (struct zebra_if *)ifp->info;
|
||||
br = BRIDGE_FROM_ZEBRA_IF(zif);
|
||||
br->br_zif = (struct zebra_if *)ifp->info;
|
||||
zebra_l2_bridge_if_vlan_table_create(zif);
|
||||
return 0;
|
||||
}
|
75
zebra/zebra_l2_bridge_if.h
Normal file
75
zebra/zebra_l2_bridge_if.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Zebra L2 bridge interface data structures and definitions
|
||||
* These are public definitions referenced by other files.
|
||||
* Copyright (C) 2021 Cumulus Networks, Inc.
|
||||
* Sharath Ramamurthy
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _ZEBRA_L2_BRIDGE_IF_H
|
||||
#define _ZEBRA_L2_BRIDGE_IF_H
|
||||
|
||||
#include <zebra.h>
|
||||
#include <zebra/zebra_router.h>
|
||||
|
||||
#include "linklist.h"
|
||||
#include "if.h"
|
||||
#include "vlan.h"
|
||||
#include "vxlan.h"
|
||||
|
||||
#include "lib/json.h"
|
||||
#include "zebra/zebra_vrf.h"
|
||||
#include "zebra/zserv.h"
|
||||
|
||||
#include "zebra/zebra_dplane.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Bridge interface change flags of interest. */
|
||||
#define ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE (1 << 0)
|
||||
|
||||
extern struct zebra_l2_bridge_vlan *
|
||||
zebra_l2_bridge_if_vlan_find(const struct zebra_if *zif, vlanid_t vid);
|
||||
extern vni_t zebra_l2_bridge_if_vni_find(const struct zebra_if *zif,
|
||||
vlanid_t vid);
|
||||
extern void zebra_l2_bridge_if_vlan_iterate(
|
||||
struct zebra_if *zif,
|
||||
int (*func)(struct zebra_if *zif, struct zebra_l2_bridge_vlan *,
|
||||
void *),
|
||||
void *arg);
|
||||
extern void
|
||||
zebra_l2_bridge_if_vlan_walk(struct zebra_if *zif,
|
||||
int (*func)(struct zebra_if *zif,
|
||||
struct zebra_l2_bridge_vlan *, void *),
|
||||
void *arg);
|
||||
extern int
|
||||
zebra_l2_bridge_if_vlan_access_bd_deref(struct zebra_evpn_access_bd *bd);
|
||||
extern int
|
||||
zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd);
|
||||
extern int zebra_l2_bridge_if_del(struct interface *ifp);
|
||||
extern int zebra_l2_bridge_if_add(struct interface *ifp);
|
||||
extern int zebra_l2_bridge_if_cleanup(struct interface *ifp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ZEBRA_L2_BRIDGE_IF_H */
|
@ -3016,20 +3016,36 @@ DEFPY(show_evpn_es_evi,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(show_evpn_access_vlan,
|
||||
show_evpn_access_vlan_cmd,
|
||||
"show evpn access-vlan [(1-4094)$vid | detail$detail] [json$json]",
|
||||
DEFPY(show_evpn_access_vlan, show_evpn_access_vlan_cmd,
|
||||
"show evpn access-vlan [IFNAME$if_name (1-4094)$vid | detail$detail] [json$json]",
|
||||
SHOW_STR
|
||||
"EVPN\n"
|
||||
"Access VLANs\n"
|
||||
"VLAN ID\n"
|
||||
"Detailed information\n"
|
||||
JSON_STR)
|
||||
"Detailed information\n" JSON_STR)
|
||||
{
|
||||
bool uj = !!json;
|
||||
|
||||
if (vid) {
|
||||
zebra_evpn_acc_vl_show_vid(vty, uj, vid);
|
||||
if (if_name && vid) {
|
||||
bool found = false;
|
||||
struct vrf *vrf;
|
||||
struct interface *ifp;
|
||||
|
||||
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
||||
if (if_name) {
|
||||
ifp = if_lookup_by_name(if_name, vrf->vrf_id);
|
||||
if (ifp) {
|
||||
zebra_evpn_acc_vl_show_vid(vty, uj, vid,
|
||||
ifp);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
vty_out(vty, "%% Can't find interface %s\n", if_name);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
} else {
|
||||
if (detail)
|
||||
zebra_evpn_acc_vl_show_detail(vty, uj);
|
||||
|
Loading…
Reference in New Issue
Block a user