The documentation sources are Zola Markdown: front matter between +++ lines, shortcodes that insert the example configurations, and @/ internal links. A code forge shows all three unrendered, which the README used to deny. A docs/README.md now explains each, and the README points to it. "Configuring BGP Neighbors" becomes "BGP Neighbors", as the other feature pages are titled; "When a Neighbor Restarts" becomes "Neighbor Restart", a noun phrase as the style guide asks. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
195 lines
9.1 KiB
Markdown
195 lines
9.1 KiB
Markdown
# Ferrix BGP
|
|
|
|
Ferrix is a BGP daemon for Linux routers, written in Rust. It exchanges
|
|
routes with neighbors, filters them by policy and the RPKI, selects the
|
|
best path for each prefix, installs it in the kernel, and passes routes on
|
|
as BGP roles and communities permit. It aims to be small, safe, observable,
|
|
and configured from one file that can be read by someone who did not write
|
|
it.
|
|
|
|
## Status
|
|
|
|
Ferrix routes the author's network, AS210036: three routers carrying full
|
|
tables from transit providers, route servers at several Internet exchanges,
|
|
and bilateral peers, with routes reflected between the routers over iBGP.
|
|
It is young software all the same. Read the [limitations](#not-supported)
|
|
before relying on it, and treat version `0.x` as meaning that configuration
|
|
and APIs may still change between releases.
|
|
|
|
What it does:
|
|
|
|
- BGP-4 over IPv4 and IPv6, with four-octet AS numbers, multiprotocol
|
|
reach for both families, IPv4 routes with IPv6 next hops (RFC 8950),
|
|
route refresh, graceful restart and ADD-PATH receive.
|
|
- Import policy per neighbor: prefix limits, prefix and origin AS lists,
|
|
bogon checks, AS path checks, and communities added on the way in.
|
|
- Route origin validation and ASPA path verification against an RTR cache.
|
|
- BGP roles (RFC 9234) and the Only to Customer attribute, with export
|
|
limits as a second line of defence against route leaks.
|
|
- Best path selection and installation of the result in the Linux kernel
|
|
over netlink, in a routing table of your choice.
|
|
- Route reflection between routers of the same AS, and passive neighbors.
|
|
- A status page, a JSON API, server-sent events, and Prometheus metrics.
|
|
- Graceful restart of the daemon itself for upgrades, with routes left in
|
|
the kernel while it is away.
|
|
|
|
### Not supported
|
|
|
|
- Per-client best path selection for route servers, and ADD-PATH for
|
|
advertised routes
|
|
- TCP-AO, TCP MD5, and GTSM
|
|
- Long-Lived Graceful Restart, BFD, and configuration changes without a
|
|
restart
|
|
- Recursive resolution of next hops that are not directly connected
|
|
- Address families other than IPv4 and IPv6 unicast
|
|
|
|
## Building
|
|
|
|
You need a stable Rust toolchain from [rustup.rs](https://rustup.rs), and a
|
|
C compiler and `make` for the jemalloc allocator the daemon uses (for
|
|
example `build-essential` on Debian and Ubuntu, `base-devel` on Arch Linux,
|
|
or the Xcode command line tools on macOS). The Protocol Buffers compiler is
|
|
not needed: the configuration schema is compiled in pure Rust.
|
|
|
|
```bash
|
|
git clone https://git.rayhaan.net/rayhaan/ferrix.git
|
|
cd ferrix
|
|
cargo build --release --locked -p bgp
|
|
```
|
|
|
|
The binary is `target/release/bgp`. `--locked` builds with the dependency
|
|
versions recorded in `Cargo.lock`, which are the versions CI tested.
|
|
|
|
To try it without touching any router, run the quick-start configuration.
|
|
It listens on loopback, needs no privileges, and serves the status page at
|
|
<http://127.0.0.1:8080>; the [quick start
|
|
guide](docs/content/docs/getting-started/quick-start.md) adds a test peer
|
|
that announces routes to it.
|
|
|
|
```bash
|
|
target/release/bgp --check docs/examples/quick-start.textpb
|
|
target/release/bgp docs/examples/quick-start.textpb
|
|
```
|
|
|
|
Other ways to build:
|
|
|
|
- **A static Linux executable** that runs on any x86_64 distribution with
|
|
nothing else installed: `scripts/build-static.sh`. It needs the
|
|
`x86_64-unknown-linux-musl` target and a musl C compiler; the script's
|
|
header says how to install them, including on macOS.
|
|
- **A container image** with the provided `Dockerfile`:
|
|
`docker build -t ferrix .`
|
|
|
|
Kernel route installation needs Linux and `CAP_NET_ADMIN`; everywhere else
|
|
Ferrix is a BGP speaker only. The [installation
|
|
guide](docs/content/docs/getting-started/installation.md) and the
|
|
[deployment guide](docs/content/docs/operations/deployment.md) cover
|
|
privileges, the systemd unit, and upgrading without withdrawing routes.
|
|
|
|
## Documentation
|
|
|
|
The documentation is a website built from [`docs/`](docs/) with
|
|
[Zola](https://www.getzola.org): `zola --root docs serve`, then open
|
|
<http://127.0.0.1:1111>. The sources are Markdown with Zola front matter,
|
|
shortcodes and internal links, so the forge shows them with those parts
|
|
unrendered; [`docs/README.md`](docs/README.md) explains what each is. The
|
|
pages:
|
|
|
|
- [Overview](docs/content/docs/getting-started/introduction.md),
|
|
[installation](docs/content/docs/getting-started/installation.md) and
|
|
[quick start](docs/content/docs/getting-started/quick-start.md)
|
|
- User guide: [BGP neighbors](docs/content/docs/guides/peers.md),
|
|
[import policy](docs/content/docs/guides/import-policy.md),
|
|
[BGP roles](docs/content/docs/guides/roles.md),
|
|
[RPKI](docs/content/docs/guides/rpki.md),
|
|
[kernel route installation](docs/content/docs/guides/kernel.md),
|
|
[route advertisement](docs/content/docs/guides/passing-routes-on.md),
|
|
[graceful restart](docs/content/docs/guides/graceful-restart.md),
|
|
[configuration examples](docs/content/docs/guides/examples.md)
|
|
- [Deployment](docs/content/docs/operations/deployment.md) and
|
|
[monitoring](docs/content/docs/operations/monitoring.md)
|
|
- Reference: [configuration](docs/content/docs/reference/configuration.md),
|
|
[command line](docs/content/docs/reference/command-line.md),
|
|
[HTTP API](docs/content/docs/reference/http-api.md),
|
|
[metrics](docs/content/docs/reference/metrics.md),
|
|
[supported standards](docs/content/docs/reference/rfcs.md)
|
|
- [Architecture](docs/content/docs/development/architecture.md),
|
|
[testing](docs/content/docs/development/testing.md) and
|
|
[contributing](docs/content/docs/development/contributing.md)
|
|
|
|
Complete configurations for an edge router, an exchange router and a
|
|
transit customer are in [`docs/examples/`](docs/examples/); CI checks that
|
|
each of them loads.
|
|
|
|
## Security
|
|
|
|
- The status page and HTTP API are not authenticated and show the whole
|
|
configuration and routing table. Bind `http_endpoint` to a loopback
|
|
address, or put it behind a proxy that authenticates.
|
|
- Ferrix does not implement TCP-MD5 or TCP-AO. Filter TCP port 179 in the
|
|
host firewall so that only configured neighbors can connect.
|
|
- Everything read from the network, the RPKI cache, and the kernel is
|
|
parsed without panicking; each parser has property tests and a fuzz
|
|
target. `unsafe` code is forbidden throughout.
|
|
|
|
If you find a vulnerability, please contact the maintainer directly rather
|
|
than opening a public issue.
|
|
|
|
## Layout
|
|
|
|
| Crate | What is in it |
|
|
| -------------------------- | -------------------------------------------------------------------------- |
|
|
| `crates/primitives` | Prefixes, address families, parsing helpers |
|
|
| `crates/packet` | The wire format: messages, attributes, capabilities |
|
|
| `crates/rib` | The routing table, best route selection, the journal of changes |
|
|
| `crates/rpki` | The RTR client; origin validation and ASPA path verification |
|
|
| `crates/fib` | The best routes in the Linux kernel, over netlink |
|
|
| `crates/server` | Sessions, the state machine, policy, configuration |
|
|
| `crates/web` | The status page, HTTP API and metrics |
|
|
| `crates/integration-tests` | A test server and test peers, and the tests that run the daemon end to end |
|
|
| `crates/bench` | Benchmarks at the scale of the Internet routing table |
|
|
| `bin/bgp` | The daemon |
|
|
|
|
## Development
|
|
|
|
CI runs these on every push, and fails on any warning:
|
|
|
|
```bash
|
|
cargo fmt --all -- --check
|
|
cargo clippy --locked --workspace --all-targets -- -D warnings
|
|
cargo test --locked --workspace
|
|
RUSTDOCFLAGS="-D warnings" cargo doc --locked --workspace --no-deps --document-private-items
|
|
zola --root docs build
|
|
```
|
|
|
|
It also runs the tests that need a real Linux kernel
|
|
(`scripts/kernel-tests.sh`) and a lab that peers the daemon with FRR, BIRD
|
|
and Routinator (`scripts/interop/lab.sh`); `scripts/linux-vm.sh` runs
|
|
either from macOS in a Lima VM.
|
|
|
|
`cargo test` includes property tests: generated messages must survive being
|
|
written and read back, and no input, however damaged, may make a parser
|
|
panic. They take about a second; for a longer hunt:
|
|
|
|
```bash
|
|
PROPTEST_CASES=1000000 cargo test --release -p bgp-packet --test properties
|
|
```
|
|
|
|
Coverage-guided fuzz targets for the same parsers are in `fuzz/`; see
|
|
[`fuzz/README.md`](fuzz/README.md). CI runs each of them for a minute.
|
|
|
|
### Development with AI agents
|
|
|
|
Much of Ferrix is written with an AI coding agent (Claude Code) working
|
|
alongside the maintainer, who directs the work, reviews every change, and
|
|
runs the result on real routers. Nothing is merged on the agent's say-so:
|
|
every change passes the checks above, the kernel tests and the
|
|
interoperability lab, and the changes that matter are tried on the network
|
|
first. Commits made with an agent carry a `Co-Authored-By` trailer that
|
|
says so. If you contribute, you are welcome to work the same way, or not;
|
|
what is reviewed is the change, not how it was produced.
|
|
|
|
## License
|
|
|
|
Apache License 2.0; see [`LICENSE`](LICENSE).
|