]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: add new per-NS tree of interfaces
authorMark Stapp <mjs@cisco.com>
Tue, 22 Oct 2024 22:20:54 +0000 (15:20 -0700)
committerMark Stapp <mjs@cisco.com>
Mon, 28 Oct 2024 18:54:06 +0000 (14:54 -0400)
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 <mjs@cisco.com>
zebra/zebra_ns.c
zebra/zebra_ns.h

index ffd749fcf17e0e29a7c42713c2fa6eee6b94c207..42a9a2fe045207baa5719746ac779e4ebe9275b5 100644 (file)
 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;
 }
index d5fd5869bca40dcd6c33e796d215535dfdcb713f..10e414dac3aa957c4b4a62758a1509137de7a2c6 100644 (file)
@@ -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);