diff --git a/.env.example b/.env.example index b2da828..f131ac0 100644 --- a/.env.example +++ b/.env.example @@ -12,6 +12,15 @@ OBMP_DATA_ROOT=/var/openbmp # (Kafka external listener, BMP source, ExaBGP peering). 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: # local — Grafana built-in login (admin / openbmp). Lab default. # OBMP_DOMAIN / OBMP_COOKIE_DOMAIN below can stay blank. diff --git a/cml/proxmox_bmp_config.py b/cml/proxmox_bmp_config.py index 6291b13..d4eafaf 100644 --- a/cml/proxmox_bmp_config.py +++ b/cml/proxmox_bmp_config.py @@ -41,9 +41,13 @@ def _env_default(key, default, dotenv=".env"): # --- BMP collector --------------------------------------------------------- -# Resolved from $HOST_IP or the HOST_IP= line in repo-root .env. -COLLECTOR_HOST = _env_default("HOST_IP", "10.40.40.202") -COLLECTOR_PORT = "5000" +# Routers must target the ROUTER-FACING address, not HOST_IP: on a WSL +# deployment HOST_IP is the unreachable WSL NAT address (portability finding +# 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. # Each line is self-contained and applied at the (config)# prompt; a bare diff --git a/cml/xrd-node-definition.yaml b/cml/xrd-node-definition.yaml index 2fcefbd..7d15111 100644 --- a/cml/xrd-node-definition.yaml +++ b/cml/xrd-node-definition.yaml @@ -129,7 +129,7 @@ configuration: ! ! bmp server 1 - host 10.40.40.202 port 5000 + host 10.40.40.202 port 1790 description OpenBMP update-source Gi0/0/0/0 flapping-delay 60 diff --git a/deploy.sh b/deploy.sh index 98fc1a7..57f0aa5 100755 --- a/deploy.sh +++ b/deploy.sh @@ -455,8 +455,8 @@ fi # 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 # 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 -# listenport=1790 connectport=5000 on WSL). +# compose publishes ${ROUTER_FACING_PORT:-1790}:5000 everywhere, so on WSL the +# portproxy forwards listenport=ROUTER_PORT to the SAME port on the WSL side. BMP_STD_PORT=1790 default_router_port="${ARG_ROUTER_PORT:-$BMP_STD_PORT}" 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: - 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} New-NetFirewallRule -DisplayName "OpenBMP ${ROUTER_PORT}" -Direction Inbound -LocalPort ${ROUTER_PORT} -Protocol TCP -Action Allow diff --git a/docker-compose.yml b/docker-compose.yml index 3d82a71..857b0ec 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -194,7 +194,11 @@ services: - net.ipv4.tcp_keepalive_probes=5 - net.ipv4.tcp_keepalive_time=180 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: - ${OBMP_DATA_ROOT}/config:/config environment: @@ -480,7 +484,7 @@ services: # 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 # 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 depends_on: - collector diff --git a/docs/DOCS.md b/docs/DOCS.md index d2b4229..8ee01c3 100644 --- a/docs/DOCS.md +++ b/docs/DOCS.md @@ -28,7 +28,7 @@ This is a **BGP Monitoring Platform (BMP) lab stack** deployed via Docker Compos **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 - 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 @@ -119,7 +119,7 @@ Traffic Generator (Phase 4): - Docker Engine (20.10+) and Docker Compose v2 - 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) - `OBMP_DATA_ROOT` directory created (default: `/var/openbmp`) diff --git a/docs/PORTABILITY-FINDINGS.md b/docs/PORTABILITY-FINDINGS.md index d5a6729..7e1ddf4 100644 --- a/docs/PORTABILITY-FINDINGS.md +++ b/docs/PORTABILITY-FINDINGS.md @@ -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 daemon with an old vendored client. -## 12. OPEN: router-side automation still targets the old lab's values -`cml/proxmox_bmp_config.py` sends routers at `HOST_IP` port `5000`, and -`cml/xrd-node-definition.yaml` bakes in `10.40.40.202:5000` — both correct on +## 12. Router-side automation targeted the old lab's values +`cml/proxmox_bmp_config.py` sent routers at `HOST_IP` port `5000`, and +`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 -target the router-facing address, and the port default is now 1790). Fold -`ROUTER_FACING_IP`/`ROUTER_FACING_PORT` from `.env` into that tooling when -the 5000-vs-1790 decision lands. See docs/router-bmp-config.md. +target the router-facing address). Resolved 2026-07: the router-facing port +is **1790** everywhere; compose publishes `${ROUTER_FACING_PORT:-1790}:5000`, +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. diff --git a/docs/router-bmp-config.md b/docs/router-bmp-config.md index 2a68e60..7ef3acd 100644 --- a/docs/router-bmp-config.md +++ b/docs/router-bmp-config.md @@ -14,18 +14,19 @@ deploy.sh records the correct target in `.env` as | Stack host | Routers target | Path to the collector | |---|---|---| -| Native Linux | `ROUTER_FACING_IP` (= host IP) : `ROUTER_FACING_PORT` | compose port map -> collector :5000 | -| WSL2 | Windows LAN IP : `ROUTER_FACING_PORT` | `netsh portproxy` (Windows) -> WSL `HOST_IP` -> 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, same port) -> WSL -> compose `ROUTER_FACING_PORT:5000` | On WSL the Windows-side forwarding must exist first — run `scripts/wsl-portproxy.ps1` in an **elevated** PowerShell, and re-run it after every WSL restart (the WSL address changes). -The router-facing port defaults to **1790** (the IANA-registered BMP port); -the collector always listens on **5000 inside the container**. The lab -routers were historically configured for 5000 — until they are reconfigured, -deploy with `--router-port 5000` (see the open decision in -docs/PORTABILITY-FINDINGS.md, finding 12). +The router-facing port is **1790** (the IANA-registered BMP port; decided +2026-07 — the lab's historical 5000 is being retired). The collector always +listens on **5000 inside the container**; compose maps +`${ROUTER_FACING_PORT:-1790}` down to it, and setup.sh renders the same port +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 diff --git a/gobgp-evpn/gobgpd.conf.tmpl b/gobgp-evpn/gobgpd.conf.tmpl index a884df7..ccb4f47 100644 --- a/gobgp-evpn/gobgpd.conf.tmpl +++ b/gobgp-evpn/gobgpd.conf.tmpl @@ -22,7 +22,7 @@ [[bmp-servers]] [bmp-servers.config] address = "__HOST_IP__" - port = 5000 + port = __BMP_PORT__ # 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. route-monitoring-policy = "local-rib" diff --git a/gobgp/gobgpd.conf.tmpl b/gobgp/gobgpd.conf.tmpl index 65eefdc..ee248ba 100644 --- a/gobgp/gobgpd.conf.tmpl +++ b/gobgp/gobgpd.conf.tmpl @@ -158,13 +158,13 @@ # --- BMP export to the OpenBMP collector ------------------------------------ # 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 -# 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. # route-monitoring-policy = "pre-policy" exports the Adj-RIB-In (received # routes, pre import-policy) -- consistent with the rest of the OpenBMP fleet. [[bmp-servers]] [bmp-servers.config] address = "__HOST_IP__" - port = 5000 + port = __BMP_PORT__ route-monitoring-policy = "pre-policy" statistics-timeout = 3600 diff --git a/scripts/wsl-portproxy.ps1 b/scripts/wsl-portproxy.ps1 index 5bf3ba5..9faa1cd 100644 --- a/scripts/wsl-portproxy.ps1 +++ b/scripts/wsl-portproxy.ps1 @@ -13,8 +13,9 @@ Must run in an ELEVATED PowerShell. .PARAMETER RouterPort - Router-facing BMP listen port on Windows (default 1790, the IANA BMP port). - Forwards to the collector's in-container port 5000. + Router-facing BMP port (default 1790, the IANA BMP port). Compose publishes + the same port on the WSL side (ROUTER_FACING_PORT:5000), so the proxy + forwards Windows:RouterPort -> WSL:RouterPort. .PARAMETER WslIp WSL address to forward to. Default: auto-detected via 'wsl hostname -I'. @@ -25,7 +26,6 @@ #> param( [int]$RouterPort = 1790, - [int]$CollectorPort = 5000, [int]$KafkaPort = 9092, [string]$WslIp = "" ) @@ -45,8 +45,9 @@ if (-not $WslIp) { } Write-Host "WSL address: $WslIp" -# listenport => connectport ($RouterPort maps DOWN to the collector's 5000) -$maps = @{ $RouterPort = $CollectorPort; $KafkaPort = $KafkaPort } +# listenport => connectport (same port both sides; compose maps RouterPort +# down to the collector's in-container 5000 on the WSL side) +$maps = @{ $RouterPort = $RouterPort; $KafkaPort = $KafkaPort } foreach ($listen in $maps.Keys) { 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 ` diff --git a/setup.sh b/setup.sh index bdcb5f9..e8213cf 100755 --- a/setup.sh +++ b/setup.sh @@ -194,11 +194,16 @@ fi # --- gobgpd.conf rendering (host-side -- gobgp image is distroless) --------- # 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 if [ -f "$d/gobgpd.conf.tmpl" ]; then - sed -e "s/__HOST_IP__/$HOST_IP/g" "$d/gobgpd.conf.tmpl" > "$d/gobgpd.conf" - echo "Rendered $d/gobgpd.conf (HOST_IP=$HOST_IP)" + sed -e "s/__HOST_IP__/$HOST_IP/g" -e "s/__BMP_PORT__/$BMP_PORT/g" \ + "$d/gobgpd.conf.tmpl" > "$d/gobgpd.conf" + echo "Rendered $d/gobgpd.conf (HOST_IP=$HOST_IP, BMP port=$BMP_PORT)" fi done