GET /bgp/routes
Search BGP best paths (engine-computed) with prefix filtering and pagination.
Auth: all authenticated roles
Query params:
| Param |
Type |
Description |
as_id |
UUID |
Filter by autonomous system |
prefix |
CIDR |
Exact prefix or search base (e.g. 10.0.0.0/8) |
match |
string |
Match mode: empty (exact), "longest", "covered" |
device_id |
UUID |
Filter by next-hop device (next_hop_device_id) |
selecting_device_id |
UUID |
Filter by selecting device perspective (device_id -- which BMP target produced this best-path) |
origin_as |
int |
Filter by origin AS number |
next_hop |
IP |
Filter by next-hop address |
community |
string |
Filter by community string (substring match) |
af |
string |
Filter by address family: ipv4 or ipv6 (filters by family(prefix)) |
limit |
int |
Max results (default 50, max 10000) |
offset |
int |
Pagination offset (default 0, capped at 100,000) |
at |
RFC 3339 |
As-of-T: return best-paths from bgp_best_path_history at this time instead of the live table. Malformed → 400. |
Note: Offset is capped at 100,000 to prevent full-table scans on large RIBs. Clients needing deeper pagination should narrow results with prefix/origin_as/next_hop filters.
Response: 200 OK
{
"routes": [
{
"as_id": "uuid",
"routing_domain_id": "uuid",
"prefix": "203.0.113.0/24",
"device_id": "uuid",
"device_hostname": "rr1",
"next_hop": "198.51.100.2",
"next_hop_device_id": "uuid",
"origin_as": 65099,
"as_path": "65002 65099",
"local_pref": 100,
"med": 0,
"communities": "65001:100 65001:200",
"source_peer_id": "uuid",
"igp_metric": 20,
"source": "loc_rib",
"ecmp_count": 1,
"updated_at": "2026-03-18T12:00:00Z",
"path_count": 3
}
],
"total": 850000,
"unique_prefixes": 335,
"limit": 50,
"offset": 0
}
Note: path_count is the number of distinct received paths for this prefix across all peers (via LEFT JOIN LATERAL on bgp_rib_entry). Value is 0 when no RIB entries exist (e.g., rib_mode = 'loc_rib'). Used by the frontend to show an expand chevron on rows with multiple paths.
Note: source and ecmp_count are always present. source is "loc_rib" when the best path was reported directly from the router's Loc-RIB, or "inferred" when the engine ran its own RFC 4271 decision process over received paths; ecmp_count is the number of equal-cost paths the winner tied with. igp_metric (the IGP cost to the next hop) is omitempty — omitted when unknown. deciding_step (omitempty) names the RFC 4271 §9.1 step the selection resolved at against the strongest runner-up (only_path, eligibility, local_pref, as_path_len, origin, med, ebgp_over_ibgp, igp_cost, router_id, tie, undetermined — the selection-funnel vocabulary): a router_id/tie row is one where a router applying RFC 5004 prefer-oldest (IOS's default; ~12 % of a real DN42 table, measured) may install a different next hop — the UI badges these rows "tie-break". Absent on rows written before the column existed.
total counts best-path rows — one per selecting device × prefix (each BMP
target independently runs its own RFC 4271 decision process), so a prefix known
to six route reflectors contributes six rows (device_hostname identifies the
selecting router). unique_prefixes counts distinct prefixes over the whole
filtered set.
When at is supplied, rows come from the best-path history as-of-T; a notice
string is added (and total is 0) when the window has no recorded routes.