-
Notifications
You must be signed in to change notification settings - Fork 2
route reflection
Pre-Alpha. This page describes behavior that may change.
Ze operates as both a route server (RFC 7947) and an iBGP route reflector (RFC 4456). Route serving is the bgp-rs plugin driven by process bindings; it forwards every received route to every other peer with zero-copy wire optimization when peers share an encoding context. iBGP route reflection is a session-level option (session/route-reflector-client plus session/cluster-id) that turns an iBGP peer into a reflector client and applies the RFC 4456 rules (ORIGINATOR_ID, CLUSTER_LIST, client vs non-client forwarding).
This page covers both. Pick the mode that matches the deployment: a route server at an IXP or transit exchange, or a route reflector inside an autonomous system.
An iBGP peer is turned into a reflector client by setting session/route-reflector-client true; on it. Ze will then apply the RFC 4456 forwarding rules to routes learned from that peer: routes from a client are forwarded to all other peers (clients and non-clients), routes from a non-client are forwarded to clients only, and the ORIGINATOR_ID plus CLUSTER_LIST attributes are handled automatically.
bgp {
router-id 10.0.0.254;
session {
asn { local 65000; }
cluster-id 10.0.0.254; # optional; defaults to router-id
}
peer client-a {
connection { remote { ip 10.0.0.1; } }
session {
asn { remote 65000; } # iBGP: same AS
route-reflector-client true;
family { ipv4/unicast { prefix { maximum 1000000; } } }
}
}
peer client-b {
connection { remote { ip 10.0.0.2; } }
session {
asn { remote 65000; }
route-reflector-client true;
family { ipv4/unicast { prefix { maximum 1000000; } } }
}
}
}
- ORIGINATOR_ID. Set to the source peer's Router ID if the attribute is absent on ingress. If it is already present (the route has been reflected before), the existing value is preserved.
-
CLUSTER_LIST. Prepended with the local cluster ID (from
session/cluster-id, falling back tobgp/router-id). If CLUSTER_LIST is absent on ingress it is created. Existing values are preserved. - Loop detection. On ingress, if ORIGINATOR_ID matches the local Router ID, or the local cluster ID is in CLUSTER_LIST, the route is treated as a loop and dropped. This is the RFC 4456 Section 8 check and runs as part of the built-in loop-detection filter (see route filters).
-
CLUSTER_LIST cluster-id. If you set
session/cluster-idon the peer, the same value is used for egress prepending AND ingress loop detection. Ze keeps the two in sync automatically, so you only need to configure it once.
| Source peer | Destination peer | Forwarded? |
|---|---|---|
| Client | Any iBGP peer (client or non-client) | Yes |
| Non-client | Client | Yes |
| Non-client | Non-client | No (RFC 4456 — non-clients rely on the full iBGP mesh to exchange among themselves) |
| eBGP | Any iBGP peer | Yes |
A peer with route-reflector-client false (the default) is a non-client. Mixing clients and non-clients on the same reflector is the normal setup for a partial-mesh deployment.
Set the same cluster-id on every reflector in the cluster. Ze's CLUSTER_LIST prepend uses that value, and the CLUSTER_LIST loop check on ingress uses the same value, so routes bounce between cluster members only when the cluster ID really is different.
The route server model uses the bgp-rs plugin, bound per peer via process. It forwards every received route to every other peer with no best-path selection, which is what IXP members expect: the server is a transparent bus and the members run their own policy downstream.
# bgp-rs and bgp-adj-rib-in are internal plugins; no separate "plugin { }" block is
# needed unless you want to override defaults.
bgp {
router-id 10.0.0.254;
session { asn { local 65000; } }
peer client-a {
connection { remote { ip 10.0.0.1; } }
session {
asn { remote 65001; }
family { ipv4/unicast { prefix { maximum 1000000; } } }
}
process bgp-rs { receive [ update ]; send [ update ]; }
process bgp-adj-rib-in { receive [ update state ]; }
}
peer client-b {
connection { remote { ip 10.0.0.2; } }
session {
asn { remote 65002; }
family { ipv4/unicast { prefix { maximum 1000000; } } }
}
process bgp-rs { receive [ update ]; send [ update ]; }
process bgp-adj-rib-in { receive [ update state ]; }
}
}
Every peer gets both plugin bindings. bgp-rs does the forwarding. bgp-adj-rib-in stores received routes so they can be replayed when a peer reconnects.
The route server forwards every received route to every other peer. There is no best-path selection. This is RFC 7947 and it is what IXP members expect: the IXP is a transparent bus that propagates routes between members, and the members run their own policy.
The combination of the route server model and ADD-PATH is what lets every downstream make its own best-path decision. Without ADD-PATH you can only forward one path per prefix to each client; with ADD-PATH every path is available. See ADD-PATH.
When two peers negotiate identical capabilities (same ADD-PATH mode, same ASN format, same extended-message support), they share the same encoding context, identified by a ContextID. Routes between peers with matching contexts are forwarded as raw wire bytes: no parse, no rebuild, no allocation. The reactor looks up the cached message, confirms the contexts match, and ships the bytes straight back out.
This is the fast path and the reason a route server with many identically-configured clients runs well on Ze. When contexts differ (for example, one peer without ADD-PATH forwarding to one with ADD-PATH), a progressive build walks the cached attributes and re-encodes for the destination.
Each destination peer has its own long-lived forwarding worker goroutine with a buffered channel. When a destination peer is slower than the update rate, the channel absorbs short bursts (default capacity 4096 items). If the channel fills, items go into a per-worker overflow buffer, and the worker fires a congestion event visible in logs and Prometheus.
The overflow uses a two-tier pool. Per-peer pools (64 slots) absorb steady-state traffic. A shared MixedBufMux pool, auto-sized from peer prefix maximums or overridable via ze.fwd.pool.size, bounds overflow memory across every peer. Routes are never dropped: missing a route update is worse than using extra memory. When a peer catches up and the channel drains below 25 %, congestion clears.
The Prometheus metrics that show this behaviour:
| Metric | Meaning |
|---|---|
ze_bgp_pool_used_ratio |
Global overflow pool utilisation. |
ze_bgp_overflow_items{peer} |
Items in a per-destination overflow buffer. |
ze_bgp_overflow_ratio{source} |
Per-source overflow ratio. |
If ze_bgp_pool_used_ratio is above 0.8 in steady state, you are close to congestion teardown and should investigate which peer is lagging.
When a peer reconnects, the route server replays every stored route from the other peers. The replay is three phases:
- Full snapshot replay from the Adj-RIB-In.
- Delta loop that catches routes received during the replay.
- End-of-RIB sent when the replay has caught up.
A batch of bug fixes in 2026 closed three latent bugs in this path (wrong-direction dispatch for sent events, nil WireUpdate on reflected UPDATEs, and wrong format when the cached route came from the text codec). The event delivery on replay is now event-driven rather than a fixed sleep, and graceful restart, LLGR, and refresh-on-reconnect tests that had flaky timeouts all pass reliably.
bgp-rs plugin. Needs receive [ update ] (so it sees routes coming in) and send [ update ] (so it can forward routes back out). Every peer that participates in the route server must have these bindings.
bgp-adj-rib-in plugin. Stores received routes for replay on peer reconnect. Needs receive [ update state ]. If you do not bind it, reconnecting peers will not get a replay and convergence will be slower.
Routes in transit are exposed through the cache surface.
cache list
cache forward <id> <peer>
cache release <id>
Use these when you want to inspect or reroute a specific cached message. They are more of a debugging surface than a day-2 operator tool, but they are the mechanism that lets a plugin take control of forwarding decisions for a specific UPDATE.
When bgp-rs is not loaded, routes are not forwarded between peers. The bgp-rib plugin (if loaded) stores routes and runs best-path selection, but it does not re-advertise them. Ze becomes a passive route collector in that mode. Load bgp-rs when you want forwarding.
| Aspect | Route reflector (RFC 4456) | Route server (RFC 7947) |
|---|---|---|
| Intended topology | iBGP inside an AS | eBGP between members at an IXP |
| Best-path selection | Yes, then forward best path per prefix (or all paths with ADD-PATH) | No, forward every path |
| Modifies NEXT_HOP | By default yes on eBGP → iBGP borders (routable inside AS) | No, forward unchanged (RFC 7947) |
| Adds ORIGINATOR_ID / CLUSTER_LIST | Yes | No |
| Config knob |
session/route-reflector-client, session/cluster-id
|
process bgp-rs binding, process bgp-adj-rib-in binding |
| Plugin | Built-in reactor logic |
bgp-rs plugin |
Pick based on intent: if you want to distribute routes inside an AS without a full iBGP mesh, it is a route reflector. If you want a transparent route exchange where members build their own RIBs from every available path, it is a route server.
- ADD-PATH for the capability that makes route servers useful.
-
Peers — Session policy for the
route-reflector-client,cluster-id, andnext-hopknobs. - BGP peers for the surrounding peer configuration.
- Route server blueprint for an end-to-end worked example.
- Route filters for the loop-detection filter that enforces RFC 4456 Section 8 checks.
Adapted from main/docs/guide/route-reflection.md.
Unreviewed draft. This wiki was authored in bulk and has not been reviewed. File corrections on the issue tracker.
- Overview
- YANG Model
- Editor Workflow
- Archive and Rollback
- System
- Interfaces
- VRRP
- BFD
- FIB
- OSPF
- IS-IS
- MPLS / LDP / RSVP-TE
- RSVP-TE
- SRv6
- Static Routes
- Policy Routing
- Firewall
- Traffic Control
- Class of Service
- L2TP/PPP
- PPPoE
- VPP Data Plane
- RPKI
- IPsec VPN
- TACACS+ AAA
- RADIUS AAA
- AS112 DNS
- Authorization
- Fleet
- BGP
- Starting and Stopping
- Show Commands
- Monitoring
- Flow Export
- DDoS Mitigation
- Anomaly Detection
- Health Checks
- Audit Trail
- Production Diagnostics
- Logging
- Operational Reports
- Healthcheck
- Self-Update
- Zero-Touch Provisioning
- MRT Analysis
- Upgrade and Restart
- Storage
- Policy
- Core
- Resilience
- Validation
- Capabilities
- Address Families
- Protocol
- Subsystems
- Infrastructure
- Route Server at an IXP
- Transit Edge with RPKI
- Public Looking Glass
- ExaBGP Migration Walkthrough
- FlowSpec Injection
- Chaos-Tested Peering
- AS Path Topology