Newansage v0.4.0 is out
Reference / Configuration

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

asnintegerrequired

Our AS number.

Rust type
u32
#global-asn
router_idstringrequired

BGP identifier, conventionally one of our IPv4 addresses.

Rust type
Ipv4Addr
#global-router_id
hold_timeinteger= 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.

Rust type
u16
Default
hold_time = 90
#global-hold_time
connect_retryinteger= 30

Seconds between connection attempts.

Rust type
u64
Default
connect_retry = 30
#global-connect_retry
max_connect_retryinteger= 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.

Rust type
u64
Default
max_connect_retry = 600
#global-max_connect_retry
announcearray= []

Our prefixes, announced to every neighbor.

Rust type
Vec<Prefix>
Default
announce = []
#global-announce
max_prefix_restartinteger= 300

Seconds before reconnecting to a neighbor that exceeded its prefix limit.

Rust type
u64
Default
max_prefix_restart = 300
#global-max_prefix_restart
control_socketstring= "/run/ansage/ansage.sock"

Unix socket for `ansage show`. An empty string turns it off.

Rust type
PathBuf
Default
control_socket = "/run/ansage/ansage.sock"
#global-control_socket
listenarray= []

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.

Rust type
Vec<SocketAddr>
Default
listen = []
#global-listen
graceful_restartboolean= 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.

Rust type
bool
Default
graceful_restart = false
#global-graceful_restart
restart_timeinteger= 30

Seconds a neighbor keeps our routes after losing the session, 1 to 4095 (advertised in the Graceful Restart capability).

Rust type
u16
Default
restart_time = 30
#global-restart_time
drain_timeinteger= 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.

Rust type
u64
Default
drain_time = 0
#global-drain_time
metrics_listenstringoptional

Serve Prometheus metrics at http://ADDR/metrics, e.g. "127.0.0.1:9179". Off by default.

Rust type
Option<SocketAddr>
#global-metrics_listen

[[neighbor]]

addressstringrequired

The neighbor's address: ansage connects to it, and with `listen` accepts connections only from configured addresses.

Rust type
IpAddr
Where
[[neighbor]]
#neighbor-address
portinteger= 179

The neighbor's TCP port.

Rust type
u16
Default
port = 179
Where
[[neighbor]]
#neighbor-port
asnintegerrequired

The neighbor's AS number; equal to `asn` makes the session iBGP.

Rust type
u32
Where
[[neighbor]]
#neighbor-asn
hold_timeintegeroptional

Overrides the global hold time for this neighbor.

Rust type
Option<u16>
Where
[[neighbor]]
#neighbor-hold_time
descriptionstringoptional

Free text shown by `ansage show` and in the metrics; a change needs no reconnect.

Rust type
Option<String>
Where
[[neighbor]]
#neighbor-description
next_hop_ipv4stringoptional

Next hop for IPv4 routes. Default: our local address of the session, if the session runs over IPv4.

Rust type
Option<Ipv4Addr>
Where
[[neighbor]]
#neighbor-next_hop_ipv4
next_hop_ipv6stringoptional

Next hop for IPv6 routes. Default: our local address of the session, if the session runs over IPv6 with a global address.

Rust type
Option<Ipv6Addr>
Where
[[neighbor]]
#neighbor-next_hop_ipv6
extended_next_hopboolean= 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.

Rust type
bool
Default
extended_next_hop = false
Where
[[neighbor]]
#neighbor-extended_next_hop
import"none" | "all" | filter name= "none"

Which learned routes are kept: "none" (default, RFC 8212), "all", or the name of a filter.

Rust type
ImportPolicy
Default
import = "none"
Where
[[neighbor]]
#neighbor-import
max_prefixes_ipv4integeroptional

Close the session when the neighbor sends more IPv4 prefixes.

Rust type
Option<u32>
Where
[[neighbor]]
#neighbor-max_prefixes_ipv4
max_prefixes_ipv6integeroptional

Close the session when the neighbor sends more IPv6 prefixes.

