Skip to content

API Commands

Thomas Mangin edited this page Nov 23, 2025 · 12 revisions

API Commands Reference

A-Z alphabetical reference for all ExaBGP API commands

πŸ“š For detailed examples and patterns, see Text API Reference and JSON API Reference


Table of Contents


Command Format

All API commands are sent to ExaBGP via STDOUT from your process.

Basic pattern:

import sys

# Send command
sys.stdout.write("announce route 100.10.0.100/32 next-hop self\n")
sys.stdout.flush()  # CRITICAL: Always flush!

Important:

  • βœ… Always end commands with \n
  • βœ… Always call sys.stdout.flush() after writing
  • βœ… Commands are case-sensitive
  • βœ… ExaBGP 4.x and 5.0.0+ send ACK responses by default (done/error/shutdown)
  • ℹ️ ACK can be disabled:
    • Environment variable: exabgp.api.ack=false (4.x and 5.0.0+)
    • Runtime commands: disable-ack or silence-ack (5.0.0+ only)

Neighbor Selectors (Targeting Specific Peers)

When you have multiple BGP peers configured with the same API process, you can use neighbor selectors to target specific peers with your announce/withdraw commands.

Syntax

neighbor <ip> [<selector-options>] <command>

By default, commands apply to all configured neighbors (equivalent to neighbor *). Use the neighbor keyword when you want to target specific peer(s) instead of broadcasting to all neighbors.

Selector Options

Use these optional filters to differentiate between multiple peers with the same IP or to target groups of peers:

Selector Purpose Example
neighbor <ip> Required: Target specific neighbor by IP neighbor 127.0.0.1
local-ip <ip> Filter by local IP address local-ip 192.168.1.2
local-as <asn> Filter by local ASN local-as 65001
peer-as <asn> Filter by peer ASN peer-as 65000
router-id <id> Filter by router ID router-id 192.168.1.1
family-allowed <families> Filter by address family capabilities family-allowed ipv4-unicast/ipv6-unicast

Special Syntax

Multiple neighbors (comma-separated):

# Target multiple specific neighbors
neighbor 127.0.0.1,192.168.1.1 announce route 10.0.0.0/24 next-hop self

Wildcard (all neighbors):

# Target ALL configured neighbors
neighbor * announce route 10.0.0.0/24 next-hop self

Basic Examples

Simple single neighbor:

# Announce to specific neighbor
sys.stdout.write("neighbor 127.0.0.1 announce route 10.0.0.0/24 next-hop 192.168.1.1\n")
sys.stdout.flush()

Target all neighbors:

# Announce to all neighbors
sys.stdout.write("neighbor * announce route 10.0.0.0/24 next-hop self\n")
sys.stdout.flush()

Multiple neighbors:

# Announce to two specific neighbors
sys.stdout.write("neighbor 10.0.0.1,10.0.0.2 announce route 100.10.0.0/24 next-hop self\n")
sys.stdout.flush()

Advanced Examples with Filters

Differentiate by local ASN:

# If you have multiple neighbors at same IP but different local-as
sys.stdout.write("neighbor 127.0.0.1 local-as 65000 announce route 10.0.0.0/24 next-hop self\n")
sys.stdout.flush()

Differentiate by peer ASN:

# Target specific peer-as
sys.stdout.write("neighbor 127.0.0.1 peer-as 65001 announce route 10.0.0.0/24 next-hop self\n")
sys.stdout.flush()

Multiple selectors:

# Combine multiple selectors for precise targeting
sys.stdout.write("neighbor 127.0.0.1 local-as 65000 peer-as 65001 announce route 10.0.0.0/24 next-hop self\n")
sys.stdout.flush()

Filter by address family:

# Target neighbors that support IPv4 unicast
sys.stdout.write("neighbor * family-allowed ipv4-unicast announce route 10.0.0.0/24 next-hop self\n")
sys.stdout.flush()

