-
Notifications
You must be signed in to change notification settings - Fork 460
From 5.x to 6.x
Complete guide for upgrading from ExaBGP 5.x to 6.0.0 (main branch)
β οΈ BREAKING CHANGES: ExaBGP 6.0.0 introduces breaking changes from 5.xExaBGP 6.0.0 brings modernization and new features, but requires careful migration planning.
Key Changes:
- β Python 3.7-3.11 dropped (Python 3.12+ required)
β οΈ Async reactor is now the default (no option to switch to legacy mode)β οΈ BGP-LS JSON API field changes (ip, sr-adj, remote-router-id)- β New shell completion (Bash, Zsh, Fish)
- β Enhanced interactive CLI
- β Health monitoring API commands
- β Migration tool for config and API conversion
- Overview
- Should You Upgrade?
- What Changed
- Breaking Changes
- New Features in 6.0.0
- Migration Tool
- Migration Steps
- Testing Your Migration
- Rollback Plan
- Common Issues
Release: ExaBGP 6.0.0 (main branch)
Severity: π‘ MEDIUM - Breaking changes, but migration tools available
Timeline: ExaBGP 6.0.0 becomes the new development branch. ExaBGP 5.0.0 remains LTS for stability.
Changes: Async reactor default, Python 3.12+, BGP-LS JSON changes, new CLI features
- β You want the async reactor for modern event loop integration
- β You need shell completion (Bash, Zsh, Fish)
- β You want enhanced CLI with tab completion and JSON pretty-printing
- β You need health monitoring API commands
- β You're already on Python 3.12+
- β You can test thoroughly before production deployment
- βΈοΈ You cannot upgrade to Python 3.12+
- βΈοΈ You're using BGP-LS JSON API (field names changed - see below)
- βΈοΈ You need guaranteed stability for production
- βΈοΈ You cannot test the migration thoroughly
Recommendation: Test 6.0.0 in staging first. ExaBGP 5.x remains a stable LTS option.
| Area | Change | Impact |
|---|---|---|
| Python | 3.12+ required (3.7-3.11 dropped) | π΄ CRITICAL - System upgrade needed |
| Reactor | Async mode now default (generators still work) | π’ LOW - Test your workloads |
| BGP-LS JSON |
ip β prefix (CIDR notation) |
π΄ HIGH - Parser updates required |
| BGP-LS JSON |
sr-adj β sr-adjs (array) |
π΄ HIGH - Parser updates required |
| BGP-LS JSON |
remote-router-id β remote-router-ids (array) |
π΄ HIGH - Parser updates required |
- β Async Reactor Default - Modern async/await event loop
- β Shell Completion - Bash, Zsh, Fish support
- β Enhanced CLI - Tab completion, JSON pretty-printing, inline help
- β
Health Monitoring -
session pinganddaemon statuscommands - β Migration Tool - Automatic config and API conversion
- β Type Annotations - Better IDE support and type safety
- β Python 3.12/3.13/3.14 - Full support for latest Python versions
- β Python 3.8+ minimum
- β Python 3.13 supported
- β Python 3.7-3.11 dropped
- β Python 3.12+ minimum
- β Python 3.13 and 3.14 supported
# Check your Python version
python3 --version
# If < 3.12, upgrade Python first
# Ubuntu/Debian:
sudo apt install python3.12
# RHEL/CentOS/Fedora:
sudo dnf install python3.12
# macOS:
brew install [email protected]
# Verify
python3.12 --versionImpact: If you're on Python 3.8-3.11, you must upgrade Python before upgrading ExaBGP.
ExaBGP 6.0.0 uses a modern async/await-based event loop as the default reactor. The separate "legacy reactor" mode toggle has been removed - all execution now goes through the unified async system.
- Performance: Better event loop integration using Python's native asyncio
- Modern: Uses Python's native async/await patterns
- Backward Compatible: Generator-based callbacks still work (they run inside asyncio.run())
- Tested: Comprehensive test coverage (72/72 functional tests, 1,376 unit tests)
- Test your workloads - most users won't notice a difference since generators still work
- Report issues on GitHub if you encounter any problems
- There is no option to switch back to a separate legacy reactor mode
- Your existing generator-based API scripts should continue to work unchanged
ExaBGP 5.x (Old):
{
"bgp-ls": {
"ip": "10.134.2.88"
}
}ExaBGP 6.0.0 (New):
{
"bgp-ls": {
"prefix": "10.134.2.88/30"
}
}Changes:
- Key renamed from
iptoprefix - Now includes prefix length in CIDR notation
ExaBGP 5.x (Old - duplicate keys):
{
"bgp-ls": {
"sr-adj": {"sid": 100, "flags": "0x80"},
"sr-adj": {"sid": 200, "flags": "0x40"}
}
}ExaBGP 6.0.0 (New - array):
{
"bgp-ls": {
"sr-adjs": [
{"sid": 100, "flags": "0x80"},
{"sid": 200, "flags": "0x40"}
]
}
}Changes:
- Key renamed from
sr-adjtosr-adjs - Now outputs as array of objects instead of duplicate keys
- Valid JSON (no duplicate keys)
ExaBGP 5.x (Old - duplicate keys):
{
"bgp-ls": {
"remote-router-id": "192.0.2.1",
"remote-router-id": "2001:db8::1"
}
}ExaBGP 6.0.0 (New - array):
{
"bgp-ls": {
"remote-router-ids": ["192.0.2.1", "2001:db8::1"]
}
}Changes:
- Key renamed from
remote-router-idtoremote-router-ids - IPv4 and IPv6 router IDs merged into single array
- Valid JSON (no duplicate keys)
Update your BGP-LS JSON parsers:
# Old 5.x parser
ip_prefix = data['bgp-ls']['ip']
adj_sid = data['bgp-ls']['sr-adj'] # Only gets last duplicate
router_id = data['bgp-ls']['remote-router-id'] # Only gets last duplicate
# New 6.0.0 parser
ip_prefix = data['bgp-ls']['prefix'] # Now includes /length
adj_sids = data['bgp-ls']['sr-adjs'] # Array of all SIDs
for sid in adj_sids:
print(f"SID: {sid['sid']}, Flags: {sid['flags']}")
router_ids = data['bgp-ls']['remote-router-ids'] # Array of all IDsDynamic completion generation for Bash, Zsh, and Fish:
# Auto-detect shell and install
exabgp shell install
# Or specify shell
exabgp shell install bash
exabgp shell install zsh
exabgp shell install fish
# Manual installation
exabgp shell completion bash > ~/.local/share/bash-completion/completions/exabgpFeatures:
- Complete subcommands and options
- Complete .conf files
- Auto-detects current shell
The exabgp-cli tool has been significantly improved:
# Start CLI
exabgpcli
# Features:
# - Intelligent tab completion for commands and neighbors
# - JSON pretty-printing for responses
# - Command descriptions and help text
# - '?' key for inline help
# - Graceful signal handling (Ctrl+C)Dual Transport Support:
- Unix sockets (default)
- Named pipes (for legacy compatibility)
New API commands for health monitoring:
# Health check ping - lightweight, responds with pong + daemon UUID
sys.stdout.write("session ping\n")
sys.stdout.flush()
# Response: {"pong": "daemon-uuid", "active": true}
# Daemon status - full status info
sys.stdout.write("daemon status\n")
sys.stdout.flush()
# Response includes: version, UUID, PID, uptime, peer statesComprehensive type annotations have been added throughout the codebase:
- Better IDE support (autocomplete, error detection)
- Static type checking with mypy
- Improved documentation
- Fewer runtime type errors
ExaBGP 6.0.0 includes a built-in migration tool for automatic conversion:
# Migrate configuration file
exabgp migrate conf -f 5 -t main /etc/exabgp/exabgp.conf
# Show what would change (dry run)
exabgp migrate conf -f 5 -t main --dry-run /etc/exabgp/exabgp.conf
# Migrate and wrap API scripts with bridge (see Bridge Mode below)
exabgp migrate conf -f 4 -t main --wrap-api old-config.conf# Migrate API commands
exabgp migrate api -f 5 -t main
# Interactive mode - enter commands to convert
> announce route 10.0.0.0/24 next-hop 1.2.3.4
peer * announce route 10.0.0.0/24 next-hop 1.2.3.4
> neighbor 192.0.2.1 announce route 10.0.0.0/24 next-hop self
peer 192.0.2.1 announce route 10.0.0.0/24 next-hop selfThe --exec option enables bidirectional API transformation, allowing legacy scripts to run unchanged with ExaBGP 6.0.0. This is the recommended approach when you have complex scripts that would be difficult to modify.
ExaBGP 6.0.0 (main)
β
β sends v6 JSON events
βΌ
[stdin: reverse transform v6 β v4]
β
βΌ
old-script.py (expects v4 format)
β
β outputs v4 commands
βΌ
[stdout: forward transform v4 β v6]
β
βΌ
ExaBGP 6.0.0 (main)
Key benefit: Your legacy v4/v5 scripts work without any code changes.
# Run legacy script with bidirectional transformation
exabgp migrate api -f 4 -t main --exec /path/to/legacy-script.py
# This will:
# 1. Transform script's v4 output β v6 commands for ExaBGP
# 2. Transform ExaBGP's v6 JSON β v4 JSON for the scriptYour original v4 script might look like this:
#!/usr/bin/env python3
import sys
import json
# Output v4-style commands (no peer selector)
print('announce route 10.0.0.0/24 next-hop 1.2.3.4', flush=True)
print('withdraw route 10.0.1.0/24', flush=True)
print('shutdown', flush=True)
# Read v4-style JSON input
for line in sys.stdin:
data = json.loads(line)
# Process v4 format JSON...With bridge mode, this script works unchanged:
exabgp migrate api -f 4 -t main --exec /path/to/legacy-script.pyThe bridge transforms:
-
Output:
announce route ...βpeer * announce route ... -
Output:
shutdownβdaemon shutdown -
Input: v6 JSON keys β v4 JSON keys (e.g.,
sr-capability-flagsβsr_capability_flags)
The --wrap-api flag automatically wraps run commands in your configuration with the bridge:
# Migrate config AND wrap scripts with bridge
exabgp migrate conf -f 4 -t main --wrap-api old-config.conf | exabgp server -This transforms configuration entries:
# Before (in 4.x config)
run /path/to/script.py;
# After (migrated with --wrap-api)
run exabgp migrate api -f 4 -t main --exec /path/to/script.py;
Forward Transform (script output β ExaBGP):
| v4 Command | v6 Command |
|---|---|
announce route ... |
peer * announce route ... |
withdraw route ... |
peer * withdraw route ... |
neighbor 1.2.3.4 announce ... |
peer 1.2.3.4 announce ... |
shutdown |
daemon shutdown |
reload |
daemon reload |
show adj-rib out |
rib show out |
show neighbor |
peer show |
Reverse Transform (ExaBGP JSON β script):
| v6 JSON Key | v4 JSON Key | Context |
|---|---|---|
sr-capability-flags |
sr_capability_flags |
bgp-ls |
interface-addresses |
interface-address |
bgp-ls |
neighbor-addresses |
neighbor-address |
bgp-ls |
prefix |
ip |
ip-reachability-tlv |
β Use bridge mode when:
- You have complex legacy scripts that are difficult to modify
- You need to migrate quickly with minimal risk
- You want to test 6.0.0 without modifying working scripts
- Your scripts use BGP-LS JSON that needs key transformation
- Scripts are simple and easy to modify
- You want to eliminate the bridge overhead
- You're starting fresh with no legacy code
ExaBGP 6.0.0 uses a "target-first" command format:
| 5.x Command | 6.0.0 Command |
|---|---|
announce route 10.0.0.0/24... |
peer * announce route 10.0.0.0/24... |
neighbor 192.0.2.1 announce... |
peer 192.0.2.1 announce... |
shutdown |
daemon shutdown |
status |
daemon status |
enable-ack |
session ack enable |
disable-ack |
session ack disable |
show neighbor |
peer show |
show adj-rib in |
rib show in |
show adj-rib out |
rib show out |
Note: The 5.x format is still accepted for backward compatibility, but the 6.0.0 format is recommended.
# Check Python version
python3 --version
# Must be 3.12 or higher
# Recommended: 3.12 or 3.13If Python < 3.12, upgrade Python first.
# Backup current config
cp /etc/exabgp/exabgp.conf /etc/exabgp/exabgp.conf.5.x.bak
# Backup API programs
cp -r /etc/exabgp/programs /etc/exabgp/programs.5.x.bak# Migrate configuration
exabgp migrate conf -f 5 -t main /etc/exabgp/exabgp.conf
# Review changes
diff /etc/exabgp/exabgp.conf.5.x.bak /etc/exabgp/exabgp.confIf you're using BGP-LS with JSON encoder, update your parsers for the new field names:
# Update field names
# ip -> prefix
# sr-adj -> sr-adjs
# remote-router-id -> remote-router-ids# From PyPI (when released)
pip3 install --upgrade exabgp
# Or from source (main branch)
git clone https://github.com/Exa-Networks/exabgp.git
cd exabgp
git checkout main
pip3 install .# Validate configuration
exabgp validate /etc/exabgp/exabgp.conf# Start ExaBGP with updated config
exabgp /etc/exabgp/exabgp.conf
# Monitor logs for errors
tail -f /var/log/exabgp.log
# Verify BGP sessions establish
exabgpcli peer show# Test with async reactor
exabgp /etc/exabgp/exabgp.conf# Install shell completion
exabgp shell installOnly after thorough testing:
# Deploy to production
# Monitor closely for first 24 hours
# Have rollback plan ready- Configuration syntax valid:
exabgp validate /etc/exabgp/exabgp.conf - No deprecated syntax
- Migration tool ran successfully
- JSON parsers handle new BGP-LS field names (if applicable)
- ACK handling still works
- Route announcements work
- Route withdrawals work
- Error handling works
- Async reactor works correctly
- No performance regressions
- Report any issues on GitHub
- BGP sessions establish successfully
- Routes announced correctly
- Health checks work (if using healthcheck module)
- CLI commands work (
exabgpcli) - Monitoring/alerting still works
If issues occur, rollback to 5.x:
# 1. Stop ExaBGP 6.0.0
systemctl stop exabgp
# 2. Restore 5.x configuration
cp /etc/exabgp/exabgp.conf.5.x.bak /etc/exabgp/exabgp.conf
# 3. Reinstall 5.x
pip3 install exabgp==5.0.0
# 4. Restart ExaBGP
systemctl start exabgp
# 5. Verify sessions
exabgpcli show neighbor summaryImportant: Keep your 5.x configuration backed up until 6.0.0 is validated in production.
Symptom:
Python 3.12+ required, found 3.11
Cause: Python < 3.12
Solution:
# Upgrade Python to 3.12+
# Ubuntu/Debian:
sudo apt install python3.12
pip3.12 install exabgpSymptom: Unexpected behavior or errors with async operations
Cause: Async reactor is the only mode in 6.0.0
Solution:
- Report the issue on GitHub with detailed reproduction steps
- Include debug output:
exabgp --debug /etc/exabgp/exabgp.conf - Check for any blocking operations in your API scripts
Symptom:
KeyError: 'ip'Cause: Field renamed to prefix
Solution:
# Update parser
prefix = data['bgp-ls']['prefix'] # Now "10.134.2.88/30"Symptom:
KeyError: 'sr-adj'Cause: Field renamed to sr-adjs (array)
Solution:
# Update parser
adj_sids = data['bgp-ls']['sr-adjs'] # Now an array
for sid in adj_sids:
print(sid)Symptom:
KeyError: 'remote-router-id'Cause: Field renamed to remote-router-ids (array)
Solution:
# Update parser
router_ids = data['bgp-ls']['remote-router-ids'] # Now an array| Feature | 5.x | 6.0.0 | Compatible? |
|---|---|---|---|
| Configuration | 5.x syntax | 6.0.0 syntax | β Compatible (migration tool available) |
| Text API | Text encoder | Text encoder | β Compatible |
| JSON API | 5.x JSON | 6.0.0 JSON | |
| Python | 3.8+ | 3.12+ only | β 3.8-3.11 removed |
| Reactor | Generator-based | Async (default) | β Generators still work inside async |
| Your Situation | Recommendation | Action |
|---|---|---|
| Python < 3.12 | βΈοΈ Wait | Upgrade Python first |
| Using BGP-LS JSON | Update parsers before upgrading | |
| Using Text API only | β Safe to upgrade | Test async reactor |
| Need shell completion | β Upgrade | Only in 6.0.0 |
| Need health monitoring API | β Upgrade | Only in 6.0.0 |
| Production-critical | βΈοΈ Test first | Validate in staging |
For New Deployments: Use ExaBGP 6.0.0 (latest development)
For Existing 5.x Users:
- β Test thoroughly in staging environment
β οΈ Update BGP-LS JSON parsers if using JSON encoder- β Upgrade Python to 3.12+ if needed
- β Test async reactor (default)
- β Deploy to production with rollback plan ready
ExaBGP 6.0.0 is the development branch. ExaBGP 5.x remains LTS (Long-Term Support) for production stability.
- Breaking Changes Reference - Complete breaking changes list
- Migration Guide - Main migration entry page
- Installation Guide - Installing 6.0.0
- API Overview - API changes and new features
- ExaBGP CLI - Enhanced CLI documentation
π» 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)