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; // Where this router passes on routes from one router of our AS to // another (Peer.route_reflector_client), the cluster it does so for, as // a dotted-quad: what it puts on such routes, and what it does not take // back (RFC 4456). Give routers that serve the same clients the same // cluster ID. Defaults to router_id. string cluster_id = 15; // Limits on what goes to other networks that are not our customers: to // every peer whose role is PROVIDER, PEER or ROUTE_SERVER, and to one // in another AS that has no role. Not to customers, route server // clients or routers of our own AS. A peer's own `export_limits` takes // the place of these. // // They hold whatever the routes are and wherever they came from, and // whatever `export` says: a check on everything else, in case it goes // wrong. With the roles, a route learned from a provider or a peer is // passed on to customers only; these keep it from going further even // if a route is not marked as it should be. ExportLimits export_limits = 16; // Names for communities, for the status page to show in place of the // numbers: what the marks on routes mean to a reader. A name for one // community ("64601:100:2" is "comrack"), or for a kind of them, with // `*` for the part left open ("64601:102:*" is "interconnection"), which // is shown with the open part after the name. The daemon itself does // nothing with them. repeated CommunityName community_names = 17; } // A name for a community, or for a kind of them. message CommunityName { // The community, standard ("64601:100") or large ("64601:100:2"), or a // pattern of them with `*` for a part left open ("64601:102:*"). string community = 1; // What it is shown as. string name = 2; } // Limits on what is announced to a peer, which hold whatever `export` // and the routes say. message ExportLimits { // Only routes for these prefixes are announced: our own address space // and our customers', say, with max_length as long as the longest // prefix announced from it. Routes for other prefixes, learned or // originated, are not. Empty allows any. repeated PrefixRange prefixes = 1; // The most routes that are announced to the peer at a time. If more // were to be, none of them is: the session is ended with a Cease / // Administrative Shutdown NOTIFICATION that says why (RFC 9003), and the // peer is kept down for its import.hold_down_seconds, as when it sends // us too many. Set it somewhat above what is expected. Zero is no // limit. uint32 max_prefixes = 2; } // 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; // The kernel's table whose routes say how a next hop that is not a // neighbour is reached: its connected and static routes, and an IGP's // if there is one. Defaults to 254, the main table. A route whose next // hop is covered by such a route is installed with that route's gateway // and interface, the kernel not looking gateways up in turn. Routes put // in the table by BGP, this daemon's or another's, never count: a next // hop reached only by way of a BGP route rests on what may itself rest // on a next hop. uint32 resolution_table = 5; // Whether the default route in that table counts as the way to a next // hop. Off by default: on a router the default route points at a // transit provider, and a next hop "reached" only by sending the // packets to the Internet at large is not reached. bool resolve_via_default_route = 6; } // 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 (empty, to a peer in our own 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; // Pass on to this peer, a router of our own AS, the routes learned from // our other routers, and pass on the routes it sends to all of them: we // are its route reflector (RFC 4456). Without it, as BGP has it, a route // learned from one router of our AS goes to no other, and every router // needs a session with every other. Routes go with this router as next // hop, so that the peer can reach what lies behind another router // through this one. Only for a peer in our own AS: other networks are // told of learned routes by `export` and the roles alone. The peer's // `export` still has to pass on learned routes. bool route_reflector_client = 14; // Limits on what is announced to the peer, in the place of the // top-level export_limits. They apply to the same peers as those do: to // one whose role is PROVIDER, PEER or ROUTE_SERVER, or that is in // another AS and has no role. ExportLimits export_limits = 15; // Do not open connections to the peer: wait for it to connect. The // session is configured in full, and comes up when the peer connects // from `endpoint`'s address; the port of `endpoint` is not used. For a // new peer whose side is not ready yet, or one that is to open the // connections itself. bool passive = 16; // About how many routes the peer sends when all is well: a full table, // a few hundred from an exchange peer, one from a customer. Nothing is // decided by it. The status page compares the routes the peer has in // the table with it, and shows an established session with fewer than // half as needing attention: a peer that is up but has sent next to // nothing looks, without this, exactly like one that is fine. Zero, the // default, compares nothing. The routing table is also made with room // for the largest of these from the start, so that it need not grow, // and so use twice its memory for a moment, while the tables come in. uint32 expected_routes = 17; } // 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, // unless one of them is a route reflector client of ours // (Peer.route_reflector_client). // - 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; // Pass on every route learned from other peers, not only the best of // each prefix, each with a path identifier (ADD-PATH, RFC 7911). For a // route collector, which wants to see every path. Needs learned_routes, // and the peer's add_path to offer sending; for a family the peer did // not agree to receive several routes for, the best goes as usual. The // export policy and the limits apply to every route alike. bool all_paths = 6; // 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. Defaults 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; // What is done to some of the routes, beyond what is done to all of // them above. Each route that is taken is looked at by the rules in // turn, and the first that holds for it is applied; the rest are not // looked at. A rule sees the route as the statements above leave it: // with our communities taken off and ours put on. repeated ImportRule rules = 20; // By default a route with the BLACKHOLE community (65535:666, RFC // 7999), which asks for the traffic to its prefix to be dropped, is // refused ("blackhole request"). True takes such a route if it is for // one address (a /32 or /128), whatever the longest prefix taken // otherwise, and inside what the peer may announce; its next hop is // not looked at. The traffic to the address is then dropped by this // router (a blackhole route in the kernel), and the route goes on to // the peers the export policy sends it to, community and all, for them // to do the same. For a customer under attack, and for a route server // whose blackhole routes are to be honoured. bool accept_blackholes = 21; } // What is done to the routes with some communities, or for some prefixes: // those learned at one exchange, say, by the mark another router of ours // put on them, to be preferred less; or one prefix of a customer's, to be // marked for a prepend. message ImportRule { // The rule holds for routes with one of these communities: one // ("64601:100"), all of an AS ("64601:*"), or large ones with three // parts ("64601:101:*"). Left out, for routes with any. repeated string match_communities = 1; // And for routes for a prefix in these. Left out, for any prefix. repeated PrefixRange match_prefixes = 2; // The LOCAL_PREF of the routes, in place of import.local_pref. optional uint32 local_pref = 3; // Communities put on the routes. repeated string add_communities = 4; repeated string add_large_communities = 5; } // 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; // Offer to send the peer several routes for a prefix. As yet only the // best is sent all the same. 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; }