# First BGP Session **Step-by-step guide to establishing your first BGP session with ExaBGP** --- ## Table of Contents - [BGP Basics](#bgp-basics) - [Lab Setup](#lab-setup) - [Configuration Walkthrough](#configuration-walkthrough) - [Establishing the Session](#establishing-the-session) - [Understanding BGP Messages](#understanding-bgp-messages) - [Adding Your First Route](#adding-your-first-route) - [Dynamic Route Announcement](#dynamic-route-announcement) - [Receiving Routes](#receiving-routes) - [Troubleshooting](#troubleshooting) - [Next Steps](#next-steps) --- ## BGP Basics ### What is BGP? **BGP (Border Gateway Protocol)** is the routing protocol of the Internet. It's how routers exchange routing information. **Key concepts:** - **AS (Autonomous System)**: A network under a single administrative control (e.g., an ISP, enterprise) - **ASN (AS Number)**: Unique identifier for an AS (e.g., 65000) - **Peer/Neighbor**: Another BGP speaker you exchange routes with - **Route**: Network prefix (e.g., 100.10.0.0/24) and how to reach it - **Next-hop**: IP address where traffic should be sent ### How ExaBGP Uses BGP > ⚠️ **Remember**: ExaBGP does NOT manipulate the kernel routing table (RIB/FIB). **The flow:** ``` Your Program → ExaBGP → BGP Protocol → Router → Router's RIB/FIB → Traffic Flow ``` 1. Your program tells ExaBGP "announce this route" 2. ExaBGP sends BGP UPDATE message to router 3. Router installs route in its routing table 4. Router forwards traffic according to that route **ExaBGP's role:** Pure BGP protocol speaker. It talks BGP, you talk to ExaBGP via API. --- ## Lab Setup ### Requirements **Minimum lab:** - ExaBGP host (your machine) - BGP router/speaker to peer with **Options for BGP peer:** 1. **Production router** (Cisco, Juniper, Arista) - if you have access 2. **FRRouting** (free, full-featured) - recommended for learning 3. **BIRD** (free, high-performance) - good alternative 4. **GNS3/EVE-NG** (network simulator) - realistic lab ### Lab Topology ``` ┌─────────────────┐ ┌─────────────────┐ │ ExaBGP Host │ │ BGP Router │ │ │ │ (FRRouting) │ │ 192.168.1.2 │ ←─── eBGP ────→ │ 192.168.1.1 │ │ AS 65001 │ TCP 179 │ AS 65000 │ │ │ │ │ │ Announces: │ │ Installs route │ │ 100.10.0.0/24 │ │ in RIB/FIB │ └─────────────────┘ └─────────────────┘ ``` **Network details:** - ExaBGP: `192.168.1.2` in AS 65001 - Router: `192.168.1.1` in AS 65000 - Connection: eBGP (different ASNs) - Route to announce: `100.10.0.0/24` ### Quick FRRouting Setup (Optional) If you don't have a router, set up FRRouting for testing: ```bash # Install FRRouting (Ubuntu/Debian) curl -s https://deb.frrouting.org/frr/keys.asc | sudo apt-key add - echo deb https://deb.frrouting.org/frr $(lsb_release -s -c) frr-stable | sudo tee /etc/apt/sources.list.d/frr.list sudo apt update sudo apt install frr frr-pythontools # Enable BGP sudo sed -i 's/bgpd=no/bgpd=yes/' /etc/frr/daemons sudo systemctl restart frr # Configure BGP sudo vtysh ``` FRRouting config: ``` configure terminal router bgp 65000 bgp router-id 192.168.1.1 neighbor 192.168.1.2 remote-as 65001 address-family ipv4 unicast network 10.0.0.0/8 exit-address-family exit write memory ``` --- ## Configuration Walkthrough ### Minimal Configuration Create `/etc/exabgp/exabgp.conf`: ```ini # Minimal BGP configuration neighbor 192.168.1.1 { # Basic identification router-id 192.168.1.2; local-address 192.168.1.2; local-as 65001; peer-as 65000; # Announce a static route static { route 100.10.0.0/24 next-hop self; } } ``` ### Understanding Each Directive #### `neighbor 192.168.1.1` The IP address of the BGP peer (router) we're connecting to. #### `router-id 192.168.1.2` **Router ID**: Unique identifier for this BGP speaker. Typically use your IP address. Must be unique in the BGP domain. #### `local-address 192.168.1.2` **Local Address**: IP address ExaBGP binds to. Must be reachable by the peer. Usually same as router-id for simple setups. #### `local-as 65001` **Local ASN**: Our autonomous system number. ASN 64512-65535 are private (like RFC 1918 IPs). #### `peer-as 65000` **Peer ASN**: The router's autonomous system number. **eBGP vs iBGP:** - Different ASNs (65001 ≠ 65000) = **eBGP** (external BGP) - Same ASN (65001 = 65001) = **iBGP** (internal BGP) #### `static { route 100.10.0.0/24 next-hop self; }` **Static route announcement**: Tell the peer about network `100.10.0.0/24`. `next-hop self` means "send traffic to me (192.168.1.2)". --- ## Establishing the Session ### Start ExaBGP ```bash exabgp /etc/exabgp/exabgp.conf ``` ### Expected Output ``` INFO: Welcome to ExaBGP INFO: Performing reload of exabgp 4.2.25 INFO: New neighbor 192.168.1.1 (local AS 65001, peer AS 65000) INFO: BGP session established with 192.168.1.1 INFO: Announced route 100.10.0.0/24 next-hop 192.168.1.2 ``` ### BGP State Machine BGP sessions go through these states: 1. **Idle** - Not connected 2. **Connect** - TCP connection attempt 3. **Active** - Failed, retrying 4. **OpenSent** - Sent OPEN message 5. **OpenConfirm** - Received OPEN message 6. **Established** - Session UP ✅ **Goal:** Reach **Established** state. ### Verify on Router **FRRouting:** ```bash vtysh -c "show ip bgp summary" ``` Expected output: ``` Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd 192.168.1.2 4 65001 5 5 0 0 0 00:00:30 1 ``` **`State/PfxRcd`**: `1` means session is up and 1 prefix received (our 100.10.0.0/24) **View received route:** ```bash vtysh -c "show ip bgp neighbor 192.168.1.2 received-routes" ``` Output: ``` Network Next Hop Metric LocPrf Weight Path *> 100.10.0.0/24 192.168.1.2 0 0 65001 i ``` **`*>`** = Best route, installed in RIB --- ## Understanding BGP Messages BGP uses 4 message types: ### 1. OPEN Sent when connection is established. Contains: - BGP version (4) - ASN (65001) - Hold time (180 seconds typically) - Router ID (192.168.1.2) - Capabilities (multi-protocol, 4-byte ASN, etc.) **ExaBGP log:** ``` INFO: Sending OPEN to 192.168.1.1 INFO: Received OPEN from 192.168.1.1 ``` ### 2. UPDATE Announces or withdraws routes. **Announcement:** ``` UPDATE: route 100.10.0.0/24 next-hop 192.168.1.2 origin IGP as-path [ 65001 ] ``` **Withdrawal:** ``` UPDATE: withdraw route 100.10.0.0/24 ``` ### 3. KEEPALIVE Sent periodically (every 60 seconds) to keep session alive. **If no KEEPALIVE for `hold-time` seconds (180s), session drops.** ### 4. NOTIFICATION Error message. Causes session termination. **Example:** ``` NOTIFICATION: Cease - Administrative Reset ``` **Common reasons:** - Configuration change - Manual shutdown - Protocol error --- ## Adding Your First Route ### Static Routes ExaBGP can announce multiple static routes: ```ini neighbor 192.168.1.1 { router-id 192.168.1.2; local-address 192.168.1.2; local-as 65001; peer-as 65000; static { # Multiple routes route 100.10.0.0/24 next-hop self; route 100.20.0.0/24 next-hop self; route 100.30.0.0/24 next-hop self; # IPv6 route 2001:db8:100::/48 next-hop self; # With attributes route 100.40.0.0/24 { next-hop self; med 100; # Multi-Exit Discriminator (metric) local-preference 200; # Preference for iBGP community [ 65001:100 ]; # BGP community } } } ``` ### Route Attributes **MED (Multi-Exit Discriminator):** Lower is preferred. Suggests which path to use when multiple exist. ```ini route 100.10.0.0/24 next-hop self med 50; # Preferred route 100.10.0.0/24 next-hop self med 100; # Less preferred ``` **Local Preference (iBGP only):** Higher is preferred. Used within an AS to prefer certain paths. ```ini route 100.10.0.0/24 next-hop self local-preference 200; ``` **Communities:** Tags attached to routes for policy decisions. ```ini route 100.10.0.0/24 next-hop self community [ 65001:100 65001:200 ]; ``` **AS Path Prepending:** Make path longer (less preferred) for traffic engineering. ```ini route 100.10.0.0/24 next-hop self as-path [ 65001 65001 65001 ]; ``` Appears as: `65001 65001 65001` (prepended twice) --- ## Dynamic Route Announcement The real power: announce routes based on application logic. ### API-Based Announcement Configuration: ```ini neighbor 192.168.1.1 { router-id 192.168.1.2; local-address 192.168.1.2; local-as 65001; peer-as 65000; # No static routes - API controls everything api { processes [ dynamic-routes ]; } } process dynamic-routes { run /etc/exabgp/api/announce.py; encoder text; } ``` ### Simple API Script Create `/etc/exabgp/api/announce.py`: ```python #!/usr/bin/env python3 """ Simple dynamic route announcement """ import sys import time # Wait for ExaBGP to be ready time.sleep(2) # Announce routes routes = [ "100.10.0.0/24", "100.20.0.0/24", "100.30.0.0/24" ] for route in routes: sys.stdout.write(f"announce route {route} next-hop self\n") sys.stdout.flush() sys.stderr.write(f"[API] Announced {route}\n") # Keep process alive while True: time.sleep(60) ``` Make executable: ```bash chmod +x /etc/exabgp/api/announce.py ``` Run ExaBGP: ```bash exabgp /etc/exabgp/exabgp.conf ``` Output: ``` INFO: Started process 'dynamic-routes' with PID 12345 [API] Announced 100.10.0.0/24 [API] Announced 100.20.0.0/24 [API] Announced 100.30.0.0/24 INFO: Announced route 100.10.0.0/24 INFO: Announced route 100.20.0.0/24 INFO: Announced route 100.30.0.0/24 ``` --- ## Receiving Routes ExaBGP can receive routes from the router and process them. ### Configuration ```ini neighbor 192.168.1.1 { router-id 192.168.1.2; local-address 192.168.1.2; local-as 65001; peer-as 65000; # Receive IPv4 unicast routes family { ipv4 unicast; } # API processes receive updates api { processes [ receive-routes ]; } } process receive-routes { run /etc/exabgp/api/receive.py; encoder json; # JSON format for easier parsing receive { parsed; # Receive parsed BGP messages updates; # Receive route updates } } ``` ### Receiving Script Create `/etc/exabgp/api/receive.py`: ```python #!/usr/bin/env python3 """ Receive and process BGP routes """ import sys import json while True: line = sys.stdin.readline().strip() if not line: break try: message = json.loads(line) # Handle route updates if message['type'] == 'update': # New route announced if 'announce' in message['neighbor']['message']: announce = message['neighbor']['message']['announce'] if 'ipv4 unicast' in announce: for prefix, attrs in announce['ipv4 unicast'].items(): next_hop = attrs[0]['next-hop'] print(f"[RECEIVED] Route {prefix} via {next_hop}", file=sys.stderr) # Route withdrawn if 'withdraw' in message['neighbor']['message']: withdraw = message['neighbor']['message']['withdraw'] if 'ipv4 unicast' in withdraw: for prefix in withdraw['ipv4 unicast'].keys(): print(f"[WITHDRAWN] Route {prefix}", file=sys.stderr) # Handle session state elif message['type'] == 'state': state = message['neighbor']['state'] print(f"[STATE] BGP session state: {state}", file=sys.stderr) except json.JSONDecodeError: pass except Exception as e: print(f"[ERROR] {e}", file=sys.stderr) ``` ### Test On router (FRRouting), announce a route: ```bash vtysh -c "configure terminal" -c "router bgp 65000" -c "network 10.0.0.0/8" ``` ExaBGP output: ``` [RECEIVED] Route 10.0.0.0/8 via 192.168.1.1 ``` --- ## Troubleshooting ### Session Not Establishing **Symptom:** BGP stays in `Connect` or `Active` state **Check:** 1. **Network connectivity** ```bash ping 192.168.1.1 telnet 192.168.1.1 179 ``` 2. **Firewall rules** ```bash # Allow TCP 179 sudo iptables -A INPUT -p tcp --dport 179 -j ACCEPT sudo iptables -A OUTPUT -p tcp --sport 179 -j ACCEPT ``` 3. **Router configuration** - Peer address correct (`neighbor 192.168.1.2`) - AS numbers match expectation - Address family enabled 4. **ExaBGP config** - `local-address` reachable by peer - `peer-as` matches router's AS - `local-as` is correct **Debug:** ```bash env exabgp.log.level=DEBUG exabgp /etc/exabgp/exabgp.conf ``` --- ### Authentication Failure **Symptom:** `NOTIFICATION: Authentication failure` **Cause:** MD5 password mismatch **Solution:** Add MD5 password to both ExaBGP and router ExaBGP: ```ini neighbor 192.168.1.1 { router-id 192.168.1.2; local-address 192.168.1.2; local-as 65001; peer-as 65000; md5-password "secretpassword"; } ``` FRRouting: ``` router bgp 65000 neighbor 192.168.1.2 password secretpassword ``` --- ### Routes Not Appearing on Router **Symptom:** Session established, but routes not in router's RIB **Check:** 1. **ExaBGP log confirms announcement** ``` INFO: Announced route 100.10.0.0/24 ``` 2. **Router sees the route** ```bash # FRRouting vtysh -c "show ip bgp neighbor 192.168.1.2 received-routes" ``` 3. **Route accepted (not filtered)** - Check prefix-lists, route-maps, AS-path filters 4. **Best path selected** - Lower MED - Higher local-pref (iBGP) - Shorter AS path - Lower IGP metric **Debug on router:** ```bash vtysh -c "show ip bgp 100.10.0.0/24" ``` Look for `*>` = best path, installed in RIB --- ### API Process Not Starting **Symptom:** Process not in `ps aux | grep announce.py` **Check:** 1. **Script executable** ```bash chmod +x /etc/exabgp/api/announce.py ``` 2. **Shebang correct** ```python #!/usr/bin/env python3 ``` 3. **Path correct** ```ini run /etc/exabgp/api/announce.py; # Absolute path ``` 4. **ExaBGP log** ``` ERROR: Process 'dynamic-routes' failed to start ``` **Test manually:** ```bash /etc/exabgp/api/announce.py ``` --- ### Routes Not Announced from API **Symptom:** API script runs, but routes not announced **Check:** 1. **STDOUT flush** ```python sys.stdout.write("announce route 100.10.0.0/24 next-hop self\n") sys.stdout.flush() # CRITICAL - without this, nothing happens ``` 2. **Command syntax** ```python # Correct print("announce route 100.10.0.0/24 next-hop self") # Wrong print("announce 100.10.0.0/24 next-hop self") # Missing 'route' ``` 3. **ExaBGP log shows command** ``` INFO: Received command from API: announce route 100.10.0.0/24 next-hop self ``` --- ## ExaBGP Version Differences > ⚠️ **Important**: ExaBGP's API and configuration syntax changed significantly between versions. ### Version Timeline - **ExaBGP 3.x** (legacy, deprecated) - **ExaBGP 4.x** (maintenance, 4.2.25+) - **ExaBGP 5.x** (LTS - stable) - **ExaBGP 6.0.0** (development - main branch) ### API Changes Between Versions #### ExaBGP 3.x → 4.x (Major Breaking Changes) **Configuration Format Changed:** **ExaBGP 3.x (OLD):** ```ini neighbor 192.168.1.1 { router-id 192.168.1.2; local-address 192.168.1.2; local-as 65001; peer-as 65000; # OLD process syntax process announce-routes { run /usr/bin/python /etc/exabgp/api/announce.py; } } ``` **ExaBGP 4.x (NEW):** ```ini neighbor 192.168.1.1 { router-id 192.168.1.2; local-address 192.168.1.2; local-as 65001; peer-as 65000; # NEW api syntax api { processes [ announce-routes ]; } } process announce-routes { run /etc/exabgp/api/announce.py; encoder text; } ``` **Key differences:** - Separate `process` block outside `neighbor` in 4.x - `api { processes [ ... ] }` syntax in 4.x - `encoder` directive added in 4.x --- **JSON Message Format Changed:** **ExaBGP 3.x JSON output:** ```json { "type": "update", "neighbor": { "ip": "192.168.1.1", "update": { "announce": { "ipv4": { "100.10.0.0/24": { "next-hop": "192.168.1.2" } } } } } } ``` **ExaBGP 4.x JSON output:** ```json { "exabgp": "4.2.25", "time": 1699564800.0, "host": "exabgp-host", "pid": 12345, "ppid": 1, "counter": 1, "type": "update", "neighbor": { "address": { "local": "192.168.1.2", "peer": "192.168.1.1" }, "asn": { "local": 65001, "peer": 65000 }, "message": { "update": { "announce": { "ipv4 unicast": { "100.10.0.0/24": [ { "next-hop": "192.168.1.2" } ] } } } } } } ``` **Key differences:** - More metadata in 4.x (exabgp version, time, host, pid, counter) - Nested structure deeper in 4.x - Address family explicit: `"ipv4 unicast"` not `"ipv4"` - Attributes in array: `[ { "next-hop": ... } ]` not just `{ "next-hop": ... }` --- **API Command Format:** **ExaBGP 3.x:** ```python # Announce print("announce route 100.10.0.0/24 next-hop 192.168.1.2") # Withdraw print("withdraw route 100.10.0.0/24") ``` **ExaBGP 4.x:** ```python # Announce - can use 'self' print("announce route 100.10.0.0/24 next-hop self") # Withdraw print("withdraw route 100.10.0.0/24") # FlowSpec syntax improved print("announce flow route { match { destination 100.10.0.0/24; } then { discard; } }") ``` **Key differences:** - `next-hop self` supported in 4.x (auto-fills with local-address) - FlowSpec syntax cleaner in 4.x - More attribute support in 4.x --- #### Migrating from 4.x to 5.0.0 (LTS) **Status:** ExaBGP 5.0.0 released November 2024 (871 commits, largest release in history). **⚠️ Breaking Changes from 4.x:** - **Python 3.8+** required (3.9+ recommended, Python 2 completely removed) - **JSON API**: AS-PATH format changed (array → string) - **BGP-LS**: Field names changed (sr_capability_flags → sr-capability-flags, etc.) - **Config syntax**: route-refresh, FlowSpec fragments, tcp.attempts - **Removed**: Prefix-SID Type-2/4, tcp.once directive - **New defaults**: Hostname capability not sent by default **New Features:** - ✅ **SRv6** - Complete Segment Routing over IPv6 support - ✅ **BGP-MUP** - Mobile User Plane SAFI - ✅ **RFC 9072** - Extended Optional Parameters Length - ✅ **ACK runtime control** - disable-ack, enable-ack, silence-ack - ✅ **Security fixes** - TOCTOU vulnerability patched **Recommendation:** See [4.x → 5.0.0 Migration Guide](From-4.x-to-5.x) for upgrade planning. ExaBGP 4.x remains in maintenance mode (critical fixes only). --- ### Which Version Should You Use? **ExaBGP 5.0.0 (LTS - Recommended)** - ✅ Latest LTS release (November 2024) - ✅ All newest features (SRv6, BGP-MUP, etc.) - ✅ Security fixes (TOCTOU vulnerability) - ✅ Python 3.8-3.13 support - ✅ Recommended for all new deployments - ⚠️ **Breaking changes from 4.x** - See [migration guide](From-4.x-to-5.x) - ✅ This documentation covers 5.0.0 **ExaBGP 4.2.x (Previous Stable)** - ✅ Production-proven - ✅ No breaking changes within 4.x series - ✅ Python 2.7 + 3.6+ support - ⚠️ **Maintenance mode** - Only critical fixes, no new features - ℹ️ Suitable for existing deployments not yet ready to migrate - ✅ This documentation covers 4.x **ExaBGP 6.0.0 (Development - main branch)** - ✅ Latest features (async reactor, shell completion, enhanced CLI) - ✅ Python 3.12-3.14 support - ⚠️ **Breaking changes from 5.x** - See [migration guide](From-5.x-to-6.x) - ⚠️ Python 3.12+ **required** (3.7-3.11 dropped) - ⚠️ BGP-LS JSON field names changed - ℹ️ Test thoroughly before production **ExaBGP 3.x (Deprecated)** - ❌ No longer maintained - ❌ Python 2 only (end-of-life) - ❌ Must upgrade - See [3.x → 4.x migration](From-3.4-to-4.x) **Decision Guide:** - **New deployment?** → Use **5.0.0** (LTS) for stability, or **6.0.0** for latest features - **Existing 5.x deployment?** → Consider 6.0.0 if you need new features and can test thoroughly - **Existing 4.x deployment?** → Plan migration to 5.0.0 (test thoroughly first) - **Still on 3.x?** → Upgrade to 5.0.0 (via 4.x if needed for staged migration) --- ### Migrating from 3.x to 4.x See **[Migration Guide: 3.4 to 4.x](From-3.4-to-4.x)** for complete migration instructions. **Quick summary:** 1. **Update configuration syntax:** - Move `process` blocks outside `neighbor` - Change to `api { processes [ ... ] }` syntax - Add `encoder text` or `encoder json` 2. **Update API scripts (if using JSON):** - Parse new JSON structure - Access: `message['neighbor']['message']['update']` not `message['neighbor']['update']` - Address family: `'ipv4 unicast'` not `'ipv4'` 3. **Test thoroughly:** - ExaBGP 3.x and 4.x are **NOT compatible** - Configuration files don't work between versions - API scripts need updates --- ### Example: 3.x to 4.x Migration **Before (3.x config):** ```ini neighbor 192.168.1.1 { router-id 192.168.1.2; local-address 192.168.1.2; local-as 65001; peer-as 65000; process announce { run /usr/bin/python /etc/exabgp/announce.py; } } ``` **After (4.x config):** ```ini 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 [ announce ]; } } process announce { run /etc/exabgp/announce.py; encoder text; } ``` --- **Before (3.x API script receiving JSON):** ```python #!/usr/bin/env python import json, sys while True: line = sys.stdin.readline() msg = json.loads(line) # 3.x structure if 'announce' in msg['neighbor']['update']: routes = msg['neighbor']['update']['announce']['ipv4'] for prefix, attrs in routes.items(): nexthop = attrs['next-hop'] print(f"Route: {prefix} via {nexthop}") ``` **After (4.x API script):** ```python #!/usr/bin/env python3 import json, sys while True: line = sys.stdin.readline() msg = json.loads(line) # 4.x structure if 'update' in msg['neighbor']['message']: update = msg['neighbor']['message']['update'] if 'announce' in update: if 'ipv4 unicast' in update['announce']: routes = update['announce']['ipv4 unicast'] for prefix, attrs_list in routes.items(): nexthop = attrs_list[0]['next-hop'] print(f"Route: {prefix} via {nexthop}") ``` **Key changes:** - Access path: `msg['neighbor']['message']['update']` not `msg['neighbor']['update']` - Address family: `'ipv4 unicast'` not `'ipv4'` - Attributes: `attrs_list[0]` (array) not `attrs` (dict) --- ### Checking Your Version ```bash exabgp version ``` Output: ``` ExaBGP : 4.2.25 Python : 3.9.16 ``` **If you see `3.x.x`:** You're on deprecated version - upgrade to 5.x (via 4.x if needed). **If you see `4.2.x`:** You're on maintenance branch - plan upgrade to 5.x when ready. **If you see `5.x.x`:** You're on LTS (stable) - recommended for production! **If you see `6.x.x` or `main`:** You're on development branch - test thoroughly before production. --- ### Further Reading - **[Migration: 3.4 to 4.x](From-3.4-to-4.x)** - Complete migration guide - **[Migration: 4.2 to 5.0](From-4.x-to-5.x)** - When 5.0 releases - **[Breaking Changes](Breaking-Changes)** - All breaking changes across versions --- ## Next Steps ### Learn More - **[API Overview](API-Overview)** - Complete API documentation - **[Configuration Syntax](Configuration-Syntax)** - All configuration options - **[Text API Reference](Text-API-Reference)** - All API commands ### Use Cases - **[High Availability](Service-High-Availability)** - Health checks + anycast - **[DDoS Mitigation](DDoS-Mitigation)** - FlowSpec automated blocking - **[Anycast Management](Anycast-Management)** - Load balancing patterns ### Advanced Topics - **[FlowSpec](FlowSpec-Overview)** - Traffic filtering with BGP - **[Communities](Communities)** - Route tagging and policies - **[Attributes](Attribute-Reference)** - BGP path attributes --- ## Summary **What you learned:** ✅ BGP fundamentals (AS, neighbor, route, next-hop) ✅ ExaBGP configuration syntax ✅ Establishing BGP session (Established state) ✅ Announcing static routes ✅ Using the API for dynamic routes ✅ Receiving routes from router ✅ Troubleshooting common issues **Key concepts:** - ExaBGP speaks BGP protocol but does NOT manipulate kernel routing table - Routers install the routes ExaBGP announces - API uses simple STDIN/STDOUT for any language - BGP session must reach "Established" state - Always `flush()` after writing to STDOUT --- **Ready for more?** Continue to [API Overview](API-Overview) → ---