-
Notifications
You must be signed in to change notification settings - Fork 460
First BGP Session
Step-by-step guide to establishing your first BGP session with ExaBGP
- BGP Basics
- Lab Setup
- Configuration Walkthrough
- Establishing the Session
- Understanding BGP Messages
- Adding Your First Route
- Dynamic Route Announcement
- Receiving Routes
- Troubleshooting
- Next Steps
BGP (Border Gateway Protocol) is the routing protocol of the Internet. It's how routers exchange routing information.
Key concepts:
- AS (Autonomous System): A network under a single administrative control (e.g., an ISP, enterprise)
- ASN (AS Number): Unique identifier for an AS (e.g., 65000)
- Peer/Neighbor: Another BGP speaker you exchange routes with
- Route: Network prefix (e.g., 100.10.0.0/24) and how to reach it
- Next-hop: IP address where traffic should be sent
β οΈ Remember: ExaBGP does NOT manipulate the kernel routing table (RIB/FIB).
The flow:
Your Program β ExaBGP β BGP Protocol β Router β Router's RIB/FIB β Traffic Flow
- Your program tells ExaBGP "announce this route"
- ExaBGP sends BGP UPDATE message to router
- Router installs route in its routing table
- Router forwards traffic according to that route
ExaBGP's role: Pure BGP protocol speaker. It talks BGP, you talk to ExaBGP via API.
Minimum lab:
- ExaBGP host (your machine)
- BGP router/speaker to peer with
Options for BGP peer:
- Production router (Cisco, Juniper, Arista) - if you have access
- FRRouting (free, full-featured) - recommended for learning
- BIRD (free, high-performance) - good alternative
- GNS3/EVE-NG (network simulator) - realistic lab
βββββββββββββββββββ βββββββββββββββββββ
β ExaBGP Host β β BGP Router β
β β β (FRRouting) β
β 192.168.1.2 β ββββ eBGP βββββ β 192.168.1.1 β
β AS 65001 β TCP 179 β AS 65000 β
β β β β
β Announces: β β Installs route β
β 100.10.0.0/24 β β in RIB/FIB β
βββββββββββββββββββ βββββββββββββββββββ
Network details:
- ExaBGP:
192.168.1.2in AS 65001 - Router:
192.168.1.1in AS 65000 - Connection: eBGP (different ASNs)
- Route to announce:
100.10.0.0/24
If you don't have a router, set up FRRouting for testing:
# Install FRRouting (Ubuntu/Debian)
curl -s https://deb.frrouting.org/frr/keys.asc | sudo apt-key add -
echo deb https://deb.frrouting.org/frr $(lsb_release -s -c) frr-stable | sudo tee /etc/apt/sources.list.d/frr.list
sudo apt update
sudo apt install frr frr-pythontools
# Enable BGP
sudo sed -i 's/bgpd=no/bgpd=yes/' /etc/frr/daemons
sudo systemctl restart frr
# Configure BGP
sudo vtyshFRRouting config:
configure terminal
router bgp 65000
bgp router-id 192.168.1.1
neighbor 192.168.1.2 remote-as 65001
address-family ipv4 unicast
network 10.0.0.0/8
exit-address-family
exit
write memory
Create /etc/exabgp/exabgp.conf:
# Minimal BGP configuration
neighbor 192.168.1.1 {
# Basic identification
router-id 192.168.1.2;
local-address 192.168.1.2;
local-as 65001;
peer-as 65000;
# Announce a static route
static {
route 100.10.0.0/24 next-hop self;
}
}The IP address of the BGP peer (router) we're connecting to.
Router ID: Unique identifier for this BGP speaker. Typically use your IP address. Must be unique in the BGP domain.
Local Address: IP address ExaBGP binds to. Must be reachable by the peer. Usually same as router-id for simple setups.
Local ASN: Our autonomous system number. ASN 64512-65535 are private (like RFC 1918 IPs).
Peer ASN: The router's autonomous system number.
eBGP vs iBGP:
- Different ASNs (65001 β 65000) = eBGP (external BGP)
- Same ASN (65001 = 65001) = iBGP (internal BGP)
Static route announcement: Tell the peer about network 100.10.0.0/24.
next-hop self means "send traffic to me (192.168.1.2)".
exabgp /etc/exabgp/exabgp.confINFO: Welcome to ExaBGP
INFO: Performing reload of exabgp 4.2.25
INFO: New neighbor 192.168.1.1 (local AS 65001, peer AS 65000)
INFO: BGP session established with 192.168.1.1
INFO: Announced route 100.10.0.0/24 next-hop 192.168.1.2
BGP sessions go through these states:
- Idle - Not connected
- Connect - TCP connection attempt
- Active - Failed, retrying
- OpenSent - Sent OPEN message
- OpenConfirm - Received OPEN message
- Established - Session UP β
Goal: Reach Established state.
FRRouting:
vtysh -c "show ip bgp summary"Expected output:
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
192.168.1.2 4 65001 5 5 0 0 0 00:00:30 1
State/PfxRcd: 1 means session is up and 1 prefix received (our 100.10.0.0/24)
View received route:
vtysh -c "show ip bgp neighbor 192.168.1.2 received-routes"Output:
Network Next Hop Metric LocPrf Weight Path
*> 100.10.0.0/24 192.168.1.2 0 0 65001 i
*> = Best route, installed in RIB
BGP uses 4 message types:
Sent when connection is established. Contains:
- BGP version (4)
- ASN (65001)
- Hold time (180 seconds typically)
- Router ID (192.168.1.2)
- Capabilities (multi-protocol, 4-byte ASN, etc.)
ExaBGP log:
INFO: Sending OPEN to 192.168.1.1
INFO: Received OPEN from 192.168.1.1
Announces or withdraws routes.
Announcement:
UPDATE: route 100.10.0.0/24 next-hop 192.168.1.2 origin IGP as-path [ 65001 ]
Withdrawal:
UPDATE: withdraw route 100.10.0.0/24
Sent periodically (every 60 seconds) to keep session alive.
If no KEEPALIVE for hold-time seconds (180s), session drops.
Error message. Causes session termination.
Example:
NOTIFICATION: Cease - Administrative Reset
Common reasons:
- Configuration change
- Manual shutdown
- Protocol error
ExaBGP can announce multiple static routes:
neighbor 192.168.1.1 {
router-id 192.168.1.2;
local-address 192.168.1.2;
local-as 65001;
peer-as 65000;
static {
# Multiple routes
route 100.10.0.0/24 next-hop self;
route 100.20.0.0/24 next-hop self;
route 100.30.0.0/24 next-hop self;
# IPv6
route 2001:db8:100::/48 next-hop self;
# With attributes
route 100.40.0.0/24 {
next-hop self;
med 100; # Multi-Exit Discriminator (metric)
local-preference 200; # Preference for iBGP
community [ 65001:100 ]; # BGP community
}
}
}MED (Multi-Exit Discriminator): Lower is preferred. Suggests which path to use when multiple exist.
route 100.10.0.0/24 next-hop self med 50; # Preferred
route 100.10.0.0/24 next-hop self med 100; # Less preferredLocal Preference (iBGP only): Higher is preferred. Used within an AS to prefer certain paths.
route 100.10.0.0/24 next-hop self local-preference 200;Communities: Tags attached to routes for policy decisions.
route 100.10.0.0/24 next-hop self community [ 65001:100 65001:200 ];AS Path Prepending: Make path longer (less preferred) for traffic engineering.
route 100.10.0.0/24 next-hop self as-path [ 65001 65001 65001 ];Appears as: 65001 65001 65001 (prepended twice)
The real power: announce routes based on application logic.
Configuration:
neighbor 192.168.1.1 {
router-id 192.168.1.2;
local-address 192.168.1.2;
local-as 65001;
peer-as 65000;
# No static routes - API controls everything
api {
processes [ dynamic-routes ];
}
}
process dynamic-routes {
run /etc/exabgp/api/announce.py;
encoder text;
}Create /etc/exabgp/api/announce.py:
#!/usr/bin/env python3
"""
Simple dynamic route announcement
"""
import sys
import time
# Wait for ExaBGP to be ready
time.sleep(2)
# Announce routes
routes = [
"100.10.0.0/24",
"100.20.0.0/24",
"100.30.0.0/24"
]
for route in routes:
sys.stdout.write(f"announce route {route} next-hop self\n")
sys.stdout.flush()
sys.stderr.write(f"[API] Announced {route}\n")
# Keep process alive
while True:
time.sleep(60)Make executable:
chmod +x /etc/exabgp/api/announce.pyRun ExaBGP:
exabgp /etc/exabgp/exabgp.confOutput:
INFO: Started process 'dynamic-routes' with PID 12345
[API] Announced 100.10.0.0/24
[API] Announced 100.20.0.0/24
[API] Announced 100.30.0.0/24
INFO: Announced route 100.10.0.0/24
INFO: Announced route 100.20.0.0/24
INFO: Announced route 100.30.0.0/24
ExaBGP can receive routes from the router and process them.
neighbor 192.168.1.1 {
router-id 192.168.1.2;
local-address 192.168.1.2;
local-as 65001;
peer-as 65000;
# Receive IPv4 unicast routes
family {
ipv4 unicast;
}
# API processes receive updates
api {
processes [ receive-routes ];
}
}
process receive-routes {
run /etc/exabgp/api/receive.py;
encoder json; # JSON format for easier parsing
receive {
parsed; # Receive parsed BGP messages
updates; # Receive route updates
}
}Create /etc/exabgp/api/receive.py:
#!/usr/bin/env python3
"""
Receive and process BGP routes
"""
import sys
import json
while True:
line = sys.stdin.readline().strip()
if not line:
break
try:
message = json.loads(line)
# Handle route updates
if message['type'] == 'update':
# New route announced
if 'announce' in message['neighbor']['message']:
announce = message['neighbor']['message']['announce']
if 'ipv4 unicast' in announce:
for prefix, attrs in announce['ipv4 unicast'].items():
next_hop = attrs[0]['next-hop']
print(f"[RECEIVED] Route {prefix} via {next_hop}", file=sys.stderr)
# Route withdrawn
if 'withdraw' in message['neighbor']['message']:
withdraw = message['neighbor']['message']['withdraw']
if 'ipv4 unicast' in withdraw:
for prefix in withdraw['ipv4 unicast'].keys():
print(f"[WITHDRAWN] Route {prefix}", file=sys.stderr)
# Handle session state
elif message['type'] == 'state':
state = message['neighbor']['state']
print(f"[STATE] BGP session state: {state}", file=sys.stderr)
except json.JSONDecodeError:
pass
except Exception as e:
print(f"[ERROR] {e}", file=sys.stderr)On router (FRRouting), announce a route:
vtysh -c "configure terminal" -c "router bgp 65000" -c "network 10.0.0.0/8"ExaBGP output:
[RECEIVED] Route 10.0.0.0/8 via 192.168.1.1
Symptom: BGP stays in Connect or Active state
Check:
-
Network connectivity
ping 192.168.1.1 telnet 192.168.1.1 179
-
Firewall rules
# Allow TCP 179 sudo iptables -A INPUT -p tcp --dport 179 -j ACCEPT sudo iptables -A OUTPUT -p tcp --sport 179 -j ACCEPT -
Router configuration
- Peer address correct (
neighbor 192.168.1.2) - AS numbers match expectation
- Address family enabled
- Peer address correct (
-
ExaBGP config
-
local-addressreachable by peer -
peer-asmatches router's AS -
local-asis correct
-
Debug:
env exabgp.log.level=DEBUG exabgp /etc/exabgp/exabgp.confSymptom: NOTIFICATION: Authentication failure
Cause: MD5 password mismatch
Solution: Add MD5 password to both ExaBGP and router
ExaBGP:
neighbor 192.168.1.1 {
router-id 192.168.1.2;
local-address 192.168.1.2;
local-as 65001;
peer-as 65000;
md5-password "secretpassword";
}FRRouting:
router bgp 65000
neighbor 192.168.1.2 password secretpassword
Symptom: Session established, but routes not in router's RIB
Check:
-
ExaBGP log confirms announcement
INFO: Announced route 100.10.0.0/24 -
Router sees the route
# FRRouting vtysh -c "show ip bgp neighbor 192.168.1.2 received-routes"
-
Route accepted (not filtered)
- Check prefix-lists, route-maps, AS-path filters
-
Best path selected
- Lower MED
- Higher local-pref (iBGP)
- Shorter AS path
- Lower IGP metric
Debug on router:
vtysh -c "show ip bgp 100.10.0.0/24"Look for *> = best path, installed in RIB
Symptom: Process not in ps aux | grep announce.py
Check:
-
Script executable
chmod +x /etc/exabgp/api/announce.py
-
Shebang correct
#!/usr/bin/env python3 -
Path correct
run /etc/exabgp/api/announce.py; # Absolute path -
ExaBGP log
ERROR: Process 'dynamic-routes' failed to start
Test manually:
/etc/exabgp/api/announce.pySymptom: API script runs, but routes not announced
Check:
-
STDOUT flush
sys.stdout.write("announce route 100.10.0.0/24 next-hop self\n") sys.stdout.flush() # CRITICAL - without this, nothing happens
-
Command syntax
# Correct print("announce route 100.10.0.0/24 next-hop self") # Wrong print("announce 100.10.0.0/24 next-hop self") # Missing 'route'
-
ExaBGP log shows command
INFO: Received command from API: announce route 100.10.0.0/24 next-hop self
β οΈ Important: ExaBGP's API and configuration syntax changed significantly between versions.
- ExaBGP 3.x (legacy, deprecated)
- ExaBGP 4.x (maintenance, 4.2.25+)
- ExaBGP 5.x (LTS - stable)
- ExaBGP 6.0.0 (development - main branch)
Configuration Format Changed:
ExaBGP 3.x (OLD):
neighbor 192.168.1.1 {
router-id 192.168.1.2;
local-address 192.168.1.2;
local-as 65001;
peer-as 65000;
# OLD process syntax
process announce-routes {
run /usr/bin/python /etc/exabgp/api/announce.py;
}
}ExaBGP 4.x (NEW):
neighbor 192.168.1.1 {
router-id 192.168.1.2;
local-address 192.168.1.2;
local-as 65001;
peer-as 65000;
# NEW api syntax
api {
processes [ announce-routes ];
}
}
process announce-routes {
run /etc/exabgp/api/announce.py;
encoder text;
}Key differences:
- Separate
processblock outsideneighborin 4.x -
api { processes [ ... ] }syntax in 4.x -
encoderdirective added in 4.x
JSON Message Format Changed:
ExaBGP 3.x JSON output:
{
"type": "update",
"neighbor": {
"ip": "192.168.1.1",
"update": {
"announce": {
"ipv4": {
"100.10.0.0/24": {
"next-hop": "192.168.1.2"
}
}
}
}
}
}ExaBGP 4.x JSON output:
{
"exabgp": "4.2.25",
"time": 1699564800.0,
"host": "exabgp-host",
"pid": 12345,
"ppid": 1,
"counter": 1,
"type": "update",
"neighbor": {
"address": {
"local": "192.168.1.2",
"peer": "192.168.1.1"
},
"asn": {
"local": 65001,
"peer": 65000
},
"message": {
"update": {
"announce": {
"ipv4 unicast": {
"100.10.0.0/24": [
{
"next-hop": "192.168.1.2"
}
]
}
}
}
}
}
}Key differences:
- More metadata in 4.x (exabgp version, time, host, pid, counter)
- Nested structure deeper in 4.x
- Address family explicit:
"ipv4 unicast"not"ipv4" - Attributes in array:
[ { "next-hop": ... } ]not just{ "next-hop": ... }
API Command Format:
ExaBGP 3.x:
# Announce
print("announce route 100.10.0.0/24 next-hop 192.168.1.2")
# Withdraw
print("withdraw route 100.10.0.0/24")ExaBGP 4.x:
# Announce - can use 'self'
print("announce route 100.10.0.0/24 next-hop self")
# Withdraw
print("withdraw route 100.10.0.0/24")
# FlowSpec syntax improved
print("announce flow route { match { destination 100.10.0.0/24; } then { discard; } }")Key differences:
-
next-hop selfsupported in 4.x (auto-fills with local-address) - FlowSpec syntax cleaner in 4.x
- More attribute support in 4.x
Status: ExaBGP 5.0.0 released November 2024 (871 commits, largest release in history).
- Python 3.8+ required (3.9+ recommended, Python 2 completely removed)
- JSON API: AS-PATH format changed (array β string)
- BGP-LS: Field names changed (sr_capability_flags β sr-capability-flags, etc.)
- Config syntax: route-refresh, FlowSpec fragments, tcp.attempts
- Removed: Prefix-SID Type-2/4, tcp.once directive
- New defaults: Hostname capability not sent by default
New Features:
- β SRv6 - Complete Segment Routing over IPv6 support
- β BGP-MUP - Mobile User Plane SAFI
- β RFC 9072 - Extended Optional Parameters Length
- β ACK runtime control - disable-ack, enable-ack, silence-ack
- β Security fixes - TOCTOU vulnerability patched
Recommendation: See 4.x β 5.0.0 Migration Guide for upgrade planning. ExaBGP 4.x remains in maintenance mode (critical fixes only).
ExaBGP 5.0.0 (LTS - Recommended)
- β Latest LTS release (November 2024)
- β All newest features (SRv6, BGP-MUP, etc.)
- β Security fixes (TOCTOU vulnerability)
- β Python 3.8-3.13 support
- β Recommended for all new deployments
β οΈ Breaking changes from 4.x - See migration guide- β This documentation covers 5.0.0
ExaBGP 4.2.x (Previous Stable)
- β Production-proven
- β No breaking changes within 4.x series
- β Python 2.7 + 3.6+ support
β οΈ Maintenance mode - Only critical fixes, no new features- βΉοΈ Suitable for existing deployments not yet ready to migrate
- β This documentation covers 4.x
ExaBGP 6.0.0 (Development - main branch)
- β Latest features (async reactor, shell completion, enhanced CLI)
- β Python 3.12-3.14 support
β οΈ Breaking changes from 5.x - See migration guideβ οΈ Python 3.12+ required (3.7-3.11 dropped)β οΈ BGP-LS JSON field names changed- βΉοΈ Test thoroughly before production
ExaBGP 3.x (Deprecated)
- β No longer maintained
- β Python 2 only (end-of-life)
- β Must upgrade - See 3.x β 4.x migration
Decision Guide:
- New deployment? β Use 5.0.0 (LTS) for stability, or 6.0.0 for latest features
- Existing 5.x deployment? β Consider 6.0.0 if you need new features and can test thoroughly
- Existing 4.x deployment? β Plan migration to 5.0.0 (test thoroughly first)
- Still on 3.x? β Upgrade to 5.0.0 (via 4.x if needed for staged migration)
See Migration Guide: 3.4 to 4.x for complete migration instructions.
Quick summary:
-
Update configuration syntax:
- Move
processblocks outsideneighbor - Change to
api { processes [ ... ] }syntax - Add
encoder textorencoder json
- Move
-
Update API scripts (if using JSON):
- Parse new JSON structure
- Access:
message['neighbor']['message']['update']notmessage['neighbor']['update'] - Address family:
'ipv4 unicast'not'ipv4'
-
Test thoroughly:
- ExaBGP 3.x and 4.x are NOT compatible
- Configuration files don't work between versions
- API scripts need updates
Before (3.x config):
neighbor 192.168.1.1 {
router-id 192.168.1.2;
local-address 192.168.1.2;
local-as 65001;
peer-as 65000;
process announce {
run /usr/bin/python /etc/exabgp/announce.py;
}
}After (4.x config):
neighbor 192.168.1.1 {
router-id 192.168.1.2;
local-address 192.168.1.2;
local-as 65001;
peer-as 65000;
api {
processes [ announce ];
}
}
process announce {
run /etc/exabgp/announce.py;
encoder text;
}Before (3.x API script receiving JSON):
#!/usr/bin/env python
import json, sys
while True:
line = sys.stdin.readline()
msg = json.loads(line)
# 3.x structure
if 'announce' in msg['neighbor']['update']:
routes = msg['neighbor']['update']['announce']['ipv4']
for prefix, attrs in routes.items():
nexthop = attrs['next-hop']
print(f"Route: {prefix} via {nexthop}")After (4.x API script):
#!/usr/bin/env python3
import json, sys
while True:
line = sys.stdin.readline()
msg = json.loads(line)
# 4.x structure
if 'update' in msg['neighbor']['message']:
update = msg['neighbor']['message']['update']
if 'announce' in update:
if 'ipv4 unicast' in update['announce']:
routes = update['announce']['ipv4 unicast']
for prefix, attrs_list in routes.items():
nexthop = attrs_list[0]['next-hop']
print(f"Route: {prefix} via {nexthop}")Key changes:
- Access path:
msg['neighbor']['message']['update']notmsg['neighbor']['update'] - Address family:
'ipv4 unicast'not'ipv4' - Attributes:
attrs_list[0](array) notattrs(dict)
exabgp --versionOutput:
ExaBGP : 4.2.25
Python : 3.9.16
If you see 3.x.x: You're on deprecated version - upgrade to 5.x (via 4.x if needed).
If you see 4.2.x: You're on maintenance branch - plan upgrade to 5.x when ready.
If you see 5.x.x: You're on LTS (stable) - recommended for production!
If you see 6.x.x or main: You're on development branch - test thoroughly before production.
- Migration: 3.4 to 4.x - Complete migration guide
- Migration: 4.2 to 5.0 - When 5.0 releases
- Breaking Changes - All breaking changes across versions
- Version Comparison - Feature matrix
- API Overview - Complete API documentation
- Configuration Syntax - All configuration options
- Text API Reference - All API commands
- High Availability - Health checks + anycast
- DDoS Mitigation - FlowSpec automated blocking
- Anycast Management - Load balancing patterns
- FlowSpec - Traffic filtering with BGP
- Communities - Route tagging and policies
- Attributes - BGP path attributes
What you learned:
β BGP fundamentals (AS, neighbor, route, next-hop) β ExaBGP configuration syntax β Establishing BGP session (Established state) β Announcing static routes β Using the API for dynamic routes β Receiving routes from router β Troubleshooting common issues
Key concepts:
- ExaBGP speaks BGP protocol but does NOT manipulate kernel routing table
- Routers install the routes ExaBGP announces
- API uses simple STDIN/STDOUT for any language
- BGP session must reach "Established" state
- Always
flush()after writing to STDOUT
Ready for more? Continue to API Overview β
π» 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)