]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zebra_nhg.c
zebra: nexthop groups vrf's are only a function of namespaces
[mirror_frr.git] / zebra / zebra_nhg.c
index d33f3a432a05dc64ab34554283d5f3335c8552e8..732349a570621f96c7e95e4bd480a5e0fb40c5b6 100644 (file)
@@ -49,7 +49,8 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
 /* id counter to keep in sync with kernel */
 uint32_t id_counter;
 
-static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi);
+static struct nhg_hash_entry *depends_find(const struct nexthop *nh,
+                                          afi_t afi);
 static void depends_add(struct nhg_connected_tree_head *head,
                        struct nhg_hash_entry *depend);
 static struct nhg_hash_entry *
@@ -98,31 +99,60 @@ nhg_connected_tree_root(struct nhg_connected_tree_head *head)
        return nhg_connected_tree_first(head);
 }
 
-void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
-                               struct nhg_hash_entry *depend)
+struct nhg_hash_entry *
+nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
+                          struct nhg_hash_entry *depend)
 {
        struct nhg_connected lookup = {};
        struct nhg_connected *remove = NULL;
+       struct nhg_hash_entry *removed_nhe;
 
        lookup.nhe = depend;
 
        /* Lookup to find the element, then remove it */
        remove = nhg_connected_tree_find(head, &lookup);
-       remove = nhg_connected_tree_del(head, remove);
-
        if (remove)
+               /* Re-returning here just in case this API changes..
+                * the _del list api's are a bit undefined at the moment.
+                *
+                * So hopefully returning here will make it fail if the api
+                * changes to something different than currently expected.
+                */
+               remove = nhg_connected_tree_del(head, remove);
+
+       /* If the entry was sucessfully removed, free the 'connected` struct */
+       if (remove) {
+               removed_nhe = remove->nhe;
                nhg_connected_free(remove);
+               return removed_nhe;
+       }
+
+       return NULL;
 }
 
-void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
-                               struct nhg_hash_entry *depend)
+/* Assuming UNIQUE RB tree. If this changes, assumptions here about
+ * insertion need to change.
+ */
+struct nhg_hash_entry *
+nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
+                          struct nhg_hash_entry *depend)
 {
        struct nhg_connected *new = NULL;
 
        new = nhg_connected_new(depend);
 
-       if (new)
-               nhg_connected_tree_add(head, new);
+       /* On success, NULL will be returned from the
+        * RB code.
+        */
+       if (new && (nhg_connected_tree_add(head, new) == NULL))
+               return NULL;
+
+       /* If it wasn't successful, it must be a duplicate. We enforce the
+        * unique property for the `nhg_connected` tree.
+        */
+       nhg_connected_free(new);
+
+       return depend;
 }
 
 static void
@@ -287,25 +317,34 @@ zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
                struct interface *ifp = NULL;
 
                ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex,
-                                        nhe->vrf_id);
+                                        nhe->nhg->nexthop->vrf_id);
                if (ifp)
                        zebra_nhg_set_if(nhe, ifp);
                else
                        flog_err(
                                EC_ZEBRA_IF_LOOKUP_FAILED,
                                "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
-                               nhe->nhg->nexthop->ifindex, nhe->vrf_id,
-                               nhe->id);
+                               nhe->nhg->nexthop->ifindex,
+                               nhe->nhg->nexthop->vrf_id, nhe->id);
        }
 }
 
-static struct nhg_hash_entry *zebra_nhg_copy(struct nhg_hash_entry *copy,
-                                            uint32_t id)
+struct nhg_hash_entry *zebra_nhg_alloc(void)
 {
        struct nhg_hash_entry *nhe;
 
        nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
 
+       return nhe;
+}
+
+static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *copy,
+                                            uint32_t id)
+{
+       struct nhg_hash_entry *nhe;
+
+       nhe = zebra_nhg_alloc();
+
        nhe->id = id;
 
        nhe->nhg = nexthop_group_new();
@@ -468,10 +507,12 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
        struct nhg_hash_entry *depend = NULL;
        struct nexthop_group resolved_ng = {};
 
-       _nexthop_group_add_sorted(&resolved_ng, nh);
+       resolved_ng.nexthop = nh;
 
        depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
-       depends_add(nhg_depends, depend);
+
+       if (depend)
+               depends_add(nhg_depends, depend);
 }
 
 static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
