summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/user/zebra.rst84
-rw-r--r--lib/command.h3
-rw-r--r--lib/log.c6
-rw-r--r--lib/srv6.c187
-rw-r--r--lib/srv6.h134
-rw-r--r--lib/zclient.c194
-rw-r--r--lib/zclient.h51
-rw-r--r--vtysh/vtysh.c82
-rw-r--r--zebra/zapi_msg.c162
-rw-r--r--zebra/zapi_msg.h8
-rw-r--r--zebra/zebra_errors.c12
-rw-r--r--zebra/zebra_errors.h2
-rw-r--r--zebra/zebra_srv6.c2078
-rw-r--r--zebra/zebra_srv6.h247
-rw-r--r--zebra/zebra_srv6_vty.c593
15 files changed, 3760 insertions, 83 deletions
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 37644dc88a..900d2fd343 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -1021,6 +1021,35 @@ and this section also helps that case.
!
...
+.. clicmd:: format NAME
+
+ Specify the SID allocation schema for the SIDs allocated from this locator. Currently,
+ FRR supports supports the following allocation schemas:
+
+ - `usid-f3216`
+ - `uncompressed`
+
+::
+
+ router# configure terminal
+ router(config)# segment-routinig
+ router(config-sr)# srv6
+ router(config-srv6)# locators
+ router(config-srv6-locators)# locator loc1
+ router(config-srv6-locator)# prefix fc00:0:1::/48
+ router(config-srv6-locator)# format usid-f3216
+
+ router(config-srv6-locator)# show run
+ ...
+ segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:1::/48
+ format usid-f3216
+ !
+ ...
+
.. clicmd:: encapsulation
Configure parameters for SRv6 encapsulation.
@@ -1029,6 +1058,61 @@ and this section also helps that case.
Configure the source address of the outer encapsulating IPv6 header.
+.. clicmd:: formats
+
+ Configure SRv6 SID formats.
+
+.. clicmd:: format NAME
+
+ Configure SRv6 SID format.
+
+.. clicmd:: compressed usid
+
+ Enable SRv6 uSID compression and configure SRv6 uSID compression parameters.
+
+.. clicmd:: local-id-block start START
+
+ Configure the start value for the Local ID Block (LIB).
+
+.. clicmd:: local-id-block explicit start START end END
+
+ Configure the start/end values for the Explicit LIB (ELIB).
+
+.. clicmd:: wide-local-id-block start START end END
+
+ Configure the start/end values for the Wide LIB (W-LIB).
+
+.. clicmd:: wide-local-id-block explicit start START
+
+ Configure the start value for the Explicit Wide LIB (EW-LIB).
+
+::
+
+ router# configure terminal
+ router(config)# segment-routinig
+ router(config-sr)# srv6
+ router(config-srv6)# formats
+ router(config-srv6-formats)# format usid-f3216
+ router(config-srv6-format)# compressed usid
+ router(config-srv6-format-usid)# local-id-block start 0xD000
+ router(config-srv6-format-usid)# local-id-block explicit start 0xF000 end 0xFDFF
+ router(config-srv6-format-usid)# wide-local-id-block start 0xFFF4 end 0xFFF5
+ router(config-srv6-format-usid)# wide-local-id-block explicit start 0xFFF4
+
+ router(config-srv6-locator)# show run
+ ...
+ segment-routing
+ srv6
+ formats
+ format usid-f3216
+ compressed usid
+ local-id-block start 0xD000
+ local-id-block explicit start 0xF000 end 0xFDFF
+ wide-local-id-block start 0xFFF4 end 0xFFF5
+ wide-local-id-block explicit start 0xFFF4
+ !
+ ...
+
.. _multicast-rib-commands:
Multicast RIB Commands
diff --git a/lib/command.h b/lib/command.h
index e4c575e8d7..6f819c7e36 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -161,6 +161,9 @@ enum node_type {
SRV6_LOCS_NODE, /* SRv6 locators node */
SRV6_LOC_NODE, /* SRv6 locator node */
SRV6_ENCAP_NODE, /* SRv6 encapsulation node */
+ SRV6_SID_FORMATS_NODE, /* SRv6 SID formats config node */
+ SRV6_SID_FORMAT_USID_F3216_NODE, /* SRv6 uSID f3216 format config node */
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, /* SRv6 uncompressed f4024 format config node */
VTY_NODE, /* Vty node. */
FPM_NODE, /* Dataplane FPM node. */
LINK_PARAMS_NODE, /* Link-parameters node */
diff --git a/lib/log.c b/lib/log.c
index 969ca79256..880180ae5a 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -436,6 +436,9 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_SRV6_LOCATOR_DELETE),
DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK),
DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK),
+ DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR),
+ DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_SRV6_SID),
+ DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID),
DESC_ENTRY(ZEBRA_ERROR),
DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES),
DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE),
@@ -461,7 +464,8 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_TC_CLASS_DELETE),
DESC_ENTRY(ZEBRA_TC_FILTER_ADD),
DESC_ENTRY(ZEBRA_TC_FILTER_DELETE),
- DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY)
+ DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY),
+ DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY)
};
#undef DESC_ENTRY
diff --git a/lib/srv6.c b/lib/srv6.c
index a82103e423..883d429b62 100644
--- a/lib/srv6.c
+++ b/lib/srv6.c
@@ -10,8 +10,11 @@
#include "log.h"
DEFINE_QOBJ_TYPE(srv6_locator);
+DEFINE_QOBJ_TYPE(srv6_sid_format);
DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR, "SRV6 locator");
DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR_CHUNK, "SRV6 locator chunk");
+DEFINE_MTYPE_STATIC(LIB, SRV6_SID_FORMAT, "SRv6 SID format");
+DEFINE_MTYPE_STATIC(LIB, SRV6_SID_CTX, "SRv6 SID context");
const char *seg6local_action2str(uint32_t action)
{
@@ -139,6 +142,21 @@ struct srv6_locator_chunk *srv6_locator_chunk_alloc(void)
return chunk;
}
+void srv6_locator_copy(struct srv6_locator *copy,
+ const struct srv6_locator *locator)
+{
+ strlcpy(copy->name, locator->name, sizeof(locator->name));
+ copy->prefix = locator->prefix;
+ copy->block_bits_length = locator->block_bits_length;
+ copy->node_bits_length = locator->node_bits_length;
+ copy->function_bits_length = locator->function_bits_length;
+ copy->argument_bits_length = locator->argument_bits_length;
+ copy->algonum = locator->algonum;
+ copy->current = locator->current;
+ copy->status_up = locator->status_up;
+ copy->flags = locator->flags;
+}
+
void srv6_locator_free(struct srv6_locator *locator)
{
if (locator) {
@@ -154,6 +172,59 @@ void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk)
XFREE(MTYPE_SRV6_LOCATOR_CHUNK, *chunk);
}
+struct srv6_sid_format *srv6_sid_format_alloc(const char *name)
+{
+ struct srv6_sid_format *format = NULL;
+
+ format = XCALLOC(MTYPE_SRV6_SID_FORMAT, sizeof(struct srv6_sid_format));
+ strlcpy(format->name, name, sizeof(format->name));
+
+ QOBJ_REG(format, srv6_sid_format);
+ return format;
+}
+
+void srv6_sid_format_free(struct srv6_sid_format *format)
+{
+ if (!format)
+ return;
+
+ QOBJ_UNREG(format);
+ XFREE(MTYPE_SRV6_SID_FORMAT, format);
+}
+
+/**
+ * Free an SRv6 SID format.
+ *
+ * @param val SRv6 SID format to be freed
+ */
+void delete_srv6_sid_format(void *val)
+{
+ srv6_sid_format_free((struct srv6_sid_format *)val);
+}
+
+struct srv6_sid_ctx *srv6_sid_ctx_alloc(enum seg6local_action_t behavior,
+ struct in_addr *nh4,
+ struct in6_addr *nh6, vrf_id_t vrf_id)
+{
+ struct srv6_sid_ctx *ctx = NULL;
+
+ ctx = XCALLOC(MTYPE_SRV6_SID_CTX, sizeof(struct srv6_sid_ctx));
+ ctx->behavior = behavior;
+ if (nh4)
+ ctx->nh4 = *nh4;
+ if (nh6)
+ ctx->nh6 = *nh6;
+ if (vrf_id)
+ ctx->vrf_id = vrf_id;
+
+ return ctx;
+}
+
+void srv6_sid_ctx_free(struct srv6_sid_ctx *ctx)
+{
+ XFREE(MTYPE_SRV6_SID_CTX, ctx);
+}
+
json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk)
{
json_object *jo_root = NULL;
@@ -223,23 +294,47 @@ json_object *srv6_locator_json(const struct srv6_locator *loc)
/* set prefix */
json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix);
- /* set block_bits_length */
- json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length);
-
- /* set node_bits_length */
- json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length);
-
- /* set function_bits_length */
- json_object_int_add(jo_root, "functionBitsLength",
- loc->function_bits_length);
-
- /* set argument_bits_length */
- json_object_int_add(jo_root, "argumentBitsLength",
- loc->argument_bits_length);
-
- /* set true if the locator is a Micro-segment (uSID) locator */
- if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID))
- json_object_string_add(jo_root, "behavior", "usid");
+ if (loc->sid_format) {
+ /* set block_bits_length */
+ json_object_int_add(jo_root, "blockBitsLength",
+ loc->sid_format->block_len);
+
+ /* set node_bits_length */
+ json_object_int_add(jo_root, "nodeBitsLength",
+ loc->sid_format->node_len);
+
+ /* set function_bits_length */
+ json_object_int_add(jo_root, "functionBitsLength",
+ loc->sid_format->function_len);
+
+ /* set argument_bits_length */
+ json_object_int_add(jo_root, "argumentBitsLength",
+ loc->sid_format->argument_len);
+
+ /* set true if the locator is a Micro-segment (uSID) locator */
+ if (loc->sid_format->type == SRV6_SID_FORMAT_TYPE_USID)
+ json_object_string_add(jo_root, "behavior", "usid");
+ } else {
+ /* set block_bits_length */
+ json_object_int_add(jo_root, "blockBitsLength",
+ loc->block_bits_length);
+
+ /* set node_bits_length */
+ json_object_int_add(jo_root, "nodeBitsLength",
+ loc->node_bits_length);
+
+ /* set function_bits_length */
+ json_object_int_add(jo_root, "functionBitsLength",
+ loc->function_bits_length);
+
+ /* set argument_bits_length */
+ json_object_int_add(jo_root, "argumentBitsLength",
+ loc->argument_bits_length);
+
+ /* set true if the locator is a Micro-segment (uSID) locator */
+ if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID))
+ json_object_string_add(jo_root, "behavior", "usid");
+ }
/* set status_up */
json_object_boolean_add(jo_root, "statusUp",
@@ -272,23 +367,47 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc)
/* set prefix */
json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix);
- /* set block_bits_length */
- json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length);
-
- /* set node_bits_length */
- json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length);
-
- /* set function_bits_length */
- json_object_int_add(jo_root, "functionBitsLength",
- loc->function_bits_length);
-
- /* set argument_bits_length */
- json_object_int_add(jo_root, "argumentBitsLength",
- loc->argument_bits_length);
-
- /* set true if the locator is a Micro-segment (uSID) locator */
- if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID))
- json_object_string_add(jo_root, "behavior", "usid");
+ if (loc->sid_format) {
+ /* set block_bits_length */
+ json_object_int_add(jo_root, "blockBitsLength",
+ loc->sid_format->block_len);
+
+ /* set node_bits_length */
+ json_object_int_add(jo_root, "nodeBitsLength",
+ loc->sid_format->node_len);
+
+ /* set function_bits_length */
+ json_object_int_add(jo_root, "functionBitsLength",
+ loc->sid_format->function_len);
+
+ /* set argument_bits_length */
+ json_object_int_add(jo_root, "argumentBitsLength",
+ loc->sid_format->argument_len);
+
+ /* set true if the locator is a Micro-segment (uSID) locator */
+ if (loc->sid_format->type == SRV6_SID_FORMAT_TYPE_USID)
+ json_object_string_add(jo_root, "behavior", "usid");
+ } else {
+ /* set block_bits_length */
+ json_object_int_add(jo_root, "blockBitsLength",
+ loc->block_bits_length);
+
+ /* set node_bits_length */
+ json_object_int_add(jo_root, "nodeBitsLength",
+ loc->node_bits_length);
+
+ /* set function_bits_length */
+ json_object_int_add(jo_root, "functionBitsLength",
+ loc->function_bits_length);
+
+ /* set argument_bits_length */
+ json_object_int_add(jo_root, "argumentBitsLength",
+ loc->argument_bits_length);
+
+ /* set true if the locator is a Micro-segment (uSID) locator */
+ if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID))
+ json_object_string_add(jo_root, "behavior", "usid");
+ }
/* set algonum */
json_object_int_add(jo_root, "algoNum", loc->algonum);
diff --git a/lib/srv6.h b/lib/srv6.h
index 433c5c14fd..01b0820133 100644
--- a/lib/srv6.h
+++ b/lib/srv6.h
@@ -20,6 +20,8 @@
#define SRH_BASE_HEADER_LENGTH 8
#define SRH_SEGMENT_LENGTH 16
+#define SRV6_SID_FORMAT_NAME_SIZE 512
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -127,6 +129,12 @@ struct srv6_locator {
uint8_t flags;
#define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */
+ /* Pointer to the SID format. */
+ struct srv6_sid_format *sid_format;
+
+ /* Pointer to the parent SID block of the locator. */
+ void *sid_block;
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(srv6_locator);
@@ -183,6 +191,72 @@ struct nexthop_srv6 {
struct seg6_seg_stack *seg6_segs;
};
+/* SID format type */
+enum srv6_sid_format_type {
+ SRV6_SID_FORMAT_TYPE_UNSPEC = 0,
+ /* SRv6 SID uncompressed format */
+ SRV6_SID_FORMAT_TYPE_UNCOMPRESSED = 1,
+ /* SRv6 SID compressed uSID format */
+ SRV6_SID_FORMAT_TYPE_USID = 2,
+};
+
+/* SRv6 SID format */
+struct srv6_sid_format {
+ /* Name of the format */
+ char name[SRV6_SID_FORMAT_NAME_SIZE];
+
+ /* Format type: uncompressed vs compressed */
+ enum srv6_sid_format_type type;
+
+ /*
+ * Lengths of block/node/function/argument parts of the SIDs allocated
+ * using this format
+ */
+ uint8_t block_len;
+ uint8_t node_len;
+ uint8_t function_len;
+ uint8_t argument_len;
+
+ union {
+ /* Configuration settings for compressed uSID format type */
+ struct {
+ /* Start of the Local ID Block (LIB) range */
+ uint32_t lib_start;
+
+ /* Start/End of the Explicit LIB range */
+ uint32_t elib_start;
+ uint32_t elib_end;
+
+ /* Start/End of the Wide LIB range */
+ uint32_t wlib_start;
+ uint32_t wlib_end;
+
+ /* Start/End of the Explicit Wide LIB range */
+ uint32_t ewlib_start;
+ } usid;
+
+ /* Configuration settings for uncompressed format type */
+ struct {
+ /* Start of the Explicit range */
+ uint32_t explicit_start;
+ } uncompressed;
+ } config;
+
+ QOBJ_FIELDS;
+};
+DECLARE_QOBJ_TYPE(srv6_sid_format);
+
+/* Context for an SRv6 SID */
+struct srv6_sid_ctx {
+ /* Behavior associated with the SID */
+ enum seg6local_action_t behavior;
+
+ /* Behavior-specific attributes */
+ struct in_addr nh4;
+ struct in6_addr nh6;
+ vrf_id_t vrf_id;
+};
+
static inline const char *seg6_mode2str(enum seg6_mode_t mode)
{
switch (mode) {
@@ -246,6 +320,54 @@ const char *seg6local_context2str(char *str, size_t size,
const struct seg6local_context *ctx,
uint32_t action);
+static inline const char *srv6_sid_ctx2str(char *str, size_t size,
+ const struct srv6_sid_ctx *ctx)
+{
+ int len = 0;
+
+ len += snprintf(str + len, size - len, "%s",
+ seg6local_action2str(ctx->behavior));
+
+ switch (ctx->behavior) {
+ case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
+ break;
+
+ case ZEBRA_SEG6_LOCAL_ACTION_END:
+ len += snprintf(str + len, size - len, " USP");
+ break;
+
+ case ZEBRA_SEG6_LOCAL_ACTION_END_X:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
+ len += snprintfrr(str + len, size - len, " nh6 %pI6", &ctx->nh6);
+ break;
+
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
+ len += snprintfrr(str + len, size - len, " nh4 %pI4", &ctx->nh4);
+ break;
+
+ case ZEBRA_SEG6_LOCAL_ACTION_END_T:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
+ len += snprintf(str + len, size - len, " vrf_id %u",
+ ctx->vrf_id);
+ break;
+
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_S:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_BPF:
+ default:
+ len += snprintf(str + len, size - len, " unknown(%s)", __func__);
+ }
+
+ return str;
+}
+
int snprintf_seg6_segs(char *str,
size_t size, const struct seg6_segs *segs);
@@ -254,12 +376,24 @@ extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void);
extern void srv6_locator_free(struct srv6_locator *locator);
extern void srv6_locator_chunk_list_free(void *data);
extern void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk);
+extern void srv6_locator_copy(struct srv6_locator *copy,
+ const struct srv6_locator *locator);
json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk);
json_object *srv6_locator_json(const struct srv6_locator *loc);
json_object *srv6_locator_detailed_json(const struct srv6_locator *loc);
json_object *
srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk);
+extern struct srv6_sid_format *srv6_sid_format_alloc(const char *name);
+extern void srv6_sid_format_free(struct srv6_sid_format *format);
+extern void delete_srv6_sid_format(void *format);
+
+extern struct srv6_sid_ctx *srv6_sid_ctx_alloc(enum seg6local_action_t behavior,
+ struct in_addr *nh4,
+ struct in6_addr *nh6,
+ vrf_id_t vrf_id);
+extern void srv6_sid_ctx_free(struct srv6_sid_ctx *ctx);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/zclient.c b/lib/zclient.c
index ca4880da43..0e832f0d8f 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1125,6 +1125,10 @@ int zapi_srv6_locator_encode(struct stream *s, const struct srv6_locator *l)
stream_put(s, l->name, strlen(l->name));
stream_putw(s, l->prefix.prefixlen);
stream_put(s, &l->prefix.prefix, sizeof(l->prefix.prefix));
+ stream_putc(s, l->block_bits_length);
+ stream_putc(s, l->node_bits_length);
+ stream_putc(s, l->function_bits_length);
+ stream_putc(s, l->argument_bits_length);
stream_putc(s, l->flags);
return 0;
}
@@ -1141,6 +1145,10 @@ int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l)
STREAM_GETW(s, l->prefix.prefixlen);
STREAM_GET(&l->prefix.prefix, s, sizeof(l->prefix.prefix));
l->prefix.family = AF_INET6;
+ STREAM_GETC(s, l->block_bits_length);
+ STREAM_GETC(s, l->node_bits_length);
+ STREAM_GETC(s, l->function_bits_length);
+ STREAM_GETC(s, l->argument_bits_length);
STREAM_GETC(s, l->flags);
return 0;
@@ -2125,6 +2133,46 @@ stream_failure:
return false;
}
+bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value, uint32_t *func,
+ uint32_t *wide_func,
+ enum zapi_srv6_sid_notify *note,
+ char **p_locator_name)
+{
+ uint32_t f, wf;
+ uint16_t len;
+ static char locator_name[SRV6_LOCNAME_SIZE] = {};
+
+ STREAM_GET(note, s, sizeof(*note));
+ STREAM_GET(ctx, s, sizeof(struct srv6_sid_ctx));
+ STREAM_GET(sid_value, s, sizeof(struct in6_addr));
+ STREAM_GETL(s, f);
+ STREAM_GETL(s, wf);
+
+ if (func)
+ *func = f;
+ if (wide_func)
+ *wide_func = wf;
+
+ STREAM_GETW(s, len);
+ if (len > SRV6_LOCNAME_SIZE) {
+ *p_locator_name = NULL;
+ return false;
+ }
+ if (p_locator_name) {
+ if (len == 0)
+ *p_locator_name = NULL;
+ else {
+ STREAM_GET(locator_name, s, len);
+ *p_locator_name = locator_name;
+ }
+ }
+ return true;
+
+stream_failure:
+ return false;
+}
+
struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
{
struct nexthop *n = nexthop_new();
@@ -3269,10 +3317,154 @@ int srv6_manager_release_locator_chunk(struct zclient *zclient,
return zclient_send_message(zclient);
}
+/**
+ * Function to request a SRv6 locator in an asynchronous way
+ *
+ * @param zclient The zclient used to connect to SRv6 Manager (zebra)
+ * @param locator_name Name of SRv6 locator
+ * @return 0 on success, -1 otherwise
+ */
+int srv6_manager_get_locator(struct zclient *zclient, const char *locator_name)
+{
+ struct stream *s;
+ size_t len;
+
+ if (!locator_name)
+ return -1;
+
+ if (zclient->sock < 0) {
+ flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket",
+ __func__);
+ return -1;
+ }
+
+ if (zclient_debug)
+ zlog_debug("Getting SRv6 Locator %s", locator_name);
+
+ len = strlen(locator_name);
+
+ /* Send request */
+ s = zclient->obuf;
+ stream_reset(s);
+ zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR, VRF_DEFAULT);
+
+ /* Locator name */
+ stream_putw(s, len);
+ stream_put(s, locator_name, len);
+
+ /* Put length at the first point of the stream. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return zclient_send_message(zclient);
+}
+
+/**
+ * Function to request an SRv6 SID in an asynchronous way
+ *
+ * @param zclient The zclient used to connect to SRv6 manager (zebra)
+ * @param ctx Context associated with the SRv6 SID
+ * @param sid_value SRv6 SID value for explicit SID allocation
+ * @param locator_name Name of the parent locator for dynamic SID allocation
+ * @param sid_func SID function assigned by the SRv6 Manager
+ * @result 0 on success, -1 otherwise
+ */
+int srv6_manager_get_sid(struct zclient *zclient, const struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value, const char *locator_name,
+ uint32_t *sid_func)
+{
+ struct stream *s;
+ uint8_t flags = 0;
+ size_t len;
+ char buf[256];
+
+ if (zclient->sock < 0) {
+ flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket",
+ __func__);
+ return ZCLIENT_SEND_FAILURE;
+ }
+
+ if (zclient_debug)
+ zlog_debug("Getting SRv6 SID: %s",
+ srv6_sid_ctx2str(buf, sizeof(buf), ctx));
+
+ /* send request */
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_SRV6_SID, VRF_DEFAULT);
+
+ /* Context associated with the SRv6 SID */
+ stream_put(s, ctx, sizeof(struct srv6_sid_ctx));
+
+ /* Flags */
+ if (!sid_zero_ipv6(sid_value))
+ SET_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE);
+ if (locator_name)
+ SET_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR);
+ stream_putc(s, flags);
+
+ /* SRv6 SID value */
+ if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE))
+ stream_put(s, sid_value, sizeof(struct in6_addr));
+
+ /* SRv6 locator */
+ if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) {
+ len = strlen(locator_name);
+ stream_putw(s, len);
+ stream_put(s, locator_name, len);
+ }
+
+ /* Put length at the first point of the stream. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ /* Send the request to SRv6 Manager */
+ return zclient_send_message(zclient);
+}
+
+/**
+ * Function to release an SRv6 SID
+ *
+ * @param zclient Zclient used to connect to SRv6 manager (zebra)
+ * @param ctx Context associated with the SRv6 SID to be removed
+ * @result 0 on success, -1 otherwise
+ */
+int srv6_manager_release_sid(struct zclient *zclient,
+ const struct srv6_sid_ctx *ctx)
+{
+ struct stream *s;
+ char buf[256];
+
+ if (zclient->sock < 0) {
+ flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket",
+ __func__);
+ return -1;
+ }
+
+ if (zclient_debug)
+ zlog_debug("Releasing SRv6 SID: %s",
+ srv6_sid_ctx2str(buf, sizeof(buf), ctx));
+
+ /* send request */
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID,
+ VRF_DEFAULT);
+
+ /* Context associated with the SRv6 SID */
+ stream_put(s, ctx, sizeof(struct srv6_sid_ctx));
+
+ /* Put length at the first point of the stream. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ /* Send the SID release message */
+ return zclient_send_message(zclient);
+}
+
/*
* Asynchronous label chunk request
*
- * @param zclient Zclient used to connect to label manager (zebra)
+ * @param zclient The zclient used to connect to label manager (zebra)
* @param keep Avoid garbage collection
* @param chunk_size Amount of labels requested
* @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care
diff --git a/lib/zclient.h b/lib/zclient.h
index 3759f94542..2877b347d8 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -209,6 +209,9 @@ typedef enum {
ZEBRA_SRV6_LOCATOR_DELETE,
ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK,
ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK,
+ ZEBRA_SRV6_MANAGER_GET_LOCATOR,
+ ZEBRA_SRV6_MANAGER_GET_SRV6_SID,
+ ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID,
ZEBRA_ERROR,
ZEBRA_CLIENT_CAPABILITIES,
ZEBRA_OPAQUE_MESSAGE,
@@ -235,6 +238,7 @@ typedef enum {
ZEBRA_TC_FILTER_ADD,
ZEBRA_TC_FILTER_DELETE,
ZEBRA_OPAQUE_NOTIFY,
+ ZEBRA_SRV6_SID_NOTIFY,
} zebra_message_types_t;
/* Zebra message types. Please update the corresponding
* command_types array with any changes!
@@ -761,6 +765,13 @@ enum zapi_iptable_notify_owner {
ZAPI_IPTABLE_FAIL_REMOVE,
};
+enum zapi_srv6_sid_notify {
+ ZAPI_SRV6_SID_FAIL_ALLOC = 0,
+ ZAPI_SRV6_SID_ALLOCATED,
+ ZAPI_SRV6_SID_RELEASED,
+ ZAPI_SRV6_SID_FAIL_RELEASE,
+};
+
enum zclient_send_status {
ZCLIENT_SEND_FAILURE = -1,
ZCLIENT_SEND_SUCCESS = 0,
@@ -813,6 +824,28 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note)
return ret;
}
+static inline const char *zapi_srv6_sid_notify2str(enum zapi_srv6_sid_notify note)
+{
+ const char *ret = "UNKNOWN";
+
+ switch (note) {
+ case ZAPI_SRV6_SID_FAIL_ALLOC:
+ ret = "ZAPI_SRV6_SID_FAIL_ALLOC";
+ break;
+ case ZAPI_SRV6_SID_ALLOCATED:
+ ret = "ZAPI_SRV6_SID_ALLOCATED";
+ break;
+ case ZAPI_SRV6_SID_FAIL_RELEASE:
+ ret = "ZAPI_SRV6_SID_FAIL_RELEASE";
+ break;
+ case ZAPI_SRV6_SID_RELEASED:
+ ret = "ZAPI_SRV6_SID_RELEASED";
+ break;
+ }
+
+ return ret;
+}
+
/* Zebra MAC types */
#define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/
#define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/
@@ -1070,10 +1103,23 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
uint32_t *start, uint32_t *end);
extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
uint32_t end);
+
+/* Zebra SRv6 Manager flags */
+#define ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE 0x01
+#define ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR 0x02
+
extern int srv6_manager_get_locator_chunk(struct zclient *zclient,
const char *locator_name);
extern int srv6_manager_release_locator_chunk(struct zclient *zclient,
const char *locator_name);
+extern int srv6_manager_get_locator(struct zclient *zclient,
+ const char *locator_name);
+extern int srv6_manager_get_sid(struct zclient *zclient,
+ const struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value,
+ const char *locator_name, uint32_t *sid_func);
+extern int srv6_manager_release_sid(struct zclient *zclient,
+ const struct srv6_sid_ctx *ctx);
extern enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient,
int cmd,
@@ -1128,6 +1174,11 @@ bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno,
bool zapi_ipset_notify_decode(struct stream *s,
uint32_t *unique,
enum zapi_ipset_notify_owner *note);
+bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value, uint32_t *func,
+ uint32_t *wide_func,
+ enum zapi_srv6_sid_notify *note,
+ char **locator_name);
/* Nexthop-group message apis */
extern enum zclient_send_status
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index b1c957d043..573320667c 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1344,6 +1344,27 @@ static struct cmd_node srv6_encap_node = {
.prompt = "%s(config-srv6-encap)# "
};
+static struct cmd_node srv6_sid_formats_node = {
+ .name = "srv6-formats",
+ .node = SRV6_SID_FORMATS_NODE,
+ .parent_node = SRV6_NODE,
+ .prompt = "%s(config-srv6-formats)# ",
+};
+
+static struct cmd_node srv6_sid_format_usid_f3216_node = {
+ .name = "srv6-format-usid-f3216",
+ .node = SRV6_SID_FORMAT_USID_F3216_NODE,
+ .parent_node = SRV6_SID_FORMATS_NODE,
+ .prompt = "%s(config-srv6-format)# "
+};
+
+static struct cmd_node srv6_sid_format_uncompressed_f4024_node = {
+ .name = "srv6-format-uncompressed-f4024",
+ .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE,
+ .parent_node = SRV6_SID_FORMATS_NODE,
+ .prompt = "%s(config-srv6-format)# "
+};
+
#ifdef HAVE_PBRD
static struct cmd_node pbr_map_node = {
.name = "pbr-map",
@@ -1715,6 +1736,31 @@ DEFUNSH(VTYSH_ZEBRA, srv6_encap, srv6_encap_cmd,
return CMD_SUCCESS;
}
+DEFUNSH(VTYSH_ZEBRA, srv6_sid_formats, srv6_sid_formats_cmd, "formats",
+ "Segment Routing SRv6 SID formats\n")
+{
+ vty->node = SRV6_SID_FORMATS_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_ZEBRA, srv6_sid_format_f3216_usid, srv6_sid_format_f3216_usid_cmd,
+ "format usid-f3216",
+ "Configure SRv6 SID format\n"
+ "Configure the uSID f3216 format\n")
+{
+ vty->node = SRV6_SID_FORMAT_USID_F3216_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_ZEBRA, srv6_sid_format_f4024_uncompressed, srv6_sid_format_f4024_uncompressed_cmd,
+ "format uncompressed-f4024",
+ "Configure SRv6 SID format\n"
+ "Configure the uncompressed f4024 format\n")
+{
+ vty->node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE;
+ return CMD_SUCCESS;
+}
+
#ifdef HAVE_BGPD
DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd,
"router bgp [ASNUM [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
@@ -2515,6 +2561,23 @@ DEFUNSH(VTYSH_ZEBRA, exit_srv6_encap, exit_srv6_encap_cmd, "exit",
return CMD_SUCCESS;
}
+DEFUNSH(VTYSH_ZEBRA, exit_srv6_sid_formats, exit_srv6_sid_formats_cmd, "exit",
+ "Exit from SRv6 SID formats configuration mode\n")
+{
+ if (vty->node == SRV6_SID_FORMATS_NODE)
+ vty->node = SRV6_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_ZEBRA, exit_srv6_sid_format, exit_srv6_sid_format_cmd,
+ "exit", "Exit from SRv6 SID format configuration mode\n")
+{
+ if (vty->node == SRV6_SID_FORMAT_USID_F3216_NODE ||
+ vty->node == SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE)
+ vty->node = SRV6_SID_FORMATS_NODE;
+ return CMD_SUCCESS;
+}
+
#ifdef HAVE_RIPD
DEFUNSH(VTYSH_MGMTD, vtysh_exit_ripd, vtysh_exit_ripd_cmd, "exit",
"Exit current mode and down to previous mode\n")
@@ -5304,6 +5367,7 @@ void vtysh_init_vty(void)
install_node(&srv6_node);
install_element(SEGMENT_ROUTING_NODE, &srv6_cmd);
install_element(SRV6_NODE, &srv6_locators_cmd);
+ install_element(SRV6_NODE, &srv6_sid_formats_cmd);
install_element(SRV6_NODE, &exit_srv6_config_cmd);
install_element(SRV6_NODE, &vtysh_end_all_cmd);
install_element(SRV6_NODE, &srv6_encap_cmd);
@@ -5321,6 +5385,24 @@ void vtysh_init_vty(void)
install_element(SRV6_ENCAP_NODE, &exit_srv6_encap_cmd);
install_element(SRV6_ENCAP_NODE, &vtysh_end_all_cmd);
+ install_node(&srv6_sid_formats_node);
+ install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd);
+ install_element(SRV6_SID_FORMATS_NODE,
+ &srv6_sid_format_f4024_uncompressed_cmd);
+ install_element(SRV6_SID_FORMATS_NODE, &exit_srv6_sid_formats_cmd);
+ install_element(SRV6_SID_FORMATS_NODE, &vtysh_end_all_cmd);
+
+ install_node(&srv6_sid_format_usid_f3216_node);
+ install_element(SRV6_SID_FORMAT_USID_F3216_NODE,
+ &exit_srv6_sid_format_cmd);
+ install_element(SRV6_SID_FORMAT_USID_F3216_NODE, &vtysh_end_all_cmd);
+
+ install_node(&srv6_sid_format_uncompressed_f4024_node);
+ install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE,
+ &exit_srv6_sid_format_cmd);
+ install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE,
+ &vtysh_end_all_cmd);
+
install_element(ENABLE_NODE, &vtysh_show_running_config_cmd);
install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd);
install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd);
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index d585ef996b..2a1eea9594 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -999,6 +999,48 @@ void zsend_neighbor_notify(int cmd, struct interface *ifp,
}
}
+void zsend_srv6_sid_notify(struct zserv *client, const struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value, uint32_t func,
+ uint32_t wide_func, const char *locator_name,
+ enum zapi_srv6_sid_notify note)
+
+{
+ struct stream *s;
+ uint16_t cmd = ZEBRA_SRV6_SID_NOTIFY;
+ char buf[256];
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: notifying %s ctx %s sid %pI6 note %s (proto=%u, instance=%u, sessionId=%u)",
+ __func__, zserv_command_string(cmd),
+ srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value,
+ zapi_srv6_sid_notify2str(note), client->proto,
+ client->instance, client->session_id);
+
+ s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+ zclient_create_header(s, cmd, VRF_DEFAULT);
+ /* Notification type (e.g. ZAPI_SRV6_SID_ALLOCATED, ZAPI_SRV6_SID_FAIL_ALLOC, ...) */
+ stream_put(s, &note, sizeof(note));
+ /* Context associated with the SRv6 SID */
+ stream_put(s, ctx, sizeof(struct srv6_sid_ctx));
+ /* SRv6 SID value (i.e. IPv6 address) */
+ stream_put(s, sid_value, sizeof(struct in6_addr));
+ /* SRv6 SID function */
+ stream_putl(s, func);
+ /* SRv6 wide SID function */
+ stream_putl(s, wide_func);
+ /* SRv6 locator name optional */
+ if (locator_name) {
+ stream_putw(s, strlen(locator_name));
+ stream_put(s, locator_name, strlen(locator_name));
+ } else
+ stream_putw(s, 0);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ zserv_send_message(client, s);
+}
+
/* Router-id is updated. Send ZEBRA_ROUTER_ID_UPDATE to client. */
int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p,
@@ -1136,9 +1178,25 @@ static int zsend_table_manager_connect_response(struct zserv *client,
int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc)
{
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ struct srv6_locator locator = {};
+ struct srv6_sid_format *format = loc->sid_format;
+
+ /*
+ * Copy the locator and fill locator block/node/func/arg length from the format
+ * before sending the locator to the zclient
+ */
+ srv6_locator_copy(&locator, loc);
+ if (format) {
+ locator.block_bits_length = format->block_len;
+ locator.node_bits_length = format->node_len;
+ locator.function_bits_length = format->function_len;
+ locator.argument_bits_length = format->argument_len;
+ if (format->type == SRV6_SID_FORMAT_TYPE_USID)
+ SET_FLAG(locator.flags, SRV6_LOCATOR_USID);
+ }
zclient_create_header(s, ZEBRA_SRV6_LOCATOR_ADD, VRF_DEFAULT);
- zapi_srv6_locator_encode(s, loc);
+ zapi_srv6_locator_encode(s, &locator);
stream_putw_at(s, 0, stream_get_endp(s));
return zserv_send_message(client, s);
@@ -2990,6 +3048,96 @@ stream_failure:
return;
}
+/**
+ * Handle SRv6 SID request received from a client daemon protocol.
+ *
+ * @param client The client zapi session
+ * @param msg The request message
+ */
+static void zread_srv6_manager_get_srv6_sid(struct zserv *client,
+ struct stream *msg)
+{
+ struct stream *s;
+ struct srv6_sid_ctx ctx = {};
+ struct in6_addr sid_value = {};
+ struct in6_addr *sid_value_ptr = NULL;
+ char locator[SRV6_LOCNAME_SIZE] = { 0 };
+ uint16_t len;
+ struct zebra_srv6_sid *sid = NULL;
+ uint8_t flags;
+
+ /* Get input stream */
+ s = msg;
+
+ /* Get data */
+ STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx));
+ STREAM_GETC(s, flags);
+ if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) {
+ STREAM_GET(&sid_value, s, sizeof(struct in6_addr));
+ sid_value_ptr = &sid_value;
+ }
+ if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) {
+ STREAM_GETW(s, len);
+ STREAM_GET(locator, s, len);
+ }
+
+ /* Call hook to get a SID using wrapper */
+ srv6_manager_get_sid_call(&sid, client, &ctx, sid_value_ptr, locator);
+
+stream_failure:
+ return;
+}
+
+/**
+ * Handle SRv6 SID release request received from a client daemon protocol.
+ *
+ * @param client The client zapi session
+ * @param msg The request message
+ */
+static void zread_srv6_manager_release_srv6_sid(struct zserv *client,
+ struct stream *msg)
+{
+ struct stream *s;
+ struct srv6_sid_ctx ctx = {};
+
+ /* Get input stream */
+ s = msg;
+
+ /* Get data */
+ STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx));
+
+ /* Call hook to release a SID using wrapper */
+ srv6_manager_release_sid_call(client, &ctx);
+
+stream_failure:
+ return;
+}
+
+/**
+ * Handle SRv6 locator get request received from a client daemon protocol.
+ *
+ * @param client The client zapi session
+ * @param msg The request message
+ */
+static void zread_srv6_manager_get_locator(struct zserv *client,
+ struct stream *msg)
+{
+ struct stream *s = msg;
+ uint16_t len;
+ char locator_name[SRV6_LOCNAME_SIZE] = { 0 };
+ struct srv6_locator *locator = NULL;
+
+ /* Get data */
+ STREAM_GETW(s, len);
+ STREAM_GET(locator_name, s, len);
+
+ /* Call hook to get the locator info using wrapper */
+ srv6_manager_get_locator_call(&locator, client, locator_name);
+
+stream_failure:
+ return;
+}
+
static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS)
{
switch (hdr->command) {
@@ -3001,6 +3149,15 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS)
zread_srv6_manager_release_locator_chunk(client, msg,
zvrf_id(zvrf));
break;
+ case ZEBRA_SRV6_MANAGER_GET_SRV6_SID:
+ zread_srv6_manager_get_srv6_sid(client, msg);
+ break;
+ case ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID:
+ zread_srv6_manager_release_srv6_sid(client, msg);
+ break;
+ case ZEBRA_SRV6_MANAGER_GET_LOCATOR:
+ zread_srv6_manager_get_locator(client, msg);
+ break;
default:
zlog_err("%s: unknown SRv6 Manager command", __func__);
break;
@@ -3949,6 +4106,9 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg,
[ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request,
[ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request,
+ [ZEBRA_SRV6_MANAGER_GET_SRV6_SID] = zread_srv6_manager_request,
+ [ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID] = zread_srv6_manager_request,
+ [ZEBRA_SRV6_MANAGER_GET_LOCATOR] = zread_srv6_manager_request,
[ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities,
[ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover,
[ZEBRA_NHG_ADD] = zread_nhg_add,
diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h
index 43f734d26e..9e3ea6fb6e 100644
--- a/zebra/zapi_msg.h
+++ b/zebra/zapi_msg.h
@@ -94,6 +94,11 @@ extern int zsend_sr_policy_notify_status(uint32_t color,
extern void zsend_neighbor_notify(int cmd, struct interface *ifp,
struct ipaddr *ipaddr, int ndm_state,
union sockunion *link_layer_ipv4, int ip_len);
+extern void zsend_srv6_sid_notify(struct zserv *client,
+ const struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value, uint32_t func,
+ uint32_t wide_func, const char *locator_name,
+ enum zapi_srv6_sid_notify note);
extern int zsend_client_close_notify(struct zserv *client,
struct zserv *closed_client);
@@ -110,6 +115,9 @@ extern int zsend_zebra_srv6_locator_delete(struct zserv *client,
extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client,
vrf_id_t vrf_id, struct srv6_locator *loc);
+extern int zsend_srv6_manager_get_locator_response(struct zserv *client,
+ struct srv6_locator *locator);
+
#ifdef __cplusplus
}
#endif
diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c
index 09b369e23e..dcfa37d268 100644
--- a/zebra/zebra_errors.c
+++ b/zebra/zebra_errors.c
@@ -788,6 +788,18 @@ static struct log_ref ferr_zebra_err[] = {
"Wait for Zebra to reattempt update.",
},
{
+ .code = EC_ZEBRA_SM_CANNOT_ASSIGN_SID,
+ .title = "SRv6 manager unable to assign SID",
+ .description = "Zebra's SRv6 manager was unable to assign a SID to client.",
+ .suggestion = "Ensure that Zebra has a sufficient SID range available.",
+ },
+ {
+ .code = EC_ZEBRA_SM_DAEMON_MISMATCH,
+ .title = "Daemon mismatch when releasing SRV6 SIDs",
+ .description = "Zebra noticed a mismatch between a SRv6 SID and a protocol daemon number or instance when releasing unused SRv6 SIDs.",
+ .suggestion = "Ignore this error.",
+ },
+ {
.code = END_FERR,
}
};
diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h
index 3ac654bda5..84632e1ad5 100644
--- a/zebra/zebra_errors.h
+++ b/zebra/zebra_errors.h
@@ -124,6 +124,8 @@ enum zebra_log_refs {
EC_ZEBRA_GRE_SET_UPDATE,
EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK,
EC_ZEBRA_INTF_UPDATE_FAILURE,
+ EC_ZEBRA_SM_CANNOT_ASSIGN_SID,
+ EC_ZEBRA_SM_DAEMON_MISMATCH,
};
void zebra_error_init(void);
diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c
index bb872ef91c..0ca77a4974 100644
--- a/zebra/zebra_srv6.c
+++ b/zebra/zebra_srv6.c
@@ -33,6 +33,16 @@
DEFINE_MGROUP(SRV6_MGR, "SRv6 Manager");
DEFINE_MTYPE_STATIC(SRV6_MGR, SRV6M_CHUNK, "SRv6 Manager Chunk");
+DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_BLOCK, "SRv6 SID block");
+DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_FUNC, "SRv6 SID function");
+DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_USID_WLIB,
+ "SRv6 uSID Wide LIB information");
+DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID, "SRv6 SID");
+DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_CTX, "SRv6 SID context");
+
+/* Prototypes */
+static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block,
+ uint32_t sid_func);
/* define hooks for the basic API, so that it can be specialized or served
* externally
@@ -55,6 +65,18 @@ DEFINE_HOOK(srv6_manager_release_chunk,
vrf_id_t vrf_id),
(client, locator_name, vrf_id));
+DEFINE_HOOK(srv6_manager_get_sid,
+ (struct zebra_srv6_sid **sid, struct zserv *client,
+ struct srv6_sid_ctx *ctx, struct in6_addr *sid_value,
+ const char *locator_name),
+ (sid, client, ctx, sid_value, locator_name));
+DEFINE_HOOK(srv6_manager_release_sid,
+ (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx));
+DEFINE_HOOK(srv6_manager_get_locator,
+ (struct srv6_locator **locator, struct zserv *client,
+ const char *locator_name),
+ (locator, client, locator_name));
+
/* define wrappers to be called in zapi_msg.c (as hooks must be called in
* source file where they were defined)
*/
@@ -85,11 +107,502 @@ int srv6_manager_client_disconnect_cb(struct zserv *client)
return 0;
}
+
+void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid,
+ struct zserv *client, struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value,
+ const char *locator_name)
+{
+ hook_call(srv6_manager_get_sid, sid, client, ctx, sid_value,
+ locator_name);
+}
+
+void srv6_manager_release_sid_call(struct zserv *client,
+ struct srv6_sid_ctx *ctx)
+{
+ hook_call(srv6_manager_release_sid, client, ctx);
+}
+
+void srv6_manager_get_locator_call(struct srv6_locator **locator,
+ struct zserv *client,
+ const char *locator_name)
+{
+ hook_call(srv6_manager_get_locator, locator, client, locator_name);
+}
+
static int zebra_srv6_cleanup(struct zserv *client)
{
+ /* Client has disconnected, let's release all the SIDs allocated by it. */
+ release_daemon_srv6_sids(client);
return 0;
}
+/* --- Zebra SRv6 SID context management functions -------------------------- */
+
+struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void)
+{
+ struct zebra_srv6_sid_ctx *ctx = NULL;
+
+ ctx = XCALLOC(MTYPE_ZEBRA_SRV6_SID_CTX,
+ sizeof(struct zebra_srv6_sid_ctx));
+
+ return ctx;
+}
+
+void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx)
+{
+ XFREE(MTYPE_ZEBRA_SRV6_SID_CTX, ctx);
+}
+
+/**
+ * Free an SRv6 SID context.
+ *
+ * @param val SRv6 SID context to be freed
+ */
+void delete_zebra_srv6_sid_ctx(void *val)
+{
+ zebra_srv6_sid_ctx_free((struct zebra_srv6_sid_ctx *)val);
+}
+
+/* --- Zebra SRv6 SID format management functions --------------------------- */
+
+void srv6_sid_format_register(struct srv6_sid_format *format)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+
+ /* Ensure that the format is registered only once */
+ assert(!srv6_sid_format_lookup(format->name));
+
+ listnode_add(srv6->sid_formats, format);
+}
+
+void srv6_sid_format_unregister(struct srv6_sid_format *format)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+
+ listnode_delete(srv6->sid_formats, format);
+}
+
+struct srv6_sid_format *srv6_sid_format_lookup(const char *name)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ struct srv6_sid_format *format;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format))
+ if (!strncmp(name, format->name, sizeof(format->name)))
+ return format;
+
+ return NULL;
+}
+
+/*
+ * Called to change the SID format of a locator.
+ *
+ * After switching the locator to a different format, the SIDs allocated
+ * from the locator may no longer be valid; we need to notify the
+ * interested zclient that the locator has changed, so that the
+ * zclients can withdraw/uninstall the old SIDs, allocate/advertise/program
+ * the new SIDs.
+ */
+void zebra_srv6_locator_format_set(struct srv6_locator *locator,
+ struct srv6_sid_format *format)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ struct zebra_srv6_sid_block *block_old, *block_new;
+ struct prefix_ipv6 block_pfx_new;
+ struct listnode *node, *nnode;
+ struct zebra_srv6_sid_ctx *ctx;
+
+ if (!locator)
+ return;
+
+ locator->sid_format = format;
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: Locator %s format has changed, old=%s new=%s",
+ __func__, locator->name,
+ locator->sid_format ? ((struct srv6_sid_format *)
+ locator->sid_format)
+ ->name
+ : NULL,
+ format ? format->name : NULL);
+
+ /* Notify zclients that the locator is no longer valid */
+ zebra_notify_srv6_locator_delete(locator);
+
+ for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) {
+ if (!ctx->sid || ctx->sid->locator != locator)
+ continue;
+
+ if (ctx->sid)
+ zebra_srv6_sid_free(ctx->sid);
+
+ listnode_delete(srv6->sids, ctx);
+ zebra_srv6_sid_ctx_free(ctx);
+ }
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_DEL notification to zclients",
+ __func__, locator->name);
+
+ /* Release the current parent block */
+ block_old = locator->sid_block;
+ if (block_old) {
+ block_old->refcnt--;
+ if (block_old->refcnt == 0) {
+ listnode_delete(srv6->sid_blocks, block_old);
+ zebra_srv6_sid_block_free(block_old);
+ }
+ }
+ locator->sid_block = NULL;
+
+ block_pfx_new = locator->prefix;
+ if (format)
+ block_pfx_new.prefixlen = format->block_len;
+ else
+ block_pfx_new.prefixlen = locator->block_bits_length;
+ apply_mask(&block_pfx_new);
+
+ /* Allocate the new parent block */
+ block_new = zebra_srv6_sid_block_lookup(&block_pfx_new);
+ if (!block_new) {
+ block_new = zebra_srv6_sid_block_alloc(format, &block_pfx_new);
+ listnode_add(srv6->sid_blocks, block_new);
+ }
+
+ block_new->refcnt++;
+ locator->sid_block = block_new;
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_ADD notification to zclients",
+ __func__, locator->name);
+
+ /* Notify zclients about the updated locator */
+ zebra_srv6_locator_add(locator);
+}
+
+/*
+ * Called when a SID format is modified by the user.
+ *
+ * After modifying a SID format, the SIDs that are using that format may no
+ * longer be valid.
+ * This function walks through the list of locators that are using the SID format
+ * and notifies the zclients that the locator has changed, so that the zclients
+ * can withdraw/uninstall the old SIDs, allocate/program/advertise the new SIDs.
+ */
+void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ struct srv6_locator *locator;
+ struct listnode *node, *nnode;
+ struct zebra_srv6_sid_ctx *ctx;
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: SID format %s has changed. Notifying zclients.",
+ __func__, format->name);
+
+ for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
+ if (locator->sid_format == format) {
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: Locator %s has changed because its format (%s) has been modified. Notifying zclients.",
+ __func__, locator->name,
+ format->name);
+
+ /* Notify zclients that the locator is no longer valid */
+ zebra_notify_srv6_locator_delete(locator);
+
+ for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) {
+ if (!ctx->sid || ctx->sid->locator != locator)
+ continue;
+
+ if (ctx->sid)
+ zebra_srv6_sid_free(ctx->sid);
+
+ listnode_delete(srv6->sids, ctx);
+ zebra_srv6_sid_ctx_free(ctx);
+ }
+
+ /* Notify zclients about the updated locator */
+ zebra_notify_srv6_locator_add(locator);
+ }
+ }
+}
+
+/*
+ * Helper function to create the SRv6 compressed format `usid-f3216`.
+ */
+static struct srv6_sid_format *create_srv6_sid_format_usid_f3216(void)
+{
+ struct srv6_sid_format *format = NULL;
+
+ format = srv6_sid_format_alloc(SRV6_SID_FORMAT_USID_F3216_NAME);
+
+ format->type = SRV6_SID_FORMAT_TYPE_USID;
+
+ /* Define block/node/function length */
+ format->block_len = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN;
+ format->node_len = SRV6_SID_FORMAT_USID_F3216_NODE_LEN;
+ format->function_len = SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN;
+ format->argument_len = SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN;
+
+ /* Define the ranges from which the SID function can be allocated */
+ format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START;
+ format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START;
+ format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END;
+ format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START;
+ format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END;
+ format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START;
+
+ return format;
+}
+
+/*
+ * Helper function to create the SRv6 uncompressed format.
+ */
+static struct srv6_sid_format *create_srv6_sid_format_uncompressed(void)
+{
+ struct srv6_sid_format *format = NULL;
+
+ format = srv6_sid_format_alloc(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME);
+
+ format->type = SRV6_SID_FORMAT_TYPE_UNCOMPRESSED;
+
+ /* Define block/node/function length */
+ format->block_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN;
+ format->node_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN;
+ format->function_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN;
+ format->argument_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN;
+
+ /* Define the ranges from which the SID function can be allocated */
+ format->config.uncompressed.explicit_start =
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START;
+
+ return format;
+}
+
+/* --- Zebra SRv6 SID function management functions ---------------------------- */
+
+uint32_t *zebra_srv6_sid_func_alloc(uint32_t func)
+{
+ uint32_t *sid_func_ptr;
+
+ sid_func_ptr = XCALLOC(MTYPE_ZEBRA_SRV6_SID_FUNC, sizeof(uint32_t));
+ *sid_func_ptr = func;
+
+ return sid_func_ptr;
+}
+
+void zebra_srv6_sid_func_free(uint32_t *func)
+{
+ XFREE(MTYPE_ZEBRA_SRV6_SID_FUNC, func);
+}
+
+/**
+ * Free an SRv6 SID function.
+ *
+ * @param val SRv6 SID function to be freed
+ */
+void delete_zebra_srv6_sid_func(void *val)
+{
+ zebra_srv6_sid_func_free((uint32_t *)val);
+}
+
+/* --- Zebra SRv6 SID block management functions ---------------------------- */
+
+static struct zebra_srv6_sid_block *zebra_srv6_sid_block_alloc_internal(void)
+{
+ struct zebra_srv6_sid_block *block = NULL;
+
+ block = XCALLOC(MTYPE_ZEBRA_SRV6_SID_BLOCK,
+ sizeof(struct zebra_srv6_sid_block));
+
+ return block;
+}
+
+struct zebra_srv6_sid_block *
+zebra_srv6_sid_block_alloc(struct srv6_sid_format *format,
+ struct prefix_ipv6 *prefix)
+{
+ struct zebra_srv6_sid_block *block;
+
+ block = zebra_srv6_sid_block_alloc_internal();
+ block->sid_format = format;
+ block->prefix = *prefix;
+
+ if (format) {
+ if (format->type == SRV6_SID_FORMAT_TYPE_USID) {
+ uint32_t wlib_start, wlib_end, func;
+
+ /* Init uSID LIB */
+ block->u.usid.lib.func_allocated = list_new();
+ block->u.usid.lib.func_allocated->del =
+ delete_zebra_srv6_sid_func;
+ block->u.usid.lib.func_released = list_new();
+ block->u.usid.lib.func_released->del =
+ delete_zebra_srv6_sid_func;
+ block->u.usid.lib.first_available_func =
+ format->config.usid.lib_start;
+
+ /* Init uSID Wide LIB */
+ wlib_start = block->sid_format->config.usid.wlib_start;
+ wlib_end = block->sid_format->config.usid.wlib_end;
+ block->u.usid.wide_lib =
+ XCALLOC(MTYPE_ZEBRA_SRV6_USID_WLIB,
+ (wlib_end - wlib_start + 1) *
+ sizeof(struct wide_lib));
+ for (func = 0; func < wlib_end - wlib_start + 1;
+ func++) {
+ block->u.usid.wide_lib[func].func_allocated =
+ list_new();
+ block->u.usid.wide_lib[func].func_allocated->del =
+ delete_zebra_srv6_sid_func;
+ block->u.usid.wide_lib[func].func_released =
+ list_new();
+ block->u.usid.wide_lib[func].func_released->del =
+ delete_zebra_srv6_sid_func;
+ block->u.usid.wide_lib[func].func = func;
+ }
+ } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) {
+ block->u.uncompressed.func_allocated = list_new();
+ block->u.uncompressed.func_allocated->del =
+ delete_zebra_srv6_sid_func;
+ block->u.uncompressed.func_released = list_new();
+ block->u.uncompressed.func_released->del =
+ delete_zebra_srv6_sid_func;
+ block->u.uncompressed.first_available_func =
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN;
+ } else {
+ /* We should never arrive here */
+ assert(0);
+ }
+ } else {
+ block->u.uncompressed.func_allocated = list_new();
+ block->u.uncompressed.func_allocated->del =
+ delete_zebra_srv6_sid_func;
+ block->u.uncompressed.func_released = list_new();
+ block->u.uncompressed.func_released->del =
+ delete_zebra_srv6_sid_func;
+ block->u.uncompressed.first_available_func = 1;
+ }
+
+ return block;
+}
+
+void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block)
+{
+ if (block->sid_format) {
+ if (block->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) {
+ uint32_t wlib_start, wlib_end, func;
+
+ /* Free uSID LIB */
+ list_delete(&block->u.usid.lib.func_allocated);
+ list_delete(&block->u.usid.lib.func_released);
+
+ /* Free uSID Wide LIB */
+ wlib_start = block->sid_format->config.usid.wlib_start;
+ wlib_end = block->sid_format->config.usid.wlib_end;
+ for (func = 0; func < wlib_end - wlib_start + 1;
+ func++) {
+ list_delete(&block->u.usid.wide_lib[func]
+ .func_allocated);
+ list_delete(&block->u.usid.wide_lib[func]
+ .func_released);
+ }
+ XFREE(MTYPE_ZEBRA_SRV6_USID_WLIB,
+ block->u.usid.wide_lib);
+ } else if (block->sid_format->type ==
+ SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) {
+ list_delete(&block->u.uncompressed.func_allocated);
+ list_delete(&block->u.uncompressed.func_released);
+ } else {
+ /* We should never arrive here */
+ assert(0);
+ }
+ } else {
+ list_delete(&block->u.uncompressed.func_allocated);
+ list_delete(&block->u.uncompressed.func_released);
+ }
+
+ XFREE(MTYPE_ZEBRA_SRV6_SID_BLOCK, block);
+}
+
+/**
+ * Free an SRv6 SID block.
+ *
+ * @param val SRv6 SID block to be freed
+ */
+void delete_zebra_srv6_sid_block(void *val)
+{
+ zebra_srv6_sid_block_free((struct zebra_srv6_sid_block *)val);
+}
+
+struct zebra_srv6_sid_block *
+zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ struct zebra_srv6_sid_block *block;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, block))
+ if (prefix_match(prefix, &block->prefix))
+ return block;
+
+ return NULL;
+}
+
+/* --- Zebra SRv6 SID management functions ---------------------------------- */
+
+/**
+ * Alloc and fill an SRv6 SID.
+ *
+ * @param ctx Context associated with the SID to be created
+ * @param sid_value IPv6 address associated with the SID to be created
+ * @param locator Parent locator of the SID to be created
+ * @param sid_block Block from which the SID value has been allocated
+ * @param sid_func Function part of the SID to be created
+ * @param alloc_mode Allocation mode of the Function (dynamic vs explicit)
+ * @return The requested SID
+ */
+struct zebra_srv6_sid *
+zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value,
+ struct srv6_locator *locator,
+ struct zebra_srv6_sid_block *sid_block, uint32_t sid_func,
+ enum srv6_sid_alloc_mode alloc_mode)
+{
+ struct zebra_srv6_sid *sid;
+
+ if (!ctx || !sid_value)
+ return NULL;
+
+ sid = XCALLOC(MTYPE_ZEBRA_SRV6_SID, sizeof(struct zebra_srv6_sid));
+ sid->ctx = ctx;
+ sid->value = *sid_value;
+ sid->locator = locator;
+ sid->block = sid_block;
+ sid->func = sid_func;
+ sid->alloc_mode = alloc_mode;
+ sid->client_list = list_new();
+
+ return sid;
+}
+
+void zebra_srv6_sid_free(struct zebra_srv6_sid *sid)
+{
+ list_delete(&sid->client_list);
+ XFREE(MTYPE_ZEBRA_SRV6_SID, sid);
+}
+
+/**
+ * Free an SRv6 SID.
+ *
+ * @param val SRv6 SID to be freed
+ */
+void delete_zebra_srv6_sid(void *val)
+{
+ zebra_srv6_sid_free((struct zebra_srv6_sid *)val);
+}
+
void zebra_srv6_locator_add(struct srv6_locator *locator)
{
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
@@ -121,7 +634,6 @@ void zebra_srv6_locator_add(struct srv6_locator *locator)
void zebra_srv6_locator_delete(struct srv6_locator *locator)
{
struct listnode *n;
- struct srv6_locator_chunk *c;
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
struct zserv *client;
@@ -136,18 +648,8 @@ void zebra_srv6_locator_delete(struct srv6_locator *locator)
* by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
* owner of each chunk.
*/
- for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) {
- if (c->proto == ZEBRA_ROUTE_SYSTEM)
- continue;
- client = zserv_find_client(c->proto, c->instance);
- if (!client) {
- zlog_warn(
- "%s: Not found zclient(proto=%u, instance=%u).",
- __func__, c->proto, c->instance);
- continue;
- }
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client))
zsend_zebra_srv6_locator_delete(client, locator);
- }
listnode_delete(srv6->locators, locator);
srv6_locator_free(locator);
@@ -190,7 +692,6 @@ void zebra_notify_srv6_locator_add(struct srv6_locator *locator)
void zebra_notify_srv6_locator_delete(struct srv6_locator *locator)
{
struct listnode *n;
- struct srv6_locator_chunk *c;
struct zserv *client;
/*
@@ -204,17 +705,8 @@ void zebra_notify_srv6_locator_delete(struct srv6_locator *locator)
* by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
* owner of each chunk.
*/
- for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) {
- if (c->proto == ZEBRA_ROUTE_SYSTEM)
- continue;
- client = zserv_find_client(c->proto, c->instance);
- if (!client) {
- zlog_warn("Not found zclient(proto=%u, instance=%u).",
- c->proto, c->instance);
- continue;
- }
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client))
zsend_zebra_srv6_locator_delete(client, locator);
- }
}
struct zebra_srv6 srv6;
@@ -222,10 +714,32 @@ struct zebra_srv6 srv6;
struct zebra_srv6 *zebra_srv6_get_default(void)
{
static bool first_execution = true;
+ struct srv6_sid_format *format_usidf3216;
+ struct srv6_sid_format *format_uncompressed;
if (first_execution) {
first_execution = false;
srv6.locators = list_new();
+
+ /* Initialize list of SID formats */
+ srv6.sid_formats = list_new();
+ srv6.sid_formats->del = delete_srv6_sid_format;
+
+ /* Create SID format `usid-f3216` */
+ format_usidf3216 = create_srv6_sid_format_usid_f3216();
+ srv6_sid_format_register(format_usidf3216);
+
+ /* Create SID format `uncompressed` */
+ format_uncompressed = create_srv6_sid_format_uncompressed();
+ srv6_sid_format_register(format_uncompressed);
+
+ /* Init list to store SRv6 SIDs */
+ srv6.sids = list_new();
+ srv6.sids->del = delete_zebra_srv6_sid_ctx;
+
+ /* Init list to store SRv6 SID blocks */
+ srv6.sid_blocks = list_new();
+ srv6.sid_blocks->del = delete_zebra_srv6_sid_block;
}
return &srv6;
}
@@ -427,21 +941,1519 @@ void zebra_srv6_encap_src_addr_unset(void)
memset(&srv6->encap_src_addr, 0, sizeof(struct in6_addr));
}
+/* --- SRv6 SID Allocation/Release functions -------------------------------- */
+
+/**
+ * Return the SRv6 SID obtained composing the locator and function.
+ *
+ * @param sid_value SRv6 SID address returned
+ * @param locator Parent locator of the SRv6 SID
+ * @param sid_func Function part of the SID
+ * @return True if success, False otherwise
+ */
+static bool zebra_srv6_sid_compose(struct in6_addr *sid_value,
+ struct srv6_locator *locator,
+ uint32_t sid_func)
+{
+ uint8_t offset, func_len;
+ struct srv6_sid_format *format = locator->sid_format;
+
+ if (!sid_value || !locator)
+ return false;
+
+ if (format) {
+ offset = format->block_len + format->node_len;
+ func_len = format->function_len;
+ } else {
+ offset = locator->block_bits_length + locator->node_bits_length;
+ func_len = locator->function_bits_length;
+ }
+
+ *sid_value = locator->prefix.prefix;
+ for (uint8_t idx = 0; idx < func_len; idx++) {
+ uint8_t tidx = offset + idx;
+
+ sid_value->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8));
+ if (sid_func >> (func_len - 1 - idx) & 0x1)
+ sid_value->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8);
+ }
+
+ return true;
+}
+
+/**
+ * Return the parent locator and function of an SRv6 SID.
+ *
+ * @param sid_value SRv6 SID address to be decomposed
+ * @param sid_block Parent block of the SRv6 SID
+ * @param locator Parent locator of the SRv6 SID
+ * @param sid_func Function part of the SID
+ * @param sid_wide_func Wide function of the SID
+ * @return True if success, False otherwise
+ */
+static bool zebra_srv6_sid_decompose(struct in6_addr *sid_value,
+ struct zebra_srv6_sid_block **sid_block,
+ struct srv6_locator **locator,
+ uint32_t *sid_func, uint32_t *sid_wide_func)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ struct srv6_locator *l;
+ struct zebra_srv6_sid_block *b;
+ struct srv6_sid_format *format;
+ struct listnode *node;
+ struct prefix_ipv6 tmp_prefix;
+ uint8_t offset, func_len;
+
+ if (!sid_value || !sid_func)
+ return false;
+
+ *sid_func = 0;
+ *sid_wide_func = 0;
+
+ /*
+ * Build a temporary prefix_ipv6 object representing the SRv6 SID.
+ * This temporary prefix object is used below by the prefix_match
+ * function to check if the SID belongs to a specific locator.
+ */
+ tmp_prefix.family = AF_INET6;
+ tmp_prefix.prefixlen = IPV6_MAX_BITLEN;
+ tmp_prefix.prefix = *sid_value;
+
+ /*
+ * Lookup the parent locator of the SID and return the locator and
+ * the function of the SID.
+ */
+ for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, l)) {
+ /*
+ * Check if the locator prefix includes the temporary prefix
+ * representing the SID.
+ */
+ if (prefix_match((struct prefix *)&l->prefix,
+ (struct prefix *)&tmp_prefix)) {
+ format = l->sid_format;
+
+ if (format) {
+ offset = format->block_len + format->node_len;
+ func_len = format->function_len;
+ } else {
+ offset = l->block_bits_length +
+ l->node_bits_length;
+ func_len = l->function_bits_length;
+ }
+
+ for (uint8_t idx = 0; idx < func_len; idx++) {
+ uint8_t tidx = offset + idx;
+ *sid_func |= (sid_value->s6_addr[tidx / 8] &
+ (0x1 << (7 - tidx % 8)))
+ << (((func_len - 1 - idx) / 8) * 8);
+ }
+
+ /*
+ * If function comes from the Wide LIB range, we also
+ * need to get the Wide function.
+ */
+ if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) {
+ if (*sid_func >= format->config.usid.wlib_start &&
+ *sid_func <= format->config.usid.wlib_end) {
+ format = l->sid_format;
+
+ offset = format->block_len +
+ format->node_len +
+ format->function_len;
+
+ for (uint8_t idx = 0; idx < 16; idx++) {
+ uint8_t tidx = offset + idx;
+ *sid_wide_func |=
+ (sid_value->s6_addr[tidx /
+ 8] &
+ (0x1 << (7 - tidx % 8)))
+ << (((16 - 1 - idx) / 8) *
+ 8);
+ }
+ }
+ }
+
+ *locator = l;
+ *sid_block = l->sid_block;
+
+ return true;
+ }
+ }
+
+ /*
+ * If we arrive here, the SID does not belong to any locator.
+ * Then, let's try to find the parent block from which the SID
+ * has been allocated.
+ */
+
+ /*
+ * Lookup the parent block of the SID and return the block and
+ * the function of the SID.
+ */
+ for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, b)) {
+ /*
+ * Check if the block prefix includes the temporary prefix
+ * representing the SID
+ */
+ if (prefix_match((struct prefix *)&b->prefix,
+ (struct prefix *)&tmp_prefix)) {
+ format = b->sid_format;
+
+ if (!format)
+ continue;
+
+ offset = format->block_len + format->node_len;
+ func_len = format->function_len;
+
+ for (uint8_t idx = 0; idx < func_len; idx++) {
+ uint8_t tidx = offset + idx;
+ *sid_func |= (sid_value->s6_addr[tidx / 8] &
+ (0x1 << (7 - tidx % 8)))
+ << ((func_len - 1 - idx) / 8);
+ }
+
+ /*
+ * If function comes from the Wide LIB range, we also
+ * need to get the Wide function.
+ */
+ if (*sid_func >= format->config.usid.wlib_start &&
+ *sid_func <= format->config.usid.wlib_end) {
+ format = b->sid_format;
+
+ offset = format->block_len + format->node_len +
+ format->function_len;
+
+ for (uint8_t idx = 0; idx < 16; idx++) {
+ uint8_t tidx = offset + idx;
+ *sid_wide_func |=
+ (sid_value->s6_addr[tidx / 8] &
+ (0x1 << (7 - tidx % 8)))
+ << (((16 - 1 - idx) / 8) * 8);
+ }
+ }
+
+ *sid_block = b;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Allocate an explicit SID function (i.e. specific SID function value) from a given SID block.
+ *
+ * @param block SRv6 SID block from which the SID function has to be allocated
+ * @param sid_func SID function to be allocated
+ * @param sid_wide_func SID wide function to be allocated
+ *
+ * @return true on success, false otherwise
+ */
+static bool alloc_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block,
+ uint32_t sid_func,
+ uint32_t sid_wide_func)
+{
+ struct srv6_sid_format *format;
+ struct listnode *node;
+ uint32_t *sid_func_ptr = NULL;
+
+ if (!block)
+ return false;
+
+ format = block->sid_format;
+
+ if (ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: trying to allocate explicit SID function %u from block %pFX",
+ __func__, sid_func, &block->prefix);
+
+ /*
+ * Allocate SID function from the corresponding range depending on the SID format type
+ */
+ if (format) {
+ if (format->type == SRV6_SID_FORMAT_TYPE_USID) {
+ uint32_t elib_start = format->config.usid.elib_start;
+ uint32_t elib_end = format->config.usid.elib_end;
+ uint32_t wlib_end = format->config.usid.wlib_end;
+ uint32_t ewlib_start = format->config.usid.ewlib_start;
+ uint32_t ewlib_end = wlib_end;
+ uint32_t *sid_wide_func_ptr = NULL;
+
+ /* Figure out the range from which the SID function has been allocated and release it */
+ if ((sid_func >= elib_start) && (sid_func <= elib_end)) {
+ /* The SID function has to be allocated from the ELIB range */
+
+ /* Ensure that the requested SID function has not already been taken */
+ for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib
+ .func_allocated,
+ node, sid_func_ptr))
+ if (*sid_func_ptr == sid_func)
+ break;
+
+ if (sid_func_ptr) {
+ zlog_err("%s: invalid SM request arguments: SID function %u already taken",
+ __func__, sid_func);
+ return false;
+ }
+
+ /*
+ * Mark the SID function as "taken" by adding it to the "func_allocated" list and
+ * increase the counter of function allocated
+ */
+ sid_func_ptr =
+ zebra_srv6_sid_func_alloc(sid_func);
+ listnode_add(block->u.usid.lib.func_allocated,
+ sid_func_ptr);
+ block->u.usid.lib.num_func_allocated++;
+ } else if ((sid_func >= ewlib_start) &&
+ (sid_func <= ewlib_end)) {
+ /* The SID function has to be allocated from the EWLIB range */
+
+ /* Ensure that the requested SID function has not already been taken */
+ for (ALL_LIST_ELEMENTS_RO(block->u.usid
+ .wide_lib[sid_func]
+ .func_allocated,
+ node,
+ sid_wide_func_ptr))
+ if (*sid_wide_func_ptr == sid_wide_func)
+ break;
+
+ if (sid_wide_func_ptr) {
+ zlog_err("%s: invalid SM request arguments: SID function %u already taken",
+ __func__, sid_func);
+ return false;
+ }
+
+ /*
+ * Mark the SID function as "taken" by adding it to the "func_allocated" list and
+ * increase the counter of function allocated
+ */
+ sid_wide_func_ptr = zebra_srv6_sid_func_alloc(
+ sid_wide_func);
+ listnode_add(block->u.usid.wide_lib[sid_func]
+ .func_allocated,
+ sid_wide_func_ptr);
+ block->u.usid.wide_lib[sid_func]
+ .num_func_allocated++;
+ } else {
+ zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]",
+ __func__, sid_func, elib_start,
+ elib_end, ewlib_start, ewlib_end);
+ return -1;
+ }
+ } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) {
+ uint32_t explicit_start =
+ format->config.uncompressed.explicit_start;
+ uint32_t explicit_end =
+ (uint32_t)((1 << format->function_len) - 1);
+
+ /* Ensure that the SID function comes from the Explicit range */
+ if (!(sid_func >= explicit_start &&
+ sid_func <= explicit_end)) {
+ zlog_err("%s: invalid SM request arguments: SID function %u out of explicit range (%u - %u)",
+ __func__, sid_func, explicit_start,
+ explicit_end);
+ return false;
+ }
+
+ /* Ensure that the SID function has not already been taken */
+
+ for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed
+ .func_allocated,
+ node, sid_func_ptr))
+ if (*sid_func_ptr == sid_func)
+ break;
+
+ /* SID function already taken */
+ if (sid_func_ptr) {
+ zlog_err("%s: invalid SM request arguments: SID function %u already taken",
+ __func__, sid_func);
+ return false;
+ }
+
+ /*
+ * Mark the SID function as "taken" by adding it to the "func_allocated" list and
+ * increase the counter of function allocated
+ */
+ sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func);
+ listnode_add(block->u.uncompressed.func_allocated,
+ sid_func_ptr);
+ block->u.uncompressed.num_func_allocated++;
+ } else {
+ /* We should never arrive here */
+ zlog_err("%s: unknown SID format type: %u", __func__,
+ format->type);
+ assert(0);
+ }
+ } else {
+ /* Ensure that the SID function has not already been taken */
+
+ for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated,
+ node, sid_func_ptr))
+ if (*sid_func_ptr == sid_func)
+ break;
+
+ /* SID function already taken */
+ if (sid_func_ptr) {
+ zlog_err("%s: invalid SM request arguments: SID function %u already taken",
+ __func__, sid_func);
+ return false;
+ }
+
+ /*
+ * Mark the SID function as "taken" by adding it to the "func_allocated" list and
+ * increase the counter of function allocated
+ */
+ sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func);
+ listnode_add(block->u.uncompressed.func_allocated, sid_func_ptr);
+ block->u.uncompressed.num_func_allocated++;
+ }
+
+ if (ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: allocated explicit SID function %u from block %pFX",
+ __func__, sid_func, &block->prefix);
+
+ return true;
+}
+
+/**
+ * Allocate a dynamic SID function (i.e. any available SID function value) from a given SID block.
+ *
+ * @param block SRv6 SID block from which the SID function has to be allocated
+ * @param sid_func SID function allocated
+ *
+ * @return true on success, false otherwise
+ */
+static bool alloc_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block,
+ uint32_t *sid_func)
+{
+ struct srv6_sid_format *format;
+ uint32_t *sid_func_ptr = NULL;
+
+ if (!block || !sid_func)
+ return false;
+
+ format = block->sid_format;
+
+ if (ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: trying to allocate dynamic SID function from block %pFX",
+ __func__, &block->prefix);
+
+ /*
+ * Allocate SID function from the corresponding range depending on the SID format type
+ */
+ if (format) {
+ if (format->type == SRV6_SID_FORMAT_TYPE_USID) {
+ /* Format is uSID and behavior => allocate SID function from LIB range */
+
+ /* The Dynamic LIB range ends where the Explicit LIB range begins */
+ uint32_t dlib_end = format->config.usid.elib_start - 1;
+
+ /* Check if we ran out of available SID functions */
+ if (block->u.usid.lib.first_available_func > dlib_end) {
+ zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted",
+ __func__);
+ return false;
+ }
+
+ /*
+ * First, let's check if there are any SID functions that were previously
+ * allocated and then released.
+ */
+ if (listcount(block->u.usid.lib.func_released) != 0) {
+ /*
+ * There are SID functions previously allocated and then released,
+ * let's pick the first one and reuse it now.
+ */
+ sid_func_ptr = listnode_head(
+ block->u.usid.lib.func_released);
+ *sid_func = *sid_func_ptr;
+ listnode_delete(block->u.usid.lib.func_released,
+ sid_func_ptr);
+ zebra_srv6_sid_func_free(sid_func_ptr);
+ } else {
+ /*
+ * There are no SID functions previously allocated and then released,
+ * let's allocate a new function from the pool of available functions.
+ */
+ *sid_func =
+ block->u.usid.lib.first_available_func;
+ block->u.usid.lib.first_available_func++;
+ }
+
+ /* Increase the counter of SID functions allocated */
+ block->u.usid.lib.num_func_allocated++;
+
+ if (block->u.usid.lib.first_available_func > dlib_end)
+ zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted and next SID request will fail",
+ __func__);
+ } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) {
+ /* Format is uncompressed => allocate SID function from Dynamic range */
+
+ uint32_t dynamic_end =
+ format->config.uncompressed.explicit_start - 1;
+
+ /* Check if we ran out of available SID functions */
+ if (block->u.uncompressed.first_available_func >
+ dynamic_end) {
+ zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted",
+ __func__);
+ return NULL;
+ }
+
+ /*
+ * First, let's check if there are any SID functions that were previously
+ * allocated and then released.
+ */
+ if (listcount(block->u.uncompressed.func_released) != 0) {
+ /*
+ * There are SID functions previously allocated and then released,
+ * let's pick the first one and reuse it now.
+ */
+ sid_func_ptr = listnode_head(
+ block->u.uncompressed.func_released);
+ *sid_func = *sid_func_ptr;
+ listnode_delete(block->u.uncompressed
+ .func_released,
+ sid_func_ptr);
+ zebra_srv6_sid_func_free(sid_func_ptr);
+ } else {
+ /*
+ * There are no SID functions previously allocated and then released,
+ * let's allocate a new function from the pool of available functions.
+ */
+ *sid_func = block->u.uncompressed
+ .first_available_func;
+ block->u.uncompressed.first_available_func++;
+ }
+
+ /* Increase the counter of SID functions allocated */
+ block->u.uncompressed.num_func_allocated++;
+
+ if (block->u.uncompressed.first_available_func >
+ dynamic_end)
+ zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted and next SID request will fail",
+ __func__);
+ } else {
+ /* We should never arrive here */
+ zlog_err("%s: unknown SID format type: %u", __func__,
+ format->type);
+ assert(0);
+ }
+ } else {
+ /*
+ * First, let's check if there are any SID functions that were previously
+ * allocated and then released.
+ */
+ if (listcount(block->u.uncompressed.func_released) != 0) {
+ /*
+ * There are SID functions previously allocated and then released,
+ * let's pick the first one and reuse it now.
+ */
+ sid_func_ptr = listnode_head(
+ block->u.uncompressed.func_released);
+ *sid_func = *sid_func_ptr;
+ listnode_delete(block->u.uncompressed.func_released,
+ sid_func_ptr);
+ zebra_srv6_sid_func_free(sid_func_ptr);
+ } else {
+ /*
+ * There are no SID functions previously allocated and then released,
+ * let's allocate a new function from the pool of available functions.
+ */
+ *sid_func = block->u.uncompressed.first_available_func;
+ block->u.uncompressed.first_available_func++;
+ }
+
+ /* Increase the counter of SID functions allocated */
+ block->u.uncompressed.num_func_allocated++;
+ }
+
+ if (ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: allocated dynamic SID function %u from block %pFX",
+ __func__, *sid_func, &block->prefix);
+
+ return true;
+}
+
+/**
+ * Get an explicit SID (i.e., a specific SID value) for a given context.
+ *
+ * If a SID already exists associated with the context, it returns the existing SID.
+ * Otherwise, it allocates a new SID.
+ *
+ * @param sid SID returned
+ * @param ctx Context for which the SID has been requested
+ * @param sid_value specific SRv6 SID value (i.e. IPv6 address) to be
+ * allocated explicitly
+ *
+ * @return 0 if the function returned an existing SID and SID value has not changed,
+ * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred
+ */
+static int get_srv6_sid_explicit(struct zebra_srv6_sid **sid,
+ struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ struct zebra_srv6_sid_ctx *s = NULL;
+ struct zebra_srv6_sid_ctx *zctx = NULL;
+ struct listnode *node;
+ uint32_t sid_func = 0, sid_func_wide = 0;
+ struct srv6_locator *locator = NULL;
+ struct zebra_srv6_sid_block *block = NULL;
+ char buf[256];
+
+ if (!ctx || !sid_value)
+ return -1;
+
+ /* Check if we already have a SID associated with the provided context */
+ for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) {
+ if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) {
+ /*
+ * If the context is already associated with a SID that has the same SID value, then
+ * return the existing SID
+ */
+ if (sid_same(&s->sid->value, sid_value)) {
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: returning existing SRv6 SID %pI6 ctx %s",
+ __func__, &s->sid->value,
+ srv6_sid_ctx2str(buf,
+ sizeof(buf),
+ ctx));
+ *sid = s->sid;
+ return 0;
+ }
+
+ /*
+ * It is not allowed to allocate an explicit SID for a given context if the context
+ * is already associated with an explicit SID
+ */
+ if (s->sid->alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) {
+ zlog_err("%s: cannot alloc SID %pI6 for ctx %s: ctx already associated with SID %pI6",
+ __func__, sid_value,
+ srv6_sid_ctx2str(buf, sizeof(buf),
+ &s->ctx),
+ &s->sid->value);
+ return -1;
+ }
+
+ zctx = s;
+ break;
+ }
+ }
+
+ /* Get parent locator and function of the provided SID */
+ if (!zebra_srv6_sid_decompose(sid_value, &block, &locator, &sid_func,
+ &sid_func_wide)) {
+ zlog_err("%s: invalid SM request arguments: parent block/locator not found for SID %pI6",
+ __func__, sid_value);
+ return -1;
+ }
+
+ if (ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) {
+ zlog_err("%s: invalid SM request arguments: explicit SID allocation not allowed for End/uN behavior",
+ __func__);
+ return -1;
+ }
+
+ /* Allocate an explicit SID function for the SID */
+ if (!alloc_srv6_sid_func_explicit(block, sid_func, sid_func_wide)) {
+ zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX",
+ __func__, sid_func, &block->prefix);
+ return -1;
+ }
+
+ if (!zctx) {
+ /* If we don't have a zebra SID context for this context, allocate a new one */
+ zctx = zebra_srv6_sid_ctx_alloc();
+ zctx->ctx = *ctx;
+ } else {
+ /*
+ * If we already have a SID associated with this context, we need to
+ * deallocate the current SID function before allocating the new one
+ */
+ if (zctx->sid) {
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: ctx %s already associated with a dynamic SID %pI6, releasing dynamic SID",
+ __func__,
+ srv6_sid_ctx2str(buf, sizeof(buf),
+ ctx),
+ &zctx->sid->value);
+
+ release_srv6_sid_func_dynamic(block, zctx->sid->func);
+ zebra_srv6_sid_free(zctx->sid);
+ zctx->sid = NULL;
+ }
+ }
+
+ /* Allocate the SID to store SID information */
+ *sid = zebra_srv6_sid_alloc(zctx, sid_value, locator, block, sid_func,
+ SRV6_SID_ALLOC_MODE_EXPLICIT);
+ if (!(*sid)) {
+ flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID,
+ "%s: failed to create SRv6 SID %s (%pI6)", __func__,
+ srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value);
+ return -1;
+ }
+ (*sid)->ctx = zctx;
+ zctx->sid = *sid;
+ listnode_add(srv6->sids, zctx);
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: allocated explicit SRv6 SID %pI6 for context %s",
+ __func__, &(*sid)->value,
+ srv6_sid_ctx2str(buf, sizeof(buf), ctx));
+
+ return 1;
+}
+
+/**
+ * Get a dynamic SID (i.e., any available SID value) for a given context.
+ *
+ * If a SID already exists associated with the context, it returns the existing SID.
+ * Otherwise, it allocates a new SID.
+ *
+ * @param sid SID returned
+ * @param ctx Context for which the SID has been requested
+ * @param locator SRv6 locator from which the SID has to be allocated
+ *
+ * @return 0 if the function returned an existing SID and SID value has not changed,
+ * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred
+ */
+static int get_srv6_sid_dynamic(struct zebra_srv6_sid **sid,
+ struct srv6_sid_ctx *ctx,
+ struct srv6_locator *locator)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ struct zebra_srv6_sid_block *block;
+ struct srv6_sid_format *format;
+ struct zebra_srv6_sid_ctx *s = NULL;
+ struct zebra_srv6_sid_ctx *zctx;
+ struct listnode *node;
+ struct in6_addr sid_value;
+ uint32_t sid_func = 0;
+ char buf[256];
+
+ if (!ctx || !locator)
+ return -1;
+
+ block = locator->sid_block;
+ format = locator->sid_format;
+
+ /*
+ * If we already have a SID for the provided context, we return the existing
+ * SID instead of allocating a new one.
+ */
+ for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) {
+ if (locator && s->sid && s->sid->locator) {
+ if (strncmp(s->sid->locator->name, locator->name,
+ SRV6_LOCNAME_SIZE)) {
+ continue;
+ }
+ }
+ if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) {
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: returning existing SID %s %pI6",
+ __func__,
+ srv6_sid_ctx2str(buf, sizeof(buf),
+ ctx),
+ &s->sid->value);
+ *sid = s->sid;
+ return 0;
+ }
+ }
+
+ if (format && format->type == SRV6_SID_FORMAT_TYPE_USID &&
+ ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) {
+ /* uN SID is allocated from the GIB range */
+ sid_value = locator->prefix.prefix;
+ } else if (!format && ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) {
+ /* uN SID is allocated from the GIB range */
+ sid_value = locator->prefix.prefix;
+ } else {
+ /* Allocate a dynamic SID function for the SID */
+ if (!alloc_srv6_sid_func_dynamic(block, &sid_func)) {
+ zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX",
+ __func__, sid_func, &block->prefix);
+ return -1;
+ }
+
+ /* Compose the SID as the locator followed by the SID function */
+ zebra_srv6_sid_compose(&sid_value, locator, sid_func);
+ }
+
+ /* Allocate a zebra SID context to store SID context information */
+ zctx = zebra_srv6_sid_ctx_alloc();
+ zctx->ctx = *ctx;
+
+ /* Allocate the SID to store SID information */
+ *sid = zebra_srv6_sid_alloc(zctx, &sid_value, locator, block, sid_func,
+ SRV6_SID_ALLOC_MODE_DYNAMIC);
+ if (!(*sid)) {
+ flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID,
+ "%s: failed to create SRv6 SID ctx %s (%pI6)", __func__,
+ srv6_sid_ctx2str(buf, sizeof(buf), ctx), &sid_value);
+ return -1;
+ }
+ (*sid)->ctx = zctx;
+ zctx->sid = *sid;
+ listnode_add(srv6->sids, zctx);
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: allocated new dynamic SRv6 SID %pI6 for context %s",
+ __func__, &(*sid)->value,
+ srv6_sid_ctx2str(buf, sizeof(buf), ctx));
+
+ return 1;
+}
+
+/**
+ * Get an SRv6 SID for a given context.
+ *
+ * If a SID already exists associated with the context, it returns the existing SID.
+ * Otherwise, it allocates a new SID.
+ *
+ * If the sid_value parameter is non-NULL, it allocates the requested SID value
+ * if it is available (explicit SID allocation).
+ * If the sid_value parameter is NULL, it allocates any available SID value
+ * (dynamic SID allocation).
+ *
+ * @param sid SID returned
+ * @param ctx Context for which the SID has been requested
+ * @param sid_value SRv6 SID value to be allocated (for explicit SID allocation)
+ * @param locator_name Parent SRv6 locator from which the SID has to be allocated (for dynamic SID allocation)
+ *
+ * @return 0 if the function returned an existing SID and SID value has not changed,
+ * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred
+ */
+int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value, const char *locator_name)
+{
+ int ret = -1;
+ struct srv6_locator *locator;
+ char buf[256];
+
+ enum srv6_sid_alloc_mode alloc_mode =
+ (sid_value) ? SRV6_SID_ALLOC_MODE_EXPLICIT
+ : SRV6_SID_ALLOC_MODE_DYNAMIC;
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: received SRv6 SID alloc request: SID ctx %s (%pI6), mode=%s",
+ __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx),
+ sid_value, srv6_sid_alloc_mode2str(alloc_mode));
+
+ switch (alloc_mode) {
+ case SRV6_SID_ALLOC_MODE_EXPLICIT:
+ /*
+ * Explicit SID allocation: allocate a specific SID value
+ */
+
+ if (!sid_value) {
+ zlog_err("%s: invalid SM request arguments: missing SRv6 SID value, necessary for explicit allocation",
+ __func__);
+ return -1;
+ }
+
+ ret = get_srv6_sid_explicit(sid, ctx, sid_value);
+
+ break;
+ case SRV6_SID_ALLOC_MODE_DYNAMIC:
+ /*
+ * Dynamic SID allocation: allocate any available SID value
+ */
+
+ if (!locator_name) {
+ zlog_err("%s: invalid SM request arguments: missing SRv6 locator, necessary for dynamic allocation",
+ __func__);
+ return -1;
+ }
+
+ locator = zebra_srv6_locator_lookup(locator_name);
+ if (!locator) {
+ zlog_err("%s: invalid SM request arguments: SRv6 locator '%s' does not exist",
+ __func__, locator_name);
+ return -1;
+ }
+
+ ret = get_srv6_sid_dynamic(sid, ctx, locator);
+
+ break;
+ case SRV6_SID_ALLOC_MODE_MAX:
+ case SRV6_SID_ALLOC_MODE_UNSPEC:
+ default:
+ flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID,
+ "%s: SRv6 Manager: Unrecognized alloc mode %u",
+ __func__, alloc_mode);
+ /* We should never arrive here */
+ assert(0);
+ }
+
+ return ret;
+}
+
+/**
+ * Release an explicit SRv6 SID function.
+ *
+ * @param block Parent SRv6 SID block of the SID function that has to be released
+ * @param sid_func SID function to be released
+ * @return 0 on success, -1 otherwise
+ */
+static bool release_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block,
+ uint32_t sid_func,
+ uint32_t sid_wide_func)
+{
+ struct srv6_sid_format *format;
+ struct listnode *node;
+ uint32_t *sid_func_ptr = NULL;
+
+ if (!block)
+ return -1;
+
+ format = block->sid_format;
+
+ if (ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: trying to release explicit SRv6 SID function %u from block %pFX",
+ __func__, sid_func, &block->prefix);
+
+ /*
+ * Release SID function from the corresponding range depending on the SID format type
+ */
+ if (format) {
+ if (format->type == SRV6_SID_FORMAT_TYPE_USID) {
+ uint32_t elib_start = format->config.usid.elib_start;
+ uint32_t elib_end = format->config.usid.elib_end;
+ uint32_t ewlib_start = format->config.usid.ewlib_start;
+ uint32_t ewlib_end = format->config.usid.wlib_end;
+ uint32_t *sid_wide_func_ptr = NULL;
+
+ /* Figure out the range from which the SID function has been allocated and release it */
+ if ((sid_func >= elib_start) && (sid_func <= elib_end)) {
+ /* The SID function comes from the ELIB range */
+
+ /* Lookup SID function in the functions allocated list of ELIB range */
+ for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib
+ .func_allocated,
+ node, sid_func_ptr))
+ if (*sid_func_ptr == sid_func)
+ break;
+
+ /* Ensure that the SID function is allocated */
+ if (!sid_func_ptr) {
+ zlog_warn("%s: failed to release SID function %u, function is not allocated",
+ __func__, sid_func);
+ return -1;
+ }
+
+ /* Release the SID function from the ELIB range */
+ listnode_delete(block->u.usid.lib.func_allocated,
+ sid_func_ptr);
+ zebra_srv6_sid_func_free(sid_func_ptr);
+ } else if ((sid_func >= ewlib_start) &&
+ (sid_func <= ewlib_end)) {
+ /* The SID function comes from the EWLIB range */
+
+ /* Lookup SID function in the functions allocated list of EWLIB range */
+ for (ALL_LIST_ELEMENTS_RO(block->u.usid
+ .wide_lib[sid_func]
+ .func_allocated,
+ node, sid_func_ptr))
+ if (*sid_wide_func_ptr == sid_wide_func)
+ break;
+
+ /* Ensure that the SID function is allocated */
+ if (!sid_wide_func_ptr) {
+ zlog_warn("%s: failed to release wide SID function %u, function is not allocated",
+ __func__, sid_wide_func);
+ return -1;
+ }
+
+ /* Release the SID function from the EWLIB range */
+ listnode_delete(block->u.usid.wide_lib[sid_func]
+ .func_allocated,
+ sid_wide_func_ptr);
+ zebra_srv6_sid_func_free(sid_wide_func_ptr);
+ } else {
+ zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]",
+ __func__, sid_func, elib_start,
+ elib_end, ewlib_start, ewlib_end);
+ return -1;
+ }
+ } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) {
+ uint32_t explicit_start =
+ format->config.uncompressed.explicit_start;
+ uint32_t explicit_end =
+ (uint32_t)((1 << format->function_len) - 1);
+
+ /* Ensure that the SID function comes from the Explicit range */
+ if (!(sid_func >= explicit_start &&
+ sid_func <= explicit_end)) {
+ zlog_warn("%s: function %u is outside explicit alloc range [%u/%u]",
+ __func__, sid_func, explicit_start,
+ explicit_end);
+ return -1;
+ }
+
+ /* Lookup SID function in the functions allocated list of Explicit range */
+ for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed
+ .func_allocated,
+ node, sid_func_ptr))
+ if (*sid_func_ptr == sid_func)
+ break;
+
+ /* Ensure that the SID function is allocated */
+ if (!sid_func_ptr) {
+ zlog_warn("%s: failed to release SID function %u, function is not allocated",
+ __func__, sid_func);
+ return -1;
+ }
+
+ /* Release the SID function from the Explicit range */
+ listnode_delete(block->u.uncompressed.func_allocated,
+ sid_func_ptr);
+ zebra_srv6_sid_func_free(sid_func_ptr);
+ } else {
+ /* We should never arrive here */
+ assert(0);
+ }
+ } else {
+ /* Lookup SID function in the functions allocated list of Explicit range */
+ for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated,
+ node, sid_func_ptr))
+ if (*sid_func_ptr == sid_func)
+ break;
+
+ /* Ensure that the SID function is allocated */
+ if (!sid_func_ptr) {
+ zlog_warn("%s: failed to release SID function %u, function is not allocated",
+ __func__, sid_func);
+ return -1;
+ }
+
+ /* Release the SID function from the Explicit range */
+ listnode_delete(block->u.uncompressed.func_allocated,
+ sid_func_ptr);
+ zebra_srv6_sid_func_free(sid_func_ptr);
+ }
+
+ if (ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: released explicit SRv6 SID function %u from block %pFX",
+ __func__, sid_func, &block->prefix);
+
+ return 0;
+}
+
+/**
+ * Release a dynamic SRv6 SID function.
+ *
+ * @param block Parent SRv6 SID block of the SID function that has to be released
+ * @param sid_func SID function to be released
+ * @return 0 on success, -1 otherwise
+ */
+static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block,
+ uint32_t sid_func)
+{
+ struct srv6_sid_format *format;
+ struct listnode *node, *nnode;
+ uint32_t *sid_func_ptr = NULL;
+
+ if (!block)
+ return -1;
+
+ format = block->sid_format;
+
+ if (ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: trying to release dynamic SRv6 SID function %u from block %pFX",
+ __func__, sid_func, &block->prefix);
+
+ /*
+ * Release SID function from the corresponding range depending on the SID format type
+ */
+ if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) {
+ uint32_t dlib_start = format->config.usid.lib_start;
+ /* The Dynamic LIB range ends where the Explicit LIB range begins */
+ uint32_t dlib_end = format->config.usid.elib_start - 1;
+
+ /* Ensure that the SID function to be released comes from the Dynamic LIB (DLIB) range */
+ if (!(sid_func >= dlib_start && sid_func <= dlib_end)) {
+ zlog_warn("%s: function %u is outside Dynamic LIB range [%u/%u]",
+ __func__, sid_func, dlib_start, dlib_end);
+ return -1;
+ }
+
+ if (sid_func == block->u.usid.lib.first_available_func - 1) {
+ /*
+ * The SID function to be released precedes the `first_available_func`.
+ * Reset first_available_func to the first available position.
+ */
+
+ block->u.usid.lib.first_available_func -= 1;
+
+ bool found;
+
+ do {
+ found = false;
+ for (ALL_LIST_ELEMENTS(block->u.usid.lib
+ .func_released,
+ node, nnode,
+ sid_func_ptr))
+ if (*sid_func_ptr ==
+ block->u.usid.lib.first_available_func -
+ 1) {
+ listnode_delete(block->u.usid
+ .lib
+ .func_released,
+ sid_func_ptr);
+ zebra_srv6_sid_func_free(
+ sid_func_ptr);
+ block->u.usid.lib
+ .first_available_func -=
+ 1;
+ found = true;
+ break;
+ }
+ } while (found);
+ } else {
+ /*
+ * The SID function to be released does not precede the `first_available_func`.
+ * Add the released function to the func_released array to indicate
+ * that it is available again for allocation.
+ */
+ sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func);
+ listnode_add_head(block->u.usid.lib.func_released,
+ sid_func_ptr);
+ }
+ } else if (format && format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) {
+ uint32_t dynamic_start =
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN;
+ /* The Dynamic range ends where the Explicit range begins */
+ uint32_t dynamic_end =
+ format->config.uncompressed.explicit_start - 1;
+
+ /* Ensure that the SID function to be released comes from the Dynamic range */
+ if (!(sid_func >= dynamic_start && sid_func <= dynamic_end)) {
+ zlog_warn("%s: function %u is outside dynamic range [%u/%u]",
+ __func__, sid_func, dynamic_start,
+ dynamic_end);
+ return -1;
+ }
+
+ if (sid_func == block->u.uncompressed.first_available_func - 1) {
+ /*
+ * The released SID function precedes the `first_available_func`.
+ * Reset first_available_func to the first available position.
+ */
+
+ block->u.uncompressed.first_available_func -= 1;
+
+ bool found;
+
+ do {
+ found = false;
+ for (ALL_LIST_ELEMENTS(block->u.uncompressed
+ .func_released,
+ node, nnode,
+ sid_func_ptr))
+ if (*sid_func_ptr ==
+ block->u.uncompressed
+ .first_available_func -
+ 1) {
+ listnode_delete(block->u.uncompressed
+ .func_released,
+ sid_func_ptr);
+ zebra_srv6_sid_func_free(
+ sid_func_ptr);
+ block->u.uncompressed
+ .first_available_func -=
+ 1;
+ found = true;
+ break;
+ }
+ } while (found);
+ } else {
+ /*
+ * The released SID function does not precede the `first_available_func`.
+ * Add the released function to the func_released array to indicate
+ * that it is available again for allocation.
+ */
+ sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func);
+ listnode_add_head(block->u.uncompressed.func_released,
+ sid_func_ptr);
+ }
+ } else if (!format) {
+ if (sid_func == block->u.uncompressed.first_available_func - 1) {
+ /*
+ * The released SID function precedes the `first_available_func`.
+ * Reset first_available_func to the first available position.
+ */
+
+ block->u.uncompressed.first_available_func -= 1;
+
+ bool found;
+
+ do {
+ found = false;
+ for (ALL_LIST_ELEMENTS(block->u.uncompressed
+ .func_released,
+ node, nnode,
+ sid_func_ptr))
+ if (*sid_func_ptr ==
+ block->u.uncompressed
+ .first_available_func -
+ 1) {
+ listnode_delete(block->u.uncompressed
+ .func_released,
+ sid_func_ptr);
+ zebra_srv6_sid_func_free(
+ sid_func_ptr);
+ block->u.uncompressed
+ .first_available_func -=
+ 1;
+ found = true;
+ break;
+ }
+ } while (found);
+ } else {
+ /*
+ * The released SID function does not precede the `first_available_func`.
+ * Add the released function to the func_released array to indicate
+ * that it is available again for allocation.
+ */
+ sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func);
+ listnode_add_head(block->u.uncompressed.func_released,
+ sid_func_ptr);
+ }
+ }
+
+ if (ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: released dynamic SRv6 SID function %u from block %pFX",
+ __func__, sid_func, &block->prefix);
+
+ return 0;
+}
+
+/**
+ * Core function, release the SRv6 SID associated with a given context.
+ *
+ * @param client The client for which the SID has to be released
+ * @param ctx Context associated with the SRv6 SID to be released
+ * @return 0 on success, -1 otherwise
+ */
+int release_srv6_sid(struct zserv *client, struct zebra_srv6_sid_ctx *zctx)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ char buf[256];
+
+ if (!zctx || !zctx->sid)
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: releasing SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)",
+ __func__, &zctx->sid->value,
+ srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx),
+ client->proto, client->instance);
+
+ /* Ensures the SID is in use by the client */
+ if (!listnode_lookup(zctx->sid->client_list, client)) {
+ flog_err(EC_ZEBRA_SM_DAEMON_MISMATCH, "%s: Daemon mismatch!!",
+ __func__);
+ return -1;
+ }
+
+ /* Remove the client from the list of clients using the SID */
+ listnode_delete(zctx->sid->client_list, client);
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: released SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)",
+ __func__, &zctx->sid->value,
+ srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx),
+ client->proto, client->instance);
+
+ /*
+ * If the SID is not used by any other client, then deallocate it
+ * and remove it from the SRv6 database.
+ */
+ if (listcount(zctx->sid->client_list) == 0) {
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: SRv6 SID %pI6 associated with ctx %s is no longer in use, removing it from SRv6 database",
+ __func__, &zctx->sid->value,
+ srv6_sid_ctx2str(buf, sizeof(buf),
+ &zctx->ctx));
+
+ if (!(zctx->sid->block->sid_format &&
+ zctx->sid->block->sid_format->type ==
+ SRV6_SID_FORMAT_TYPE_USID &&
+ zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) &&
+ !(!zctx->sid->block->sid_format &&
+ zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END)) {
+ if (zctx->sid->alloc_mode ==
+ SRV6_SID_ALLOC_MODE_EXPLICIT)
+ /* Release SRv6 SID function */
+ release_srv6_sid_func_explicit(zctx->sid->block,
+ zctx->sid->func,
+ zctx->sid->wide_func);
+ else if (zctx->sid->alloc_mode ==
+ SRV6_SID_ALLOC_MODE_DYNAMIC)
+ /* Release SRv6 SID function */
+ release_srv6_sid_func_dynamic(zctx->sid->block,
+ zctx->sid->func);
+ else
+ /* We should never arrive here */
+ assert(0);
+ }
+
+ /* Free the SID */
+ zebra_srv6_sid_free(zctx->sid);
+ zctx->sid = NULL;
+
+ /* Remove the SID context from the list and free memory */
+ listnode_delete(srv6->sids, zctx);
+ zebra_srv6_sid_ctx_free(zctx);
+ }
+
+ return 0;
+}
+
+/**
+ * Handle a get SRv6 Locator request received from a client.
+ *
+ * It looks up the requested locator and send it to the client.
+ *
+ * @param locator SRv6 locator returned by this function
+ * @param client The client that sent the Get SRv6 Locator request
+ * @param locator_name Name of the locator to look up
+ *
+ * @return 0 on success
+ */
+static int srv6_manager_get_srv6_locator_internal(struct srv6_locator **locator,
+ struct zserv *client,
+ const char *locator_name)
+{
+ *locator = zebra_srv6_locator_lookup(locator_name);
+ if (!*locator)
+ return -1;
+
+ return zsend_zebra_srv6_locator_add(client, *locator);
+}
+
+/**
+ * Handle a get SID request received from a client.
+ *
+ * It gets a SID for a given context. If there is no SID associated with the context yet,
+ * we allocate one and return it to the client. Otherwise, we return the existing SID.
+ *
+ * - When the `sid_value` parameter is non-NULL, SRv6 Manager assigns the requested SID value
+ * if it is available (explicit SID allocation).
+ * - When the `sid_value` parameter is NULL, SRv6 Manager assigns any available SID value
+ * (dynamic SID allocation).
+ *
+ * Finally, notify the client whether the SID allocation was successful or failed.
+ *
+ * @param sid SID returned by this function
+ * @param client The client that requested the SID
+ * @param ctx Context for which the SID was requested
+ * @param sid_value SID value (i.e., IPv6 address) that has to be assigned to the SID
+ * (for explicit SID allocation)
+ * @param locator_name Locator from which the SID has to be allocated (for dynamic SID allocation)
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid,
+ struct zserv *client,
+ struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value,
+ const char *locator_name)
+{
+ int ret = -1;
+ struct listnode *node;
+ struct zserv *c;
+ char buf[256];
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: getting SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s",
+ __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx),
+ sid_value ? sid_value : &in6addr_any, locator_name);
+
+ ret = get_srv6_sid(sid, ctx, sid_value, locator_name);
+ if (ret < 0) {
+ zlog_warn("%s: not got SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s",
+ __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx),
+ sid_value ? sid_value : &in6addr_any, locator_name);
+
+ /* Notify client about SID alloc failure */
+ zsend_srv6_sid_notify(client, ctx, sid_value, 0, 0, NULL,
+ ZAPI_SRV6_SID_FAIL_ALLOC);
+ } else if (ret == 0) {
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: got existing SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notify client",
+ __func__,
+ srv6_sid_ctx2str(buf, sizeof(buf), ctx),
+ &(*sid)->value, (*sid)->func, client->proto,
+ client->instance, client->session_id);
+ if (!listnode_lookup((*sid)->client_list, client))
+ listnode_add((*sid)->client_list, client);
+
+ zsend_srv6_sid_notify(client, ctx, &(*sid)->value, (*sid)->func,
+ (*sid)->wide_func,
+ (*sid)->locator ? (*sid)->locator->name
+ : NULL,
+ ZAPI_SRV6_SID_ALLOCATED);
+ } else {
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: got new SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notifying all clients",
+ __func__,
+ srv6_sid_ctx2str(buf, sizeof(buf), ctx),
+ &(*sid)->value, (*sid)->func, client->proto,
+ client->instance, client->session_id);
+ if (!listnode_lookup((*sid)->client_list, client))
+ listnode_add((*sid)->client_list, client);
+
+ for (ALL_LIST_ELEMENTS_RO((*sid)->client_list, node, c))
+ zsend_srv6_sid_notify(c, ctx, &(*sid)->value,
+ (*sid)->func, (*sid)->wide_func,
+ (*sid)->locator
+ ? (*sid)->locator->name
+ : NULL,
+ ZAPI_SRV6_SID_ALLOCATED);
+ }
+
+ return ret;
+}
+
+/**
+ * Release SRv6 SIDs from a client.
+ *
+ * Called on client disconnection or reconnection.
+ *
+ * @param client The client to release SIDs from
+ * @return Number of SIDs released
+ */
+int release_daemon_srv6_sids(struct zserv *client)
+{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ struct listnode *node, *nnode;
+ struct zebra_srv6_sid_ctx *ctx;
+ int count = 0;
+ int ret;
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: releasing SRv6 SIDs for client proto %s, instance %d, session %u",
+ __func__, zebra_route_string(client->proto),
+ client->instance, client->session_id);
+
+ /* Iterate over the SIDs and release SIDs used by the client daemon */
+ for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) {
+ if (!listnode_lookup(ctx->sid->client_list, client))
+ continue;
+
+ ret = release_srv6_sid(client, ctx);
+ if (ret == 0)
+ count++;
+ }
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: released %d SRv6 SIDs", __func__, count);
+
+ return count;
+}
+
+/**
+ * Release SRv6 SIDs from a client.
+ *
+ * @param client The client zapi session
+ * @param ctx Context associated with the SRv6 SID
+ * @return 0 on success, -1 on failure
+ */
+static int srv6_manager_release_sid_internal(struct zserv *client,
+ struct srv6_sid_ctx *ctx)
+{
+ int ret = -1;
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ struct zebra_srv6_sid_ctx *zctx;
+ struct listnode *node, *nnode;
+ char buf[256];
+ const char *locator_name = NULL;
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: releasing SRv6 SID associated with ctx %s",
+ __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx));
+
+ /* Lookup Zebra SID context and release it */
+ for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, zctx))
+ if (memcmp(&zctx->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) {
+ if (zctx->sid && zctx->sid->locator)
+ locator_name =
+ (const char *)zctx->sid->locator->name;
+ ret = release_srv6_sid(client, zctx);
+ break;
+ }
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: no SID associated with ctx %s", __func__,
+ srv6_sid_ctx2str(buf, sizeof(buf), ctx));
+
+ if (ret == 0)
+ zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name,
+ ZAPI_SRV6_SID_RELEASED);
+ else
+ zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name,
+ ZAPI_SRV6_SID_FAIL_RELEASE);
+
+ return ret;
+}
+
void zebra_srv6_terminate(void)
{
struct srv6_locator *locator;
+ struct srv6_sid_format *format;
+ struct zebra_srv6_sid_block *block;
+ struct zebra_srv6_sid_ctx *sid_ctx;
- if (!srv6.locators)
- return;
+ if (srv6.locators) {
+ while (listcount(srv6.locators)) {
+ locator = listnode_head(srv6.locators);
+
+ listnode_delete(srv6.locators, locator);
+ srv6_locator_free(locator);
+ }
- while (listcount(srv6.locators)) {
- locator = listnode_head(srv6.locators);
+ list_delete(&srv6.locators);
+ }
+
+ /* Free SRv6 SIDs */
+ if (srv6.sids) {
+ while (listcount(srv6.sids)) {
+ sid_ctx = listnode_head(srv6.sids);
- listnode_delete(srv6.locators, locator);
- srv6_locator_free(locator);
+ listnode_delete(srv6.sids, sid_ctx);
+ zebra_srv6_sid_ctx_free(sid_ctx);
+ }
+
+ list_delete(&srv6.sids);
}
- list_delete(&srv6.locators);
+ /* Free SRv6 SID blocks */
+ if (srv6.sid_blocks) {
+ while (listcount(srv6.sid_blocks)) {
+ block = listnode_head(srv6.sid_blocks);
+
+ listnode_delete(srv6.sid_blocks, block);
+ zebra_srv6_sid_block_free(block);
+ }
+
+ list_delete(&srv6.sid_blocks);
+ }
+
+ /* Free SRv6 SID formats */
+ if (srv6.sid_formats) {
+ while (listcount(srv6.sid_formats)) {
+ format = listnode_head(srv6.sid_formats);
+
+ srv6_sid_format_unregister(format);
+ srv6_sid_format_free(format);
+ }
+
+ list_delete(&srv6.sid_formats);
+ }
}
void zebra_srv6_init(void)
@@ -451,6 +2463,12 @@ void zebra_srv6_init(void)
zebra_srv6_manager_get_locator_chunk);
hook_register(srv6_manager_release_chunk,
zebra_srv6_manager_release_locator_chunk);
+
+ hook_register(srv6_manager_get_sid, srv6_manager_get_sid_internal);
+ hook_register(srv6_manager_release_sid,
+ srv6_manager_release_sid_internal);
+ hook_register(srv6_manager_get_locator,
+ srv6_manager_get_srv6_locator_internal);
}
bool zebra_srv6_is_enable(void)
diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h
index 21936c3323..1599fd7adf 100644
--- a/zebra/zebra_srv6.h
+++ b/zebra/zebra_srv6.h
@@ -16,12 +16,197 @@
#include <pthread.h>
#include <plist.h>
+/* Default config for SRv6 SID `usid-f3216` format */
+#define SRV6_SID_FORMAT_USID_F3216_NAME "usid-f3216"
+#define SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN 32
+#define SRV6_SID_FORMAT_USID_F3216_NODE_LEN 16
+#define SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN 16
+#define SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN 0
+#define SRV6_SID_FORMAT_USID_F3216_LIB_START 0xE000
+#define SRV6_SID_FORMAT_USID_F3216_ELIB_START 0xFE00
+#define SRV6_SID_FORMAT_USID_F3216_ELIB_END 0xFEFF
+#define SRV6_SID_FORMAT_USID_F3216_WLIB_START 0xFFF0
+#define SRV6_SID_FORMAT_USID_F3216_WLIB_END 0xFFF7
+#define SRV6_SID_FORMAT_USID_F3216_EWLIB_START 0xFFF7
+
+/* Default config for SRv6 SID `uncompressed` format */
+#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME "uncompressed-f4024"
+#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN 40
+#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN 24
+#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN 16
+#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN 0
+#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START 0xFF00
+#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN 0x40
+
+/* uSID Wide LIB */
+struct wide_lib {
+ uint32_t func;
+ uint32_t num_func_allocated;
+ uint32_t first_available_func;
+ struct list *func_allocated;
+ struct list *func_released;
+};
+
+/*
+ * SRv6 SID block.
+ *
+ * A SID block is an IPv6 prefix from which SRv6 SIDs are allocated.
+ * Example:
+ * SID block = fc00:0::/32
+ * SID 1 = fc00:0:1:e000::
+ * SID 2 = fc00:0:1:fe00::
+ * ...
+ */
+struct zebra_srv6_sid_block {
+ /* Prefix of this block, e.g. fc00:0::/32 */
+ struct prefix_ipv6 prefix;
+
+ /* Reference counter */
+ unsigned long refcnt;
+
+ /*
+ * Pointer to the SID format that defines the structure of the SIDs
+ * allocated from this block
+ */
+ struct srv6_sid_format *sid_format;
+
+ /*
+ * Run-time information/state of this SID block.
+ *
+ * This includes stuff like how many SID functions have been allocated
+ * from this block, which functions are still available to be allocated
+ * and so on...
+ */
+ union {
+ /* Information/state for compressed uSID format */
+ struct {
+ /* uSID Local ID Block (LIB) */
+ struct {
+ uint32_t num_func_allocated;
+ uint32_t first_available_func;
+ struct list *func_allocated;
+ struct list *func_released;
+ } lib;
+
+ /* uSID Wide LIB */
+ struct wide_lib *wide_lib;
+ } usid;
+
+ /* Information/state for uncompressed SID format */
+ struct {
+ uint32_t num_func_allocated;
+ uint32_t first_available_func;
+ struct list *func_allocated;
+ struct list *func_released;
+ } uncompressed;
+ } u;
+};
+
+/**
+ * The function part of an SRv6 SID can be allocated in one
+ * of the following ways:
+ * - dynamic: allocate any available function
+ * - explicit: allocate a specific function
+ */
+enum srv6_sid_alloc_mode {
+ SRV6_SID_ALLOC_MODE_UNSPEC = 0,
+ /* Dynamic SID allocation */
+ SRV6_SID_ALLOC_MODE_DYNAMIC = 1,
+ /* Explicit SID allocation */
+ SRV6_SID_ALLOC_MODE_EXPLICIT = 2,
+ SRV6_SID_ALLOC_MODE_MAX = 3,
+};
+
+/**
+ * Convert SID allocation mode to string.
+ *
+ * @param alloc_mode SID allocation mode
+ * @return String representing the allocation mode
+ */
+static inline const char *
+srv6_sid_alloc_mode2str(enum srv6_sid_alloc_mode alloc_mode)
+{
+ switch (alloc_mode) {
+ case SRV6_SID_ALLOC_MODE_EXPLICIT:
+ return "explicit";
+ case SRV6_SID_ALLOC_MODE_DYNAMIC:
+ return "dynamic";
+ case SRV6_SID_ALLOC_MODE_UNSPEC:
+ return "unspec";
+ case SRV6_SID_ALLOC_MODE_MAX:
+ default:
+ return "unknown";
+ }
+}
+
+/* SRv6 SID instance. */
+struct zebra_srv6_sid {
+ /*
+ * SID context associated with the SID.
+ * Defines behavior and attributes of the SID.
+ */
+ struct zebra_srv6_sid_ctx *ctx;
+
+ /* SID value (e.g. fc00:0:1:e000::) */
+ struct in6_addr value;
+
+ /* Pointer to the SRv6 locator from which the SID has been allocated */
+ struct srv6_locator *locator;
+
+ /* Pointer to the SRv6 block from which the SID has been allocated */
+ struct zebra_srv6_sid_block *block;
+
+ /*
+ * Function part of the SID
+ * Example:
+ * SID = fc00:0:1:e000:: => func = e000
+ */
+ uint32_t func;
+
+ /* SID wide function. */
+ uint32_t wide_func;
+
+ /* SID allocation mode: dynamic or explicit */
+ enum srv6_sid_alloc_mode alloc_mode;
+
+ /* List of clients that are using the SID */
+ struct list *client_list;
+};
+
+/*
+ * Zebra SRv6 SID context.
+ * A context defines a behavior and (optionally) some behavior-specific
+ * attributes. Client daemons (bgp, isis, ...) ask SRv6 Manager to allocate
+ * a SID for a particular context. SRv6 Manager is responsible for allocating
+ * a SID from a given SID block and associating with the context.
+ *
+ * Example:
+ * bgp asks to associate a SID to the context {behavior=End.DT46 vrf=Vrf10}.
+ * SRv6 Manager allocate SID fc00:0:1:e000:: for that context.
+ */
+struct zebra_srv6_sid_ctx {
+ /* SRv6 SID context information. */
+ struct srv6_sid_ctx ctx;
+
+ /* SID associated with the context. */
+ struct zebra_srv6_sid *sid;
+};
+
/* SRv6 instance structure. */
struct zebra_srv6 {
struct list *locators;
/* Source address for SRv6 encapsulation */
struct in6_addr encap_src_addr;
+
+ /* SRv6 SID formats */
+ struct list *sid_formats;
+
+ /* SRv6 SIDs */
+ struct list *sids;
+
+ /* SRv6 SID blocks */
+ struct list *sid_blocks;
};
/* declare hooks for the basic API, so that it can be specialized or served
@@ -46,6 +231,17 @@ DECLARE_HOOK(srv6_manager_release_chunk,
vrf_id_t vrf_id),
(client, locator_name, vrf_id));
+DECLARE_HOOK(srv6_manager_get_sid,
+ (struct zebra_srv6_sid **sid, struct zserv *client,
+ struct srv6_sid_ctx *ctx, struct in6_addr *sid_value,
+ const char *locator_name),
+ (sid, client, ctx, sid_value, locator_name));
+DECLARE_HOOK(srv6_manager_release_sid,
+ (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx));
+DECLARE_HOOK(srv6_manager_get_locator,
+ (struct srv6_locator **locator, struct zserv *client,
+ const char *locator_name),
+ (locator, client, locator_name));
extern void zebra_srv6_locator_add(struct srv6_locator *locator);
extern void zebra_srv6_locator_delete(struct srv6_locator *locator);
@@ -74,4 +270,55 @@ extern int release_daemon_srv6_locator_chunks(struct zserv *client);
extern void zebra_srv6_encap_src_addr_set(struct in6_addr *src_addr);
extern void zebra_srv6_encap_src_addr_unset(void);
+void srv6_sid_format_register(struct srv6_sid_format *format);
+void srv6_sid_format_unregister(struct srv6_sid_format *format);
+struct srv6_sid_format *srv6_sid_format_lookup(const char *name);
+void zebra_srv6_locator_format_set(struct srv6_locator *locator,
+ struct srv6_sid_format *format);
+void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format);
+
+uint32_t *zebra_srv6_sid_func_alloc(uint32_t func);
+void zebra_srv6_sid_func_free(uint32_t *func);
+void delete_zebra_srv6_sid_func(void *val);
+
+extern struct zebra_srv6_sid_block *
+zebra_srv6_sid_block_alloc(struct srv6_sid_format *format,
+ struct prefix_ipv6 *prefix);
+extern void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block);
+extern void delete_zebra_srv6_sid_block(void *val);
+extern struct zebra_srv6_sid_block *
+zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix);
+
+extern struct zebra_srv6_sid *
+zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value,
+ struct srv6_locator *locator,
+ struct zebra_srv6_sid_block *sid_block, uint32_t sid_func,
+ enum srv6_sid_alloc_mode alloc_mode);
+extern void zebra_srv6_sid_free(struct zebra_srv6_sid *sid);
+extern void delete_zebra_srv6_sid(void *val);
+
+extern void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid,
+ struct zserv *client,
+ struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value,
+ const char *locator_name);
+extern void srv6_manager_release_sid_call(struct zserv *client,
+ struct srv6_sid_ctx *ctx);
+
+extern void srv6_manager_get_locator_call(struct srv6_locator **locator,
+ struct zserv *client,
+ const char *locator_name);
+
+extern int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx,
+ struct in6_addr *sid_value, const char *locator_name);
+extern int release_srv6_sid(struct zserv *client,
+ struct zebra_srv6_sid_ctx *zctx);
+extern int release_daemon_srv6_sids(struct zserv *client);
+extern int srv6_manager_get_sid_response(struct zebra_srv6_sid *sid,
+ struct zserv *client);
+
+extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void);
+extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx);
+extern void delete_zebra_srv6_sid_ctx(void *val);
+
#endif /* _ZEBRA_SRV6_H */
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index d5cd30e64b..c664a9c69f 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -68,6 +68,27 @@ static struct cmd_node srv6_encap_node = {
.prompt = "%s(config-srv6-encap)# "
};
+static struct cmd_node srv6_sid_formats_node = {
+ .name = "srv6-formats",
+ .node = SRV6_SID_FORMATS_NODE,
+ .parent_node = SRV6_NODE,
+ .prompt = "%s(config-srv6-formats)# ",
+};
+
+static struct cmd_node srv6_sid_format_usid_f3216_node = {
+ .name = "srv6-format-usid-f3216",
+ .node = SRV6_SID_FORMAT_USID_F3216_NODE,
+ .parent_node = SRV6_SID_FORMATS_NODE,
+ .prompt = "%s(config-srv6-format)# "
+};
+
+static struct cmd_node srv6_sid_format_uncompressed_f4024_node = {
+ .name = "srv6-format-uncompressed-f4024",
+ .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE,
+ .parent_node = SRV6_SID_FORMATS_NODE,
+ .prompt = "%s(config-srv6-format)# "
+};
+
DEFPY (show_srv6_manager,
show_srv6_manager_cmd,
"show segment-routing srv6 manager [json]",
@@ -198,15 +219,32 @@ DEFUN (show_srv6_locator_detail,
prefix2str(&locator->prefix, str, sizeof(str));
vty_out(vty, "Name: %s\n", locator->name);
vty_out(vty, "Prefix: %s\n", str);
- vty_out(vty, "Block-Bit-Len: %u\n", locator->block_bits_length);
- vty_out(vty, "Node-Bit-Len: %u\n", locator->node_bits_length);
- vty_out(vty, "Function-Bit-Len: %u\n",
- locator->function_bits_length);
- vty_out(vty, "Argument-Bit-Len: %u\n",
- locator->argument_bits_length);
+ if (locator->sid_format) {
+ vty_out(vty, "Block-Bit-Len: %u\n",
+ locator->sid_format->block_len);
+ vty_out(vty, "Node-Bit-Len: %u\n",
+ locator->sid_format->node_len);
+ vty_out(vty, "Function-Bit-Len: %u\n",
+ locator->sid_format->function_len);
+ vty_out(vty, "Argument-Bit-Len: %u\n",
+ locator->sid_format->argument_len);
+
+ if (locator->sid_format->type ==
+ SRV6_SID_FORMAT_TYPE_USID)
+ vty_out(vty, "Behavior: uSID\n");
+ } else {
+ vty_out(vty, "Block-Bit-Len: %u\n",
+ locator->block_bits_length);
+ vty_out(vty, "Node-Bit-Len: %u\n",
+ locator->node_bits_length);
+ vty_out(vty, "Function-Bit-Len: %u\n",
+ locator->function_bits_length);
+ vty_out(vty, "Argument-Bit-Len: %u\n",
+ locator->argument_bits_length);
- if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
- vty_out(vty, "Behavior: uSID\n");
+ if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ vty_out(vty, "Behavior: uSID\n");
+ }
vty_out(vty, "Chunks:\n");
for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node,
@@ -248,9 +286,30 @@ DEFUN (no_srv6,
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
struct srv6_locator *locator;
struct listnode *node, *nnode;
+ struct zebra_srv6_sid_block *block;
+ struct zebra_srv6_sid_ctx *ctx;
+
+ for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) {
+ if (ctx->sid)
+ zebra_srv6_sid_free(ctx->sid);
+
+ listnode_delete(srv6->sids, ctx);
+ zebra_srv6_sid_ctx_free(ctx);
+ }
+
+ for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) {
+ block = locator->sid_block;
+ if (block) {
+ block->refcnt--;
+ if (block->refcnt == 0) {
+ listnode_delete(srv6->sid_blocks, block);
+ zebra_srv6_sid_block_free(block);
+ }
+ locator->sid_block = NULL;
+ }
- for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator))
zebra_srv6_locator_delete(locator);
+ }
return CMD_SUCCESS;
}
@@ -297,12 +356,37 @@ DEFUN (no_srv6_locator,
"Segment Routing SRv6 locator\n"
"Specify locator-name\n")
{
+ struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+ struct zebra_srv6_sid_block *block;
+ struct listnode *node, *nnode;
+ struct zebra_srv6_sid_ctx *ctx;
struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg);
if (!locator) {
vty_out(vty, "%% Can't find SRv6 locator\n");
return CMD_WARNING_CONFIG_FAILED;
}
+ for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) {
+ if (!ctx->sid || ctx->sid->locator != locator)
+ continue;
+
+ if (ctx->sid)
+ zebra_srv6_sid_free(ctx->sid);
+
+ listnode_delete(srv6->sids, ctx);
+ zebra_srv6_sid_ctx_free(ctx);
+ }
+
+ block = locator->sid_block;
+ if (block) {
+ block->refcnt--;
+ if (block->refcnt == 0) {
+ listnode_delete(srv6->sid_blocks, block);
+ zebra_srv6_sid_block_free(block);
+ }
+ locator->sid_block = NULL;
+ }
+
zebra_srv6_locator_delete(locator);
return CMD_SUCCESS;
}
@@ -323,14 +407,37 @@ DEFPY (locator_prefix,
VTY_DECLVAR_CONTEXT(srv6_locator, locator);
struct srv6_locator_chunk *chunk = NULL;
struct listnode *node = NULL;
+ uint8_t expected_prefixlen;
+ struct srv6_sid_format *format;
locator->prefix = *prefix;
func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH;
+ expected_prefixlen = prefix->prefixlen;
+ format = locator->sid_format;
+ if (format) {
+ if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME))
+ expected_prefixlen =
+ SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN +
+ SRV6_SID_FORMAT_USID_F3216_NODE_LEN;
+ else if (strmatch(format->name,
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME))
+ expected_prefixlen =
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN +
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN;
+ }
+
+ if (prefix->prefixlen != expected_prefixlen) {
+ vty_out(vty,
+ "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n",
+ prefix->prefixlen, format->name);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
/* Resolve optional arguments */
if (block_bit_len == 0 && node_bit_len == 0) {
- block_bit_len =
- prefix->prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH;
+ block_bit_len = prefix->prefixlen -
+ ZEBRA_SRV6_LOCATOR_NODE_LENGTH;
node_bit_len = ZEBRA_SRV6_LOCATOR_NODE_LENGTH;
} else if (block_bit_len == 0) {
block_bit_len = prefix->prefixlen - node_bit_len;
@@ -401,7 +508,8 @@ DEFPY (locator_prefix,
}
}
- zebra_srv6_locator_add(locator);
+ zebra_srv6_locator_format_set(locator, locator->sid_format);
+
return CMD_SUCCESS;
}
@@ -422,8 +530,9 @@ DEFPY (locator_behavior,
/* SRv6 locator uSID flag already set, nothing to do */
return CMD_SUCCESS;
- /* Remove old locator from zclients */
- zebra_notify_srv6_locator_delete(locator);
+ if (!locator->sid_format)
+ /* Remove old locator from zclients */
+ zebra_notify_srv6_locator_delete(locator);
/* Set/Unset the SRV6_LOCATOR_USID */
if (no)
@@ -431,8 +540,75 @@ DEFPY (locator_behavior,
else
SET_FLAG(locator->flags, SRV6_LOCATOR_USID);
- /* Notify the new locator to zclients */
- zebra_notify_srv6_locator_add(locator);
+ if (!locator->sid_format)
+ /* Notify the new locator to zclients */
+ zebra_srv6_locator_add(locator);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(locator_sid_format,
+ locator_sid_format_cmd,
+ "format <usid-f3216|uncompressed-f4024>$format",
+ "Configure SRv6 SID format\n"
+ "Specify usid-f3216 format\n"
+ "Specify uncompressed-f4024 format\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_locator, locator);
+ struct srv6_sid_format *sid_format = NULL;
+ uint8_t expected_prefixlen;
+
+ expected_prefixlen = locator->prefix.prefixlen;
+ if (strmatch(format, SRV6_SID_FORMAT_USID_F3216_NAME))
+ expected_prefixlen = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN +
+ SRV6_SID_FORMAT_USID_F3216_NODE_LEN;
+ else if (strmatch(format, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME))
+ expected_prefixlen =
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN +
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN;
+
+ if (IPV6_ADDR_SAME(&locator->prefix, &in6addr_any)) {
+ vty_out(vty,
+ "%% Unexpected configuration sequence: the prefix of the locator is required before configuring the format. Please configure the prefix first and then configure the format.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (locator->prefix.prefixlen != expected_prefixlen) {
+ vty_out(vty,
+ "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n",
+ locator->prefix.prefixlen, format);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ sid_format = srv6_sid_format_lookup(format);
+ if (!sid_format) {
+ vty_out(vty, "%% Cannot find SRv6 SID format '%s'\n", format);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (sid_format == locator->sid_format)
+ /* Format has not changed, nothing to do */
+ return CMD_SUCCESS;
+
+ zebra_srv6_locator_format_set(locator, sid_format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (no_locator_sid_format,
+ no_locator_sid_format_cmd,
+ "no format [WORD]",
+ NO_STR
+ "Configure SRv6 SID format\n"
+ "Specify SRv6 SID format\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_locator, locator);
+
+ if (!locator->sid_format)
+ /* SID format already unset, nothing to do */
+ return CMD_SUCCESS;
+
+ zebra_srv6_locator_format_set(locator, NULL);
return CMD_SUCCESS;
}
@@ -469,11 +645,312 @@ DEFPY (no_srv6_src_addr,
return CMD_SUCCESS;
}
+DEFUN_NOSH(srv6_sid_formats,
+ srv6_sid_formats_cmd,
+ "formats",
+ "Segment Routing SRv6 SID formats\n")
+{
+ vty->node = SRV6_SID_FORMATS_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUN_NOSH (srv6_sid_format_f3216_usid,
+ srv6_sid_format_f3216_usid_cmd,
+ "format usid-f3216",
+ "Configure SRv6 SID format\n"
+ "Configure the uSID f3216 format\n")
+{
+ struct srv6_sid_format *format;
+
+ format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME);
+ assert(format);
+
+ VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_USID_F3216_NODE, format);
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_srv6_sid_format_f3216_usid,
+ no_srv6_sid_format_f3216_usid_cmd,
+ "no format usid-f3216",
+ NO_STR
+ "Configure SRv6 SID format\n"
+ "Configure the uSID f3216 format\n")
+{
+ struct srv6_sid_format *format;
+
+ format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME);
+ assert(format);
+
+ format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START;
+ format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START;
+ format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END;
+ format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START;
+ format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END;
+ format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START;
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_NOSH (srv6_sid_format_f4024_uncompressed,
+ srv6_sid_format_uncompressed_cmd,
+ "format uncompressed-f4024",
+ "Configure SRv6 SID format\n"
+ "Configure the uncompressed f4024 format\n")
+{
+ struct srv6_sid_format *format;
+
+ format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME);
+ assert(format);
+
+ VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, format);
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_srv6_sid_format_f4024_uncompressed,
+ no_srv6_sid_format_f4024_uncompressed_cmd,
+ "no format uncompressed-f4024",
+ NO_STR
+ "Configure SRv6 SID format\n"
+ "Configure the uncompressed f4024 format\n")
+{
+ struct srv6_sid_format *format;
+
+ format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME);
+ assert(format);
+
+ format->config.uncompressed.explicit_start =
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START;
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(srv6_sid_format_usid_lib,
+ srv6_sid_format_usid_lib_cmd,
+ "local-id-block start (0-4294967295)$start",
+ "Configure LIB\n"
+ "Configure the start value for the LIB\n"
+ "Specify the start value for the LIB\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+
+ format->config.usid.lib_start = start;
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_srv6_sid_format_usid_lib,
+ no_srv6_sid_format_usid_lib_cmd,
+ "no local-id-block [start (0-4294967295)]",
+ NO_STR
+ "Configure LIB\n"
+ "Configure the start value for the LIB\n"
+ "Specify the start value for the LIB\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+
+ if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME))
+ format->config.usid.lib_start =
+ SRV6_SID_FORMAT_USID_F3216_LIB_START;
+ else
+ assert(0);
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(srv6_sid_format_usid_lib_explicit,
+ srv6_sid_format_usid_lib_explicit_cmd,
+ "local-id-block explicit start (0-4294967295)$start end (0-4294967295)$end",
+ "Configure LIB\n"
+ "Configure the Explicit LIB\n"
+ "Configure the start value for the Explicit LIB\n"
+ "Specify the start value for the Explicit LIB\n"
+ "Configure the end value for the Explicit LIB\n"
+ "Specify the end value for the Explicit LIB\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+
+ format->config.usid.elib_start = start;
+ format->config.usid.elib_end = end;
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_srv6_sid_format_usid_lib_explicit,
+ no_srv6_sid_format_usid_lib_explicit_cmd,
+ "no local-id-block explicit [start (0-4294967295) end (0-4294967295)]",
+ NO_STR
+ "Configure LIB\n"
+ "Configure the Explicit LIB\n"
+ "Configure the start value for the Explicit LIB\n"
+ "Specify the start value for the Explicit LIB\n"
+ "Configure the end value for the Explicit LIB\n"
+ "Specify the end value for the Explicit LIB\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+
+ if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) {
+ format->config.usid.elib_start =
+ SRV6_SID_FORMAT_USID_F3216_ELIB_START;
+ format->config.usid.elib_end =
+ SRV6_SID_FORMAT_USID_F3216_ELIB_END;
+ } else {
+ assert(0);
+ }
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(srv6_sid_format_usid_wlib,
+ srv6_sid_format_usid_wlib_cmd,
+ "wide-local-id-block start (0-4294967295)$start end (0-4294967295)$end",
+ "Configure Wide LIB\n"
+ "Configure the start value for the Wide LIB\n"
+ "Specify the start value for the Wide LIB\n"
+ "Configure the end value for the Wide LIB\n"
+ "Specify the end value for the Wide LIB\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+
+ format->config.usid.wlib_start = start;
+ format->config.usid.wlib_end = end;
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_srv6_sid_format_usid_wlib,
+ no_srv6_sid_format_usid_wlib_cmd,
+ "no wide-local-id-block [start (0-4294967295) end (0-4294967295)]",
+ NO_STR
+ "Configure Wide LIB\n"
+ "Configure the start value for the Wide LIB\n"
+ "Specify the start value for the Wide LIB\n"
+ "Configure the end value for the Wide LIB\n"
+ "Specify the end value for the Wide LIB\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+
+ if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) {
+ format->config.usid.wlib_start =
+ SRV6_SID_FORMAT_USID_F3216_WLIB_START;
+ format->config.usid.wlib_end =
+ SRV6_SID_FORMAT_USID_F3216_WLIB_END;
+ } else {
+ assert(0);
+ }
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(srv6_sid_format_usid_wide_lib_explicit,
+ srv6_sid_format_usid_wide_lib_explicit_cmd,
+ "wide-local-id-block explicit start (0-4294967295)$start",
+ "Configure Wide LIB\n"
+ "Configure Explicit Wide LIB\n"
+ "Configure the start value for the Explicit Wide LIB\n"
+ "Specify the start value for the Explicit Wide LIB\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+
+ format->config.usid.ewlib_start = start;
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_srv6_sid_format_usid_wide_lib_explicit,
+ no_srv6_sid_format_usid_wide_lib_explicit_cmd,
+ "no wide-local-id-block explicit [start (0-4294967295)]",
+ NO_STR
+ "Configure Wide LIB\n"
+ "Configure Explicit Wide LIB\n"
+ "Configure the start value for the Explicit Wide LIB\n"
+ "Specify the start value for the Explicit Wide LIB\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+
+ if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME))
+ format->config.usid.ewlib_start =
+ SRV6_SID_FORMAT_USID_F3216_EWLIB_START;
+ else
+ assert(0);
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(srv6_sid_format_explicit,
+ srv6_sid_format_explicit_cmd,
+ "explicit start (0-4294967295)$start",
+ "Configure Explicit range\n"
+ "Configure the start value for the Explicit range\n"
+ "Specify the start value for the Explicit range\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+
+ format->config.uncompressed.explicit_start = start;
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_srv6_sid_format_explicit,
+ no_srv6_sid_format_explicit_cmd,
+ "no explicit [start (0-4294967295)$start]",
+ NO_STR
+ "Configure Explicit range\n"
+ "Configure the start value for the Explicit range\n"
+ "Specify the start value for the Explicit range\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+
+ if (strmatch(format->name, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME))
+ format->config.usid.ewlib_start =
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START;
+ else
+ assert(0);
+
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
+ return CMD_SUCCESS;
+}
+
static int zebra_sr_config(struct vty *vty)
{
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
struct listnode *node;
struct srv6_locator *locator;
+ struct srv6_sid_format *format;
char str[256];
bool display_source_srv6 = false;
@@ -515,6 +992,54 @@ static int zebra_sr_config(struct vty *vty)
vty_out(vty, "\n");
if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
vty_out(vty, " behavior usid\n");
+ if (locator->sid_format) {
+ format = locator->sid_format;
+ vty_out(vty, " format %s\n", format->name);
+ }
+ vty_out(vty, " exit\n");
+ vty_out(vty, " !\n");
+ }
+ vty_out(vty, " exit\n");
+ vty_out(vty, " !\n");
+ vty_out(vty, " formats\n");
+ for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) {
+ if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) {
+ vty_out(vty, " format %s\n", format->name);
+ if (format->config.uncompressed.explicit_start !=
+ SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START)
+ vty_out(vty, " explicit start %u\n",
+ format->config.uncompressed
+ .explicit_start);
+ }
+ if (format->type == SRV6_SID_FORMAT_TYPE_USID) {
+ vty_out(vty, " format %s\n", format->name);
+ if (format->config.usid.lib_start !=
+ SRV6_SID_FORMAT_USID_F3216_LIB_START)
+ vty_out(vty,
+ " local-id-block start %u\n",
+ format->config.usid.lib_start);
+ if (format->config.usid.elib_start !=
+ SRV6_SID_FORMAT_USID_F3216_ELIB_START ||
+ format->config.usid.elib_end !=
+ SRV6_SID_FORMAT_USID_F3216_ELIB_END)
+ vty_out(vty,
+ " local-id-block explicit start %u end %u\n",
+ format->config.usid.elib_start,
+ format->config.usid.elib_end);
+ if (format->config.usid.wlib_start !=
+ SRV6_SID_FORMAT_USID_F3216_WLIB_START ||
+ format->config.usid.wlib_end !=
+ SRV6_SID_FORMAT_USID_F3216_WLIB_END)
+ vty_out(vty,
+ " wide-local-id-block start %u end %u\n",
+ format->config.usid.wlib_start,
+ format->config.usid.wlib_end);
+ if (format->config.usid.ewlib_start !=
+ SRV6_SID_FORMAT_USID_F3216_EWLIB_START)
+ vty_out(vty,
+ " wide-local-id-block explicit start %u\n",
+ format->config.usid.ewlib_start);
+ }
vty_out(vty, " exit\n");
vty_out(vty, " !\n");
}
@@ -538,11 +1063,17 @@ void zebra_srv6_vty_init(void)
install_node(&srv6_locs_node);
install_node(&srv6_loc_node);
install_node(&srv6_encap_node);
+ install_node(&srv6_sid_formats_node);
+ install_node(&srv6_sid_format_usid_f3216_node);
+ install_node(&srv6_sid_format_uncompressed_f4024_node);
install_default(SEGMENT_ROUTING_NODE);
install_default(SRV6_NODE);
install_default(SRV6_LOCS_NODE);
install_default(SRV6_LOC_NODE);
install_default(SRV6_ENCAP_NODE);
+ install_default(SRV6_SID_FORMATS_NODE);
+ install_default(SRV6_SID_FORMAT_USID_F3216_NODE);
+ install_default(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE);
/* Command for change node */
install_element(CONFIG_NODE, &segment_routing_cmd);
@@ -550,14 +1081,44 @@ void zebra_srv6_vty_init(void)
install_element(SEGMENT_ROUTING_NODE, &no_srv6_cmd);
install_element(SRV6_NODE, &srv6_locators_cmd);
install_element(SRV6_NODE, &srv6_encap_cmd);
+ install_element(SRV6_NODE, &srv6_sid_formats_cmd);
install_element(SRV6_LOCS_NODE, &srv6_locator_cmd);
install_element(SRV6_LOCS_NODE, &no_srv6_locator_cmd);
+ install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd);
+ install_element(SRV6_SID_FORMATS_NODE,
+ &srv6_sid_format_uncompressed_cmd);
+ install_element(SRV6_SID_FORMATS_NODE,
+ &no_srv6_sid_format_f3216_usid_cmd);
+ install_element(SRV6_SID_FORMATS_NODE,
+ &no_srv6_sid_format_f4024_uncompressed_cmd);
/* Command for configuration */
install_element(SRV6_LOC_NODE, &locator_prefix_cmd);
install_element(SRV6_LOC_NODE, &locator_behavior_cmd);
+ install_element(SRV6_LOC_NODE, &locator_sid_format_cmd);
+ install_element(SRV6_LOC_NODE, &no_locator_sid_format_cmd);
install_element(SRV6_ENCAP_NODE, &srv6_src_addr_cmd);
install_element(SRV6_ENCAP_NODE, &no_srv6_src_addr_cmd);
+ install_element(SRV6_SID_FORMAT_USID_F3216_NODE,
+ &srv6_sid_format_usid_lib_cmd);
+ install_element(SRV6_SID_FORMAT_USID_F3216_NODE,
+ &no_srv6_sid_format_usid_lib_cmd);
+ install_element(SRV6_SID_FORMAT_USID_F3216_NODE,
+ &srv6_sid_format_usid_lib_explicit_cmd);
+ install_element(SRV6_SID_FORMAT_USID_F3216_NODE,
+ &no_srv6_sid_format_usid_lib_explicit_cmd);
+ install_element(SRV6_SID_FORMAT_USID_F3216_NODE,
+ &srv6_sid_format_usid_wlib_cmd);
+ install_element(SRV6_SID_FORMAT_USID_F3216_NODE,
+ &no_srv6_sid_format_usid_wlib_cmd);
+ install_element(SRV6_SID_FORMAT_USID_F3216_NODE,
+ &srv6_sid_format_usid_wide_lib_explicit_cmd);
+ install_element(SRV6_SID_FORMAT_USID_F3216_NODE,
+ &no_srv6_sid_format_usid_wide_lib_explicit_cmd);
+ install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE,
+ &srv6_sid_format_explicit_cmd);
+ install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE,
+ &no_srv6_sid_format_explicit_cmd);
/* Command for operation */
install_element(VIEW_NODE, &show_srv6_locator_cmd);