# Target neighbors supporting both IPv4 and IPv6 unicast (multi-session)
sys.stdout.write("neighbor * family-allowed ipv4-unicast/ipv6-unicast announce route 10.0.0.0/24 next-hop self\n")
sys.stdout.flush()

# Target neighbors with FlowSpec capability
sys.stdout.write("neighbor * family-allowed ipv4-flowspec announce flow route { match { destination 10.0.0.0/8; } then { discard; } }\n")
sys.stdout.flush()

Complete Example: Multi-Peer Announcement

#!/usr/bin/env python3
"""
multi_peer_announce.py - Announce different routes to different peers
"""
import sys
import time

time.sleep(2)  # Wait for BGP sessions

# Announce to all neighbors
sys.stdout.write("neighbor * announce route 100.10.0.0/24 next-hop self\n")
sys.stdout.flush()

# Announce specific route to specific neighbor
sys.stdout.write("neighbor 192.168.1.1 announce route 100.20.0.0/24 next-hop self\n")
sys.stdout.flush()

# Announce to multiple neighbors
sys.stdout.write("neighbor 192.168.1.1,192.168.1.2 announce route 100.30.0.0/24 next-hop self\n")
sys.stdout.flush()

# Target by peer AS
sys.stdout.write("neighbor 192.168.1.1 peer-as 65000 announce route 100.40.0.0/24 next-hop self\n")
sys.stdout.flush()

# Keep running
while True:
    time.sleep(60)

Understanding family-allowed

The family-allowed selector filters neighbors based on their negotiated address family capabilities. The value format depends on the neighbor configuration:

Single-session neighbors (default):

  • Value: in-open
  • All address families are negotiated in the BGP OPEN message
  • Example: family-allowed in-open

Multi-session neighbors (when multi-session capability is enabled):

  • Value: Slash-separated list of address families
  • Format: <afi>-<safi>/<afi>-<safi>/...
  • Example: family-allowed ipv4-unicast/ipv6-unicast/ipv4-flowspec

Common address family values:

  • ipv4-unicast - IPv4 unicast routes
  • ipv6-unicast - IPv6 unicast routes
  • ipv4-flowspec - IPv4 FlowSpec rules
  • ipv6-flowspec - IPv6 FlowSpec rules
  • ipv4-mpls-vpn - IPv4 L3VPN (VPNv4)
  • ipv6-mpls-vpn - IPv6 L3VPN (VPNv6)
  • l2vpn-evpn - EVPN routes
  • ipv4-multicast - IPv4 multicast
  • ipv6-multicast - IPv6 multicast

Examples:

# Target only neighbors with FlowSpec capability (multi-session)
sys.stdout.write("neighbor * family-allowed ipv4-flowspec announce flow route { match { destination 10.0.0.0/8; } then { discard; } }\n")
sys.stdout.flush()

# Target neighbors with dual-stack unicast capability
sys.stdout.write("neighbor * family-allowed ipv4-unicast/ipv6-unicast announce route 10.0.0.0/24 next-hop self\n")
sys.stdout.flush()

# Target single-session neighbors (all families negotiated in OPEN)
sys.stdout.write("neighbor * family-allowed in-open announce route 10.0.0.0/24 next-hop self\n")
sys.stdout.flush()

Use case: Send FlowSpec rules only to neighbors that support FlowSpec, avoiding errors on neighbors that don't support it.

Use Cases

1. Per-Peer Route Customization:

# Announce different routes to different transit providers
sys.stdout.write("neighbor 10.0.1.1 announce route 100.10.0.0/24 next-hop self as-path [65001 65001]\n")  # Provider A
sys.stdout.flush()

sys.stdout.write("neighbor 10.0.2.1 announce route 100.10.0.0/24 next-hop self\n")  # Provider B (preferred)
sys.stdout.flush()

2. Geographic Load Balancing:

# US datacenter announces to US peers
sys.stdout.write("neighbor 192.168.1.1 announce route 100.10.0.100/32 next-hop self local-preference 200\n")
sys.stdout.flush()

