# Configuration

> Every setting of ansage.toml, generated from the doc comments in config.rs.

ansage reads one TOML file (`--config /etc/ansage/ansage.toml`). `ansage check -c FILE`
validates it. The tables below are generated from `crates/ansage/src/config.rs`.

## Global settings

| setting | type | default | meaning |
|---|---|---|---|
| `asn` | integer | required | Our AS number. |
| `router_id` | string | required | BGP identifier, conventionally one of our IPv4 addresses. |
| `hold_time` | integer | `90` | Hold time we propose in seconds; the session uses the smaller of ours and the peer's. 0 disables keepalives, otherwise at least 3. |
| `connect_retry` | integer | `30` | Seconds between connection attempts. |
| `max_connect_retry` | integer | `600` | Upper bound in seconds for the reconnect backoff: the delay doubles after failed connects and after the peer shut the session down (RFC 4486 §4), and resets once a session is established. |
| `announce` | array | `[]` | Our prefixes, announced to every neighbor. |
| `max_prefix_restart` | integer | `300` | Seconds before reconnecting to a neighbor that exceeded its prefix limit. |
| `control_socket` | string | `"/run/ansage/ansage.sock"` | Unix socket for `ansage show`. An empty string turns it off. |
| `listen` | array | `[]` | Addresses to accept BGP connections on, e.g. ["0.0.0.0:179", "[::]:179"]; only configured neighbors get through. Empty (default): ansage only connects. Port 179 needs CAP_NET_BIND_SERVICE. |
| `graceful_restart` | boolean | `false` | Graceful Restart (RFC 4724, RFC 8538): neighbors keep our routes for `restart_time` seconds when the session is lost without a Hard Reset (`ansage upgrade`, a crash), and we keep theirs. Off by default. |
| `restart_time` | integer | `30` | Seconds a neighbor keeps our routes after losing the session, 1 to 4095 (advertised in the Graceful Restart capability). |
| `drain_time` | integer | `0` | Seconds to stay drained (RFC 8326 GRACEFUL_SHUTDOWN on our routes) on SIGTERM/SIGINT before the sessions are closed, so traffic moves to other sites first. 0 (default): close at once. |
| `metrics_listen` | string | - | Serve Prometheus metrics at http://ADDR/metrics, e.g. "127.0.0.1:9179". Off by default. |

## [[neighbor]]

