From c715dffc8c5690f084bbf801d0d0101098ec5c00 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Tue, 10 Dec 2024 13:05:04 -0800 Subject: [PATCH] [FRR]Fixing zebra to use internal rbtree per NS tree of ifps (#21095) Adding the below fix from FRR FRRouting/frr#17297 This is to fix the following crash which is a statistical issue [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Core was generated by `/usr/lib/frr/zebra -A 127.0.0.1 -s 90000000 -M dplane_fpm_nl -M snmp'. Program terminated with signal SIGABRT, Aborted. #0 0x00007fccd7351e2c in ?? () from /lib/x86_64-linux-gnu/libc.so.6 [Current thread is 1 (Thread 0x7fccd6faf7c0 (LWP 36))] (gdb) bt #0 0x00007fccd7351e2c in ?? () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x00007fccd7302fb2 in raise () from /lib/x86_64-linux-gnu/libc.so.6 #2 0x00007fccd72ed472 in abort () from /lib/x86_64-linux-gnu/libc.so.6 #3 0x00007fccd75bb3a9 in _zlog_assert_failed (xref=xref@entry=0x7fccd7652380 <_xref.16>, extra=extra@entry=0x0) at ../lib/zlog.c:678 #4 0x00007fccd759b2fe in route_node_delete (node=) at ../lib/table.c:352 #5 0x00007fccd759b445 in route_unlock_node (node=0x0) at ../lib/table.h:258 #6 route_next (node=) at ../lib/table.c:436 #7 route_next (node=node@entry=0x56029d89e560) at ../lib/table.c:410 #8 0x000056029b6b6b7a in if_lookup_by_name_per_ns (ns=ns@entry=0x56029d873d90, ifname=ifname@entry=0x7fccc0029340 "PortChannel1020") at ../zebra/interface.c:312 #9 0x000056029b6b8b36 in zebra_if_dplane_ifp_handling (ctx=0x7fccc0029310) at ../zebra/interface.c:1867 #10 zebra_if_dplane_result (ctx=0x7fccc0029310) at ../zebra/interface.c:2221 #11 0x000056029b7137a9 in rib_process_dplane_results (thread=) at ../zebra/zebra_rib.c:4810 #12 0x00007fccd75a0e0d in thread_call (thread=thread@entry=0x7ffe8e553cc0) at ../lib/thread.c:1990 #13 0x00007fccd7559368 in frr_run (master=0x56029d65a040) at ../lib/libfrr.c:1198 #14 0x000056029b6ac317 in main (argc=9, argv=0x7ffe8e5540d8) at ../zebra/main.c:478 --- ...zebra-lib-use-internal-rbtree-per-ns.patch | 1826 +++++++++++++++++ src/sonic-frr/patch/series | 1 + 2 files changed, 1827 insertions(+) create mode 100644 src/sonic-frr/patch/0062-zebra-lib-use-internal-rbtree-per-ns.patch diff --git a/src/sonic-frr/patch/0062-zebra-lib-use-internal-rbtree-per-ns.patch b/src/sonic-frr/patch/0062-zebra-lib-use-internal-rbtree-per-ns.patch new file mode 100644 index 000000000000..4fb56f6094f5 --- /dev/null +++ b/src/sonic-frr/patch/0062-zebra-lib-use-internal-rbtree-per-ns.patch @@ -0,0 +1,1826 @@ +From a4eb079b5d87dbc6720ac9788ad3bec5a25aa519 Mon Sep 17 00:00:00 2001 +From: Mark Stapp +Date: Tue, 15 Oct 2024 11:31:22 -0400 +Subject: [PATCH 1/9] zebra: make a zif MTYPE internal/static + +Make an MTYPE used in zifs internal/static + +Signed-off-by: Mark Stapp +--- + zebra/interface.c | 2 +- + zebra/interface.h | 3 --- + 2 files changed, 1 insertion(+), 4 deletions(-) + +diff --git a/zebra/interface.c b/zebra/interface.c +index 5ce222cc04..bbdc62c1c2 100644 +--- a/zebra/interface.c ++++ b/zebra/interface.c +@@ -44,7 +44,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); + +diff --git a/zebra/interface.h b/zebra/interface.h +index 7d633f32d2..4cbec83cce 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 */ +-- +2.43.2 + + +From ccc18a117a74b3d7caec9db926b0d52e9180ef13 Mon Sep 17 00:00:00 2001 +From: Mark Stapp +Date: Tue, 22 Oct 2024 15:20:54 -0700 +Subject: [PATCH 2/9] zebra: add new per-NS tree of interfaces + +Add new per-NS interface typerb tree, using external linkage, to +replace the use of the if_table table. +Add apis to iterate the per-NS collection - which is not public. + +Signed-off-by: Mark Stapp +--- + zebra/zebra_ns.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++ + zebra/zebra_ns.h | 34 +++++++++ + 2 files changed, 222 insertions(+) + +diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c +index 803d8f0034..c6b279a9d7 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) +@@ -59,6 +235,7 @@ static int zebra_ns_new(struct ns *ns) + + /* Do any needed per-NS data structure allocation. */ + zns->if_table = route_table_init(); ++ ifp_tree_init(&zns->ifp_tree); + + return 0; + } +@@ -66,11 +243,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; + } +diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h +index 8d988c3f82..1ddecc8252 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]; +@@ -55,12 +69,32 @@ struct zebra_ns { + + struct route_table *if_table; + ++ /* Tree of interfaces in this ns */ ++ struct ifp_tree_head ifp_tree; ++ + /* Back pointer */ + struct ns *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); +-- +2.43.2 + + +From 24957f224f8a9918e451d152917feb5cf5ce0d2f Mon Sep 17 00:00:00 2001 +From: Mark Stapp +Date: Tue, 22 Oct 2024 15:23:17 -0700 +Subject: [PATCH 3/9] zebra: use new per-NS interface iteration + +Replace use of the old if_table with the new per-NS ifp +iteration apis. + +Signed-off-by: Mark Stapp +--- + zebra/if_netlink.c | 61 +++++++++++++++++++++++++++++++--------------- + 1 file changed, 41 insertions(+), 20 deletions(-) + +diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c +index 5f096e3039..f7567f06d0 100644 +--- a/zebra/if_netlink.c ++++ b/zebra/if_netlink.c +@@ -1775,6 +1775,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. +@@ -1782,35 +1791,47 @@ 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) +- return ret; ++ zebra_ns_ifp_walk(zns, tunneldump_walk_cb, &ctx); ++ ret = ctx.ret; + +- ret = netlink_parse_info(netlink_link_change, netlink_cmd, +- &dp_info, 0, true); ++ return ret; ++} + +- if (ret < 0) +- 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 const char *port_state2str(uint8_t state) +-- +2.43.2 + + +From 8504e1119d084deef326a72f930873e6f7d921a6 Mon Sep 17 00:00:00 2001 +From: Mark Stapp +Date: Tue, 22 Oct 2024 15:56:11 -0700 +Subject: [PATCH 4/9] isisd: add include file + +Add an include to an isis header so it's self-contained. + +Signed-off-by: Mark Stapp +--- + isisd/isis_route.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/isisd/isis_route.h b/isisd/isis_route.h +index 4d49a5ae9c..d9572336af 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 { +-- +2.43.2 + + +From eb75106d9a0e5bc689f914e5ff9ebd3528fd3b7a Mon Sep 17 00:00:00 2001 +From: Mark Stapp +Date: Tue, 22 Oct 2024 15:57:53 -0700 +Subject: [PATCH 5/9] zebra: removing use of per-NS if_table + +Remove use of the per-NS if_table from zebra/interface +module. Use new add, lookup, and iteration apis. + +Signed-off-by: Mark Stapp +--- + zebra/interface.c | 144 +++++++++++++++------------------------------- + zebra/interface.h | 5 +- + 2 files changed, 49 insertions(+), 100 deletions(-) + +diff --git a/zebra/interface.c b/zebra/interface.c +index bbdc62c1c2..7ec80cb259 100644 +--- a/zebra/interface.c ++++ b/zebra/interface.c +@@ -233,62 +233,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; + } + +@@ -296,18 +248,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) +@@ -579,7 +524,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); + +@@ -784,7 +730,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 +@@ -1121,50 +1067,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 4cbec83cce..4f768e0217 100644 +--- a/zebra/interface.h ++++ b/zebra/interface.h +@@ -212,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; + }; +@@ -259,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, +-- +2.43.2 + + +From 3f951796fcd65edba9fa41e5f094f0e79e9583b9 Mon Sep 17 00:00:00 2001 +From: Mark Stapp +Date: Wed, 23 Oct 2024 12:34:36 -0700 +Subject: [PATCH 6/9] zebra: use new per-NS iteration in zebra_evpn + +Use the new per-NS interface iteration apis in the evpn +module. + +Signed-off-by: Mark Stapp +--- + zebra/zebra_evpn.c | 245 +++++++++++++++++++-------------------------- + zebra/zebra_evpn.h | 2 + + 2 files changed, 103 insertions(+), 144 deletions(-) + +diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c +index 147f5b93fa..1122b5a2c0 100644 +--- a/zebra/zebra_evpn.c ++++ b/zebra/zebra_evpn.c +@@ -644,70 +644,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; +- 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; + } + +@@ -719,44 +696,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; +@@ -764,47 +736,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; +- 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; + } + +@@ -815,17 +770,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; +@@ -833,58 +792,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; +- 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; + } + +@@ -893,17 +854,16 @@ static int zvni_map_to_macvlan_ns(struct ns *ns, + 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; + } + +@@ -915,13 +875,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 c946425dd5..85bdf54272 100644 +--- a/zebra/zebra_evpn.h ++++ b/zebra/zebra_evpn.h +@@ -116,7 +116,9 @@ 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; + uint8_t bridge_vlan_aware; + vlanid_t vid; + }; +-- +2.43.2 + + +From 8a9d5ecbbcdf04894de461662e83df8c5dcb7ab4 Mon Sep 17 00:00:00 2001 +From: Mark Stapp +Date: Thu, 24 Oct 2024 14:49:28 -0700 +Subject: [PATCH 7/9] lib,zebra: remove table node from ifp struct + +Finish removing the table route_node from the ifp struct. + +Signed-off-by: Mark Stapp +--- + lib/if.c | 6 ------ + lib/if.h | 2 -- + zebra/interface.c | 3 ++- + 3 files changed, 2 insertions(+), 9 deletions(-) + +diff --git a/lib/if.c b/lib/if.c +index a8ceac7243..bde35a3460 100644 +--- a/lib/if.c ++++ b/lib/if.c +@@ -1003,12 +1003,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 0dc56bd210..c2ec73378d 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/interface.c b/zebra/interface.c +index 7ec80cb259..237ad2340d 100644 +--- a/zebra/interface.c ++++ b/zebra/interface.c +@@ -223,6 +223,8 @@ static int if_zebra_delete_hook(struct interface *ifp) + if_nhg_dependents_release(ifp); + zebra_if_nhg_dependents_free(zebra_if); + ++ zebra_ns_unlink_ifp(ifp); ++ + XFREE(MTYPE_ZIF_DESC, zebra_if->desc); + + EVENT_OFF(zebra_if->speed_update); +@@ -738,7 +740,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); + +-- +2.43.2 + + +From bf41170c63771c5bda25476ccbab56383d9c74a6 Mon Sep 17 00:00:00 2001 +From: Mark Stapp +Date: Thu, 24 Oct 2024 14:50:12 -0700 +Subject: [PATCH 8/9] zebra: use new per-NS ifp iterators in vxlan code + +Replace use of the old if_table with the new per-NS ifp +iterator apis in the zebra vxlan code. + +Signed-off-by: Mark Stapp +--- + zebra/zebra_evpn.h | 1 + + zebra/zebra_vxlan.c | 368 ++++++++++++++++++++------------------------ + 2 files changed, 172 insertions(+), 197 deletions(-) + +diff --git a/zebra/zebra_evpn.h b/zebra/zebra_evpn.h +index 85bdf54272..0ffebdd277 100644 +--- a/zebra/zebra_evpn.h ++++ b/zebra/zebra_evpn.h +@@ -119,6 +119,7 @@ struct zebra_from_svi_param { + 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_vxlan.c b/zebra/zebra_vxlan.c +index 0b75ec261e..28646a7a6a 100644 +--- a/zebra/zebra_vxlan.c ++++ b/zebra/zebra_vxlan.c +@@ -862,39 +862,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; + } + +@@ -907,10 +898,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; +@@ -925,12 +915,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) +@@ -1010,9 +999,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 +@@ -1075,48 +1064,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; + } + +@@ -1127,7 +1100,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); + } + + /* +@@ -1966,70 +1945,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) +@@ -2084,57 +2056,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; + } + +@@ -2145,10 +2095,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; +@@ -2156,15 +2107,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; + +@@ -2172,15 +2123,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) +@@ -2334,6 +2288,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 +@@ -2384,39 +2368,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", +@@ -2429,6 +2399,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 */ +@@ -2441,13 +2415,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); + } + } + +-- +2.43.2 + + +From 328f2f83feed43f0871669f47aa4206e9cd7a065 Mon Sep 17 00:00:00 2001 +From: Mark Stapp +Date: Thu, 24 Oct 2024 14:52:21 -0700 +Subject: [PATCH 9/9] zebra: remove if_table from the zebra NS + +Finish removing the if_table from the zebra NS struct. + +Signed-off-by: Mark Stapp +--- + zebra/zebra_ns.c | 5 ----- + zebra/zebra_ns.h | 2 -- + 2 files changed, 7 deletions(-) + +diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c +index c6b279a9d7..578dee7b7e 100644 +--- a/zebra/zebra_ns.c ++++ b/zebra/zebra_ns.c +@@ -234,7 +234,6 @@ 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; +@@ -334,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 1ddecc8252..96b78d4745 100644 +--- a/zebra/zebra_ns.h ++++ b/zebra/zebra_ns.h +@@ -67,8 +67,6 @@ 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; + +-- +2.43.2 + diff --git a/src/sonic-frr/patch/series b/src/sonic-frr/patch/series index 557105858b33..86ec826af8c0 100644 --- a/src/sonic-frr/patch/series +++ b/src/sonic-frr/patch/series @@ -41,3 +41,4 @@ 0059-Fix-BGP-reset-on-suppress-fib-pending-configuration.patch 0060-bgpd-Validate-both-nexthop-information-NEXTHOP-and-N.patch 0061-Set-multipath-to-514-and-disable-bgp-vnc-for-optimiz.patch +0062-zebra-lib-use-internal-rbtree-per-ns.patch