Add CML integration: XRd and ExaBGP node/image definitions and build scripts
CML 2.9 node definitions for XRd Control-Plane (third RR) and ExaBGP route injector as Docker-based CML nodes. Includes build scripts to export Docker images as tars for CML import, with IOS-XR startup configs for IS-IS, BGP, and BMP. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
541f018bc5
commit
da49b3e462
53
cml/build-cml-image.sh
Executable file
53
cml/build-cml-image.sh
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Build the ExaBGP Docker image and export it for CML 2.9 import.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./cml/build-cml-image.sh
|
||||||
|
#
|
||||||
|
# Output:
|
||||||
|
# /tmp/obmp-exabgp.tar — upload this to CML via:
|
||||||
|
# Tools > Node and Image Definitions > Image Definitions > Manage Image Uploads
|
||||||
|
#
|
||||||
|
# After upload, also import the node + image definition YAMLs:
|
||||||
|
# Tools > Node and Image Definitions > Import > cml/exabgp-node-definition.yaml
|
||||||
|
# Tools > Node and Image Definitions > Import > cml/exabgp-image-definition.yaml
|
||||||
|
|
||||||
|
set -e
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
echo "=== Building ExaBGP Docker image ==="
|
||||||
|
docker build -t obmp-exabgp:latest ./exabgp/
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Exporting image to /tmp/obmp-exabgp.tar ==="
|
||||||
|
docker save -o /tmp/obmp-exabgp.tar obmp-exabgp:latest
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Image details ==="
|
||||||
|
SIZE=$(du -h /tmp/obmp-exabgp.tar | cut -f1)
|
||||||
|
echo " File: /tmp/obmp-exabgp.tar ($SIZE)"
|
||||||
|
|
||||||
|
SHA=$(sha256sum /tmp/obmp-exabgp.tar | awk '{print $1}')
|
||||||
|
echo " SHA256: $SHA"
|
||||||
|
|
||||||
|
IMAGE_ID=$(docker image inspect obmp-exabgp:latest --format='{{.Id}}')
|
||||||
|
echo " Image ID: $IMAGE_ID"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Next steps ==="
|
||||||
|
echo "1. Update cml/exabgp-image-definition.yaml with:"
|
||||||
|
echo " sha256: $SHA"
|
||||||
|
echo ""
|
||||||
|
echo "2. Upload to CML:"
|
||||||
|
echo " a. Tools > Node and Image Definitions > Import"
|
||||||
|
echo " Upload: cml/exabgp-node-definition.yaml"
|
||||||
|
echo " b. Tools > Node and Image Definitions > Import"
|
||||||
|
echo " Upload: cml/exabgp-image-definition.yaml"
|
||||||
|
echo " c. Tools > Node and Image Definitions > Image Definitions > Manage Image Uploads"
|
||||||
|
echo " Upload: /tmp/obmp-exabgp.tar"
|
||||||
|
echo ""
|
||||||
|
echo "3. In your CML lab topology:"
|
||||||
|
echo " a. Drag 'ExaBGP Route Injector' from the node palette"
|
||||||
|
echo " b. Draw links to CORE-01 and CORE-02"
|
||||||
|
echo " c. Edit the boot.sh in the node config to set correct IPs"
|
||||||
|
echo " d. Start the node"
|
||||||
62
cml/build-xrd-image.sh
Executable file
62
cml/build-xrd-image.sh
Executable file
@ -0,0 +1,62 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Export the XRd control-plane Docker image for CML 2.9 import.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./cml/build-xrd-image.sh
|
||||||
|
#
|
||||||
|
# The XRd image already exists locally (ios-xr/xrd-control-plane:25.1.1).
|
||||||
|
# This script just exports it to a .tar file for CML upload.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
IMAGE="ios-xr/xrd-control-plane:25.1.1"
|
||||||
|
OUTPUT="/tmp/xrd-control-plane.tar"
|
||||||
|
|
||||||
|
echo "=== Verifying XRd image exists ==="
|
||||||
|
if ! docker image inspect "$IMAGE" >/dev/null 2>&1; then
|
||||||
|
echo "ERROR: Image $IMAGE not found locally."
|
||||||
|
echo "Check with: docker images | grep xrd"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " Image: $IMAGE"
|
||||||
|
SIZE=$(docker image inspect "$IMAGE" --format='{{.Size}}' | numfmt --to=iec 2>/dev/null || echo "unknown")
|
||||||
|
echo " Size: $SIZE"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Exporting image to $OUTPUT ==="
|
||||||
|
echo " (This may take a minute for ~1.3GB image...)"
|
||||||
|
docker save -o "$OUTPUT" "$IMAGE"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Export complete ==="
|
||||||
|
TAR_SIZE=$(du -h "$OUTPUT" | cut -f1)
|
||||||
|
echo " File: $OUTPUT ($TAR_SIZE)"
|
||||||
|
|
||||||
|
SHA=$(sha256sum "$OUTPUT" | awk '{print $1}')
|
||||||
|
echo " SHA256: $SHA"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Next steps ==="
|
||||||
|
echo "1. Update cml/xrd-image-definition.yaml with:"
|
||||||
|
echo " sha256: $SHA"
|
||||||
|
echo ""
|
||||||
|
echo "2. Upload to CML:"
|
||||||
|
echo " a. Tools > Node and Image Definitions > Import"
|
||||||
|
echo " Upload: cml/xrd-node-definition.yaml"
|
||||||
|
echo " b. Tools > Node and Image Definitions > Import"
|
||||||
|
echo " Upload: cml/xrd-image-definition.yaml"
|
||||||
|
echo " c. Tools > Node and Image Definitions > Image Definitions > Manage Image Uploads"
|
||||||
|
echo " Upload: $OUTPUT"
|
||||||
|
echo " (For large files, consider SCP to CML server instead)"
|
||||||
|
echo ""
|
||||||
|
echo "3. In your CML lab topology:"
|
||||||
|
echo " a. Drag 'XRd Control-Plane (IOS-XR)' from the node palette"
|
||||||
|
echo " b. Draw links to CORE-01 (→Gi0/0/0/0) and CORE-02 (→Gi0/0/0/1)"
|
||||||
|
echo " c. Edit xrd-startup.cfg if needed (IPs, BMP target, etc.)"
|
||||||
|
echo " d. Start the node (allow ~3-5 min for XRd boot)"
|
||||||
|
echo ""
|
||||||
|
echo "4. After boot, verify via XRd console:"
|
||||||
|
echo " show isis adjacency"
|
||||||
|
echo " show bgp summary"
|
||||||
|
echo " show bmp server 1"
|
||||||
10
cml/exabgp-image-definition.yaml
Normal file
10
cml/exabgp-image-definition.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
id: obmp-exabgp.latest
|
||||||
|
node_definition_id: obmp-exabgp
|
||||||
|
description: |-
|
||||||
|
OpenBMP ExaBGP Route Injector
|
||||||
|
Python 3.11 + ExaBGP + Flask API for BGP route injection testing.
|
||||||
|
label: ExaBGP Route Injector
|
||||||
|
disk_image: obmp-exabgp.tar
|
||||||
|
read_only: false
|
||||||
|
schema_version: 0.0.1
|
||||||
|
# sha256: <UPDATE after running: sha256sum /tmp/obmp-exabgp.tar>
|
||||||
112
cml/exabgp-node-definition.yaml
Normal file
112
cml/exabgp-node-definition.yaml
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
id: obmp-exabgp
|
||||||
|
boot:
|
||||||
|
timeout: 60
|
||||||
|
completed:
|
||||||
|
- "ExaBGP Route Injector"
|
||||||
|
uses_regex: false
|
||||||
|
sim:
|
||||||
|
linux_native:
|
||||||
|
libvirt_domain_driver: docker
|
||||||
|
driver: ubuntu
|
||||||
|
ram: 512
|
||||||
|
cpus: 1
|
||||||
|
cpu_limit: 100
|
||||||
|
video:
|
||||||
|
memory: 1
|
||||||
|
general:
|
||||||
|
nature: server
|
||||||
|
description: OpenBMP ExaBGP Route Injector (Docker container)
|
||||||
|
read_only: false
|
||||||
|
configuration:
|
||||||
|
generator:
|
||||||
|
driver: null
|
||||||
|
provisioning:
|
||||||
|
files:
|
||||||
|
- editable: false
|
||||||
|
name: config.json
|
||||||
|
content: |-
|
||||||
|
{
|
||||||
|
"docker": {
|
||||||
|
"image": "obmp-exabgp:latest",
|
||||||
|
"mounts": [
|
||||||
|
"type=bind,source=cfg/boot.sh,target=/cml-boot.sh"
|
||||||
|
],
|
||||||
|
"misc_args": [],
|
||||||
|
"env": [
|
||||||
|
"EXABGP_LOCAL_AS=65100",
|
||||||
|
"EXABGP_PEER_AS=65020",
|
||||||
|
"EXABGP_API_PORT=5050"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"shell": "/bin/bash",
|
||||||
|
"day0cmd": [ "/bin/bash", "/cml-boot.sh" ],
|
||||||
|
"busybox": false
|
||||||
|
}
|
||||||
|
- editable: true
|
||||||
|
name: boot.sh
|
||||||
|
content: |-
|
||||||
|
#!/bin/bash
|
||||||
|
# CML boot script for ExaBGP container
|
||||||
|
# Configures data-plane interfaces before starting ExaBGP
|
||||||
|
#
|
||||||
|
# Interface mapping (assigned by CML topology links):
|
||||||
|
# eth0 = first connected interface (data-plane link 1)
|
||||||
|
# eth1 = second connected interface (data-plane link 2)
|
||||||
|
# ...additional interfaces as connected in topology
|
||||||
|
#
|
||||||
|
# Edit the IPs below to match your topology addressing.
|
||||||
|
# These are examples using 10.120.x.x/30 point-to-point links.
|
||||||
|
|
||||||
|
# --- Data-plane interface configuration ---
|
||||||
|
# Link to CORE-01: ExaBGP=10.120.1.2/30, CORE-01=10.120.1.1/30
|
||||||
|
ip address add 10.120.1.2/30 dev eth0
|
||||||
|
ip link set dev eth0 up
|
||||||
|
|
||||||
|
# Link to CORE-02: ExaBGP=10.120.2.2/30, CORE-02=10.120.2.1/30
|
||||||
|
ip address add 10.120.2.2/30 dev eth1
|
||||||
|
ip link set dev eth1 up
|
||||||
|
|
||||||
|
# --- Set environment for ExaBGP peering ---
|
||||||
|
export EXABGP_LOCAL_IP=10.120.1.2
|
||||||
|
export EXABGP_PEER_1=10.120.1.1
|
||||||
|
export EXABGP_PEER_2=10.120.2.1
|
||||||
|
|
||||||
|
# --- Start ExaBGP ---
|
||||||
|
exec /bin/bash /exabgp/startup.sh
|
||||||
|
media_type: raw
|
||||||
|
volume_name: cfg
|
||||||
|
device:
|
||||||
|
interfaces:
|
||||||
|
serial_ports: 1
|
||||||
|
physical:
|
||||||
|
- eth0
|
||||||
|
- eth1
|
||||||
|
- eth2
|
||||||
|
- eth3
|
||||||
|
has_loopback_zero: false
|
||||||
|
default_count: 2
|
||||||
|
ui:
|
||||||
|
label_prefix: exabgp-
|
||||||
|
icon: server
|
||||||
|
label: ExaBGP Route Injector
|
||||||
|
visible: true
|
||||||
|
group: Others
|
||||||
|
description: |-
|
||||||
|
OpenBMP ExaBGP Route Injector
|
||||||
|
BGP route injection for OpenBMP testing.
|
||||||
|
AS 65100 (eBGP) peering with IOS-XR routers (AS 65020).
|
||||||
|
Flask API on port 5050 for route management.
|
||||||
|
inherited:
|
||||||
|
image:
|
||||||
|
ram: true
|
||||||
|
cpus: false
|
||||||
|
data_volume: false
|
||||||
|
boot_disk_size: false
|
||||||
|
cpu_limit: false
|
||||||
|
node:
|
||||||
|
ram: true
|
||||||
|
cpus: false
|
||||||
|
data_volume: false
|
||||||
|
boot_disk_size: false
|
||||||
|
cpu_limit: false
|
||||||
|
schema_version: 0.0.1
|
||||||
10
cml/xrd-image-definition.yaml
Normal file
10
cml/xrd-image-definition.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
id: xrd-control-plane.25.1.1
|
||||||
|
node_definition_id: xrd-control-plane-rr
|
||||||
|
description: |-
|
||||||
|
Cisco XRd Control-Plane 25.1.1
|
||||||
|
IOS-XR containerized routing daemon for BGP/IS-IS/BMP workloads.
|
||||||
|
label: XRd Control-Plane 25.1.1
|
||||||
|
disk_image: xrd-control-plane.tar
|
||||||
|
read_only: false
|
||||||
|
schema_version: 0.0.1
|
||||||
|
# sha256: <UPDATE after running: sha256sum /tmp/xrd-control-plane.tar>
|
||||||
179
cml/xrd-node-definition.yaml
Normal file
179
cml/xrd-node-definition.yaml
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
id: xrd-control-plane-rr
|
||||||
|
boot:
|
||||||
|
timeout: 300
|
||||||
|
completed:
|
||||||
|
- "IOS XR RUN"
|
||||||
|
uses_regex: false
|
||||||
|
sim:
|
||||||
|
linux_native:
|
||||||
|
libvirt_domain_driver: docker
|
||||||
|
driver: ubuntu
|
||||||
|
ram: 2048
|
||||||
|
cpus: 2
|
||||||
|
cpu_limit: 100
|
||||||
|
video:
|
||||||
|
memory: 1
|
||||||
|
general:
|
||||||
|
nature: router
|
||||||
|
description: Cisco XRd Control-Plane - IOS-XR containerized routing daemon
|
||||||
|
read_only: false
|
||||||
|
configuration:
|
||||||
|
generator:
|
||||||
|
driver: null
|
||||||
|
provisioning:
|
||||||
|
files:
|
||||||
|
- editable: false
|
||||||
|
name: config.json
|
||||||
|
content: |-
|
||||||
|
{
|
||||||
|
"docker": {
|
||||||
|
"image": "ios-xr/xrd-control-plane:25.1.1",
|
||||||
|
"mounts": [
|
||||||
|
"type=bind,source=cfg/boot.sh,target=/cml-boot.sh",
|
||||||
|
"type=bind,source=cfg/xrd-startup.cfg,target=/etc/xrd/startup.cfg"
|
||||||
|
],
|
||||||
|
"misc_args": [
|
||||||
|
"--privileged"
|
||||||
|
],
|
||||||
|
"env": [
|
||||||
|
"XR_STARTUP_CFG=/etc/xrd/startup.cfg",
|
||||||
|
"XR_MGMT_INTERFACES=linux:eth0,chksum",
|
||||||
|
"XR_INTERFACES=linux:eth1,xr_name=Gi0/0/0/0;linux:eth2,xr_name=Gi0/0/0/1;linux:eth3,xr_name=Gi0/0/0/2;linux:eth4,xr_name=Gi0/0/0/3"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"shell": "/bin/bash",
|
||||||
|
"day0cmd": [ "/bin/bash", "/cml-boot.sh" ],
|
||||||
|
"busybox": false
|
||||||
|
}
|
||||||
|
- editable: true
|
||||||
|
name: boot.sh
|
||||||
|
content: |-
|
||||||
|
#!/bin/bash
|
||||||
|
# CML boot wrapper for XRd control-plane.
|
||||||
|
# XRd handles its own init — this script configures
|
||||||
|
# data-plane interfaces before XRd starts.
|
||||||
|
#
|
||||||
|
# Interface mapping (set via XR_INTERFACES env var):
|
||||||
|
# eth0 = MgmtEth0/RP0/CPU0/0 (CML mgmt)
|
||||||
|
# eth1 = Gi0/0/0/0 (data-plane link 1, e.g. to CORE-01)
|
||||||
|
# eth2 = Gi0/0/0/1 (data-plane link 2, e.g. to CORE-02)
|
||||||
|
# eth3+ = Gi0/0/0/2+ (additional links)
|
||||||
|
#
|
||||||
|
# Linux-level IP config is handled by XRd via startup.cfg.
|
||||||
|
# Just ensure interfaces are up.
|
||||||
|
for iface in eth0 eth1 eth2 eth3 eth4; do
|
||||||
|
[ -d /sys/class/net/$iface ] && ip link set dev $iface up
|
||||||
|
done
|
||||||
|
|
||||||
|
# XRd entrypoint
|
||||||
|
exec /usr/sbin/xrd
|
||||||
|
- editable: true
|
||||||
|
name: xrd-startup.cfg
|
||||||
|
content: |-
|
||||||
|
!! XRd Control-Plane - Third Route Reflector (RR3)
|
||||||
|
!! Peers with CORE-01 and CORE-02 as RR mesh (non-client iBGP)
|
||||||
|
!! Sends BMP to OpenBMP collector at 10.40.40.202:5000
|
||||||
|
!!
|
||||||
|
hostname XRd-RR3
|
||||||
|
!
|
||||||
|
interface Loopback0
|
||||||
|
ipv4 address 10.10.255.30 255.255.255.255
|
||||||
|
!
|
||||||
|
interface Gi0/0/0/0
|
||||||
|
description to-CORE-01
|
||||||
|
ipv4 address 10.120.3.2 255.255.255.252
|
||||||
|
no shutdown
|
||||||
|
!
|
||||||
|
interface Gi0/0/0/1
|
||||||
|
description to-CORE-02
|
||||||
|
ipv4 address 10.120.4.2 255.255.255.252
|
||||||
|
no shutdown
|
||||||
|
!
|
||||||
|
router isis 1
|
||||||
|
is-type level-2-only
|
||||||
|
net 49.0001.0100.1000.0030.00
|
||||||
|
address-family ipv4 unicast
|
||||||
|
metric-style wide
|
||||||
|
!
|
||||||
|
interface Loopback0
|
||||||
|
passive
|
||||||
|
address-family ipv4 unicast
|
||||||
|
!
|
||||||
|
!
|
||||||
|
interface Gi0/0/0/0
|
||||||
|
point-to-point
|
||||||
|
address-family ipv4 unicast
|
||||||
|
!
|
||||||
|
!
|
||||||
|
interface Gi0/0/0/1
|
||||||
|
point-to-point
|
||||||
|
address-family ipv4 unicast
|
||||||
|
!
|
||||||
|
!
|
||||||
|
!
|
||||||
|
router bgp 65020
|
||||||
|
bgp router-id 10.10.255.30
|
||||||
|
address-family ipv4 unicast
|
||||||
|
!
|
||||||
|
neighbor 10.10.255.0
|
||||||
|
remote-as 65020
|
||||||
|
update-source Loopback0
|
||||||
|
address-family ipv4 unicast
|
||||||
|
!
|
||||||
|
!
|
||||||
|
neighbor 10.10.255.20
|
||||||
|
remote-as 65020
|
||||||
|
update-source Loopback0
|
||||||
|
address-family ipv4 unicast
|
||||||
|
!
|
||||||
|
!
|
||||||
|
!
|
||||||
|
bmp server 1
|
||||||
|
host 10.40.40.202 port 5000
|
||||||
|
description OpenBMP
|
||||||
|
update-source Gi0/0/0/0
|
||||||
|
flapping-delay 60
|
||||||
|
initial-delay 5
|
||||||
|
stats-reporting-period 300
|
||||||
|
initial-refresh delay 30 spread 2
|
||||||
|
!
|
||||||
|
ssh server v2
|
||||||
|
end
|
||||||
|
media_type: raw
|
||||||
|
volume_name: cfg
|
||||||
|
device:
|
||||||
|
interfaces:
|
||||||
|
serial_ports: 1
|
||||||
|
physical:
|
||||||
|
- eth0
|
||||||
|
- eth1
|
||||||
|
- eth2
|
||||||
|
- eth3
|
||||||
|
- eth4
|
||||||
|
has_loopback_zero: false
|
||||||
|
default_count: 3
|
||||||
|
ui:
|
||||||
|
label_prefix: xrd-
|
||||||
|
icon: router
|
||||||
|
label: XRd Control-Plane (IOS-XR)
|
||||||
|
visible: true
|
||||||
|
group: Cisco
|
||||||
|
description: |-
|
||||||
|
Cisco XRd Control-Plane (IOS-XR 25.1.1)
|
||||||
|
Containerized IOS-XR routing daemon for control-plane workloads.
|
||||||
|
Full BGP, IS-IS, BMP, NETCONF support.
|
||||||
|
Configured as third Route Reflector (RR3) with BMP to OpenBMP.
|
||||||
|
inherited:
|
||||||
|
image:
|
||||||
|
ram: true
|
||||||
|
cpus: true
|
||||||
|
data_volume: false
|
||||||
|
boot_disk_size: false
|
||||||
|
cpu_limit: false
|
||||||
|
node:
|
||||||
|
ram: true
|
||||||
|
cpus: true
|
||||||
|
data_volume: false
|
||||||
|
boot_disk_size: false
|
||||||
|
cpu_limit: false
|
||||||
|
schema_version: 0.0.1
|
||||||
Loading…
x
Reference in New Issue
Block a user