Status: Accepted Date: 2026-03-05
Standard Graceful Restart (RFC 4724, ADR-0024) preserves a restarting peer's routes for a bounded window (typically 120s). If the peer takes longer to recover — common in VM migrations, container rescheduling, or software upgrades with long init times — its routes are purged and traffic is disrupted.
RFC 9494 (Long-Lived Graceful Restart) extends GR with a second stale-timer phase. Instead of purging routes when the GR timer expires, LLGR-negotiated families are promoted to "LLGR-stale" and preserved for a much longer window (up to ~194 days). This is the standard mechanism used by large-scale deployments (Google, major IXPs) to handle extended peer outages gracefully.
GoBGP supports LLGR. Adding it closes a meaningful parity gap.
- Code 71 (
LLGR):Vec<LlgrFamily>where each family carriesafi,safi,forwarding_preserved(1 bit), andstale_time(24-bit seconds, max 16,777,215 ≈ 194 days). - Advertised when
llgr_stale_time > 0in neighbor config.
GR timer expires → check LLGR negotiation:
- LLGR negotiated for family: promote routes to LLGR-stale, start LLGR
timer with
effective_stale_time = min(local llgr_stale_time, peer's per-family minimum). - LLGR not negotiated for family: purge stale routes (existing GR behavior).
LLGR timer expires → purge all remaining LLGR-stale routes.
Three-tier stale ranking at step 0 (before LOCAL_PREF), via stale_rank():
- Fresh routes: rank 0 (preferred)
- GR-stale routes: rank 1
- LLGR-stale routes: rank 2 (least preferred)
This ensures LLGR-stale routes are used only as a last resort when no fresh or GR-stale alternative exists.
LLGR_STALE(0xFFFF0006): Added to routes when promoted from GR-stale to LLGR-stale. Locally-injected instances are tracked and removed when stale flags are cleared (EoR or peer recovery). Peer-originatedLLGR_STALEcommunities are preserved.NO_LLGR(0xFFFF0007): Routes carrying this community are purged at the GR-to-LLGR transition (they explicitly opt out of long-lived preservation).
llgr_peers: HashMap<IpAddr, HashSet<(Afi, Safi)>>— peers in LLGR phasellgr_stale_deadlines: HashMap<IpAddr, tokio::time::Instant>— LLGR timer deadlinesllgr_peer_config: HashMap<IpAddr, LlgrPeerConfig>— stored at PeerUp, consumed at GR timer expiry
Third timer arm in run() select! loop for LLGR deadline polling.
If a peer reconnects while in the LLGR phase, its families move back to
gr_peers (awaiting EoR), and the LLGR timer is cancelled. EoR clears
is_llgr_stale and removes locally-injected LLGR_STALE communities.
[[neighbors]]
address = "10.0.0.2"
remote_asn = 65002
llgr_stale_time = 3600 # 0 = disabled (default), max 16777215No new global config. LLGR is strictly per-neighbor.
- Routes survive extended peer outages (VM migration, slow restarts)
- Matches GoBGP LLGR support
- Three-tier ranking ensures LLGR-stale routes are least preferred
NO_LLGRcommunity provides explicit opt-out per route
- Additional timer complexity in RibManager (third deadline set)
LLGR_STALEcommunity provenance tracking adds per-route state- Very long stale times could mask genuine peer failures
- LLGR capability is only advertised when configured (no impact on peers that don't negotiate it)
- Builds on existing GR infrastructure (ADR-0024) with minimal new code paths