Implement BGP Infrahub Transforms - Underlay and EVPN Overlay #23

Closed
opened 2026-02-27 12:23:41 +00:00 by Damien · 0 comments
Owner

Description

Create Infrahub Transforms for complete BGP configuration including process, neighbors, peer groups, and EVPN address-family.

Context

BGP is the control plane for the EVPN-VXLAN fabric. The transforms need to handle both underlay eBGP (spine-leaf) and overlay EVPN (loopback-to-loopback) sessions, querying BGP data from Infrahub's schema.

Tasks

  • Define Infrahub schema for BGP objects (or use schema-library)
    • BGP Process (ASN, router-id, settings)
    • BGP Peer Groups (templates)
    • BGP Sessions (neighbors)
    • EVPN configuration
  • Create GraphQL queries for BGP intent
    • bgp_process_intent.gql - ASN, router-id, ECMP settings
    • bgp_neighbors_intent.gql - All neighbor sessions
    • bgp_evpn_intent.gql - EVPN overlay configuration
  • Create Jinja2/Python transforms for YANG generation
    • bgp_global_yang.j2 - BGP process config
    • bgp_peer_groups_yang.j2 - Peer group definitions
    • bgp_neighbors_yang.j2 - Neighbor configurations
    • bgp_evpn_yang.j2 - EVPN address-family
  • Handle iBGP (MLAG peer) vs eBGP (spine) distinctions
  • Support ebgp-multihop for EVPN overlay
  • Map next-hop-unchanged for spine EVPN reflectors

BGP Configuration Scope

Based on the reference topology:

Underlay BGP

router bgp 65001
  router-id 10.0.250.11
  neighbor underlay peer group
  neighbor underlay remote-as 65000
  neighbor 10.0.1.0 peer group underlay  # Spine1
  neighbor 10.0.2.0 peer group underlay  # Spine2
  address-family ipv4
    neighbor underlay activate
    network 10.0.250.11/32  # Loopback0
    maximum-paths 4 ecmp 64

EVPN Overlay

router bgp 65001
  neighbor evpn peer group
  neighbor evpn remote-as 65000
  neighbor evpn update-source Loopback0
  neighbor evpn ebgp-multihop 3
  neighbor evpn send-community extended
  neighbor 10.0.250.1 peer group evpn   # Spine1 loopback
  neighbor 10.0.250.2 peer group evpn   # Spine2 loopback
  address-family evpn
    neighbor evpn activate

Example Implementation

GraphQL Query (bgp_neighbors_intent.gql)

query BgpNeighborsIntent($device: String!) {
  InfraBGPSession(device__name__value: $device) {
    edges {
      node {
        peer_address { value }
        peer_asn { value }
        peer_group { node { name { value } } }
        address_families { edges { node { afi { value } } } }
        description { value }
        update_source { node { name { value } } }
        ebgp_multihop { value }
      }
    }
  }
}

Jinja2 Transform (bgp_neighbors_yang.j2)

{% for session in data.InfraBGPSession.edges %}
{% set s = session.node %}
{
  "path": "/network-instances/network-instance[name=default]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address={{ s.peer_address.value }}]",
  "value": {
    "config": {
      "neighbor-address": "{{ s.peer_address.value }}",
      "peer-as": {{ s.peer_asn.value }},
      {% if s.peer_group %}"peer-group": "{{ s.peer_group.node.name.value }}",{% endif %}
      {% if s.description %}"description": "{{ s.description.value }}",{% endif %}
      "enabled": true
    }{% if s.update_source or s.ebgp_multihop %},
    "transport": {
      "config": {
        {% if s.update_source %}"local-address": "{{ s.update_source.node.name.value }}"{% endif %}
      }
    }{% endif %}{% if s.ebgp_multihop %},
    "ebgp-multihop": {
      "config": { "multihop-ttl": {{ s.ebgp_multihop.value }} }
    }{% endif %}
  }
}{% if not loop.last %},{% endif %}
{% endfor %}

.infrahub.yml Addition

