Commit db6e6da526 for frr

commit db6e6da526e810c8fc76a3fdcda8a0a7c0025a44
Author: Andreas Karis <ak.karis@gmail.com>
Date:   Thu Sep 17 00:31:58 2026 +0200

    zebra: skip writing empty SRv6 locator prefix in config output

    The config writer unconditionally outputs the prefix line for every
    locator in srv6->locators. When a prefix is removed via "no prefix",
    no_locator_prefix zeroes the prefix but leaves the locator in the
    list, causing the config to display:

      prefix ::/0 block-len 0 node-len 0 func-bits 0

    This was a pre-existing issue, but the previous commit (adding the
    locator to srv6->locators immediately on allocation) exacerbates it:
    locators now appear in the list before a prefix is ever configured,
    so the zeroed prefix is also output for newly created locators that
    have not yet had their prefix set.

    Fix by guarding the prefix output with a check against in6addr_any.

    Reported-at: https://github.com/FRRouting/frr/issues/23387
    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
    Signed-off-by: Andreas Karis <ak.karis@gmail.com>

diff --git a/lib/srv6.h b/lib/srv6.h
index d906d78e16..dedee8e394 100644
--- a/lib/srv6.h
+++ b/lib/srv6.h
@@ -166,6 +166,10 @@ struct srv6_locator {
 };
 DECLARE_QOBJ_TYPE(srv6_locator);

+#define SRV6_LOCATOR_PREFIX_IS_SET(loc)                                                           \
+	(!IPV6_ADDR_SAME(&(loc)->prefix.prefix, &in6addr_any) || (loc)->prefix.prefixlen ||       \
+	 (loc)->block_bits_length || (loc)->node_bits_length || (loc)->function_bits_length)
+
 struct srv6_locator_chunk {
 	char locator_name[SRV6_LOCNAME_SIZE];
 	struct prefix_ipv6 prefix;
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index da2af776f3..f9ad786b66 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -1652,22 +1652,22 @@ static int zebra_sr_config(struct vty *vty)
 		vty_out(vty, "  locators\n");
 		for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) {
 			vty_out(vty, "   locator %s\n", locator->name);
-			vty_out(vty, "    prefix %pFX", &locator->prefix);
-			if (locator->block_bits_length !=
-			    locator->prefix.prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH)
-				vty_out(vty, " block-len %u",
-					locator->block_bits_length);
-			if (locator->node_bits_length != ZEBRA_SRV6_LOCATOR_NODE_LENGTH)
-				vty_out(vty, " node-len %u",
-					locator->node_bits_length);
-
-			if (locator->function_bits_length != ZEBRA_SRV6_FUNCTION_LENGTH)
-				vty_out(vty, " func-bits %u", locator->function_bits_length);
-
-			if (locator->argument_bits_length)
-				vty_out(vty, " arg-len %u",
-					locator->argument_bits_length);
-			vty_out(vty, "\n");
+			if (SRV6_LOCATOR_PREFIX_IS_SET(locator)) {
+				vty_out(vty, "    prefix %pFX", &locator->prefix);
+				if (locator->block_bits_length !=
+				    locator->prefix.prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH)
+					vty_out(vty, " block-len %u", locator->block_bits_length);
+				if (locator->node_bits_length != ZEBRA_SRV6_LOCATOR_NODE_LENGTH)
+					vty_out(vty, " node-len %u", locator->node_bits_length);
+
+				if (locator->function_bits_length != ZEBRA_SRV6_FUNCTION_LENGTH)
+					vty_out(vty, " func-bits %u",
+						locator->function_bits_length);
+
+				if (locator->argument_bits_length)
+					vty_out(vty, " arg-len %u", locator->argument_bits_length);
+				vty_out(vty, "\n");
+			}
 			if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
 				vty_out(vty, "    behavior usid\n");
 			if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_PSP))