summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/if_netlink.c3
-rw-r--r--zebra/rt_netlink.c23
-rw-r--r--zebra/zebra_dplane.c9
-rw-r--r--zebra/zebra_dplane.h2
-rw-r--r--zebra/zebra_nhg.c302
-rw-r--r--zebra/zebra_nhg.h31
-rw-r--r--zebra/zebra_rib.c1
-rw-r--r--zebra/zebra_router.c7
-rw-r--r--zebra/zebra_router.h1
9 files changed, 269 insertions, 110 deletions
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 8c2caed1b0..44249d7dd1 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -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);
}
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index c6f15aef2a..3e913a7f5f 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -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;
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 0e89ba3a27..e2c7bd7635 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -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);
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index d0fde958e4..fede3bfcca 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -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 *
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 3589c0e7b7..fb9e913590 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -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);
+}
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index e06d415b28..1fdda276cb 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -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
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index c89033b18c..bc647864ff 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -3374,6 +3374,7 @@ int rib_sweep_route(struct thread *t)
}
zebra_router_sweep_route();
+ zebra_router_sweep_nhgs();
return 0;
}
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index b85319df73..d6ec6ac165 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -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);
}
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index 497846e0fa..ac4c961475 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -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);