# EU datacenter announces to EU peers
sys.stdout.write("neighbor 192.168.2.1 announce route 100.10.0.100/32 next-hop self local-preference 100\n")
sys.stdout.flush()

3. ASN-Based Filtering:

# Only announce to peers in specific AS
sys.stdout.write("neighbor * peer-as 65000 announce route 10.0.0.0/8 next-hop self\n")
sys.stdout.flush()

Important Notes

  • πŸ’‘ Default behavior: Commands without neighbor selector apply to all configured neighbors (equivalent to neighbor *)
  • πŸ’‘ Selective targeting: Use neighbor keyword to target specific peer(s) instead of all neighbors
  • πŸ’‘ The neighbor selector always comes before the command (announce/withdraw)
  • πŸ’‘ Selectors are evaluated as AND logic - all specified selectors must match
  • πŸ’‘ If no neighbor matches your selectors, the command is silently ignored

Configuration Example

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 [ my-program ];
    }
}

neighbor 192.168.2.1 {
    router-id 192.168.1.2;
    local-address 192.168.1.2;
    local-as 65001;
    peer-as 65002;

    api {
        processes [ my-program ];
    }
}

process my-program {
    run /etc/exabgp/api/announce.py;
    encoder text;
}

With this configuration, your API program can selectively target either neighbor using selectors.


Announce Commands

Commands to advertise BGP routes.

announce route

Announce IPv4/IPv6 unicast route

announce route <prefix> next-hop <ip> [attributes]

Examples:

# Basic IPv4
announce route 100.10.0.100/32 next-hop self

# IPv6
announce route 2001:db8::1/128 next-hop 2001:db8::2

# With attributes
announce route 100.10.0.100/32 next-hop self community [65001:100]
announce route 100.10.0.100/32 next-hop self as-path [65001 65002]
announce route 100.10.0.100/32 next-hop self local-preference 200
announce route 100.10.0.100/32 next-hop self med 50

Attributes:

  • next-hop self - Use local router IP
  • next-hop <ip> - Explicit next-hop
  • community [<asn>:<value>] - BGP communities
  • as-path [<asn> ...] - AS path
  • local-preference <n> - Local preference (higher = preferred)
  • med <n> - Multi-Exit Discriminator (lower = preferred)
  • origin igp|egp|incomplete - Origin attribute

See also:


announce flow

Announce FlowSpec rule

announce flow route { match { <conditions> } then { <actions> } }

Examples:

# Block TCP port 80 from 10.0.0.0/8
announce flow route { match { source 10.0.0.0/8; destination-port =80; protocol =tcp; } then { discard; } }

# Rate-limit DNS
announce flow route { match { destination-port =53; protocol =udp; } then { rate-limit 1000000; } }

# Block SYN flood
announce flow route { match { destination-port =443; tcp-flags [ syn ]; protocol =tcp; } then { discard; } }

# Redirect to VRF
announce flow route { match { destination 100.10.0.0/24; } then { redirect 65001:100; } }

Match conditions:

  • source <prefix> - Source IP
  • destination <prefix> - Destination IP
  • protocol =<n> - IP protocol (tcp=6, udp=17, icmp=1)
  • source-port <op><n> - Source port
  • destination-port <op><n> - Destination port
  • packet-length <op><n> - Packet length
  • tcp-flags [ <flags> ] - TCP flags
  • icmp-type =<n> - ICMP type
  • icmp-code =<n> - ICMP code
  • fragment [ <flags> ] - Fragment flags
  • dscp =<n> - DSCP value

Actions:

  • discard - Drop packets
  • rate-limit <bytes/sec> - Rate limit
  • redirect <rt> - Redirect to VRF
  • mark <dscp> - Mark DSCP
  • community [ <communities> ] - Tag with community

See also:


announce vpnv4

Announce L3VPN IPv4 route

announce vpnv4 <prefix> next-hop <ip> route-distinguisher <rd> [attributes]

Examples:

