diff --git a/isisd/isis_route.h b/isisd/isis_route.h index 4d49a5ae9cf5..d9572336af5d 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -12,6 +12,7 @@ #ifndef _ZEBRA_ISIS_ROUTE_H #define _ZEBRA_ISIS_ROUTE_H +#include "lib/table.h" #include "lib/nexthop.h" struct isis_nexthop { diff --git a/lib/if.c b/lib/if.c index 8f15230f2334..378ca16e4957 100644 --- a/lib/if.c +++ b/lib/if.c @@ -1002,12 +1002,6 @@ void if_terminate(struct vrf *vrf) while (!RB_EMPTY(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); } } diff --git a/lib/if.h b/lib/if.h index 0dc56bd21098..c2ec73378d85 100644 --- a/lib/if.h +++ b/lib/if.h @@ -295,8 +295,6 @@ struct interface { struct if_data stats; #endif /* HAVE_NET_RT_IFLIST */ - struct route_node *node; - struct vrf *vrf; /* diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 62b665682ff6..7ef3fa2e61f7 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1568,6 +1568,15 @@ static int netlink_request_tunneldump(struct zebra_ns *zns, int family, 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. * 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 ret = 0; + struct tunneldump_ctx ctx = {}; 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*/); - 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; + /* Set up context and call iterator */ + ctx.zns = zns; + ctx.dp_info = &dp_info; - ret = netlink_request_tunneldump(zns, PF_BRIDGE, - tmp_if->ifindex); - if (ret < 0) { - route_unlock_node(rn); - return ret; - } + zebra_ns_ifp_walk(zns, tunneldump_walk_cb, &ctx); - ret = netlink_parse_info(netlink_link_change, netlink_cmd, - &dp_info, 0, true); + ret = ctx.ret; - if (ret < 0) { - route_unlock_node(rn); - return ret; - } + 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) diff --git a/zebra/interface.c b/zebra/interface.c index f1f1b17209a7..86de5dbae68e 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -43,7 +43,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information"); DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *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); @@ -215,6 +215,8 @@ static int if_zebra_delete_hook(struct interface *ifp) if_nhg_dependents_release(ifp); nhg_connected_tree_free(&zebra_if->nhg_dependents); + zebra_ns_unlink_ifp(ifp); + XFREE(MTYPE_ZIF_DESC, zebra_if->desc); EVENT_OFF(zebra_if->speed_update); @@ -225,62 +227,14 @@ static int if_zebra_delete_hook(struct interface *ifp) 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 */ struct interface *if_lookup_by_index_per_ns(struct zebra_ns *ns, uint32_t ifindex) { - struct prefix p; - struct route_node *rn; struct interface *ifp = NULL; - if_build_key(ifindex, &p); - rn = route_node_lookup(ns->if_table, &p); - if (rn) { - ifp = (struct interface *)rn->info; - route_unlock_node(rn); /* lookup */ - } + ifp = zebra_ns_lookup_ifp(ns, ifindex); + 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, const char *ifname) { - struct route_node *rn; struct interface *ifp; - for (rn = route_top(ns->if_table); rn; rn = route_next(rn)) { - ifp = (struct interface *)rn->info; - if (ifp && strcmp(ifp->name, ifname) == 0) { - route_unlock_node(rn); - return (ifp); - } - } + ifp = zebra_ns_lookup_ifp_name(ns, ifname); - return NULL; + return ifp; } 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; else zns = zebra_ns_lookup(NS_DEFAULT); - if_link_per_ns(zns, ifp); + + zebra_ns_link_ifp(zns, ifp); if_data = ifp->info; assert(if_data); @@ -776,7 +724,7 @@ void if_delete_update(struct interface **pifp) /* Send out notification on interface delete. */ 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 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 interface deletion message. */ if_set_index(ifp, IFINDEX_INTERNAL); - ifp->node = NULL; UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); @@ -1082,50 +1029,52 @@ void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex, } /* - * 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 + * Callback for per-ns link fixup iteration */ -void zebra_if_update_all_links(struct zebra_ns *zns) +static int zif_link_fixup_cb(struct interface *ifp, void *arg) { - struct route_node *rn; - struct interface *ifp; struct zebra_if *zif; - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_info("fixup link dependencies"); + 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); + } - for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { - 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 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)); - /* 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 + * upper devices so we need to fixup link dependencies at the end of dump + */ +void zebra_if_update_all_links(struct zebra_ns *zns) +{ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("fixup link dependencies"); + + zebra_ns_ifp_walk(zns, zif_link_fixup_cb, NULL); } static bool if_ignore_set_protodown(const struct interface *ifp, bool new_down, diff --git a/zebra/interface.h b/zebra/interface.h index 8d19c1838fbf..2c7a079bf474 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -94,9 +94,6 @@ enum zebra_if_flags { #define ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) \ ((zif)->protodown_rc == ZEBRA_PROTODOWN_EXTERNAL) -/* Mem type for zif desc */ -DECLARE_MTYPE(ZIF_DESC); - /* `zebra' daemon local interface structure. */ struct zebra_if { /* back pointer to the interface */ @@ -215,6 +212,9 @@ struct zebra_if { char neigh_mac[6]; 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 */ 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_name_per_ns(struct zebra_ns *, 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, uint32_t ifindex); 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, char mac[6], struct in6_addr *address, diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index a733b5917f94..0ad42ebd5b0d 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -610,70 +610,47 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket, return; } -static int zebra_evpn_map_vlan_ns(struct ns *ns, - void *_in_param, - void **_p_zevpn) +/* Callback for per-NS ifp walk */ +static int zebra_evpn_map_vlan_ns(struct interface *tmp_if, void *_in_param) { - int found = 0; - struct zebra_ns *zns = ns->info; - struct route_node *rn; + bool found = false; struct interface *br_if; - struct zebra_evpn **p_zevpn = (struct zebra_evpn **)_p_zevpn; struct zebra_evpn *zevpn; - struct interface *tmp_if = NULL; struct zebra_if *zif; - struct zebra_from_svi_param *in_param = - (struct zebra_from_svi_param *)_in_param; - vlanid_t vid; + struct zebra_from_svi_param *in_param = _in_param; vni_t vni_id = 0; - uint8_t bridge_vlan_aware; - assert(p_zevpn && in_param); + assert(in_param); br_if = in_param->br_if; assert(br_if); zif = in_param->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); - if (vni_id) - found = 1; - } else { - /* - * See if this interface (or interface plus VLAN Id) maps to a - * VxLAN - */ - /* 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) - continue; - - vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if); - if (vni_id) { - found = 1; - route_unlock_node(rn); - break; - } - } - } + /* + * See if this interface (or interface plus VLAN Id) maps to a + * VxLAN + */ + /* TODO: Optimize with a hash. */ + zif = tmp_if->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + goto done; + if (!if_is_operative(tmp_if)) + goto done; + + if (zif->brslave_info.br_if != br_if) + goto done; + + vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if); + if (vni_id) + found = true; +done: if (!found) return NS_WALK_CONTINUE; zevpn = zebra_evpn_lookup(vni_id); - *p_zevpn = zevpn; + in_param->zevpn = zevpn; 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 zebra_if *zif; - struct zebra_evpn **p_zevpn; - struct zebra_evpn *zevpn = NULL; - struct zebra_from_svi_param in_param; + struct zebra_from_svi_param in_param = {}; + vni_t vni_id = 0; /* Determine if bridge is VLAN-aware or not */ zif = br_if->info; 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.br_if = br_if; in_param.zif = zif; - p_zevpn = &zevpn; - ns_walk_func(zebra_evpn_map_vlan_ns, (void *)&in_param, (void **)p_zevpn); - return zevpn; + zebra_ns_ifp_walk_all(zebra_evpn_map_vlan_ns, &in_param); + + return in_param.zevpn; } -static int zebra_evpn_from_svi_ns(struct ns *ns, - void *_in_param, - void **_p_zevpn) +/* Callback for from_svi ifp walker */ +static int zebra_evpn_from_svi_ns(struct interface *tmp_if, void *_in_param) { - struct zebra_ns *zns = ns->info; - struct route_node *rn; struct interface *br_if; - struct zebra_evpn **p_zevpn = (struct zebra_evpn **)_p_zevpn; struct zebra_evpn *zevpn; - struct interface *tmp_if = NULL; struct zebra_if *zif; struct zebra_if *br_zif; - struct zebra_l2_bridge_vlan *bvlan; - struct zebra_from_svi_param *in_param = - (struct zebra_from_svi_param *)_in_param; - int found = 0; + struct zebra_from_svi_param *in_param = _in_param; + bool found = false; vni_t vni_id = 0; - vlanid_t vid = 0; - uint8_t bridge_vlan_aware; if (!in_param) return NS_WALK_STOP; @@ -728,48 +702,30 @@ static int zebra_evpn_from_svi_ns(struct ns *ns, br_if = in_param->br_if; zif = in_param->zif; assert(zif); - bridge_vlan_aware = in_param->bridge_vlan_aware; - vid = in_param->vid; br_zif = br_if->info; assert(br_zif); - if (bridge_vlan_aware) { - bvlan = zebra_l2_bridge_if_vlan_find(br_zif, vid); - if (bvlan && bvlan->access_bd && bvlan->access_bd->vni) { - found = 1; - vni_id = bvlan->access_bd->vni; - } - } else { - /* 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) - continue; - - vni_id = - zebra_vxlan_if_access_vlan_vni_find(zif, br_if); - if (vni_id) { - found = 1; - route_unlock_node(rn); - break; - } - } - } + if (!tmp_if) + goto done; + zif = tmp_if->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + goto done; + if (!if_is_operative(tmp_if)) + goto done; + + if (zif->brslave_info.br_if != br_if) + goto done; + + vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if); + if (vni_id) + found = true; +done: if (!found) return NS_WALK_CONTINUE; zevpn = zebra_evpn_lookup(vni_id); - if (p_zevpn) - *p_zevpn = zevpn; + in_param->zevpn = zevpn; 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 interface *br_if) { - struct zebra_evpn *zevpn = NULL; - struct zebra_evpn **p_zevpn; 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) return NULL; /* 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; + } /* Determine if bridge is VLAN-aware or not */ 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.vid = 0; + /* Don't need to search in this case */ if (in_param.bridge_vlan_aware) { - struct zebra_l2info_vlan *vl; - if (!IS_ZEBRA_IF_VLAN(ifp)) return NULL; + zevpn = NULL; + zif = ifp->info; assert(zif); vl = &zif->l2info.vl; 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.zif = zif; - p_zevpn = &zevpn; - /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ - ns_walk_func(zebra_evpn_from_svi_ns, (void *)&in_param, - (void **)p_zevpn); - return zevpn; + zebra_ns_ifp_walk_all(zebra_evpn_from_svi_ns, &in_param); + + return in_param.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 = - (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_from_svi_param *in_param = _in_param; struct zebra_if *zif; - assert(in_param && p_ifp); + assert(in_param); /* 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) - continue; + /* Check oper status of the SVI. */ + if (!tmp_if || !if_is_operative(tmp_if)) + goto done; - if (zif->link == in_param->svi_if) { - *p_ifp = tmp_if; - route_unlock_node(rn); - return NS_WALK_STOP; - } + zif = tmp_if->info; + if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN) + goto done; + + if (zif->link == in_param->svi_if) { + in_param->ret_ifp = tmp_if; + return NS_WALK_STOP; } +done: 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 *svi_if) { - struct interface *tmp_if = NULL; 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. */ if (!br_if) return NULL; 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; } @@ -879,11 +841,10 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if, in_param.br_if = br_if; in_param.zif = NULL; in_param.svi_if = svi_if; - p_ifp = &tmp_if; /* Identify corresponding VLAN interface. */ - ns_walk_func(zvni_map_to_macvlan_ns, (void *)&in_param, (void **)p_ifp); - return tmp_if; + zebra_ns_ifp_walk_all(zvni_map_to_macvlan_ns, &in_param); + return in_param.ret_ifp; } /* diff --git a/zebra/zebra_evpn.h b/zebra/zebra_evpn.h index c946425dd52f..0ffebdd2774f 100644 --- a/zebra/zebra_evpn.h +++ b/zebra/zebra_evpn.h @@ -116,7 +116,10 @@ struct zebra_evpn { struct zebra_from_svi_param { struct interface *br_if; struct interface *svi_if; + struct interface *ret_ifp; struct zebra_if *zif; + struct zebra_evpn *zevpn; + struct zebra_l3vni *zl3vni; uint8_t bridge_vlan_aware; vlanid_t vid; }; diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index ffd749fcf17e..771e7d671998 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -28,9 +28,185 @@ extern struct zebra_privs_t zserv_privs; 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 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); 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; /* Do any needed per-NS data structure allocation. */ - zns->if_table = route_table_init(); + ifp_tree_init(&zns->ifp_tree); return 0; } @@ -66,11 +242,22 @@ static int zebra_ns_new(struct ns *ns) static int zebra_ns_delete(struct ns *ns) { struct zebra_ns *zns = (struct zebra_ns *)ns->info; + struct zebra_if *zif; + struct ifp_tree_link *link; if (IS_ZEBRA_DEBUG_EVENT) zlog_info("ZNS %s with id %u (deleted)", ns->name, ns->ns_id); if (!zns) 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); return 0; } @@ -146,10 +333,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info) */ 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*/); kernel_terminate(zns, complete); diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index d5fd5869bca4..0e40cebbe0a8 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -32,6 +32,20 @@ struct nlsock { }; #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 { /* net-ns name. */ char name[VRF_NAMSIZ]; @@ -53,7 +67,8 @@ struct zebra_ns { struct nlsock ge_netlink_cmd; /* command channel for generic netlink */ #endif - struct route_table *if_table; + /* Tree of interfaces in this ns */ + struct ifp_tree_head ifp_tree; /* Back pointer */ struct ns *ns; @@ -61,6 +76,23 @@ struct zebra_ns { 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_enable(ns_id_t ns_id, void **info); int zebra_ns_disabled(struct ns *ns); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 0f72259951b0..8a1664440f08 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -859,39 +859,30 @@ static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data) vty_out(vty, "\n"); } -static int zvni_map_to_svi_ns(struct ns *ns, - void *_in_param, - void **_p_ifp) +static int zvni_map_to_svi_ns(struct interface *tmp_if, void *_in_param) { - struct zebra_ns *zns = ns->info; - struct route_node *rn; - struct zebra_from_svi_param *in_param = - (struct zebra_from_svi_param *)_in_param; + struct zebra_from_svi_param *in_param = _in_param; struct zebra_l2info_vlan *vl; - struct interface *tmp_if = NULL; - struct interface **p_ifp = (struct interface **)_p_ifp; struct zebra_if *zif; - assert(in_param && p_ifp); + assert(in_param); /* 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) { - *p_ifp = tmp_if; - route_unlock_node(rn); - return NS_WALK_STOP; - } + + /* Check oper status of the SVI. */ + if (!tmp_if || !if_is_operative(tmp_if)) + goto done; + 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; } @@ -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 *tmp_if = NULL; struct zebra_if *zif; - struct zebra_from_svi_param in_param; - struct interface **p_ifp; + struct zebra_from_svi_param in_param = {}; + /* Defensive check, caller expected to invoke only with valid bridge. */ if (!br_if) 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.br_if = br_if; - in_param.zif = NULL; - p_ifp = &tmp_if; + /* Identify corresponding VLAN interface. */ - ns_walk_func(zvni_map_to_svi_ns, (void *)&in_param, - (void **)p_ifp); - return tmp_if; + zebra_ns_ifp_walk_all(zvni_map_to_svi_ns, &in_param); + + return in_param.ret_ifp; } 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); if (zevpn) { - zlog_debug( - "EVPN hash already present for IF %s(%u) L2-VNI %u", - ifp->name, ifp->ifindex, vni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("EVPN hash already present for IF %s(%u) L2-VNI %u", + ifp->name, ifp->ifindex, vni); /* * 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; } -static int zevpn_build_hash_table_zns(struct ns *ns, - void *param_in __attribute__((unused)), - void **param_out __attribute__((unused))) +static int zevpn_build_hash_table_zns(struct interface *ifp, void *arg) { - struct zebra_ns *zns = ns->info; - struct route_node *rn; - struct interface *ifp; - struct zebra_vrf *zvrf; - - zvrf = zebra_vrf_get_evpn(); + struct zebra_vrf *zvrf = arg; + struct zebra_if *zif; + struct zebra_l2info_vxlan *vxl; - /* Walk VxLAN interfaces and create EVPN hash. */ - for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { - struct zebra_if *zif; - struct zebra_l2info_vxlan *vxl; + zif = ifp->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + goto done; - 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 as BGP EVPN core instance", + ifp->name, ifp->ifindex); + goto done; + } - 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; - } + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Building vni table for %s-if %s", + IS_ZEBRA_VXLAN_IF_VNI(zif) ? "vni" : "svd", ifp->name); - 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); - zebra_vxlan_if_vni_iterate(zif, zevpn_build_vni_hash_table, - NULL); - } +done: 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) { - 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; } -static int zl3vni_map_to_vxlan_if_ns(struct ns *ns, - void *_zl3vni, - 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; +/* Context arg for zl3vni map iteration */ +struct zl3vni_map_arg { struct zebra_vrf *zvrf; + struct zebra_l3vni *zl3vni; + struct interface *ret_ifp; +}; - zvrf = zebra_vrf_get_evpn(); - - assert(_pifp); - - /* loop through all vxlan-interface */ - for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { +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; - struct zebra_if *zif = NULL; - struct zebra_l2info_vxlan *vxl; - struct zebra_vxlan_vni *vni = NULL; + /* look for vxlan-interface */ - ifp = (struct interface *)rn->info; - if (!ifp) - continue; - - zif = ifp->info; - if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) - continue; + zif = ifp->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + goto done; - vxl = &zif->l2info.vxl; - vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni); - if (!vni || vni->vni != zl3vni->vni) - continue; + vxl = &zif->l2info.vxl; + vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni); + if (!vni || vni->vni != zl3vni->vni) + goto done; - /* 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; - } + /* 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 as BGP EVPN core instance", + ifp->name, ifp->ifindex, vni->vni); + goto done; + } + zl3vni->local_vtep_ip = zif->l2info.vxl.vtep_ip; + ctx->ret_ifp = ifp; - zl3vni->local_vtep_ip = zif->l2info.vxl.vtep_ip; - *_pifp = (void *)ifp; - route_unlock_node(rn); - return NS_WALK_STOP; - } + return NS_WALK_STOP; +done: return NS_WALK_CONTINUE; } struct interface *zl3vni_map_to_vxlan_if(struct zebra_l3vni *zl3vni) { - struct interface **p_ifp; - struct interface *ifp = NULL; + struct zl3vni_map_arg arg = {}; - p_ifp = &ifp; + arg.zl3vni = zl3vni; + arg.zvrf = zebra_vrf_get_evpn(); - ns_walk_func(zl3vni_map_to_vxlan_if_ns, - (void *)zl3vni, (void **)p_ifp); - return ifp; + if (arg.zvrf == NULL) + return NULL; + + 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) @@ -2086,57 +2058,35 @@ 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) +/* loop through all vxlan-interface */ +static int zl3vni_from_svi_ns(struct interface *tmp_if, void *_in_param) { int found = 0; vni_t vni_id = 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_from_svi_param *in_param = _in_param; 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; - assert(br_zif); + zif = tmp_if->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + goto done; + if (!if_is_operative(tmp_if)) + goto done; - if (in_param->bridge_vlan_aware) { - vni_id = zebra_l2_bridge_if_vni_find(br_zif, in_param->vid); - 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) - continue; - - vni_id = zebra_vxlan_if_access_vlan_vni_find( - zif, in_param->br_if); - if (vni_id) { - found = 1; - route_unlock_node(rn); - break; - } - } + if (zif->brslave_info.br_if != in_param->br_if) + goto done; + + vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, in_param->br_if); + if (vni_id) { + in_param->zl3vni = zl3vni_lookup(vni_id); + found = 1; } +done: if (!found) return NS_WALK_CONTINUE; - *p_zl3vni = zl3vni_lookup(vni_id); 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, struct interface *br_if) { - struct zebra_l3vni *zl3vni = 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_l3vni **p_zl3vni; + struct zebra_l2info_vlan *vl; if (!br_if) return NULL; @@ -2158,15 +2109,15 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp, /* 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); - in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif); - if (in_param.bridge_vlan_aware) { - struct zebra_l2info_vlan *vl; + br_zif = br_if->info; + assert(br_zif); + 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)) return NULL; @@ -2174,15 +2125,18 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp, assert(zif); vl = &zif->l2info.vl; 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 */ /* 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 zl3vni; + return in_param.zl3vni; } 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); } +/* 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. * 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; } } else { - struct zebra_ns *zns; - struct route_node *rn; - struct interface *ifp; - struct zebra_if *zif; struct zebra_vxlan_vni *vnip; struct zebra_l2info_vxlan *vxl; 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) zlog_debug("Adding L2-VNI %u - transition from L3-VNI", vni); - /* Find VxLAN interface for this VNI. */ 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; - vnip = zebra_vxlan_if_vni_find(zif, vni); - if (vnip) { - found = true; - route_unlock_node(rn); - break; - } - } - if (!found) { + ctx.vni = vni; + + /* 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) zlog_err( "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) return 0; + zif = ctx.ret_ifp->info; + vnip = ctx.vnip; + vxl = &zif->l2info.vxl; + zevpn = zebra_evpn_add(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); } - zevpn->vxlan_if = ifp; + zevpn->vxlan_if = ctx.ret_ifp; zevpn->local_vtep_ip = vxl->vtep_ip; /* 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_read_mac_neigh(zevpn, ifp); + zebra_evpn_read_mac_neigh(zevpn, ctx.ret_ifp); } }