| setting | type | default | meaning |
|---|---|---|---|
| `address` | string | required | The neighbor's address: ansage connects to it, and with `listen` accepts connections only from configured addresses. |
| `port` | integer | `179` | The neighbor's TCP port. |
| `asn` | integer | required | The neighbor's AS number; equal to `asn` makes the session iBGP. |
| `hold_time` | integer | - | Overrides the global hold time for this neighbor. |
| `description` | string | - | Free text shown by `ansage show` and in the metrics; a change needs no reconnect. |
| `next_hop_ipv4` | string | - | Next hop for IPv4 routes. Default: our local address of the session, if the session runs over IPv4. |
| `next_hop_ipv6` | string | - | Next hop for IPv6 routes. Default: our local address of the session, if the session runs over IPv6 with a global address. |
| `next_hop_ipv6_link_local` | string | - | Our link-local address on the link shared with this neighbor; sent together with the global IPv6 next hop (RFC 2545 §3). |
| `extended_next_hop` | boolean | `false` | Offer extended next hop (RFC 8950): IPv4 routes may use an IPv6 next hop, both ways. When the neighbor agrees and there is no IPv4 next hop (an IPv6 session without `next_hop_ipv4`), our IPv4 prefixes go out with the IPv6 next hop. A change reconnects the session. |
| `import` | "none" \| "all" \| filter name | `"none"` | Which learned routes are kept: "none" (default, RFC 8212), "all", or the name of a filter. |
| `max_prefixes_ipv4` | integer | - | Close the session when the neighbor sends more IPv4 prefixes. |
| `max_prefixes_ipv6` | integer | - | Close the session when the neighbor sends more IPv6 prefixes. |
| `export` | "own" \| "none" \| filter name | `"own"` | Which routes this neighbor gets: "own" (default, our prefixes), "none" (nothing, e.g. to take its routes for a shadow test), or the name of a filter. A filter that can pass learned routes on needs `role`. |
| `role` | "provider" \| "customer" \| "peer" \| "rs" | - | What the neighbor is to us (RFC 9234): "provider" (we buy transit from it), "customer" (it buys transit from us), "peer" or "rs" (an IXP route server). Routes learned from providers, peers and route servers only ever go to customers. Sent as our BGP Role in the OPEN (the opposite one) and checked against the neighbor's. eBGP only; a change reconnects the session. |
| `strict_role` | boolean | `false` | With `role`: refuse a neighbor that sends no BGP Role (RFC 9234 strict mode). A change reconnects the session. |
| `default_route` | boolean | `false` | Announce a default route (0.0.0.0/0, ::/0) to this neighbor while a neighbor with role "provider" is up, whatever `export` says. |
| `password` | string | - | TCP-MD5 key shared with the neighbor (RFC 2385). |
| `password_file` | string | - | File holding the TCP-MD5 key instead of `password`; one trailing newline is ignored. Relative paths start at the config file. |
| `ttl_security` | integer | - | GTSM (RFC 5082): the neighbor is at most this many hops away (1 = directly connected). Packets with a lower TTL are dropped. |
| `graceful_restart` | boolean | - | Overrides the global `graceful_restart` for this neighbor. |
| `restart_time` | integer | - | Overrides the global `restart_time` for this neighbor. |
| `passive` | boolean | `false` | Never connect to this neighbor, wait for it to connect (needs `listen`). |
| `drain_prepend` | integer | `0` | While drained, prepend our AS this many extra times on our routes to this (eBGP) neighbor, for neighbors that ignore GRACEFUL_SHUTDOWN. |
| `install` | boolean | - | Install this neighbor's routes into the kernel when they are the best ones. Default: true with [kernel] (which it needs). |

## [kernel]

| setting | type | default | meaning |
|---|---|---|---|
| `table` | integer | `254` | Routing table, by number: 254 (default) is main. |
| `metric` | integer | `20` | Metric of ansage's routes; another route for the same prefix with a lower metric wins. Default 20 (FRR's for eBGP). |
| `families` | array | `["ipv4", "ipv6"]` | Families to install, default both. |
| `resolve_via_default` | boolean | `false` | A BGP next hop whose only route in the kernel is the default route counts as reachable (e.g. multihop to a router behind the default gateway). Off by default, like FRR: usually such a route is broken. |

## [[filter.NAME.rule]]

| setting | type | default | meaning |
|---|---|---|---|
| `source` | "own" \| "learned" | - | "own" (our `announce` prefixes) or "learned" (from neighbors). |
| `from_role` | array | `[]` | Learned from a neighbor with one of these roles. |
| `from_neighbor` | array | `[]` | Learned from one of these neighbor addresses. |
| `prefixes` | array | `[]` | Prefix ranges, e.g. "203.0.113.0/24" (exactly), "10.0.0.0/8 le 24" (/8 to /24 inside 10.0.0.0/8), "::/0 ge 49" (longer than /48). |
| `origin_as` | array | `[]` | The last AS in the AS path (who originated the route). |
| `as_path_contains` | array | `[]` | One of these AS numbers anywhere in the AS path. |
| `as_path_max_len` | integer | - | At most this many AS numbers in the AS path. |
| `communities` | array | `[]` | Carries one of these communities, e.g. "64500:200". |
| `large_communities` | array | `[]` | Carries one of these large communities, e.g. "64500:1:2". |
| `action` | "accept" \| "reject" | required | "accept" or "reject". |
| `prepend` | integer | `0` | Export only: prepend our AS this many extra times. |
| `add_communities` | array | `[]` | - |
| `remove_communities` | array | `[]` | - |
| `add_large_communities` | array | `[]` | - |
| `remove_large_communities` | array | `[]` | - |
| `med` | integer | - | Set the MED. |
| `local_pref` | integer | - | Import only: set LOCAL_PREF (higher wins in best path selection). |
