]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: Sweep our nexthop objects out on restart
authorStephen Worley <sworley@cumulusnetworks.com>
Thu, 1 Aug 2019 18:07:04 +0000 (14:07 -0400)
committerStephen Worley <sworley@cumulusnetworks.com>
Fri, 25 Oct 2019 15:13:41 +0000 (11:13 -0400)
On restart, if we failed to remove any nexthop objects due
to a kill -9 or such event, sweep them if we aren't using them.
Add a proto field to handle this and remove the is_kernel bool.

Add a dupicate flag that indicates this nexthop group is only
present in our ID hashtable. It is a dupicate nexthop we received
from the kernel, therefore we cannot hash on it.

Make the idcounter globally accessible so that kernel updates
increment it as soon as we receive them, not when we handle them.

Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com>
zebra/if_netlink.c
zebra/rt_netlink.c
zebra/zebra_dplane.c
zebra/zebra_dplane.h
zebra/zebra_nhg.c
zebra/zebra_nhg.h
zebra/zebra_rib.c
zebra/zebra_router.c
zebra/zebra_router.h

index 8c2caed1b0e16c57f1d146319940be2037494a64..44249d7dd11208a4f26a2f8dd754bac8f868673c 100644 (file)
@@ -1489,9 +1489,8 @@ void interface_list(struct zebra_ns *zns)
                 */
                zlog_debug("Nexthop objects disabled on this kernel");
                zns->supports_nh = false;
-       } else {
+       } else
                zns->supports_nh = true;
-       }
 
        interface_addr_lookup_netlink(zns);
 }
index c6f15aef2a653cf211750750c4b646f15cab3e01..3e913a7f5ff93c1b580022b868a7632804dfa550 100644 (file)
@@ -188,7 +188,7 @@ static inline int zebra2proto(int proto)
                proto = RTPROT_OPENFABRIC;
                break;
        case ZEBRA_ROUTE_TABLE:
-       case ZEBRA_NHG:
+       case ZEBRA_ROUTE_NHG:
                proto = RTPROT_ZEBRA;
                break;
        default:
@@ -208,7 +208,7 @@ static inline int zebra2proto(int proto)
        return proto;
 }
 
-static inline int proto2zebra(int proto, int family)
+static inline int proto2zebra(int proto, int family, bool is_nexthop)
 {
        switch (proto) {
        case RTPROT_BABEL:
@@ -252,6 +252,12 @@ static inline int proto2zebra(int proto, int family)
        case RTPROT_OPENFABRIC:
                proto = ZEBRA_ROUTE_OPENFABRIC;
                break;
+       case RTPROT_ZEBRA:
+               if (is_nexthop) {
+                       proto = ZEBRA_ROUTE_NHG;
+                       break;
+               }
+               /* Intentional fall thru */
        default:
                /*
                 * When a user adds a new protocol this will show up
@@ -589,7 +595,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
        /* Route which inserted by Zebra. */
        if (is_selfroute(rtm->rtm_protocol)) {
                flags |= ZEBRA_FLAG_SELFROUTE;
-               proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family);
+               proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family, false);
        }
        if (tb[RTA_OIF])
                index = *(int *)RTA_DATA(tb[RTA_OIF]);
@@ -2001,7 +2007,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
                        // TODO: Handle Encap
                }
 
-               req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_type(ctx));
+               req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx));
 
        } else if (cmd != RTM_DELNEXTHOP) {
                flog_err(
@@ -2243,10 +2249,12 @@ static int netlink_nexthop_process_group(struct rtattr **tb,
                return count;
        }
 
+#if 0
        // TODO: Need type for something?
        zlog_debug("Nexthop group type: %d",
                   *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE])));
 
+#endif
 
        for (int i = 0; i < count; i++) {
                z_grp[i].id = n_grp[i].id;
@@ -2270,6 +2278,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        /* nexthop group id */
        uint32_t id;
        unsigned char family;
+       int type;
        afi_t afi = AFI_UNSPEC;
        vrf_id_t vrf_id = 0;
        struct interface *ifp = NULL;
@@ -2311,9 +2320,10 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        id = *((uint32_t *)RTA_DATA(tb[NHA_ID]));
 
        family = nhm->nh_family;
-
        afi = family2afi(family);
 
+       type = proto2zebra(nhm->nh_protocol, 0, true);
+
        if (IS_ZEBRA_DEBUG_KERNEL)
                zlog_debug("%s ID (%u) %s NS %u",
                           nl_msg_type_to_str(h->nlmsg_type), id,
@@ -2363,7 +2373,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                // Gotta figure that one out.
 
 
-               if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi))
+               if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi,
+                                         type, startup))
                        return -1;
 
 
