Skip to content

Process

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

Process Configuration

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.

Table of Contents

Overview

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

Process Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  ExaBGP Main        β”‚
β”‚  Process            β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚ stdin/stdout
       β”‚ pipe communication
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  API Process        β”‚
β”‚  (Python/Bash/Go)   β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚
       β”‚ checks service/logic
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  External System    β”‚
β”‚  (Service/Monitor)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Concepts

  • 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

Basic Process Configuration

Minimal Process Configuration

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

Simple Announcement Script

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

Complete Process Syntax

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 Reference

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 with Arguments

process healthcheck {
    run /usr/bin/python3 /etc/exabgp/healthcheck.py --interval 10 --route 198.51.100.0/24;
    encoder text;
}

Process with Neighbor Updates

process monitor {
    run /etc/exabgp/monitor.py;
    encoder json;
    neighbor-changes;
    receive-routes;
}

Environment Variables

ExaBGP passes configuration information to processes via environment variables prefixed with exabgp..

Available Environment Variables

# 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

Using Environment Variables in Python

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

Using Environment Variables in Bash

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

API Communication

Text API Format

Text 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 Format

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)

Configuration for JSON Encoder

process json-api {
    run /etc/exabgp/json-api.py;
    encoder json;  # Use JSON format
}

Multiple Processes

You can configure multiple processes for different purposes.

Multiple Process Configuration

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

Process Coordination

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 Types

Health Check Process

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)

Monitoring Process

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

Traffic Engineering Process

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 minutes

FlowSpec DDoS Mitigation Process

process 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 hour

Best Practices

1. Always Flush stdout

ExaBGP 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 unbuffered

2. Handle Signals Gracefully

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

3. Use stderr for Logging

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 command

4. Keep Processes Running

Process 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!

5. Make Scripts Executable

chmod +x /etc/exabgp/announce.py

6. Use Absolute Paths

# GOOD
run /usr/bin/python3 /etc/exabgp/announce.py;

# BAD (may not work)
run python3 announce.py;

7. Test Scripts Independently

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 self

8. Monitor Process Health

Use systemd or supervisor to restart failed processes:

# /etc/systemd/system/exabgp.service
[Service]
Restart=always
RestartSec=10

Troubleshooting

Problem: Process Not Starting

Symptoms: ExaBGP logs show process start failures.

Solutions:

  1. Check script is executable:
chmod +x /etc/exabgp/announce.py
  1. Check shebang line:
#!/usr/bin/env python3  # Correct
#!/usr/bin/python3      # Also correct
  1. Test script manually:
/etc/exabgp/announce.py
# Should run without errors
  1. Check ExaBGP logs:
tail -f /var/log/exabgp/exabgp.log

Problem: Routes Not Being Announced

Symptoms: Process runs but routes don't appear.

Solutions:

  1. Ensure stdout is flushed:
print("announce route ...", flush=True)
  1. Check API is enabled for the process:
api {
    processes [ announce-routes ];  # Process must be listed
}
  1. Verify BGP session is established:
grep "Peer.*up" /var/log/exabgp/exabgp.log
  1. Check address family is configured:
family {
    ipv4 unicast;  # Must match route type
}

Problem: Process Crashes

Symptoms: Process exits unexpectedly.

Solutions:

  1. 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)
  1. Check for syntax errors:
python3 -m py_compile /etc/exabgp/announce.py
  1. Review stderr output:
# ExaBGP logs process stderr
tail -f /var/log/exabgp/exabgp.log | grep -i error

Problem: Process Receives No Updates

Symptoms: Monitoring process doesn't receive neighbor/route updates.

Solutions:

  1. Enable update reception:
process monitor {
    neighbor-changes;   # For neighbor state updates
    receive-routes;     # For route updates
}
  1. Use correct encoder:
process monitor {
    encoder json;  # Updates are in JSON format
}
  1. Read from stdin properly:
while True:
    line = sys.stdin.readline()
    if not line:
        break
    # Process update

Problem: Multiple Processes Conflict

Symptoms: Processes announce conflicting routes.

Solutions:

  1. Use different routes per process:
# Process 1: Announces 198.51.100.0/24
# Process 2: Announces 203.0.113.0/24
  1. Coordinate via shared state:
# Use lock file or shared state file
  1. Use single master process:
# One process coordinates and announces all routes

See Also


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

Clone this wiki locally