# Basic VPNv4
announce vpnv4 10.0.0.0/24 next-hop 192.168.1.2 route-distinguisher 65001:100

# With label and route-target
announce vpnv4 10.0.0.0/24 next-hop 192.168.1.2 route-distinguisher 65001:100 label 16 extended-community [ target:65001:100 ]

See also:


announce vpnv6

Announce L3VPN IPv6 route

announce vpnv6 <prefix> next-hop <ip> route-distinguisher <rd> [attributes]

Examples:

announce vpnv6 2001:db8::/32 next-hop 2001:db8::1 route-distinguisher 65001:100
announce vpnv6 2001:db8::/32 next-hop 2001:db8::1 route-distinguisher 65001:100 label 16

See also:


announce evpn

Announce EVPN route

EVPN MAC Advertisement:

announce evpn macadvertisement aa:bb:cc:dd:ee:ff 100.10.0.1 1000 rd 65001:100 route-target [ target:65001:100 ]

EVPN Multicast:

announce evpn multicast 192.168.1.1 rd 65001:100 route-target [ target:65001:100 ]

See also:


announce vpls

Announce VPLS route

announce vpls <endpoint> <offset> <size> rd <rd> route-target [ <rt> ]

Example:

announce vpls 192.168.1.1 10 8 rd 65001:100 route-target [ target:65001:100 ]

See also:


announce refresh

Request route refresh from peer

announce refresh <afi> <safi>

Examples:

# Request IPv4 unicast refresh
announce refresh ipv4 unicast

# Request FlowSpec refresh
announce refresh ipv4 flowspec

See also:


Withdraw Commands

Commands to remove previously announced routes.

withdraw route

Withdraw IPv4/IPv6 unicast route

withdraw route <prefix> next-hop <ip>

Examples:

# Withdraw IPv4
withdraw route 100.10.0.100/32 next-hop self

# Withdraw IPv6
withdraw route 2001:db8::1/128 next-hop 2001:db8::2

# Alternative: withdraw by prefix only (if unique)
withdraw route 100.10.0.100/32

Important: Withdrawal must match announcement (prefix + next-hop + attributes).

See also:


withdraw flow

Withdraw FlowSpec rule

withdraw flow route { match { <conditions> } }

Examples:

# Withdraw by exact match
withdraw flow route { match { source 10.0.0.0/8; destination-port =80; protocol =tcp; } }

# Auto-withdraw pattern
import threading

def auto_withdraw(rule, timeout=300):
    time.sleep(timeout)
    withdraw = rule.replace('announce', 'withdraw').replace('then { discard; }', '')
    sys.stdout.write(withdraw + "\n")
    sys.stdout.flush()

rule = "announce flow route { match { source 10.0.0.0/8; } then { discard; } }"
sys.stdout.write(rule + "\n")
sys.stdout.flush()

threading.Thread(target=auto_withdraw, args=(rule,)).start()

See also:


withdraw vpnv4

Withdraw L3VPN IPv4 route

withdraw vpnv4 <prefix> next-hop <ip> route-distinguisher <rd>

Example:

withdraw vpnv4 10.0.0.0/24 next-hop 192.168.1.2 route-distinguisher 65001:100

withdraw vpnv6

Withdraw L3VPN IPv6 route

withdraw vpnv6 <prefix> next-hop <ip> route-distinguisher <rd>

Example:

withdraw vpnv6 2001:db8::/32 next-hop 2001:db8::1 route-distinguisher 65001:100

withdraw evpn

Withdraw EVPN route

withdraw evpn macadvertisement aa:bb:cc:dd:ee:ff 100.10.0.1 1000 rd 65001:100

withdraw vpls

Withdraw VPLS route

withdraw vpls 192.168.1.1 10 8 rd 65001:100

Operational Commands

Commands for BGP session control and monitoring.

shutdown

Gracefully shutdown ExaBGP

shutdown

Example:

import signal
import sys

def signal_handler(sig, frame):
    sys.stdout.write("shutdown\n")
    sys.stdout.flush()
    sys.exit(0)