index 0e89ba3a27cd127ff5f308a32f6eab117979f98c..e2c7bd7635bacfc3fd3b78bb098d3476458ad82a 100644 (file)
@@ -73,7 +73,7 @@ struct dplane_nexthop_info {
        uint32_t id;
        afi_t afi;
        vrf_id_t vrf_id;
-       bool is_kernel_nh;
+       int type;
 
        struct nexthop_group ng;
        struct nh_grp nh_grp[MULTIPATH_NUM];
@@ -1077,10 +1077,10 @@ vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx)
        return ctx->u.rinfo.nhe.vrf_id;
 }
 
-bool dplane_ctx_get_nhe_is_kernel_nh(const struct zebra_dplane_ctx *ctx)
+int dplane_ctx_get_nhe_type(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
-       return ctx->u.rinfo.nhe.is_kernel_nh;
+       return ctx->u.rinfo.nhe.type;
 }
 
 const struct nexthop_group *
@@ -1577,13 +1577,12 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx,
 
        ctx->zd_op = op;
        ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
-       ctx->u.rinfo.zd_type = ZEBRA_ROUTE_TABLE;
 
        /* Copy over nhe info */
        ctx->u.rinfo.nhe.id = nhe->id;
        ctx->u.rinfo.nhe.afi = nhe->afi;
        ctx->u.rinfo.nhe.vrf_id = nhe->vrf_id;
-       ctx->u.rinfo.nhe.is_kernel_nh = nhe->is_kernel_nh;
+       ctx->u.rinfo.nhe.type = nhe->type;
 
        nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), nhe->nhg);
 
index d0fde958e4c98aaf4d5e67f6bcca3065bc7fb6f4..fede3bfcca4e9e9140e9dd6d958c357cd59db76b 100644 (file)
@@ -279,7 +279,7 @@ const struct nexthop_group *dplane_ctx_get_old_ng(
 uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx);
 afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx);
 vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx);
-bool dplane_ctx_get_nhe_is_kernel_nh(const struct zebra_dplane_ctx *ctx);
+int dplane_ctx_get_nhe_type(const struct zebra_dplane_ctx *ctx);
 const struct nexthop_group *
 dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx);
 const struct nh_grp *
index 3589c0e7b78f61296f33554b781b3cab2ea3fe20..fb9e9135900c529703ed2bd0e8b64465d21cbad6 100644 (file)
@@ -46,11 +46,17 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
 DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
 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 void depends_add(struct nhg_connected_tree_head *head,
                        struct nhg_hash_entry *depend);
-static void depends_find_add(struct nhg_connected_tree_head *head,
-                            struct nexthop *nh, afi_t afi);
+static struct nhg_hash_entry *
+depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
+                afi_t afi);
+static struct nhg_hash_entry *
+depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id);
 static void depends_decrement_free(struct nhg_connected_tree_head *head);
 
 
@@ -273,26 +279,18 @@ int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
        return 0;
 }
 
-
-static void *zebra_nhg_alloc(void *arg)
+static void
+zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
+                         struct nhg_connected_tree_head nhg_depends)
 {
-       struct nhg_hash_entry *nhe;
-       struct nhg_hash_entry *copy = arg;
        struct nhg_connected *rb_node_dep = NULL;
 
-       nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
-
-       nhe->id = copy->id;
-       nhe->nhg_depends = copy->nhg_depends;
-
-       nhe->nhg = nexthop_group_new();
-       nexthop_group_copy(nhe->nhg, copy->nhg);
-
-       nhe->vrf_id = copy->vrf_id;
-       nhe->afi = copy->afi;
-       nhe->refcnt = 0;
-       nhe->is_kernel_nh = copy->is_kernel_nh;
-       nhe->dplane_ref = zebra_router_get_next_sequence();
+       /* This has been allocated higher above in the stack. Could probably
+        * re-allocate and free the old stuff but just using the same memory
+        * for now. Otherwise, their might be a time trade-off for repeated
+        * alloc/frees as startup.
+        */
+       nhe->nhg_depends = nhg_depends;
 
        /* Attach backpointer to anything that it depends on */
        zebra_nhg_dependents_init(nhe);
@@ -318,8 +316,37 @@ static void *zebra_nhg_alloc(void *arg)
                                nhe->nhg->nexthop->ifindex, nhe->vrf_id,
                                nhe->id);
        }
