Commit 513acb8e91 for frr

commit 513acb8e91638bbd1fb5b431e3582f3e9c0d35b1
Author: Carmine Scarpitta <cscarpit@cisco.com>
Date:   Sat Nov 7 18:21:25 2026 +0100

    zebra: Release SRv6 SIDs when SID format changes

    An operator can change the SRv6 SID format or its allocation ranges.
    Zebra applies the new values, then calls
    `zebra_srv6_sid_format_changed_cb()`. The callback notifies clients
    that the locator is unavailable, removes its existing SIDs, and
    notifies clients that the locator is available again so they can
    allocate SIDs from the new range.

    This causes two problems:

    - Deleting the last SID entry does not release its function, leaving it
      marked as allocated.
    - The callback runs after the range changes. The explicit SID release
      routine checks the active range, so releasing an old function outside
      the new bounds fails and leaves it marked as allocated.

    Fix this by:

    - Releasing the SID function when its last entry is deleted.
    - Splitting `zebra_srv6_sid_format_changed_cb()` into
      `zebra_srv6_sid_format_change_start()` and
      `zebra_srv6_sid_format_change_finish()`. The start function notifies
      clients that the locator is unavailable and removes existing SIDs
      while the old range is configured. After the range changes, the finish
      function notifies clients that the locator is available so they can
      allocate SIDs from the new range.

    Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>

diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c
index 6b89c13721..4dfbb481f7 100644
--- a/zebra/zebra_srv6.c
+++ b/zebra/zebra_srv6.c
@@ -228,6 +228,7 @@ static void zebra_srv6_sid_entry_del_by_locator(struct zebra_srv6_sid *sid,
 		}

 	if (zebra_srv6_sid_entry_list_count(&sid->entries) == 0) {
+		release_srv6_sid_func(sid->ctx);
 		zebra_srv6_sid_ctx_list_del(&block->sids, sid->ctx);
 		zebra_srv6_sid_ctx_free(sid->ctx);

@@ -314,23 +315,24 @@ void zebra_srv6_locator_format_set(struct srv6_locator *locator,
 }

 /*
- * Called when a SID format is modified by the user.
+ * Called before 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.
+ * The SIDs that are using that format may no longer be valid after the
+ * change. Delete them while the old ranges are still configured so their
+ * allocations can be released correctly.
  * 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.
+ * can withdraw/uninstall the old SIDs.
  */
-void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format)
+void zebra_srv6_sid_format_change_start(struct srv6_sid_format *format)
 {
 	struct zebra_srv6 *srv6 = zebra_srv6_get_default();
 	struct srv6_locator *locator;
 	struct listnode *node;

 	if (IS_ZEBRA_DEBUG_SRV6)
-		zlog_debug("%s: SID format %s has changed. Notifying zclients.",
-			   __func__, format->name);
+		zlog_debug("%s: SID format %s is changing. Notifying zclients.", __func__,
+			   format->name);

 	for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
 		if (locator->sid_format == format) {
@@ -343,11 +345,41 @@ void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format)
 			zebra_notify_srv6_locator_delete(locator);

 			zebra_srv6_sid_entry_del_by_locator_all_sids(locator);
+		}
+	}
+}

-			/* Notify zclients about the updated locator */
-			zebra_notify_srv6_locator_add(locator);
+/*
+ * Called after a SID format is modified.
+ *
+ * Notify clients that locators using this format are available again so they
+ * can allocate SIDs using the updated format.
+ */
+void zebra_srv6_sid_format_change_finish(struct srv6_sid_format *format)
+{
+	struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+	struct zebra_srv6_sid_block *block;
+	struct srv6_locator *locator;
+	struct listnode *node;
+
+	/* Reset the allocator before clients can request SIDs from the new range. */
+	for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, block)) {
+		if (block->sid_format != format)
+			continue;
+
+		if (format->type == SRV6_SID_FORMAT_TYPE_USID) {
+			block->u.usid.lib.first_available_func = format->config.usid.lib_start;
+			list_delete_all_node(block->u.usid.lib.func_released);
+		} else {
+			block->u.uncompressed.first_available_func =
+				SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN;
+			list_delete_all_node(block->u.uncompressed.func_released);
 		}
 	}
+
+	for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator))
+		if (locator->sid_format == format)
+			zebra_notify_srv6_locator_add(locator);
 }

 /*
diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h
index a1731404c8..4a7d108fa8 100644
--- a/zebra/zebra_srv6.h
+++ b/zebra/zebra_srv6.h
@@ -312,7 +312,8 @@ 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);
+void zebra_srv6_sid_format_change_start(struct srv6_sid_format *format);
+void zebra_srv6_sid_format_change_finish(struct srv6_sid_format *format);

 uint32_t *zebra_srv6_sid_func_alloc(uint32_t func);
 void zebra_srv6_sid_func_free(uint32_t *func);
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index b7cb5d22c4..020bc7f3b3 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -1271,6 +1271,8 @@ DEFUN(no_srv6_sid_format_f3216_usid,
 	format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME);
 	assert(format);

+	zebra_srv6_sid_format_change_start(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;
@@ -1279,7 +1281,7 @@ DEFUN(no_srv6_sid_format_f3216_usid,
 	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);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1311,6 +1313,8 @@ DEFUN(no_srv6_sid_format_f4816_usid,
 	format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F4816_NAME);
 	assert(format);

+	zebra_srv6_sid_format_change_start(format);
+
 	format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F4816_LIB_START;
 	format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F4816_ELIB_START;
 	format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F4816_ELIB_END;
@@ -1319,7 +1323,7 @@ DEFUN(no_srv6_sid_format_f4816_usid,
 	format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F4816_EWLIB_START;

 	/* Notify zclients that the format has changed */
