-
Notifications
You must be signed in to change notification settings - Fork 461
Large Configuration File
As your ExaBGP deployment grows, configuration files can become complex and difficult to manage. This guide covers best practices for organizing, maintaining, and optimizing large ExaBGP configurations.
- Overview
- Configuration Organization
- Templates and Inheritance
- File Inclusion
- Variable Substitution
- Configuration Generation
- Performance Considerations
- Validation and Testing
- Best Practices
- Troubleshooting
- See Also
Important: ExaBGP does NOT manipulate the routing table (RIB/FIB). Large configurations typically involve many BGP neighbors, multiple address families, and complex API processes for dynamic route control.
- Many neighbors (10+ peers)
- Multiple sites with similar configurations
- Complex route policies across many peers
- Many address families (IPv4, IPv6, FlowSpec, EVPN, etc.)
- Multiple API processes for different services
- Team collaboration requiring modular configuration
Organize configuration files in a logical hierarchy:
/etc/exabgp/
├── exabgp.conf # Main configuration file
├── conf.d/ # Neighbor configurations
│ ├── core-routers.conf # Core network peers
│ ├── edge-routers.conf # Edge network peers
│ ├── route-reflectors.conf # Route reflector peers
│ └── external-peers.conf # External BGP peers
├── processes/ # API process configurations
│ ├── healthcheck.conf
│ ├── monitoring.conf
│ └── flowspec.conf
├── scripts/ # API process scripts
│ ├── healthcheck.py
│ ├── monitor.py
│ └── ddos-mitigation.py
├── templates/ # Configuration templates
│ │── neighbor-template.conf
│ └── process-template.conf
└── secrets/ # Passwords and keys
├── rr1-password.txt
└── rr2-password.txt
ExaBGP does not have an include directive. All configuration must be in a single file. To manage large deployments, use one of these approaches:
-
Native templates —
templateandinheritdirectives (see Templates and Inheritance) - External generation — Use Jinja2, shell scripts, or other tools to generate a single config file
- API-driven — Use the API to announce/withdraw routes dynamically instead of static config
ExaBGP has native template support via the template and inherit directives (see Templates and Inheritance). For more complex generation, you can also use external tools like Jinja2.
{# /etc/exabgp/templates/neighbor.j2 #}
neighbor {{ neighbor_ip }} {
router-id {{ router_id }};
local-address {{ local_address }};
local-as {{ local_as }};
peer-as {{ peer_as }};
{% if md5_password %}
md5-password "{{ md5_password }}";
{% endif %}
{% if ttl_security %}
incoming-ttl 255;
{% endif %}
family {
{% for family in address_families %}
{{ family }};
{% endfor %}
}
{% if api_processes %}
api {
processes [ {{ api_processes | join(', ') }} ];
}
{% endif %}
}# /etc/exabgp/data/neighbors.yaml
neighbors:
- neighbor_ip: 192.0.2.1
router_id: 192.0.2.10
local_address: 192.0.2.10
local_as: 65001
peer_as: 65001
md5_password: "strong-password-123"
ttl_security: true
address_families:
- "ipv4 unicast"
- "ipv6 unicast"
route_reflector_client: true
cluster_id: 192.0.2.254
api_processes:
- healthcheck
- monitor
- neighbor_ip: 192.0.2.2
router_id: 192.0.2.10
local_address: 192.0.2.10
local_as: 65001
peer_as: 65001
md5_password: "strong-password-456"
ttl_security: true
address_families:
- "ipv4 unicast"
- "ipv6 unicast"
route_reflector_client: true
cluster_id: 192.0.2.254
api_processes:
- healthcheck
- monitor#!/usr/bin/env python3
# /usr/local/bin/generate-exabgp-config.py
import yaml
from jinja2 import Environment, FileSystemLoader
# Load configuration data
with open('/etc/exabgp/data/neighbors.yaml', 'r') as f:
data = yaml.safe_load(f)
# Setup Jinja2 environment
env = Environment(loader=FileSystemLoader('/etc/exabgp/templates'))
template = env.get_template('neighbor.j2')
# Generate configuration for each neighbor
output = []
for neighbor in data['neighbors']:
output.append(template.render(neighbor))
# Write generated configuration
with open('/etc/exabgp/conf.d/generated-neighbors.conf', 'w') as f:
f.write('\n\n'.join(output))
print("Configuration generated successfully")#!/bin/bash
# /usr/local/bin/update-exabgp-config.sh
# Generate configuration
/usr/local/bin/generate-exabgp-config.py
# Validate configuration
exabgp configuration validate /etc/exabgp/exabgp.conf
# If validation succeeds, reload ExaBGP
if [ $? -eq 0 ]; then
systemctl reload exabgp
echo "Configuration updated and reloaded"
else
echo "Configuration validation failed"
exit 1
fiExaBGP does not have an include directive — all configuration goes in a single file. However, you can use external tools to generate that file from modular sources (see Configuration Generation below).
# /etc/exabgp/conf.d/core-routers.conf
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;
}
}
neighbor 192.0.2.2 {
router-id 192.0.2.10;
local-address 192.0.2.10;
local-as 65001;
peer-as 65001;
family {
ipv4 unicast;
}
}# /etc/exabgp/conf.d/edge-routers.conf
neighbor 192.0.2.11 {
router-id 192.0.2.10;
local-address 192.0.2.10;
local-as 65001;
peer-as 65002;
family {
ipv4 unicast;
ipv4 flow;
}
}# /etc/exabgp/processes/healthcheck.conf
process healthcheck {
run /etc/exabgp/scripts/healthcheck.py;
encoder text;
}# /etc/exabgp/processes/monitoring.conf
process monitor {
run /etc/exabgp/scripts/monitor.py;
encoder json;
neighbor-changes;
receive-routes;
}While ExaBGP doesn't natively support variables, you can use preprocessing tools.
# /etc/exabgp/templates/exabgp.conf.m4
define(`ROUTER_ID', `192.0.2.10')
define(`LOCAL_AS', `65001')
define(`LOCAL_ADDRESS', `192.0.2.10')
neighbor 192.0.2.1 {
router-id ROUTER_ID;
local-address LOCAL_ADDRESS;
local-as LOCAL_AS;
peer-as 65001;
family {
ipv4 unicast;
}
}
neighbor 192.0.2.2 {
router-id ROUTER_ID;
local-address LOCAL_ADDRESS;
local-as LOCAL_AS;
peer-as 65001;
family {
ipv4 unicast;
}
}Generate configuration:
m4 /etc/exabgp/templates/exabgp.conf.m4 > /etc/exabgp/exabgp.conf#!/bin/bash
# /usr/local/bin/generate-config.sh
ROUTER_ID="192.0.2.10"
LOCAL_AS="65001"
cat > /etc/exabgp/exabgp.conf <<EOF
neighbor 192.0.2.1 {
router-id ${ROUTER_ID};
local-address ${ROUTER_ID};
local-as ${LOCAL_AS};
peer-as 65001;
family {
ipv4 unicast;
}
}
EOF#!/usr/bin/env python3
# /usr/local/bin/exabgp-config-generator.py
class ExaBGPConfig:
def __init__(self, router_id, local_as):
self.router_id = router_id
self.local_as = local_as
self.neighbors = []
self.processes = []
def add_neighbor(self, ip, peer_as, families, **kwargs):
neighbor = {
'ip': ip,
'peer_as': peer_as,
'families': families,
**kwargs
}
self.neighbors.append(neighbor)
def add_process(self, name, run, encoder='text', **kwargs):
process = {
'name': name,
'run': run,
'encoder': encoder,
**kwargs
}
self.processes.append(process)
def generate(self):
lines = []
# Log configuration
lines.append("log {")
lines.append(" all = true;")
lines.append(" destination = /var/log/exabgp/exabgp.log;")
lines.append(" level = INFO;")
lines.append("}")
lines.append("")
# Process configurations
for proc in self.processes:
lines.append(f"process {proc['name']} {{")
lines.append(f" run {proc['run']};")
lines.append(f" encoder {proc['encoder']};")
if proc.get('neighbor_changes'):
lines.append(" neighbor-changes;")
if proc.get('receive_routes'):
lines.append(" receive-routes;")
lines.append("}")
lines.append("")
# Neighbor configurations
for neighbor in self.neighbors:
lines.append(f"neighbor {neighbor['ip']} {{")
lines.append(f" router-id {self.router_id};")
lines.append(f" local-address {self.router_id};")
lines.append(f" local-as {self.local_as};")
lines.append(f" peer-as {neighbor['peer_as']};")
lines.append("")
if neighbor.get('md5_password'):
lines.append(f" md5-password \"{neighbor['md5_password']}\";")
if neighbor.get('ttl_security'):
lines.append(" incoming-ttl 255;")
lines.append(" family {")
for family in neighbor['families']:
lines.append(f" {family};")
lines.append(" }")
lines.append("")
if neighbor.get('api_processes'):
lines.append(" api {")
procs = ', '.join(neighbor['api_processes'])
lines.append(f" processes [ {procs} ];")
lines.append(" }")
lines.append("}")
lines.append("")
return '\n'.join(lines)
# Example usage
config = ExaBGPConfig(router_id='192.0.2.10', local_as=65001)
# Add processes
config.add_process('healthcheck', '/etc/exabgp/scripts/healthcheck.py')
config.add_process('monitor', '/etc/exabgp/scripts/monitor.py',
encoder='json', neighbor_changes=True, receive_routes=True)
# Add neighbors
config.add_neighbor('192.0.2.1', 65001, ['ipv4 unicast', 'ipv6 unicast'],
md5_password='strong-password-123',
ttl_security=True,
route_reflector_client=True,
cluster_id='192.0.2.254',
api_processes=['healthcheck', 'monitor'])
config.add_neighbor('192.0.2.2', 65001, ['ipv4 unicast', 'ipv6 unicast'],
md5_password='strong-password-456',
ttl_security=True,
route_reflector_client=True,
cluster_id='192.0.2.254',
api_processes=['healthcheck', 'monitor'])
# Generate and save configuration
with open('/etc/exabgp/exabgp.conf', 'w') as f:
f.write(config.generate())
print("Configuration generated successfully")# /etc/ansible/playbooks/exabgp-config.yml
---
- name: Generate ExaBGP Configuration
hosts: exabgp_servers
become: true
vars:
router_id: "192.0.2.10"
local_as: 65001
neighbors:
- ip: 192.0.2.1
peer_as: 65001
families:
- ipv4 unicast
- ipv6 unicast
route_reflector_client: true
- ip: 192.0.2.2
peer_as: 65001
families:
- ipv4 unicast
- ipv6 unicast
route_reflector_client: true
tasks:
- name: Deploy ExaBGP configuration
template:
src: templates/exabgp.conf.j2
dest: /etc/exabgp/exabgp.conf
owner: exabgp
group: exabgp
mode: '0640'
notify: Reload ExaBGP
- name: Validate configuration
command: exabgp configuration validate /etc/exabgp/exabgp.conf
register: validation
changed_when: false
handlers:
- name: Reload ExaBGP
systemd:
name: exabgp
state: reloadedLarge configurations with many neighbors can take time to parse. Use native templates (via template/inherit) to reduce config size and improve readability.
Each neighbor consumes memory. For large deployments:
-
Monitor memory usage:
ps aux | grep exabgp - Use 64-bit Python: Supports larger memory spaces
- Limit concurrent sessions: Start neighbors gradually
Stagger session establishment to avoid overwhelming peers:
#!/usr/bin/env python3
# /etc/exabgp/scripts/staggered-announce.py
import sys
import time
routes = [
"198.51.100.0/24",
"203.0.113.0/24",
# ... 1000+ routes
]
# Announce routes gradually
for i, route in enumerate(routes):
print(f"announce route {route} next-hop self", flush=True)
# Brief delay every 100 routes
if i % 100 == 0:
time.sleep(1)
while True:
time.sleep(60)Always validate before deploying:
# Validate configuration syntax
exabgp configuration validate /etc/exabgp/exabgp.conf
# Check for syntax errors
if [ $? -eq 0 ]; then
echo "Configuration is valid"
else
echo "Configuration has errors"
exit 1
fi#!/bin/bash
# /usr/local/bin/validate-exabgp-config.sh
set -e
CONFIG_FILE="/etc/exabgp/exabgp.conf"
BACKUP_DIR="/etc/exabgp/backups"
# Create backup
mkdir -p "$BACKUP_DIR"
cp "$CONFIG_FILE" "$BACKUP_DIR/exabgp.conf.$(date +%Y%m%d-%H%M%S)"
# Validate syntax
echo "Validating configuration..."
if exabgp configuration validate "$CONFIG_FILE"; then
echo "✓ Syntax validation passed"
else
echo "✗ Syntax validation failed"
exit 1
fi
# Check for common issues
echo "Checking for common issues..."
# Check for duplicate neighbor IPs
DUPLICATES=$(grep -h "^neighbor" "$CONFIG_FILE" /etc/exabgp/conf.d/*.conf 2>/dev/null | awk '{print $2}' | sort | uniq -d)
if [ -n "$DUPLICATES" ]; then
echo "✗ Duplicate neighbor IPs found:"
echo "$DUPLICATES"
exit 1
else
echo "✓ No duplicate neighbors"
fi
# Check all included files exist
MISSING_FILES=$(grep "^include" "$CONFIG_FILE" | awk '{print $2}' | sed 's/;$//' | while read f; do [ ! -f "$f" ] && echo "$f"; done)
if [ -n "$MISSING_FILES" ]; then
echo "✗ Missing included files:"
echo "$MISSING_FILES"
exit 1
else
echo "✓ All included files exist"
fi
echo "✓ All validation checks passed"Test configuration changes in staging:
#!/bin/bash
# /usr/local/bin/test-exabgp-config.sh
STAGING_CONFIG="/etc/exabgp/staging/exabgp.conf"
PROD_CONFIG="/etc/exabgp/exabgp.conf"
# Validate staging configuration
echo "Testing staging configuration..."
exabgp configuration validate "$STAGING_CONFIG"
if [ $? -eq 0 ]; then
echo "Staging configuration valid"
# Optionally: Run in dry-run mode (if supported)
# exabgp --dry-run "$STAGING_CONFIG"
read -p "Deploy to production? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
cp "$STAGING_CONFIG" "$PROD_CONFIG"
systemctl reload exabgp
echo "Configuration deployed"
fi
else
echo "Staging configuration invalid"
exit 1
fiTrack configuration changes with git:
cd /etc/exabgp
git init
git add exabgp.conf conf.d/ processes/
git commit -m "Initial ExaBGP configuration"
# After changes
git diff
git add -A
git commit -m "Add new BGP peers for datacenter 2"Add comments liberally:
# /etc/exabgp/conf.d/core-routers.conf
# Core Router 1 - Primary route reflector
# Location: DC1, Rack A12
# Contact: netops@example.com
neighbor 192.0.2.1 {
router-id 192.0.2.10;
local-address 192.0.2.10;
local-as 65001;
peer-as 65001;
# MD5 auth enabled per security policy SEC-2023-001
md5-password include "/etc/exabgp/secrets/rr1-password.txt";
family {
ipv4 unicast;
}
}# GOOD: Consistent naming
/etc/exabgp/conf.d/01-core-routers.conf
/etc/exabgp/conf.d/02-edge-routers.conf
/etc/exabgp/conf.d/03-route-reflectors.conf
# BAD: Inconsistent naming
/etc/exabgp/core.conf
/etc/exabgp/Edges.cfg
/etc/exabgp/rr_config.txt
# Change management workflow
1. Create branch: git checkout -b add-new-peers
2. Make changes
3. Validate: exabgp configuration validate /etc/exabgp/exabgp.conf
4. Test in staging
5. Peer review: git diff
6. Merge: git merge add-new-peers
7. Deploy to production
8. Monitor for issues#!/bin/bash
# /etc/cron.daily/backup-exabgp-config.sh
BACKUP_DIR="/backup/exabgp/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# Backup configuration
cp -r /etc/exabgp "$BACKUP_DIR/"
# Compress
tar czf "$BACKUP_DIR.tar.gz" "$BACKUP_DIR"
rm -rf "$BACKUP_DIR"
# Keep only last 30 days
find /backup/exabgp/ -name "*.tar.gz" -mtime +30 -delete
echo "ExaBGP configuration backed up to $BACKUP_DIR.tar.gz"Symptoms: ExaBGP fails to start after configuration change.
Solutions:
- Check syntax:
exabgp configuration validate /etc/exabgp/exabgp.conf- Check file permissions:
ls -la /etc/exabgp/exabgp.conf
# Should be readable by exabgp user- Check included files exist:
grep "^include" /etc/exabgp/exabgp.conf | awk '{print $2}' | sed 's/;$//' | xargs ls -laSymptoms: ExaBGP startup is slow.
Solutions:
-
Use native templates to reduce config repetition (see Templates and Inheritance)
-
Profile startup time:
time exabgp /etc/exabgp/exabgp.confSymptoms: Production config differs from version control.
Solutions:
- Use configuration management (Ansible, Puppet, Chef)
- Regular audits:
# Compare production vs git
diff /etc/exabgp/exabgp.conf /path/to/git/repo/exabgp.conf- Read-only production configs:
chmod 440 /etc/exabgp/exabgp.conf
# Prevents manual edits- Configuration Syntax - Complete configuration reference
- Templates and Inheritance - Configuration reuse patterns
- Process Configuration - Process directive documentation
- Examples Index - Index of 98 configuration examples
- Best Practices - Security hardening
Getting Started
Configuration
- Configuration Syntax
- Neighbor Configuration
- Directives A-Z
- Templates
- Environment Variables
- Process Configuration
API
- API Overview
- Text API Reference
- JSON API Reference
- API Commands
- Writing API Programs
- Error Handling
- Production Best Practices
Address Families
- Overview
- IPv4 Unicast
- IPv6 Unicast
- FlowSpec
- EVPN
- L3VPN
- BGP-LS
- VPLS
- SRv6 / MUP
- Multicast
- RT Constraint
Features
Use Cases
Tools
Operations
Reference
- Architecture
- Design
- Attribute Reference
- Command Reference
- BGP State Machine
- Capabilities
- Communities
- Examples Index
- Glossary
- RFC Support
Integration
Migration
Community
External