EVPN (E-LAN, EVPN-VPWS)

Discovered EVPN instances (RFC 7432), observed via BMP (AFI 25 / SAFI 70) — no SNMP walk. An EVI is a route-target equivalence class of per-(BMP target, RD) observations; members are deduped by PE across observing targets (observer-collapse: a dual-RR fabric reports one EVI, not two). Control-plane only: membership and MAC/IP counts come from BGP routes; the data path (VXLAN underlay or LSPs) is not traced. Read-only, all-role, scoped per network.

List EVPN Instances

GET /api/v1/networks/{networkID}/evpn/instances

Canonical EVIs for the network. No query parameters; returns a plain JSON array (not the paginated envelope).

Response: 200 OK

[
  {
    "name": "65100:10100",
    "service_kind": "elan",
    "encap": "vxlan",
    "rds": ["192.0.2.1:100", "192.0.2.2:100"],
    "rts": ["65100:10100"],
    "members": [
      { "pe_addr": "192.0.2.1", "pe_device_id": "uuid", "vni_or_label": 10100, "mac_count": 5, "ip_count": 2, "oper": true },
      { "pe_addr": "192.0.2.2", "vni_or_label": 10100, "mac_count": 3, "ip_count": 1, "oper": true }
    ],
    "mac_count": 8,
    "stale": false,
    "observations": 2,
    "instance_ids": ["uuid-a", "uuid-b"]
  }
]

service_kind is elan (any IMET/RT-3 observation in the cluster) or vpws (per-EVI RT-1 with no IMET anywhere — RFC 8214). encap is vxlan | mpls | "". pe_device_id is present only when the PE resolves to a known node (absent = off-view). mac_count sums the deduped members. stale is true when every observing target's session is down — a monitoring gap, never a withdrawal. The array is [] when empty.

Get EVPN Instance

GET /api/v1/evpn/instances/{id}

One canonical EVI — the rollup cluster containing observation {id} (any value from a list entry's instance_ids), plus the Ethernet Segments (RT-4) its member PEs attach to and its recent symptom events (newest first, max 20, last 30 days).

Response: 200 OK — the instance object above, with added segments and recent_events arrays:

{
  "name": "65100:10100", "service_kind": "elan", "encap": "vxlan",
  "members": [ ... ],
  "segments": [
    { "esi": "00:00:00:00:00:00:00:00:00:01", "pes": [ { "pe_addr": "192.0.2.1", "pe_device_id": "uuid" } ] }
  ],
  "recent_events": [
    { "id": "uuid", "event_time": "2026-07-09T12:00:00Z", "event_type": "evpn_mac_move",
      "detail": { "mac": "00:00:be:ef:00:11", "old_pe": "192.0.2.1", "new_pe": "192.0.2.2", "mobility_seq": 1 } }
  ]
}

recent_events carries evpn_mac_move (a host moved between PEs — RFC 7432 §7.7 sequence bump; all-active multihoming aliasing never fires) and evpn_pe_lost (membership absent across all live BMP targets) topology events. 404 Not Found when the id is unknown.

For evpn_mac_move, detail contains mac, evi_rt, rd, vni_or_label, old_pe, new_pe, old_esi, new_esi, mobility_seq, router_a, and router_b. For evpn_pe_lost, it contains rd, pe_addr, and router_a. PE addresses and resolved router identities are distinct; unavailable identity values can be empty. A BMP monitoring outage is not itself a membership withdrawal.

List Ethernet Segments

GET /api/v1/networks/{networkID}/evpn/segments

Ethernet Segments (RT-4 view): each ESI with the PEs attached to it (multihoming membership). No query parameters; returns a plain JSON array.

Response: 200 OK

[
  { "esi": "00:00:00:00:00:00:00:00:00:01", "pes": [ { "pe_addr": "192.0.2.1", "pe_device_id": "uuid" }, { "pe_addr": "192.0.2.2" } ] }
]

The array is [] when empty.