- Rust 1.95+ (edition 2024 — workspace MSRV; raised to 1.95 because the bundled SQLite build (libsqlite3-sys) uses the
cfg_select!macro stabilized in Rust 1.95) protobuf-compiler(apt-get install protobuf-compileron Debian/Ubuntu)- Linux x86_64 or aarch64 (primary targets)
- macOS works for development but is not CI-tested
- Docker + containerlab for interop tests
git clone https://github.com/lance0/rustbgpd
cd rustbgpd
cargo build --workspace # builds rustbgpd + rustbgpctl
cargo test --workspacecargo fmt # Format
cargo clippy -- -D warnings # Lint with warnings as errors
cargo test --workspace # All testsAll PRs must pass (enforced by CI in .github/workflows/ci.yml):
cargo fmt --checkcargo clippy --workspace --all-targets -- -D warningscargo test --workspace
We ship a .pre-commit-config.yaml that runs cargo fmt and
cargo clippy --workspace --all-targets -- -D warnings on every
commit and cargo test --workspace --lib on every push. The
clippy invocation matches CI exactly so a clean commit is a clean
PR. cargo test is gated to pre-push (not pre-commit) so commits
stay fast.
Set it up once:
# Recommended: prek (fast Rust port, drop-in compatible)
cargo install --locked prek
prek install
# Or via standalone installer (no Rust toolchain needed)
curl -LsSf https://github.com/j178/prek/releases/latest/download/prek-installer.sh | sh
# Or with the original Python pre-commit
pipx install pre-commit
pre-commit install --hook-type pre-commit --hook-type pre-pushAfter install, hooks run automatically. To run them manually
against staged files: prek run (or pre-commit run).
- No
unsafecode without aSAFETYcomment and strong justification - Keep lines under 100 characters when possible
#![deny(unsafe_code)]on every crate — this is enforced, not advisory
Any postmortem doc that cites raw data — soak runs, scale tests,
interop captures — copies the load-bearing artifacts into
docs/artifacts/<topic>/<run-id>/ and references them by
repo-relative path. The doc body either inlines the load-bearing
numbers or links the in-repo files; it must not depend on machine-
specific paths or "preserved on host X" language. Host-side run
trees (e.g., tests/soak/runs/...) stay gitignored — they're
per-machine working directories, not the published record. A
README.md next to the artifacts explains what each file is and
points back at the postmortem.
- Start with a verb: Add, Fix, Update, Remove, Refactor, Bump
- Keep the first line under 72 characters
- Use the body for context when needed
Examples:
Add NOTIFICATION encode/decode to wire crate
Fix hold time negotiation edge case for zero values
Update FRR interop topology to 10.3.1
Refactor FSM event dispatch to use match exhaustiveness
Version bumps:
Bump version to v0.1.0
Roadmap/docs updates:
roadmap: add M1 exit criteria
docs: update interop matrix for BIRD 2.16
src/main.rs # Binary entry point — config, wiring, shutdown
src/config/ # TOML config types, loading, validation
src/metrics_server.rs # Prometheus /metrics HTTP endpoint
crates/
wire/ # BGP codec — zero internal deps, independently publishable
fsm/ # RFC 4271 state machine — pure, no I/O
transport/ # Tokio TCP glue — session runtime, BMP event emission
rib/ # RIB data structures, best-path selection, route distribution
policy/ # Match + modify + filter engine: prefix, community, AS_PATH regex, RPKI
rpki/ # RPKI origin validation: RTR client (RFC 8210), VRP table
bmp/ # BMP exporter (RFC 7854): codec, per-collector client, manager
mrt/ # MRT dump export (RFC 6396): codec, writer, manager
evpn/ # EVPN local VTEP domain model (RFC 7432 / RFC 8365 / RFC 9136): EvpnInstance, IpVrf, RouteTarget, origination + projection state machines (kernel-free)
evpn-linux/ # Linux kernel dataplane for EVPN VTEP mode (#[cfg(target_os = "linux")]): rtnetlink reconciler, FDB / link / IP-VRF dumps, RTNLGRP_NEIGH classifier, RTNLGRP_IPV4_ROUTE / RTNLGRP_IPV6_ROUTE route observer (Gate 9 slice 6), L3 FIB programming (Gate 9 slice 6 PR B), nexthop_raw raw-netlink FDB-NHG primitive + group_state refcount + nh_id_alloc tag bits (ADR-0059 aliasing-ECMP)
api/ # gRPC server (tonic) — 11 services
telemetry/ # Prometheus metrics + structured tracing
cli/ # rustbgpctl — gRPC CLI with human-readable and JSON output
proto/ # gRPC proto definitions (rustbgpd.v1)
tests/interop/ # Containerlab topologies and configs
docs/ # Design doc, RFC notes, interop results, ADRs
These are not guidelines — they are enforced invariants:
wiredepends on nothing internal — it is a pure codec libraryfsmdepends only onwiretypesfsmnever imports tokio, never touches I/Opolicydepends only onwirerpkidepends only onwirebmpandtelemetryhave no internal dependenciesribdepends onwire,policy,telemetry, andrpkitransportowns BGP peer session I/O and drives the FSM — it depends onwire,fsm,rib,policy,telemetry, andbmpevpnis the local-VTEP domain crate — depends only onwire, never onribortransport, never programs the kernelevpn-linuxis the Linux kernel dataplane for EVPN VTEP mode — depends only onevpn, never onribortransportclihas no internal crate dependencies (client-only proto stubs)
- Fork the repository
- Create a feature branch from
main - Make changes, ensure all checks pass
- Submit PR with a clear description
- Bug fixes: Steps to reproduce, how you verified the fix
- New protocol behavior: RFC citation and proposed interop test
- New features: Update CHANGELOG.md and relevant docs
- Architectural changes (open an issue)
- New protocol extensions (open an issue with RFC citation)
- Changes to design constraints (these are non-negotiable — read DESIGN.md)
Every protocol feature must be validated against real peers in containerlab. Unit tests are necessary but not sufficient.
# Deploy a test topology
containerlab deploy -t tests/interop/m0-frr.clab.yml
# Tear down
containerlab destroy -t tests/interop/m0-frr.clab.ymlUnless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as MIT/Apache-2.0, without any additional terms or conditions.