On this page
Pathvector NG
Pathvector NG (Next Generation) is a community-maintained continuation of Pathvector, the declarative edge routing platform by Nate Sales that automates route optimization and control plane configuration with secure and repeatable routing policy.
The upstream repository is no longer actively maintained. Pathvector NG picks up where it left off: the outstanding upstream issues and unmerged pull requests are resolved, the additions from the zappiehost/pathvector fork are included, and maintenance continues on top.
Pathvector NG is a drop-in replacement: the binary is still pathvector,
the config file is still pathvector.yml, and existing configs, systemd units,
and /etc paths keep working unchanged.
Provenance
Pathvector NG is built openly on top of other people's work. Credit where it is due:
- natesales/pathvector — the original project by Nate Sales and its contributors, MIT licensed. The full upstream history is preserved in this repository's git log.
- Community contributors — the pull requests and issue reports filed against upstream that were merged here, including work by l27001, Skyler Mäntysaari, SteveYi, Junxiao Shi, Zachary Seguin, Nick Hilliard, 尤理衡 (Li-Heng Yu), Dennis de Houx, Hampton Moore, Alfie Foster, Nico, Joey Julian König, L8X, potvinp, CloudieLLC and others — see the commit history and the contributors graph for the complete list.
- zappiehost/pathvector —
Zappie Host's fork. Their changes are merged here: reordered import filters
(local-pref/community policy applied before sanity filters, blackholing,
and RPKI last), blackholing down to /32 and /128 via standard and large
communities with a proper
RTD_BLACKHOLEdestination, host-route prefix bounds (-R 32/-R 128for IRR queries and out-of-bounds filtering), theextended-next-hoppeer option, ASN-based local-pref taking precedence over the session default, community stripping before adding, sortedstatusoutput, and raised default import limits.
Bug reports for code inherited from upstream are welcome here — the goal is one maintained tree, not fragmentation.
Features
- Robust BGP route filtering with RPKI, IRR, and downstream AS cone, ASPA, never-via-RS and more
- Automatic configuration from PeeringDB
- Automatic route optimization by enriching the standard set of BGP attributes with latency and packet loss metrics
- Declarative configuration model: Want to track your changes? Just commit your file to version control.
- Data-plane agnostic: Pathvector works on servers, network switches, embedded devices, etc
- BFD and VRRP support
- Extensible Go plugin API
- Prometheus metrics —
pathvector metricsexports protocol state, route counts, and BGP session info on/metricsfor scraping
Fixed upstream issues
At fork time the upstream tracker had a long tail of open bugs and feature requests. Those are addressed here, including (upstream issue numbers):
- Template inheritance & list merging (#128), named communities (#213),
per-peer
source4/source6(#233, #255),l3vpnfor VPNv4/VPNv6 (#252), multiple kernel tables (#118), overriding built-in protocols (#277),prefix-prefs(#196),as-prefs4/as-prefs6(#236),gateway(#197),cost(#190),vip-interface(#193),restartcommand (#219), YANG model generation (#22) dont-announce/only-announcesplit by address family (#282, #258), blackhole routes exempted from out-of-bounds (#208),announce-originatedwith origin-communities (#189), no default local-pref override on iBGP (#241), kernel protocols named kernel4/kernel6 (#207), kernel statics exported with SRD (#215), learned default routes preferred withaccept-default(#242)- Optimizer edits the live BIRD config instead of a cache copy (#235),
--traceactually enables trace logging,clialias restored (#224),bird-sockethonored by all commands (#184), robust BIRD version parsing (#212) - Fail-safe per peer on IRR errors (#202), cached IRR/PeeringDB fallback when
sources are unreachable (#188), user
bgpq-argssources respected (#192),filter-irr/auto-as-set-membersvalidated against missing as-sets (#217),verify-irr-policycommand (#165) - Docker-based BIRD test matrix in CI and before releases (#216, #146),
advertise-hostnameplacement regression test (#256), route-limit troubleshooting docs (#260), Team Cymru UTRS guide (#244),peeringdb-cachedocs (#251), default import limits documented (#237), as-prefs precedence over community-prefs (#198) - Plus the zappiehost improvements listed in Provenance
Daemon compatibility
Pathvector is one binary, one config — the routing daemon is a backend
setting, not a separate install. Every backend renders the same peer/policy
model and is verified by an automated matrix that runs on every change
(tests/bird-matrix, tests/frr-matrix, tests/e2e, tests/cairn-e2e).
one binary · pathvector.yml"] --> GEN["generate + validate + deploy"] GEN --> B{backend} B -->|"backend: bird"| BD["BIRD
v2.0.7 → v3.4.0
15 releases · all pass"] B -->|"backend: frr"| FD["FRR
9.1.3 → 10.7.1
7 releases · core pass"] B -->|"backend: cairn"| CD["Cairn
0.1.1
e2e pass · private beta"]
Regenerate with tests/gen-compat-heatmap.py.
| Backend | Daemon | Verified versions | Result |
|---|---|---|---|
bird |
BIRD | v2.0.7 – v3.4.0 (15 releases) | all pass — one known XFAIL (v2.0.7 + complex config) |
frr |
FRR | frr-9.1.3 – frr-10.7.1 (7 releases) | core pass — FRR ≤ 10.0 needs rpki-enable: false |
cairn |
Cairn | 0.1.1 | e2e pass (private beta) |
The "Verified versions" column is generated from the matrix version files —
regenerate it with make compat (see tests/compat-report.sh). To check the
daemon installed on a router against this range, run pathvector compat there.
Each matrix
entry exercises
config generation, the daemon's own config validation (bird -p,
vtysh -C/-b, cairnd --check), a live daemon, and control-channel
commands (status, restart, diff, metrics).
Known limits, by design rather than defect:
- FRR ≤ 10.0 uses the pre-10.1 RPKI cache syntax — set
rpki-enable: falseor upgrade. Everything else passes. - FRR 7.x/8.x predate libyang 2 and can't build on the modern toolchain — unsupported.
- BIRD v2.0.7 fails only the
generate-complexconfig (transit-lock+AS-path mask needs ≥ 2.0.8). - Cairn is early-release/private-beta; its backend is experimental and its
.debisn't publicly distributed yet.
<details> <summary>Every version exercised by the matrices</summary>
BIRD — v2.0.7 v2.0.12 v2.13.1 v2.14 v2.15.1 v2.16.2 v2.17.7
v2.18.4 v2.19.3 v2.20.0 v3.0.5 v3.1.9 v3.2.4 v3.3.3 v3.4.0
FRR — frr-9.1.3 frr-10.0.5 frr-10.1.5 frr-10.2.6 frr-10.3.4
frr-10.5.5 frr-10.7.1
Cairn — 0.1.1
Each entry runs config generation, the daemon's own config check, a live
daemon, and the control commands. To add a release, append its tag to the
matching tests/*-matrix/versions.txt.
</details>
Build from source
Requires Go ≥ 1.23 (the go directive in go.mod; any newer toolchain works):
git clone https://github.com/XodoTechnology/pathvector-ng.git
cd pathvector-ng
go build -o pathvector .
To stamp version info into the binary (recommended for production so pathvector version reports something useful):
go build -o pathvector \
-ldflags "-X main.version=$(git describe --tags --always --dirty) \
-X main.commit=$(git rev-parse --short HEAD) \
-X main.date=$(date -u +%Y-%m-%d)" .
Builds without ldflags print a "development build" warning banner — cosmetic only.
Runtime dependencies
Required:
- BIRD ≥ 2.0.7 running with a control socket (default
/run/bird/bird.ctl)
Optional, per feature:
- bgpq4 — IRR prefix-list generation (
filter-irr,auto-as-set); queriesirr.irrd3.netby default, override withirr-server - RTR server — RPKI filtering. Defaults to the project's public RTR at
rtr.irrd3.net:3233; run your own with gortr and setrtr-server - PeeringDB — defaults to the project's public cache at
https://pdb.irrd3.net/api; override withpeeringdb-url(e.g.https://peeringdb.com/apior a local cache) - keepalived — VRRP output
Install
Debian/Ubuntu (apt repository)
curl -fsSL https://repo.xodo.net/xodo-archive-keyring.gpg -o /etc/apt/keyrings/xodo.gpg --create-dirs
echo "deb [signed-by=/etc/apt/keyrings/xodo.gpg] https://repo.xodo.net stable main" \
> /etc/apt/sources.list.d/xodo.list
apt update
apt install pathvector-ng
The package installs the pathvector binary and systemd units, and replaces:/conflicts: the upstream
pathvector package — you can drop it in on an existing install.
From a release archive or source
install -m0755 pathvector /usr/local/sbin/pathvector
install -m0640 /dev/null /etc/pathvector.yml # then edit it
mkdir -p /etc/bird /var/run/pathvector/cache
Then run pathvector generate -c /etc/pathvector.yml on a schedule (e.g.
0 */12 * * * in cron) to render, validate, and apply the BIRD config.
Migrating from upstream pathvector
- Install
pathvector-ng(the packagereplaces:/conflicts:upstream'spathvectorpackage, and provides apathvectorbinary in the same location). - Keep your existing
/etc/pathvector.yml— every upstream option is still valid. - New knobs are opt-in; see
docs/docs/configuration.mdorpathvector docs.
Branches and releases
dev— development branch. All PRs targetdev; every push builds a rollingdevprerelease.main— stable branch.devis merged intomainfor release; tagsv<major>.<minor>.<patch>onmainrun the BIRD version matrix and then GoReleaser, producingpathvector-ng.deb/.rpm/.tar.gzpackages and vendor platform images (Arista, Juniper, MikroTik, Cisco IOx).
Differences from upstream natesales/pathvector
- Every open issue/PR-class fix listed above — upstream is unmaintained
- New peer fields:
gateway,cost,l3vpn,source4,source6,vip-interface,prefix-prefs,as-prefs4,as-prefs6,extended-next-hop, named communities pathvector check(CI-safe config lint),pathvector restart,pathvector yang,pathvector verify-irr-policy,pathvector metricscommands- zappiehost improvements: policy-before-sanity import filter order, /32 and /128 blackholing with proper
RTD_BLACKHOLE, standard+large blackhole communities, sortedstatusoutput - Default import limits bumped to
1500000(v4) /1000000(v6) - Public infrastructure defaults point at project-hosted services instead of upstream's:
irr-server→irr.irrd3.net(IRRd),rtr-server→rtr.irrd3.net:3233(RPKI RTR),peeringdb-url→https://pdb.irrd3.net/api(PeeringDB cache). All three can be overridden inpathvector.yml go.modrequires Go 1.23; library code returns errors instead oflog.Fatalmid-pipeline
Everything else — peer options, filtering families, optimizer, plugins, VRRP/BFD/MRT — matches upstream. The
regenerated field reference is in docs/docs/configuration.md, or run pathvector docs.
Development
go build ./...
go vet ./...
go test ./pkg/... ./cmd/...
License
MIT — same as upstream. Original work © Nate Sales; modifications © their respective contributors (see git history).