Files
ferrix/docs/content/docs/guides/passing-routes-on.md
T
Rayhaan JaufeerallyandClaude Fable 5.1 ec5c9be454 export: advertise every route for a prefix with ADD-PATH (all_paths)
Before this change, a session on which ADD-PATH (RFC 7911) was
negotiated in the sending direction was sent path identifiers, but only
the best route for each prefix. A route collector such as bgp.tools
wants every route a router has accepted, from every neighbor, and from
one session: without this the collector saw one path per prefix, nearly
always the same neighbor's.

This change adds `all_paths` to the export policy. On a session with it,
and ADD-PATH send negotiated for a family, every accepted route for a
prefix of that family is advertised, each with a path identifier of its
own; for a family without ADD-PATH send the best route goes as before.
`all_paths` needs `learned_routes` (a configuration error otherwise) and
the peer's `add_path` to offer sending. The export policy, the role
rules, the well-known communities and the export limits apply to every
route alike, and the export limits count every route.

Implementation, in the advertiser:

* An exporter with `all_paths` follows the table's journal of all routes
  (`RibTable::reader_of_all_routes`, until now unused) instead of the
  best-route journal, and is given all the routes of a prefix whenever
  one of them changes (`News::Routes`).
* What the peer holds is `Announced`: the set of prefixes for a
  best-route session, as before; or for an all-paths session, for each
  prefix the routes announced, keyed by the peer they came from and that
  peer's own identifier, with the identifier they went out with and the
  form they went out in. A route keeps its identifier for as long as it
  is announced, goes out again only if it changed, and is withdrawn by
  its identifier; a new route gets the lowest identifier not in use for
  the prefix, from 1.
* Verdicts carry either kind (`Verdict::Best`, `Verdict::All`), and a
  reset of the table puts what was announced in doubt until heard of
  again, as before, with the same identifiers kept across the reset.
* The record for an all-paths session is about 50 bytes a route, some
  tens of megabytes for a full table from several neighbors; the
  best-route bookkeeping is unchanged in size.

Also, so that a collector session can be watched: the number of routes
advertised to each peer and not withdrawn since, every route counted
where several are sent for a prefix. The exporter keeps it in the
session's counters after every change; it is `advertised_routes` in
`/api/peers`, the "sent" column of the status page's neighbor table,
and the gauge `bgp_peer_advertised_routes{peer}`.

Documentation: a "Feeding a Route Collector" section in the guide to
passing routes on, with the configuration for a collector; `all_paths`
in the configuration reference; the ADD-PATH sections of the neighbor
guide and the standards reference; the limitation that was removed;
the new field, column and metric in the HTTP API, monitoring and
metrics references.

Testing: an integration test with two feeders and a collector that
negotiated ADD-PATH receive, which checks the two routes with their
identifiers, the withdrawal of one by its identifier, a changed route
keeping its identifier and a new route taking the free one; a
configuration test for `all_paths` without `learned_routes`; a new
`collector` phase of the interoperability lab in which FRR, as a route
collector, is told both of BIRD's routes for a prefix from BIRD's two
sessions and holds them apart, and loses one when its session is
disabled, with the advertised count checked at each step. The workspace tests, the kernel tests and every lab phase pass.

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

18 KiB

+++ title = "Route Advertisement" description = "Describes how Ferrix advertises originated and learned routes, how BGP roles and communities restrict advertisement, and how to configure export policy." weight = 6 +++

Ferrix advertises two kinds of routes to its neighbors:

  • Originated routes, configured with the originate statement. Ferrix advertises them to every neighbor.
  • Learned routes, received from other neighbors. Ferrix advertises the best path for each prefix to the neighbors whose export policy enables learned_routes.

Configuring Originated Routes

The following example originates one IPv4 and one IPv6 prefix:

originate { prefix: "198.51.100.0/24" }
originate {
  prefix: "2001:db8:100::/48"
  med: 50
  as_path_prepend: 1
  large_communities: "64500:2:0"
}

Ferrix advertises an originated route with an AS path that contains the local AS number and, on each session, the local address of the session as the next hop. For the optional attributes, see OriginatedRoute.

Advertising Learned Routes

To advertise learned routes to a neighbor, enable learned_routes in its export policy:

export { learned_routes: true }

The top-level export statement applies to every neighbor that does not have its own export statement. A neighbor's export statement replaces the top-level statement entirely.

