BMP port 1790 everywhere: parameterize the published collector port (finding 12)

Decision landed: routers target 1790 (IANA BMP port); the collector keeps
listening on 5000 in-container. One .env variable now drives every hop:

- compose publishes ${ROUTER_FACING_PORT:-1790}:5000 (was hardcoded 5000:5000)
- gobgpd.conf.tmpl (+ evpn) gains __BMP_PORT__; setup.sh renders it from
  ROUTER_FACING_PORT -- gobgp is host-networked, so it must chase the
  published port or the full-table feeder silently breaks
- deploy.sh + scripts/wsl-portproxy.ps1: the WSL side now publishes the
  router-facing port itself, so the portproxy forwards the same port
  end-to-end instead of down-mapping to 5000
- cml/proxmox_bmp_config.py reads ROUTER_FACING_IP/PORT from .env (HOST_IP
  fallback for pre-key .envs); xrd-node-definition.yaml baked port -> 1790
- .env.example documents ROUTER_FACING_IP/PORT; docs updated, finding 12
  closed on the repo side (routers still on 5000 need a config re-apply)

Verified live: collector republished 0.0.0.0:1790->5000, gobgp BMP session
Up to HOST_IP:1790 with the RIB dump flowing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Sam 2026-07-20 16:19:53 -07:00
parent 0c91cad55f
commit b480615ca2
12 changed files with 63 additions and 35 deletions

View File

@ -12,6 +12,15 @@ OBMP_DATA_ROOT=/var/openbmp
# (Kafka external listener, BMP source, ExaBGP peering). # (Kafka external listener, BMP source, ExaBGP peering).
HOST_IP=changeme HOST_IP=changeme
# Router-facing BMP target -- what routers' `bmp server` config points at.
# On WSL this is the WINDOWS LAN IP (portproxy forwards into WSL); on native
# Linux it is normally the host IP. Port 1790 is the IANA BMP port; it maps
# to the collector's in-container 5000 (compose publishes
# ROUTER_FACING_PORT:5000, and gobgp/setup.sh render the same port).
# deploy.sh reconciles both values per host.
ROUTER_FACING_IP=changeme
ROUTER_FACING_PORT=1790
# Auth mode: # Auth mode:
# local — Grafana built-in login (admin / openbmp). Lab default. # local — Grafana built-in login (admin / openbmp). Lab default.
# OBMP_DOMAIN / OBMP_COOKIE_DOMAIN below can stay blank. # OBMP_DOMAIN / OBMP_COOKIE_DOMAIN below can stay blank.

View File

@ -41,9 +41,13 @@ def _env_default(key, default, dotenv=".env"):
# --- BMP collector --------------------------------------------------------- # --- BMP collector ---------------------------------------------------------
# Resolved from $HOST_IP or the HOST_IP= line in repo-root .env. # Routers must target the ROUTER-FACING address, not HOST_IP: on a WSL
COLLECTOR_HOST = _env_default("HOST_IP", "10.40.40.202") # deployment HOST_IP is the unreachable WSL NAT address (portability finding
COLLECTOR_PORT = "5000" # 4/12). ROUTER_FACING_* are written to .env by deploy.sh; HOST_IP remains
# the fallback for old native-lab .envs that predate those keys.
COLLECTOR_HOST = _env_default("ROUTER_FACING_IP",
_env_default("HOST_IP", "10.40.40.202"))
COLLECTOR_PORT = _env_default("ROUTER_FACING_PORT", "1790")
# `bmp server 1` block — flat formal form, identical to the ESXi lab. # `bmp server 1` block — flat formal form, identical to the ESXi lab.
# Each line is self-contained and applied at the (config)# prompt; a bare # Each line is self-contained and applied at the (config)# prompt; a bare

View File

@ -129,7 +129,7 @@ configuration:
! !
! !
bmp server 1 bmp server 1
host 10.40.40.202 port 5000 host 10.40.40.202 port 1790
description OpenBMP description OpenBMP
update-source Gi0/0/0/0 update-source Gi0/0/0/0
flapping-delay 60 flapping-delay 60