@@ -494,10 +535,10 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
        lookup.type = type ? type : ZEBRA_ROUTE_NHG;
        lookup.nhg = nhg;
 
+       lookup.vrf_id = vrf_id;
        if (lookup.nhg->nexthop->next) {
                /* Groups can have all vrfs and AF's in them */
                lookup.afi = AFI_UNSPEC;
-               lookup.vrf_id = 0;
        } else {
                switch (lookup.nhg->nexthop->type) {
                case (NEXTHOP_TYPE_IFINDEX):
@@ -521,8 +562,6 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
                        lookup.afi = AFI_IP6;
                        break;
                }
-
-               lookup.vrf_id = vrf_id;
        }
 
        if (id)
@@ -581,28 +620,15 @@ zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
 {
        struct nhg_hash_entry *nhe = NULL;
        struct nexthop_group nhg = {};
+       vrf_id_t vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nh->vrf_id;
 
-       _nexthop_group_add_sorted(&nhg, nh);
+       nexthop_group_add_sorted(&nhg, nh);
 
-       zebra_nhg_find(&nhe, id, &nhg, NULL, nh->vrf_id, afi, 0);
+       zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type);
 
        return nhe;
 }
 
-static struct nhg_ctx *nhg_ctx_new()
-{
-       struct nhg_ctx *new = NULL;
-
-       new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
-
-       return new;
-}
-
-static void nhg_ctx_free(struct nhg_ctx *ctx)
-{
-       XFREE(MTYPE_NHG_CTX, ctx);
-}
-
 static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx)
 {
        return ctx->id;
@@ -658,6 +684,36 @@ static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx)
        return ctx->u.grp;
 }
 
+static struct nhg_ctx *nhg_ctx_new()
+{
+       struct nhg_ctx *new = NULL;
+
+       new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
+
+       return new;
+}
+
+static void nhg_ctx_free(struct nhg_ctx **ctx)
+{
+       struct nexthop *nh;
+
+       if (ctx == NULL)
+               return;
+
+       assert((*ctx) != NULL);
+
+       if (nhg_ctx_get_count(*ctx))
+               goto done;
+
+       nh = nhg_ctx_get_nh(*ctx);
+
+       nexthop_del_labels(nh);
+
+done:
+       XFREE(MTYPE_NHG_CTX, *ctx);
+       *ctx = NULL;
+}
+
 static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
                                    struct nh_grp *grp, vrf_id_t vrf_id,
                                    afi_t afi, int type, uint8_t count)
@@ -906,23 +962,13 @@ static int nhg_ctx_process_del(struct nhg_ctx *ctx)
        return 0;
 }
 
-static void nhg_ctx_process_finish(struct nhg_ctx *ctx)
+static void nhg_ctx_fini(struct nhg_ctx **ctx)
 {
-       struct nexthop *nh;
-
        /*
         * Just freeing for now, maybe do something more in the future
         * based on flag.
         */
 
-       if (nhg_ctx_get_count(ctx))
-               goto done;
-
-       nh = nhg_ctx_get_nh(ctx);
-
-       nexthop_del_labels(nh);
-
-done:
        nhg_ctx_free(ctx);
 }
 
@@ -978,7 +1024,7 @@ int nhg_ctx_process(struct nhg_ctx *ctx)
 
        nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
 
-       nhg_ctx_process_finish(ctx);
+       nhg_ctx_fini(&ctx);
 
        return ret;
 }
@@ -1007,7 +1053,7 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
                return nhg_ctx_process(ctx);
 
        if (queue_add(ctx)) {
-               nhg_ctx_process_finish(ctx);
+               nhg_ctx_fini(&ctx);
                return -1;
        }
 
@@ -1015,16 +1061,16 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
 }
 
 /* Kernel-side, received delete message */
