# ExaBGP: a BGP implementation that stops at the routing table on purpose

> ExaBGP speaks BGP without touching a forwarding table, which makes it a library and API rather than a router. That choice puts it in front of BIRD and FRRouting for labs, automation and attack response, and nowhere near them for packet forwarding.

**Exa-Networks/exabgp** — The BGP swiss army knife of networking

- Repository: https://github.com/Exa-Networks/exabgp
- Stars: 2,311 · Forks: 463
- Language: Python
- License: NOASSERTION
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/exa-networks-exabgp

## A BGP speaker with no forwarding table

The README leads with its own tagline, BGP swiss army knife of networking, and then immediately states the design decision everything else follows from. Unlike traditional BGP daemons such as BIRD and FRRouting, ExaBGP does not manipulate the FIB. It implements the protocol and offers an API for an external process to drive.

That sounds like a limitation until you work out what it buys. A daemon that writes routes into a kernel needs privileges, needs to be on the forwarding path, and needs to restart cleanly when the kernel underneath it changes. ExaBGP needs none of that. It can sit on a laptop, in a container, or on a host that is not a router at all, and still speak real BGP to real peers. The topics the repository declares line up with that: ddos-protection, flowspec, bgp-ls, health-check, traffic visualisation, vpls, mpls. Those are the jobs where you want a protocol peer and no packets.

The README also points readers who need FIB programming elsewhere, naming BIRD and FRRouting by link, which is the clearest possible statement that this is not a full routing stack. The architecture list backs it up: a JSON API for control from Python or shell scripts, no FIB manipulation, an event-driven custom reactor that predates asyncio, and a registry-based plugin structure.

## Picking between the 5.0 branch and main

Two branches are maintained and both are supported, and the README is unusually explicit about which one you get by default. The `5.0` branch is stable, currently at 5.0.13, is what pip and most OS packages install, and runs on Python 3.8 or later. The `main` branch is the development branch and the repository default. It will become 6.0, nothing is tagged on it yet, and it requires Python 3.12 or later.

The trap is spelled out too. A `git clone` with no checkout gives you main. So does `docker pull ghcr.io/exa-networks/exabgp:latest`. Only `pip install exabgp` gives you the latest 5.0 release. That is three installation methods returning three different things, and the version notice exists mainly to prevent people from being surprised by it.

```sh
git clone https://github.com/Exa-Networks/exabgp
cd exabgp
git checkout 5.0
```

The pyproject.toml on main tells you what is coming in 6.0. It declares version 6.0.0, requires Python 3.12 or above, and lists classifiers for 3.12 through 3.14. The README names the headline features as an asyncio engine, an interactive CLI with shell completion, and health monitoring API commands. What you also get on main, per the README's own warning, are rough edges, and its compensating virtue is that the full unit and functional test suites run on every commit.

## Five ways to install, and which one you actually want

The quickest demonstration is the container image:

```sh
docker pull ghcr.io/exa-networks/exabgp:latest
docker run -it --rm ghcr.io/exa-networks/exabgp:latest version
```

Building from source yourself is a matter of cloning and running the binary from `sbin/`. The zipapp route produces a self-contained executable from the source folder, which is the option the README calls the simplest, alongside installing from git if the packaged versions cause trouble.

```sh
pip install exabgp
exabgp --help
```

The Dockerfile in the repository is worth reading even if you install by pip, because it answers the question every BGP tool eventually gets asked: how do you talk to it from outside the process. It creates two FIFOs, `/run/exabgp.in` and `/run/exabgp.out`, owned by an unprivileged `exa` user with mode 600, and points the entrypoint at them through dumb-init. That is the control channel, and it explains why the container is a sensible unit of deployment: the process boundary is where the JSON API lives. The build stage uses uv to build a wheel, and the runtime image installs `iproute2` plus dumb-init.

The `Docker.remote` file exists for a variant built with pip that needs no other file, and the repository also carries `debian/` and `redhat/` directories for OS packaging.

## What the 5.0.12 and 5.0.13 releases actually changed

The recent release notes are unusually valuable, because they describe peer-supplied input being handled more carefully rather than listing feature additions. Version 5.0.12, published 2026-08-20, is described as carrying input validation work for data a BGP peer, an API client or a configuration file can put in front of ExaBGP, and the notes state that none of it had reached a release before.

The specifics are the point. OPEN capabilities a peer sends are now validated: `HostName` and `Software Version` used to decode peer-supplied bytes without checking the announced length fitted inside the capability, and invalid UTF-8 left the parser raising a `UnicodeDecodeError` rather than ending the session with a NOTIFICATION. The AS4 capability accepted a 2 octet value, which RFC 6793 section 3 does not allow. The AIGP attribute is now parsed as the TLV sequence it is defined to be under RFC 7311.

Then 5.0.13, published 2026-08-24, is framed as a compatibility release about what a peer can do to the API itself. Its security note explains that a peer could previously write data of its own into the API streams, fields into the JSON stream through a BGP-LS attribute and whole events into the text stream through its hostname, software version or a shutdown message. The output stayed parseable, which meant a program reading the API acted on data no peer had sent. Version 5.0.11 closed the JSON hostname, software version and NOTIFICATION cases only.

For an operator this is the argument for staying current. The last push was on 2026-09-28, so this is moving code in a project where the author is also building a successor.

