Files
ferrix/bin/bgp
Rayhaan JaufeerallyandClaude Fable 5.1 af76ecb345 fix: leave sessions politely on shutdown; answer ROUTE-REFRESH
Against a production BIRD router, restarting ferrix was followed by
several refused connection attempts before the session came back.

- The daemon had no signal handling: Ctrl-C killed the process and the
  peer only ever saw a dead TCP connection. On SIGINT or SIGTERM it now
  sends Cease / Administrative Shutdown (RFC 4486) to every established
  peer, waits up to two seconds for the sessions to close, and stops the
  dialers from reconnecting meanwhile. A NOTIFICATION queued for a session
  ends that session once sent.
- ROUTE-REFRESH was parsed and ignored. A peer sends it when its import
  policy changes (e.g. after `birdc configure`), expecting our routes
  again so the new policy can be applied. The session now reports the
  request and the advertiser re-sends every local route to that peer. The
  request also appears in the event stream and the status page log.

Tests: a refresh request in real wire format re-sends all routes and keeps
the session up; shutdown delivers the Cease to every peer and closes the
sessions. Verified with the real binary: SIGINT, peer logs the Cease.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 17:51:04 +02:00
..

BGP

This crate provides the bgp binary which runs the Border Gateway Protocol daemon together with its HTTP API.

cargo run -- path/to/config.textpb

The configuration format is defined in crates/server/proto/config.proto; testdata/server.textpb is a worked example. When http_endpoint is set the binary also serves:

Path Purpose
GET /statusz Status page: peers, announce form, local and received routes, live event log
GET /api/status Router ID, ASN, uptime and table sizes
GET /api/peers Established sessions
GET /api/routes/local Locally originated routes
POST /api/routes/local Announce a route (JSON body, see below)
DELETE /api/routes/local Withdraw a route (JSON body: prefix, optional owner)
GET /api/routes/local/wire?prefix=… The exact UPDATE bytes sent to each peer
GET /api/routes/received Adj-RIB-In contents
GET /api/communities/well-known Names accepted in place of numeric communities
GET /api/events Server-sent events for session and route changes
GET /metricz Prometheus metrics

Announce body:

{
  "prefix": "10.100.1.0/24",
  "owner": "alice",
  "origin": "IGP",
  "prepend": 2,
  "med": 100,
  "communities": ["65000:100", "NO_EXPORT"],
  "large_communities": ["65000:1:2"]
}

Only prefix and owner are required. Routes are subject to the local_route_policy in the configuration.

Trying it without a router

fake_peer is a minimal BGP speaker that connects to the daemon, announces a prefix, prints every UPDATE it receives and, with --echo, re-announces each received prefix back with its own ASN prepended (dropping NO_EXPORT routes). That makes locally announced prefixes show up in the received table as if they had travelled through a neighbouring AS:

cargo run -- testdata/server.textpb
cargo run -p bgp-integration-tests --example fake_peer -- \
    --server 127.0.0.1:179 --asn 65001 --announce 203.0.113.0/24 --echo

Please refer to the other implementation crates in this repository where most of the actual implementation lives.

Warning: This is still very much a work in progress and is not yet ready for production use.