View File

@ -455,8 +455,8 @@ fi
# The router-facing/external BMP port defaults to 1790 (the IANA-registered BMP # The router-facing/external BMP port defaults to 1790 (the IANA-registered BMP
# port) rather than the collector's internal 5000 - avoids the crowded 5000 and # port) rather than the collector's internal 5000 - avoids the crowded 5000 and
# is self-documenting. The collector still listens on 5000 INSIDE the container; # is self-documenting. The collector still listens on 5000 INSIDE the container;
# the external 1790 maps down to it (compose 1790:5000 on native, portproxy # compose publishes ${ROUTER_FACING_PORT:-1790}:5000 everywhere, so on WSL the
# listenport=1790 connectport=5000 on WSL). # portproxy forwards listenport=ROUTER_PORT to the SAME port on the WSL side.
BMP_STD_PORT=1790 BMP_STD_PORT=1790
default_router_port="${ARG_ROUTER_PORT:-$BMP_STD_PORT}" default_router_port="${ARG_ROUTER_PORT:-$BMP_STD_PORT}"
if [ -n "$ARG_ROUTER_IP" ]; then ROUTER_IP="$ARG_ROUTER_IP"; else if [ -n "$ARG_ROUTER_IP" ]; then ROUTER_IP="$ARG_ROUTER_IP"; else
@ -738,7 +738,7 @@ if [ "$HOSTTYPE" = "wsl" ] && [ "$DTYPE" != "central-store" ]; then
or add the rules by hand: or add the rules by hand:
netsh interface portproxy add v4tov4 listenport=${ROUTER_PORT} listenaddress=0.0.0.0 connectport=${COLLECTOR_PORT} connectaddress=${HOST_IP} netsh interface portproxy add v4tov4 listenport=${ROUTER_PORT} listenaddress=0.0.0.0 connectport=${ROUTER_PORT} connectaddress=${HOST_IP}
netsh interface portproxy add v4tov4 listenport=9092 listenaddress=0.0.0.0 connectport=9092 connectaddress=${HOST_IP} netsh interface portproxy add v4tov4 listenport=9092 listenaddress=0.0.0.0 connectport=9092 connectaddress=${HOST_IP}
New-NetFirewallRule -DisplayName "OpenBMP ${ROUTER_PORT}" -Direction Inbound -LocalPort ${ROUTER_PORT} -Protocol TCP -Action Allow New-NetFirewallRule -DisplayName "OpenBMP ${ROUTER_PORT}" -Direction Inbound -LocalPort ${ROUTER_PORT} -Protocol TCP -Action Allow

View File

@ -194,7 +194,11 @@ services:
- net.ipv4.tcp_keepalive_probes=5 - net.ipv4.tcp_keepalive_probes=5
- net.ipv4.tcp_keepalive_time=180 - net.ipv4.tcp_keepalive_time=180
ports: ports:
- "5000:5000" # Router-facing BMP port (default 1790, the IANA BMP port) maps down to
# the collector's fixed in-container 5000. Kept in sync with .env
# ROUTER_FACING_PORT by deploy.sh; gobgp's BMP export targets the same
# published port (setup.sh renders it into gobgpd.conf).
- "${ROUTER_FACING_PORT:-1790}:5000"
volumes: volumes:
- ${OBMP_DATA_ROOT}/config:/config - ${OBMP_DATA_ROOT}/config:/config
environment: environment:
@ -480,7 +484,7 @@ services:
# Host networking: the daemon uses the host's real IPv4 + IPv6 stack, so # Host networking: the daemon uses the host's real IPv4 + IPv6 stack, so
# both the v4 and v6 eBGP sessions to AS57355 source from the host's # both the v4 and v6 eBGP sessions to AS57355 source from the host's
# public addresses (no Docker IPv6/NAT plumbing). BMP still reaches the # public addresses (no Docker IPv6/NAT plumbing). BMP still reaches the
# collector on $HOST_IP:5000 (its published port). # collector on $HOST_IP:$ROUTER_FACING_PORT (its published port).
network_mode: host network_mode: host
depends_on: depends_on:
- collector - collector