-	zebra_srv6_sid_format_changed_cb(format);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1351,11 +1355,13 @@ DEFUN(no_srv6_sid_format_f4024_uncompressed,
 	format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME);
 	assert(format);

+	zebra_srv6_sid_format_change_start(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);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1369,10 +1375,11 @@ DEFPY(srv6_sid_format_usid_lib,
 {
 	VTY_DECLVAR_CONTEXT(srv6_sid_format, format);

+	zebra_srv6_sid_format_change_start(format);
 	format->config.usid.lib_start = start;

 	/* Notify zclients that the format has changed */
-	zebra_srv6_sid_format_changed_cb(format);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1387,6 +1394,7 @@ DEFPY(no_srv6_sid_format_usid_lib,
 {
 	VTY_DECLVAR_CONTEXT(srv6_sid_format, format);

+	zebra_srv6_sid_format_change_start(format);
 	if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME))
 		format->config.usid.lib_start =
 			SRV6_SID_FORMAT_USID_F3216_LIB_START;
@@ -1396,7 +1404,7 @@ DEFPY(no_srv6_sid_format_usid_lib,
 		assert(0);

 	/* Notify zclients that the format has changed */
-	zebra_srv6_sid_format_changed_cb(format);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1421,11 +1429,12 @@ DEFPY(srv6_sid_format_usid_lib_explicit,
 		return CMD_WARNING_CONFIG_FAILED;
 	}

+	zebra_srv6_sid_format_change_start(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);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1443,6 +1452,7 @@ DEFPY(no_srv6_sid_format_usid_lib_explicit,
 {
 	VTY_DECLVAR_CONTEXT(srv6_sid_format, format);

+	zebra_srv6_sid_format_change_start(format);
 	if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) {
 		format->config.usid.elib_start =
 			SRV6_SID_FORMAT_USID_F3216_ELIB_START;
@@ -1456,7 +1466,7 @@ DEFPY(no_srv6_sid_format_usid_lib_explicit,
 	}

 	/* Notify zclients that the format has changed */
-	zebra_srv6_sid_format_changed_cb(format);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1488,11 +1498,12 @@ DEFPY(srv6_sid_format_usid_wlib,
 		return CMD_WARNING_CONFIG_FAILED;
 	}

+	zebra_srv6_sid_format_change_start(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);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1527,11 +1538,12 @@ DEFPY(no_srv6_sid_format_usid_wlib,
 		return CMD_WARNING_CONFIG_FAILED;
 	}

+	zebra_srv6_sid_format_change_start(format);
 	format->config.usid.wlib_start = wlib_start;
 	format->config.usid.wlib_end = wlib_end;

 	/* Notify zclients that the format has changed */
-	zebra_srv6_sid_format_changed_cb(format);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1554,10 +1566,11 @@ DEFPY(srv6_sid_format_usid_wide_lib_explicit,
 		return CMD_WARNING_CONFIG_FAILED;
 	}

+	zebra_srv6_sid_format_change_start(format);
 	format->config.usid.ewlib_start = start;

 	/* Notify zclients that the format has changed */
-	zebra_srv6_sid_format_changed_cb(format);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1588,10 +1601,11 @@ DEFPY(no_srv6_sid_format_usid_wide_lib_explicit,
 		return CMD_WARNING_CONFIG_FAILED;
 	}

+	zebra_srv6_sid_format_change_start(format);
 	format->config.usid.ewlib_start = ewlib_start;

 	/* Notify zclients that the format has changed */
-	zebra_srv6_sid_format_changed_cb(format);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1605,10 +1619,11 @@ DEFPY(srv6_sid_format_explicit,
 {
 	VTY_DECLVAR_CONTEXT(srv6_sid_format, format);

+	zebra_srv6_sid_format_change_start(format);
 	format->config.uncompressed.explicit_start = start;

 	/* Notify zclients that the format has changed */
-	zebra_srv6_sid_format_changed_cb(format);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }
@@ -1623,6 +1638,7 @@ DEFPY(no_srv6_sid_format_explicit,
 {
 	VTY_DECLVAR_CONTEXT(srv6_sid_format, format);

+	zebra_srv6_sid_format_change_start(format);
 	if (strmatch(format->name, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME))
 		format->config.uncompressed.explicit_start =
 			SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START;
@@ -1630,7 +1646,7 @@ DEFPY(no_srv6_sid_format_explicit,
 		assert(0);

 	/* Notify zclients that the format has changed */
-	zebra_srv6_sid_format_changed_cb(format);
+	zebra_srv6_sid_format_change_finish(format);

 	return CMD_SUCCESS;
 }