+}
+
+static struct nhg_hash_entry *zebra_nhg_copy(struct nhg_hash_entry *copy,
+                                            uint32_t id)
+{
+       struct nhg_hash_entry *nhe;
+
+       nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
+
+       nhe->id = id;
+
+       nhe->nhg = nexthop_group_new();
+       nexthop_group_copy(nhe->nhg, copy->nhg);
+
+       nhe->vrf_id = copy->vrf_id;
+       nhe->afi = copy->afi;
+       nhe->type = copy->type ? copy->type : ZEBRA_ROUTE_NHG;
+       nhe->refcnt = 0;
+       nhe->dplane_ref = zebra_router_get_next_sequence();
+
+       return nhe;
+}
+
+/* Allocation via hash handler */
+static void *zebra_nhg_hash_alloc(void *arg)
+{
+       struct nhg_hash_entry *nhe = NULL;
+       struct nhg_hash_entry *copy = arg;
 
-       /* Add to id table as well */
+       nhe = zebra_nhg_copy(copy, copy->id);
+       zebra_nhg_connect_depends(nhe, copy->nhg_depends);
        zebra_nhg_insert_id(nhe);
 
        return nhe;
@@ -391,24 +418,24 @@ static void zebra_nhg_process_grp(struct nexthop_group *nhg,
                 * how to adapt this to our code in
                 * the future.
                 */
-               depend = zebra_nhg_lookup_id(grp[i].id);
-               if (depend) {
-                       nhg_connected_tree_add_nhe(depends, depend);
-                       /*
-                        * If this is a nexthop with its own group
-                        * dependencies, add them as well. Not sure its
-                        * even possible to have a group within a group
-                        * in the kernel.
-                        */
+               depend = depends_find_id_add(depends, grp[i].id);
 
-                       copy_nexthops(&nhg->nexthop, depend->nhg->nexthop,
-                                     NULL);
-               } else {
+               if (!depend) {
                        flog_err(
                                EC_ZEBRA_NHG_SYNC,
                                "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
                                grp[i].id);
+                       return;
                }
+
+               /*
+                * If this is a nexthop with its own group
+                * dependencies, add them as well. Not sure its
+                * even possible to have a group within a group
+                * in the kernel.
+                */
+
+               copy_nexthops(&nhg->nexthop, depend->nhg->nexthop, NULL);
        }
 }
 
@@ -416,29 +443,22 @@ static void zebra_nhg_process_grp(struct nexthop_group *nhg,
 static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
                           struct nexthop_group *nhg,
                           struct nhg_connected_tree_head *nhg_depends,
-                          vrf_id_t vrf_id, afi_t afi, bool is_kernel_nh)
+                          vrf_id_t vrf_id, afi_t afi, int type)
 {
-       /* id counter to keep in sync with kernel */
-       static uint32_t id_counter = 0;
-
        struct nhg_hash_entry lookup = {};
 
        uint32_t old_id_counter = id_counter;
 
        bool created = false;
 
-       if (id > id_counter) {
-               /* Increase our counter so we don't try to create
-                * an ID that already exists
-                */
-               id_counter = id;
-               lookup.id = id;
-       } else
-               lookup.id = ++id_counter;
+       /*
+        * If it has an id at this point, we must have gotten it from the kernel
+        */
+       lookup.id = id ? id : ++id_counter;
 
        lookup.afi = afi;
        lookup.vrf_id = vrf_id;
-       lookup.is_kernel_nh = is_kernel_nh;
+       lookup.type = type;
        lookup.nhg = nhg;
 
        if (nhg_depends)
@@ -454,7 +474,7 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
                id_counter = old_id_counter;
 
        if (!(*nhe)) {
-               (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc);
+               (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_hash_alloc);
                created = true;
        }
 
@@ -475,8 +495,7 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
 
 /* Find/create a single nexthop */
 static bool zebra_nhg_find_nexthop(struct nhg_hash_entry **nhe, uint32_t id,
-                                  struct nexthop *nh, afi_t afi,
-                                  bool is_kernel_nh)
+                                  struct nexthop *nh, afi_t afi, int type)
 {
        struct nexthop_group nhg = {};
        struct nhg_connected_tree_head nhg_depends = {};
@@ -489,8 +508,7 @@ static bool zebra_nhg_find_nexthop(struct nhg_hash_entry **nhe, uint32_t id,
                handle_recursive_depend(&nhg_depends, nh->resolved, afi);
        }
 
-       if (!zebra_nhg_find(nhe, id, &nhg, &nhg_depends, nh->vrf_id, afi,
-                             is_kernel_nh)) {
+       if (!zebra_nhg_find(nhe, id, &nhg, &nhg_depends, nh->vrf_id, afi, 0)) {
                created = false;
                depends_decrement_free(&nhg_depends);
        } else {
@@ -535,6 +553,29 @@ static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx)
        return ctx->op;
 }
 
+static bool zebra_nhg_contains_dup(struct nhg_hash_entry *nhe)
+{
+       struct nhg_connected *rb_node_dep = NULL;
+
+       frr_each (nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
+               if (CHECK_FLAG(rb_node_dep->nhe->flags,
+                              NEXTHOP_GROUP_DUPLICATE))
+                       return true;
+       }
+
+       return false;
+}
+
+static void zebra_nhg_set_dup(struct nhg_hash_entry *nhe)
+{
+       SET_FLAG(nhe->flags, NEXTHOP_GROUP_DUPLICATE);
+       SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+
+       flog_warn(EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
+                 "Nexthop Group with ID (%d) is a duplicate, ignoring",
+                 nhe->id);
+}
+
 static int nhg_ctx_process_new(struct nhg_ctx *ctx)
 {
        struct nexthop_group *nhg = NULL;
@@ -546,17 +587,19 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
                zebra_nhg_process_grp(nhg, &nhg_depends, ctx->u.grp,
                                      ctx->count);
                if (!zebra_nhg_find(&nhe, ctx->id, nhg, &nhg_depends,
-                                   ctx->vrf_id, ctx->afi, true))
-                       nhg_connected_tree_free(&nhg_depends);
+                                   ctx->vrf_id, ctx->type, ctx->afi))
+                       depends_decrement_free(&nhg_depends);
 
                /* These got copied over in zebra_nhg_alloc() */
                nexthop_group_free_delete(&nhg);
