docs: add router-integration guide + router-blueprints/ fragments

The stack side is portable; the router side had no reference material -- a
new operator standing up OBMP has no guide for what to configure on their
devices to feed it. Adds two artifacts, both vendor-neutral in intent,
IOS-XR-specific in syntax:

  docs/router-integration.md
    Multi-path tour of the four ingest paths (BMP, BGP-LS, gNMI,
    NETCONF) with a bring-up checklist and cross-references. The BMP
    section is deliberately thin -- it hands off to docs/router-bmp-config.md
    for the address-selection, port-choice, and RR-scope activation
    detail already covered there.

  router-blueprints/iosxr/*.cfg
    Copy-paste config fragments, one per ingest path plus a
    role-route-reflector overlay. All values are <PLACEHOLDER>
    substitutions -- no hardcoded IPs, no lab-gear names. Fragments
    align to the ROUTER_FACING_IP / ROUTER_FACING_PORT convention
    introduced in docs/router-bmp-config.md.

  router-blueprints/README.md
    Substitution legend + layout, cross-links to PORTABILITY-FINDINGS.md
    finding 4 (why routers can't target HOST_IP on WSL).

Also appends the multi-path guide link to the Greenfield deploy section
in README.md so router-side integration is discoverable from the top.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sam 2026-07-20 16:31:06 -07:00
parent 9e67ef10ba
commit 0c91cad55f
8 changed files with 580 additions and 1 deletions

View File

@ -54,7 +54,9 @@ branch + commit with the deployment.
Deployment types (`--scope full-stack|remote|central-store`) are described in Deployment types (`--scope full-stack|remote|central-store`) are described in
[docs/DEPLOYMENT-TYPES.md](docs/DEPLOYMENT-TYPES.md). Router-side BMP config: [docs/DEPLOYMENT-TYPES.md](docs/DEPLOYMENT-TYPES.md). Router-side BMP config:
[docs/router-bmp-config.md](docs/router-bmp-config.md). [docs/router-bmp-config.md](docs/router-bmp-config.md); multi-path integration
(BGP-LS, gNMI, NETCONF, RR overlay): [docs/router-integration.md](docs/router-integration.md),
with copy-paste IOS-XR fragments under [router-blueprints/iosxr/](router-blueprints/iosxr/).
## Using Docker Compose to run everything ## Using Docker Compose to run everything

260
docs/router-integration.md Normal file
View File

@ -0,0 +1,260 @@
# Router Integration Guide
The stack side of an OpenBMP deployment is covered by [deploy.sh](../deploy.sh)
and [setup.sh](../setup.sh) — see [DEPLOYMENT-TYPES.md](DEPLOYMENT-TYPES.md)
for the three scopes (`full-stack`, `remote`, `central-store`). This
document covers the other side: what to configure on the routers you want
to feed into it.
The stack supports four ingest paths. This guide is the tour of all four
and the order to bring them up in. For the BMP path specifically — the
mandatory one — the detailed reference lives in
[router-bmp-config.md](router-bmp-config.md) (address selection on WSL
vs native Linux, port choice, RR-scope activation, verification). Read
this file to understand the shape, then follow router-bmp-config.md when
you actually configure BMP.
Two artifacts per path:
1. **Hand-config reference** — copy-paste IOS-XR fragments under
[`router-blueprints/iosxr/`](../router-blueprints/iosxr/).
2. **Automation** — for fleets, drive the same config with `ncclient`
(NETCONF) or SSH-CLI. Reference implementations for a specific lab
live under [`cml/`](../cml/) and [`exabgp/`](../exabgp/); those are
examples of the automation shape, not required.
The two are meant to stay in sync — if you change one, mirror the other,
or the drift will surface as either a broken fleet run or a fragment that
no longer matches how you actually deploy.
---
## The four ingest paths (and what each costs you if you skip it)
| Path | What lights up if you configure it | What you lose if you don't | Mandatory? |
|-------------------|-----------------------------------------------|-------------------------------------------------------|---------------------|
| BMP session | Everything BGP: peers, RIB, churn, dashboards | The stack sees nothing. Grafana panels are empty. | Yes |
| BGP-LS export | LinkState folder: ls_nodes/links, LS Topology | LinkState dashboards are empty; Maps folder degraded. | Only for topology |
| gNMI streaming | Telemetry-3001 folder: interface counters etc | Container-level Stack Resources still works, but per-router interface telemetry is missing. | Only for interface |
| NETCONF | Programmatic config + polling automation | You can still do everything by hand on the router CLI, but there's no automation path. | Only for automation |
Bring these up incrementally — BMP first, then layer on the others as
you use the dashboards that consume them.
---
## Prerequisite: NETCONF over SSH
Nearly every automation entry point in this repo connects with `ncclient`
over port 830 using the IOS-XR NETCONF device dialect. Turn it on first
even if you plan to configure the rest by hand — you'll want it for the
poller and any programmatic per-router queries.
**Fragment:** [`router-blueprints/iosxr/00-netconf.cfg`](../router-blueprints/iosxr/00-netconf.cfg)
**Credentials to align with `.env`:**
- `IOSXR_NETCONF_USER` / `IOSXR_NETCONF_PASS` — the account the automation
logs in as. Whatever you pick, create it on the router with matching
credentials and enough privilege to `edit-config`.
- `IOSXR_NETCONF_ADMIN_USER` / `IOSXR_NETCONF_ADMIN_PASS` — separate
admin-tier override for routers whose config draws from a privileged
account.
**Verify from the stack host:**
```bash
ssh -p 830 <NETCONF_USER>@<ROUTER_MGMT_IP> -s netconf
# Expect an <hello> capability exchange, not a login shell.
```
---
## Path 1: BMP session (mandatory) → see router-bmp-config.md
The BMP collector is what the whole stack is built around. Every router
you want visibility into opens a TCP session to it and streams its
Adj-RIB-In.
**Full reference:** [router-bmp-config.md](router-bmp-config.md) — read
it before configuring. Covers:
- Which address the router targets (`ROUTER_FACING_IP` from `.env`, **not
`HOST_IP`** on WSL deployments — the WSL VM's NAT address is
unreachable from real routers; see
[PORTABILITY-FINDINGS.md](PORTABILITY-FINDINGS.md) finding 4).
- Which port (`ROUTER_FACING_PORT`, defaults to 1790 — the IANA BMP port;
existing lab routers configured for 5000 need `--router-port 5000`
until reconfigured).
- The BMP `bmp server 1` block, flat formal form.
- Activation via `neighbor-group BMP-MONITORED`.
- **RR-scope-only activation** for load reduction — the single biggest
ingest-load lever in an RR topology.
**Fragment (matches the block in router-bmp-config.md):**
[`router-blueprints/iosxr/01-bmp-basic.cfg`](../router-blueprints/iosxr/01-bmp-basic.cfg)
— substitutions and the RR-scope note are inline in the fragment header.
**Deployment-type note:** on a `remote` collector deployment, routers
targeting *that* remote node use its own `ROUTER_FACING_IP`, not the
central-store's — the split-ingest topology (see
[DEPLOYMENT-TYPES.md](DEPLOYMENT-TYPES.md)) has each remote terminating
BMP locally and forwarding parsed data over Kafka to the central store.
---
## Path 2: BGP-LS export
Adds IGP topology visibility. The router distributes its local IS-IS
database into BGP as the link-state address family, and the RRs propagate
it. The collector's BMP session picks it up and the stack lands it in
`ls_nodes` / `ls_links` / `ls_prefixes` tables, which feed the
OBMP-LinkState folder and the LS Topology Map under OBMP-Maps.
**Fragment:** [`router-blueprints/iosxr/02-bgp-ls.cfg`](../router-blueprints/iosxr/02-bgp-ls.cfg)
**Three parts, applied in order:**
1. **IS-IS `distribute link-state`** — tell the IGP to hand its LSDB to
BGP.
2. **BGP `address-family link-state link-state`** — enable the AF
globally.
3. **Per-neighbor LS activation** — activate LS toward the two RRs (on a
client router) or between RRs (on a reflector). Only peers with the
LS AF activated will exchange topology.
**Substitutions:**
- `<ISIS_INSTANCE>` — the IS-IS instance tag on this router.
- `<LOCAL_ASN>`, `<RR_LOOPBACK_1>`, `<RR_LOOPBACK_2>` — as documented in
[router-blueprints/README.md](../router-blueprints/README.md).
**Verify:**
On the router:
```
show isis database detail
show bgp link-state link-state summary
```
On the stack:
```bash
docker exec -i obmp-psql psql -U openbmp -d openbmp \
-c "SELECT protocol, count(*) FROM ls_nodes GROUP BY protocol;"
```
Grafana → *OBMP-LinkState**LS Topology* should render an actual graph.
If you run OSPF instead of IS-IS, replace the `router isis <ISIS_INSTANCE>`
block with `router ospf <PROCESS_ID>` + `distribute link-state`; the BGP
side is identical.
---
## Path 3: gNMI streaming telemetry
Feeds the Telemetry-3001 dashboards: interface counters, interface state,
and anything else you subscribe to. This is **dial-in** gNMI — the
stack's `obmp-telegraf` container opens a gRPC connection to each router
on port 57400 and asks it to stream OpenConfig paths on an interval.
**Fragment:** [`router-blueprints/iosxr/03-gnmi.cfg`](../router-blueprints/iosxr/03-gnmi.cfg)
**Router-side setup is small:**
- Enable the gRPC server on `57400`. Use `no-tls` only on a trusted
management network; provision a server cert otherwise.
- Have a user Telegraf can authenticate as — a read-only account is
fine. Values live in `.env` as `GNMI_USERNAME` and `GNMI_PASSWORD`;
create the matching user on the router.
**Subscription paths are configured on the stack side**, not the router
— see [telegraf/telegraf.conf](../telegraf/telegraf.conf) for the exact
paths. The two currently active subscriptions are:
| Path | Interval | What it feeds |
|---------------------------------------------------------------|----------|-----------------------------------|
| `openconfig-interfaces:/interfaces/interface/state/counters` | 10s | Interface Utilization, Errors |
| `openconfig-interfaces:/interfaces/interface/state` | 30s | Interface Utilization (oper state)|
To add more sensors, edit `telegraf.conf` and rebuild the telegraf
container — no router-side change needed as long as the OpenConfig path
is model-supported on your platform.
**Reachability note:** not every IOS-XR platform / release has gRPC
dial-in enabled on every VRF or every interface by default. If a router
authenticates fine over NETCONF but the Telegraf log shows a connection
refused on 57400, verify `show grpc status` locally and that management
ACLs don't drop 57400.
**Verify:**
On the router:
```
show grpc status
show running-config grpc
```
On the stack:
```bash
docker logs obmp-telegraf 2>&1 | grep -i "connected"
```
Grafana → *OBMP-Telemetry**Interface Utilization* should show per-if
lines within a couple minutes.
---
## Route-reflector-only overlay
If the router is an iBGP route reflector, also apply the RR overlay
after the base fragments.
**Fragment:** [`router-blueprints/iosxr/role-route-reflector.cfg`](../router-blueprints/iosxr/role-route-reflector.cfg)
Adds an `RR-CLIENT` neighbor-group with `route-reflector-client` under
both `ipv4-unicast` and `link-state link-state`, plus a `bgp cluster-id`.
Every client peer just needs `use neighbor-group RR-CLIENT`.
The RR overlay is also where the RR-scope-only BMP activation belongs
in practice — the `RR-CLIENT` group already has `bmp-activate server 1`
in the fragment, so every client session added to the RR is
auto-monitored, while the client-router side has BMP off. See the
[router-bmp-config.md](router-bmp-config.md) discussion of activation
scope for why this matters.
---
## Multi-router bring-up checklist
For a fresh AS with two RRs and N clients, apply in this order:
1. **All routers**: `00-netconf.cfg` (enables everything else).
2. **RRs**: `01-bmp-basic.cfg` + `role-route-reflector.cfg` (which
handles both RR-client wiring and BMP activation on reflected sessions).
3. **Clients**: `01-bmp-basic.cfg` server block only — do NOT
`bmp-activate` your iBGP session to the RR; the RR is already
monitoring the same table pre-policy. This is the load-reduction
pattern from `router-bmp-config.md`.
4. **Routers you want in topology**: `02-bgp-ls.cfg` (usually all).
5. **Routers you want streaming telemetry**: `03-gnmi.cfg`.
6. **Verify** each layer on the stack side before adding the next — don't
configure all four on all routers in one shot; you lose the ability
to correlate a failure to a specific ingest path.
---
## Extending to another vendor
The four ingest paths are all standards (RFC 7854 for BMP, RFC 7752 for
BGP-LS, gNMI 0.10.0+ for telemetry, RFC 6241 for NETCONF). The fragments
under `router-blueprints/iosxr/` are IOS-XR syntax; the *behavior* the
stack expects is vendor-neutral:
- **BMP**: TCP session from router to `ROUTER_FACING_IP:ROUTER_FACING_PORT`,
Adj-RIB-In scope (pre-policy inbound), no monitoring type restrictions.
- **BGP-LS**: standard NLRI encoding, exported over any iBGP session.
- **gNMI**: OpenConfig models on the paths listed above; JSON_IETF
encoding.
- **NETCONF**: `edit-config` over SSH port 830 with vendor-native YANG
models — a different vendor obviously uses different modules and
scripts.
If you deploy against Junos, EOS, or SR OS, treat the IOS-XR fragments
as a specification of *what* to configure and translate to your vendor's
syntax. A sibling `router-blueprints/<vendor>/` tree can be added the
same way once someone has a working end-to-end deployment to base it on.

View File

@ -0,0 +1,60 @@
# Router Blueprints
Vendor-native configuration fragments that describe what a router must
present for the OpenBMP Docker stack to ingest data from it. Copy, edit
the `<PLACEHOLDER>` values for your topology, paste.
For the walkthrough (what each ingest path does, in what order to apply,
how to verify), see [docs/router-config-guide.md](../docs/router-config-guide.md).
## Layout
```
router-blueprints/
├── README.md <- this file
└── iosxr/
├── 00-netconf.cfg <- prerequisite: enable NETCONF/SSH
├── 01-bmp-basic.cfg <- BMP session to the collector
├── 02-bgp-ls.cfg <- BGP-LS export for topology
├── 03-gnmi.cfg <- gNMI streaming telemetry
└── role-route-reflector.cfg <- add-on for RR-role routers
```
Number-prefixed fragments are applied in order for a fresh router
bring-up. `role-*.cfg` fragments are additive overlays for routers that
fill a specific role.
## Substitutions
Every fragment uses `<ANGLE_BRACKET>` placeholders. Substitute the
following before pasting:
| Placeholder | What it is |
|------------------------|------------------------------------------------------------------|
| `<ROUTER_FACING_IP>` | `ROUTER_FACING_IP` in the stack's `.env` — the address routers target to reach the collector. NOT `HOST_IP` on WSL (see [docs/PORTABILITY-FINDINGS.md](../docs/PORTABILITY-FINDINGS.md) finding 4). |
| `<ROUTER_FACING_PORT>` | `ROUTER_FACING_PORT` in `.env` — collector port routers connect to (defaults to 1790, the IANA BMP port). |
| `<LOCAL_ASN>` | The router's own BGP AS number. |
| `<ROUTER_LOOPBACK>` | This router's `Loopback0` address (also its BGP router-id). |
| `<RR_LOOPBACK_1/2>` | The two route-reflector loopbacks in this router's AS. |
| `<ISIS_INSTANCE>` | The router's IS-IS instance tag. |
| `<MGMT_INTERFACE>` | Interface whose source IP the collector should see. |
| `<GNMI_USER>` | `GNMI_USERNAME` in `.env` — the user Telegraf authenticates as. |
| `<GNMI_PASS>` | `GNMI_PASSWORD` in `.env`. |
| `<NETCONF_USER>` | `IOSXR_NETCONF_USER` in `.env` — user the automation logs in as. |
## Vendor scope
**IOS-XR only.** The four ingest paths themselves (BMP, BGP-LS, gNMI,
NETCONF) are standards, so the *behavior* the stack expects is
vendor-neutral — see the "Extending to another vendor" section in the
guide. Only the syntax below is IOS-XR-specific; a sibling
`router-blueprints/<vendor>/` tree can be added the same way once someone
has an end-to-end deployment to base it on.
## Credentials
Credentials come from your stack's `.env`. There is no shipped default —
whatever you set for `IOSXR_NETCONF_USER`, `IOSXR_NETCONF_PASS`,
`GNMI_USERNAME`, and `GNMI_PASSWORD` is what the fragments' user creation
blocks must match. Standardize on one account per role (read-only for
gNMI, config-capable for NETCONF) rather than reusing shell logins.

View File

@ -0,0 +1,38 @@
! ============================================================================
! 00-netconf.cfg -- IOS-XR NETCONF/SSH enablement (prerequisite)
! ============================================================================
! The stack's automation (rib-poller, RR diff pipeline, any
! ncclient-based configurator) connects to routers on TCP/830 using the
! IOS-XR NETCONF device dialect. If NETCONF is not enabled, none of that
! works and the BMP ingest path is the only thing that can succeed.
!
! Apply once per router before any of the other fragments. Substitute
! <NETCONF_USER> and its password with values that match your stack's
! .env (IOSXR_NETCONF_USER / IOSXR_NETCONF_PASS).
! ============================================================================
! --- SSH server (NETCONF-over-SSH transport) --------------------------------
ssh server v2
ssh server netconf vrf default
!
! --- NETCONF-YANG agent -----------------------------------------------------
netconf-yang agent
ssh
!
! --- Local user for NETCONF (skip if you use AAA/TACACS+) -------------------
username <NETCONF_USER>
group root-lr
group cisco-support
secret <PLAINTEXT_OR_HASHED_PASSWORD>
!
! --- Verify -----------------------------------------------------------------
! show netconf-yang statistics
! show ssh
! show run formal ssh
!
! From the stack host, quick sanity check:
! ssh -p 830 <NETCONF_USER>@<ROUTER_MGMT_IP> -s netconf
! (should return an <hello> capability exchange, not a shell prompt)

View File

@ -0,0 +1,65 @@
! ============================================================================
! 01-bmp-basic.cfg -- BMP session from this router to the OpenBMP collector
! ============================================================================
! Without this fragment, the stack sees nothing from this router. Everything
! else (BGP-LS export, gNMI streaming, RIB polling) is additive telemetry;
! BMP is the primary data plane the collector, kafka pipeline, and Grafana
! dashboards are built around.
!
! BMP config on IOS-XR (verified through 24.3.1) is CLI-only -- the NETCONF
! YANG models do not cover `bmp server`, so any automation must push this
! block over SSH-CLI rather than NETCONF.
!
! Two-part configuration:
! Part A: define the BMP server (one per router).
! Part B: activate BMP on the peers you want to monitor.
!
! Apply after 00-netconf.cfg. Substitute <ROUTER_FACING_IP>,
! <ROUTER_FACING_PORT>, <LOCAL_ASN>, and <MGMT_INTERFACE> for your
! topology. See docs/router-bmp-config.md for the full reference,
! including WSL-vs-native address selection, port choice, and the
! RR-scope-only activation pattern this fragment assumes.
! ============================================================================
! --- Part A: BMP server definition ------------------------------------------
bmp server 1
host <ROUTER_FACING_IP> port <ROUTER_FACING_PORT>
description OpenBMP-Collector
update-source <MGMT_INTERFACE>
initial-delay 60
stats-reporting-period 300
initial-refresh delay 60 spread 30
!
! --- Part B: activation via neighbor-group ---------------------------------
! Recommended pattern in an RR topology: activate BMP on the RR sessions
! (see role-route-reflector.cfg -- the RR-CLIENT neighbor-group there
! already includes `bmp-activate server 1`), and leave BMP OFF on the
! client-router side of those iBGP sessions. Activating on both sides
! makes the collector ingest the full table x monitored-sessions
! simultaneously, which is the biggest avoidable load driver.
!
! For sessions the RR pattern doesn't cover -- e.g. an eBGP session to a
! transit or peer you want reported directly -- use a dedicated group:
router bgp <LOCAL_ASN>
neighbor-group BMP-MONITORED
bmp-activate server 1
!
!
! Then reference the group per-neighbor:
! router bgp <LOCAL_ASN>
! neighbor <PEER_ADDRESS>
! use neighbor-group BMP-MONITORED
! ...
! !
! !
! --- Verify -----------------------------------------------------------------
! show run formal bmp
! show bmp server 1
! show bmp neighbor ! peers currently reported to the server
!
! On the stack side:
! docker logs obmp-collector 2>&1 | grep -i "peer up"
! Grafana -> OBMP-Operations -> Base-1001 -> Peers Table

View File

@ -0,0 +1,51 @@
! ============================================================================
! 02-bgp-ls.cfg -- BGP-LS export of the IGP topology to the collector
! ============================================================================
! Feeds the OBMP-LinkState dashboards (ls_nodes, ls_links, ls_prefixes,
! LS Topology map). Enable on every router that runs IS-IS in the domain
! you want visualized; typically only the RRs need to actually SEND the
! link-state AF to the collector, but any router can distribute its local
! IGP database into BGP-LS.
!
! Three-part configuration:
! Part A: tell IS-IS to distribute the LSDB into BGP-LS.
! Part B: enable the link-state address-family in BGP globally.
! Part C: activate the link-state AF toward the collector's RR peers.
!
! Apply after 01-bmp-basic.cfg.
! ============================================================================
! --- Part A: IS-IS distribute link-state ------------------------------------
router isis <ISIS_INSTANCE>
distribute link-state
!
! --- Part B: BGP address-family link-state link-state (global) --------------
router bgp <LOCAL_ASN>
address-family link-state link-state
!
!
! --- Part C: activate LS AF per-neighbor (toward the RRs) -------------------
! On a client router, activate LS toward the two RRs. On an RR, activate
! toward its peer RR (and toward the collector's own BGP peer if present).
router bgp <LOCAL_ASN>
neighbor <RR_LOOPBACK_1>
address-family link-state link-state
!
!
neighbor <RR_LOOPBACK_2>
address-family link-state link-state
!
!
!
! --- Verify -----------------------------------------------------------------
! show isis database detail
! show bgp link-state link-state summary
! show bgp link-state link-state
!
! On the stack side:
! docker exec -i obmp-psql psql -U openbmp -d openbmp \
! -c "SELECT protocol, count(*) FROM ls_nodes GROUP BY protocol;"
! Grafana -> OBMP-LinkState -> LS Topology / LS Nodes

View File

@ -0,0 +1,46 @@
! ============================================================================
! 03-gnmi.cfg -- gNMI dial-in for the Telegraf telemetry sink
! ============================================================================
! Enables the Telemetry-3001 dashboards (interface counters + state, and
! anything else Telegraf's cisco_telemetry_gnmi input is set to subscribe
! to). This is dial-IN telemetry: Telegraf initiates the gRPC connection
! and asks the router to stream openconfig paths on an interval.
!
! IOS-XR note: `no-tls` is only appropriate on a trusted management
! network. For any deployment reachable from an untrusted path, provision
! a server certificate and drop `no-tls` -- Telegraf's gNMI input supports
! TLS with cert verification.
! ============================================================================
! --- gRPC server for gNMI dial-in ------------------------------------------
grpc
port 57400
no-tls
!
! --- User for Telegraf to authenticate as ----------------------------------
! Whatever user you pick, populate GNMI_USERNAME / GNMI_PASSWORD in the
! stack's .env to match. A read-only account is sufficient.
!
! username <GNMI_USER>
! group root-lr
! secret <PLAINTEXT_OR_HASHED_PASSWORD>
! !
! --- Paths Telegraf subscribes to ------------------------------------------
! These are configured in telegraf/telegraf.conf, NOT on the router --
! openconfig paths are model-native, not sensor-groups. Reference only:
!
! openconfig-interfaces:/interfaces/interface/state/counters (10s)
! openconfig-interfaces:/interfaces/interface/state (30s)
!
! If you want additional sensors (LSDB size, CPU/mem), add the subscription
! block in telegraf/telegraf.conf and rebuild the telegraf container.
! --- Verify -----------------------------------------------------------------
! show grpc status
! show running-config grpc
!
! On the stack side:
! docker logs obmp-telegraf 2>&1 | grep -i "connected"
! Grafana -> OBMP-Telemetry -> Interface Utilization

View File

@ -0,0 +1,57 @@
! ============================================================================
! role-route-reflector.cfg -- RR-specific overlay for CORE routers
! ============================================================================
! Apply ONLY on routers that act as iBGP route reflectors for their AS.
! Skip on the client routers -- there this overlay is a no-op at best and
! creates inadvertent reflection at worst.
!
! Complements 01-bmp-basic.cfg (defines the BMP-MONITORED neighbor-group)
! and 02-bgp-ls.cfg (which activates the LS AF toward peers). The
! RR-specific bit here is `route-reflector-client` under the AFs for
! every client neighbor.
!
! Two conventions worth preserving:
! - Put every RR client into a `RR-CLIENT` neighbor-group so the
! reflector attribute is set once at group scope.
! - Combine with BMP-MONITORED via `use neighbor-group` at the neighbor
! itself -- IOS-XR only allows one `use neighbor-group` per neighbor,
! so nest common bits by inheritance if you need multiple groups.
! ============================================================================
router bgp <LOCAL_ASN>
!
! Cluster-id -- set to the RR's loopback so RR<->RR pairs recognize each
! other's reflected routes and don't loop. Both RRs in a pair share the
! same cluster-id if you want them to act as a single logical RR.
bgp cluster-id <ROUTER_LOOPBACK>
!
! RR-CLIENT neighbor-group: applied to every iBGP client peer.
neighbor-group RR-CLIENT
remote-as <LOCAL_ASN>
update-source Loopback0
bmp-activate server 1
address-family ipv4 unicast
route-reflector-client
next-hop-self
!
address-family link-state link-state
route-reflector-client
!
!
!
! Per-client wiring (repeat per client, replacing <CLIENT_LOOPBACK>):
!
! router bgp <LOCAL_ASN>
! neighbor <CLIENT_LOOPBACK>
! use neighbor-group RR-CLIENT
! !
! !
! --- Verify -----------------------------------------------------------------
! show bgp neighbors <CLIENT_LOOPBACK> | include Route-Reflector
! show bgp summary ! all clients Established
! show bgp neighbors <CLIENT_LOOPBACK> advertised-routes | count
!
! On the stack side (once the routers are BMP-reporting and reflecting):
! Grafana -> OBMP-Learning -> RR Loc-RIB Diff (should populate)