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);