-
Notifications
You must be signed in to change notification settings - Fork 462
Process
The process directive in ExaBGP configures external programs that communicate with ExaBGP via its API. Processes are used for dynamic route control, health checking, monitoring, and integration with external systems.
- Overview
- Basic Process Configuration
- Process Directives
- Environment Variables
- API Communication
- Multiple Processes
- Process Types
- Best Practices
- Troubleshooting
- See Also
Important: ExaBGP does NOT manipulate the routing table (RIB/FIB). External processes use the ExaBGP API to dynamically announce and withdraw routes based on application logic (health checks, monitoring, traffic engineering, etc.).
βββββββββββββββββββββββ
β ExaBGP Main β
β Process β
ββββββββ¬βββββββββββββββ
β stdin/stdout
β pipe communication
βΌ
βββββββββββββββββββββββ
β API Process β
β (Python/Bash/Go) β
ββββββββ¬βββββββββββββββ
β
β checks service/logic
βΌ
βββββββββββββββββββββββ
β External System β
β (Service/Monitor) β
βββββββββββββββββββββββ
- Process - External program that communicates with ExaBGP via API
- API - Text or JSON-based protocol for sending commands to ExaBGP
- Encoder - Format for API messages (text or JSON)
- Run - Command to execute the process
- Environment Variables - Configuration passed to the process
# /etc/exabgp/exabgp.conf
process announce-routes {
run /etc/exabgp/announce.py;
encoder text;
}
neighbor 192.0.2.1 {
router-id 192.0.2.10;
local-address 192.0.2.10;
local-as 65001;
peer-as 65001;
family {
ipv4 unicast;
}
api {
processes [ announce-routes ];
}
}#!/usr/bin/env python3
# /etc/exabgp/announce.py
import sys
import time
# Announce a route
print("announce route 198.51.100.0/24 next-hop 192.0.2.10", flush=True)
# Keep process running
while True:
time.sleep(60)process process-name {
# Command to execute (required)
run /path/to/program [arguments];
# API message format: text or json (default: text)
encoder text;
# Receive neighbor state updates (default: false)
neighbor-changes;
# Receive route updates from peers (default: false)
receive-routes;
# Receive parsed routes (default: false)
receive-parsed;
# Receive raw BGP packets (default: false)
receive-packets;
}| Directive | Description | Values | Default |
|---|---|---|---|
run |
Command to execute | Path + arguments | Required |
encoder |
API message format |
text, json
|
text |
neighbor-changes |
Receive neighbor state updates | Flag | Disabled |
receive-routes |
Receive route updates from peers | Flag | Disabled |
receive-parsed |
Receive parsed route information | Flag | Disabled |
receive-packets |
Receive raw BGP packets | Flag | Disabled |
process healthcheck {
run /usr/bin/python3 /etc/exabgp/healthcheck.py --interval 10 --route 198.51.100.0/24;
encoder text;
}process monitor {
run /etc/exabgp/monitor.py;
encoder json;
neighbor-changes;
receive-routes;
}ExaBGP passes configuration information to processes via environment variables prefixed with exabgp..
# Process Information
exabgp.version # ExaBGP version (e.g., "5.0.0")
exabgp.api.encoder # Encoder type (text or json)
# Neighbor Information (per neighbor)
exabgp.neighbor.address # Neighbor IP address
exabgp.neighbor.as # Neighbor AS number
exabgp.neighbor.local_address # Local IP address
exabgp.neighbor.local_as # Local AS number
exabgp.neighbor.peer_as # Peer AS number
# File Locations
exabgp.etc # ExaBGP configuration directory
exabgp.log # Log file location#!/usr/bin/env python3
# /etc/exabgp/announce-with-env.py
import os
import sys
# Read ExaBGP environment variables
version = os.environ.get('exabgp.version', 'unknown')
encoder = os.environ.get('exabgp.api.encoder', 'text')
neighbor = os.environ.get('exabgp.neighbor.address', 'unknown')
sys.stderr.write(f"ExaBGP version: {version}\n")
sys.stderr.write(f"API encoder: {encoder}\n")
sys.stderr.write(f"Neighbor: {neighbor}\n")
# Use local address for next-hop
local_address = os.environ.get('exabgp.neighbor.local_address', 'self')
print(f"announce route 198.51.100.0/24 next-hop {local_address}", flush=True)
while True:
import time
time.sleep(60)#!/bin/bash
# /etc/exabgp/announce-with-env.sh
# Read ExaBGP environment variables
NEIGHBOR="${exabgp.neighbor.address}"
LOCAL_AS="${exabgp.neighbor.local_as}"
PEER_AS="${exabgp.neighbor.peer_as}"
echo "Connected to neighbor: $NEIGHBOR (AS $PEER_AS)" >&2
echo "Our AS: $LOCAL_AS" >&2
# Announce route
echo "announce route 198.51.100.0/24 next-hop self"
# Keep running
while true; do
sleep 60
doneText API uses simple command syntax:
#!/usr/bin/env python3
# /etc/exabgp/text-api.py
import sys
# Announce route
print("announce route 198.51.100.0/24 next-hop 192.0.2.10", flush=True)
# Announce with attributes
print("announce route 203.0.113.0/24 next-hop 192.0.2.10 as-path [ 65001 65002 ] community [ 65001:100 ]", flush=True)
# Withdraw route
print("withdraw route 198.51.100.0/24 next-hop 192.0.2.10", flush=True)
# FlowSpec rule
print("announce flow route { match { source 192.0.2.0/24; destination-port =80; } then { rate-limit 9600; } }", flush=True)
while True:
import time
time.sleep(60)JSON API uses structured JSON messages:
#!/usr/bin/env python3
# /etc/exabgp/json-api.py
import sys
import json
# Announce route (JSON format)
route = {
"exabgp": "5.0.0",
"type": "update",
"neighbor": {
"address": {"local": "192.0.2.10", "peer": "192.0.2.1"},
"asn": {"local": 65001, "peer": 65001}
},
"announce": {
"ipv4 unicast": {
"192.0.2.10": {
"198.51.100.0/24": {
"next-hop": "192.0.2.10",
"as-path": [65001],
"community": [[65001, 100]]
}
}
}
}
}
print(json.dumps(route), flush=True)
while True:
import time
time.sleep(60)process json-api {
run /etc/exabgp/json-api.py;
encoder json; # Use JSON format
}You can configure multiple processes for different purposes.
# /etc/exabgp/exabgp.conf
# Health check process
process healthcheck {
run /etc/exabgp/healthcheck.py;
encoder text;
}
# Monitoring process
process monitor {
run /etc/exabgp/monitor.py;
encoder json;
neighbor-changes;
receive-routes;
}
# Metrics exporter
process metrics {
run /usr/bin/python3 -m exabgp.application.metrics;
encoder json;
}
neighbor 192.0.2.1 {
router-id 192.0.2.10;
local-address 192.0.2.10;
local-as 65001;
peer-as 65001;
family {
ipv4 unicast;
ipv4 flow;
}
api {
# All processes can send commands
processes [ healthcheck, monitor, metrics ];
}
}Multiple processes can coordinate by reading shared state:
#!/usr/bin/env python3
# /etc/exabgp/coordinated-announce.py
import sys
import time
import json
import os
STATE_FILE = "/var/run/exabgp/state.json"
def read_state():
"""Read shared state file"""
try:
with open(STATE_FILE, 'r') as f:
return json.load(f)
except:
return {}
def should_announce():
"""Check if we should announce based on shared state"""
state = read_state()
return state.get('all_healthy', False)
route_announced = False
while True:
if should_announce() and not route_announced:
print("announce route 198.51.100.0/24 next-hop self", flush=True)
route_announced = True
sys.stderr.write("Route announced based on shared state\n")
elif not should_announce() and route_announced:
print("withdraw route 198.51.100.0/24 next-hop self", flush=True)
route_announced = False
sys.stderr.write("Route withdrawn based on shared state\n")
time.sleep(10)process healthcheck {
run /etc/exabgp/healthcheck.py;
encoder text;
}#!/usr/bin/env python3
import sys, time, requests
while True:
try:
r = requests.get("http://127.0.0.1/health", timeout=5)
if r.status_code == 200:
print("announce route 198.51.100.0/24 next-hop self", flush=True)
else:
print("withdraw route 198.51.100.0/24 next-hop self", flush=True)
except:
print("withdraw route 198.51.100.0/24 next-hop self", flush=True)
time.sleep(10)process monitor {
run /etc/exabgp/monitor.py;
encoder json;
neighbor-changes;
receive-routes;
}#!/usr/bin/env python3
import sys
import json
# Read updates from ExaBGP
while True:
line = sys.stdin.readline().strip()
if not line:
break
try:
data = json.loads(line)
# Log neighbor state changes
if data.get('type') == 'state':
neighbor = data['neighbor']['address']['peer']
state = data['neighbor']['state']
sys.stderr.write(f"Neighbor {neighbor} is {state}\n")
# Log received routes
elif data.get('type') == 'update':
sys.stderr.write(f"Received update: {json.dumps(data)}\n")
except Exception as e:
sys.stderr.write(f"Error processing message: {e}\n")process traffic-engineering {
run /etc/exabgp/traffic-engineering.py;
encoder text;
}#!/usr/bin/env python3
import sys
import time
import random
ROUTES = ["198.51.100.0/24", "203.0.113.0/24"]
AS_PATHS = [
"[65001 65002]",
"[65001 65003 65003]", # Longer path
]
while True:
# Randomly adjust AS path to influence routing
for route in ROUTES:
as_path = random.choice(AS_PATHS)
print(f"announce route {route} next-hop self as-path {as_path}", flush=True)
sys.stderr.write(f"Updated {route} with AS path {as_path}\n")
time.sleep(300) # Adjust every 5 minutesprocess ddos-mitigation {
run /etc/exabgp/ddos-mitigation.py;
encoder text;
}#!/usr/bin/env python3
import sys
import time
def block_attack(source_ip, dport):
"""Send FlowSpec rule to block attack"""
rule = f"announce flow route {{ match {{ source {source_ip}/32; destination-port ={dport}; }} then {{ discard; }} }}"
print(rule, flush=True)
sys.stderr.write(f"Blocked {source_ip} attacking port {dport}\n")
# Example: Block detected attacks
while True:
# In real implementation, read from IDS/monitoring system
# For demo, just block example attack
block_attack("192.0.2.100", 80)
time.sleep(3600) # Check every hourExaBGP reads from the process's stdout. Always flush after printing:
print("announce route 198.51.100.0/24 next-hop self", flush=True)Or set unbuffered output:
#!/usr/bin/env python3 -u
# -u flag makes Python unbufferedWithdraw routes before exiting:
import signal
import sys
def signal_handler(signum, frame):
print("withdraw route 198.51.100.0/24 next-hop self", flush=True)
sys.stderr.write("Graceful shutdown - routes withdrawn\n")
sys.exit(0)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)stdout is for API commands only. Use stderr for logging:
sys.stderr.write("Health check passed\n") # Logging
print("announce route 198.51.100.0/24 next-hop self", flush=True) # API commandProcess must stay running to maintain routes:
# GOOD: Process keeps running
while True:
check_and_announce()
time.sleep(10)
# BAD: Process exits after announcing
print("announce route 198.51.100.0/24 next-hop self", flush=True)
# Process exits here - routes will be withdrawn!chmod +x /etc/exabgp/announce.py# GOOD
run /usr/bin/python3 /etc/exabgp/announce.py;
# BAD (may not work)
run python3 announce.py;Test your script before using it with ExaBGP:
# Test script runs and outputs correctly
/etc/exabgp/announce.py
# Should output:
# announce route 198.51.100.0/24 next-hop selfUse systemd or supervisor to restart failed processes:
# /etc/systemd/system/exabgp.service
[Service]
Restart=always
RestartSec=10Symptoms: ExaBGP logs show process start failures.
Solutions:
- Check script is executable:
chmod +x /etc/exabgp/announce.py- Check shebang line:
#!/usr/bin/env python3 # Correct
#!/usr/bin/python3 # Also correct- Test script manually:
/etc/exabgp/announce.py
# Should run without errors- Check ExaBGP logs:
tail -f /var/log/exabgp/exabgp.logSymptoms: Process runs but routes don't appear.
Solutions:
- Ensure stdout is flushed:
print("announce route ...", flush=True)- Check API is enabled for the process:
api {
processes [ announce-routes ]; # Process must be listed
}- Verify BGP session is established:
grep "Peer.*up" /var/log/exabgp/exabgp.log- Check address family is configured:
family {
ipv4 unicast; # Must match route type
}Symptoms: Process exits unexpectedly.
Solutions:
- Add exception handling:
try:
while True:
check_and_announce()
time.sleep(10)
except Exception as e:
sys.stderr.write(f"Fatal error: {e}\n")
sys.exit(1)- Check for syntax errors:
python3 -m py_compile /etc/exabgp/announce.py- Review stderr output:
# ExaBGP logs process stderr
tail -f /var/log/exabgp/exabgp.log | grep -i errorSymptoms: Monitoring process doesn't receive neighbor/route updates.
Solutions:
- Enable update reception:
process monitor {
neighbor-changes; # For neighbor state updates
receive-routes; # For route updates
}- Use correct encoder:
process monitor {
encoder json; # Updates are in JSON format
}- Read from stdin properly:
while True:
line = sys.stdin.readline()
if not line:
break
# Process updateSymptoms: Processes announce conflicting routes.
Solutions:
- Use different routes per process:
# Process 1: Announces 198.51.100.0/24
# Process 2: Announces 203.0.113.0/24- Coordinate via shared state:
# Use lock file or shared state file- Use single master process:
# One process coordinates and announces all routes- API Overview - ExaBGP API architecture
- Text API Reference - Text API command syntax
- JSON API Reference - JSON API format
- Configuration Syntax - Overall configuration reference
- Health Checks - Health checking patterns
- Writing API Programs - API program development guide
π» 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)