## 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
298 lines
8.7 KiB
YAML
298 lines
8.7 KiB
YAML
# BGP Schema for EVPN-VXLAN Fabric
|
|
# Defines Autonomous System, Peer Groups, and BGP Sessions
|
|
---
|
|
version: "1.0"
|
|
nodes:
|
|
# ================================================================
|
|
# Autonomous System
|
|
# ================================================================
|
|
- name: AutonomousSystem
|
|
namespace: Infra
|
|
description: BGP Autonomous System
|
|
label: Autonomous System
|
|
icon: mdi--cloud-outline
|
|
include_in_menu: false
|
|
human_friendly_id:
|
|
- asn__value
|
|
order_by:
|
|
- asn__value
|
|
display_label: "{{ asn__value }}"
|
|
attributes:
|
|
- name: asn
|
|
kind: Number
|
|
unique: true
|
|
description: AS Number (e.g., 65000)
|
|
- name: description
|
|
kind: Text
|
|
optional: true
|
|
- name: as_type
|
|
kind: Dropdown
|
|
default_value: private
|
|
choices:
|
|
- name: private
|
|
label: Private
|
|
- name: public
|
|
label: Public
|
|
|
|
# ================================================================
|
|
# BGP Router Configuration (per device)
|
|
# ================================================================
|
|
- name: BGPRouterConfig
|
|
namespace: Infra
|
|
description: BGP router configuration on a device
|
|
label: BGP Router Config
|
|
icon: mdi--router-wireless
|
|
include_in_menu: false
|
|
human_friendly_id:
|
|
- device__name__value
|
|
display_label: "{{ router_id__value }}"
|
|
attributes:
|
|
- name: router_id
|
|
kind: IPHost
|
|
unique: true
|
|
description: BGP Router ID
|
|
- name: default_ipv4_unicast
|
|
kind: Boolean
|
|
default_value: false
|
|
description: Enable default IPv4 unicast
|
|
- name: log_neighbor_changes
|
|
kind: Boolean
|
|
default_value: true
|
|
- name: ecmp_max_paths
|
|
kind: Number
|
|
default_value: 4
|
|
description: Maximum ECMP paths
|
|
- name: ecmp_max_ecmp
|
|
kind: Number
|
|
default_value: 64
|
|
description: Maximum ECMP routes
|
|
- name: ebgp_distance
|
|
kind: Number
|
|
default_value: 20
|
|
description: eBGP administrative distance
|
|
- name: ibgp_distance
|
|
kind: Number
|
|
default_value: 200
|
|
description: iBGP administrative distance
|
|
- name: local_distance
|
|
kind: Number
|
|
default_value: 200
|
|
description: Local route administrative distance
|
|
relationships:
|
|
- name: device
|
|
peer: InfraDevice
|
|
cardinality: one
|
|
kind: Parent
|
|
optional: false
|
|
- name: local_asn
|
|
peer: InfraAutonomousSystem
|
|
cardinality: one
|
|
- name: peer_groups
|
|
peer: InfraBGPPeerGroup
|
|
cardinality: many
|
|
kind: Component
|
|
- name: sessions
|
|
peer: InfraBGPSession
|
|
cardinality: many
|
|
kind: Component
|
|
|
|
# ================================================================
|
|
# BGP Peer Group
|
|
# ================================================================
|
|
- name: BGPPeerGroup
|
|
namespace: Infra
|
|
description: BGP peer group template
|
|
label: BGP Peer Group
|
|
icon: mdi--account-group
|
|
include_in_menu: false
|
|
uniqueness_constraints:
|
|
- ["local_identifier__value"]
|
|
human_friendly_id:
|
|
- local_identifier__value
|
|
display_label: "{{ name__value }}"
|
|
attributes:
|
|
- name: local_identifier
|
|
kind: Text
|
|
description: "Unique identifier combining device name and peer group name (e.g. spine1__evpn)"
|
|
- name: name
|
|
kind: Text
|
|
description: Peer group name (e.g., underlay, evpn)
|
|
- name: description
|
|
kind: Text
|
|
optional: true
|
|
- name: update_source
|
|
kind: Text
|
|
optional: true
|
|
description: Update source interface (e.g., Loopback0)
|
|
- name: ebgp_multihop
|
|
kind: Number
|
|
optional: true
|
|
description: eBGP multihop TTL
|
|
- name: send_community
|
|
kind: Dropdown
|
|
default_value: none
|
|
choices:
|
|
- name: none
|
|
label: None
|
|
- name: standard
|
|
label: Standard
|
|
- name: extended
|
|
label: Extended
|
|
- name: both
|
|
label: Both
|
|
- name: next_hop_self
|
|
kind: Boolean
|
|
default_value: false
|
|
- name: next_hop_unchanged
|
|
kind: Boolean
|
|
default_value: false
|
|
description: Keep next-hop unchanged (for route reflector)
|
|
- name: maximum_routes
|
|
kind: Number
|
|
optional: true
|
|
- name: maximum_routes_warning_only
|
|
kind: Boolean
|
|
default_value: true
|
|
- name: peer_group_type
|
|
kind: Dropdown
|
|
default_value: underlay
|
|
choices:
|
|
- name: underlay
|
|
label: Underlay IPv4
|
|
- name: underlay_ibgp
|
|
label: Underlay iBGP
|
|
- name: evpn
|
|
label: EVPN Overlay
|
|
relationships:
|
|
- name: bgp_config
|
|
peer: InfraBGPRouterConfig
|
|
cardinality: one
|
|
kind: Parent
|
|
optional: false
|
|
- name: remote_asn
|
|
peer: InfraAutonomousSystem
|
|
cardinality: one
|
|
optional: true
|
|
|
|
# ================================================================
|
|
# BGP Session (Neighbor)
|
|
# ================================================================
|
|
- name: BGPSession
|
|
namespace: Infra
|
|
description: BGP neighbor session
|
|
label: BGP Session
|
|
icon: mdi--connection
|
|
include_in_menu: false
|
|
uniqueness_constraints:
|
|
- ["local_identifier__value"]
|
|
human_friendly_id:
|
|
- local_identifier__value
|
|
display_label: "{{ peer_address__value }}"
|
|
attributes:
|
|
- name: local_identifier
|
|
kind: Text
|
|
description: "Unique identifier combining device name and peer address (e.g. spine1__10.0.250.11)"
|
|
- name: peer_address
|
|
kind: IPHost
|
|
description: Neighbor IP address
|
|
- name: description
|
|
kind: Text
|
|
optional: true
|
|
- name: enabled
|
|
kind: Boolean
|
|
default_value: true
|
|
relationships:
|
|
- name: bgp_config
|
|
peer: InfraBGPRouterConfig
|
|
cardinality: one
|
|
kind: Parent
|
|
optional: false
|
|
- name: peer_group
|
|
peer: InfraBGPPeerGroup
|
|
cardinality: one
|
|
optional: true
|
|
- name: remote_asn
|
|
peer: InfraAutonomousSystem
|
|
cardinality: one
|
|
optional: true
|
|
description: Override peer group remote-as
|
|
- name: peer_device
|
|
peer: InfraDevice
|
|
cardinality: one
|
|
optional: true
|
|
description: Remote peer device (for documentation)
|
|
- name: vrf
|
|
peer: InfraVRF
|
|
cardinality: one
|
|
kind: Attribute
|
|
optional: true
|
|
description: VRF context for this session (null = global BGP process)
|
|
|
|
# ================================================================
|
|
# BGP Address Family Configuration
|
|
# ================================================================
|
|
- name: BGPAddressFamily
|
|
namespace: Infra
|
|
description: BGP address family configuration
|
|
label: BGP Address Family
|
|
icon: mdi--format-list-bulleted
|
|
include_in_menu: false
|
|
human_friendly_id:
|
|
- local_identifier__value
|
|
display_label: "{{ afi__value }}"
|
|
attributes:
|
|
- name: local_identifier
|
|
kind: Text
|
|
description: "Unique identifier combining device name and AFI/SAFI (e.g. spine1__ipv4_unicast)"
|
|
- name: afi
|
|
kind: Dropdown
|
|
choices:
|
|
- name: ipv4
|
|
label: IPv4
|
|
- name: ipv6
|
|
label: IPv6
|
|
- name: evpn
|
|
label: EVPN
|
|
description: Address Family Identifier
|
|
- name: safi
|
|
kind: Dropdown
|
|
default_value: unicast
|
|
choices:
|
|
- name: unicast
|
|
label: Unicast
|
|
- name: multicast
|
|
label: Multicast
|
|
description: Sub Address Family Identifier
|
|
relationships:
|
|
- name: device
|
|
peer: InfraDevice
|
|
cardinality: one
|
|
kind: Attribute
|
|
optional: false
|
|
description: Device this address family belongs to (denormalized for query filtering)
|
|
- name: bgp_config
|
|
peer: InfraBGPRouterConfig
|
|
cardinality: one
|
|
kind: Parent
|
|
optional: false
|
|
- name: active_peer_groups
|
|
peer: InfraBGPPeerGroup
|
|
cardinality: many
|
|
description: Peer groups activated in this AF
|
|
- name: active_sessions
|
|
peer: InfraBGPSession
|
|
cardinality: many
|
|
optional: true
|
|
description: Individual sessions activated in this AF (e.g. spine direct neighbors)
|
|
- name: vrf
|
|
peer: InfraVRF
|
|
cardinality: one
|
|
kind: Attribute
|
|
optional: true
|
|
description: VRF context for this AF (null = global BGP process)
|
|
- name: networks
|
|
peer: InfraIPAddress
|
|
cardinality: many
|
|
optional: true
|
|
description: Networks to advertise
|