-       } else if (!zebra_nhg_find_nexthop(&nhe, ctx->id, &ctx->u.nh, ctx->afi,
-                                          ctx->is_kernel_nh))
-               nhg_connected_tree_free(&nhg_depends);
+       } else
+               zebra_nhg_find_nexthop(&nhe, ctx->id, &ctx->u.nh, ctx->afi,
+                                      ctx->type);
 
        if (nhe) {
-               if (ctx->id != nhe->id)
+               if (ctx->id != nhe->id) {
+                       struct nhg_hash_entry *kernel_nhe = NULL;
+
                        /* Duplicate but with different ID from
                         * the kernel
                         */
@@ -566,17 +609,25 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
                         * We are ignoring those to prevent
                         * syncing problems with the kernel
                         * changes.
+                        *
+                        * We maintain them *ONLY* in the ID hash table to
+                        * track them.
+                        */
+
+                       kernel_nhe = zebra_nhg_copy(nhe, ctx->id);
+                       zebra_nhg_insert_id(kernel_nhe);
+                       zebra_nhg_set_dup(kernel_nhe);
+               } else if (zebra_nhg_contains_dup(nhe)) {
+                       /* The group we got contains a duplciate depend,
+                        * so lets mark this group as a dup as well and release
+                        * it from the non-ID hash.
                         */
-                       flog_warn(
-                               EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
-                               "Nexthop Group with ID (%d) is a duplicate, ignoring",
-                               ctx->id);
-               else {
+                       hash_release(zrouter.nhgs, nhe);
+                       zebra_nhg_set_dup(nhe);
+               } else {
                        /* It actually created a new nhe */
-                       if (nhe->is_kernel_nh) {
-                               SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
-                               SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
-                       }
+                       SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+                       SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
                }
        } else {
                flog_err(
@@ -638,7 +689,8 @@ static int queue_add(struct nhg_ctx *ctx)
 
 /* Kernel-side, you either get a single new nexthop or a array of ID's */
 int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
-                         uint8_t count, vrf_id_t vrf_id, afi_t afi)
+                         uint8_t count, vrf_id_t vrf_id, afi_t afi, int type,
+                         int startup)
 {
        // TODO: Can probably put table lookup
        // here before queueing? And if deleted, re-send to kernel?
@@ -647,12 +699,18 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
 
        struct nhg_ctx *ctx = NULL;
 
+       if (id > id_counter)
+               /* Increase our counter so we don't try to create
+                * an ID that already exists
+                */
+               id_counter = id;
+
        ctx = nhg_ctx_new();
 
        ctx->id = id;
        ctx->vrf_id = vrf_id;
        ctx->afi = afi;
-       ctx->is_kernel_nh = true;
+       ctx->type = type;
        ctx->count = count;
 
        if (count)
@@ -663,6 +721,13 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
 
        nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
 
+       /* Under statup conditions, we need to handle them immediately
+        * like we do for routes. Otherwise, we are going to get a route
+        * with a nhe_id that we have not handled.
+        */
+       if (startup)
+               return nhg_ctx_process(ctx);
+
        if (queue_add(ctx)) {
                nhg_ctx_process_finish(ctx);
                return -1;
@@ -685,7 +750,7 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi)
        lookup->next = NULL;
        lookup->prev = NULL;
 
-       zebra_nhg_find_nexthop(&nhe, 0, lookup, afi, false);
+       zebra_nhg_find_nexthop(&nhe, 0, lookup, afi, 0);
 
        nexthops_free(lookup);
 
@@ -699,13 +764,27 @@ static void depends_add(struct nhg_connected_tree_head *head,
        zebra_nhg_increment_ref(depend);
 }
 
-static void depends_find_add(struct nhg_connected_tree_head *head,
-                            struct nexthop *nh, afi_t afi)
+static struct nhg_hash_entry *
+depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
+                afi_t afi)
 {
        struct nhg_hash_entry *depend = NULL;
 
        depend = depends_find(nh, afi);
        depends_add(head, depend);
+
+       return depend;
+}
+
+static struct nhg_hash_entry *
+depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id)
+{
+       struct nhg_hash_entry *depend = NULL;
+
+       depend = zebra_nhg_lookup_id(id);
+       depends_add(head, depend);
+
+       return depend;
 }
 
 static void depends_decrement_free(struct nhg_connected_tree_head *head)
