summaryrefslogtreecommitdiff
path: root/zebra/zebra_nhg.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_nhg.c')
-rw-r--r--zebra/zebra_nhg.c116
1 files changed, 81 insertions, 35 deletions
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 2bb117b272..2d7521d8be 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -360,6 +360,8 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
{
const struct nhg_hash_entry *nhe1 = arg1;
const struct nhg_hash_entry *nhe2 = arg2;
+ struct nexthop *nexthop1;
+ struct nexthop *nexthop2;
/* No matter what if they equal IDs, assume equal */
if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
@@ -371,12 +373,47 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
if (nhe1->afi != nhe2->afi)
return false;
- if (nexthop_group_active_nexthop_num_no_recurse(nhe1->nhg)
- != nexthop_group_active_nexthop_num_no_recurse(nhe2->nhg))
- return false;
+ /* Nexthops should be sorted */
+ for (nexthop1 = nhe1->nhg->nexthop, nexthop2 = nhe2->nhg->nexthop;
+ nexthop1 || nexthop2;
+ nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
+ if (nexthop1 && !nexthop2)
+ return false;
- if (!nexthop_group_equal_no_recurse(nhe1->nhg, nhe2->nhg))
- return false;
+ if (!nexthop1 && nexthop2)
+ return false;
+
+ /*
+ * We have to check the active flag of each individual one,
+ * not just the overall active_num. This solves the special case
+ * issue of a route with a nexthop group with one nexthop
+ * resolving to itself and thus marking it inactive. If we
+ * have two different routes each wanting to mark a different
+ * nexthop inactive, they need to hash to two different groups.
+ *
+ * If we just hashed on num_active, they would hash the same
+ * which is incorrect.
+ *
+ * ex)
+ * 1.1.1.0/24
+ * -> 1.1.1.1 dummy1 (inactive)
+ * -> 1.1.2.1 dummy2
+ *
+ * 1.1.2.0/24
+ * -> 1.1.1.1 dummy1
+ * -> 1.1.2.1 dummy2 (inactive)
+ *
+ * Without checking each individual one, they would hash to
+ * the same group and both have 1.1.1.1 dummy1 marked inactive.
+ *
+ */
+ if (CHECK_FLAG(nexthop1->flags, NEXTHOP_FLAG_ACTIVE)
+ != CHECK_FLAG(nexthop2->flags, NEXTHOP_FLAG_ACTIVE))
+ return false;
+
+ if (!nexthop_same(nexthop1, nexthop2))
+ return false;
+ }
return true;
}
@@ -552,20 +589,6 @@ zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int 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;
@@ -621,6 +644,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)
@@ -869,25 +922,14 @@ 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:
- if (ctx)
- nhg_ctx_free(ctx);
+ nhg_ctx_free(ctx);
}
static int queue_add(struct nhg_ctx *ctx)
@@ -942,7 +984,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;
}
@@ -971,7 +1013,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;
}
@@ -988,7 +1030,7 @@ int zebra_nhg_kernel_del(uint32_t id)
nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
if (queue_add(ctx)) {
- nhg_ctx_process_finish(ctx);
+ nhg_ctx_fini(&ctx);
return -1;
}
@@ -1001,6 +1043,9 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi)
struct nexthop *lookup = NULL;
struct nhg_hash_entry *nhe = NULL;
+ if (!nh)
+ goto done;
+
copy_nexthops(&lookup, nh, NULL);
/* Clear it, in case its a group */
@@ -1013,6 +1058,7 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi)
nexthops_free(lookup);
+done:
return nhe;
}