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; // Route origin validation (RFC 6811) and AS path verification with the // RPKI. Left out, routes are not validated. Rpki rpki = 10; // Put the best route of every prefix in the kernel's routing table, so // that the machine forwards packets by them. Left out, the daemon only // speaks BGP and the machine's forwarding is not touched. Kernel kernel = 11; // What is announced, and how, to every peer that has no `export` of its // own. ExportPolicy export = 12; // Let routes say, with communities, which peers they are passed on to // and how far away we look to them, as the route servers of Internet // exchanges and transit networks do. With L our own AS number, P a // peer's, and G a group of sessions (`groups` of a peer): // // 0:P or L:0:P not to the peer with AS P // L:P or L:1:P to the peer with AS P, and then only to peers // named so // 0:L or L:0:0 to nobody // L:11:P with our AS once more on the path to the peer // L:12:P with AS P; twice, three times. P 0 is every // L:13:P peer in another AS. // L:20:G not to the sessions of group G // L:21:G to the sessions of group G, and then only to // sessions named so, by group or AS // L:31:G with our AS once more on the path to the // L:32:G sessions of group G; twice, three times // L:33:G // // A route with none of these goes to everyone it otherwise would. "Not" // wins over "to". Of several prepends that apply, the most counts, on // top of the session's export.as_path_prepend. The two-part form is a // standard community, with room for AS numbers below 65536; the // three-part forms are large communities and work for any. // // They are acted on where a route leaves our AS, and taken off there: // to a peer in our own AS a route goes with them, for that router to act // on. They are honoured on routes we originate too (`communities` and // `large_communities` of `originate`), on what import.add_communities // puts on, and on what a peer in our own AS, or one with // import.accept_control_communities, sends. From any other peer the // communities of our own AS are taken off as its routes come in, so that // nobody outside can say what is done with our routes. // // With this on, standard communities L:n are taken for "to the peer // with AS n": mark routes with something else (large communities // L:100:n and up, say; functions 2 to 9 are left for marks too). bool control_communities = 13; // Graceful restart, for every peer that has no `graceful_restart` of its // own. Left out, it is on, as the defaults below have it. GracefulRestart graceful_restart = 14; } // Graceful restart (RFC 4724): BGP restarting without the routes going. // // When the daemon is restarted in good order for an upgrade (on SIGUSR1), // it leaves its routes in the kernel, and its peers keep the routes it // announced to them, for as long as they were told a restart takes. When a // peer restarts, its routes are kept and used as before, marked stale, // until it has sent them again; those it does not send again are removed. // Either way, nothing is withdrawn across the network for a restart. // // It is in use with a peer that offers it too. A session that ends with a // Hard Reset (RFC 8538), or because of an error, has its routes removed at // once, as without graceful restart. message GracefulRestart { // True does not offer graceful restart: a peer's routes are removed as // soon as its session ends, and it removes ours as soon as it sees ours // end. optional bool disabled = 1; // How long, in seconds, peers are told a restart of this daemon takes: // how long they keep our routes after our session with them ends. At // most 4095. Defaults to 120. optional uint32 restart_time_seconds = 2; // The longest time, in seconds, a restarting peer's routes are kept // stale: while it is gone, whatever restart time it gave, and again once // it is back, until it has sent all its routes. Zero keeps none. // Defaults to 120. optional uint32 stale_routes_seconds = 3; } // Installing routes in the kernel. Linux only; the daemon needs the // CAP_NET_ADMIN capability. // // The best route of a prefix is installed if its next hop is a neighbor: // an address in the network of one of the machine's interfaces. Routes // are marked as BGP's ("proto bgp"), and every route with that mark, the // table and the metric below is taken to be this daemon's: what it finds // at startup and no longer wants, it removes. When the daemon stops in // good order it removes its routes. message Kernel { // The routing table. Defaults to 254, the main table, which is the one // packets are forwarded by unless rules say otherwise. uint32 table = 1; // The metric of the routes. Defaults to 20. Of several routes for a // prefix the kernel uses the one with the lowest metric. optional uint32 metric = 2; // By default, where the kernel has nexthop objects (Linux 5.3 and // later), a gateway is put there once as such an object and routes name // it, which makes installing a full table about a third faster. `ip // route` then shows routes with "nhid". True has every route carry its // own gateway, as on older kernels. bool without_nexthop_objects = 3; // How long, after the daemon starts, routes of its own that an earlier // run left in the kernel are kept though no peer has announced them // (again). Defaults to 120. The daemon's table is empty until its peers // have sent theirs; removing the old routes at once would stop the // machine forwarding for as long as that takes. After this time, what // was not announced again is removed. // Zero removes them at once. optional uint32 stale_seconds = 4; } // Where to get the validated ROA payloads that say which AS may originate // which prefixes. With this set, a route whose origin is not authorised // for its prefix ("invalid") is refused, from every peer that is not in // our own AS and does not have accept_rpki_invalid set. Routes that // nothing is known about are taken as before. // // A validator that speaks version 2 of the protocol also gives the ASPAs, // in which networks say who their providers are. With those, a route // whose AS path cannot have come about by networks passing routes on as // they should (a route leak, or a made-up path) is refused, from every // peer that has a role set and does not have accept_aspa_invalid set. message Rpki { // The RPKI-to-Router servers (RFC 8210, draft-ietf-sidrops-8210bis) of // one or more validators, such as Routinator, rpki-client with StayRTR, // or FORT, in order of preference. The port is required. One is used at // a time, over plain TCP: keep it on a network you trust. repeated TcpEndpoint caches = 1; // How often to ask the cache for changes unprompted, how long to wait // before trying again after a failure, and how long the data may be used // without a cache confirming it, after which nothing is invalid any // more. Each defaults to what the cache says, or to 3600, 600 and 7200. uint32 refresh_seconds = 2; uint32 retry_seconds = 3; uint32 expire_seconds = 4; } // 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). A peer at a link-local IPv6 address has the // interface it is on after it: "fe80::1%eth0". 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). // At least 3, or 0 for a session without keepalives that is never timed // out. Defaults to 90 when unset. optional 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 the peer is to us. Not for a peer in our own AS. With it set: // // - Our OPEN says what we are to the peer, and a peer that says it is // something else than configured here is refused (RFC 9234). One side // having the other down as a customer and the other as a peer is how // leaks come about. // - Routes are marked "only to customer" as they come in from a provider, // a peer or a route server, and as they go out to a customer, a peer // or a route server client. A route with that mark that comes back up // from a customer, or across from a second peer, is a leak and is // refused. This cannot be turned off. // - Where rpki is configured, the AS paths of the peer's routes are // verified against the ASPAs: a route from a customer, a peer or a // route server must have come up through providers all the way; one // from a provider may have come up and then down. // // Left out, none of this is done for the peer. Role role = 9; // Refuse the peer unless its OPEN says what it is. By default a peer // that says nothing (one that does not implement RFC 9234) is taken at // this configuration's word for it. Needs role. bool require_role = 10; // What is announced to the peer, and how. Left out, the top-level // `export` holds, and without that the routes we originate are // announced as they are. ExportPolicy export = 11; // Graceful restart with this peer. What is set here takes the place of // what the top-level `graceful_restart` says. GracefulRestart graceful_restart = 12; // The groups the session is in, by number, for control communities to // name sessions by (see control_communities): those at one Internet // exchange, say, or those over one link, whatever AS the peers are. Use // the same numbers on all routers of the AS: a route marked on one is // acted on by another. From 1. repeated uint32 groups = 13; } // What is announced to a peer. // // The routes we originate are always announced. Routes learned from other // peers are passed on only if learned_routes says so, and then only as // far as these let them: // // - Never back to the peer a route came from, nor to a peer whose AS is // on its path already. // - A route from a peer in our own AS is not passed to another such peer // (there is no route reflection). // - Where peers have roles (RFC 9234): a route learned from a provider, a // peer or a route server goes on to customers only. So with roles on // all peers, turning this on makes us transit for our customers and for // nobody else. Without roles there is no such rule, and every route // goes to every peer: do not turn this on for a peer without a role // unless that is what is wanted. // - The communities NO_EXPORT and NO_ADVERTISE, and control_communities. // // A route is passed on with our AS added to its path and ourselves as // next hop, without the MED it came with. To a peer in our own AS the // path is left as it is and LOCAL_PREF goes along. To a peer whose role // is ROUTE_SERVER_CLIENT the route goes as a route server sends it // (RFC 7947): path, MED and, where the client can use it, next hop // unchanged. message ExportPolicy { // Pass on the best routes learned from other peers. bool learned_routes = 1; // Communities put on every route announced to the peer: which router // it went through, say. "64601:100", or a well-known name. repeated string add_communities = 2; // Large communities put on, as "64601:1:2". repeated string add_large_communities = 3; // Communities taken off first: one ("64601:100"), all of an AS // ("64601:*"), or large ones with three parts ("64601:1:*"). repeated string remove_communities = 4; // How many more times our AS is put on the path of every route // announced to the peer, to make them look further away. At most 16. uint32 as_path_prepend = 5; } // What a peer is to us. enum Role { ROLE_UNSPECIFIED = 0; // We buy transit from the peer. PROVIDER = 1; // The peer buys transit from us. CUSTOMER = 2; // The peer and we exchange our own and our customers' routes. PEER = 3; // The peer is an Internet exchange's route server. ROUTE_SERVER = 4; // We are a route server and the peer is one of our clients. ROUTE_SERVER_CLIENT = 5; } // 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; // By default, where route origin validation is configured (rpki), a // route that is invalid is refused. True takes it all the same. bool accept_rpki_invalid = 11; // By default, where the validator gives ASPAs and the peer has a role, // a route whose AS path they find invalid is refused. True takes it all // the same. bool accept_aspa_invalid = 12; // By default a route whose AS path has an AS_SET in it is refused: sets // are deprecated (RFC 9774), and with one nobody can say where a route // comes from. True takes such routes. bool accept_as_sets = 13; // By default the next hop of a route from another network has to be the // peer itself, so that a peer can only draw traffic to itself and not // send it to a third party. True takes any next hop packets can be sent // to. Not needed for a peer whose role is ROUTE_SERVER, whose routes // have its clients as next hops. bool accept_third_party_next_hop = 14; // Communities put on every route taken from the peer: where it was // learned, say, for other routers of ours and for `export` to go by. // "64601:100", or a well-known name. repeated string add_communities = 15; // Large communities put on, as "64601:1:2". repeated string add_large_communities = 16; // Communities taken off first: one ("64601:100"), all of an AS // ("64601:*"), or large ones with three parts ("64601:1:*"). Marks that // mean something to us are not to be taken on a peer's word. repeated string remove_communities = 17; // The LOCAL_PREF of the peer's routes: of two routes for a prefix the // one with the higher is chosen, whatever else they have. Left out, 100. optional uint32 local_pref = 18; // By default the communities of our own AS (L:n and L:n:m; and 0:n, // with control_communities on) are taken off the routes of a peer in // another AS as they come in, before add_communities puts ours on: what // they ask of us is not for others to ask. True keeps them, for a // customer that is to steer its own routes with control communities, or // a route server's client. Not for a peer in our own AS, whose routes // keep them in any case. bool accept_control_communities = 19; } // 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; }