A configured peer could announce any prefix with any path, in any number, and all of it was stored and could be chosen as best. Each peer now has an import policy, and every route goes through it before it reaches the routing table. Checks that hold for any peer unless turned off for it: - no prefixes that are not routed on the Internet (private, loopback, link-local, documentation, multicast, reserved; for IPv6, anything outside global unicast); - nothing longer than /24 or /48, no default route, nothing shorter than /8 or /16; - no reserved, private or documentation AS number in the path; - a path that begins with the peer's own AS (turned off for a route server), and of at most 64 AS numbers. Always: a route with our own AS number in its path is refused. RFC 4271 requires this loop check and it was missing. Per peer, if configured: the prefixes it may announce, each with an optional longest more-specific, and the AS numbers its routes may originate from. This is the list generated from the routing registries. max_prefixes limits how many routes a peer may have. One more ends the session with Cease / Maximum Number of Prefixes Reached, and the peer is kept down for hold_down_seconds (ten minutes unless set): its connections are not taken and it is not dialled. Refused routes do not count towards the limit. A refused route is withdrawn rather than ignored, so that it replaces whatever the peer had announced for it before. On a session with two-octet AS numbers the path is judged with its AS4_PATH merged in, so that the real AS numbers are what is checked. Peers that are not configured (accept_unconfigured_peers, for test networks) get a policy that takes everything but loops. Refusals are counted in bgp_routes_rejected_total by reason. The status page and /api/peers show, for each session, how many routes the peer has and how many were refused. The server warns at startup about peers with no limit. The prefix check costs about 4 ns a route with the default policy; the end-to-end benchmark is unchanged. Also: the benchmark's server AS is one that is in none of its generated paths, and a table test that depended on the hasher's seed is fixed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
193 lines
7.0 KiB
Protocol Buffer
193 lines
7.0 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;
|
|
|
|
// Routes this router originates and announces to every peer.
|
|
repeated OriginatedRoute originate = 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;
|
|
|
|
// Connections are accepted only from the addresses of configured peers;
|
|
// from anywhere else they are closed before a byte is read. When true,
|
|
// any host that can reach a listening endpoint may open a session, as
|
|
// any AS it cares to name, and have its routes taken. That is for
|
|
// testing on a closed network and nothing else.
|
|
bool accept_unconfigured_peers = 9;
|
|
}
|
|
|
|
// A route originated by this router. It is announced with an AS_PATH of the
|
|
// local AS and, on each session, that session's local address as next hop.
|
|
message OriginatedRoute {
|
|
// The prefix in CIDR notation, e.g. "192.0.2.0/24" or "2001:db8::/32".
|
|
string prefix = 1;
|
|
|
|
// ORIGIN attribute: "IGP" (the default), "EGP" or "INCOMPLETE".
|
|
string origin = 2;
|
|
|
|
// Extra copies of the local AS to prepend to the AS_PATH. At most 16.
|
|
uint32 as_path_prepend = 3;
|
|
|
|
// MULTI_EXIT_DISC. Left out of the announcement when unset.
|
|
optional uint32 med = 4;
|
|
|
|
// Standard communities (RFC 1997): "ASN:VALUE", or a well-known name such
|
|
// as "NO_EXPORT".
|
|
repeated string communities = 5;
|
|
|
|
// Large communities (RFC 8092): "GLOBAL:LOCAL1:LOCAL2".
|
|
repeated string large_communities = 6;
|
|
}
|
|
|
|
// 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;
|
|
|
|
// Source IP address for connections we open to this peer. It is also the
|
|
// next hop of the routes we send it. Required when the peer identifies us
|
|
// by address and the host has several, e.g. when both speakers run on the
|
|
// same machine. Must be the same address family as the endpoint. Unset
|
|
// lets the operating system choose.
|
|
string local_address = 5;
|
|
|
|
// The address families to exchange with this peer. Each is offered to the
|
|
// peer in our OPEN, and is in use on the session only if the peer offers
|
|
// it too (RFC 4760). Defaults to all of them when empty. A session with
|
|
// no family in common is refused.
|
|
repeated AddressFamily address_families = 6;
|
|
|
|
// ADD-PATH (RFC 7911): whether to take several routes for one prefix
|
|
// from this peer, to send it several, or both. It is in use, for each
|
|
// direction and address family, only if the peer agrees. Defaults to
|
|
// off: one route for each prefix, as in plain BGP.
|
|
AddPath add_path = 7;
|
|
|
|
// Which of the peer's routes are taken. Left out, the general checks
|
|
// apply and there is no limit and no list.
|
|
ImportPolicy import = 8;
|
|
}
|
|
|
|
// What is taken from a peer. Every route is judged before it goes into
|
|
// the routing table. One that is refused is dropped, and so is the route
|
|
// it would have replaced.
|
|
//
|
|
// A route whose AS path holds our own AS number is always refused.
|
|
message ImportPolicy {
|
|
// The most routes the peer may have at a time. One more ends the session
|
|
// with Cease / Maximum Number of Prefixes Reached, and the peer is kept
|
|
// down for hold_down_seconds. Set it somewhat above what the peer is
|
|
// expected to send. Zero is no limit.
|
|
uint32 max_prefixes = 1;
|
|
|
|
// How long the peer is kept down after going over max_prefixes. Neither
|
|
// side's connections are taken meanwhile. Defaults to 600.
|
|
uint32 hold_down_seconds = 2;
|
|
|
|
// By default, prefixes that are not routed on the Internet are refused
|
|
// (private, loopback, link-local, documentation, multicast and reserved
|
|
// space), and so are routes with a reserved, private or documentation AS
|
|
// number anywhere in their path. True takes them.
|
|
bool accept_bogons = 3;
|
|
|
|
// By default a default route (0.0.0.0/0 or ::/0) is refused. True takes
|
|
// one, as from an upstream that is asked to send it.
|
|
bool accept_default_route = 4;
|
|
|
|
// The longest prefixes taken. Default to 24 and 48, the longest that are
|
|
// routed between networks.
|
|
uint32 max_ipv4_prefix_length = 5;
|
|
uint32 max_ipv6_prefix_length = 6;
|
|
|
|
// By default the AS path of a route has to begin with the peer's own AS
|
|
// number. True takes any, as is needed for an Internet exchange's route
|
|
// server, which does not put its AS on the path.
|
|
bool accept_any_first_as = 7;
|
|
|
|
// The longest AS path taken, counted in AS numbers. Defaults to 64.
|
|
uint32 max_as_path_length = 8;
|
|
|
|
// The prefixes the peer may announce. Empty allows any. This is the
|
|
// list generated for a peer from the routing registries (with bgpq4,
|
|
// say).
|
|
repeated PrefixRange prefixes = 9;
|
|
|
|
// The AS numbers the peer's routes may originate from: the last AS of
|
|
// the path. Empty allows any.
|
|
repeated uint32 origin_asns = 10;
|
|
}
|
|
|
|
// A prefix, and optionally the more specific prefixes inside it.
|
|
message PrefixRange {
|
|
// In CIDR notation, e.g. "193.0.0.0/21".
|
|
string prefix = 1;
|
|
// The longest prefix inside it that is also allowed. Left out, only the
|
|
// prefix itself is.
|
|
uint32 max_length = 2;
|
|
}
|
|
|
|
// The directions ADD-PATH can be offered for.
|
|
enum AddPath {
|
|
ADD_PATH_OFF = 0;
|
|
// Accept several routes for a prefix from the peer.
|
|
ADD_PATH_RECEIVE = 1;
|
|
// Send the peer several routes for a prefix.
|
|
ADD_PATH_SEND = 2;
|
|
ADD_PATH_BOTH = 3;
|
|
}
|
|
|
|
// An address family routes can be exchanged for.
|
|
enum AddressFamily {
|
|
ADDRESS_FAMILY_UNSPECIFIED = 0;
|
|
IPV4_UNICAST = 1;
|
|
IPV6_UNICAST = 2;
|
|
}
|