View File

@ -28,7 +28,7 @@ This is a **BGP Monitoring Platform (BMP) lab stack** deployed via Docker Compos
**What it does:** **What it does:**
- Receives BMP (BGP Monitoring Protocol, RFC 7854) telemetry from routers on TCP port 5000 - Receives BMP (BGP Monitoring Protocol, RFC 7854) telemetry from routers on the router-facing port (default 1790, mapped to the collector's internal 5000)
- Streams BMP data through Kafka into a TimescaleDB/PostgreSQL database - Streams BMP data through Kafka into a TimescaleDB/PostgreSQL database
- Provides **30 Grafana dashboards** (17 operational + 6 learning + 4 advanced analytics + 3 streaming telemetry) for real-time and historical BGP analysis - Provides **30 Grafana dashboards** (17 operational + 6 learning + 4 advanced analytics + 3 streaming telemetry) for real-time and historical BGP analysis
- Includes an **ExaBGP route injector** that peers with the two CORE routers and injects synthetic BGP routes, enabling testing of BGP policy, route propagation, and Grafana dashboards without needing internet connectivity - Includes an **ExaBGP route injector** that peers with the two CORE routers and injects synthetic BGP routes, enabling testing of BGP policy, route propagation, and Grafana dashboards without needing internet connectivity
@ -119,7 +119,7 @@ Traffic Generator (Phase 4):
- Docker Engine (20.10+) and Docker Compose v2 - Docker Engine (20.10+) and Docker Compose v2
- Host IP `10.40.40.202` reachable from the CML management network - Host IP `10.40.40.202` reachable from the CML management network
- CML routers with BMP configured pointing to `10.40.40.202:5000` - CML routers with BMP configured pointing to the collector's router-facing address (see docs/router-bmp-config.md)
- CML CORE routers configured with ExaBGP as eBGP neighbor (see Section 5) - CML CORE routers configured with ExaBGP as eBGP neighbor (see Section 5)
- `OBMP_DATA_ROOT` directory created (default: `/var/openbmp`) - `OBMP_DATA_ROOT` directory created (default: `/var/openbmp`)

View File

@ -90,10 +90,14 @@ telegraf >= 1.30, which negotiates the API version (telegraf/Dockerfile now
pins 1.33). Watch for the same failure in any other tooling that talks to the pins 1.33). Watch for the same failure in any other tooling that talks to the
daemon with an old vendored client. daemon with an old vendored client.
## 12. OPEN: router-side automation still targets the old lab's values ## 12. Router-side automation targeted the old lab's values
`cml/proxmox_bmp_config.py` sends routers at `HOST_IP` port `5000`, and `cml/proxmox_bmp_config.py` sent routers at `HOST_IP` port `5000`, and
`cml/xrd-node-definition.yaml` bakes in `10.40.40.202:5000` — both correct on `cml/xrd-node-definition.yaml` baked in `10.40.40.202:5000` — both correct on
the old native-Linux dev lab, wrong on a WSL host (finding 4: routers must the old native-Linux dev lab, wrong on a WSL host (finding 4: routers must
target the router-facing address, and the port default is now 1790). Fold target the router-facing address). Resolved 2026-07: the router-facing port
`ROUTER_FACING_IP`/`ROUTER_FACING_PORT` from `.env` into that tooling when is **1790** everywhere; compose publishes `${ROUTER_FACING_PORT:-1790}:5000`,
the 5000-vs-1790 decision lands. See docs/router-bmp-config.md. setup.sh renders the same port into gobgp's BMP export (gobgp is
host-networked and must hit the *published* port), and the cml tooling reads
`ROUTER_FACING_IP`/`ROUTER_FACING_PORT` from `.env`. Remaining hands-on step:
re-apply the config to routers still pointed at 5000. See
docs/router-bmp-config.md.

