Skip to content

bgp rib

Thomas Mangin edited this page Aug 16, 2026 · 12 revisions

Pre-Alpha. This page describes behavior that may change.

The main BGP RIB store and best-path selection engine.

Category

Storage.

Configuration

Load the plugin and bind it to peers.

plugin {
    internal rib { use bgp-rib }
}

bgp {
    peer upstream {
        connection { remote { ip 10.0.0.1; } }
        session    { asn { remote 65001; } }
        process rib { receive [ update state ]; send [ update ]; }
    }
}

receive [ update state ] lets the RIB see routes arriving and peer state changes. send [ update ] lets it send routes back out after best-path selection (when acting as a router) or forwarding (when paired with bgp-rs).

Behaviour

bgp-rib stores routes per prefix per family and runs RFC 4271 section 9.1.2 best-path selection when multiple paths exist for a prefix. N-way multipath is supported: when bgp/multipath is configured with maximum-paths and relax-as-path, multiple equal-cost paths are selected and installed. The output is fed to sysrib (unified Loc-RIB) for cross-protocol admin-distance selection and then to fib-kernel and/or fib-vpp for forwarding table installation. The best-path order is LOCAL_PREF, AS_PATH length, ORIGIN, MED (same neighbour AS only), eBGP over iBGP, IGP cost (not implemented), lowest router-id, lowest peer address.

When candidates tie under multipath selection, the winner and its equal-cost sibling next hops both go into the shared Loc-RIB, and the system RIB emits one ECMP group to the active FIB backend. A membership-only change, such as one equal-cost peer going away, updates the installed group without the winning peer having to change. show rib reports the primary next-hop plus an ecmp-paths array; the two together are the complete installed next-hop set.

A route naming this speaker is not a candidate

RFC 4271 Section 5.1.3 states that a BGP speaker shall not install a route with itself as the next hop, because the route tells it to forward through itself. Ze removes such a route from best-path candidacy rather than refusing it at install, so a sound alternative still wins instead of the prefix being blackholed. That is what Section 9.1.2 already does with a next hop it cannot resolve.

"Itself" is the set of local addresses of the sessions this speaker holds, derived from the peer metadata the RIB already receives on every peer event and rebuilt when a session is added or removed. There is no second source of truth and no host-interface read.

Only Adj-RIB-In entries are tested, so every candidate is a route another speaker sent. Static, connected and redistributed routes never enter that map and are untouched. Each exclusion logs the peer, the next hop, the family and the section, so a missing route is visible rather than silent.

The next hop show renders

show bgp rib best and show bgp rib received read the legacy IPv4 NEXT_HOP attribute (type 3) first, then fall back to the next hop stored in MP_REACH_NLRI. Every IPv6 unicast route and every RFC 5549 extended next hop carries its address in MP_REACH only, so without the fallback those routes printed no next hop at all.

The RIB uses a two-level ribInPool keyed by ProtocolID, enabling multi-source support. BGP peers and BMP-monitored peers store routes under separate ProtocolIDs, so best-path selection only iterates real BGP routes while BMP routes are visible through the looking glass without additional filtering.

Internally, the RIB uses BART (Binary Adaptive Radix Tree) storage with per-family NLRI split registry. Non-CIDR families (EVPN, FlowSpec, etc.) get an opaque-map backend. bestPathRecord is packed into uint64 with a shared cross-family interner for memory efficiency. The Loc-RIB shards by prefix hash and the peer-keyed map lock is split from the main RIB mutex to keep it off the hot path.

The plugin also handles the RIB half of Graceful Restart: holding stale routes during a peer restart, clearing them on EOR, and purging any that did not come back.

Compact ribOut storage

The per-peer Adj-RIB-Out (ribOut) stores a 16-byte entry per peer per route: a MsgID (8 B), an attribute pool handle (4 B), a stale level (1 B), and padding. The wire attribute bytes are deduplicated in a shared pool (pool.RibOut), so the same UPDATE sent to N peers stores one pool copy and N four-byte handles instead of N full attribute blobs. The full *Route is reconstructed on demand on cold paths only (replay, show, refresh) by parsing the wire bytes back out of the pool. Source-peer tracking uses a separate refcounted map with one entry per unique route, not per destination peer. See performance for the measured per-route numbers.

Route replay on reconnect

The plugin replays stored routes when a peer reconnects. A batch of fixes landed recently (three bugs in the sent-event path: dispatch routing by Direction instead of EventType, missing WireUpdate on sent events, and a format mismatch for text-codec routes). The sync is now event-driven rather than timer-driven, and the graceful-restart, LLGR, and refresh-on-reconnect test scenarios all pass reliably.

A peer's first session is not replayed. Its Adj-RIB-Out is empty by definition (RFC 4271 Section 3.2), so anything recorded there when the peer-up event is processed is this session's own send, arriving early because the forward's sent event is processed before the state event. Replaying it produced a duplicate that also lacked ORIGINATOR_ID, CLUSTER_LIST, and the LLGR depreference. Re-established sessions, the case the replay exists to serve, are unaffected.

Known residual: a re-established session cannot yet make that distinction. Neither the state event nor the sent event carries session identity, and a message id does not discriminate, because an old UPDATE may legitimately be forwarded on the new session.

Metrics

Registered via ConfigureMetrics. Includes both route counts and attribute-pool statistics.

Metric Type Meaning
ze_rib_routes_in_total gauge Total Adj-RIB-In route count across all peers.
ze_rib_routes_out_total gauge Total Adj-RIB-Out route count across all peers.
ze_rib_routes_in{peer} gauge Adj-RIB-In route count per peer.
ze_rib_routes_out{peer} gauge Adj-RIB-Out route count per peer.
ze_rib_route_inserts_total{peer,family} counter Routes inserted into Adj-RIB-In.
ze_rib_route_withdrawals_total{peer,family} counter Routes withdrawn from Adj-RIB-In.
ze_attr_pool_intern_total{pool} gauge Total Intern() calls per attribute pool.
ze_attr_pool_dedup_hits_total{pool} gauge Intern() dedup hits per pool.
ze_attr_pool_slots_used{pool} gauge Active slots per pool.

See plugin metrics.

RPF lookup

The RIB supports Reverse Path Forwarding queries via longest-prefix-match on the sharded Loc-RIB. This is exposed as a CLI command for external multicast daemons (PIM-SM) to resolve upstream next-hops.

ze> show bgp rib rpf ipv4/multicast 10.0.1.5

The command is show bgp rib rpf <family> <source-addr>. It returns the best-path entry for the longest matching prefix, including next-hop, AS path, and origin peer.

Interactions

  • bgp-gr depends on bgp-rib for the stale route handling.
  • bgp-persist snapshots the RIB to disk.
  • bgp-adj-rib-in feeds raw received updates into the RIB.
  • sysrib consumes best-path change events from the RIB.

Source

main/internal/component/bgp/plugins/rib/

Home

About

First Steps

Configuration

Operation

Interfaces

Plugins

Plugin Development

Chaos Testing

Blueprints

Development

Reference

Clone this wiki locally