-int zebra_nhg_kernel_del(uint32_t id)
+int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
 {
        struct nhg_ctx *ctx = NULL;
 
-       ctx = nhg_ctx_init(id, NULL, NULL, 0, 0, 0, 0);
+       ctx = nhg_ctx_init(id, NULL, NULL, vrf_id, 0, 0, 0);
 
        nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
 
        if (queue_add(ctx)) {
-               nhg_ctx_process_finish(ctx);
+               nhg_ctx_fini(&ctx);
                return -1;
        }
 
@@ -1032,18 +1078,13 @@ int zebra_nhg_kernel_del(uint32_t id)
 }
 
 /* Some dependency helper functions */
-static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi)
+static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
+                                                    afi_t afi)
 {
+       struct nhg_hash_entry *nhe;
        struct nexthop *lookup = NULL;
-       struct nhg_hash_entry *nhe = NULL;
-
-       copy_nexthops(&lookup, nh, NULL);
 
-       /* Clear it, in case its a group */
-       nexthops_free(lookup->next);
-       nexthops_free(lookup->prev);
-       lookup->next = NULL;
-       lookup->prev = NULL;
+       lookup = nexthop_dup(nh, NULL);
 
        nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0);
 
@@ -1052,11 +1093,55 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi)
        return nhe;
 }
 
+static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
+                                                    afi_t afi)
+{
+       struct nhg_hash_entry *nhe;
+       struct nexthop lookup = {};
+
+       /* Capture a snapshot of this single nh; it might be part of a list,
+        * so we need to make a standalone copy.
+        */
+       nexthop_copy_no_recurse(&lookup, nh, NULL);
+
+       nhe = zebra_nhg_find_nexthop(0, &lookup, afi, 0);
+
+       /* The copy may have allocated labels; free them if necessary. */
+       nexthop_del_labels(&lookup);
+
+       return nhe;
+}
+
+static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
+{
+       struct nhg_hash_entry *nhe = NULL;
+
+       if (!nh)
+               goto done;
+
+       /* We are separating these functions out to increase handling speed
+        * in the non-recursive case (by not alloc/freeing)
+        */
+       if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
+               nhe = depends_find_recursive(nh, afi);
+       else
+               nhe = depends_find_singleton(nh, afi);
+
+done:
+       return nhe;
+}
+
 static void depends_add(struct nhg_connected_tree_head *head,
                        struct nhg_hash_entry *depend)
 {
-       nhg_connected_tree_add_nhe(head, depend);
-       zebra_nhg_increment_ref(depend);
+       /* If NULL is returned, it was successfully added and
+        * needs to have its refcnt incremented.
+        *
+        * Else the NHE is already present in the tree and doesn't
+        * need to increment the refcnt.
+        */
+       if (nhg_connected_tree_add_nhe(head, depend) == NULL)
+               zebra_nhg_increment_ref(depend);
 }
 
 static struct nhg_hash_entry *
@@ -1097,6 +1182,14 @@ struct nhg_hash_entry *
 zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
 {
        struct nhg_hash_entry *nhe = NULL;
+       vrf_id_t vrf_id;
+
+       /*
+        * CLANG SA is complaining that nexthop may be NULL
+        * Make it happy but this is ridonc
+        */
+       assert(nhg->nexthop);
+       vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id;
 
        if (!(nhg && nhg->nexthop)) {
                flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
@@ -1104,7 +1197,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
                return NULL;
        }
 
-       zebra_nhg_find(&nhe, id, nhg, NULL, nhg->nexthop->vrf_id, rt_afi, 0);
+       zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0);
 
        return nhe;
 }
@@ -1118,12 +1211,8 @@ static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
        nhg_connected_tree_free(&nhe->nhg_dependents);
 }
 
-void zebra_nhg_free(void *arg)
+void zebra_nhg_free(struct nhg_hash_entry *nhe)
 {
-       struct nhg_hash_entry *nhe = NULL;
-
-       nhe = (struct nhg_hash_entry *)arg;
-
        if (nhe->refcnt)
                zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt);
 
@@ -1132,6 +1221,11 @@ void zebra_nhg_free(void *arg)
        XFREE(MTYPE_NHG, nhe);
 }
 
+void zebra_nhg_hash_free(void *p)
+{
+       zebra_nhg_free((struct nhg_hash_entry *)p);
+}
+
 void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
 {
        nhe->refcnt--;
@@ -1344,6 +1438,17 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                }
        }
 