jinja2_transforms:
  - name: bgp_global_yang_transform
    description: "Generate YANG payload for BGP process"
    query: bgp_process_intent
    template_path: transforms/bgp_global_yang.j2

  - name: bgp_peer_groups_yang_transform
    description: "Generate YANG payload for BGP peer groups"
    query: bgp_peer_groups_intent
    template_path: transforms/bgp_peer_groups_yang.j2

  - name: bgp_neighbors_yang_transform
    description: "Generate YANG payload for BGP neighbors"
    query: bgp_neighbors_intent
    template_path: transforms/bgp_neighbors_yang.j2

  - name: bgp_evpn_yang_transform
    description: "Generate YANG payload for EVPN address-family"
    query: bgp_evpn_intent
    template_path: transforms/bgp_evpn_yang.j2

queries:
  - name: bgp_process_intent
    file_path: queries/bgp_process_intent.gql
  - name: bgp_peer_groups_intent
    file_path: queries/bgp_peer_groups_intent.gql
  - name: bgp_neighbors_intent
    file_path: queries/bgp_neighbors_intent.gql
  - name: bgp_evpn_intent
    file_path: queries/bgp_evpn_intent.gql

Output Files

transforms/
├── bgp_global_yang.j2
├── bgp_peer_groups_yang.j2
├── bgp_neighbors_yang.j2
└── bgp_evpn_yang.j2
queries/
├── bgp_process_intent.gql
├── bgp_peer_groups_intent.gql
├── bgp_neighbors_intent.gql
└── bgp_evpn_intent.gql
tests/
├── bgp_global_transform_test.yml
├── bgp_neighbors_transform_test.yml
└── bgp_evpn_transform_test.yml

Acceptance Criteria

  • Transforms produce valid BGP YANG structures
  • Correctly handles underlay (eBGP) and overlay (EVPN) sessions
  • Peer groups properly referenced by neighbors
  • EVPN address-family with route-targets supported
  • Unit tests cover all BGP scenarios

Migration Notes (from NetBox)