signal.signal(signal.SIGTERM, signal_handler)

Effect:

  • Sends BGP NOTIFICATION to all peers
  • Closes connections gracefully
  • Exits ExaBGP process

restart

Restart BGP connection to peer

restart

Example:

# Restart after configuration change
sys.stdout.write("restart\n")
sys.stdout.flush()

Effect:

  • Closes existing connections
  • Re-reads configuration
  • Establishes new connections

reload

Reload configuration without restarting

reload

Effect:

  • Re-reads configuration file
  • Applies changes without dropping sessions (if possible)

version

Query ExaBGP version

version

Response (on STDIN):

exabgp 4.2.25

Control Commands

Commands for flow control and debugging.

flush

Flush pending route updates

flush

Use case:

# Announce multiple routes, then flush
for prefix in prefixes:
    sys.stdout.write(f"announce route {prefix} next-hop self\n")

sys.stdout.write("flush\n")
sys.stdout.flush()

Effect: Forces ExaBGP to send pending BGP UPDATEs immediately.


enable-ack

Re-enable ACK responses (ExaBGP 5.0.0+, safe on 4.x)

enable-ack

Behavior:

  • βœ… ExaBGP 5.0.0+: Sends "done" ACK, re-enables ACK for future commands
  • ⚠️ ExaBGP 4.x: Prints warning but continues (safe, no harm)
  • βœ… All future commands will receive ACK responses (done or error)

Use case:

# Re-enable error checking after fire-and-forget mode
sys.stdout.write("enable-ack\n")
sys.stdout.flush()

# Check for "done" response to confirm ACK is re-enabled
# Now all future commands will receive ACK

disable-ack

Disable ACK responses gracefully (ExaBGP 5.0.0+, safe on 4.x)

disable-ack

Behavior:

  • βœ… ExaBGP 5.0.0+: Sends final "done" ACK, then disables future ACKs
  • ⚠️ ExaBGP 4.x: Prints warning but continues (safe, no harm)
  • ❌ Future commands will NOT receive ACK responses (fire-and-forget mode)

Use cases:

  1. Transition to high-performance mode
  2. Best practice for non-ACK-aware programs on ExaBGP 5.0.0+

Example:

# Transition to high-performance mode
sys.stdout.write("disable-ack\n")
sys.stdout.flush()

# Receive final "done" ACK confirming ACK is now disabled
# Future commands are fire-and-forget (no ACK overhead)

for i in range(10000):
    prefix = f"10.{i//256}.{i%256}.0/24"
    sys.stdout.write(f"announce route {prefix} next-hop self\n")
    sys.stdout.flush()
    # No ACK expected - maximum performance

silence-ack

Disable ACK responses immediately (ExaBGP 5.0.0+, safe on 4.x)

silence-ack

Behavior:

  • ❌ ExaBGP 5.0.0+: Does NOT send ACK for this command (immediate silence)
  • ⚠️ ExaBGP 4.x: Prints warning but continues (safe, no harm)
  • ❌ Future commands will NOT receive ACK responses (fire-and-forget mode)

Use case:

# Maximum performance - skip even the final ACK
sys.stdout.write("silence-ack\n")
sys.stdout.flush()

# No ACK expected for silence-ack itself
# All future commands are fire-and-forget (no ACK overhead)

for i in range(10000):
    prefix = f"10.{i//256}.{i%256}.0/24"
    sys.stdout.write(f"announce route {prefix} next-hop self\n")
    sys.stdout.flush()

Comparison:

Command Sends ACK for itself? Future commands ACKed?
enable-ack βœ… Yes ("done") βœ… Yes
disable-ack βœ… Yes (final "done") ❌ No
silence-ack ❌ No (immediate silence) ❌ No

Version compatibility:

  • ExaBGP 4.x: Commands are ignored with warning (safe, no harm)
  • ExaBGP 5.x/main: ACK can be controlled dynamically with these runtime commands