Ferrix does not advertise a learned route in the following cases. These rules cannot be disabled:

  • To the neighbor from which the route was received.
  • To a neighbor whose AS number is in the AS path of the route.
  • From one IBGP neighbor to another IBGP neighbor, unless one of them is a route reflector client. See Route Reflection.
  • To an EBGP neighbor, if the route has the NO_EXPORT community; to any neighbor, if the route has the NO_ADVERTISE community.

Attributes of Advertised Routes

Table 1 lists how Ferrix modifies the attributes of a learned route for each type of neighbor.

Neighbor type AS path Next hop MED Local preference
EBGP Local AS prepended Local address of the session Removed Not sent
IBGP Unchanged Local address of the session Unchanged Sent; 100 if the route has none
IBGP, reflected Unchanged Local address of the session Unchanged Sent unchanged
ROUTE_SERVER_CLIENT (RFC 7947) Unchanged Unchanged, if the client can use it Unchanged Not sent

Ferrix advertises unknown optional transitive attributes with the Partial bit set, and does not advertise unknown non-transitive attributes.

Roles and Route Advertisement

Ferrix adds the Only to Customer (OTC) attribute to routes received from providers, peers, and route servers (RFC 9234), and advertises routes with the OTC attribute only to customers. Routes received from customers are advertised to all neighbors. Therefore, when every neighbor has a role, the local router provides transit only to its customers.

export { learned_routes: true }
peers { name: "customer-a" role: CUSTOMER ... }
peers { name: "transit-a"  role: PROVIDER ... }
peers { name: "ixp-a-rs"   role: ROUTE_SERVER ... }

If any export statement enables learned_routes, every EBGP neighbor must have a role. Ferrix does not start with a configuration in which an EBGP neighbor has no role, because the routes received from that neighbor would be advertised to all other neighbors, and all learned routes would be advertised to it. For the same reason, accept_unconfigured_peers is not permitted with a top-level export statement that enables learned_routes.

A route collector, which receives routes and advertises none, is configured with the role CUSTOMER.

Export Limits

Export limits restrict the routes that Ferrix advertises to providers, peers, and route servers, regardless of the export policy, the BGP roles, and the communities of the routes. They protect against route leaks that the roles do not prevent, for example a route that a customer advertises for address space that is not its own, or an error in the configuration of a role.

Export limits apply to the following neighbors:

  • Neighbors with the role PROVIDER, PEER, or ROUTE_SERVER.
  • EBGP neighbors without a role.

They do not apply to customers, route server clients, or IBGP neighbors, which receive the full routing table where their export policy permits it.

Configuring Export Limits

The top-level export_limits statement applies to every neighbor that does not have its own export_limits statement:

export_limits {
  prefixes { prefix: "198.51.100.0/22" max_length: 24 }
  prefixes { prefix: "2001:db8::/32" max_length: 48 }
  max_prefixes: 50
}
Statement Description
prefixes Specifies the prefixes that can be advertised: typically the address space of the local AS and of its customers. Ferrix does not advertise learned or originated routes for other prefixes to the neighbor. Default: all prefixes.
max_prefixes Specifies the maximum number of routes advertised to the neighbor, counting learned and originated routes of both address families. Default: no limit.

A neighbor's export_limits statement replaces the top-level statement. An empty statement, export_limits {}, removes the limits for the neighbor. Unlike the export statement, the limits are not lost when a neighbor has its own export policy.

If more routes are to be advertised to a neighbor than max_prefixes permits, Ferrix advertises none of them. It tears down the session with a Cease NOTIFICATION message, subcode Administrative Shutdown, that contains the reason as a shutdown communication (RFC 9003), and places the neighbor in hold-down for the neighbor's import.hold_down_seconds (default: 600 seconds). Set max_prefixes somewhat above the number of routes that the local AS and its customers originate.

At startup, Ferrix logs a warning that lists the neighbors to which export limits apply but none are configured, and a warning for each originated route that the prefixes of the export limits do not permit.

Verifying Export Limits

When the limit is exceeded, Ferrix logs an error that states the number of routes and the limit, and increments the metric bgp_export_limit_exceeded_total{peer}. The status page and /api/peers show the reason in the neighbor's last error, for example:

6 routes were to be advertised to the peer, over its export limit of 5; none of them was

While the neighbor is in hold-down, its last error is held down after more routes were to be advertised to it than its export limit allows. To restore the session before the hold-down expires, correct the cause and restart Ferrix.

Configuring Export Policy

The export policy can add and remove communities on advertised routes, and prepend the local AS number to the AS path:

export {
  remove_communities: "64500:2:*"
  add_large_communities: "64500:3:1"
  as_path_prepend: 2
}
Statement Description
remove_communities Removes matching communities before communities are added. A pattern has two fields for a standard community and three for a large community; each field is a number or *.
add_communities, add_large_communities Adds communities to every advertised route.
as_path_prepend Prepends the local AS number the specified number of additional times. Range: 0 through 16. Default: 0.

Control Communities

Control communities allow a route's communities to restrict the neighbors to which Ferrix advertises it, and to prepend the local AS number to its AS path on its way to them. The formats are the ones used by Internet exchange route servers and transit providers. To enable control communities, configure the following top-level statement:

control_communities: true

Table 2 lists the control communities, where L is the local AS number, P is a neighbor's AS number, and G is a session group (see Session Groups).

Standard community Large community Action
0:P L:0:P Do not advertise to the neighbor with AS P.
L:P L:1:P Advertise to the neighbor with AS P. If present, advertise only to neighbors named in such communities.
0:L L:0:0 Do not advertise to any neighbor.
L:11:P, L:12:P, L:13:P Prepend the local AS number once, twice, or three times when advertising to the neighbor with AS P. If P is 0, prepend to every EBGP neighbor.
L:20:G Do not advertise to the sessions in group G.
L:21:G Advertise to the sessions in group G. If present, advertise only to sessions named in such communities, by group or by AS.
L:31:G, L:32:G, L:33:G Prepend the local AS number once, twice, or three times when advertising to the sessions in group G.

Control communities are evaluated as follows:

  • "Do not advertise" takes precedence over "advertise".
  • A route without control communities is advertised as the other rules permit.
  • If several prepend communities apply to a session, the largest number of prepends applies. It is added to the session's as_path_prepend.
  • Standard communities can express AS numbers up to 65535 only. Use the large community forms for four-octet AS numbers.

Where Control Communities Apply

Ferrix acts on control communities when it advertises a route to an EBGP neighbor, and removes them from the route at that point. Informational communities of the local AS are not removed. To an IBGP neighbor, Ferrix advertises the route with its control communities, and without acting on them: the other router acts on them when it advertises the route outside the local AS. A control community can therefore be set on one router and take effect on another.

Ferrix acts on control communities that come from the following sources:

  • The communities and large_communities statements of an originated route.
  • The add_communities and add_large_communities statements of an import policy.
  • Routes from IBGP neighbors.
  • Routes from EBGP neighbors with accept_control_communities, usually customers that steer their own routes.

Ferrix removes the local AS's communities from routes from all other neighbors when it receives them. See Communities of the Local AS.

Session Groups

A control community can name sessions by group instead of by AS. A group is a number that the configuration assigns to sessions, for example the sessions at one Internet exchange. A neighbor present at two exchanges has the same AS number at both, but its sessions are in different groups. A session can be in several groups:

peers {
  name: "exchange-b-rs1"
  role: ROUTE_SERVER
  groups: 2
  groups: 10
}

Use the same group numbers on all routers in the local AS, because a control community set on one router can take effect on another.

Example: Inbound Traffic Engineering

In the following example, the router is connected to exchange A over a fast link and to exchange B over a slow one. Routes of the customer are to reach networks at exchange B with a longer AS path, so that networks present at both exchanges send traffic for them through exchange A. The originated anycast prefix is advertised at both exchanges unchanged.

local_asn: 64500
control_communities: true
originate { prefix: "198.51.100.0/24" }

peers {
  name: "customer-a"
  role: CUSTOMER
  import {
    add_large_communities: "64500:31:2"
    accept_control_communities: true
  }
}

peers {
  name: "exchange-a-rs1"
  role: ROUTE_SERVER
  groups: 1
}

peers {
  name: "exchange-b-rs1"
  role: ROUTE_SERVER
  groups: 2
}

Ferrix adds 64500:31:2 to every route of the customer, and prepends the local AS number once to those routes on the sessions in group 2. With accept_control_communities, the customer can also set control communities on individual prefixes, for example 64500:20:2 to withdraw a prefix from exchange B.

Important

When control communities are enabled, Ferrix interprets the standard community L:n as "advertise to AS n", and the large communities of Table 2 as listed. Use large communities with a second field of 2 through 9, or 100 and higher, for informational communities. Values 10 through 99 are reserved for control communities.

Update Generation

Ferrix groups routes with identical attributes into a single UPDATE message. It collects changes for 50 milliseconds before it sends them.