Rust type
Option<u32>
Where
[[neighbor]]
#neighbor-max_prefixes_ipv6
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`.

Rust type
ExportPolicy
Default
export = "own"
Where
[[neighbor]]
#neighbor-export
role"provider" | "customer" | "peer" | "rs"optional

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.

Rust type
Option<NeighborRole>
Where
[[neighbor]]
#neighbor-role
strict_roleboolean= false

With `role`: refuse a neighbor that sends no BGP Role (RFC 9234 strict mode). A change reconnects the session.

Rust type
bool
Default
strict_role = false
Where
[[neighbor]]
#neighbor-strict_role
default_routeboolean= 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.

Rust type
bool
Default
default_route = false
Where
[[neighbor]]
#neighbor-default_route
passwordstringoptional

TCP-MD5 key shared with the neighbor (RFC 2385).

Rust type
Option<Md5Key>
Where
[[neighbor]]
#neighbor-password
password_filestringoptional

File holding the TCP-MD5 key instead of `password`; one trailing newline is ignored. Relative paths start at the config file.

Rust type
Option<PathBuf>
Where
[[neighbor]]
#neighbor-password_file
ttl_securityintegeroptional

GTSM (RFC 5082): the neighbor is at most this many hops away (1 = directly connected). Packets with a lower TTL are dropped.

Rust type
Option<u8>
Where
[[neighbor]]
#neighbor-ttl_security
graceful_restartbooleanoptional

Overrides the global `graceful_restart` for this neighbor.

Rust type
Option<bool>
Where
[[neighbor]]
#neighbor-graceful_restart
restart_timeintegeroptional

Overrides the global `restart_time` for this neighbor.

Rust type
Option<u16>
Where
[[neighbor]]
#neighbor-restart_time
passiveboolean= false

Never connect to this neighbor, wait for it to connect (needs `listen`).

Rust type
bool
Default
passive = false
Where
[[neighbor]]
#neighbor-passive
drain_prependinteger= 0

While drained, prepend our AS this many extra times on our routes to this (eBGP) neighbor, for neighbors that ignore GRACEFUL_SHUTDOWN.

Rust type
u8
Default
drain_prepend = 0
Where
[[neighbor]]
#neighbor-drain_prepend
installbooleanoptional

Install this neighbor's routes into the kernel when they are the best ones. Default: true with [kernel] (which it needs).

Rust type
Option<bool>
Where
[[neighbor]]
#neighbor-install

[kernel]

tableinteger= 254

Routing table, by number: 254 (default) is main.

Rust type
u32
Default
table = 254
Where
[kernel]
#kernel-table
metricinteger= 20

Metric of ansage's routes; another route for the same prefix with a lower metric wins. Default 20 (FRR's for eBGP).

Rust type
u32
Default
metric = 20
Where
[kernel]
#kernel-metric
familiesarray= ["ipv4", "ipv6"]

Families to install, default both.

Rust type
Vec<Family>
Default
families = ["ipv4", "ipv6"]
Where
[kernel]
#kernel-families
resolve_via_defaultboolean= 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.

Rust type
bool
Default
resolve_via_default = false
Where
[kernel]
#kernel-resolve_via_default

[[filter.NAME.rule]]

source"own" | "learned"optional

"own" (our `announce` prefixes) or "learned" (from neighbors).

Rust type
Option<RouteSource>
Where
[[filter.NAME.rule]]
#filter-source
from_rolearray= []

Learned from a neighbor with one of these roles.

Rust type
Vec<NeighborRole>
Default
from_role = []
Where
[[filter.NAME.rule]]
#filter-from_role
from_neighborarray= []

Learned from one of these neighbor addresses.

Rust type
Vec<IpAddr>
Default
from_neighbor = []
Where
[[filter.NAME.rule]]
#filter-from_neighbor
prefixesarray= []

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).

Rust type
Vec<PrefixRange>
Default
prefixes = []
Where
[[filter.NAME.rule]]
#filter-prefixes
origin_asarray= []

The last AS in the AS path (who originated the route).

Rust type
Vec<u32>
Default
origin_as = []
Where
[[filter.NAME.rule]]
#filter-origin_as
as_path_containsarray= []

One of these AS numbers anywhere in the AS path.

Rust type
Vec<u32>
Default
as_path_contains = []
Where
[[filter.NAME.rule]]
#filter-as_path_contains
as_path_max_lenintegeroptional

At most this many AS numbers in the AS path.

Rust type
Option<u32>
Where
[[filter.NAME.rule]]
#filter-as_path_max_len
communitiesarray= []

Carries one of these communities, e.g. "64500:200".

Rust type
Vec<Community>
Default
communities = []
Where
[[filter.NAME.rule]]
#filter-communities
large_communitiesarray= []

Carries one of these large communities, e.g. "64500:1:2".

Rust type
Vec<LargeCommunityValue>
Default
large_communities = []
Where
[[filter.NAME.rule]]
#filter-large_communities
action"accept" | "reject"required

"accept" or "reject".

Rust type
Action
Where
[[filter.NAME.rule]]
#filter-action
prependinteger= 0

Export only: prepend our AS this many extra times.

Rust type
u8
Default
prepend = 0
Where
[[filter.NAME.rule]]
#filter-prepend
add_communitiesarray= []
Rust type
Vec<Community>
Default
add_communities = []
Where
[[filter.NAME.rule]]
#filter-add_communities
remove_communitiesarray= []
Rust type
Vec<Community>
Default
remove_communities = []
Where
[[filter.NAME.rule]]
#filter-remove_communities
add_large_communitiesarray= []
Rust type
Vec<LargeCommunityValue>
Default
add_large_communities = []
Where
[[filter.NAME.rule]]
#filter-add_large_communities
remove_large_communitiesarray= []
Rust type
Vec<LargeCommunityValue>
Default
remove_large_communities = []
Where
[[filter.NAME.rule]]
#filter-remove_large_communities
medintegeroptional

Set the MED.

Rust type
Option<u32>
Where
[[filter.NAME.rule]]
#filter-med
local_prefintegeroptional

Import only: set LOCAL_PREF (higher wins in best path selection).

Rust type
Option<u32>
Where
[[filter.NAME.rule]]
#filter-local_pref

Esc to close