Skip to content

bgpd: Retain the routes if we do a clear with N-bit set for Graceful-Restart - #18498

Merged
riw777 merged 2 commits into
FRRouting:masterfrom
opensourcerouting:fix/keep_stale_routes_on_clear
Mar 26, 2025
Merged

bgpd: Retain the routes if we do a clear with N-bit set for Graceful-Restart#18498
riw777 merged 2 commits into
FRRouting:masterfrom
opensourcerouting:fix/keep_stale_routes_on_clear

Conversation

@ton31337

Copy link
Copy Markdown
Member

Closes #18238

…Restart

On receiving side we already did the job correctly, but the peer which initiates
the clear does not retain the other's routes. This commit fixes that.

Fixes: 2017077 ("bgpd: Activate Graceful-Restart when receiving CEASE/HOLDTIME notifications")

Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
…r GR

Related-to: b7c657d ("bgpd: Retain the routes if we do a clear with N-bit set for Graceful-Restart")

Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
@frrbot frrbot Bot added bgp bugfix tests Topotests, make check, etc labels Mar 25, 2025
@ton31337

Copy link
Copy Markdown
Member Author

@Mergifyio backport stable/10.3 stable/10.2 stable/10.1 stable/10.0

@mergify

mergify Bot commented Mar 25, 2025

Copy link
Copy Markdown

backport stable/10.3 stable/10.2 stable/10.1 stable/10.0

βœ… Backports have been created

Details

@dawkopagh

Copy link
Copy Markdown
Contributor

This indeed fixes the issue #18238. Manual testing with this fix included proved to work as expected and routes are retained on both peers (the one we clear the session on, and the one that receives the Cease/Administrative Reset message. Thanks!

@ton31337
ton31337 requested a review from riw777 March 26, 2025 16:54

@riw777 riw777 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good -- thanks!

@riw777
riw777 merged commit 565da4d into FRRouting:master Mar 26, 2025
@ton31337
ton31337 deleted the fix/keep_stale_routes_on_clear branch March 26, 2025 20:17
riw777 added a commit that referenced this pull request Apr 1, 2025
bgpd: Retain the routes if we do a clear with N-bit set for Graceful-Restart (backport #18498)
selva-nexthop added a commit to selva-nexthop/frr-comm that referenced this pull request May 1, 2026
Problem:
When a BGP peer sends a Hard Reset (Cease/subcode 9, per RFC 8538), the
GR helper side must flush peer routes immediately rather than retaining
them as stale. Four code gaps allow the NSF_WAIT flag to be set (or the
hard_reset flag to be missed) after a Hard Reset, causing stale routes
to remain in the RIB:

1. bgp_packet.c (bgp_notify_receive): peer->notify.hard_reset is only
   set when the received Hard Reset has a non-empty encapsulated payload
   (outer.length > 0). A valid bare Hard Reset (Cease/subcode 9 with no
   inner notification) leaves peer->notify.hard_reset = false. This
   bypasses the existing !hard_reset guard for the TCP error handler and
   doppelganger handler paths below.

2. bgpd.c (bgp_process_conn_error / TCP error handler): When the TCP
   socket reports an error or close, the handler unconditionally sets
   NSF_WAIT if NSF_MODE is set. If the peer sent a Hard Reset and the
   TCP stack delivered the RST before the NOTIFICATION was read from the
   socket, peer->notify.hard_reset is already true but is ignored here,
   causing GR helper mode to be entered and routes kept stale.

3. bgp_network.c (bgp_accept / doppelganger handler): Same issue -- when
   an incoming TCP collision tears down the existing established session,
   NSF_WAIT is set without checking peer->notify.hard_reset. A peer that
   sends Hard Reset and immediately reconnects can trigger this path
   before the NOTIFICATION event is processed by the FSM.

4. bgp_fsm.c (bgp_establish): peer->notify.hard_reset is NOT cleared
   when a new BGP session is established. After a Hard Reset the peer
   reconnects and establishes a new session. If that new session later
   drops normally (TCP drop, no notification), the TCP error handler
   sees the stale hard_reset=true from the previous session and skips
   NSF_WAIT, permanently defeating GR for that neighbor until a restart.

Note: bgp_packet.c already has correct !hard_reset guards for the
NOTIFICATION send path (~line 1058) and receive path (~line 2704). The
bgp_packet.c fix here closes the gap that lets those guards be bypassed.

FRR upstream master and stable/10.4 have the same gaps as of April 2026.
The bgp_packet.c send/recv path fix corresponds to upstream PR FRRouting#18498
(merged to master 2026-03-26, not backported to stable/10.4).

Solution:
- bgp_packet.c: Set peer->notify.hard_reset = true whenever hard_reset
  is true, independently of whether outer.length > 0.
- bgpd.c: Add !peer->notify.hard_reset check in the TCP error handler
  before setting NSF_WAIT.
- bgp_network.c: Add !peer->notify.hard_reset check in the doppelganger
  handler before setting NSF_WAIT.
- bgp_fsm.c: Clear peer->notify.hard_reset in bgp_establish() alongside
  PEER_STATUS_NSF_WAIT to prevent the flag from leaking across sessions.

Topotest:
- TC3: Add test_bgp_hard_reset_gr() -- Hard Reset with delayopen=60
  (both sides). Exercises bgp_process_conn_error (bgpd.c fix). Verifies
  R1 does not retain stale routes after receiving a Hard Reset.
- TC4: Add test_bgp_hard_reset_gr_doppelganger() -- Hard Reset with
  delayopen=5 on R1 only, no delayopen on R2. R2 reconnects immediately
  after Hard Reset, maximising the probability that R2's new TCP SYN
  reaches R1's listen socket while R1 is still in Established state,
  triggering the bgp_accept() doppelganger handler (bgp_network.c fix).
  R1's delayopen=5 holds the new session in OpenWait for ~5 s providing
  a stable observation window. Verifies routes are flushed in either
  code path (TCP error handler or doppelganger).

Resolves: FRRouting#21822
Signed-off-by: selva <selva@nexthop.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Graceful Restart procedures do not apply when hard-administrative-reset flag is disabled

3 participants