Before (NetBox) After (Infrahub)
netbox-bgp plugin Infrahub BGP schema (schema-library or custom)
BgpProcessMapper class bgp_global_yang_transform
BgpNeighborMapper class bgp_neighbors_yang_transform
BgpEvpnMapper class bgp_evpn_yang_transform
## Description Create Infrahub Transforms for complete BGP configuration including process, neighbors, peer groups, and EVPN address-family. ## Context BGP is the control plane for the EVPN-VXLAN fabric. The transforms need to handle both underlay eBGP (spine-leaf) and overlay EVPN (loopback-to-loopback) sessions, querying BGP data from Infrahub's schema. ## Tasks - [x] Define Infrahub schema for BGP objects (or use schema-library) - BGP Process (ASN, router-id, settings) - BGP Peer Groups (templates) - BGP Sessions (neighbors) - EVPN configuration - [x] Create GraphQL queries for BGP intent - `bgp_process_intent.gql` - ASN, router-id, ECMP settings - `bgp_neighbors_intent.gql` - All neighbor sessions - `bgp_evpn_intent.gql` - EVPN overlay configuration - [x] Create Jinja2/Python transforms for YANG generation - `bgp_global_yang.j2` - BGP process config - `bgp_peer_groups_yang.j2` - Peer group definitions - `bgp_neighbors_yang.j2` - Neighbor configurations - `bgp_evpn_yang.j2` - EVPN address-family - [x] Handle iBGP (MLAG peer) vs eBGP (spine) distinctions - [x] Support `ebgp-multihop` for EVPN overlay - [x] Map `next-hop-unchanged` for spine EVPN reflectors ## BGP Configuration Scope Based on the reference topology: ### Underlay BGP ``` router bgp 65001 router-id 10.0.250.11 neighbor underlay peer group neighbor underlay remote-as 65000 neighbor 10.0.1.0 peer group underlay # Spine1 neighbor 10.0.2.0 peer group underlay # Spine2 address-family ipv4 neighbor underlay activate network 10.0.250.11/32 # Loopback0 maximum-paths 4 ecmp 64 ``` ### EVPN Overlay ``` router bgp 65001 neighbor evpn peer group neighbor evpn remote-as 65000 neighbor evpn update-source Loopback0 neighbor evpn ebgp-multihop 3 neighbor evpn send-community extended neighbor 10.0.250.1 peer group evpn # Spine1 loopback neighbor 10.0.250.2 peer group evpn # Spine2 loopback address-family evpn neighbor evpn activate ``` ## Example Implementation ### GraphQL Query (`bgp_neighbors_intent.gql`) ```graphql query BgpNeighborsIntent($device: String!) { InfraBGPSession(device__name__value: $device) { edges { node { peer_address { value } peer_asn { value } peer_group { node { name { value } } } address_families { edges { node { afi { value } } } } description { value } update_source { node { name { value } } } ebgp_multihop { value } } } } } ``` ### Jinja2 Transform (`bgp_neighbors_yang.j2`) ```jinja2 {% for session in data.InfraBGPSession.edges %} {% set s = session.node %} { "path": "/network-instances/network-instance[name=default]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address={{ s.peer_address.value }}]", "value": { "config": { "neighbor-address": "{{ s.peer_address.value }}", "peer-as": {{ s.peer_asn.value }}, {% if s.peer_group %}"peer-group": "{{ s.peer_group.node.name.value }}",{% endif %} {% if s.description %}"description": "{{ s.description.value }}",{% endif %} "enabled": true }{% if s.update_source or s.ebgp_multihop %}, "transport": { "config": { {% if s.update_source %}"local-address": "{{ s.update_source.node.name.value }}"{% endif %} } }{% endif %}{% if s.ebgp_multihop %}, "ebgp-multihop": { "config": { "multihop-ttl": {{ s.ebgp_multihop.value }} } }{% endif %} } }{% if not loop.last %},{% endif %} {% endfor %} ``` ### `.infrahub.yml` Addition ```yaml jinja2_transforms: - name: bgp_global_yang_transform description: "Generate YANG payload for BGP process" query: bgp_process_intent template_path: transforms/bgp_global_yang.j2 - name: bgp_peer_groups_yang_transform description: "Generate YANG payload for BGP peer groups" query: bgp_peer_groups_intent template_path: transforms/bgp_peer_groups_yang.j2 - name: bgp_neighbors_yang_transform description: "Generate YANG payload for BGP neighbors" query: bgp_neighbors_intent template_path: transforms/bgp_neighbors_yang.j2 - name: bgp_evpn_yang_transform description: "Generate YANG payload for EVPN address-family" query: bgp_evpn_intent template_path: transforms/bgp_evpn_yang.j2 queries: - name: bgp_process_intent file_path: queries/bgp_process_intent.gql - name: bgp_peer_groups_intent file_path: queries/bgp_peer_groups_intent.gql - name: bgp_neighbors_intent file_path: queries/bgp_neighbors_intent.gql - name: bgp_evpn_intent file_path: queries/bgp_evpn_intent.gql ``` ## Output Files ``` transforms/ ├── bgp_global_yang.j2 ├── bgp_peer_groups_yang.j2 ├── bgp_neighbors_yang.j2 └── bgp_evpn_yang.j2 queries/ ├── bgp_process_intent.gql ├── bgp_peer_groups_intent.gql ├── bgp_neighbors_intent.gql └── bgp_evpn_intent.gql tests/ ├── bgp_global_transform_test.yml ├── bgp_neighbors_transform_test.yml └── bgp_evpn_transform_test.yml ``` ## Acceptance Criteria - [ ] Transforms produce valid BGP YANG structures - [ ] Correctly handles underlay (eBGP) and overlay (EVPN) sessions - [ ] Peer groups properly referenced by neighbors - [ ] EVPN address-family with route-targets supported - [ ] Unit tests cover all BGP scenarios ## Migration Notes (from NetBox) | Before (NetBox) | After (Infrahub) | |-----------------|------------------| | netbox-bgp plugin | Infrahub BGP schema (schema-library or custom) | | `BgpProcessMapper` class | `bgp_global_yang_transform` | | `BgpNeighborMapper` class | `bgp_neighbors_yang_transform` | | `BgpEvpnMapper` class | `bgp_evpn_yang_transform` | ## Related - **Depends on: #41** (Infrahub Schema definition) - Depends on: #30 (Base Transforms pattern) - Reference: [Arista BGP EVPN Configuration](https://overlaid.net/2019/01/27/arista-bgp-evpn-configuration-example/)
Damien added reference feat/infrahub-transforms-bgp 2026-03-01 13:22:20 +00:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Damien/arista-evpn-vxlan-clab#23