Skip to content

Commit

Permalink
zebra: update zl3vni when bridge link refreshed in other namespaces
Browse files Browse the repository at this point in the history
When running bgp evpn rt5 setup with vrf namespace backend, once the
BGP configuration loaded, some refresh like the config change of a
vxlan interface is not taken into account. As consequence, the BGP
l2vpn evpn entries are empty. This can happen by recreating vxlan
interface like follows:

ip netns exec cust1 ip li del vxlan1000
ip link add vxlan1000 type vxlan id 1000 dev loopback0 local 10.209.36.1 learning
ip link set dev vxlan1000 mtu 9000
ip link set dev vxlan1000 netns cust1
ip netns exec cust1 bash
ip link set dev vxlan1000 up
ip link set dev vxlan1000 master br1000

Actually, changing learning attribute requires recreation, and this
change needs to manually reload the frr configuration.

The update mechanism in zebra about vxlan interface updates is
already put in place, but it does not work well with namespace
based vrf backend. The function zl3vni_from_svi() is then
modified to parse all the interfaces of each namespace.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
  • Loading branch information
pguibert6WIND committed Sep 7, 2021
1 parent b44f7c3 commit 2490726
Showing 1 changed file with 53 additions and 33 deletions.
86 changes: 53 additions & 33 deletions zebra/zebra_vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -1798,37 +1798,78 @@ struct zebra_l3vni *zl3vni_from_vrf(vrf_id_t vrf_id)
return zl3vni_lookup(zvrf->l3vni);
}

static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni)
{
int found = 0;
struct zebra_ns *zns = ns->info;
struct zebra_l3vni **p_zl3vni = (struct zebra_l3vni **)_p_zl3vni;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
struct route_node *rn = NULL;
struct interface *tmp_if = NULL;
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;

if (!in_param)
return NS_WALK_STOP;

/* loop through all vxlan-interface */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
if (!tmp_if)
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
continue;
if (!if_is_operative(tmp_if))
continue;
vxl = &zif->l2info.vxl;

if (zif->brslave_info.br_if != in_param->br_if)
continue;

if (!in_param->bridge_vlan_aware
|| vxl->access_vlan == in_param->vid) {
found = 1;
break;
}
}

if (!found)
return NS_WALK_CONTINUE;

if (p_zl3vni)
*p_zl3vni = zl3vni_lookup(vxl->vni);
return NS_WALK_STOP;
}

/*
* Map SVI and associated bridge to a VNI. This is invoked upon getting
* neighbor notifications, to see if they are of interest.
*/
static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
struct interface *br_if)
{
int found = 0;
vlanid_t vid = 0;
uint8_t bridge_vlan_aware = 0;
struct zebra_l3vni *zl3vni = NULL;
struct zebra_ns *zns = NULL;
struct route_node *rn = NULL;
struct zebra_if *zif = NULL;
struct interface *tmp_if = NULL;
struct zebra_l2info_bridge *br = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
struct zebra_from_svi_param in_param = {};
struct zebra_l3vni **p_zl3vni;

if (!br_if)
return NULL;

/* Make sure the linked interface is a bridge. */
if (!IS_ZEBRA_IF_BRIDGE(br_if))
return NULL;
in_param.br_if = br_if;

/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
bridge_vlan_aware = br->vlan_aware;
if (bridge_vlan_aware) {
in_param.bridge_vlan_aware = br->vlan_aware;
if (in_param.bridge_vlan_aware) {
struct zebra_l2info_vlan *vl;

if (!IS_ZEBRA_IF_VLAN(ifp))
Expand All @@ -1837,36 +1878,15 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
zif = ifp->info;
assert(zif);
vl = &zif->l2info.vl;
vid = vl->vid;
in_param.vid = vl->vid;
}

/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
/* TODO: Optimize with a hash. */
zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
if (!tmp_if)
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
continue;
if (!if_is_operative(tmp_if))
continue;
vxl = &zif->l2info.vxl;

if (zif->brslave_info.br_if != br_if)
continue;

if (!bridge_vlan_aware || vxl->access_vlan == vid) {
found = 1;
break;
}
}

if (!found)
return NULL;
p_zl3vni = &zl3vni;

zl3vni = zl3vni_lookup(vxl->vni);
ns_walk_func(zl3vni_from_svi_ns, (void *)&in_param, (void **)p_zl3vni);
return zl3vni;
}

Expand Down

0 comments on commit 2490726

Please sign in to comment.