Graceful restart (RFC 4724, RFC 8538)

A peer that restarts keeps its routes with us, and we keep ours with our
peers while we restart, so that a restart withdraws nothing across the
network and the machine goes on forwarding. On by default for every
peer; `graceful_restart` sets the restart time we give, caps how long a
peer's routes are kept, or turns it off.

When a peer restarts: its routes are marked stale in the routing table,
and chosen as before, for at most its restart time. When it is back, what
it sends again is fresh, and the stale routes of a family go at its
End-of-RIB marker, or after the cap; at once for a family whose
forwarding it did not keep. Only a connection that failed counts as a
restart, and, with RFC 8538 agreed, an expired hold timer or a
NOTIFICATION other than a Hard Reset. The stale mark is a bit of the
route's word that selection never looks at.

When we restart: SIGUSR1 leaves the kernel's routes where they are,
closes the sessions without a word where graceful restart is agreed, and
exits with status 75, on which the systemd unit starts us again. The next
start finds the routes in the kernel, says so in its OPENs (R, and F where
forwarding was kept), and has them go once every peer has sent its
End-of-RIB. Our own End-of-RIB markers for learned routes wait for that
too. SIGTERM still stops for good, now with a Hard Reset where RFC 8538 is
agreed, as are errors of ours.

The status page and API show what was agreed with each peer, the routes
kept while a peer restarts, and which routes are stale. Tested against
FRR and BIRD in a new phase of the interoperability lab, and with routes
kept in a real kernel over a restart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Rayhaan JaufeerallyandClaude Opus 5.5 committed 2026-10-04 22:43:47 +02:00
1 parent acecc22f48
commit 65f136048e
45 files changed
+2696 -116

No files matched your search

+3
View File
@@ -22,6 +22,7 @@ use bgp_rib::LocalRib;
use bgp_rib::table::RibTable;
use bgp_rpki::Rpki;
use bgp_server::refusals::RefusalLog;
use bgp_server::restart::Restarts;
use bgp_server::session::SessionRegistry;
use tokio::net::TcpListener;
use tracing::info;
@@ -93,6 +94,8 @@ pub struct AppState {
pub rpki: Option<Rpki>,
/// What keeps the best routes in the kernel, where that is configured.
pub kernel: Option<Fib>,
/// Graceful restart: the routes kept of restarting peers.
pub restarts: Arc<Restarts>,
}
/// The status page, embedded so the binary is self-contained.