Skip to content

Large Configuration File

Thomas Mangin edited this page Nov 15, 2025 · 1 revision

Managing Large Configuration Files

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.

Table of Contents

Overview

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.

When You Need Large Configuration Management

  • 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

Configuration Organization

Directory Structure

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

Main Configuration File

The main file includes modular components:

# /etc/exabgp/exabgp.conf
# Main ExaBGP Configuration

# Global settings
log {
    all = true;
    destination = /var/log/exabgp/exabgp.log;
    level = INFO;
}

# Include process definitions
include /etc/exabgp/processes/*.conf;

# Include neighbor definitions
include /etc/exabgp/conf.d/*.conf;

Templates and Inheritance

Using Configuration Templates

ExaBGP doesn't have native template support, but you can use external tools to generate configurations from templates.

Template Example (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 %}
    ttl-security 255;
    {% endif %}

    family {
        {% for family in address_families %}
        {{ family }};
        {% endfor %}
    }

    {% if route_reflector_client %}
    route-reflector-client;
    {% endif %}

    {% if cluster_id %}
    cluster-id {{ cluster_id }};
    {% endif %}

    {% if api_processes %}
    api {
        processes [ {{ api_processes | join(', ') }} ];
    }
    {% endif %}
}

Data File (YAML)

# /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

Generation Script (Python)

#!/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")

Running the Generator

#!/bin/bash
# /usr/local/bin/update-exabgp-config.sh

# Generate configuration
/usr/local/bin/generate-exabgp-config.py

# Validate configuration
exabgp --test /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
fi

File Inclusion

Include Directive

ExaBGP supports including external files:

# /etc/exabgp/exabgp.conf

# Include single file
include /etc/exabgp/processes/healthcheck.conf;

# Include all files in directory
include /etc/exabgp/conf.d/*.conf;

# Include with absolute path
include /etc/exabgp/neighbors/core-routers.conf;

Modular Neighbor Configuration

# /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;
    }
}

Modular Process Configuration

# /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;
}

Variable Substitution

While ExaBGP doesn't natively support variables, you can use preprocessing tools.

Using m4 for Variable Substitution

# /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

Using Environment Variables (in scripts)

#!/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

Configuration Generation

Python Configuration Generator

#!/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("    ttl-security 255;")

            lines.append("    family {")
            for family in neighbor['families']:
                lines.append(f"        {family};")
            lines.append("    }")
            lines.append("")

            if neighbor.get('route_reflector_client'):
                lines.append("    route-reflector-client;")

            if neighbor.get('cluster_id'):
                lines.append(f"    cluster-id {neighbor['cluster_id']};")

            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")

Ansible Playbook for Configuration Management

# /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 --test /etc/exabgp/exabgp.conf
      register: validation
      changed_when: false

  handlers:
    - name: Reload ExaBGP
      systemd:
        name: exabgp
        state: reloaded

Performance Considerations

Configuration Loading Time

Large configurations can take time to load. Optimize:

# SLOW: Many small include files
include /etc/exabgp/neighbors/neighbor-*.conf;  # 100+ files

# FASTER: Fewer larger files
include /etc/exabgp/conf.d/*.conf;  # 5-10 files

Memory Usage

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

BGP Session Establishment

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)

Validation and Testing

Configuration Validation

Always validate before deploying:

# Validate configuration syntax
exabgp --test /etc/exabgp/exabgp.conf

# Check for syntax errors
if [ $? -eq 0 ]; then
    echo "Configuration is valid"
else
    echo "Configuration has errors"
    exit 1
fi

Automated Validation Script

#!/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 --test "$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"

Integration Testing

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 --test "$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
fi

Best Practices

1. Use Version Control

Track 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"

2. Document Your Configuration

Add comments liberally:

# /etc/exabgp/conf.d/core-routers.conf

# Core Router 1 - Primary route reflector
# Location: DC1, Rack A12
# Contact: [email protected]
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;
    }
}

3. Use Consistent Naming

# 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

4. Implement Change Management

# Change management workflow
1. Create branch: git checkout -b add-new-peers
2. Make changes
3. Validate: exabgp --test /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

5. Regular Backups

#!/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"

Troubleshooting

Problem: Configuration Not Loading

Symptoms: ExaBGP fails to start after configuration change.

Solutions:

  1. Check syntax:
exabgp --test /etc/exabgp/exabgp.conf
  1. Check file permissions:
ls -la /etc/exabgp/exabgp.conf
# Should be readable by exabgp user
  1. Check included files exist:
grep "^include" /etc/exabgp/exabgp.conf | awk '{print $2}' | sed 's/;$//' | xargs ls -la

Problem: Configuration Takes Long to Load

Symptoms: ExaBGP startup is slow.

Solutions:

  1. Reduce number of include files:
# Consolidate multiple small files into larger files
cat /etc/exabgp/neighbors/*.conf > /etc/exabgp/conf.d/all-neighbors.conf
  1. Profile startup time:
time exabgp /etc/exabgp/exabgp.conf

Problem: Configuration Drift

Symptoms: Production config differs from version control.

Solutions:

  1. Use configuration management (Ansible, Puppet, Chef)
  2. Regular audits:
# Compare production vs git
diff /etc/exabgp/exabgp.conf /path/to/git/repo/exabgp.conf
  1. Read-only production configs:
chmod 440 /etc/exabgp/exabgp.conf
# Prevents manual edits

See Also


πŸ‘» Ghost written by Claude (Anthropic AI)

Clone this wiki locally