-
Notifications
You must be signed in to change notification settings - Fork 460
Route Reflection
Route reflection is a BGP scaling technique that reduces the number of required IBGP (Internal BGP) peering sessions in large networks. This guide covers how to use ExaBGP as a route reflector or route reflector client.
- Overview
- Route Reflection Concepts
- Route Reflector Configuration
- Route Reflector Client Configuration
- Cluster Configuration
- Loop Prevention
- Best Practices
- Troubleshooting
- See Also
Important: ExaBGP does NOT manipulate the routing table (RIB/FIB). When using ExaBGP as a route reflector, it reflects routes between BGP peers but does not install routes into the system routing table.
In traditional IBGP, all routers must peer with each other (full mesh). For n routers, this requires n(n-1)/2 peering sessions:
- 5 routers: 10 sessions
- 10 routers: 45 sessions
- 50 routers: 1,225 sessions
- 100 routers: 4,950 sessions
Route reflection allows routers to peer with a route reflector instead of each other, dramatically reducing the number of sessions.
Traditional IBGP (Full Mesh): Route Reflection:
R1 βββββββ R2 R1 βββββ
β β² β± β R2 ββββ€
β β² β± β R3 ββββΌβββ RR (Route Reflector)
β β± β² β R4 ββββ€
β β± β² β R5 βββββ
R3 βββββββ R4
β β 5 sessions (vs 10 in full mesh)
βββββR5ββββ
10 sessions
- Route Reflector (RR) - Router that reflects routes to clients
- Route Reflector Client - Router that peers with the RR
- Non-Client - IBGP peer that is not a client (full mesh with RR)
- Cluster - Route reflector and its clients
- Cluster ID - Identifier for a cluster (prevents loops)
- Originator ID - Original router that advertised the route
A route reflector follows these rules when receiving routes from IBGP peers:
1. Routes from Clients:
- Reflect to all other clients in the cluster
- Reflect to all non-client IBGP peers
- Advertise to all EBGP peers
2. Routes from Non-Clients:
- Reflect to all clients in the cluster
- Do NOT reflect to other non-clients
- Advertise to all EBGP peers
3. Routes from EBGP peers:
- Reflect to all clients
- Advertise to all non-client IBGP peers
- Advertise to all other EBGP peers
Route reflectors add special BGP attributes to prevent loops:
- ORIGINATOR_ID (Type Code 9) - Router ID of the route originator
- CLUSTER_LIST (Type Code 10) - List of cluster IDs the route has traversed
Configure ExaBGP as a route reflector.
# /etc/exabgp/exabgp.conf
# ExaBGP as Route Reflector
# Client 1
neighbor 192.0.2.11 {
router-id 192.0.2.1;
local-address 192.0.2.1;
local-as 65001;
peer-as 65001;
# This peer is a route reflector client
route-reflector-client;
family {
ipv4 unicast;
ipv6 unicast;
}
}
# Client 2
neighbor 192.0.2.12 {
router-id 192.0.2.1;
local-address 192.0.2.1;
local-as 65001;
peer-as 65001;
# This peer is a route reflector client
route-reflector-client;
family {
ipv4 unicast;
ipv6 unicast;
}
}
# Client 3
neighbor 192.0.2.13 {
router-id 192.0.2.1;
local-address 192.0.2.1;
local-as 65001;
peer-as 65001;
# This peer is a route reflector client
route-reflector-client;
family {
ipv4 unicast;
ipv6 unicast;
}
}
# Non-client IBGP peer (traditional full mesh with this peer)
neighbor 192.0.2.20 {
router-id 192.0.2.1;
local-address 192.0.2.1;
local-as 65001;
peer-as 65001;
# No route-reflector-client directive = non-client
family {
ipv4 unicast;
ipv6 unicast;
}
}neighbor 192.0.2.11 {
router-id 192.0.2.1;
local-address 192.0.2.1;
local-as 65001;
peer-as 65001;
route-reflector-client;
# Route reflection for multiple address families
family {
ipv4 unicast;
ipv6 unicast;
ipv4 mpls-vpn;
ipv6 mpls-vpn;
l2vpn evpn;
}
}Configure ExaBGP as a route reflector client.
# /etc/exabgp/exabgp.conf
# ExaBGP as Route Reflector Client
# Peer with route reflector
neighbor 192.0.2.1 {
router-id 192.0.2.11;
local-address 192.0.2.11;
local-as 65001;
peer-as 65001;
# No special directive needed on client side
# Route reflector marks this as a client
family {
ipv4 unicast;
ipv6 unicast;
}
}
# API process to announce routes
process announce {
run /etc/exabgp/announce.py;
encoder text;
}
neighbor 192.0.2.1 {
api {
processes [ announce ];
}
}#!/usr/bin/env python3
# /etc/exabgp/announce.py
# Route reflector client announcing routes
import sys
import time
# Announce routes to route reflector
# Route reflector will reflect to other clients
routes = [
"198.51.100.0/24",
"203.0.113.0/24",
]
for route in routes:
print(f"announce route {route} next-hop self", flush=True)
sys.stderr.write(f"Announced {route} to route reflector\n")
# Keep process running
while True:
time.sleep(60)A cluster consists of a route reflector and its clients. Cluster IDs prevent routing loops.
# /etc/exabgp/exabgp.conf
# Route Reflector with Cluster ID
neighbor 192.0.2.11 {
router-id 192.0.2.1;
local-address 192.0.2.1;
local-as 65001;
peer-as 65001;
route-reflector-client;
# Cluster ID (typically the RR's router ID)
cluster-id 192.0.2.1;
family {
ipv4 unicast;
}
}For redundancy, deploy multiple route reflectors in the same cluster:
RR1 (192.0.2.1)
/ \
/ \
Client1 Client2
\ /
\ /
RR2 (192.0.2.2)
Both RRs must use the SAME cluster ID:
# RR1 Configuration
neighbor 192.0.2.11 {
router-id 192.0.2.1;
local-address 192.0.2.1;
local-as 65001;
peer-as 65001;
route-reflector-client;
cluster-id 192.0.2.254; # Same cluster ID on both RRs
family {
ipv4 unicast;
}
}
# RR2 Configuration
neighbor 192.0.2.11 {
router-id 192.0.2.2;
local-address 192.0.2.2;
local-as 65001;
peer-as 65001;
route-reflector-client;
cluster-id 192.0.2.254; # Same cluster ID on both RRs
family {
ipv4 unicast;
}
}In very large networks, use hierarchical route reflection:
Top-Level RR
/ \
Regional RR1 Regional RR2
/ | \ / | \
C1 C2 C3 C4 C5 C6
Different clusters use different cluster IDs:
# Top-Level RR Configuration
neighbor 192.0.2.10 { # Regional RR1
router-id 192.0.2.1;
local-address 192.0.2.1;
local-as 65001;
peer-as 65001;
route-reflector-client;
cluster-id 192.0.2.1; # Top-level cluster ID
family {
ipv4 unicast;
}
}
# Regional RR1 Configuration
neighbor 192.0.2.11 { # Client 1
router-id 192.0.2.10;
local-address 192.0.2.10;
local-as 65001;
peer-as 65001;
route-reflector-client;
cluster-id 192.0.2.10; # Regional cluster ID
family {
ipv4 unicast;
}
}Route reflectors use two BGP attributes to prevent routing loops:
The ORIGINATOR_ID is the router ID of the router that originally advertised the route into IBGP.
Loop Prevention Rule: If a router receives a route with its own router ID in the ORIGINATOR_ID, it rejects the route.
The CLUSTER_LIST is a list of cluster IDs the route has traversed.
Loop Prevention Rule: If a route reflector receives a route with its own cluster ID in the CLUSTER_LIST, it rejects the route.
RR1 (Cluster 192.0.2.1)
β
β reflects route with:
β ORIGINATOR_ID = 192.0.2.11
β CLUSTER_LIST = [192.0.2.1]
βΌ
RR2 (Cluster 192.0.2.2)
β
β reflects route with:
β ORIGINATOR_ID = 192.0.2.11
β CLUSTER_LIST = [192.0.2.1, 192.0.2.2]
βΌ
RR1 (Cluster 192.0.2.1)
β
ββ REJECTS route (own cluster ID in CLUSTER_LIST)
Check ExaBGP logs for rejected routes:
tail -f /var/log/exabgp/exabgp.log | grep -i "cluster\|originator"Deploy at least 2 route reflectors per cluster for redundancy:
# Client peers with both RRs
neighbor 192.0.2.1 { # RR1
router-id 192.0.2.11;
local-address 192.0.2.11;
local-as 65001;
peer-as 65001;
family {
ipv4 unicast;
}
}
neighbor 192.0.2.2 { # RR2
router-id 192.0.2.11;
local-address 192.0.2.11;
local-as 65001;
peer-as 65001;
family {
ipv4 unicast;
}
}All route reflectors in the same cluster MUST use the same cluster ID:
# GOOD: Same cluster ID
# RR1: cluster-id 192.0.2.254
# RR2: cluster-id 192.0.2.254
# BAD: Different cluster IDs
# RR1: cluster-id 192.0.2.1
# RR2: cluster-id 192.0.2.2For large networks, design a hierarchical route reflection architecture:
- Small networks (<50 routers): Single cluster, 2+ RRs
- Medium networks (50-500 routers): 2-3 clusters, 2+ RRs per cluster
- Large networks (>500 routers): Hierarchical, 3+ levels
Route reflectors are critical infrastructure. Monitor them carefully:
#!/usr/bin/env python3
# /etc/exabgp/rr-monitor.py
import sys
import json
client_count = 0
routes_reflected = 0
while True:
line = sys.stdin.readline()
if not line:
break
try:
data = json.loads(line)
if data.get('type') == 'state':
state = data['neighbor']['state']
peer = data['neighbor']['address']['peer']
if state == 'up':
client_count += 1
sys.stderr.write(f"Client {peer} connected (total: {client_count})\n")
elif state == 'down':
client_count -= 1
sys.stderr.write(f"Client {peer} disconnected (total: {client_count})\n")
elif data.get('type') == 'update':
routes_reflected += 1
sys.stderr.write(f"Routes reflected: {routes_reflected}\n")
except Exception as e:
sys.stderr.write(f"Error: {e}\n")Maintain documentation of your route reflection topology:
# route-reflection-topology.yaml
clusters:
- cluster_id: 192.0.2.1
name: "Core Cluster"
route_reflectors:
- ip: 192.0.2.1
hostname: rr1.example.com
- ip: 192.0.2.2
hostname: rr2.example.com
clients:
- 192.0.2.11
- 192.0.2.12
- 192.0.2.13
- 192.0.2.14
- 192.0.2.15
- cluster_id: 192.0.2.10
name: "Regional Cluster 1"
route_reflectors:
- ip: 192.0.2.10
hostname: rr-regional1.example.com
clients:
- 192.0.2.21
- 192.0.2.22
- 192.0.2.23Regularly test route reflector failover:
# Shutdown RR1, verify clients fail over to RR2
sudo systemctl stop exabgp@rr1
# Check client connectivity
# Clients should maintain connectivity via RR2
# Restore RR1
sudo systemctl start exabgp@rr1Enable route refresh capability to request route updates:
neighbor 192.0.2.11 {
router-id 192.0.2.1;
local-address 192.0.2.1;
local-as 65001;
peer-as 65001;
route-reflector-client;
capability {
route-refresh enable;
}
family {
ipv4 unicast;
}
}Symptoms: Clients don't receive routes from other clients.
Debugging steps:
- Verify route reflector client configuration:
neighbor 192.0.2.11 {
route-reflector-client; # Must be present
}- Check BGP sessions are established:
grep "Peer.*up" /var/log/exabgp/exabgp.log- Verify address families match:
# RR and clients must have matching address families
family {
ipv4 unicast;
}- Check for loop prevention rejections:
tail -f /var/log/exabgp/exabgp.log | grep -i "loop\|cluster\|originator"Symptoms: Routes loop between route reflectors, consuming bandwidth.
Solutions:
- Verify cluster IDs are configured:
neighbor 192.0.2.11 {
route-reflector-client;
cluster-id 192.0.2.1; # Must be present
}- Check cluster IDs are identical within a cluster:
# All RRs in same cluster must have same cluster-id- Review hierarchical design:
# Different clusters must have different cluster IDs
# Top-level: cluster-id 192.0.2.1
# Regional: cluster-id 192.0.2.10
Symptoms: Different clients receive different routes.
Debugging steps:
- Check route policies are consistent across RRs:
# All RRs in a cluster should have identical policies- Verify all RRs are receiving the same routes:
# Enable receive-routes on RRs
neighbor-changes;
receive-routes;- Check for split-brain scenario:
# Verify RRs can communicate with each otherSymptoms: Route reflector CPU/memory usage is high.
Solutions:
- Add more route reflectors:
# Distribute clients across more RRs
- Use hierarchical route reflection:
# Create regional clusters
- Optimize address families:
# Only reflect required address families
family {
ipv4 unicast; # Don't enable unnecessary families
}- Configuration Syntax - ExaBGP configuration reference
- BGP-LS Overview - BGP Link-State for topology collection
- IPv4 Unicast - IPv4 unicast routing
- IPv6 Unicast - IPv6 unicast routing
- RFC 4456 - BGP Route Reflection
- RFC 2796 - BGP Route Reflection (Historic)
π» Ghost written by Claude (Anthropic AI)
π Home
π Getting Started
π§ API
π‘οΈ Use Cases
π Address Families
βοΈ Configuration
π Operations
π Reference
- Architecture
- BGP State Machine
- Communities (RFC)
- Extended Communities
- BGP Ecosystem
- Capabilities (AFI/SAFI)
- RFC Support
π Migration
π Community
π External
- GitHub Repo β
- Slack β
- Issues β
π» Ghost written by Claude (Anthropic AI)