Merge pull request #17297 from mjstapp/mjs_ifp_table

zebra, lib: use internal rbtree for per-NS tree of ifps
This commit is contained in:
Donald Sharp 2024-11-12 15:12:07 -05:00 committed by GitHub
commit ac6314d380
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 586 additions and 475 deletions

View File

@ -12,6 +12,7 @@
#ifndef _ZEBRA_ISIS_ROUTE_H #ifndef _ZEBRA_ISIS_ROUTE_H
#define _ZEBRA_ISIS_ROUTE_H #define _ZEBRA_ISIS_ROUTE_H
#include "lib/table.h"
#include "lib/nexthop.h" #include "lib/nexthop.h"
struct isis_nexthop { struct isis_nexthop {

View File

@ -1002,12 +1002,6 @@ void if_terminate(struct vrf *vrf)
while (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) { while (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) {
ifp = RB_ROOT(if_name_head, &vrf->ifaces_by_name); ifp = RB_ROOT(if_name_head, &vrf->ifaces_by_name);
if (ifp->node) {
ifp->node->info = NULL;
route_unlock_node(ifp->node);
ifp->node = NULL;
}
if_delete(&ifp); if_delete(&ifp);
} }
} }

View File

@ -295,8 +295,6 @@ struct interface {
struct if_data stats; struct if_data stats;
#endif /* HAVE_NET_RT_IFLIST */ #endif /* HAVE_NET_RT_IFLIST */
struct route_node *node;
struct vrf *vrf; struct vrf *vrf;
/* /*

View File

@ -1568,6 +1568,15 @@ static int netlink_request_tunneldump(struct zebra_ns *zns, int family,
return netlink_request(&zns->netlink_cmd, &req); return netlink_request(&zns->netlink_cmd, &req);
} }
/* Prototype for tunneldump walker */
static int tunneldump_walk_cb(struct interface *ifp, void *arg);
struct tunneldump_ctx {
struct zebra_ns *zns;
struct zebra_dplane_info *dp_info;
int ret;
};
/* /*
* Currently we only ask for vxlan l3svd vni information. * Currently we only ask for vxlan l3svd vni information.
* In the future this can be expanded. * In the future this can be expanded.
@ -1575,39 +1584,48 @@ static int netlink_request_tunneldump(struct zebra_ns *zns, int family,
int netlink_tunneldump_read(struct zebra_ns *zns) int netlink_tunneldump_read(struct zebra_ns *zns)
{ {
int ret = 0; int ret = 0;
struct tunneldump_ctx ctx = {};
struct zebra_dplane_info dp_info; struct zebra_dplane_info dp_info;
struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct nlsock *netlink_cmd = &zns->netlink_cmd;
zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { /* Set up context and call iterator */
tmp_if = (struct interface *)rn->info; ctx.zns = zns;
if (!tmp_if) ctx.dp_info = &dp_info;
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
continue;
ret = netlink_request_tunneldump(zns, PF_BRIDGE, zebra_ns_ifp_walk(zns, tunneldump_walk_cb, &ctx);
tmp_if->ifindex);
if (ret < 0) {
route_unlock_node(rn);
return ret;
}
ret = netlink_parse_info(netlink_link_change, netlink_cmd, ret = ctx.ret;
&dp_info, 0, true);
if (ret < 0) { return ret;
route_unlock_node(rn); }
return ret;
} static int tunneldump_walk_cb(struct interface *ifp, void *arg)
{
int ret;
struct tunneldump_ctx *ctx = arg;
struct zebra_if *zif;
zif = ifp->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
goto done;
ret = netlink_request_tunneldump(ctx->zns, PF_BRIDGE, ifp->ifindex);
if (ret < 0) {
ctx->ret = ret;
return NS_WALK_STOP;
} }
return 0; ret = netlink_parse_info(netlink_link_change, &(ctx->zns->netlink_cmd),
ctx->dp_info, 0, true);
if (ret < 0) {
ctx->ret = ret;
return NS_WALK_STOP;
}
done:
return NS_WALK_CONTINUE;
} }
static uint8_t netlink_get_dplane_vlan_state(uint8_t state) static uint8_t netlink_get_dplane_vlan_state(uint8_t state)

View File