@@ -752,7 +831,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
        }
 
        if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi,
-                           false))
+                           0))
                depends_decrement_free(&nhg_depends);
        else if (recursive)
                SET_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE);
@@ -775,12 +854,21 @@ void zebra_nhg_free(void *arg)
 
        nhe = (struct nhg_hash_entry *)arg;
 
+       if (nhe->refcnt)
+               zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt);
+
        zebra_nhg_free_members(nhe);
 
        XFREE(MTYPE_NHG, nhe);
 }
 
-static void zebra_nhg_release(struct nhg_hash_entry *nhe)
+/*
+ * Release from the non-ID hash'd table.
+ *
+ * Basically, we are saying don't let routes use this anymore,
+ * because we are removing it.
+ */
+static void zebra_nhg_release_no_id(struct nhg_hash_entry *nhe)
 {
        /* Remove it from any lists it may be on */
        zebra_nhg_depends_release(nhe);
@@ -788,10 +876,17 @@ static void zebra_nhg_release(struct nhg_hash_entry *nhe)
        if (nhe->ifp)
                if_nhg_dependents_del(nhe->ifp, nhe);
 
-       hash_release(zrouter.nhgs, nhe);
-       hash_release(zrouter.nhgs_id, nhe);
+       /*
+        * If its a dup, we didn't store it here and have to be
+        * sure we don't clear one thats actually being used.
+        */
+       if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_DUPLICATE))
+               hash_release(zrouter.nhgs, nhe);
+}
 
