summaryrefslogtreecommitdiff
path: root/lib/nexthop.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nexthop.c')
-rw-r--r--lib/nexthop.c128
1 files changed, 105 insertions, 23 deletions
diff --git a/lib/nexthop.c b/lib/nexthop.c
index b04c95c05e..4ddb53cd96 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -56,6 +56,7 @@ static int _nexthop_srv6_cmp(const struct nexthop *nh1,
const struct nexthop *nh2)
{
int ret = 0;
+ int i = 0;
if (!nh1->nh_srv6 && !nh2->nh_srv6)
return 0;
@@ -78,9 +79,26 @@ static int _nexthop_srv6_cmp(const struct nexthop *nh1,
if (ret != 0)
return ret;
- ret = memcmp(&nh1->nh_srv6->seg6_segs,
- &nh2->nh_srv6->seg6_segs,
- sizeof(struct in6_addr));
+ if (!nh1->nh_srv6->seg6_segs && !nh2->nh_srv6->seg6_segs)
+ return 0;
+
+ if (!nh1->nh_srv6->seg6_segs && nh2->nh_srv6->seg6_segs)
+ return -1;
+
+ if (nh1->nh_srv6->seg6_segs && !nh2->nh_srv6->seg6_segs)
+ return 1;
+
+ if (nh1->nh_srv6->seg6_segs->num_segs !=
+ nh2->nh_srv6->seg6_segs->num_segs)
+ return -1;
+
+ for (i = 0; i < nh1->nh_srv6->seg6_segs->num_segs; i++) {
+ ret = memcmp(&nh1->nh_srv6->seg6_segs->seg[i],
+ &nh2->nh_srv6->seg6_segs->seg[i],
+ sizeof(struct in6_addr));
+ if (ret != 0)
+ break;
+ }
return ret;
}
@@ -155,7 +173,7 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
ret = _nexthop_gateway_cmp(next1, next2);
if (ret != 0)
return ret;
- /* Intentional Fall-Through */
+ fallthrough;
case NEXTHOP_TYPE_IFINDEX:
if (next1->ifindex < next2->ifindex)
return -1;
@@ -277,7 +295,7 @@ int nexthop_cmp_basic(const struct nexthop *nh1,
ret = nexthop_g_addr_cmp(nh1->type, &nh1->gate, &nh2->gate);
if (ret != 0)
return ret;
- /* Intentional Fall-Through */
+ fallthrough;
case NEXTHOP_TYPE_IFINDEX:
if (nh1->ifindex < nh2->ifindex)
return -1;
@@ -362,7 +380,7 @@ struct nexthop *nexthop_new(void)
* The linux kernel does some weird stuff with adding +1 to
* all nexthop weights it gets over netlink.
* To handle this, just default everything to 1 right from
- * from the beginning so we don't have to special case
+ * the beginning so we don't have to special case
* default weights in the linux netlink code.
*
* 1 should be a valid on all platforms anyway.
@@ -568,15 +586,25 @@ void nexthop_del_srv6_seg6local(struct nexthop *nexthop)
if (!nexthop->nh_srv6)
return;
+ if (nexthop->nh_srv6->seg6local_action == ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
+ return;
+
nexthop->nh_srv6->seg6local_action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
- if (sid_zero(&nexthop->nh_srv6->seg6_segs))
+ if (nexthop->nh_srv6->seg6_segs &&
+ (nexthop->nh_srv6->seg6_segs->num_segs == 0 ||
+ sid_zero(nexthop->nh_srv6->seg6_segs)))
+ XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6->seg6_segs);
+
+ if (nexthop->nh_srv6->seg6_segs == NULL)
XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6);
}
-void nexthop_add_srv6_seg6(struct nexthop *nexthop,
- const struct in6_addr *segs)
+void nexthop_add_srv6_seg6(struct nexthop *nexthop, const struct in6_addr *segs,
+ int num_segs)
{
+ int i;
+
if (!segs)
return;
@@ -584,7 +612,22 @@ void nexthop_add_srv6_seg6(struct nexthop *nexthop,
nexthop->nh_srv6 = XCALLOC(MTYPE_NH_SRV6,
sizeof(struct nexthop_srv6));
- nexthop->nh_srv6->seg6_segs = *segs;
+ /* Enforce limit on srv6 seg stack size */
+ if (num_segs > SRV6_MAX_SIDS)
+ num_segs = SRV6_MAX_SIDS;
+
+ if (!nexthop->nh_srv6->seg6_segs) {
+ nexthop->nh_srv6->seg6_segs =
+ XCALLOC(MTYPE_NH_SRV6,
+ sizeof(struct seg6_seg_stack) +
+ num_segs * sizeof(struct in6_addr));
+ }
+
+ nexthop->nh_srv6->seg6_segs->num_segs = num_segs;
+
+ for (i = 0; i < num_segs; i++)
+ memcpy(&nexthop->nh_srv6->seg6_segs->seg[i], &segs[i],
+ sizeof(struct in6_addr));
}
void nexthop_del_srv6_seg6(struct nexthop *nexthop)
@@ -592,12 +635,14 @@ void nexthop_del_srv6_seg6(struct nexthop *nexthop)
if (!nexthop->nh_srv6)
return;
- memset(&nexthop->nh_srv6->seg6_segs, 0,
- sizeof(nexthop->nh_srv6->seg6_segs));
-
- if (nexthop->nh_srv6->seg6local_action ==
- ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
- XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6);
+ if (nexthop->nh_srv6->seg6local_action == ZEBRA_SEG6_LOCAL_ACTION_UNSPEC &&
+ nexthop->nh_srv6->seg6_segs) {
+ memset(nexthop->nh_srv6->seg6_segs->seg, 0,
+ sizeof(struct in6_addr) *
+ nexthop->nh_srv6->seg6_segs->num_segs);
+ XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6->seg6_segs);
+ }
+ XFREE(MTYPE_NH_SRV6, nexthop->nh_srv6);
}
const char *nexthop2str(const struct nexthop *nexthop, char *str, int size)
@@ -743,11 +788,32 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
}
if (nexthop->nh_srv6) {
- key = jhash_1word(nexthop->nh_srv6->seg6local_action, key);
- key = jhash(&nexthop->nh_srv6->seg6local_ctx,
- sizeof(nexthop->nh_srv6->seg6local_ctx), key);
- key = jhash(&nexthop->nh_srv6->seg6_segs,
- sizeof(nexthop->nh_srv6->seg6_segs), key);
+ int segs_num = 0;
+ int i = 0;
+
+ if (nexthop->nh_srv6->seg6local_action !=
+ ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) {
+ key = jhash_1word(nexthop->nh_srv6->seg6local_action,
+ key);
+ key = jhash(&nexthop->nh_srv6->seg6local_ctx,
+ sizeof(nexthop->nh_srv6->seg6local_ctx),
+ key);
+ if (nexthop->nh_srv6->seg6_segs)
+ key = jhash(&nexthop->nh_srv6->seg6_segs->seg[0],
+ sizeof(struct in6_addr), key);
+ } else {
+ if (nexthop->nh_srv6->seg6_segs) {
+ segs_num = nexthop->nh_srv6->seg6_segs->num_segs;
+ while (segs_num >= 1) {
+ key = jhash(&nexthop->nh_srv6->seg6_segs
+ ->seg[i],
+ sizeof(struct in6_addr),
+ key);
+ segs_num -= 1;
+ i += 1;
+ }
+ }
+ }
}
return key;
@@ -797,6 +863,7 @@ void nexthop_copy_no_recurse(struct nexthop *copy,
memcpy(&copy->gate, &nexthop->gate, sizeof(nexthop->gate));
memcpy(&copy->src, &nexthop->src, sizeof(nexthop->src));
memcpy(&copy->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src));
+ memcpy(&copy->rmac, &nexthop->rmac, sizeof(nexthop->rmac));
copy->rparent = rparent;
if (nexthop->nh_label)
nexthop_add_labels(copy, nexthop->nh_label_type,
@@ -809,9 +876,13 @@ void nexthop_copy_no_recurse(struct nexthop *copy,
nexthop_add_srv6_seg6local(copy,
nexthop->nh_srv6->seg6local_action,
&nexthop->nh_srv6->seg6local_ctx);
- if (!sid_zero(&nexthop->nh_srv6->seg6_segs))
+ if (nexthop->nh_srv6->seg6_segs &&
+ nexthop->nh_srv6->seg6_segs->num_segs &&
+ !sid_zero(nexthop->nh_srv6->seg6_segs))
nexthop_add_srv6_seg6(copy,
- &nexthop->nh_srv6->seg6_segs);
+ &nexthop->nh_srv6->seg6_segs->seg[0],
+ nexthop->nh_srv6->seg6_segs
+ ->num_segs);
}
}
@@ -932,6 +1003,8 @@ ssize_t printfrr_nhs(struct fbuf *buf, const struct nexthop *nexthop)
ret += bputs(buf, "blackhole");
break;
}
+
+ ret += bprintfrr(buf, " vrfid %u", nexthop->vrf_id);
return ret;
}
@@ -1076,3 +1149,12 @@ static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea,
}
return -1;
}
+
+bool nexthop_is_ifindex_type(const struct nexthop *nh)
+{
+ if (nh->type == NEXTHOP_TYPE_IFINDEX ||
+ nh->type == NEXTHOP_TYPE_IPV4_IFINDEX ||
+ nh->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+ return true;
+ return false;
+}