@ -43,7 +43,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information");
DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp),
(vty, ifp)); (vty, ifp));
DEFINE_MTYPE(ZEBRA, ZIF_DESC, "Intf desc"); DEFINE_MTYPE_STATIC(ZEBRA, ZIF_DESC, "Intf desc");
static void if_down_del_nbr_connected(struct interface *ifp); static void if_down_del_nbr_connected(struct interface *ifp);
@ -215,6 +215,8 @@ static int if_zebra_delete_hook(struct interface *ifp)
if_nhg_dependents_release(ifp); if_nhg_dependents_release(ifp);
nhg_connected_tree_free(&zebra_if->nhg_dependents); nhg_connected_tree_free(&zebra_if->nhg_dependents);
zebra_ns_unlink_ifp(ifp);
XFREE(MTYPE_ZIF_DESC, zebra_if->desc); XFREE(MTYPE_ZIF_DESC, zebra_if->desc);
EVENT_OFF(zebra_if->speed_update); EVENT_OFF(zebra_if->speed_update);
@ -225,62 +227,14 @@ static int if_zebra_delete_hook(struct interface *ifp)
return 0; return 0;
} }
/* Build the table key */
static void if_build_key(uint32_t ifindex, struct prefix *p)
{
p->family = AF_INET;
p->prefixlen = IPV4_MAX_BITLEN;
p->u.prefix4.s_addr = ifindex;
}
/* Link an interface in a per NS interface tree */
struct interface *if_link_per_ns(struct zebra_ns *ns, struct interface *ifp)
{
struct prefix p;
struct route_node *rn;
if (ifp->ifindex == IFINDEX_INTERNAL)
return NULL;
if_build_key(ifp->ifindex, &p);
rn = route_node_get(ns->if_table, &p);
if (rn->info) {
ifp = (struct interface *)rn->info;
route_unlock_node(rn); /* get */
return ifp;
}
rn->info = ifp;
ifp->node = rn;
return ifp;
}
/* Delete a VRF. This is called in vrf_terminate(). */
void if_unlink_per_ns(struct interface *ifp)
{
if (!ifp->node)
return;
ifp->node->info = NULL;
route_unlock_node(ifp->node);
ifp->node = NULL;
}
/* Look up an interface by identifier within a NS */ /* Look up an interface by identifier within a NS */
struct interface *if_lookup_by_index_per_ns(struct zebra_ns *ns, struct interface *if_lookup_by_index_per_ns(struct zebra_ns *ns,
uint32_t ifindex) uint32_t ifindex)
{ {
struct prefix p;
struct route_node *rn;
struct interface *ifp = NULL; struct interface *ifp = NULL;
if_build_key(ifindex, &p); ifp = zebra_ns_lookup_ifp(ns, ifindex);
rn = route_node_lookup(ns->if_table, &p);
if (rn) {
ifp = (struct interface *)rn->info;
route_unlock_node(rn); /* lookup */
}
return ifp; return ifp;
} }
@ -288,18 +242,11 @@ struct interface *if_lookup_by_index_per_ns(struct zebra_ns *ns,
struct interface *if_lookup_by_name_per_ns(struct zebra_ns *ns, struct interface *if_lookup_by_name_per_ns(struct zebra_ns *ns,
const char *ifname) const char *ifname)
{ {
struct route_node *rn;
struct interface *ifp; struct interface *ifp;
for (rn = route_top(ns->if_table); rn; rn = route_next(rn)) { ifp = zebra_ns_lookup_ifp_name(ns, ifname);
ifp = (struct interface *)rn->info;
if (ifp && strcmp(ifp->name, ifname) == 0) {
route_unlock_node(rn);
return (ifp);
}
}
return NULL; return ifp;
} }
struct interface *if_lookup_by_index_per_nsid(ns_id_t ns_id, uint32_t ifindex) struct interface *if_lookup_by_index_per_nsid(ns_id_t ns_id, uint32_t ifindex)
@ -571,7 +518,8 @@ void if_add_update(struct interface *ifp)
zns = zvrf->zns; zns = zvrf->zns;
else else
zns = zebra_ns_lookup(NS_DEFAULT); zns = zebra_ns_lookup(NS_DEFAULT);
if_link_per_ns(zns, ifp);
zebra_ns_link_ifp(zns, ifp);
if_data = ifp->info; if_data = ifp->info;
assert(if_data); assert(if_data);
@ -776,7 +724,7 @@ void if_delete_update(struct interface **pifp)
/* Send out notification on interface delete. */ /* Send out notification on interface delete. */
zebra_interface_delete_update(ifp); zebra_interface_delete_update(ifp);
if_unlink_per_ns(ifp); zebra_ns_unlink_ifp(ifp);
/* Update ifindex after distributing the delete message. This is in /* Update ifindex after distributing the delete message. This is in
case any client needs to have the old value of ifindex available case any client needs to have the old value of ifindex available
@ -784,7 +732,6 @@ void if_delete_update(struct interface **pifp)
for setting ifindex to IFINDEX_INTERNAL after processing the for setting ifindex to IFINDEX_INTERNAL after processing the
interface deletion message. */ interface deletion message. */
if_set_index(ifp, IFINDEX_INTERNAL); if_set_index(ifp, IFINDEX_INTERNAL);
ifp->node = NULL;
UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
@ -1081,51 +1028,53 @@ void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex,
link_ifindex); link_ifindex);
} }
/*
* Callback for per-ns link fixup iteration
*/
static int zif_link_fixup_cb(struct interface *ifp, void *arg)
{
struct zebra_if *zif;
zif = ifp->info;
/* update bond-member to bond linkages */
if ((IS_ZEBRA_IF_BOND_SLAVE(ifp)) &&
(zif->bondslave_info.bond_ifindex != IFINDEX_INTERNAL) &&
!zif->bondslave_info.bond_if) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("bond mbr %s map to bond %d", zif->ifp->name,
zif->bondslave_info.bond_ifindex);
zebra_l2_map_slave_to_bond(zif, ifp->vrf->vrf_id);
}
/* update SVI linkages */
if ((zif->link_ifindex != IFINDEX_INTERNAL) && !zif->link) {
zif->link = if_lookup_by_index_per_nsid(zif->link_nsid,
zif->link_ifindex);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("interface %s/%d's lower fixup to %s/%d",
ifp->name, ifp->ifindex,
zif->link ? zif->link->name : "unk",
zif->link_ifindex);
}
/* Update VLAN<=>SVI map */
if (IS_ZEBRA_IF_VLAN(ifp))
zebra_evpn_acc_bd_svi_set(zif, NULL,
!!if_is_operative(ifp));
return NS_WALK_CONTINUE;
}
/* /*
* during initial link dump kernel does not order lower devices before * during initial link dump kernel does not order lower devices before
* upper devices so we need to fixup link dependencies at the end of dump * upper devices so we need to fixup link dependencies at the end of dump
*/ */
void zebra_if_update_all_links(struct zebra_ns *zns) void zebra_if_update_all_links(struct zebra_ns *zns)
{ {
struct route_node *rn;
struct interface *ifp;
struct zebra_if *zif;
if (IS_ZEBRA_DEBUG_KERNEL) if (IS_ZEBRA_DEBUG_KERNEL)
zlog_info("fixup link dependencies"); zlog_debug("fixup link dependencies");
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { zebra_ns_ifp_walk(zns, zif_link_fixup_cb, NULL);
ifp = (struct interface *)rn->info;
if (!ifp)
continue;
zif = ifp->info;
/* update bond-member to bond linkages */
if ((IS_ZEBRA_IF_BOND_SLAVE(ifp))
&& (zif->bondslave_info.bond_ifindex != IFINDEX_INTERNAL)
&& !zif->bondslave_info.bond_if) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("bond mbr %s map to bond %d",
zif->ifp->name,
zif->bondslave_info.bond_ifindex);
zebra_l2_map_slave_to_bond(zif, ifp->vrf->vrf_id);
}
/* update SVI linkages */
if ((zif->link_ifindex != IFINDEX_INTERNAL) && !zif->link) {
zif->link = if_lookup_by_index_per_nsid(
zif->link_nsid, zif->link_ifindex);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("interface %s/%d's lower fixup to %s/%d",
ifp->name, ifp->ifindex,
zif->link?zif->link->name:"unk",
zif->link_ifindex);
}
/* Update VLAN<=>SVI map */
if (IS_ZEBRA_IF_VLAN(ifp))
zebra_evpn_acc_bd_svi_set(zif, NULL,
!!if_is_operative(ifp));
}
} }
static bool if_ignore_set_protodown(const struct interface *ifp, bool new_down, static bool if_ignore_set_protodown(const struct interface *ifp, bool new_down,

View File

@ -94,9 +94,6 @@ enum zebra_if_flags {
#define ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) \ #define ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) \
((zif)->protodown_rc == ZEBRA_PROTODOWN_EXTERNAL) ((zif)->protodown_rc == ZEBRA_PROTODOWN_EXTERNAL)
/* Mem type for zif desc */
DECLARE_MTYPE(ZIF_DESC);
/* `zebra' daemon local interface structure. */ /* `zebra' daemon local interface structure. */
struct zebra_if { struct zebra_if {
/* back pointer to the interface */ /* back pointer to the interface */
@ -215,6 +212,9 @@ struct zebra_if {
char neigh_mac[6]; char neigh_mac[6];
struct in6_addr v6_2_v4_ll_addr6; struct in6_addr v6_2_v4_ll_addr6;
/* Linkage for per-vrf/per-NS ifp container */
struct ifp_tree_link *ns_tree_link;
/* The description of the interface */ /* The description of the interface */
char *desc; char *desc;
}; };
@ -262,12 +262,10 @@ extern void zebra_if_init(void);
extern struct interface *if_lookup_by_index_per_ns(struct zebra_ns *, uint32_t); extern struct interface *if_lookup_by_index_per_ns(struct zebra_ns *, uint32_t);
extern struct interface *if_lookup_by_name_per_ns(struct zebra_ns *, extern struct interface *if_lookup_by_name_per_ns(struct zebra_ns *,
const char *); const char *);
extern struct interface *if_link_per_ns(struct zebra_ns *, struct interface *);
extern struct interface *if_lookup_by_index_per_nsid(ns_id_t nsid, extern struct interface *if_lookup_by_index_per_nsid(ns_id_t nsid,
uint32_t ifindex); uint32_t ifindex);
extern const char *ifindex2ifname_per_ns(struct zebra_ns *, unsigned int); extern const char *ifindex2ifname_per_ns(struct zebra_ns *, unsigned int);
extern void if_unlink_per_ns(struct interface *);
extern void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *fip, extern void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *fip,
char mac[6], char mac[6],
struct in6_addr *address, struct in6_addr *address,

View File

@ -610,70 +610,47 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
return; return;
} }
static int zebra_evpn_map_vlan_ns(struct ns *ns, /* Callback for per-NS ifp walk */
void *_in_param, static int zebra_evpn_map_vlan_ns(struct interface *tmp_if, void *_in_param)
void **_p_zevpn)
{ {
int found = 0; bool found = false;
struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct interface *br_if; struct interface *br_if;
struct zebra_evpn **p_zevpn = (struct zebra_evpn **)_p_zevpn;
struct zebra_evpn *zevpn; struct zebra_evpn *zevpn;
struct interface *tmp_if = NULL;
struct zebra_if *zif; struct zebra_if *zif;
struct zebra_from_svi_param *in_param = struct zebra_from_svi_param *in_param = _in_param;
(struct zebra_from_svi_param *)_in_param;
vlanid_t vid;
vni_t vni_id = 0; vni_t vni_id = 0;
uint8_t bridge_vlan_aware;
assert(p_zevpn && in_param); assert(in_param);
br_if = in_param->br_if; br_if = in_param->br_if;
assert(br_if); assert(br_if);
zif = in_param->zif; zif = in_param->zif;
assert(zif); assert(zif);
vid = in_param->vid;
bridge_vlan_aware = in_param->bridge_vlan_aware;
if (bridge_vlan_aware) { /*
vni_id = zebra_l2_bridge_if_vni_find(zif, vid); * See if this interface (or interface plus VLAN Id) maps to a
if (vni_id) * VxLAN
found = 1; */
} else { /* TODO: Optimize with a hash. */
/* zif = tmp_if->info;
* See if this interface (or interface plus VLAN Id) maps to a if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
* VxLAN goto done;
*/ if (!if_is_operative(tmp_if))
/* TODO: Optimize with a hash. */ goto done;
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;
if (zif->brslave_info.br_if != br_if) if (zif->brslave_info.br_if != br_if)
continue; goto done;
vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if); vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
if (vni_id) { if (vni_id)
found = 1; found = true;
route_unlock_node(rn);
break;
}
}
}
done:
if (!found) if (!found)
return NS_WALK_CONTINUE; return NS_WALK_CONTINUE;
zevpn = zebra_evpn_lookup(vni_id); zevpn = zebra_evpn_lookup(vni_id);
*p_zevpn = zevpn; in_param->zevpn = zevpn;
return NS_WALK_STOP; return NS_WALK_STOP;
} }
@ -685,42 +662,39 @@ struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid) struct interface *br_if, vlanid_t vid)
{ {
struct zebra_if *zif; struct zebra_if *zif;
struct zebra_evpn **p_zevpn; struct zebra_from_svi_param in_param = {};
struct zebra_evpn *zevpn = NULL; vni_t vni_id = 0;
struct zebra_from_svi_param in_param;
/* Determine if bridge is VLAN-aware or not */ /* Determine if bridge is VLAN-aware or not */
zif = br_if->info; zif = br_if->info;
assert(zif); assert(zif);
in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
/* Special case for vlan */
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif)) {
vni_id = zebra_l2_bridge_if_vni_find(zif, vid);
if (vni_id)
return zebra_evpn_lookup(vni_id);
}
in_param.vid = vid; in_param.vid = vid;
in_param.br_if = br_if; in_param.br_if = br_if;
in_param.zif = zif; in_param.zif = zif;
p_zevpn = &zevpn;
ns_walk_func(zebra_evpn_map_vlan_ns, (void *)&in_param, (void **)p_zevpn); zebra_ns_ifp_walk_all(zebra_evpn_map_vlan_ns, &in_param);
return zevpn;
return in_param.zevpn;
} }
static int zebra_evpn_from_svi_ns(struct ns *ns, /* Callback for from_svi ifp walker */
void *_in_param, static int zebra_evpn_from_svi_ns(struct interface *tmp_if, void *_in_param)
void **_p_zevpn)
{ {
struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct interface *br_if; struct interface *br_if;
struct zebra_evpn **p_zevpn = (struct zebra_evpn **)_p_zevpn;
struct zebra_evpn *zevpn; struct zebra_evpn *zevpn;
struct interface *tmp_if = NULL;
struct zebra_if *zif; struct zebra_if *zif;
struct zebra_if *br_zif; struct zebra_if *br_zif;
struct zebra_l2_bridge_vlan *bvlan; struct zebra_from_svi_param *in_param = _in_param;
struct zebra_from_svi_param *in_param = bool found = false;
(struct zebra_from_svi_param *)_in_param;
int found = 0;
vni_t vni_id = 0; vni_t vni_id = 0;
vlanid_t vid = 0;
uint8_t bridge_vlan_aware;
if (!in_param) if (!in_param)
return NS_WALK_STOP; return NS_WALK_STOP;
@ -728,48 +702,30 @@ static int zebra_evpn_from_svi_ns(struct ns *ns,
br_if = in_param->br_if; br_if = in_param->br_if;
zif = in_param->zif; zif = in_param->zif;
assert(zif); assert(zif);
bridge_vlan_aware = in_param->bridge_vlan_aware;
vid = in_param->vid;
br_zif = br_if->info; br_zif = br_if->info;
assert(br_zif); assert(br_zif);
if (bridge_vlan_aware) { if (!tmp_if)
bvlan = zebra_l2_bridge_if_vlan_find(br_zif, vid); goto done;
if (bvlan && bvlan->access_bd && bvlan->access_bd->vni) { zif = tmp_if->info;
found = 1; if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
vni_id = bvlan->access_bd->vni; goto done;
} if (!if_is_operative(tmp_if))
} else { goto done;
/* TODO: Optimize with a hash. */
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;
if (zif->brslave_info.br_if != br_if) if (zif->brslave_info.br_if != br_if)
continue; goto done;
vni_id = vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
zebra_vxlan_if_access_vlan_vni_find(zif, br_if); if (vni_id)
if (vni_id) { found = true;
found = 1;
route_unlock_node(rn);
break;
}
}
}
done:
if (!found) if (!found)
return NS_WALK_CONTINUE; return NS_WALK_CONTINUE;
zevpn = zebra_evpn_lookup(vni_id); zevpn = zebra_evpn_lookup(vni_id);
if (p_zevpn) in_param->zevpn = zevpn;
*p_zevpn = zevpn;
return NS_WALK_STOP; return NS_WALK_STOP;
} }
@ -780,17 +736,21 @@ static int zebra_evpn_from_svi_ns(struct ns *ns,
struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp, struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
struct interface *br_if) struct interface *br_if)
{ {
struct zebra_evpn *zevpn = NULL;
struct zebra_evpn **p_zevpn;
struct zebra_if *zif; struct zebra_if *zif;
struct zebra_from_svi_param in_param; struct zebra_l2_bridge_vlan *bvlan;
struct zebra_from_svi_param in_param = {};
vni_t vni_id = 0;
struct zebra_evpn *zevpn;
struct zebra_l2info_vlan *vl;
if (!br_if) if (!br_if)
return NULL; return NULL;
/* Make sure the linked interface is a bridge. */ /* Make sure the linked interface is a bridge. */
if (!IS_ZEBRA_IF_BRIDGE(br_if)) if (!IS_ZEBRA_IF_BRIDGE(br_if)) {
zlog_debug("%s: br_if NOT a bridge", __func__);
return NULL; return NULL;
}
/* Determine if bridge is VLAN-aware or not */ /* Determine if bridge is VLAN-aware or not */
zif = br_if->info; zif = br_if->info;
@ -798,57 +758,60 @@ struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif); in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
in_param.vid = 0; in_param.vid = 0;
/* Don't need to search in this case */
if (in_param.bridge_vlan_aware) { if (in_param.bridge_vlan_aware) {
struct zebra_l2info_vlan *vl;
if (!IS_ZEBRA_IF_VLAN(ifp)) if (!IS_ZEBRA_IF_VLAN(ifp))
return NULL; return NULL;
zevpn = NULL;
zif = ifp->info; zif = ifp->info;
assert(zif); assert(zif);
vl = &zif->l2info.vl; vl = &zif->l2info.vl;
in_param.vid = vl->vid; in_param.vid = vl->vid;
bvlan = zebra_l2_bridge_if_vlan_find(br_if->info, vl->vid);
if (bvlan && bvlan->access_bd && bvlan->access_bd->vni) {
vni_id = bvlan->access_bd->vni;
zevpn = zebra_evpn_lookup(vni_id);
}
return zevpn;
} }
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN:
* search all NSes
*/
in_param.br_if = br_if; in_param.br_if = br_if;
in_param.zif = zif; in_param.zif = zif;
p_zevpn = &zevpn; zebra_ns_ifp_walk_all(zebra_evpn_from_svi_ns, &in_param);
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
ns_walk_func(zebra_evpn_from_svi_ns, (void *)&in_param, return in_param.zevpn;
(void **)p_zevpn);
return zevpn;
} }
static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp) static int zvni_map_to_macvlan_ns(struct interface *tmp_if, void *_in_param)
{ {
struct zebra_ns *zns = ns->info; struct zebra_from_svi_param *in_param = _in_param;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
struct interface **p_ifp = (struct interface **)_p_ifp;
struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif; struct zebra_if *zif;
assert(in_param && p_ifp); assert(in_param);
/* Identify corresponding VLAN interface. */ /* Identify corresponding VLAN interface. */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
/* Check oper status of the SVI. */
if (!tmp_if || !if_is_operative(tmp_if))
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN) /* Check oper status of the SVI. */
continue; if (!tmp_if || !if_is_operative(tmp_if))
goto done;
if (zif->link == in_param->svi_if) { zif = tmp_if->info;
*p_ifp = tmp_if; if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
route_unlock_node(rn); goto done;
return NS_WALK_STOP;
} if (zif->link == in_param->svi_if) {
in_param->ret_ifp = tmp_if;
return NS_WALK_STOP;
} }
done:
return NS_WALK_CONTINUE; return NS_WALK_CONTINUE;
} }
@ -857,17 +820,16 @@ static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp)
struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if, struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
struct interface *svi_if) struct interface *svi_if)
{ {
struct interface *tmp_if = NULL;
struct zebra_if *zif; struct zebra_if *zif;
struct interface **p_ifp; struct zebra_from_svi_param in_param = {};
struct zebra_from_svi_param in_param;
/* Defensive check, caller expected to invoke only with valid bridge. */ /* Defensive check, caller expected to invoke only with valid bridge. */
if (!br_if) if (!br_if)
return NULL; return NULL;
if (!svi_if) { if (!svi_if) {
zlog_debug("svi_if is not passed."); if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("%s: svi_if is not passed.", __func__);
return NULL; return NULL;
} }
@ -879,11 +841,10 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
in_param.br_if = br_if; in_param.br_if = br_if;
in_param.zif = NULL; in_param.zif = NULL;
in_param.svi_if = svi_if; in_param.svi_if = svi_if;
p_ifp = &tmp_if;
/* Identify corresponding VLAN interface. */ /* Identify corresponding VLAN interface. */
ns_walk_func(zvni_map_to_macvlan_ns, (void *)&in_param, (void **)p_ifp); zebra_ns_ifp_walk_all(zvni_map_to_macvlan_ns, &in_param);
return tmp_if; return in_param.ret_ifp;
} }
/* /*

View File

@ -116,7 +116,10 @@ struct zebra_evpn {
struct zebra_from_svi_param { struct zebra_from_svi_param {
struct interface *br_if; struct interface *br_if;
struct interface *svi_if; struct interface *svi_if;
struct interface *ret_ifp;
struct zebra_if *zif; struct zebra_if *zif;
struct zebra_evpn *zevpn;
struct zebra_l3vni *zl3vni;
uint8_t bridge_vlan_aware; uint8_t bridge_vlan_aware;
vlanid_t vid; vlanid_t vid;
}; };

View File

@ -28,9 +28,185 @@
extern struct zebra_privs_t zserv_privs; extern struct zebra_privs_t zserv_privs;
DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_NS, "Zebra Name Space"); DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_NS, "Zebra Name Space");
DEFINE_MTYPE_STATIC(ZEBRA, ZNS_IFP, "Zebra NS Ifp");
static int ifp_tree_cmp(const struct ifp_tree_link *a, const struct ifp_tree_link *b);
DECLARE_RBTREE_UNIQ(ifp_tree, struct ifp_tree_link, link, ifp_tree_cmp);
static struct zebra_ns *dzns; static struct zebra_ns *dzns;
static int ifp_tree_cmp(const struct ifp_tree_link *a, const struct ifp_tree_link *b)
{
return (a->ifindex - b->ifindex);
}
/*
* Link an ifp into its parent NS
*/
void zebra_ns_link_ifp(struct zebra_ns *zns, struct interface *ifp)
{
struct zebra_if *zif;
struct ifp_tree_link *link, tlink = {};
zif = ifp->info;
assert(zif != NULL);
if (zif->ns_tree_link) {
assert(zif->ns_tree_link->zns == zns);
assert(zif->ns_tree_link->ifp == ifp);
return;
}
/* Lookup first - already linked? */
tlink.ifindex = ifp->ifindex;
link = ifp_tree_find(&zns->ifp_tree, &tlink);
if (link) {
assert(link->ifp == ifp);
return;
}
/* Allocate new linkage struct and add */
link = XCALLOC(MTYPE_ZNS_IFP, sizeof(struct ifp_tree_link));
link->ifp = ifp;
link->ifindex = ifp->ifindex;
link->zns = zns;
ifp_tree_add(&zns->ifp_tree, link);
zif->ns_tree_link = link;
}
/*
* Unlink an ifp from its parent NS (probably because the ifp is being deleted)
*/
void zebra_ns_unlink_ifp(struct interface *ifp)
{
struct zebra_if *zif;
struct ifp_tree_link *link;
struct zebra_ns *zns;
zif = ifp->info;
if (zif && zif->ns_tree_link) {
link = zif->ns_tree_link;
zns = link->zns;
ifp_tree_del(&zns->ifp_tree, link);
zif->ns_tree_link = NULL;
XFREE(MTYPE_ZNS_IFP, link);
}
}
/*
* ifp lookup apis
*/
struct interface *zebra_ns_lookup_ifp(struct zebra_ns *zns, uint32_t ifindex)
{
struct interface *ifp = NULL;
struct ifp_tree_link *link, tlink = {};
/* Init temp struct for lookup */
tlink.ifindex = ifindex;
link = ifp_tree_find(&zns->ifp_tree, &tlink);
if (link)
ifp = link->ifp;
return ifp;
}
static int lookup_ifp_name_cb(struct interface *ifp, void *arg);
struct ifp_name_ctx {
const char *ifname;
struct interface *ifp;
};
struct interface *zebra_ns_lookup_ifp_name(struct zebra_ns *zns, const char *ifname)
{
struct ifp_name_ctx ctx = {};
/* Hand context struct into walker function for use in its callback */
ctx.ifname = ifname;
zebra_ns_ifp_walk(zns, lookup_ifp_name_cb, &ctx);
return ctx.ifp;
}
static int lookup_ifp_name_cb(struct interface *ifp, void *arg)
{
struct ifp_name_ctx *pctx = arg;
if (strcmp(ifp->name, pctx->ifname) == 0) {
pctx->ifp = ifp;
return NS_WALK_STOP;
}
return NS_WALK_CONTINUE;
}
/* Iterate collection of ifps, calling application's callback. Callback uses
* return semantics from lib/ns.h: return NS_WALK_STOP to stop the iteration.
* Caller's 'arg' is included in each callback.
*/
int zebra_ns_ifp_walk(struct zebra_ns *zns,
int (*func)(struct interface *ifp, void *arg), void *arg)
{
struct ifp_tree_link *link;
int ret = NS_WALK_CONTINUE;
frr_each (ifp_tree, &zns->ifp_tree, link) {
ret = (func)(link->ifp, arg);
if (ret == NS_WALK_STOP)
break;
}
if (ret == NS_WALK_STOP)
return NS_WALK_STOP;
else
return NS_WALK_CONTINUE;
}
/*
* Walk all NSes, and all ifps for each NS.
*/
struct ns_ifp_walk_ctx {
int (*func)(struct interface *ifp, void *arg);
void *arg;
int ret;
};
static int ns_ifp_walker(struct ns *ns, void *in_param, void **unused);
void zebra_ns_ifp_walk_all(int (*func)(struct interface *ifp, void *arg), void *arg)
{
struct ns_ifp_walk_ctx ctx = {};
ctx.func = func;
ctx.arg = arg;
ns_walk_func(ns_ifp_walker, &ctx, NULL);
}
static int ns_ifp_walker(struct ns *ns, void *in_param, void **unused)
{
struct zebra_ns *zns;
struct ns_ifp_walk_ctx *ctx = in_param;
int ret = NS_WALK_CONTINUE;
zns = ns->info;
if (zns == NULL)
goto done;
ret = zebra_ns_ifp_walk(zns, ctx->func, ctx->arg);
done:
return ret;
}
static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete); static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete);
struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id) struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id)
@ -58,7 +234,7 @@ static int zebra_ns_new(struct ns *ns)
zns->ns_id = ns->ns_id; zns->ns_id = ns->ns_id;
/* Do any needed per-NS data structure allocation. */ /* Do any needed per-NS data structure allocation. */
zns->if_table = route_table_init(); ifp_tree_init(&zns->ifp_tree);
return 0; return 0;
} }
@ -66,11 +242,22 @@ static int zebra_ns_new(struct ns *ns)
static int zebra_ns_delete(struct ns *ns) static int zebra_ns_delete(struct ns *ns)
{ {
struct zebra_ns *zns = (struct zebra_ns *)ns->info; struct zebra_ns *zns = (struct zebra_ns *)ns->info;
struct zebra_if *zif;
struct ifp_tree_link *link;
if (IS_ZEBRA_DEBUG_EVENT) if (IS_ZEBRA_DEBUG_EVENT)
zlog_info("ZNS %s with id %u (deleted)", ns->name, ns->ns_id); zlog_info("ZNS %s with id %u (deleted)", ns->name, ns->ns_id);
if (!zns) if (!zns)
return 0; return 0;
/* Clean up ifp tree */
while ((link = ifp_tree_pop(&zns->ifp_tree)) != NULL) {
zif = link->ifp->info;
zif->ns_tree_link = NULL;
XFREE(MTYPE_ZNS_IFP, link);
}
XFREE(MTYPE_ZEBRA_NS, ns->info); XFREE(MTYPE_ZEBRA_NS, ns->info);
return 0; return 0;
} }
@ -157,10 +344,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
*/ */
static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete) static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
{ {
if (zns->if_table)
route_table_finish(zns->if_table);
zns->if_table = NULL;
zebra_dplane_ns_enable(zns, false /*Disable*/); zebra_dplane_ns_enable(zns, false /*Disable*/);
kernel_terminate(zns, complete); kernel_terminate(zns, complete);

View File

@ -32,6 +32,20 @@ struct nlsock {
}; };
#endif #endif
/* Tree of interfaces: external linkage struct, and rbtree */
PREDECL_RBTREE_UNIQ(ifp_tree);
struct ifp_tree_link {
struct ifp_tree_item link;
ifindex_t ifindex;
struct interface *ifp;
/* Backpointer */
struct zebra_ns *zns;
};
struct zebra_ns { struct zebra_ns {
/* net-ns name. */ /* net-ns name. */
char name[VRF_NAMSIZ]; char name[VRF_NAMSIZ];
@ -53,7 +67,8 @@ struct zebra_ns {
struct nlsock ge_netlink_cmd; /* command channel for generic netlink */ struct nlsock ge_netlink_cmd; /* command channel for generic netlink */
#endif #endif
struct route_table *if_table; /* Tree of interfaces in this ns */
struct ifp_tree_head ifp_tree;
/* Back pointer */ /* Back pointer */
struct ns *ns; struct ns *ns;
@ -61,6 +76,23 @@ struct zebra_ns {
struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id); struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id);
/* Manage collection of ifps per-NS */
void zebra_ns_link_ifp(struct zebra_ns *zns, struct interface *ifp);
void zebra_ns_unlink_ifp(struct interface *ifp);
struct interface *zebra_ns_lookup_ifp(struct zebra_ns *zns, uint32_t ifindex);
struct interface *zebra_ns_lookup_ifp_name(struct zebra_ns *zns, const char *ifname);
/* Iterate collection of ifps, calling application's callback. Callback uses
* return semantics from lib/ns.h: return NS_WALK_STOP to stop the iteration.
* Caller's 'arg' is included in each callback.
* The iterator returns STOP or CONTINUE also.
*/
int zebra_ns_ifp_walk(struct zebra_ns *zns,
int (*func)(struct interface *ifp, void *arg), void *arg);
/* Walk all NSes, and all ifps for each NS. */
void zebra_ns_ifp_walk_all(int (*func)(struct interface *ifp, void *arg), void *arg);
int zebra_ns_init(void); int zebra_ns_init(void);
int zebra_ns_enable(ns_id_t ns_id, void **info); int zebra_ns_enable(ns_id_t ns_id, void **info);
int zebra_ns_disabled(struct ns *ns); int zebra_ns_disabled(struct ns *ns);

View File

@ -859,39 +859,30 @@ static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
static int zvni_map_to_svi_ns(struct ns *ns, static int zvni_map_to_svi_ns(struct interface *tmp_if, void *_in_param)
void *_in_param,
void **_p_ifp)
{ {
struct zebra_ns *zns = ns->info; struct zebra_from_svi_param *in_param = _in_param;
struct route_node *rn;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
struct zebra_l2info_vlan *vl; struct zebra_l2info_vlan *vl;
struct interface *tmp_if = NULL;
struct interface **p_ifp = (struct interface **)_p_ifp;
struct zebra_if *zif; struct zebra_if *zif;
assert(in_param && p_ifp); assert(in_param);
/* TODO: Optimize with a hash. */ /* TODO: Optimize with a hash. */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
/* Check oper status of the SVI. */
if (!tmp_if || !if_is_operative(tmp_if))
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_VLAN
|| zif->link != in_param->br_if)
continue;
vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
if (vl->vid == in_param->vid) { /* Check oper status of the SVI. */
*p_ifp = tmp_if; if (!tmp_if || !if_is_operative(tmp_if))
route_unlock_node(rn); goto done;
return NS_WALK_STOP; zif = tmp_if->info;
} if (!zif || zif->zif_type != ZEBRA_IF_VLAN || zif->link != in_param->br_if)
goto done;
vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
if (vl->vid == in_param->vid) {
in_param->ret_ifp = tmp_if;
return NS_WALK_STOP;
} }
done:
return NS_WALK_CONTINUE; return NS_WALK_CONTINUE;
} }
@ -904,10 +895,9 @@ static int zvni_map_to_svi_ns(struct ns *ns,
*/ */
struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if) struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
{ {
struct interface *tmp_if = NULL;
struct zebra_if *zif; struct zebra_if *zif;
struct zebra_from_svi_param in_param; struct zebra_from_svi_param in_param = {};
struct interface **p_ifp;
/* Defensive check, caller expected to invoke only with valid bridge. */ /* Defensive check, caller expected to invoke only with valid bridge. */
if (!br_if) if (!br_if)
return NULL; return NULL;
@ -922,12 +912,11 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
in_param.vid = vid; in_param.vid = vid;
in_param.br_if = br_if; in_param.br_if = br_if;
in_param.zif = NULL;
p_ifp = &tmp_if;
/* Identify corresponding VLAN interface. */ /* Identify corresponding VLAN interface. */
ns_walk_func(zvni_map_to_svi_ns, (void *)&in_param, zebra_ns_ifp_walk_all(zvni_map_to_svi_ns, &in_param);
(void **)p_ifp);
return tmp_if; return in_param.ret_ifp;
} }
int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn) int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn)
@ -1007,9 +996,9 @@ static int zevpn_build_vni_hash_table(struct zebra_if *zif,
*/ */
zevpn = zebra_evpn_lookup(vni); zevpn = zebra_evpn_lookup(vni);
if (zevpn) { if (zevpn) {
zlog_debug( if (IS_ZEBRA_DEBUG_VXLAN)
"EVPN hash already present for IF %s(%u) L2-VNI %u", zlog_debug("EVPN hash already present for IF %s(%u) L2-VNI %u",
ifp->name, ifp->ifindex, vni); ifp->name, ifp->ifindex, vni);
/* /*
* Inform BGP if intf is up and mapped to * Inform BGP if intf is up and mapped to
@ -1072,48 +1061,32 @@ static int zevpn_build_vni_hash_table(struct zebra_if *zif,
return 0; return 0;
} }
static int zevpn_build_hash_table_zns(struct ns *ns, static int zevpn_build_hash_table_zns(struct interface *ifp, void *arg)
void *param_in __attribute__((unused)),
void **param_out __attribute__((unused)))
{ {
struct zebra_ns *zns = ns->info; struct zebra_vrf *zvrf = arg;
struct route_node *rn; struct zebra_if *zif;
struct interface *ifp; struct zebra_l2info_vxlan *vxl;
struct zebra_vrf *zvrf;
zvrf = zebra_vrf_get_evpn(); zif = ifp->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
/* Walk VxLAN interfaces and create EVPN hash. */ goto done;
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
ifp = (struct interface *)rn->info;
if (!ifp)
continue;
zif = ifp->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
continue;
vxl = &zif->l2info.vxl;
/* link of VXLAN interface should be in zebra_evpn_vrf */
if (zvrf->zns->ns_id != vxl->link_nsid) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"Intf %s(%u) link not in same "
"namespace than BGP EVPN core instance ",
ifp->name, ifp->ifindex);
continue;
}
vxl = &zif->l2info.vxl;
/* link of VXLAN interface should be in zebra_evpn_vrf */
if (zvrf->zns->ns_id != vxl->link_nsid) {
if (IS_ZEBRA_DEBUG_VXLAN) if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("Building vni table for %s-if %s", zlog_debug("Intf %s(%u) link not in same namespace as BGP EVPN core instance",
IS_ZEBRA_VXLAN_IF_VNI(zif) ? "vni" : "svd", ifp->name, ifp->ifindex);
ifp->name); goto done;
zebra_vxlan_if_vni_iterate(zif, zevpn_build_vni_hash_table,
NULL);
} }
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("Building vni table for %s-if %s",
IS_ZEBRA_VXLAN_IF_VNI(zif) ? "vni" : "svd", ifp->name);
zebra_vxlan_if_vni_iterate(zif, zevpn_build_vni_hash_table, NULL);
done:
return NS_WALK_CONTINUE; return NS_WALK_CONTINUE;
} }
@ -1124,7 +1097,13 @@ static int zevpn_build_hash_table_zns(struct ns *ns,
static void zevpn_build_hash_table(void) static void zevpn_build_hash_table(void)
{ {
ns_walk_func(zevpn_build_hash_table_zns, NULL, NULL); struct zebra_vrf *zvrf;
zvrf = zebra_vrf_get_evpn();
if (zvrf == NULL)
return;
zebra_ns_ifp_walk_all(zevpn_build_hash_table_zns, zvrf);
} }
/* /*
@ -1968,70 +1947,63 @@ static int zl3vni_del(struct zebra_l3vni *zl3vni)
return 0; return 0;
} }
static int zl3vni_map_to_vxlan_if_ns(struct ns *ns, /* Context arg for zl3vni map iteration */
void *_zl3vni, struct zl3vni_map_arg {
void **_pifp)
{
struct zebra_ns *zns = ns->info;
struct zebra_l3vni *zl3vni = (struct zebra_l3vni *)_zl3vni;
struct route_node *rn = NULL;
struct interface *ifp = NULL;
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
struct zebra_l3vni *zl3vni;
struct interface *ret_ifp;
};
zvrf = zebra_vrf_get_evpn(); static int zl3vni_map_to_vxlan_if_ns(struct interface *ifp, void *arg)
{
struct zl3vni_map_arg *ctx = arg;
struct zebra_l3vni *zl3vni = ctx->zl3vni;
struct zebra_vrf *zvrf = ctx->zvrf;
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl;
struct zebra_vxlan_vni *vni = NULL;
assert(_pifp); /* look for vxlan-interface */
/* loop through all vxlan-interface */ zif = ifp->info;
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
goto done;
struct zebra_if *zif = NULL; vxl = &zif->l2info.vxl;
struct zebra_l2info_vxlan *vxl; vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
struct zebra_vxlan_vni *vni = NULL; if (!vni || vni->vni != zl3vni->vni)
goto done;
ifp = (struct interface *)rn->info; /* link of VXLAN interface should be in zebra_evpn_vrf */
if (!ifp) if (zvrf->zns->ns_id != vxl->link_nsid) {
continue; if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("Intf %s(%u) VNI %u, link not in same namespace as BGP EVPN core instance",
zif = ifp->info; ifp->name, ifp->ifindex, vni->vni);
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) goto done;
continue;
vxl = &zif->l2info.vxl;
vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
if (!vni || vni->vni != zl3vni->vni)
continue;
/* link of VXLAN interface should be in zebra_evpn_vrf */
if (zvrf->zns->ns_id != vxl->link_nsid) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"Intf %s(%u) VNI %u, link not in same "
"namespace than BGP EVPN core instance ",
ifp->name, ifp->ifindex, vni->vni);
continue;
}
zl3vni->local_vtep_ip = zif->l2info.vxl.vtep_ip;
*_pifp = (void *)ifp;
route_unlock_node(rn);
return NS_WALK_STOP;
} }
zl3vni->local_vtep_ip = zif->l2info.vxl.vtep_ip;
ctx->ret_ifp = ifp;
return NS_WALK_STOP;
done:
return NS_WALK_CONTINUE; return NS_WALK_CONTINUE;
} }
struct interface *zl3vni_map_to_vxlan_if(struct zebra_l3vni *zl3vni) struct interface *zl3vni_map_to_vxlan_if(struct zebra_l3vni *zl3vni)
{ {
struct interface **p_ifp; struct zl3vni_map_arg arg = {};
struct interface *ifp = NULL;
p_ifp = &ifp; arg.zl3vni = zl3vni;
arg.zvrf = zebra_vrf_get_evpn();
ns_walk_func(zl3vni_map_to_vxlan_if_ns, if (arg.zvrf == NULL)
(void *)zl3vni, (void **)p_ifp); return NULL;
return ifp;
zebra_ns_ifp_walk_all(zl3vni_map_to_vxlan_if_ns, &arg);
return arg.ret_ifp;
} }
struct interface *zl3vni_map_to_svi_if(struct zebra_l3vni *zl3vni) struct interface *zl3vni_map_to_svi_if(struct zebra_l3vni *zl3vni)
@ -2086,57 +2058,35 @@ struct zebra_l3vni *zl3vni_from_vrf(vrf_id_t vrf_id)
return zl3vni_lookup(zvrf->l3vni); return zl3vni_lookup(zvrf->l3vni);
} }
static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni) /* loop through all vxlan-interface */
static int zl3vni_from_svi_ns(struct interface *tmp_if, void *_in_param)
{ {
int found = 0; int found = 0;
vni_t vni_id = 0; vni_t vni_id = 0;
struct zebra_ns *zns = ns->info; struct zebra_from_svi_param *in_param = _in_param;
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_if *zif = NULL;
struct zebra_if *br_zif = NULL;
assert(in_param && p_zl3vni); assert(in_param);
br_zif = in_param->br_if->info; zif = tmp_if->info;
assert(br_zif); if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
goto done;
if (!if_is_operative(tmp_if))
goto done;
if (in_param->bridge_vlan_aware) { if (zif->brslave_info.br_if != in_param->br_if)
vni_id = zebra_l2_bridge_if_vni_find(br_zif, in_param->vid); goto done;
if (vni_id)
found = 1;
} else {
/* 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;
if (zif->brslave_info.br_if != in_param->br_if) vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, in_param->br_if);
continue; if (vni_id) {
in_param->zl3vni = zl3vni_lookup(vni_id);
vni_id = zebra_vxlan_if_access_vlan_vni_find( found = 1;
zif, in_param->br_if);
if (vni_id) {
found = 1;
route_unlock_node(rn);
break;
}
}
} }
done:
if (!found) if (!found)
return NS_WALK_CONTINUE; return NS_WALK_CONTINUE;
*p_zl3vni = zl3vni_lookup(vni_id);
return NS_WALK_STOP; return NS_WALK_STOP;
} }
@ -2147,10 +2097,11 @@ static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni)
static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp, static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
struct interface *br_if) struct interface *br_if)
{ {
struct zebra_l3vni *zl3vni = NULL;
struct zebra_if *zif = NULL; struct zebra_if *zif = NULL;
vni_t vni_id = 0;
struct zebra_if *br_zif = NULL;
struct zebra_from_svi_param in_param = {}; struct zebra_from_svi_param in_param = {};
struct zebra_l3vni **p_zl3vni; struct zebra_l2info_vlan *vl;
if (!br_if) if (!br_if)
return NULL; return NULL;
@ -2158,15 +2109,15 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
/* Make sure the linked interface is a bridge. */ /* Make sure the linked interface is a bridge. */
if (!IS_ZEBRA_IF_BRIDGE(br_if)) if (!IS_ZEBRA_IF_BRIDGE(br_if))
return NULL; return NULL;
in_param.br_if = br_if; in_param.br_if = br_if;
/* Determine if bridge is VLAN-aware or not */ /* Determine if bridge is VLAN-aware or not */
zif = br_if->info; br_zif = br_if->info;
assert(zif); assert(br_zif);
in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
if (in_param.bridge_vlan_aware) {
struct zebra_l2info_vlan *vl;
in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif);
if (in_param.bridge_vlan_aware) {
if (!IS_ZEBRA_IF_VLAN(ifp)) if (!IS_ZEBRA_IF_VLAN(ifp))
return NULL; return NULL;
@ -2174,15 +2125,18 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
assert(zif); assert(zif);
vl = &zif->l2info.vl; vl = &zif->l2info.vl;
in_param.vid = vl->vid; in_param.vid = vl->vid;
vni_id = zebra_l2_bridge_if_vni_find(br_zif, in_param.vid);
if (vni_id)
return zl3vni_lookup(vni_id);
} }
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
/* TODO: Optimize with a hash. */ /* TODO: Optimize with a hash. */
p_zl3vni = &zl3vni; zebra_ns_ifp_walk_all(zl3vni_from_svi_ns, &in_param);
ns_walk_func(zl3vni_from_svi_ns, (void *)&in_param, (void **)p_zl3vni); return in_param.zl3vni;
return zl3vni;
} }
vni_t vni_id_from_svi(struct interface *ifp, struct interface *br_if) vni_t vni_id_from_svi(struct interface *ifp, struct interface *br_if)
@ -2336,6 +2290,36 @@ static void zevpn_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt)
listnode_add_sort(zl3vni->l2vnis, zevpn); listnode_add_sort(zl3vni->l2vnis, zevpn);
} }
/* Helper for vni transition iterator */
struct vni_trans_ctx {
vni_t vni;
struct zebra_vxlan_vni *vnip;
struct interface *ret_ifp;
};
static int vni_trans_cb(struct interface *ifp, void *arg)
{
struct vni_trans_ctx *ctx = arg;
struct zebra_if *zif;
struct zebra_vxlan_vni *vnip;
/* Find VxLAN interface for this VNI. */
zif = ifp->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
goto done;
vnip = zebra_vxlan_if_vni_find(zif, ctx->vni);
if (vnip) {
ctx->ret_ifp = ifp;
ctx->vnip = vnip;
return NS_WALK_STOP;
}
done:
return NS_WALK_CONTINUE;
}
/* /*
* Handle transition of vni from l2 to l3 and vice versa. * Handle transition of vni from l2 to l3 and vice versa.
* This function handles only the L2VNI add/delete part of * This function handles only the L2VNI add/delete part of
@ -2386,39 +2370,25 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
return -1; return -1;
} }
} else { } else {
struct zebra_ns *zns;
struct route_node *rn;
struct interface *ifp;
struct zebra_if *zif;
struct zebra_vxlan_vni *vnip; struct zebra_vxlan_vni *vnip;
struct zebra_l2info_vxlan *vxl; struct zebra_l2info_vxlan *vxl;
struct interface *vlan_if; struct interface *vlan_if;
bool found = false; struct zebra_if *zif;
struct zebra_ns *zns;
struct vni_trans_ctx ctx = {};
if (IS_ZEBRA_DEBUG_VXLAN) if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("Adding L2-VNI %u - transition from L3-VNI", zlog_debug("Adding L2-VNI %u - transition from L3-VNI",
vni); vni);
/* Find VxLAN interface for this VNI. */
zns = zebra_ns_lookup(NS_DEFAULT); zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
ifp = (struct interface *)rn->info;
if (!ifp)
continue;
zif = ifp->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
continue;
vxl = &zif->l2info.vxl; ctx.vni = vni;
vnip = zebra_vxlan_if_vni_find(zif, vni);
if (vnip) {
found = true;
route_unlock_node(rn);
break;
}
}
if (!found) { /* Find VxLAN interface for this VNI. */
zebra_ns_ifp_walk(zns, vni_trans_cb, &ctx);
if (ctx.ret_ifp == NULL) {
if (IS_ZEBRA_DEBUG_VXLAN) if (IS_ZEBRA_DEBUG_VXLAN)
zlog_err( zlog_err(
"Adding L2-VNI - Failed to find VxLAN interface for VNI %u", "Adding L2-VNI - Failed to find VxLAN interface for VNI %u",
@ -2431,6 +2401,10 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
if (zevpn) if (zevpn)
return 0; return 0;
zif = ctx.ret_ifp->info;
vnip = ctx.vnip;
vxl = &zif->l2info.vxl;
zevpn = zebra_evpn_add(vni); zevpn = zebra_evpn_add(vni);
/* Find bridge interface for the VNI */ /* Find bridge interface for the VNI */
@ -2443,13 +2417,13 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
} }
zevpn->vxlan_if = ifp; zevpn->vxlan_if = ctx.ret_ifp;
zevpn->local_vtep_ip = vxl->vtep_ip; zevpn->local_vtep_ip = vxl->vtep_ip;
/* Inform BGP if the VNI is up and mapped to a bridge. */ /* Inform BGP if the VNI is up and mapped to a bridge. */
if (if_is_operative(ifp) && zif->brslave_info.br_if) { if (if_is_operative(ctx.ret_ifp) && zif->brslave_info.br_if) {
zebra_evpn_send_add_to_client(zevpn); zebra_evpn_send_add_to_client(zevpn);
zebra_evpn_read_mac_neigh(zevpn, ifp); zebra_evpn_read_mac_neigh(zevpn, ctx.ret_ifp);
} }
} }