Commit e294dccd01 for frr
commit e294dccd017cf65b55fbbdd3607b871e4263e92a
Author: Donatas Abraitis <donatas@opensourcerouting.org>
Date: Tue Oct 27 14:50:35 2026 +0200
bgpd: Move t_llgr_stale event to struct peer_af
Since t_announce_route is already handled by peer_af as well, let's be consistent
and keep the same pattern here too.
The same is happening to t_refresh_stalepath (GR).
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index faf3578124..128b9133c5 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -366,6 +366,7 @@ void bgp_timer_set(struct peer_connection *connection)
{
afi_t afi;
safi_t safi;
+ struct peer_af *paf;
struct peer *peer = connection->peer;
switch (connection->status) {
@@ -494,8 +495,11 @@ void bgp_timer_set(struct peer_connection *connection)
event_cancel(&connection->t_gr_restart);
event_cancel(&connection->t_gr_stale);
- FOREACH_AFI_SAFI (afi, safi)
- event_cancel(&peer->t_llgr_stale[afi][safi]);
+ FOREACH_AFI_SAFI (afi, safi) {
+ paf = peer_af_find(peer, afi, safi);
+ if (paf)
+ event_cancel(&paf->t_llgr_stale);
+ }
event_cancel(&connection->t_pmax_restart);
event_cancel(&peer->t_refresh_stalepath);
@@ -858,9 +862,8 @@ static void bgp_graceful_restart_timer_expire(struct event *event)
bgp_set_llgr_stale(peer, afi, safi);
bgp_clear_stale_route(peer, afi, safi);
- event_add_timer(bm->master, bgp_llgr_stale_timer_expire,
- paf, peer->llgr[afi][safi].stale_time,
- &peer->t_llgr_stale[afi][safi]);
+ event_add_timer(bm->master, bgp_llgr_stale_timer_expire, paf,
+ peer->llgr[afi][safi].stale_time, &paf->t_llgr_stale);
for (ALL_LIST_ELEMENTS(peer->bgp->peer, node, nnode,
tmp_peer))
@@ -877,6 +880,7 @@ static void bgp_graceful_stale_timer_expire(struct event *event)
{
struct peer_connection *connection = EVENT_ARG(event);
struct peer *peer = connection->peer;
+ struct peer_af *paf;
afi_t afi;
safi_t safi;
@@ -888,7 +892,7 @@ static void bgp_graceful_stale_timer_expire(struct event *event)
* RFC 9494 §4.3: for LLGR-negotiated AFI/SAFI, retention is bounded
* by the Long-Lived Stale Time, not stalepath-time. Skip the delete
* if LLGR retention is (or will be) active for this AFI/SAFI:
- * - t_llgr_stale[afi][safi] scheduled: the LLGR window is already
+ * - paf->t_llgr_stale scheduled: the LLGR window is already
* running; t_gr_restart has fired but didn't cancel t_gr_stale
* (bgp_graceful_restart_timer_off() bails when any AFI/SAFI is
* in PEER_STATUS_LLGR_WAIT).
@@ -904,7 +908,8 @@ static void bgp_graceful_stale_timer_expire(struct event *event)
if (!peer->nsf[afi][safi])
continue;
- if (event_is_scheduled(peer->t_llgr_stale[afi][safi]) ||
+ paf = peer_af_find(peer, afi, safi);
+ if ((paf && event_is_scheduled(paf->t_llgr_stale)) ||
(peer->llgr[afi][safi].stale_time &&
event_is_scheduled(connection->t_gr_restart))) {
if (bgp_debug_neighbor_events(peer))
@@ -3010,6 +3015,7 @@ bgp_establish(struct peer_connection *connection)
{
afi_t afi;
safi_t safi;
+ struct peer_af *paf;
enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS;
struct peer *other;
struct peer *peer = connection->peer;
@@ -3093,8 +3099,9 @@ bgp_establish(struct peer_connection *connection)
* Stop Long-lived Graceful Restart timers.
*/
FOREACH_AFI_SAFI (afi, safi) {
- if (event_is_scheduled(peer->t_llgr_stale[afi][safi])) {
- event_cancel(&peer->t_llgr_stale[afi][safi]);
+ paf = peer_af_find(peer, afi, safi);
+ if (paf && event_is_scheduled(paf->t_llgr_stale)) {
+ event_cancel(&paf->t_llgr_stale);
if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP Long-lived stale timer stopped for afi/safi: %d/%d for %s",
peer, afi, safi,
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 42710fc94d..3bd3b5da3f 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -13781,6 +13781,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
int first = 0;
struct listnode *node, *nnode;
struct peer *peer;
+ struct peer_af *paf;
bool addpath_capable;
int has_adj;
unsigned int first_as;
@@ -14919,12 +14920,10 @@ skip_nexthop:
gr_remaining);
}
- if (event_is_scheduled(path->peer->t_llgr_stale[afi][safi]) &&
- bgp_attr_get_community(attr) &&
- community_include(bgp_attr_get_community(attr),
- COMMUNITY_LLGR_STALE)) {
- unsigned long llgr_remaining = event_timer_remain_second(
- path->peer->t_llgr_stale[afi][safi]);
+ paf = peer_af_find(path->peer, afi, safi);
+ if (paf && event_is_scheduled(paf->t_llgr_stale) && bgp_attr_get_community(attr) &&
+ community_include(bgp_attr_get_community(attr), COMMUNITY_LLGR_STALE)) {
+ unsigned long llgr_remaining = event_timer_remain_second(paf->t_llgr_stale);
if (json_paths) {
json_object_int_add(json_path, "llgrSecondsRemaining",
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index e5d6403a15..fe22cef974 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1088,7 +1088,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
bgp_soft_reconfig_table_task_cancel(bgp, bgp->rib[afi][safi], peer);
bgp_stop_announce_route_timer(af);
- event_cancel(&peer->t_llgr_stale[afi][safi]);
+ event_cancel(&af->t_llgr_stale);
if (PAF_SUBGRP(af)) {
if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
@@ -3121,13 +3121,16 @@ void peer_nsf_stop(struct peer *peer)
{
afi_t afi;
safi_t safi;
+ struct peer_af *paf;
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
FOREACH_AFI_SAFI_NSF (afi, safi) {
peer->nsf[afi][safi] = 0;
- event_cancel(&peer->t_llgr_stale[afi][safi]);
+ paf = peer_af_find(peer, afi, safi);
+ if (paf)
+ event_cancel(&paf->t_llgr_stale);
}
if (event_is_scheduled(peer->connection->t_gr_restart)) {
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 77ede3806e..207f341312 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1392,6 +1392,9 @@ struct peer_af {
*/
struct event *t_announce_route;
+ /* Long-lived Graceful Restart "Long-lived Stale Time" timer */
+ struct event *t_llgr_stale;
+
afi_t afi;
safi_t safi;
int afid;
@@ -2058,7 +2061,6 @@ struct peer {
_Atomic uint32_t v_gr_restart;
/* Threads. */
- struct event *t_llgr_stale[AFI_MAX][SAFI_MAX];
struct event *t_refresh_stalepath;
/* Thread flags. */
diff --git a/tests/topotests/bgp_llgr_stale_timer_af_delete/test_bgp_llgr_stale_timer_af_delete.py b/tests/topotests/bgp_llgr_stale_timer_af_delete/test_bgp_llgr_stale_timer_af_delete.py
index 4d3846dd35..088a8314ad 100644
--- a/tests/topotests/bgp_llgr_stale_timer_af_delete/test_bgp_llgr_stale_timer_af_delete.py
+++ b/tests/topotests/bgp_llgr_stale_timer_af_delete/test_bgp_llgr_stale_timer_af_delete.py
@@ -4,9 +4,9 @@
"""
Regression test for stale BGP LLGR timers after peer AF deletion.
-The test arms peer->t_llgr_stale[afi][safi], deletes the peer AF that was used
-as the timer callback argument, and verifies that bgpd survives beyond the
-original timer deadline.
+The test arms paf->t_llgr_stale, deletes the peer AF that owns the timer (and
+is used as the timer callback argument), and verifies that bgpd survives beyond
+the original timer deadline.
"""
import functools
@@ -94,7 +94,7 @@ def test_bgp_llgr_stale_timer_cancelled_on_peer_af_delete():
Deleting a peer AF must cancel any LLGR stale timer using that peer_af.
Broken behavior:
- - GR helper mode arms peer->t_llgr_stale[afi][safi] with struct peer_af.
+ - GR helper mode arms paf->t_llgr_stale with struct peer_af as argument.
- `no neighbor ... activate` deletes and frees that peer_af.
- The stale timer later fires and dereferences the freed callback argument.
"""