-       zebra_nhg_free(nhe);
+static void zebra_nhg_release_id(struct nhg_hash_entry *nhe)
+{
+       hash_release(zrouter.nhgs_id, nhe);
 }
 
 void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
@@ -801,7 +896,7 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
        if (!zebra_nhg_depends_is_empty(nhe))
                nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
 
-       if (!nhe->is_kernel_nh && nhe->refcnt <= 0)
+       if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
                zebra_nhg_uninstall_kernel(nhe);
 }
 
@@ -1417,6 +1512,15 @@ 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;
@@ -1430,13 +1534,13 @@ int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new)
        if (re->nhe_id != new->id) {
                old = zebra_nhg_lookup_id(re->nhe_id);
 
-               re->ng = new->nhg;
-               re->nhe_id = new->id;
+               zebra_nhg_re_attach_ref(re, new);
 
-               zebra_nhg_increment_ref(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;
@@ -1504,7 +1608,6 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
 
        if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
            && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
-               nhe->is_kernel_nh = false;
                int ret = dplane_nexthop_add(nhe);
 
                switch (ret) {
@@ -1524,8 +1627,18 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
        }
 }
 
+static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe)
+{
+       zlog_debug("Freeing nhe_id=%u", nhe->id);
+       zebra_nhg_release_id(nhe);
+       zebra_nhg_free(nhe);
+}
+
 void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
 {
+       /* Release from the non-ID hash'd table so nothing tries to use it */
+       zebra_nhg_release_no_id(nhe);
+
        if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
                int ret = dplane_nexthop_delete(nhe);
 
@@ -1541,11 +1654,11 @@ void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
                        break;
                case ZEBRA_DPLANE_REQUEST_SUCCESS:
                        UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
-                       zebra_nhg_release(nhe);
+                       zebra_nhg_handle_uninstall(nhe);
                        break;
                }
        } else
-               zebra_nhg_release(nhe);
+               zebra_nhg_handle_uninstall(nhe);
 }
 
 static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg)
@@ -1554,16 +1667,16 @@ static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg)
 
        nhe = (struct nhg_hash_entry *)bucket->data;
 
-       if (nhe && !nhe->is_kernel_nh)
+       if (ZEBRA_NHG_CREATED(nhe))
                zebra_nhg_uninstall_kernel(nhe);
 }
 
-void zebra_nhg_cleanup_tables(void)
+void zebra_nhg_cleanup_tables(struct hash *hash)
 {
        // TODO: These should only be uninstalled via route cleanup
        // path?
        return;
-       hash_iterate(zrouter.nhgs, zebra_nhg_uninstall_created, NULL);
+       hash_iterate(hash, zebra_nhg_uninstall_created, NULL);
 }
 
 void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
@@ -1592,7 +1705,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
                case DPLANE_OP_NH_DELETE:
                        if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
                                UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