When a neighbor requires the full routing table, at session establishment or after a ROUTE-REFRESH message, Ferrix collects the entire table before it sends it, so that prefixes with identical attributes share UPDATE messages. At most four sessions collect a full table concurrently; other sessions wait.

Each session has its own export task, which records the routes advertised on the session. If the neighbor reads slowly, only that session's task waits; other sessions are not affected.

In the transit benchmark, in which one neighbor advertises 1.23 million routes and Ferrix advertises them to a second neighbor, the second neighbor receives all routes after 2.1 seconds, with an average of four routes in each UPDATE message.

Route Reflection

By default, Ferrix does not advertise a route learned from an IBGP neighbor to another IBGP neighbor (RFC 4271). Every router of the local AS then requires an IBGP session with every other router. Route reflection (RFC 4456) removes that requirement: a router that is a route reflector advertises routes between its IBGP neighbors.

To make an IBGP neighbor a route reflector client, configure the following statements:

peers {
  name: "router-3"
  remote_asn: 64500
  route_reflector_client: true
  export { learned_routes: true }
}

Ferrix then advertises routes as follows:

  • Routes from a client go to all IBGP neighbors, clients and others.
  • Routes from an IBGP neighbor that is not a client go to the clients only.
  • Routes from EBGP neighbors go to all IBGP neighbors, as without route reflection.

The export policy of the receiving neighbor must enable learned_routes. route_reflector_client is permitted only for IBGP neighbors; Ferrix rejects the configuration otherwise. Advertisement to EBGP neighbors is not affected.

Next Hop of Reflected Routes

Ferrix advertises a reflected route with the local address of the session as next hop, as it does every route. A standard route reflector does not change the next hop. Ferrix does, so that a client needs no route to the router that learned the route: the client sends the traffic through the route reflector, which forwards it. Preserving the next hop on reflection is not yet configurable; clients that have a route to the originating router, for example over a tunnel, would then forward to it directly. See Next Hop Resolution.

Loop Prevention

When Ferrix reflects a route, it adds the ORIGINATOR_ID attribute, which contains the BGP identifier of the router that learned the route, if the route does not already have it. It also prepends its cluster ID to the CLUSTER_LIST attribute. Ferrix does not reflect a route back to the router in its ORIGINATOR_ID, and does not reflect a route whose CLUSTER_LIST contains its cluster ID. Ferrix rejects a route from an IBGP neighbor whose ORIGINATOR_ID is the local router ID, or whose CLUSTER_LIST contains the local cluster ID, with the reason route reflected back to us.

The cluster ID is the router ID by default. Configure the top-level cluster_id statement to give two route reflectors that serve the same clients the same cluster ID.

Ferrix does not send ORIGINATOR_ID and CLUSTER_LIST to EBGP neighbors.

Verifying Route Advertisement

The metric bgp_routes_exported_total{change} counts learned routes that Ferrix advertised (announced) and withdrew (withdrawn). Ferrix does not provide a view of the routes advertised to a neighbor (Adj-RIB-Out); to display them, use the neighbor's own tools.

Feeding a Route Collector

A route collector, such as a looking glass or a measurement project, wants every route that a router has accepted, not only the best path for each prefix. ADD-PATH (RFC 7911) lets one session carry several routes for a prefix, each with a path identifier. To advertise every accepted route to a neighbor, configure ADD-PATH in the sending direction and enable all_paths in the neighbor's export policy:

peers {
  name: "collector"
  endpoint { address: "203.0.113.10" }
  remote_asn: 64496
  role: PEER
  add_path: ADD_PATH_SEND
  export {
    learned_routes: true
    all_paths: true
  }
  export_limits {}
}

Ferrix advertises every route for a prefix only for the address families for which the neighbor negotiated ADD-PATH receive. For other families it advertises the best path, as without all_paths. Each route is advertised with a path identifier that stays with the route for as long as it is advertised; a route that is withdrawn is withdrawn by its identifier, and a route whose attributes change is advertised again with the same identifier. The export policy, the BGP role rules, the well-known communities and the export limits apply to every route alike, and max_prefixes in export_limits counts every route advertised.

A session with all_paths keeps a record of every route advertised and its identifier, which takes about 50 bytes for each route. For a full Internet table from several neighbors, this is some tens of megabytes.

Limitations

  • Per-client best path selection for route servers is not supported. Every client receives the same best path.
  • Best path selection does not use ORIGINATOR_ID and CLUSTER_LIST as tie breakers (RFC 4456 Section 9).
  • UPDATE messages are generated separately for each session, even when several sessions receive identical routes.