ExaBGP and GoBGP: Route Injection for Testing - 夜莺博客

ExaBGP and GoBGP: Route Injection for Testing

Sometimes you need to be the peer, not the router. Injecting routes lets you validate an eBGP policy before it is loaded, build an RTBH trigger without owning a real attack, prove a new prefix filter works, and test what a customer router does when 200,000 prefixes arrive at once. ExaBGP and GoBGP are the two tools most network teams reach for: ExaBGP is a Python-based BGP speaker designed exactly for announcement injection, and GoBGP is a full-featured Go implementation with an API. This guide covers installing both, announcing and withdrawing prefixes, hardening the lab against mistakes, and verifying that what you sent is what the router received.

Which tool for which job

Requirement ExaBGP GoBGP
Scripted announcement injection Ideal — config or API driven, Python hooks Workable via gRPC/REST API
Full routing stack (adj-rib-in, best path) Minimal Complete, including MPLS and EVPN
Bulk prefix announcement Good for tens of thousands Good, with more memory headroom
RTBH / blackhole trigger Very common Common
Integration with automation Plain text API, easy gRPC API, structured

For a policy test that lasts an hour, ExaBGP is faster to write. For a persistent lab peer that must behave like a router, GoBGP is the better foundation.

Install

# ExaBGP
python3 -m venv /opt/exabgp && /opt/exabgp/bin/pip install exabgp
/opt/exabgp/bin/exabgp --version

# GoBGP (static binary)
curl -LO https://github.com/osrg/gobgp/releases/latest/download/gobgp_linux_amd64.tar.gz
tar xzf gobgp_linux_amd64.tar.gz && sudo install gobgp gobgpd /usr/local/bin/
gobgpd -v

ExaBGP: announce, then withdraw

# /etc/exabgp/lab.conf
neighbor 10.40.0.1 {
    router-id 10.40.0.99;
    local-address 10.40.0.99;
    local-as 65099;
    peer-as 65001;
    hold-time 30;
    family {
        ipv4 unicast;
    }
    api {
        processes [ announce ];
    }
}
#!/usr/bin/env python3
# /etc/exabgp/announce.py  (ExaBGP API process: reads stdin, writes stdout)
import sys, time

def emit(cmd):
    sys.stdout.write(cmd + "\n")
    sys.stdout.flush()

time.sleep(2)
emit("announce route 192.0.2.0/24 next-hop self community [65001:666]")
emit("announce route 198.51.100.0/24 next-hop self as-path [65001 65002]")
emit("announce route 203.0.113.128/25 next-hop self med 50")

# keep the session alive and react to commands on stdin
for line in sys.stdin:
    parts = line.strip().split()
    if parts and parts[0] == "withdraw":
        emit("withdraw route %s" % parts[1])
sudo /opt/exabgp/bin/exabgp /etc/exabgp/lab.conf
# from the API process, or with the CLI:
exabgp-cli -p 179 -s 127.0.0.1 -e "announce route 192.0.2.0/24 next-hop self"
exabgp-cli -p 179 -s 127.0.0.1 -e "withdraw route 192.0.2.0/24"

Test with a single prefix and a narrow community first. If the receiving router has a policy that filters it, you will see the announcement arrive in its Adj-RIB-In while the Loc-RIB stays empty — that is a filtering result, not a session problem, and it is exactly what a policy test should surface.

GoBGP: a peer with an API

# /etc/gobgp/gobgpd.conf
[global.config]
  as = 65099
  router-id = "10.40.0.99"
  local-address-list = ["10.40.0.99"]
  port = 179

[[neighbors]]
  [neighbors.config]
    neighbor-address = "10.40.0.1"
    peer-as = 65001
  [neighbors.transport.config]
    passive-mode = false
  [[neighbors.afi-safis]]
    [neighbors.afi-safis.config]
      afi-safi-name = "ipv4-unicast"
sudo gobgpd -f /etc/gobgp/gobgpd.conf

# add a route with a community and a next hop
gobgp global rib add 192.0.2.0/24 nexthop 10.40.0.99 community 65001:666

# add many prefixes from a file
awk '{print "gobgp global rib add "$1" nexthop 10.40.0.99"}' prefixes.txt > bulk.sh
sh bulk.sh

# withdraw one or all
gobgp global rib del 192.0.2.0/24
gobgp global rib del all

# session and table visibility
gobgp neighbor
gobgp neighbor 10.40.0.1 adj-in
gobgp global rib

gobgp neighbor <ip> adj-in shows what the peer sent you, while gobgp global rib shows what you are advertising into your own table — the distinction that matters when debugging a one-way announcement problem.

Safe use in production: the guardrails

  1. Never inject from a device that can be reached by a real BGP peer with a permissive prefix filter. A stray default route announcement is a network-wide outage.
  2. Announce inside a lab ASN with a documented, temporary prefix range — 192.0.2.0/24 (TEST-NET-1) and 198.51.100.0/24 (TEST-NET-2) exist for exactly this purpose.
  3. Ask the receiving router to apply an inbound prefix-list, max-prefix limit and a community match before the first announcement. Agree the policy with the network owner in writing.
  4. Put a session timeout in place: hold-time 30 on ExaBGP means a crashed injector withdraws its routes quickly instead of leaving them in the table.
  5. Run injection from a dedicated VM, never from a management workstation with other privileges.

Verification on the receiving router

show bgp neighbors 10.40.0.99
show bgp neighbors 10.40.0.99 received-routes
show bgp ipv4 unicast 192.0.2.0/24
show bgp ipv4 unicast community 65001:666
show bgp ipv4 unicast summary | include 10.40.0.99
show route receive-protocol bgp 10.40.0.99 extensive    # Junos

Confirm three things: the session is Established, the prefix appears in the received-routes table, and the local routing table installed it if policy allows. For a route reflector test, check that the announcement reaches a client that is not directly peered with the injector. When the same tool is used to trigger a blackhole, the mechanics intersect with the RTBH configuration: the injector announces the host route with the blackhole community and the edge sets next hop to discard.

Test scenarios worth scripting

  • Policy validation: announce prefixes with unusual AS paths, communities and MED values; verify the intended ones are filtered and the rest accepted.
  • Max-prefix behaviour: announce in batches until the peer hits its configured limit; confirm the router logs and shuts the session as designed rather than crashing.
  • Route flap resistance: withdraw and re-announce a prefix repeatedly to observe whether your damping policy is too aggressive for a peer running normal convergence behaviour.
  • Convergence measurement: withdraw a prefix and time the failover to a secondary path; validate it against your SLA.

Integration with a lab

An injector is most useful inside a disposable topology. Container-based labs let you spin up routers, injectors and a monitoring host per scenario — the workflow in the containerlab multi-vendor lab guide covers the topology automation, and a Linux router peer can be built with the FRR BGP configuration. Wire the injector into CI so a policy change is validated by a real BGP session before it reaches a production router.

原文链接:https://github.com/Exa-Networks/exabgp/wiki