Best practice for non-ACK-aware programs:

If you're using ExaBGP 5.x/main with API programs that don't handle ACK responses, send disable-ack at startup:

#!/usr/bin/env python3
import sys
import time

# Safe on all ExaBGP versions (5.x disables, 4.x warns but continues)
sys.stdout.write("disable-ack\n")
sys.stdout.flush()
time.sleep(0.1)

# Your legacy code works without modification
while True:
    sys.stdout.write("announce route 100.10.0.100/32 next-hop self\n")
    sys.stdout.flush()
    time.sleep(5)

For maximum compatibility across ExaBGP 4.x and 5.x, combine both methods:

# Set environment variable (works on 4.x and 5.x)
export exabgp.api.ack=false

# AND send disable-ack in your program (defense-in-depth)

See also:


Quick Reference Table

Command Purpose Example
announce route Announce IPv4/IPv6 route announce route 1.1.1.1/32 next-hop self
announce flow Announce FlowSpec rule announce flow route { match { ... } then { ... } }
announce vpnv4 Announce L3VPN IPv4 announce vpnv4 10.0.0.0/24 ... rd 65001:100
announce vpnv6 Announce L3VPN IPv6 announce vpnv6 2001:db8::/32 ... rd 65001:100
announce evpn Announce EVPN route announce evpn macadvertisement ...
announce vpls Announce VPLS route announce vpls 192.168.1.1 ...
announce refresh Request route refresh announce refresh ipv4 unicast
withdraw route Withdraw IPv4/IPv6 route withdraw route 1.1.1.1/32
withdraw flow Withdraw FlowSpec rule withdraw flow route { match { ... } }
withdraw vpnv4 Withdraw L3VPN IPv4 withdraw vpnv4 10.0.0.0/24 ... rd 65001:100
withdraw vpnv6 Withdraw L3VPN IPv6 withdraw vpnv6 2001:db8::/32 ... rd 65001:100
withdraw evpn Withdraw EVPN route withdraw evpn macadvertisement ...
withdraw vpls Withdraw VPLS route withdraw vpls 192.168.1.1 ...
shutdown Gracefully shutdown shutdown
restart Restart BGP session restart
reload Reload configuration reload
version Query version version
flush Flush pending updates flush
enable-ack Re-enable ACK responses (5.x/main, safe on 4.x) enable-ack
disable-ack Disable ACK gracefully (5.x/main, safe on 4.x) disable-ack
silence-ack Disable ACK immediately (5.x/main, safe on 4.x) silence-ack

Command Acknowledgment (ACK)

ACK Feature (Enabled by Default)

ExaBGP 4.x and 5.x send command acknowledgments via STDIN (enabled by default).

Response types:

done       # Command succeeded
error      # Command failed
shutdown   # ExaBGP is shutting down

Robust pattern with polling loop:

#!/usr/bin/env python3
import sys
import select
import time

def wait_for_ack(expected_count=1, timeout=30):
    """
    Wait for ACK responses with polling loop.
    ExaBGP may not respond immediately, so we poll with sleep.

    Handles both text and JSON encoder formats:
    - Text: "done", "error", "shutdown"
    - JSON: {"answer": "done|error|shutdown", "message": "..."}
    """
    import json
    received = 0
    start_time = time.time()

    while received < expected_count:
        if time.time() - start_time >= timeout:
            return False

        ready, _, _ = select.select([sys.stdin], [], [], 0.1)
        if ready:
            line = sys.stdin.readline().strip()

            # Parse response (could be text or JSON)
            answer = None
            if line.startswith('{'):
                try:
                    data = json.loads(line)
                    answer = data.get('answer')
                except:
                    pass
            else:
                answer = line

            if answer == "done":
                received += 1
            elif answer == "error":
                return False
            elif answer == "shutdown":
                raise SystemExit(0)
        else:
            time.sleep(0.1)

    return True

