Files
ferrix/crates/server/proto/config.proto
T
Rayhaan JaufeerallyandClaude Fable 5.1 48da8cc7d2 rib: size the routing table for the routes the peers are expected to send
The routing table's shards started empty and grew as routes came in,
each growth moving every row of the shard into a table twice the size.
In a profile of the daemon taking in a full table, the growth showed as
up to a seventh of the session's time, and the daemon's resident memory
had the old and the new table of each shard side by side for a moment.

This change adds `RibTable::expect_prefixes`, which reserves room for
that many prefixes spread over the shards, and has the server call it at
startup with the largest `expected_routes` among the configured peers:
the prefixes of several full tables are mostly the same ones. Without
`expected_routes` nothing changes. The `full_table` benchmark does the
same unless `BENCH_PRESIZE=0`.

Measured, the saving in time is within the run-to-run noise: in the
Linux VM one peer's table is in the routing table in 0.81 s instead of
0.89 s, and the kernel is in step at about the same time as before;
three pairs of runs of the benchmark on a Mac average 0.33 s against
0.35 s. The profile's attribution to the growth was mostly sampling skid.
The memory saving is real: 442 MiB resident with one peer's table in
instead of 483 MiB, and 626 MiB instead of 632 MiB with four.

Also: the profiling script printed nothing for the kernel's change
counts because it asked `/metrics` for them; the endpoint is `/metricz`.
With that fixed, a four-peer load shows 1.25 million installs for 1.23
million prefixes: the journal already gives the kernel task only the
latest change of a prefix when it lags, so no further coalescing of
installs is called for.

Documentation: `expected_routes` in the configuration reference, the
neighbor guide and the proto comment say that the table is sized by it;
the testing guide's VM results are brought up to date.

Testing: a table test checks that the room is there and is kept; the
workspace tests pass.

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

638 lines
28 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;
// 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;
// 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;
}