View File

@ -14,18 +14,19 @@ deploy.sh records the correct target in `.env` as
| Stack host | Routers target | Path to the collector | | Stack host | Routers target | Path to the collector |
|---|---|---| |---|---|---|
| Native Linux | `ROUTER_FACING_IP` (= host IP) : `ROUTER_FACING_PORT` | compose port map -> collector :5000 | | Native Linux | `ROUTER_FACING_IP` (= host IP) : `ROUTER_FACING_PORT` | compose publishes `ROUTER_FACING_PORT:5000` |
| WSL2 | Windows LAN IP : `ROUTER_FACING_PORT` | `netsh portproxy` (Windows) -> WSL `HOST_IP` -> collector :5000 | | WSL2 | Windows LAN IP : `ROUTER_FACING_PORT` | `netsh portproxy` (Windows, same port) -> WSL -> compose `ROUTER_FACING_PORT:5000` |
On WSL the Windows-side forwarding must exist first — run On WSL the Windows-side forwarding must exist first — run
`scripts/wsl-portproxy.ps1` in an **elevated** PowerShell, and re-run it after `scripts/wsl-portproxy.ps1` in an **elevated** PowerShell, and re-run it after
every WSL restart (the WSL address changes). every WSL restart (the WSL address changes).
The router-facing port defaults to **1790** (the IANA-registered BMP port); The router-facing port is **1790** (the IANA-registered BMP port; decided
the collector always listens on **5000 inside the container**. The lab 2026-07 — the lab's historical 5000 is being retired). The collector always
routers were historically configured for 5000 — until they are reconfigured, listens on **5000 inside the container**; compose maps
deploy with `--router-port 5000` (see the open decision in `${ROUTER_FACING_PORT:-1790}` down to it, and setup.sh renders the same port
docs/PORTABILITY-FINDINGS.md, finding 12). into gobgp's BMP export. Routers still configured for 5000 must be updated
(`cml/proxmox_bmp_config.py` applies the current values from `.env`).
## `bmp server` block ## `bmp server` block

View File

@ -22,7 +22,7 @@
[[bmp-servers]] [[bmp-servers]]
[bmp-servers.config] [bmp-servers.config]
address = "__HOST_IP__" address = "__HOST_IP__"
port = 5000 port = __BMP_PORT__
# local-rib: the injected EVPN routes live in the loc-rib (there are no # local-rib: the injected EVPN routes live in the loc-rib (there are no
# BGP peers / no adj-rib-in), so export the local RIB. # BGP peers / no adj-rib-in), so export the local RIB.
route-monitoring-policy = "local-rib" route-monitoring-policy = "local-rib"

View File

@ -158,13 +158,13 @@
# --- BMP export to the OpenBMP collector ------------------------------------ # --- BMP export to the OpenBMP collector ------------------------------------
# GoBGP connects OUT to the collector. GoBGP's BMP config requires a literal # GoBGP connects OUT to the collector. GoBGP's BMP config requires a literal
# IP (it cannot resolve a hostname), so we target the docker host IP where the # IP (it cannot resolve a hostname), so we target the docker host IP where the
# collector publishes port 5000 -- stable across container recreation, unlike # collector publishes the router-facing BMP port (default 1790) -- stable
# the collector's internal docker IP. Matches HOST_IP in .env. # the collector's internal docker IP. Matches HOST_IP in .env.
# route-monitoring-policy = "pre-policy" exports the Adj-RIB-In (received # route-monitoring-policy = "pre-policy" exports the Adj-RIB-In (received
# routes, pre import-policy) -- consistent with the rest of the OpenBMP fleet. # routes, pre import-policy) -- consistent with the rest of the OpenBMP fleet.
[[bmp-servers]] [[bmp-servers]]
[bmp-servers.config] [bmp-servers.config]
address = "__HOST_IP__" address = "__HOST_IP__"
port = 5000 port = __BMP_PORT__
route-monitoring-policy = "pre-policy" route-monitoring-policy = "pre-policy"
statistics-timeout = 3600 statistics-timeout = 3600

View File

@ -13,8 +13,9 @@
Must run in an ELEVATED PowerShell. Must run in an ELEVATED PowerShell.
.PARAMETER RouterPort .PARAMETER RouterPort
Router-facing BMP listen port on Windows (default 1790, the IANA BMP port). Router-facing BMP port (default 1790, the IANA BMP port). Compose publishes
Forwards to the collector's in-container port 5000. the same port on the WSL side (ROUTER_FACING_PORT:5000), so the proxy
forwards Windows:RouterPort -> WSL:RouterPort.
.PARAMETER WslIp .PARAMETER WslIp
WSL address to forward to. Default: auto-detected via 'wsl hostname -I'. WSL address to forward to. Default: auto-detected via 'wsl hostname -I'.
@ -25,7 +26,6 @@
#> #>
param( param(
[int]$RouterPort = 1790, [int]$RouterPort = 1790,
[int]$CollectorPort = 5000,
[int]$KafkaPort = 9092, [int]$KafkaPort = 9092,
[string]$WslIp = "" [string]$WslIp = ""
) )
@ -45,8 +45,9 @@ if (-not $WslIp) {
} }
Write-Host "WSL address: $WslIp" Write-Host "WSL address: $WslIp"
# listenport => connectport ($RouterPort maps DOWN to the collector's 5000) # listenport => connectport (same port both sides; compose maps RouterPort
$maps = @{ $RouterPort = $CollectorPort; $KafkaPort = $KafkaPort } # down to the collector's in-container 5000 on the WSL side)
$maps = @{ $RouterPort = $RouterPort; $KafkaPort = $KafkaPort }
foreach ($listen in $maps.Keys) { foreach ($listen in $maps.Keys) {
netsh interface portproxy delete v4tov4 listenport=$listen listenaddress=0.0.0.0 2>$null | Out-Null netsh interface portproxy delete v4tov4 listenport=$listen listenaddress=0.0.0.0 2>$null | Out-Null
netsh interface portproxy add v4tov4 listenport=$listen listenaddress=0.0.0.0 ` netsh interface portproxy add v4tov4 listenport=$listen listenaddress=0.0.0.0 `

View File

@ -194,11 +194,16 @@ fi
# --- gobgpd.conf rendering (host-side -- gobgp image is distroless) --------- # --- gobgpd.conf rendering (host-side -- gobgp image is distroless) ---------
# Render gobgp{,-evpn}/gobgpd.conf from gobgpd.conf.tmpl, substituting # Render gobgp{,-evpn}/gobgpd.conf from gobgpd.conf.tmpl, substituting
# __HOST_IP__ with $HOST_IP. The rendered .conf is gitignored. # __HOST_IP__ with $HOST_IP and __BMP_PORT__ with the collector's published
# port (ROUTER_FACING_PORT, default 1790 -- gobgp is host-networked, so it
# must target the published port, not the in-container 5000). The rendered
# .conf is gitignored.
BMP_PORT="$(get_env ROUTER_FACING_PORT)"; BMP_PORT="${BMP_PORT:-1790}"
for d in gobgp gobgp-evpn; do for d in gobgp gobgp-evpn; do
if [ -f "$d/gobgpd.conf.tmpl" ]; then if [ -f "$d/gobgpd.conf.tmpl" ]; then
sed -e "s/__HOST_IP__/$HOST_IP/g" "$d/gobgpd.conf.tmpl" > "$d/gobgpd.conf" sed -e "s/__HOST_IP__/$HOST_IP/g" -e "s/__BMP_PORT__/$BMP_PORT/g" \
echo "Rendered $d/gobgpd.conf (HOST_IP=$HOST_IP)" "$d/gobgpd.conf.tmpl" > "$d/gobgpd.conf"
echo "Rendered $d/gobgpd.conf (HOST_IP=$HOST_IP, BMP port=$BMP_PORT)"
fi fi
done done