def send_command(command):
    """Send command and wait for ACK"""
    sys.stdout.write(command + "\n")
    sys.stdout.flush()
    return wait_for_ack(expected_count=1)

# Use it
send_command("announce route 100.10.0.100/32 next-hop self")

Configuration:

[exabgp.api]
ack = true  # Default in 5.x/main

See also:


ExaBGP 4.x (No ACK)

ExaBGP 4.x does NOT send acknowledgments.

Pattern (fire-and-forget):

#!/usr/bin/env python3
import sys
import time

# Send commands (no ACK)
sys.stdout.write("announce route 100.10.0.100/32 next-hop self\n")
sys.stdout.flush()

# Add delay to avoid overwhelming ExaBGP
time.sleep(0.1)

Issues:

  • ❌ No confirmation of success/failure
  • ❌ Hard to debug command errors
  • ❌ Can't detect ExaBGP shutdown

Upgrade to ExaBGP 5.x/main for ACK support.


Common Errors

Error: Command not sent

Symptom: Routes not announced, no error message.

Cause: Forgot to flush STDOUT.

Fix:

# ❌ WRONG
sys.stdout.write("announce route 100.10.0.100/32 next-hop self\n")
# Buffer not flushed!

# βœ… CORRECT
sys.stdout.write("announce route 100.10.0.100/32 next-hop self\n")
sys.stdout.flush()  # Always flush!

Error: Syntax error in command

Symptom (ExaBGP 5.x): error response.

Cause: Invalid command syntax.

Examples:

# ❌ Missing next-hop
announce route 100.10.0.100/32

# βœ… Correct
announce route 100.10.0.100/32 next-hop self

# ❌ Invalid FlowSpec syntax
announce flow route { match { source 10.0.0.0/8 } }  # Missing 'then'

# βœ… Correct
announce flow route { match { source 10.0.0.0/8; } then { discard; } }

Fix: Check command syntax against this reference.


Error: Withdrawal doesn't match

Symptom: Route not withdrawn.

Cause: Withdrawal doesn't match announcement exactly.

Example:

# Announce with community
announce route 100.10.0.100/32 next-hop self community [65001:100]

# ❌ Withdraw without community (doesn't match)
withdraw route 100.10.0.100/32 next-hop self

# βœ… Withdraw with same attributes
withdraw route 100.10.0.100/32 next-hop self community [65001:100]

Fix: Withdrawal must match all attributes from announcement.


Error: Process hangs waiting for input

Symptom (ExaBGP 5.x): Process blocks after sending command.

Cause: Not reading ACK response from STDIN.

Fix:

# ❌ WRONG (blocks forever)
sys.stdout.write("announce route 100.10.0.100/32 next-hop self\n")
sys.stdout.flush()
# ExaBGP waiting to send 'done', but we're not reading!

# βœ… CORRECT
sys.stdout.write("announce route 100.10.0.100/32 next-hop self\n")
sys.stdout.flush()

# Read ACK
response = sys.stdin.readline().strip()  # or use select()

Error: Too many commands too fast

Symptom: Routes not announced, ExaBGP unresponsive.

Cause: Overwhelming ExaBGP with rapid commands.

Fix:

# ❌ WRONG (too fast)
for prefix in range(1000):
    sys.stdout.write(f"announce route 10.0.{prefix}.0/24 next-hop self\n")
    sys.stdout.flush()

# βœ… CORRECT (batched)
for prefix in range(1000):
    sys.stdout.write(f"announce route 10.0.{prefix}.0/24 next-hop self\n")

    if prefix % 100 == 0:
        sys.stdout.flush()
        time.sleep(0.1)  # Give ExaBGP time to process

sys.stdout.flush()

Or use flush command:

for prefix in range(1000):
    sys.stdout.write(f"announce route 10.0.{prefix}.0/24 next-hop self\n")

sys.stdout.write("flush\n")
sys.stdout.flush()

Next Steps

Learn More

Examples

Production


Need help? Join the ExaBGP Slack or check GitHub Discussions β†’


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

Clone this wiki locally