From 71cc8de7d5dbbc9b49c2e909a8fa1c570ffc9551 Mon Sep 17 00:00:00 2001 From: Damien Arnodo Date: Thu, 9 Jul 2026 13:33:21 +0000 Subject: [PATCH] Integrate gnmic for gNMI telemetry collection Add gnmic container node subscribing to interface, BGP, system, and VXLAN gNMI paths across all Arista cEOS nodes, exposed via a Prometheus exporter. gNMI runs in plaintext (no SSL profile on management api gnmi), so insecure:true is used instead of TLS. Refs #43, Refs #44 --- README.md | 283 ++++++++++++++++++--------------- configs/gnmic/gnmic-config.yml | 135 ++++++++++++++++ evpn-lab.clab.yml | 12 ++ 3 files changed, 305 insertions(+), 125 deletions(-) create mode 100644 configs/gnmic/gnmic-config.yml diff --git a/README.md b/README.md index 2e0239b..66e10fe 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ An extended Arista BGP EVPN-VXLAN multi-fabric lab using ContainerLab and cEOS. ## 🎯 Overview -| Zone | Devices | -| ------ | --------------------------------------------------------------------------------------- | -| DC | 2 spines, 8 leafs (4 MLAG VTEPs), 2 border leafs (MLAG), 4 access switches, 4 hosts | -| Core | 2 core routers (iBGP AS 65500, OSPF underlay with BLs, eBGP to DC & Campus BLs) | -| Campus | 2 spines, 4 leafs (2 MLAG VTEPs), 2 border leafs (MLAG), 2 access switches, 2 hosts | +| Zone | Devices | +| ------ | ----------------------------------------------------------------------------------- | +| DC | 2 spines, 8 leafs (4 MLAG VTEPs), 2 border leafs (MLAG), 4 access switches, 4 hosts | +| Core | 2 core routers (iBGP AS 65500, OSPF underlay with BLs, eBGP to DC & Campus BLs) | +| Campus | 2 spines, 4 leafs (2 MLAG VTEPs), 2 border leafs (MLAG), 2 access switches, 2 hosts | Key design choices: @@ -16,12 +16,12 @@ Key design choices: - **OSPF area 0 + eBGP multi-hop** between each Border Leaf pair and both Core routers (over dot1q subinterfaces: `.100` = default VRF underlay, `.200` = VRF `gold`). - **MLAG** everywhere there is dual-homing at the fabric layers (leaf pairs, border-leaf pairs, access β†’ leafs, and DC host β†’ access). - **Host attachment pattern**: - - **DC hosts** (servers) are **dual-homed via LACP** to an access switch β€” typical DC - server redundancy. - - **Campus hosts** (user endpoints: PC, phone, printer) are **single-attached** to a - Campus access switch via one plain Ethernet link. Redundancy lives at the access-switch - layer (the access switch itself is dual-homed via LACP to its leaf MLAG pair), not at - the host. + - **DC hosts** (servers) are **dual-homed via LACP** to an access switch β€” typical DC + server redundancy. + - **Campus hosts** (user endpoints: PC, phone, printer) are **single-attached** to a + Campus access switch via one plain Ethernet link. Redundancy lives at the access-switch + layer (the access switch itself is dual-homed via LACP to its leaf MLAG pair), not at + the host. - **VRF `gold`** is stretched end-to-end: DC leafs (VLAN 34 / 78) ↔ DC-BL ↔ Core ↔ Campus-BL ↔ Campus leafs (VLAN 60 / 70), all sharing L3 VNI `100001`. - **VLAN 50** remains defined as a campus-local L2 VXLAN stretched between the two Campus VTEPs (infrastructure-only, not wired to any host in the current topology). - **Convention**: L2 VNI = `110000 + vlan_id`, L3 VNI = `100001` for VRF `gold`, RT `1:100001` in both fabrics. @@ -64,50 +64,50 @@ docker exec -it clab-arista-evpn-fabric-dc-border-leaf1 Cli ### Node Inventory -| Zone | Role | Nodes | AS | -| ------ | ----------------------- | ------------------------------------------------------ | ------ | -| DC | Spine | `dc-spine1`, `dc-spine2` | 65000 | -| DC | Leaf VTEP1 (MLAG) | `dc-leaf1`, `dc-leaf2` | 65001 | -| DC | Leaf VTEP2 (MLAG) | `dc-leaf3`, `dc-leaf4` | 65002 | -| DC | Leaf VTEP3 (MLAG) | `dc-leaf5`, `dc-leaf6` | 65003 | -| DC | Leaf VTEP4 (MLAG) | `dc-leaf7`, `dc-leaf8` | 65004 | -| DC | Border Leaf (MLAG) | `dc-border-leaf1`, `dc-border-leaf2` | 65005 | -| DC | Access (L2-only) | `dc-access1`-`dc-access4` | β€” | -| DC | Host | `dc-server1`-`dc-server4` | β€” | -| Core | Core router | `core1`, `core2` | 65500 | -| Campus | Spine | `campus-spine1`, `campus-spine2` | 66000 | -| Campus | Leaf VTEP1 (MLAG) | `campus-leaf1`, `campus-leaf2` | 66001 | -| Campus | Leaf VTEP2 (MLAG) | `campus-leaf3`, `campus-leaf4` | 66002 | -| Campus | Border Leaf (MLAG) | `campus-border-leaf1`, `campus-border-leaf2` | 66005 | -| Campus | Access (L2-only) | `campus-access1`, `campus-access2` | β€” | -| Campus | Host | `campus-host1`, `campus-host2` | β€” | +| Zone | Role | Nodes | AS | +| ------ | ------------------ | -------------------------------------------- | ----- | +| DC | Spine | `dc-spine1`, `dc-spine2` | 65000 | +| DC | Leaf VTEP1 (MLAG) | `dc-leaf1`, `dc-leaf2` | 65001 | +| DC | Leaf VTEP2 (MLAG) | `dc-leaf3`, `dc-leaf4` | 65002 | +| DC | Leaf VTEP3 (MLAG) | `dc-leaf5`, `dc-leaf6` | 65003 | +| DC | Leaf VTEP4 (MLAG) | `dc-leaf7`, `dc-leaf8` | 65004 | +| DC | Border Leaf (MLAG) | `dc-border-leaf1`, `dc-border-leaf2` | 65005 | +| DC | Access (L2-only) | `dc-access1`-`dc-access4` | β€” | +| DC | Host | `dc-server1`-`dc-server4` | β€” | +| Core | Core router | `core1`, `core2` | 65500 | +| Campus | Spine | `campus-spine1`, `campus-spine2` | 66000 | +| Campus | Leaf VTEP1 (MLAG) | `campus-leaf1`, `campus-leaf2` | 66001 | +| Campus | Leaf VTEP2 (MLAG) | `campus-leaf3`, `campus-leaf4` | 66002 | +| Campus | Border Leaf (MLAG) | `campus-border-leaf1`, `campus-border-leaf2` | 66005 | +| Campus | Access (L2-only) | `campus-access1`, `campus-access2` | β€” | +| Campus | Host | `campus-host1`, `campus-host2` | β€” | ### AS Numbering -| AS | Role | -| ----- | ---------------------------------- | -| 65000 | DC Spine | -| 65001 | DC VTEP1 (dc-leaf1/2) | -| 65002 | DC VTEP2 (dc-leaf3/4) | -| 65003 | DC VTEP3 (dc-leaf5/6) | -| 65004 | DC VTEP4 (dc-leaf7/8) | -| 65005 | DC Border Leaf pair | -| 65500 | Core (iBGP between core1 & core2) | -| 66000 | Campus Spine | -| 66001 | Campus VTEP1 (campus-leaf1/2) | -| 66002 | Campus VTEP2 (campus-leaf3/4) | -| 66005 | Campus Border Leaf pair | +| AS | Role | +| ----- | --------------------------------- | +| 65000 | DC Spine | +| 65001 | DC VTEP1 (dc-leaf1/2) | +| 65002 | DC VTEP2 (dc-leaf3/4) | +| 65003 | DC VTEP3 (dc-leaf5/6) | +| 65004 | DC VTEP4 (dc-leaf7/8) | +| 65005 | DC Border Leaf pair | +| 65500 | Core (iBGP between core1 & core2) | +| 66000 | Campus Spine | +| 66001 | Campus VTEP1 (campus-leaf1/2) | +| 66002 | Campus VTEP2 (campus-leaf3/4) | +| 66005 | Campus Border Leaf pair | ### Access Switches -| Access Switch | Uplink Pair | VLANs | Host | Host attachment | -| --------------- | ------------------------ | -------- | -------------- | ------------------------- | -| dc-access1 | dc-leaf1/2 (VTEP1) | 40 | dc-server1 | LACP Po1 (dual-homed) | -| dc-access2 | dc-leaf3/4 (VTEP2) | 34 | dc-server2 | LACP Po1 (dual-homed) | -| dc-access3 | dc-leaf5/6 (VTEP3) | 40 | dc-server3 | LACP Po1 (dual-homed) | -| dc-access4 | dc-leaf7/8 (VTEP4) | 78 | dc-server4 | LACP Po1 (dual-homed) | -| campus-access1 | campus-leaf1/2 (VTEP1) | 60 | campus-host1 | access port (single link) | -| campus-access2 | campus-leaf3/4 (VTEP2) | 70 | campus-host2 | access port (single link) | +| Access Switch | Uplink Pair | VLANs | Host | Host attachment | +| -------------- | ---------------------- | ----- | ------------ | ------------------------- | +| dc-access1 | dc-leaf1/2 (VTEP1) | 40 | dc-server1 | LACP Po1 (dual-homed) | +| dc-access2 | dc-leaf3/4 (VTEP2) | 34 | dc-server2 | LACP Po1 (dual-homed) | +| dc-access3 | dc-leaf5/6 (VTEP3) | 40 | dc-server3 | LACP Po1 (dual-homed) | +| dc-access4 | dc-leaf7/8 (VTEP4) | 78 | dc-server4 | LACP Po1 (dual-homed) | +| campus-access1 | campus-leaf1/2 (VTEP1) | 60 | campus-host1 | access port (single link) | +| campus-access2 | campus-leaf3/4 (VTEP2) | 70 | campus-host2 | access port (single link) | All access switches are L2-only, LACP-bonded to their leaf MLAG pair via `Port-Channel10`. MSTP + edge-port BPDU guard. @@ -122,71 +122,72 @@ Host-facing ports: ### Management (`172.16.0.0/24`) -| Node | IP | Node | IP | -| ------------------------- | --------------- | ------------------------- | --------------- | -| dc-spine1 | 172.16.0.1 | campus-spine1 | 172.16.0.20 | -| dc-spine2 | 172.16.0.2 | campus-spine2 | 172.16.0.21 | -| dc-border-leaf1 | 172.16.0.3 | campus-border-leaf1 | 172.16.0.22 | -| dc-border-leaf2 | 172.16.0.4 | campus-border-leaf2 | 172.16.0.23 | -| core1 | 172.16.0.10 | campus-leaf1-4 | 172.16.0.51-54 | -| core2 | 172.16.0.11 | campus-access1 | 172.16.0.61 | -| dc-leaf1 | 172.16.0.25 | campus-access2 | 172.16.0.62 | -| dc-leaf2 | 172.16.0.50 | dc-server1-4 | 172.16.0.101-104| -| dc-leaf3-8 | 172.16.0.27-32 | campus-host1 | 172.16.0.105 | -| dc-access1-4 | 172.16.0.41-44 | campus-host2 | 172.16.0.106 | +| Node | IP | Node | IP | +| --------------- | -------------- | ------------------- | ---------------- | +| dc-spine1 | 172.16.0.1 | campus-spine1 | 172.16.0.20 | +| dc-spine2 | 172.16.0.2 | campus-spine2 | 172.16.0.21 | +| dc-border-leaf1 | 172.16.0.3 | campus-border-leaf1 | 172.16.0.22 | +| dc-border-leaf2 | 172.16.0.4 | campus-border-leaf2 | 172.16.0.23 | +| core1 | 172.16.0.10 | campus-leaf1-4 | 172.16.0.51-54 | +| core2 | 172.16.0.11 | campus-access1 | 172.16.0.61 | +| dc-leaf1 | 172.16.0.25 | campus-access2 | 172.16.0.62 | +| dc-leaf2 | 172.16.0.50 | dc-server1-4 | 172.16.0.101-104 | +| dc-leaf3-8 | 172.16.0.27-32 | campus-host1 | 172.16.0.105 | +| dc-access1-4 | 172.16.0.41-44 | campus-host2 | 172.16.0.106 | +| | | gnmic | 172.16.0.70 | Gateway: `172.16.0.254`. ### Router-ID Loopback0 (`Lo0`) -| Zone | Range | Nodes | -| ------ | ------------------- | --------------------------------------------------------------------- | -| DC | `10.0.250.0/24` | dc-spine1 .1, dc-spine2 .2, dc-leaf1-8 .11-.18, BL-dc1 .21, BL-dc2 .22 | -| Core | `10.0.200.0/24` | core1 `10.0.200.1`, core2 `10.0.200.2` | -| Campus | `10.1.250.0/24` | campus-spine1 .1, campus-spine2 .2, campus-leaf1-4 .11-.14, BL-campus1 .21, BL-campus2 .22 | +| Zone | Range | Nodes | +| ------ | --------------- | ------------------------------------------------------------------------------------------ | +| DC | `10.0.250.0/24` | dc-spine1 .1, dc-spine2 .2, dc-leaf1-8 .11-.18, BL-dc1 .21, BL-dc2 .22 | +| Core | `10.0.200.0/24` | core1 `10.0.200.1`, core2 `10.0.200.2` | +| Campus | `10.1.250.0/24` | campus-spine1 .1, campus-spine2 .2, campus-leaf1-4 .11-.14, BL-campus1 .21, BL-campus2 .22 | ### VTEP Loopback1 (`Lo1`) β€” shared per MLAG pair -| Fabric | VTEP | Address | Leafs | -| ------ | ------ | --------------- | ---------------------- | -| DC | VTEP1 | `10.0.255.11` | dc-leaf1, dc-leaf2 | -| DC | VTEP2 | `10.0.255.12` | dc-leaf3, dc-leaf4 | -| DC | VTEP3 | `10.0.255.13` | dc-leaf5, dc-leaf6 | -| DC | VTEP4 | `10.0.255.14` | dc-leaf7, dc-leaf8 | -| DC | BL | `10.0.255.15` | dc-border-leaf1/2 | -| Campus | VTEP1 | `10.1.255.11` | campus-leaf1/2 | -| Campus | VTEP2 | `10.1.255.12` | campus-leaf3/4 | -| Campus | BL | `10.1.255.21` | campus-border-leaf1/2 | +| Fabric | VTEP | Address | Leafs | +| ------ | ----- | ------------- | --------------------- | +| DC | VTEP1 | `10.0.255.11` | dc-leaf1, dc-leaf2 | +| DC | VTEP2 | `10.0.255.12` | dc-leaf3, dc-leaf4 | +| DC | VTEP3 | `10.0.255.13` | dc-leaf5, dc-leaf6 | +| DC | VTEP4 | `10.0.255.14` | dc-leaf7, dc-leaf8 | +| DC | BL | `10.0.255.15` | dc-border-leaf1/2 | +| Campus | VTEP1 | `10.1.255.11` | campus-leaf1/2 | +| Campus | VTEP2 | `10.1.255.12` | campus-leaf3/4 | +| Campus | BL | `10.1.255.21` | campus-border-leaf1/2 | ### Underlay P2P (`/31`) -| Segment | Subnets | -| -------------------------------- | --------------------------------------- | -| DC dc-spine1 ↔ leaf/BL | `10.0.1.0/31` … `10.0.1.18/31` | -| DC dc-spine2 ↔ leaf/BL | `10.0.2.0/31` … `10.0.2.18/31` | -| DC MLAG iBGP SVIs (per pair) | `10.0.3.0/31`, `.2/31`, `.4/31`, `.6/31`, `.8/31` (BL) | -| DC MLAG peer-link SVIs | `10.0.199.240/31` … `10.0.199.246/31` | -| DC-BL ↔ Core (default, `.100`) | `10.0.4.0/31` .. `10.0.4.6/31` | -| DC-BL ↔ Core (VRF gold, `.200`) | `10.0.14.0/31` .. `10.0.14.6/31` | -| Campus-BL ↔ Core (default) | `10.0.5.0/31` .. `10.0.5.6/31` | -| Campus-BL ↔ Core (VRF gold) | `10.0.15.0/31` .. `10.0.15.6/31` | -| Core1 ↔ Core2 (default) | `10.0.200.128/31` | -| Core1 ↔ Core2 (VRF gold) | `10.0.200.130/31` | -| Campus dc-spine1 ↔ leaf/BL | `10.1.1.0/31` … `10.1.1.10/31` | -| Campus dc-spine2 ↔ leaf/BL | `10.1.2.0/31` … `10.1.2.10/31` | -| Campus MLAG iBGP SVIs | `10.1.3.0/31`, `.2/31`, `.4/31` | -| Campus MLAG peer-link SVIs | `10.1.199.250/31` … `10.1.199.254/31` | +| Segment | Subnets | +| ------------------------------- | ------------------------------------------------------ | +| DC dc-spine1 ↔ leaf/BL | `10.0.1.0/31` … `10.0.1.18/31` | +| DC dc-spine2 ↔ leaf/BL | `10.0.2.0/31` … `10.0.2.18/31` | +| DC MLAG iBGP SVIs (per pair) | `10.0.3.0/31`, `.2/31`, `.4/31`, `.6/31`, `.8/31` (BL) | +| DC MLAG peer-link SVIs | `10.0.199.240/31` … `10.0.199.246/31` | +| DC-BL ↔ Core (default, `.100`) | `10.0.4.0/31` .. `10.0.4.6/31` | +| DC-BL ↔ Core (VRF gold, `.200`) | `10.0.14.0/31` .. `10.0.14.6/31` | +| Campus-BL ↔ Core (default) | `10.0.5.0/31` .. `10.0.5.6/31` | +| Campus-BL ↔ Core (VRF gold) | `10.0.15.0/31` .. `10.0.15.6/31` | +| Core1 ↔ Core2 (default) | `10.0.200.128/31` | +| Core1 ↔ Core2 (VRF gold) | `10.0.200.130/31` | +| Campus dc-spine1 ↔ leaf/BL | `10.1.1.0/31` … `10.1.1.10/31` | +| Campus dc-spine2 ↔ leaf/BL | `10.1.2.0/31` … `10.1.2.10/31` | +| Campus MLAG iBGP SVIs | `10.1.3.0/31`, `.2/31`, `.4/31` | +| Campus MLAG peer-link SVIs | `10.1.199.250/31` … `10.1.199.254/31` | ### Host Addressing -| Host | VLAN | VRF | IP / Mask | Gateway | Purpose | -| ------------- | ---- | -------- | ----------------- | ------------ | ------------------------------ | -| dc-server1 | 40 | default | 10.40.40.101/24 | β€” | DC L2 stretched (VTEP1↔VTEP3) | -| dc-server2 | 34 | gold | 10.34.34.102/24 | 10.34.34.1 | DC L3 VRF gold | -| dc-server3 | 40 | default | 10.40.40.103/24 | β€” | DC L2 stretched | -| dc-server4 | 78 | gold | 10.78.78.104/24 | 10.78.78.1 | DC L3 VRF gold | -| campus-host1 | 60 | gold | 10.60.60.101/24 | 10.60.60.1 | Campus L3 VRF gold | -| campus-host2 | 70 | gold | 10.60.70.102/24 | 10.60.70.1 | Campus L3 VRF gold | +| Host | VLAN | VRF | IP / Mask | Gateway | Purpose | +| ------------ | ---- | ------- | --------------- | ---------- | ----------------------------- | +| dc-server1 | 40 | default | 10.40.40.101/24 | β€” | DC L2 stretched (VTEP1↔VTEP3) | +| dc-server2 | 34 | gold | 10.34.34.102/24 | 10.34.34.1 | DC L3 VRF gold | +| dc-server3 | 40 | default | 10.40.40.103/24 | β€” | DC L2 stretched | +| dc-server4 | 78 | gold | 10.78.78.104/24 | 10.78.78.1 | DC L3 VRF gold | +| campus-host1 | 60 | gold | 10.60.60.101/24 | 10.60.60.1 | Campus L3 VRF gold | +| campus-host2 | 70 | gold | 10.60.70.102/24 | 10.60.70.1 | Campus L3 VRF gold | > DC hosts are dual-homed in LACP over `bond0` with tagged VLAN sub-interfaces. > Campus hosts are single-attached with one untagged `eth1` in a single access VLAN. @@ -195,20 +196,20 @@ Gateway: `172.16.0.254`. ### L2 VNI Mapping -| VLAN | Description | VNI | Scope | RT | -| ---- | ------------------------------ | ------ | ------------------------------------------------------ | ---------- | -| 40 | DC L2 VXLAN (stretched) | 110040 | DC VTEP1 (dc-leaf1/2) + VTEP3 (dc-leaf5/6) | 40:110040 | -| 50 | Campus L2 VXLAN (stretched) | 110050 | Campus VTEP1 (campus-leaf1/2) + VTEP2 (campus-leaf3/4) | 50:110050 | -| 34 | DC VRF gold subnet (local) | 110034 | DC VTEP2 only (anycast GW 10.34.34.1) | 34:110034 | -| 78 | DC VRF gold subnet (local) | 110078 | DC VTEP4 only (anycast GW 10.78.78.1) | 78:110078 | -| 60 | Campus VRF gold subnet (local) | 110060 | Campus VTEP1 only (anycast GW 10.60.60.1) | 60:110060 | -| 70 | Campus VRF gold subnet (local) | 110070 | Campus VTEP2 only (anycast GW 10.60.70.1) | 70:110070 | +| VLAN | Description | VNI | Scope | RT | +| ---- | ------------------------------ | ------ | ------------------------------------------------------ | --------- | +| 40 | DC L2 VXLAN (stretched) | 110040 | DC VTEP1 (dc-leaf1/2) + VTEP3 (dc-leaf5/6) | 40:110040 | +| 50 | Campus L2 VXLAN (stretched) | 110050 | Campus VTEP1 (campus-leaf1/2) + VTEP2 (campus-leaf3/4) | 50:110050 | +| 34 | DC VRF gold subnet (local) | 110034 | DC VTEP2 only (anycast GW 10.34.34.1) | 34:110034 | +| 78 | DC VRF gold subnet (local) | 110078 | DC VTEP4 only (anycast GW 10.78.78.1) | 78:110078 | +| 60 | Campus VRF gold subnet (local) | 110060 | Campus VTEP1 only (anycast GW 10.60.60.1) | 60:110060 | +| 70 | Campus VRF gold subnet (local) | 110070 | Campus VTEP2 only (anycast GW 10.60.70.1) | 70:110070 | ### L3 VNI Mapping (end-to-end) -| VRF | L3 VNI | RT | Scope | -| ---- | ------- | ---------- | ----------------------------------------------------- | -| gold | 100001 | 1:100001 | DC VTEP2/VTEP4/DC-BL + Campus VTEP1/VTEP2/Campus-BL | +| VRF | L3 VNI | RT | Scope | +| ---- | ------ | -------- | --------------------------------------------------- | +| gold | 100001 | 1:100001 | DC VTEP2/VTEP4/DC-BL + Campus VTEP1/VTEP2/Campus-BL | VRF `gold` is announced over EVPN Type-5 (IP prefix) inside each fabric, and **stitched by the Core** via eBGP IPv4 unicast in VRF gold (over the `.200` dot1q subinterfaces). L3 VNI `100001` is re-used end-to-end for symmetry; RT `1:100001` is consistent across both fabrics. @@ -219,19 +220,19 @@ VRF `gold` is announced over EVPN Type-5 (IP prefix) inside each fabric, and **s ## πŸ”€ Control Plane Summary -| Segment | Protocol | Notes | -| ----------------------------------- | ------------------------------------ | ------------------------------------- | -| DC spine ↔ leaf/BL underlay | eBGP IPv4 (AS 65000 ↔ 650xx) | `maximum-paths 4 ecmp 64` | -| DC spine ↔ leaf/BL overlay | eBGP EVPN via Loopback0, multi-hop 3 | Spines reflect via `ebgp peer-group` | -| DC MLAG pair iBGP | iBGP over VLAN 4091 SVI | `next-hop-self` | -| DC-BL ↔ Core (default) | OSPF area 0 + eBGP AS 65005 ↔ 65500 | on `.100` dot1q subinterface | -| DC-BL ↔ Core (VRF gold) | eBGP AS 65005 ↔ 65500 | on `.200` dot1q subinterface | -| Core1 ↔ Core2 (default) | OSPF area 0 + iBGP AS 65500 | via Loopback0 | -| Core1 ↔ Core2 (VRF gold) | iBGP AS 65500 | VRF-aware over `.200` subinterface | -| Campus-BL ↔ Core (default / gold) | OSPF + eBGP AS 66005 ↔ 65500 | same pattern as DC-BL | -| Campus spine ↔ leaf/BL underlay | eBGP IPv4 (AS 66000 ↔ 660xx) | | -| Campus spine ↔ leaf/BL overlay | eBGP EVPN via Loopback0, multi-hop 3 | | -| Campus MLAG pair iBGP | iBGP over VLAN 4091 SVI | | +| Segment | Protocol | Notes | +| --------------------------------- | ------------------------------------ | ------------------------------------ | +| DC spine ↔ leaf/BL underlay | eBGP IPv4 (AS 65000 ↔ 650xx) | `maximum-paths 4 ecmp 64` | +| DC spine ↔ leaf/BL overlay | eBGP EVPN via Loopback0, multi-hop 3 | Spines reflect via `ebgp peer-group` | +| DC MLAG pair iBGP | iBGP over VLAN 4091 SVI | `next-hop-self` | +| DC-BL ↔ Core (default) | OSPF area 0 + eBGP AS 65005 ↔ 65500 | on `.100` dot1q subinterface | +| DC-BL ↔ Core (VRF gold) | eBGP AS 65005 ↔ 65500 | on `.200` dot1q subinterface | +| Core1 ↔ Core2 (default) | OSPF area 0 + iBGP AS 65500 | via Loopback0 | +| Core1 ↔ Core2 (VRF gold) | iBGP AS 65500 | VRF-aware over `.200` subinterface | +| Campus-BL ↔ Core (default / gold) | OSPF + eBGP AS 66005 ↔ 65500 | same pattern as DC-BL | +| Campus spine ↔ leaf/BL underlay | eBGP IPv4 (AS 66000 ↔ 660xx) | | +| Campus spine ↔ leaf/BL overlay | eBGP EVPN via Loopback0, multi-hop 3 | | +| Campus MLAG pair iBGP | iBGP over VLAN 4091 SVI | | ## πŸ§ͺ Testing & Validation @@ -323,6 +324,36 @@ ssh admin@clab-arista-evpn-fabric-dc-border-leaf1 "show bgp evpn route-type ip-p ssh admin@clab-arista-evpn-fabric-campus-border-leaf1 "show bgp evpn route-type ip-prefix ipv4" ``` +## πŸ“‘ Telemetry + +A [`gnmic`](https://gnmic.openconfig.net/) container node subscribes to gNMI (port `6030`, +`eos-native` provider) on every Arista `cEOS` node in the fabric, and exposes the +collected metrics on a Prometheus exporter endpoint. + +Subscriptions (see issue #44 for the path-selection rationale): + +| Subscription | Nodes | Paths | +| -------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------- | +| `eos-interfaces` | all | `interfaces/interface/state/{oper-status,counters}` | +| `eos-bgp` | all | `.../bgp/neighbors/neighbor/state/session-state`, `.../afi-safis/afi-safi/state/prefixes` (IPv4/IPv6 unicast + L2VPN EVPN) | +| `eos-system` | all | `/system/cpus/cpu/state`, `/system/memory/state` | +| `eos-vxlan` | VTEP nodes only (leafs + border-leafs, both fabrics) | VLAN-to-VNI mapping + MAC table entries β€” joined in Prometheus to get MAC count per VNI | + +- Config: `configs/gnmic/gnmic-config.yml` +- TLS: `insecure: true` β€” cEOS gNMI runs in plaintext here (no SSL profile configured on + `management api gnmi`), not TLS; `skip-verify` would fail the handshake +- `oper-status` and BGP `session-state` are string enums; gnmic's Prometheus output drops + non-numeric leaves, so the `state-to-int` event-processor maps them to `1`/`0` +- Prometheus exporter: `http://clab-arista-evpn-fabric-gnmic:9273/metrics` + +```bash +# Validate gnmic is subscribed and streaming from all targets +docker logs clab-arista-evpn-fabric-gnmic + +# Scrape the Prometheus exporter directly +docker exec clab-arista-evpn-fabric-gnmic wget -qO- http://localhost:9273/metrics | head +``` + ## πŸ“ Repository Structure ``` @@ -343,7 +374,9 @@ arista-evpn-vxlan-clab/ β”‚ β”œβ”€β”€ campus-spine1.cfg, campus-spine2.cfg β”‚ β”œβ”€β”€ campus-leaf1.cfg … campus-leaf4.cfg β”‚ β”œβ”€β”€ campus-border-leaf1.cfg, campus-border-leaf2.cfg -β”‚ └── campus-access1.cfg, campus-access2.cfg +β”‚ β”œβ”€β”€ campus-access1.cfg, campus-access2.cfg +β”‚ └── gnmic/ +β”‚ └── gnmic-config.yml └── hosts/ β”œβ”€β”€ README.md β”œβ”€β”€ dc-server1_interfaces … dc-server4_interfaces diff --git a/configs/gnmic/gnmic-config.yml b/configs/gnmic/gnmic-config.yml new file mode 100644 index 0000000..1fe6e5e --- /dev/null +++ b/configs/gnmic/gnmic-config.yml @@ -0,0 +1,135 @@ +username: admin +password: admin +port: 6030 +timeout: 10s + +common_eos_subscriptions: &common_eos_subs + insecure: true + subscriptions: + - eos-interfaces + - eos-bgp + - eos-system + +vtep_eos_subscriptions: &vtep_eos_subs + insecure: true + subscriptions: + - eos-interfaces + - eos-bgp + - eos-system + - eos-vxlan + +targets: + # DC fabric + dc-spine1: *common_eos_subs + dc-spine2: *common_eos_subs + dc-leaf1: *vtep_eos_subs + dc-leaf2: *vtep_eos_subs + dc-leaf3: *vtep_eos_subs + dc-leaf4: *vtep_eos_subs + dc-leaf5: *vtep_eos_subs + dc-leaf6: *vtep_eos_subs + dc-leaf7: *vtep_eos_subs + dc-leaf8: *vtep_eos_subs + dc-border-leaf1: *vtep_eos_subs + dc-border-leaf2: *vtep_eos_subs + dc-access1: *common_eos_subs + dc-access2: *common_eos_subs + dc-access3: *common_eos_subs + dc-access4: *common_eos_subs + + # Core + core1: *common_eos_subs + core2: *common_eos_subs + + # Campus fabric + campus-spine1: *common_eos_subs + campus-spine2: *common_eos_subs + campus-border-leaf1: *vtep_eos_subs + campus-border-leaf2: *vtep_eos_subs + campus-leaf1: *vtep_eos_subs + campus-leaf2: *vtep_eos_subs + campus-leaf3: *vtep_eos_subs + campus-leaf4: *vtep_eos_subs + campus-access1: *common_eos_subs + campus-access2: *common_eos_subs + +subscriptions: + eos-interfaces: + mode: stream + stream-mode: sample + sample-interval: 10s + paths: + - /interfaces/interface/state/oper-status + - /interfaces/interface/state/counters + eos-bgp: + mode: stream + stream-mode: sample + sample-interval: 10s + paths: + - /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/state/session-state + - /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/state/prefixes + eos-system: + mode: stream + stream-mode: sample + sample-interval: 10s + paths: + - /system/cpus/cpu/state + - /system/memory/state + eos-vxlan: + mode: stream + stream-mode: sample + sample-interval: 10s + paths: + # VLAN-to-VNI mapping (join key for MAC-count-per-VNI in Prometheus) + - /interfaces/interface[name=Vxlan1]/arista-exp-eos-vxlan:arista-vxlan/vlan-to-vnis/vlan-to-vni + # MAC table entries, tagged by VLAN β€” joined with the mapping above to get per-VNI counts + - /network-instances/network-instance/fdb/mac-table/entries/entry + +outputs: + prom-output: + type: prometheus + listen: :9273 + event-processors: + - state-to-int + +# oper-status and BGP session-state are string enums; the Prometheus output +# silently drops non-numeric values, so they're mapped to 1 (up/established) / 0 (anything else) +processors: + state-to-int: + event-strings: + value-names: + - ".*oper-status$" + - ".*session-state$" + transforms: + - replace: + apply-on: "value" + old: "UP" + new: "1" + - replace: + apply-on: "value" + old: "ESTABLISHED" + new: "1" + - replace: + apply-on: "value" + old: "DOWN" + new: "0" + - replace: + apply-on: "value" + old: "IDLE" + new: "0" + - replace: + apply-on: "value" + old: "CONNECT" + new: "0" + - replace: + apply-on: "value" + old: "ACTIVE" + new: "0" + - replace: + apply-on: "value" + old: "OPENSENT" + new: "0" + - replace: + apply-on: "value" + old: "OPENCONFIRM" + new: "0" diff --git a/evpn-lab.clab.yml b/evpn-lab.clab.yml index 07c656d..46a6d40 100644 --- a/evpn-lab.clab.yml +++ b/evpn-lab.clab.yml @@ -290,6 +290,18 @@ topology: exec: - ifup eth1 + # ===================================================== + # TELEMETRY + # ===================================================== + + gnmic: + kind: linux + mgmt-ipv4: 172.16.0.70 + image: ghcr.io/openconfig/gnmic:0.46.0 + binds: + - configs/gnmic/gnmic-config.yml:/gnmic-config.yml:ro + cmd: --config /gnmic-config.yml --log subscribe + links: # ===================================================== # DATACENTER FABRIC LINKS