- Add exabgp/ container: ExaBGP 5.x + Flask REST API for on-demand BGP route injection into CML IOS-XR lab (AS 65020 via eBGP from AS 65100) - Add 6 injection scenarios: internet_sample, churn, blackhole, anycast, full_table, lab_prefixes - Add inject.py CLI wrapper for the ExaBGP API - Add iosxr_bgp_config.md with IOS-XR neighbor config and NETCONF script - Add obmp-grafana/ dashboards and provisioning (17 dashboards) - Update docker-compose.yml: add exabgp service, fix Kafka external listener IP, extend log retention from 90min to 720min - Add DOCS.md: full project documentation including architecture, setup, user guide, sanity checks, troubleshooting, and command reference - Update .gitignore: exclude .env and .claude/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.7 KiB
4.7 KiB
IOS-XR BGP Config for ExaBGP Peering
Apply to both CORE routers (CML-R9K-CORE-01 @ 10.100.0.100 and
CML-R9K-CORE-02 @ 10.100.0.200).
Credentials: ssh user@<mgmt-ip> password cisco
Route Policy (apply once per router)
route-policy EXABGP_IN
pass
end-policy
route-policy EXABGP_OUT
drop
end-policy
BGP Neighbor Block
router bgp 65020
neighbor 10.40.40.202
remote-as 65100
description ExaBGP-Route-Injector
ebgp-multihop 5
update-source MgmtEth0/RP0/CPU0/0
!
address-family ipv4 unicast
route-policy EXABGP_IN in
route-policy EXABGP_OUT out
next-hop-self
!
address-family ipv6 unicast
route-policy EXABGP_IN in
route-policy EXABGP_OUT out
next-hop-self
!
!
!
Key config notes
| Knob | Why |
|---|---|
remote-as 65100 |
ExaBGP presents as AS 65100 (eBGP to your AS 65020 mesh) |
ebgp-multihop 5 |
Host (10.40.40.202) and router (10.100.0.x) are different subnets |
update-source MgmtEth0/RP0/CPU0/0 |
Use management interface for the TCP session |
next-hop-self |
Replace ExaBGP's next-hop (10.40.40.202) with the CORE router's loopback when reflecting into iBGP — ensures other routers can resolve the next-hop via ISIS |
EXABGP_OUT drops |
Prevent the lab from advertising its own prefixes back to ExaBGP |
Verification Commands
show bgp neighbors 10.40.40.202
show bgp neighbors 10.40.40.202 received routes
show bgp summary
show route 1.1.1.0/24
show bgp 1.1.1.0/24
After loading the internet_sample scenario you should see ~94 new
prefixes in the BGP table and they should propagate to all 9 routers
via the iBGP mesh.
NETCONF push (alternative to CLI)
With NETCONF already enabled, you can push this config programmatically:
pip install ncclient
python3 - <<'EOF'
from ncclient import manager
ROUTERS = [
{'host': '10.100.0.100', 'description': 'CML-R9K-CORE-01'},
{'host': '10.100.0.200', 'description': 'CML-R9K-CORE-02'},
]
POLICY_XML = """
<config>
<routing-policy xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-policy-repository-cfg">
<route-policies>
<route-policy>
<route-policy-name>EXABGP_IN</route-policy-name>
<rpl-route-policy>route-policy EXABGP_IN pass end-policy</rpl-route-policy>
</route-policy>
<route-policy>
<route-policy-name>EXABGP_OUT</route-policy-name>
<rpl-route-policy>route-policy EXABGP_OUT drop end-policy</rpl-route-policy>
</route-policy>
</route-policies>
</routing-policy>
<bgp xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ipv4-bgp-cfg">
<instance>
<instance-name>default</instance-name>
<instance-as>
<as>0</as>
<four-byte-as>
<as>65020</as>
<bgp-running/>
<default-vrf>
<bgp-entity>
<neighbors>
<neighbor>
<neighbor-address>10.40.40.202</neighbor-address>
<remote-as>
<as-xx>0</as-xx>
<as-yy>65100</as-yy>
</remote-as>
<description>ExaBGP-Route-Injector</description>
<ebgp-multihop>
<max-hop-count>5</max-hop-count>
</ebgp-multihop>
<update-in-filtering>
<enable/>
</update-in-filtering>
<neighbor-afs>
<neighbor-af>
<af-name>ipv4-unicast</af-name>
<activate/>
<route-policy-in>EXABGP_IN</route-policy-in>
<route-policy-out>EXABGP_OUT</route-policy-out>
<next-hop-self>true</next-hop-self>
</neighbor-af>
<neighbor-af>
<af-name>ipv6-unicast</af-name>
<activate/>
<route-policy-in>EXABGP_IN</route-policy-in>
<route-policy-out>EXABGP_OUT</route-policy-out>
<next-hop-self>true</next-hop-self>
</neighbor-af>
</neighbor-afs>
</neighbor>
</neighbors>
</bgp-entity>
</default-vrf>
</four-byte-as>
</instance-as>
</instance>
</bgp>
</config>
"""
for router in ROUTERS:
print(f"Configuring {router['description']} ({router['host']})...")
with manager.connect(
host=router['host'],
port=830,
username='user',
password='cisco',
hostkey_verify=False,
device_params={'name': 'iosxr'},
) as m:
m.edit_config(target='candidate', config=POLICY_XML)
m.commit()
print(f" Done.")
print("All routers configured.")
EOF