Newansage v0.4.0 is out
Concepts / How ansage works

How ansage works

Sessions, the RIB, own prefixes, import and export, and how ansage picks the best route.

ansage is one process with one BGP session per configured neighbor, one routing table (the RIB), a control socket for the ansage commands and, optionally, an HTTP listener for metrics and a thread that writes routes into the kernel.

              ansage.toml
                   |
   +---------------+----------------+
   |               |                |
 neighbor 1    neighbor 2   ...  own prefixes (announce, ansage announce/withdraw)
   |               |                |
   +---- import ---+----> RIB <-----+
                           |
                export     | best routes
                 v         v
          per neighbor  [kernel] (optional)
                        ip route ... proto bgp

Sessions

Each [[neighbor]] runs the BGP state machine of RFC 4271 (Idle, Connect, Active, OpenSent, OpenConfirm, Established). ansage connects out every connect_retry seconds; after a failed connect, or when the neighbor shuts the session down, the delay doubles up to max_connect_retry and resets once a session is up. With listen it also accepts connections, but only from configured neighbor addresses; a passive neighbor is never connected to.

Every session negotiates IPv4 and IPv6 unicast, 4-octet AS numbers, route refresh, extended messages and, if enabled, Graceful Restart and the BGP Role (RFC 9234). Both families run over one session, IPv4 or IPv6, see Next hops.

Own prefixes

The prefixes in announce are ansage's own. They go to every neighbor (unless its export says otherwise), are the best route for their prefix whatever a neighbor sends, and never go into the kernel. ansage announce and ansage withdraw change the set at runtime until the next restart; a reload applies only what changed in the file, so runtime changes survive it.

Import and export

DirectionSettingValues
from a neighborimportnone (default, RFC 8212): nothing is stored; all: every valid route is stored; a filter name
to a neighborexportown (default): our own prefixes; none: nothing; a filter name

With the defaults ansage cannot become a transit AS by accident: learned routes only go out through a filter, only to neighbors with a role, and routes from providers, peers and route servers only ever go to customers. See Transit and filters.

On the way out, ansage adds its AS to the path and sets itself as the next hop (eBGP), drops LOCAL_PREF and MED towards eBGP neighbors (a filter can set MED again), and marks a passed-on attribute it does not know as partial. ansage show rib --out NEIGHBOR shows exactly what a neighbor got.

A route is not stored when its AS path contains ansage's own AS (a loop), and UPDATEs with broken attributes are handled per RFC 7606: treated as a withdraw, or the bad attribute is discarded, instead of tearing the session down.

Best path

Of all routes for one prefix, ansage picks one in this order:

  1. Own prefixes beat anything learned.
  2. A route whose next hop is unreachable (with [kernel]) is ranked last.
  3. Highest LOCAL_PREF (default 100). An eBGP neighbor's LOCAL_PREF is dropped on receipt, so on an eBGP route it comes from an import filter. A route with GRACEFUL_SHUTDOWN counts as LOCAL_PREF 0, also on eBGP (RFC 8326).
  4. Shortest AS path.
  5. Lowest ORIGIN (IGP, EGP, incomplete).
  6. Lowest MED among routes from the same neighbor AS (a missing MED is 0).
  7. eBGP over iBGP.
  8. Lowest BGP identifier, then lowest neighbor address.

The best routes are what ansage show rib marks with * and, with [kernel], what goes into the routing table.

Control socket and HTTP

ansage show, announce, drain and the other client commands send one request over the Unix control socket (control_socket, default /run/ansage/ansage.sock) and print the reply. metrics_listen adds Prometheus metrics and a read-only copy of the same answers as JSON, see the HTTP API.

Esc to close