Commit 464b7a9ca4 for frr

commit 464b7a9ca4fef47e57a2504c80b4645e82c36464
Author: Carmine Scarpitta <cscarpit@cisco.com>
Date:   Mon Oct 19 11:13:38 2026 +0200

    staticd: Release uDT SIDs when VRFs go down

    Create a Linux VRF and bring it up:

      ip link add Vrf30 type vrf table 30
      ip link set dev Vrf30 up

    Configure a uDT46 SID for Vrf30:

      configure terminal
       segment-routing
        srv6
         static-sids
          sid fcbb:bbbb:1:fe30::/64 locator MAIN behavior uDT46 vrf Vrf30

    staticd allocates the SID for Vrf30. The `show segment-routing srv6 sid`
    command shows the SID with `VRF 'Vrf30'` as its context:

      r1# show segment-routing srv6 sid
       SID                 Behavior    Context          Daemon/Instance    Locator    AllocationType
       ------------------------------  ---------------  -----------------  ---------  ---------------
       fcbb:bbbb:1:fe30::  End.DT46    VRF 'Vrf30'      static(0)          MAIN       explicit

    Delete the VRF:

      ip link del Vrf30

    The SID is not deallocated. It remains allocated against the old Vrf30, which
    no longer exists. The command still lists the SID, but its context is now
    `VRF '<unknown>'`:

      r1# show segment-routing srv6 sid
       SID                 Behavior    Context            Daemon/Instance    Locator    AllocationType
       ------------------------------  -----------------  -----------------  ---------  ---------------
       fcbb:bbbb:1:fe30::  End.DT46    VRF '<unknown>'    static(0)          MAIN       explicit

    Fix this by releasing the SID when staticd receives the Vrf30 down event.
    When the VRF is recreated, existing staticd logic requests and installs the
    SID again for the new VRF.

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

diff --git a/staticd/static_srv6.c b/staticd/static_srv6.c
index 377802d1ec..f70d680e60 100644
--- a/staticd/static_srv6.c
+++ b/staticd/static_srv6.c
@@ -39,6 +39,19 @@ DECLARE_HASH(static_srv6_neigh_table, struct static_srv6_if_neigh, item,
 /* Global neighbor cache instance */
 struct static_srv6_neigh_cache *neigh_cache;

+static bool is_udt_sid(const struct static_srv6_sid *sid)
+{
+	if (sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT6 ||
+	    sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID ||
+	    sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT4 ||
+	    sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID ||
+	    sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT46 ||
+	    sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID)
+		return true;
+	else
+		return false;
+}
+
 /*
  * Determines if the specified SID needs to be installed or removed
  * due to a state change (up/down) on the provided interface.
@@ -50,14 +63,6 @@ struct static_srv6_neigh_cache *neigh_cache;
  */
 static bool is_sid_update_required(struct interface *ifp, struct static_srv6_sid *sid)
 {
-	/* Check if the SID's behavior is one of the uDT* variants. */
-	bool is_udt = (sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT6 ||
-		       sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID ||
-		       sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT4 ||
-		       sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID ||
-		       sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT46 ||
-		       sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID);
-
 	/* Check if the SID's behavior is one of the uDT4/uDT46 variants. */
 	bool is_udt4_or_udt46 = (sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT4 ||
 				 sid->behavior == SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID ||
@@ -92,7 +97,7 @@ static bool is_sid_update_required(struct interface *ifp, struct static_srv6_sid
 			return true;
 	}

-	if (is_udt) {
+	if (is_udt_sid(sid)) {
 		/*
 		 * 3a. SID is uDT*. uDT* SIDs are associated with a VRF interface defined in their attributes.
 		 *     Therefore, an update is needed if the provided interface 'ifp' matches the SID's associated VRF.
@@ -166,6 +171,12 @@ void static_ifp_srv6_sids_update(struct interface *ifp, bool is_up)
 			if (needs_install)
 				static_zebra_srv6_sid_install(sid);
 		} else {
+			if (is_udt_sid(sid) && strmatch(sid->attributes.vrf_name, ifp->name) &&
+			    CHECK_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID)) {
+				static_zebra_release_srv6_sid(sid);
+				UNSET_FLAG(sid->flags, STATIC_FLAG_SRV6_SID_VALID);
+			}
+
 			static_zebra_srv6_sid_uninstall(sid);
 		}
 	}