summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2023-09-20 23:09:35 -0400
committerGitHub <noreply@github.com>2023-09-20 23:09:35 -0400
commit90d19d1489c7237acaad7dfa79af2080301ad60d (patch)
tree59d903742e50c7d36edf22cfcd98cff736fbf063 /lib
parent0c9aabe76040dff04c76b127f92087236a623451 (diff)
parent9f3ceabd490a4ab90dd8e8b74b4d16117edd8c10 (diff)
Merge pull request #14089 from dmytroshytyi-6WIND/srv6_multiple_segs_sids
bgpd,doc,lib,sharpd,staticd,yang,zebra: SRv6 multiple segs SIDs
Diffstat (limited to 'lib')
-rw-r--r--lib/nexthop.c112
-rw-r--r--lib/nexthop.h4
-rw-r--r--lib/srv6.h29
-rw-r--r--lib/zclient.c38
-rw-r--r--lib/zclient.h3
5 files changed, 145 insertions, 41 deletions
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 4f92ef9c8b..8df57e36a2 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;
}
@@ -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;
@@ -810,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);
}
}
diff --git a/lib/nexthop.h b/lib/nexthop.h
index 2be89f8240..bed6447d49 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -157,8 +157,8 @@ void nexthop_del_labels(struct nexthop *);
void nexthop_add_srv6_seg6local(struct nexthop *nexthop, uint32_t action,
const struct seg6local_context *ctx);
void nexthop_del_srv6_seg6local(struct nexthop *nexthop);
-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 *seg,
+ int num_segs);
void nexthop_del_srv6_seg6(struct nexthop *nexthop);
/*
diff --git a/lib/srv6.h b/lib/srv6.h
index 7c8c6b4a65..fb34f861c8 100644
--- a/lib/srv6.h
+++ b/lib/srv6.h
@@ -14,8 +14,11 @@
#include <arpa/inet.h>
#include <netinet/in.h>
-#define SRV6_MAX_SIDS 16
+#define SRV6_MAX_SIDS 16
+#define SRV6_MAX_SEGS 8
#define SRV6_LOCNAME_SIZE 256
+#define SRH_BASE_HEADER_LENGTH 8
+#define SRH_SEGMENT_LENGTH 16
#ifdef __cplusplus
extern "C" {
@@ -74,6 +77,8 @@ enum seg6local_flavor_op {
ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID = 4,
};
+#define SRV6_SEG_STRLEN 1024
+
struct seg6_segs {
size_t num_segs;
struct in6_addr segs[256];
@@ -89,6 +94,11 @@ struct seg6local_flavors_info {
uint8_t lcnode_func_len;
};
+struct seg6_seg_stack {
+ uint8_t num_segs;
+ struct in6_addr seg[0]; /* 1 or more segs */
+};
+
struct seg6local_context {
struct in_addr nh4;
struct in6_addr nh6;
@@ -170,7 +180,7 @@ struct nexthop_srv6 {
struct seg6local_context seg6local_ctx;
/* SRv6 Headend-behaviour */
- struct in6_addr seg6_segs;
+ struct seg6_seg_stack *seg6_segs;
};
static inline const char *seg6_mode2str(enum seg6_mode_t mode)
@@ -206,12 +216,21 @@ static inline bool sid_diff(
return !sid_same(a, b);
}
-static inline bool sid_zero(
- const struct in6_addr *a)
+
+static inline bool sid_zero(const struct seg6_seg_stack *a)
+{
+ struct in6_addr zero = {};
+
+ assert(a);
+
+ return sid_same(&a->seg[0], &zero);
+}
+
+static inline bool sid_zero_ipv6(const struct in6_addr *a)
{
struct in6_addr zero = {};
- return sid_same(a, &zero);
+ return sid_same(&a[0], &zero);
}
static inline void *sid_copy(struct in6_addr *dst,
diff --git a/lib/zclient.c b/lib/zclient.c
index 68a3429822..f8f9cf7aba 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1061,10 +1061,11 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
sizeof(struct seg6local_context));
}
- if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_SEG6))
- stream_write(s, &api_nh->seg6_segs,
- sizeof(struct in6_addr));
-
+ if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_SEG6)) {
+ stream_putc(s, api_nh->seg_num);
+ stream_put(s, &api_nh->seg6_segs[0],
+ api_nh->seg_num * sizeof(struct in6_addr));
+ }
done:
return ret;
}
@@ -1430,9 +1431,18 @@ int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
sizeof(struct seg6local_context));
}
- if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6))
- STREAM_GET(&api_nh->seg6_segs, s,
- sizeof(struct in6_addr));
+ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6)) {
+ STREAM_GETC(s, api_nh->seg_num);
+ if (api_nh->seg_num > SRV6_MAX_SIDS) {
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: invalid number of SRv6 Segs (%u)",
+ __func__, api_nh->seg_num);
+ return -1;
+ }
+
+ STREAM_GET(&api_nh->seg6_segs[0], s,
+ api_nh->seg_num * sizeof(struct in6_addr));
+ }
/* Success */
ret = 0;
@@ -2132,8 +2142,8 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
nexthop_add_srv6_seg6local(n, znh->seg6local_action,
&znh->seg6local_ctx);
- if (!sid_zero(&znh->seg6_segs))
- nexthop_add_srv6_seg6(n, &znh->seg6_segs);
+ if (znh->seg_num && !sid_zero_ipv6(znh->seg6_segs))
+ nexthop_add_srv6_seg6(n, &znh->seg6_segs[0], znh->seg_num);
return n;
}
@@ -2193,10 +2203,14 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
sizeof(struct seg6local_context));
}
- if (!sid_zero(&nh->nh_srv6->seg6_segs)) {
+ if (nh->nh_srv6->seg6_segs && nh->nh_srv6->seg6_segs->num_segs &&
+ !sid_zero(nh->nh_srv6->seg6_segs)) {
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6);
- memcpy(&znh->seg6_segs, &nh->nh_srv6->seg6_segs,
- sizeof(struct in6_addr));
+ znh->seg_num = nh->nh_srv6->seg6_segs->num_segs;
+ for (i = 0; i < nh->nh_srv6->seg6_segs->num_segs; i++)
+ memcpy(&znh->seg6_segs[i],
+ &nh->nh_srv6->seg6_segs->seg[i],
+ sizeof(struct in6_addr));
}
}
diff --git a/lib/zclient.h b/lib/zclient.h
index 42c5a5fdac..2a3ce4e488 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -438,7 +438,8 @@ struct zapi_nexthop {
struct seg6local_context seg6local_ctx;
/* SRv6 Headend-behaviour */
- struct in6_addr seg6_segs;
+ int seg_num;
+ struct in6_addr seg6_segs[SRV6_MAX_SEGS];
};
/*