Commit f67f686fcc for frr

commit f67f686fcc7905da893352ea680052550692a408
Author: Philippe Guibert <philippe.guibert@6wind.com>
Date:   Thu Oct 22 15:49:11 2026 +0200

    bgpd: fix SRv6 unicast SIDs after a zebra restart

    When zebra restarts while bgpd keeps running, zebra loses the SRv6
    unicast SIDs allocated by bgp ('sid export' in the address-families of
    the default instance), and their local SIDs. BGP keeps advertising its
    unicast prefixes with these SIDs, while zebra is stopped and after it is
    started again, although these SIDs are no longer allocated in zebra nor
    installed. Before zebra is stopped on r1:

    > r1# show segment-routing srv6 sid
    >  SID                Behavior    Context          Daemon/Instance    Locator    AllocationType
    >  -----------------------------  ---------------  -----------------  ---------  ----------------
    >  2001:db8:1:1:a1::  End.DT4     VRF 'default'    bgp(0)             default    explicit
    >  2001:db8:1:1:37::  End.DT6     VRF 'default'    bgp(0)             default    explicit

    Twenty seconds after zebra is stopped on r1, r3, a peer of r1 configured
    with 'encapsulation-srv6', still uses these SIDs:

    > r3# show ip fib
    > [..]
    > B>* 10.0.0.1/32 [20/0] via 10.125.3.1, r3-eth0, seg6 2001:db8:1:1:a1::, weight 1, 00:00:26
    > r3# show ipv6 fib
    > [..]
    > B>* fd00:200::/64 [20/0] via fe80::c408:6ff:fe4f:2d86, r3-eth0, seg6 2001:db8:1:1:37::, weight 1, 00:00:26

    Nothing stops advertising the SIDs when the connection to zebra is
    lost. And when the locator is received again,
    bgp_srv6_unicast_ensure_afi_sid() does not request a SID, because the
    address-family still has its SID, and the local SID is not installed
    again, because it is the SID last sent to zebra.

    Fix this by stopping the advertisement of the unicast prefixes with
    their SID, as when the SID is removed from the configuration, and by
    forgetting the SRv6 unicast SIDs without releasing them, when the
    connection to zebra is lost. The prefixes are withdrawn from the peers
    configured with 'encapsulation-srv6', and advertised without SID to the
    peers configured with 'encapsulation-srv6-relax'. The SIDs are requested
    again when the locator is received, the prefixes are advertised again
    with them once they are allocated, and their local SIDs are installed.
    With this fix, two seconds after zebra is stopped on r1, r3 no longer has
    10.0.0.1/32 nor fd00:200::/64, and r2, a peer of r1 configured with
    'encapsulation-srv6-relax', has them without SID. Once zebra is started
    again on r1:

    > r1# show segment-routing srv6 sid
    >  SID                Behavior    Context          Daemon/Instance    Locator    AllocationType
    >  -----------------------------  ---------------  -----------------  ---------  ----------------
    >  2001:db8:1:1:a1::  End.DT4     VRF 'default'    bgp(0)             default    explicit
    >  2001:db8:1:1:37::  End.DT6     VRF 'default'    bgp(0)             default    explicit

    Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>

diff --git a/bgpd/bgp_srv6.c b/bgpd/bgp_srv6.c
index c1a9d53d9e..02008f434c 100644
--- a/bgpd/bgp_srv6.c
+++ b/bgpd/bgp_srv6.c
@@ -227,6 +227,28 @@ void bgp_srv6_unicast_sid_withdraw(struct bgp *bgp, afi_t afi)
 	bgp_zebra_release_srv6_sid(&ctx, bgp->srv6_unicast[afi].sid_locator->name);
 }

+/*
+ * A stopped zebra has lost the SRv6 unicast SIDs and their local SIDs: stop
+ * advertising the unicast prefixes with them, and forget them without
+ * releasing them, so that they are requested again once the locator is
+ * received.
+ */
+void bgp_srv6_unicast_sids_forget(struct bgp *bgp)
+{
+	afi_t afi;
+
+	for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+		if (bgp->srv6_unicast[afi].sid) {
+			bgp_srv6_unicast_withdraw(bgp, afi);
+			sid_unregister(bgp, bgp->srv6_unicast[afi].sid);
+			XFREE(MTYPE_BGP_SRV6_SID, bgp->srv6_unicast[afi].sid);
+		}
+		XFREE(MTYPE_BGP_SRV6_SID, bgp->srv6_unicast[afi].zebra_sid_last_sent);
+		srv6_locator_free(bgp->srv6_unicast[afi].sid_locator);
+		bgp->srv6_unicast[afi].sid_locator = NULL;
+	}
+}
+
 void bgp_srv6_unicast_delete(struct bgp *bgp, afi_t afi)
 {
 	struct interface *ifp;
diff --git a/bgpd/bgp_srv6.h b/bgpd/bgp_srv6.h
index 71917272aa..3446c99488 100644
--- a/bgpd/bgp_srv6.h
+++ b/bgpd/bgp_srv6.h
@@ -52,6 +52,7 @@ void bgp_srv6_unicast_sid_withdraw(struct bgp *bgp, afi_t afi);
 void bgp_srv6_unicast_sid_withdraw_dt46(struct bgp *bgp, afi_t afi);
 void bgp_srv6_unicast_sid_update(struct bgp *bgp, afi_t afi);
 void bgp_srv6_unicast_delete(struct bgp *bgp, afi_t afi);
+void bgp_srv6_unicast_sids_forget(struct bgp *bgp);
 void bgp_srv6_unicast_sid_endpoint(struct bgp *bgp, afi_t afi,
 				   struct interface *ifp, bool install);
 void bgp_srv6_unicast_unregister_route(struct bgp_dest *dest);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index cc3a27c21b..fc76ffe601 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -3402,6 +3402,8 @@ static void bgp_zebra_disconnected(struct zclient *zclient)
 	for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
 		/* zebra has lost the SIDs of BGP */
 		vpn_leak_zebra_vrf_sids_forget(bgp);
+		if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+			bgp_srv6_unicast_sids_forget(bgp);

 		/* the locators may have changed when zebra is started again */
 		srv6_locator_free(bgp->srv6_locator);