/docs/3.8/ for archival purposes and is no longer updated.1. Overview
NetTopology Core runs as a single daemon, nettopo, that passively collects routing state and makes it queryable. It does not forward packets, does not install routes into the kernel FIB, and never modifies the configuration of the routers it observes.
BMP peers ─▶ ingest ─┐
├─▶ normalizer ─▶ snapshot store ─▶ CLI / HTTP API
MRT dumps ─▶ import ─┘Data enters through one of two paths:
- BMP (RFC 7854) — live sessions from routers. Preferred: near real-time, includes withdrawals and policy changes.
- MRT / RIB dumps — batch import of historical tables in bgpdump-compatible format. Used for backfilling and lab work.
The normalizer merges both sources into a single RIB view with full history (see rib_retention). Snapshots are written to snapshot_dir every snapshot_interval and can be queried with nettopo-cli or the HTTP API.
2. Requirements
| Component | Requirement |
|---|---|
| Operating system | Linux ≥ 4.19 (x86-64, aarch64), FreeBSD ≥ 13. macOS ≥ 12 compiles but is best-effort. |
| Memory | Rule of thumb: ~2 GB per 1M RIB entries, including history. |
| Disk | ~250 MB per 100k prefixes with 72h retention enabled. |
| Privileges | None in the default configuration. Local BGP peering on port 179 requires CAP_NET_RAW. |
3. Configuration
The daemon reads a single file, /etc/nettopo/nettopo.conf. The format is INI-like with brace blocks. Reload with SIGHUP or systemctl reload nettopo.
Example
# /etc/nettopo/nettopo.conf — example for a lab collector
listen_bmp = 0.0.0.0:1179
listen_api = 127.0.0.1:8421
log_level = info
log_file = /var/log/nettopo/bgp.log
rib_retention = 72h
snapshot_interval = 15m
snapshot_dir = /var/lib/nettopo
peer "edge01" {
remote_as = 64515
neighbor = 192.168.1.1
password = "hf7,2nNQp9" # MD5, optional
}Directives
| Directive | Type | Default | Description |
|---|---|---|---|
listen_bmp | addr:port | 0.0.0.0:1179 | BMP listener socket. |
listen_api | addr:port | 127.0.0.1:8421 | HTTP API bind address. |
log_level | enum | info | One of: debug, info, warn, err. |
log_file | path | syslog | Log destination; reopened on SIGHUP. |
rib_retention | duration | 72h | How long withdrawn prefixes stay queryable. |
snapshot_interval | duration | 15m | Background snapshot cadence. |
snapshot_dir | path | /var/lib/nettopo | Snapshot storage location. |
maxmind_db | path | unset | MaxMind ASNum database for enrichment. |
api_token | string | unset | Required for POST endpoints (X-Auth-Token header). |
nettopo --check-config.4. CLI reference
Commands
| Command | Description |
|---|---|
nettopo-cli peers list | Session table with state, uptime and prefix counts. |
nettopo-cli peers dump <asn> | Full RIB as received from a given peer. |
nettopo-cli route lookup <prefix> | Longest-prefix match against the local RIB. |
nettopo-cli table export --format=csv|json | Export the normalized RIB. |
nettopo-cli rpki validate <prefix> | Check a prefix/origin pair against the ROA set. |
nettopo-cli topology dot | Emit the AS-level graph as Graphviz DOT. |
nettopo-cli snapshot status | Show snapshot age, size and last write result. |
Signals
| Signal | Effect |
|---|---|
SIGHUP | Reload configuration, re-open the log file. |
SIGUSR1 | Force a snapshot flush. |
SIGTERM, SIGINT | Graceful shutdown: flush, close BMP sessions, exit. |
5. HTTP API
| Endpoint | Description |
|---|---|
GET /v1/health | Liveness, version, uptime. |
GET /v1/peers | BGP session table. |
GET /v1/routes?prefix=&peer= | RIB query, paginated (200 per page). |
GET /v1/rpki/status | Validator cache state and ROA counts. |
POST /v1/snapshot | Force a snapshot. Requires X-Auth-Token. |
Example
$ curl -s http://127.0.0.1:8421/v1/peers
[
{
"peer": "192.168.1.1",
"asn": 64515,
"state": "established",
"uptime_s": 1218401,
"prefixes_v4": 4123,
"prefixes_v6": 1842
}
]api_token and terminate TLS on a reverse proxy if remote access is required.6. Logging
Every line follows one format: <timestamp> [<level>] <module> <message>. The module is the internal subsystem that emitted the line (bgp, ospf, rib, rpki, store and others).
Rotation
The daemon does not rotate logs itself. A standard logrotate snippet ships in contrib/logrotate/:
/var/log/nettopo/*.log {
weekly
rotate 12
compress
missingok
postrotate
systemctl kill -s HUP nettopo.service
endscript
}7. FAQ
How is nettopo different from a full routing daemon?
Routing daemons such as FRR or Bird build a RIB in order to forward traffic. nettopo builds a RIB in order to answer questions about it — who announced what, when, and through which AS path. It never programs the kernel and performs no best-path selection of its own beyond mirroring what its sources report.
Does the daemon need root privileges?
No. In the default configuration it only opens TCP ports above 1024 and writes to its own directories. Local BGP peering on port 179 requires CAP_NET_RAW: setcap cap_net_raw+ep /usr/local/bin/nettopo.
Which routers can feed it?
Anything that speaks BMP (RFC 7854): FRR ≥ 7.5, Bird 2.x, Cisco IOS-XR, Juniper Junos, Nokia SR OS. For everything else there is MRT dump import.
Is Windows supported?
No, and it is not on the roadmap. It compiles under WSL2, but nobody on the team tests it.
Where is the web interface?
There is none on purpose. The workspace view on the landing page is rendered from the HTTP API by a separate contrib project, nettopo-web. Use nettopo-cli or the API directly.
How much memory does a full table need?
Rule of thumb: ~2 GB per 1M IPv4 prefixes including history. A full Internet table (≈950k prefixes) with 72h retention fits comfortably in 2.5 GB.
Found an error in this page? Open an issue or edit the sources under
docs/ in the repository.