## Summary Closes #23. Implements a single unified `bgp_yang_transform` covering the complete BGP router stanza for all 10 fabric devices. **Design decision:** One transform (one query + one template) rather than 4 separate transforms, because all BGP components (process config, peer groups, neighbors, AFs) live under a single `router bgp <ASN>` stanza and must be consistent. This avoids multiple API calls per device and keeps the data model coherent. | File | Description | |------|-------------| | `infrahub/transforms/queries/bgp_intent.gql` | Unified GraphQL query — `InfraBGPRouterConfig` (with peer_groups, sessions) + `InfraBGPAddressFamily` (with active_peer_groups, active_sessions, networks, optional vrf) | | `infrahub/transforms/templates/bgp_yang.j2` | Jinja2 template — renders `bgp.global`, `bgp.peer_groups`, `bgp.neighbors`, `bgp.address_families`, `bgp.vrf_neighbors`, `bgp.vrf_address_families`; returns `[]` for devices with no BGP config | | `infrahub/transforms/tests/bgp_yang/test.yml` | Smoke check + unit render tests for leaf1, spine1, leaf7 | | `infrahub/transforms/tests/bgp_yang/leaf1/` | 3 peer-groups, 5 global neighbors, 2 global AFs | | `infrahub/transforms/tests/bgp_yang/spine1/` | 1 peer-group (evpn/next-hop-unchanged), 16 neighbors (8 direct underlay + 8 EVPN), IPv4 AF activates individual sessions | | `infrahub/transforms/tests/bgp_yang/leaf7/` | leaf1 pattern + VRF gold border session (AS 64999) + VRF-scoped IPv4 unicast AF | | `.infrahub.yml` | Registers `bgp_intent` query and `bgp_yang_transform` | ## Validation | Device | Expected output | |--------|----------------| | `leaf1` | 3 peer-groups, 5 global neighbors (underlay×2, iBGP×1, EVPN×2), 2 AFs, empty VRF sections | | `spine1` | 1 peer-group (evpn, next-hop-unchanged), 16 neighbors (8 direct with `remote_asn`, 8 EVPN via peer-group), IPv4 AF activates individual sessions | | `leaf7` | Same as leaf1 (AS 65004) + `vrf_neighbors: [{10.90.90.1, AS 64999, VRF gold}]` + `vrf_address_families: [{ipv4, VRF gold, active_sessions: [10.90.90.1]}]` | ```bash infrahubctl render bgp_yang_transform device_name=leaf1 infrahubctl render bgp_yang_transform device_name=spine1 infrahubctl render bgp_yang_transform device_name=leaf7 ``` ## Design notes - Follows identical conventions to existing transforms (#20–#22) - All optional relationships (`remote_asn`, `peer_group`, `vrf`, `peer_device`, `update_source`, etc.) wrapped in `is defined and is not none` guards - `send_community` value `"none"` (schema default) is normalised to `null` in the output — keeps the rendered JSON clean for downstream consumers - VRF-scoped sessions and AFs are separated into `vrf_neighbors` / `vrf_address_families` arrays, each entry carrying a `"vrf"` key, so the template consumer can trivially iterate per-VRF without filtering
Infrahub Schema for EVPN-VXLAN Fabric
This directory contains the Infrahub schema definitions for modeling an EVPN-VXLAN fabric. The schema is designed to represent the overlaid.net reference topology (2 spines, 8 leafs in 4 MLAG pairs).
Schema Files
| File | Nodes | Description |
|---|---|---|
base.yml |
Device, InterfaceEthernet, InterfaceLoopback, InterfaceVlan, InterfaceLag, IPAddress, Site, Platform | Core infrastructure and generic Interface |
bgp.yml |
AutonomousSystem, BGPRouterConfig, BGPPeerGroup, BGPSession, BGPAddressFamily | BGP routing configuration |
vlan_vxlan.yml |
VLAN, VNI, VTEP, VlanVniMapping, EVPNInstance | Layer 2 overlay and VXLAN tunneling |
vrf.yml |
VRF, RouteTarget, VRFDeviceAssignment | VRF and L3VNI configuration |
mlag.yml |
MlagDomain, MlagPeerConfig, MlagInterface | MLAG domain and peer configuration |
extensions.yml |
Fabric, UnderlayLink, HostConnection | Fabric topology and connectivity |
Entity Relationship Diagram
┌──────────────┐
│ InfraFabric │
└──────┬───────┘
┌───────────┼───────────┐
▼ ▼ ▼
┌────────────┐ ┌──────────┐ ┌──────────────────┐
│LocationSite│ │InfraAS │ │InfraUnderlayLink │
└────────────┘ └────┬─────┘ │ local/remote: │
│ │ Device,Interface,│
│ │ IPAddress │
┌────────────┘ └──────────────────┘
▼
┌──────────────┐ ┌────────────────┐
│ InfraDevice │◄────────│ InfraPlatform │
└──────┬───────┘ └────────────────┘
│
┌─────────────┼──────────────┬────────────────┐
▼ ▼ ▼ ▼
┌─────────────┐ ┌──────────┐ ┌───────────┐ ┌──────────────┐
│InfraInterface│ │InfraBGP- │ │InfraVTEP │ │InfraMlagDomain│
│ (generic) │ │RouterCfg │ │ │ │ (2 devices) │
└──────┬──────┘ └────┬─────┘ └─────┬─────┘ └──────┬───────┘
│ │ │ │
▼ ▼ ▼ ▼
Subtypes: ┌──────────┐ ┌──────────┐ ┌───────────────┐
- Ethernet │BGPPeer- │ │VlanVni- │ │MlagPeerConfig │
- Loopback │ Group │ │ Mapping │ │ (per device) │
- Vlan └──────────┘ └──────────┘ └───────────────┘
- Lag ┌──────────┐ ┌───────────────┐
│ │BGPSession│ │MlagInterface │
▼ └────┬─────┘ └───────────────┘
┌──────────────┐ │
│InfraIPAddress│ │ optional vrf
└──────────────┘ ▼
┌─────────┐ ┌──────────────┐
│InfraVRF │◄────│InfraRoute- │
└────┬────┘ │ Target │
│ └──────────────┘
▼
┌────────────────┐
│VRFDevice- │
│ Assignment │
│ (per device RD)│
└────────────────┘
Layer 2 / EVPN:
┌──────────┐ ┌──────────┐ ┌──────────────┐
│InfraVLAN │◄──►│ InfraVNI │ │EVPNInstance │
│ │ │(L2/L3) │ │(per device │
│ │ └──────────┘ │ RD/RT) │
└──────────┘ └──────────────┘
Relationship Legend
| Symbol | Meaning |
|---|---|
Parent → child |
Child lifecycle depends on parent (e.g., Device → Interface) |
Component → child |
Owned collection (e.g., VTEP → VlanVniMapping) |
Attribute |
Association without ownership (e.g., BGPSession → VRF) |
Generic |
Polymorphic (e.g., IPAddress → any Interface subtype) |
All Relationships
| Source | Relationship | Target | Kind | Cardinality |
|---|---|---|---|---|
| base.yml | ||||
| InfraInterface | device |
InfraDevice | Parent | one |
| InfraInterface | ip_addresses |
InfraIPAddress | Generic | many |
| InfraDevice | site |
LocationSite | Attribute | one (opt) |
| InfraDevice | platform |
InfraPlatform | Attribute | one (opt) |
| InfraDevice | asn |
InfraAutonomousSystem | Attribute | one (opt) |
| InfraDevice | interfaces |
InfraInterface | Component | many |
| InfraDevice | mlag_domain |
InfraMlagDomain | Attribute | one (opt) |
| InterfaceEthernet | lag |
InterfaceLag | Attribute | one (opt) |
| InterfaceEthernet | connected_interface |
InterfaceEthernet | outbound | one (opt) |
| InterfaceVlan | vlan |
InfraVLAN | Attribute | one (opt) |
| InterfaceLag | members |
InterfaceEthernet | Component | many |
| InfraIPAddress | interface |
InfraInterface | Attribute | one (opt) |
| bgp.yml | ||||
| BGPRouterConfig | device |
InfraDevice | Parent | one |
| BGPRouterConfig | local_asn |
InfraAutonomousSystem | Attribute | one |
| BGPRouterConfig | peer_groups |
BGPPeerGroup | Component | many |
| BGPRouterConfig | sessions |
BGPSession | Component | many |
| BGPPeerGroup | bgp_config |
BGPRouterConfig | Parent | one |
| BGPPeerGroup | remote_asn |
InfraAutonomousSystem | Attribute | one (opt) |
| BGPSession | bgp_config |
BGPRouterConfig | Parent | one |
| BGPSession | peer_group |
BGPPeerGroup | Attribute | one (opt) |
| BGPSession | remote_asn |
InfraAutonomousSystem | Attribute | one (opt) |
| BGPSession | peer_device |
InfraDevice | Attribute | one (opt) |
| BGPSession | vrf |
InfraVRF | Attribute | one (opt) |
| BGPAddressFamily | bgp_config |
BGPRouterConfig | Parent | one |
| BGPAddressFamily | active_peer_groups |
BGPPeerGroup | Attribute | many |
| BGPAddressFamily | networks |
InfraIPAddress | Attribute | many (opt) |
| vlan_vxlan.yml | ||||
| InfraVLAN | vni |
InfraVNI | Attribute | one (opt) |
| InfraVLAN | site |
LocationSite | Attribute | one (opt) |
| InfraVNI | vlan |
InfraVLAN | Attribute | one (opt) |
| InfraVNI | vrf |
InfraVRF | Attribute | one (opt) |
| InfraVTEP | device |
InfraDevice | Parent | one |
| InfraVTEP | source_interface |
InterfaceLoopback | Attribute | one |
| InfraVTEP | vlan_vni_mappings |
VlanVniMapping | Component | many |
| VlanVniMapping | vtep |
InfraVTEP | Parent | one |
| VlanVniMapping | vlan |
InfraVLAN | Attribute | one |
| VlanVniMapping | vni |
InfraVNI | Attribute | one |
| EVPNInstance | device |
InfraDevice | Parent | one |
| EVPNInstance | vlan |
InfraVLAN | Attribute | one |
| vrf.yml | ||||
| InfraVRF | l3vni |
InfraVNI | Attribute | one (opt) |
| InfraVRF | import_targets |
InfraRouteTarget | outbound | many (opt) |
| InfraVRF | export_targets |
InfraRouteTarget | outbound | many (opt) |
| InfraVRF | interfaces |
InfraInterface | Attribute | many (opt) |
| VRFDeviceAssignment | vrf |
InfraVRF | Attribute | one |
| VRFDeviceAssignment | device |
InfraDevice | Parent | one |
| VRFDeviceAssignment | import_targets |
InfraRouteTarget | outbound | many (opt) |
| VRFDeviceAssignment | export_targets |
InfraRouteTarget | outbound | many (opt) |
| mlag.yml | ||||
| MlagDomain | devices |
InfraDevice | Attribute | many (2) |
| MlagDomain | peer_vlan |
InfraVLAN | outbound | one |
| MlagDomain | ibgp_vlan |
InfraVLAN | outbound | one (opt) |
| MlagPeerConfig | device |
InfraDevice | Parent | one |
| MlagPeerConfig | mlag_domain |
MlagDomain | Attribute | one |
| MlagPeerConfig | local_interface |
InterfaceVlan | Attribute | one |
| MlagPeerConfig | peer_link |
InterfaceLag | Attribute | one |
| MlagInterface | mlag_domain |
MlagDomain | Attribute | one |
| MlagInterface | lag_interfaces |
InterfaceLag | Attribute | many (1-2) |
| extensions.yml | ||||
| InfraFabric | spine_asn |
InfraAutonomousSystem | Attribute | one (opt) |
| InfraFabric | sites |
LocationSite | Attribute | many (opt) |
| UnderlayLink | fabric |
InfraFabric | Parent | one |
| UnderlayLink | local_device |
InfraDevice | outbound | one |
| UnderlayLink | local_interface |
InterfaceEthernet | outbound | one |
| UnderlayLink | local_ip_address |
InfraIPAddress | outbound | one |
| UnderlayLink | remote_device |
InfraDevice | outbound | one |
| UnderlayLink | remote_interface |
InterfaceEthernet | outbound | one |
| UnderlayLink | remote_ip_address |
InfraIPAddress | outbound | one |
| HostConnection | vlans |
InfraVLAN | Attribute | many |
| HostConnection | mlag_interface |
MlagInterface | Attribute | one (opt) |
| HostConnection | lag_interface |
InterfaceLag | Attribute | one (opt) |
Reference Topology Mapping
| Physical | Infrahub Model |
|---|---|
| spine1, spine2 | InfraDevice (role: spine) |
| leaf1-8 | InfraDevice (role: leaf) |
| AS 65000 | InfraAutonomousSystem (spines) |
| AS 65001-65004 | InfraAutonomousSystem (leaf pairs) |
| AS 64999 | InfraAutonomousSystem (border router) |
| VLAN 40, 34, 78, 900 | InfraVLAN + InfraVNI |
| VLAN 4090, 4091 | InfraVLAN (vlan_type: mlag_peer/mlag_ibgp, trunk_groups, stp_enabled: false) |
| VRF gold | InfraVRF + VRFDeviceAssignment (per-device RD) |
| Route targets 1:100001 | InfraRouteTarget |
| leaf1+leaf2 pair | InfraMlagDomain |
| Port-Channel999 | InfraInterfaceLag (peer-link) |
| Port-Channel1 | InfraMlagInterface (host-facing) |
| Ethernet1-12 | InfraInterfaceEthernet |
| Loopback0 | InfraInterfaceLoopback (BGP router-id) |
| Loopback1 | InfraInterfaceLoopback (shared VTEP IP per MLAG pair) |
| Vxlan1 | InfraVTEP |
| Vlan34/78 SVIs | InfraInterfaceVlan (virtual_router_address for anycast gateway) |
| peer groups (underlay, evpn, underlay_ibgp) | InfraBGPPeerGroup |
| BGP sessions (global) | InfraBGPSession (vrf: null) |
| BGP sessions in VRF gold (leaf7/8 → AS 64999) | InfraBGPSession (vrf: gold) |
| spine1/2 p2p links | InfraUnderlayLink (IPAddress relations, not attributes) |
| distance bgp 20 200 200 | BGPRouterConfig (ebgp_distance, ibgp_distance, local_distance) |
Usage
Loading the Schema
infrahubctl schema load schemas/
Validation
infrahubctl schema check schemas/
Key Design Decisions
- Generic Interface: All interface types inherit from
InfraInterfacegeneric for polymorphic queries - MLAG as Domain: MLAG is modeled as a domain containing exactly 2 devices, with per-device config via MlagPeerConfig
- BGP Hierarchy: BGPRouterConfig → PeerGroups → Sessions allows template-based configuration
- BGP VRF Sessions: BGPSession has an optional
vrfrelation (kind: Attribute) to support peering inside a VRF context (#50) - VTEP as single model: VTEP is the unique VXLAN model (InterfaceVxlan was removed to avoid duplication — #44)
- EVPN Instance per VLAN: Allows device-specific RD/RT while referencing common VLAN/VNI
- Per-device scoped IDs: BGPPeerGroup and BGPSession use
bgp_config__router_id__valueprefix in human_friendly_id for global uniqueness (#43) - UnderlayLink IPs as relations: local/remote IPs reference InfraIPAddress objects instead of inline attributes to avoid dual source of truth (#47)
- VRFDeviceAssignment: Separates VRF definition (global) from per-device assignment (with device-specific RD/RT overrides)
- Anycast gateway: InterfaceVlan has
virtual_router_addressforip virtual-router addressandautostatefor MLAG SVIs (#46)
Related Issues
- Parent issue: #41 — Define Infrahub Schema for EVPN-VXLAN Fabric
- Schema fixes: #43 (unique IDs), #44 (remove duplicate VTEP), #45 (VLAN unique), #46 (anycast gateway), #47 (underlay IPs), #48 (BGP distance), #49 (trunk groups), #50 (VRF BGP sessions)
- Depends on: Schema being loaded before transforms (#30, #31, #32, #33)