+       if ((top->p.family == AF_INET && top->p.prefixlen == 32
+            && nexthop->gate.ipv4.s_addr == top->p.u.prefix4.s_addr)
+           || (top->p.family == AF_INET6 && top->p.prefixlen == 128
+               && memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) {
+               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                       zlog_debug(
+                               "\t:%s: Attempting to install a max prefixlength route through itself",
+                               __PRETTY_FUNCTION__);
+               return 0;
+       }
+
        /* Make lookup prefix. */
        memset(&p, 0, sizeof(struct prefix));
        switch (afi) {
@@ -1426,7 +1531,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
 
                if (match->type == ZEBRA_ROUTE_CONNECT) {
                        /* Directly point connected route. */
-                       newhop = match->ng->nexthop;
+                       newhop = match->nhe->nhg->nexthop;
                        if (newhop) {
                                if (nexthop->type == NEXTHOP_TYPE_IPV4
                                    || nexthop->type == NEXTHOP_TYPE_IPV6)
@@ -1435,7 +1540,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                        return 1;
                } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
                        resolved = 0;
-                       for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
+                       for (ALL_NEXTHOPS_PTR(match->nhe->nhg, newhop)) {
                                if (!CHECK_FLAG(match->status,
                                                ROUTE_ENTRY_INSTALLED))
                                        continue;
@@ -1456,7 +1561,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                        return resolved;
                } else if (re->type == ZEBRA_ROUTE_STATIC) {
                        resolved = 0;
-                       for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
+                       for (ALL_NEXTHOPS_PTR(match->nhe->nhg, newhop)) {
                                if (!CHECK_FLAG(match->status,
                                                ROUTE_ENTRY_INSTALLED))
                                        continue;
@@ -1647,7 +1752,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
        UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
 
        /* Copy over the nexthops in current state */
-       nexthop_group_copy(&new_grp, re->ng);
+       nexthop_group_copy(&new_grp, re->nhe->nhg);
 
        for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) {
 
@@ -1665,10 +1770,13 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
                new_active =
                        nexthop_active_check(rn, re, nexthop);
 
-               if (new_active
-                   && nexthop_group_active_nexthop_num(&new_grp)
-                              >= zrouter.multipath_num) {
-                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               if (new_active && curr_active >= zrouter.multipath_num) {
+                       struct nexthop *nh;
+
+                       /* Set it and its resolved nexthop as inactive. */
+                       for (nh = nexthop; nh; nh = nh->resolved)
+                               UNSET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE);
+
                        new_active = 0;
                }
 
@@ -1694,7 +1802,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
 
                new_nhe = zebra_nhg_rib_find(0, &new_grp, rt_afi);
 
-               zebra_nhg_re_update_ref(re, new_nhe);
+               route_entry_update_nhe(re, new_nhe);
        }
 
        if (curr_active) {
@@ -1720,40 +1828,6 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
        return curr_active;
 }
 
-static void zebra_nhg_re_attach_ref(struct route_entry *re,
-                                   struct nhg_hash_entry *new)
-{
-       re->ng = new->nhg;
-       re->nhe_id = new->id;
-
-       zebra_nhg_increment_ref(new);
-}
-
-int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new)
-{
-       struct nhg_hash_entry *old = NULL;
-       int ret = 0;
-
-       if (new == NULL) {
-               re->ng = NULL;
-               goto done;
-       }
-
-       if (re->nhe_id != new->id) {
-               old = zebra_nhg_lookup_id(re->nhe_id);
-
-               zebra_nhg_re_attach_ref(re, new);
-
-               if (old)
-                       zebra_nhg_decrement_ref(old);
-       } else if (!re->ng)
-               /* This is the first time it's being attached */
-               zebra_nhg_re_attach_ref(re, new);
-
-done:
-       return ret;
-}
-
 /* Convert a nhe into a group array */
 uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
                          int max_num)
@@ -1790,7 +1864,7 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
                if (!duplicate) {
                        grp[i].id = depend->id;
                        /* We aren't using weights for anything right now */
-                       grp[i].weight = 0;
+                       grp[i].weight = depend->nhg->nexthop->weight;
                        i++;
                }