-                               zebra_nhg_release(nhe);
+                               zebra_nhg_handle_uninstall(nhe);
                        } else {
                                flog_err(
                                        EC_ZEBRA_DP_DELETE_FAIL,
@@ -1641,3 +1754,18 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
        dplane_ctx_fini(&ctx);
 }
 
+static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
+{
+       struct nhg_hash_entry *nhe = NULL;
+
+       nhe = (struct nhg_hash_entry *)bucket->data;
+
+       /* If its being ref'd, just let it be uninstalled via a route removal */
+       if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
+               zebra_nhg_uninstall_kernel(nhe);
+}
+
+void zebra_nhg_sweep_table(struct hash *hash)
+{
+       hash_iterate(hash, zebra_nhg_sweep_entry, NULL);
+}
index e06d415b28ecd59246dcf398b8b326e2c42ea839..1fdda276cb822bd9bad944e167cec55294d3f14a 100644 (file)
@@ -45,7 +45,7 @@ struct nhg_hash_entry {
        uint32_t id;
        afi_t afi;
        vrf_id_t vrf_id;
-       bool is_kernel_nh;
+       int type;
 
        struct nexthop_group *nhg;
 
@@ -77,24 +77,32 @@ struct nhg_hash_entry {
  * and correct( ie no recursive pointer ) or a nexthop that is recursively
  * resolved and correct.
  */
-#define NEXTHOP_GROUP_VALID 0x1
+#define NEXTHOP_GROUP_VALID (1 << 0)
 /*
  * Has this nexthop group been installed?  At this point in time, this
  * means that the data-plane has been told about this nexthop group
  * and it's possible usage by a route entry.
  */
-#define NEXTHOP_GROUP_INSTALLED 0x2
+#define NEXTHOP_GROUP_INSTALLED (1 << 1)
 /*
  * Has the nexthop group been queued to be send to the FIB?
  * The NEXTHOP_GROUP_VALID flag should also be set by this point.
  */
-#define NEXTHOP_GROUP_QUEUED 0x4
+#define NEXTHOP_GROUP_QUEUED (1 << 2)
 /*
  * Is this a nexthop that is recursively resolved?
  */
-#define NEXTHOP_GROUP_RECURSIVE 0x8
+#define NEXTHOP_GROUP_RECURSIVE (1 << 3)
+/*
+ * This is a duplicate nexthop we got from the kernel, we are only tracking
+ * it in our ID hash table, it is unusable by our routes.
+ */
+#define NEXTHOP_GROUP_DUPLICATE (1 << 4)
 };
 
+/* Was this one we created, either this session or previously? */
+#define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG)
+
 /* Abstraction for connected trees */
 struct nhg_connected {
        struct nhg_connected_tree_item tree_item;
@@ -135,7 +143,11 @@ struct nhg_ctx {
 
        vrf_id_t vrf_id;
        afi_t afi;
-       bool is_kernel_nh;
+       /*
+        * This should only every be ZEBRA_ROUTE_NHG unless we get a a kernel
+        * created nexthop not made by us.
+        */
+       int type;
 
        /* If its a group array, how many? */
        uint8_t count;
@@ -216,7 +228,8 @@ extern int nhg_ctx_process(struct nhg_ctx *ctx);
 /* Find via kernel nh creation */
 extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
                                 struct nh_grp *grp, uint8_t count,
-                                vrf_id_t vrf_id, afi_t afi);
+                                vrf_id_t vrf_id, afi_t afi, int type,
+                                int startup);
 
 /* Find via route creation */
 extern struct nhg_hash_entry *
@@ -242,9 +255,11 @@ extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
 void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe);
 void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe);
 
-void zebra_nhg_cleanup_tables(void);
+void zebra_nhg_cleanup_tables(struct hash *hash);
 
 /* Forward ref of dplane update context type */
 struct zebra_dplane_ctx;
 void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx);
+
+void zebra_nhg_sweep_table(struct hash *hash);
 #endif
index c89033b18c724f459150fbef8eea5bfafbf8d00f..bc647864ff7b49ddcf8e96757efd69dbe80eac8c 100644 (file)
@@ -3374,6 +3374,7 @@ int rib_sweep_route(struct thread *t)
        }
 
        zebra_router_sweep_route();
+       zebra_router_sweep_nhgs();
 
        return 0;
 }
index b85319df735af361983d20db83740065d2cc159f..d6ec6ac1658e10eb14f836061b70db3e96949508 100644 (file)
@@ -154,6 +154,11 @@ void zebra_router_sweep_route(void)
        }
 }
 
+void zebra_router_sweep_nhgs(void)
+{
+       zebra_nhg_sweep_table(zrouter.nhgs_id);
+}
+
 static void zebra_router_free_table(struct zebra_router_table *zrt)
 {
        void *table_info;
@@ -275,5 +280,5 @@ void zebra_router_init(void)
  */
 void zebra_router_cleanup(void)
 {
-       zebra_nhg_cleanup_tables();
+       zebra_nhg_cleanup_tables(zrouter.nhgs_id);
 }
index 497846e0fae4eba31833fa3404acd9d78e85ab9f..ac4c96147563212a58cf0b72104ffc6215f02838 100644 (file)
@@ -160,6 +160,7 @@ extern void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid,
 extern int zebra_router_config_write(struct vty *vty);
 
 extern void zebra_router_sweep_route(void);
+extern void zebra_router_sweep_nhgs(void);
 
 extern void zebra_router_show_table_summary(struct vty *vty);