Files
ferrix/crates/server/proto/config.proto
T
Rayhaan JaufeerallyandClaude Fable 5.1 87f96f9389 feature: RFC 4271 §6.8 connection collision detection
When both ends dial each other, exactly one TCP connection must survive
and both ends must pick the same one. Previously ferrix relied on the
other router to sort this out and could briefly hold two sessions.

- collision: a shared map keyed by the peer's BGP Identifier holds the one
  connection currently preferred for that peer plus a kill signal. Each
  connection calls admit() on receiving the peer's OPEN. The connection
  initiated by the higher BGP Identifier wins; the loser gets Cease /
  Connection Collision Resolution, whether it is the new connection or an
  existing one in OpenConfirm running in another task.
- A collision with an Established session closes the new connection (RFC
  default). The optional CollisionDetectEstablishedState is available as
  collision_detect_established_state: a restarted peer's new connection
  then replaces the stale session at once instead of being refused until
  the hold timer expires. Enabled in the lab config.
- Two connections opened by the same side: the newer wins.
- OPEN validation rejects a peer using our own BGP Identifier or 0.0.0.0
  with Bad BGP Identifier; collision resolution needs distinct identifiers.
- OpenConfirm no longer times out instantly when the negotiated hold time
  is zero.
- Sessions record which side opened them; shown as "opened by" on the
  status page and as `direction` in /api/peers. New counter
  bgp_connection_collisions_total{closed}.
- Tests: unit tests for the rule (including that both ends agree), and
  integration tests for simultaneous open in both identifier orders and
  both arrival orders, Established default, restart replacement with route
  flush, distinct identifiers, slot release, and Bad BGP Identifier.
  Existing fan-out test now gives its two peers distinct identifiers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 15:05:13 +02:00

76 lines
2.5 KiB
Protocol Buffer

syntax = "proto3";
package bgp.server;
// Top level BGP Server configuration.
message BgpConfig {
// The router ID, written as a dotted-quad IPv4 address (e.g. "192.0.2.1").
// Required even on IPv6-only routers per RFC 4271.
string router_id = 1;
// The local 4-byte AS number (RFC 6793).
uint32 local_asn = 2;
// Endpoints to accept incoming BGP connections on.
// Defaults to 0.0.0.0:179 and [::]:179 when empty.
repeated TcpEndpoint listen_endpoints = 3;
// Peers configured on this server.
repeated Peer peers = 4;
// Limits on routes originated locally (e.g. via the demo UI).
LocalRoutePolicy local_route_policy = 5;
// Where to serve the HTTP API, status page and metrics. The port is
// required. Unset disables the HTTP server.
TcpEndpoint http_endpoint = 6;
// Initial delay between attempts to connect to a configured peer, in
// seconds. Doubles after each failure up to two minutes. Defaults to 5.
uint32 connect_retry_seconds = 7;
// Connection collisions (RFC 4271 §6.8) against a session that is already
// Established are, by default, resolved by closing the new connection.
// When true they are resolved like any other collision: the connection
// initiated by the higher BGP Identifier survives, and a second connection
// opened by the same side replaces the first. This lets a peer that
// restarted take over from a session we have not yet noticed is dead,
// instead of being refused until the hold timer expires.
bool collision_detect_established_state = 8;
}
// Limits on locally originated routes.
message LocalRoutePolicy {
// A locally originated route is accepted only if it is covered by one of
// these prefixes, written in CIDR notation (e.g. "10.100.0.0/16").
// Empty means any prefix may be announced.
repeated string allowed_prefixes = 1;
// Maximum number of routes a single owner may announce. 0 means unlimited.
uint32 max_routes_per_owner = 2;
}
// An IP address and port pair.
message TcpEndpoint {
// IP address (V4 or V6).
string address = 1;
// TCP port. Defaults to 179 for BGP when unset.
uint32 port = 2;
}
// Configuration of a BGP peer.
message Peer {
// Human-readable name for logging and diagnostics.
string name = 1;
// Address and port to connect to for this peer.
TcpEndpoint endpoint = 2;
// The peer's 4-byte AS number (RFC 6793).
uint32 remote_asn = 3;
// Hold time to advertise in the OPEN message, in seconds (RFC 4271 §4.2).
// Must be 0 or >= 3. Defaults to 90 when unset.
uint32 hold_time_seconds = 4;
}