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`.
*/
if (locator->sid_format->type ==
SRV6_SID_FORMAT_TYPE_USID)
vty_out(vty, "Behavior: uSID\n");
- } else {
+ } else {
vty_out(vty, "Block-Bit-Len: %u\n",
locator->block_bits_length);
vty_out(vty, "Node-Bit-Len: %u\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,
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;
}
"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;
}
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;
}
}
- zebra_srv6_locator_add(locator);
+ zebra_srv6_locator_format_set(locator, locator->sid_format);
+
return CMD_SUCCESS;
}
/* 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)
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;
}
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;
}
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;
}
format->config.usid.lib_start = start;
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
return CMD_SUCCESS;
}
else
assert(0);
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
return CMD_SUCCESS;
}
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;
}
assert(0);
}
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
return CMD_SUCCESS;
}
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;
}
assert(0);
}
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
return CMD_SUCCESS;
}
format->config.usid.ewlib_start = start;
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
return CMD_SUCCESS;
}
else
assert(0);
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
return CMD_SUCCESS;
}
format->config.uncompressed.explicit_start = start;
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
return CMD_SUCCESS;
}
else
assert(0);
+ /* Notify zclients that the format has changed */
+ zebra_srv6_sid_format_changed_cb(format);
+
return CMD_SUCCESS;
}
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");
}
/* 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,