## Protocol coverage and the API surface

The features list is long, and the categories are worth separating. RFC compliance covers ASN4, IPv6, MPLS, VPLS, Flow, Graceful Restart, Enhanced Route Refresh, Extended Next-Hop, BGP-LS and AIGP. Address families cover IPv4 and IPv6 unicast and multicast, VPNv4 and VPNv6, EVPN, FlowSpec, BGP-LS, MUP and SRv6. Capabilities cover Add-Path, Route Refresh, Graceful Restart and 4-byte ASN. The README sends you to a wiki page for the current RFC compliance details rather than claiming completeness on the front page, which is the right call.

The entry points are declared in pyproject.toml as three console scripts: `exabgp`, `exabgp-cli` and `exabgp-healthcheck`. That third one is the health monitoring piece referenced in the version notice for 6.0, and its presence on main suggests the API is gaining a query surface rather than staying write-only.

The declared use cases explain why that matters. Cross-datacenter failover and migrating a /32 service IP is a control-plane problem. Centralised deployment of blackhole or FlowSpec filters is a mitigation mechanism you drive from a script. Gathering topology through BGP-LS or BGP with Add-Path is telemetry. Anycast management is automation. In all four cases the deliverable is a routing decision made by something else, and that is exactly the boundary ExaBGP is built to sit on. The repository's `tests/`, `qa/`, `lab/` and `data/` directories suggest a serious testing posture, including hypothesis in the dev dependency group.

## ExaBGP against BIRD, FRRouting and the successor project

The honest comparison is not a feature matrix, it is a division of labour. BIRD and FRRouting are routing daemons: they hold sessions, compute a table and install routes into a kernel. ExaBGP holds sessions and computes nothing you will forward on, and hands you an API instead. If you need packets to move, ExaBGP is the wrong tool and the README tells you so. If you need a program to decide what a session should say, ExaBGP is the right tool and those daemons are awkward at it.

The comparison with the author's own successor is more interesting, because the README spends a section on it. Ze is described as a ground-up rewrite in Go aiming at a fully programmable network stack, going beyond BGP to manage interfaces, program the FIB, and serve a config editor over SSH and a web UI. The README is careful about its status: pre-alpha, with a working core BGP engine but many advanced features incomplete or untested, and APIs and config syntax subject to change without notice. It claims existing ExaBGP plugins work unchanged and that `ze config migrate` converts ExaBGP configs, and it asks ExaBGP users to try that conversion and report back.

Two readings of that are possible. One is a deprecation notice in polite form. The other is a maintained successor with a compatibility path and a migration tool. Both point the same direction for a new deployment: pick 5.0 unless you have a specific reason not to. The licence is declared in pyproject.toml as BSD-3-Clause with LICENCE.txt as the licence file, and release 5.0.11 notes that the metadata now takes pyproject.toml as its single source of truth.

## Conclusion

ExaBGP is the tool for the jobs a routing daemon is bad at: teaching a topology in a lab, injecting and withdrawing routes from a script, centralising FlowSpec filters during an attack, or replaying a routing table from MRT dumps. It is the wrong tool the moment packets need forwarding, and the README says so itself rather than leaving you to discover it. The specific first step is to pin your branch before anything else, because a bare `git clone` and a `docker pull` of the latest tag both hand you `main` while `pip install exabgp` gives you 5.0.13, and those are different products with different Python requirements.

## FAQ

### Does ExaBGP install routes into the kernel like a normal BGP daemon?

No, and that is the deliberate design choice. The README states that unlike BIRD and FRRouting, ExaBGP does not manipulate the FIB, and it points readers who need FIB programming to those projects instead. ExaBGP implements the BGP protocol itself and exposes an API for an external process to drive.

### What is the difference between ExaBGP main and the 5.0 branch?

The 5.0 branch is stable at 5.0.13, runs on Python 3.8 or later, and is what pip and most OS packages install. main is the development branch and repository default, requires Python 3.12 or later, and will become 6.0, with an asyncio engine, an interactive CLI and health monitoring API commands among the planned features. Nothing is tagged on main yet.

### How do you install ExaBGP, and which version does pip give you?

Five routes are documented: the ghcr.io container image, a zipapp built from the source folder, pip, GitHub releases and OS packages. pip install exabgp gives you the latest 5.0 release, while a plain git clone and a docker pull of the latest tag both give you main, which is the development branch.

### What changed in the ExaBGP 5.0.12 and 5.0.13 security releases?

5.0.12 added input validation for what a BGP peer sends: OPEN capabilities are checked against their announced length, invalid UTF-8 ends the session with a NOTIFICATION instead of raising a UnicodeDecodeError, the AS4 capability no longer accepts a 2 octet value that RFC 6793 disallows, and AIGP is parsed as the TLV sequence RFC 7311 defines. 5.0.13 continued that work on the API side, because a peer could previously inject its own fields into the JSON stream through BGP-LS attributes and its own events into the text stream via hostname, software version or shutdown message.

## Sources

- [Exa-Networks/exabgp on GitHub](https://github.com/Exa-Networks/exabgp)
- [Issues](https://github.com/Exa-Networks/exabgp/issues)
- [README](https://github.com/Exa-Networks/exabgp/blob/main/README.md)
- [Releases](https://github.com/Exa-Networks/exabgp/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/exa-networks-exabgp
