# NetBox Data Model for Fabric Orchestrator This document describes how fabric intent is represented in NetBox for the fabric-orchestrator to consume. ## Overview The fabric-orchestrator uses NetBox as the **source of truth** for EVPN-VXLAN fabric configuration. Instead of using ConfigContexts, we leverage NetBox's native data models plus the [NetBox BGP Plugin](https://github.com/netbox-community/netbox-bgp) for comprehensive fabric representation. ### Requirements - NetBox 4.4.x - NetBox BGP Plugin v0.17.x --- ## Data Model Summary ### Native NetBox Models | Feature | NetBox Model | API Endpoint | |---------|--------------|--------------| | **Devices** | `dcim.Device` | `/api/dcim/devices/` | | **Interfaces** | `dcim.Interface` | `/api/dcim/interfaces/` | | **LAGs/Port-Channels** | `dcim.Interface` (type=LAG) | `/api/dcim/interfaces/` | | **VLANs** | `ipam.VLAN` | `/api/ipam/vlans/` | | **VLAN Groups** | `ipam.VLANGroup` | `/api/ipam/vlan-groups/` | | **VRFs** | `ipam.VRF` | `/api/ipam/vrfs/` | | **Route Targets** | `ipam.RouteTarget` | `/api/ipam/route-targets/` | | **IP Addresses** | `ipam.IPAddress` | `/api/ipam/ip-addresses/` | | **Prefixes** | `ipam.Prefix` | `/api/ipam/prefixes/` | | **ASNs** | `ipam.ASN` | `/api/ipam/asns/` | | **L2VPN (EVPN)** | `vpn.L2VPN` | `/api/vpn/l2vpns/` | | **L2VPN Terminations** | `vpn.L2VPNTermination` | `/api/vpn/l2vpn-terminations/` | ### NetBox BGP Plugin Models | Feature | Plugin Model | API Endpoint | |---------|--------------|--------------| | **BGP Sessions** | `netbox_bgp.BGPSession` | `/api/plugins/bgp/sessions/` | | **BGP Peer Groups** | `netbox_bgp.PeerGroup` | `/api/plugins/bgp/peer-groups/` | | **BGP Communities** | `netbox_bgp.Community` | `/api/plugins/bgp/communities/` | | **Routing Policies** | `netbox_bgp.RoutingPolicy` | `/api/plugins/bgp/routing-policies/` | | **Prefix Lists** | `netbox_bgp.PrefixList` | `/api/plugins/bgp/prefix-lists/` | | **AS Path Lists** | `netbox_bgp.ASPathList` | `/api/plugins/bgp/as-path-lists/` | --- ## Custom Fields Reference NetBox doesn't natively support all fabric-specific configurations. The following custom fields must be created to support MLAG, ASN assignment, and VRF extensions. ### Complete Custom Fields List #### Device Custom Fields | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `asn` | ASN | Integer | No | BGP Autonomous System Number assigned to this device | | `mlag_domain_id` | MLAG Domain ID | Text | No | MLAG domain identifier (e.g., "leafs") | | `mlag_peer_address` | MLAG Peer Address | Text | No | MLAG peer IP address | | `mlag_local_address` | MLAG Local Address | Text | No | MLAG local IP address | | `mlag_virtual_mac` | MLAG Virtual MAC | Text | No | Shared virtual-router MAC (e.g., "c001.cafe.babe") | #### Interface Custom Fields | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `mlag_peer_link` | MLAG Peer Link | Boolean | No | Marks interface as MLAG peer-link | | `mlag_id` | MLAG ID | Integer | No | MLAG port-channel ID for host-facing LAGs | #### VRF Custom Fields | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `l3vni` | L3 VNI | Integer | No | Layer 3 VNI for EVPN symmetric IRB | | `vrf_vlan` | VRF VLAN | Integer | No | VLAN ID used for L3 VNI SVI | #### IP Address Custom Fields | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `virtual_ip` | Virtual IP | Boolean | No | Marks IP as anycast/virtual IP (shared across MLAG pair) | ### Custom Field Creation via API ```bash # Example: Create ASN custom field on Device curl -X POST "https://netbox.example.com/api/extras/custom-fields/" \ -H "Authorization: Token $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "content_types": ["dcim.device"], "name": "asn", "label": "ASN", "type": "integer", "required": false, "description": "BGP Autonomous System Number assigned to this device" }' # Example: Create MLAG Peer Link custom field on Interface curl -X POST "https://netbox.example.com/api/extras/custom-fields/" \ -H "Authorization: Token $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "content_types": ["dcim.interface"], "name": "mlag_peer_link", "label": "MLAG Peer Link", "type": "boolean", "required": false, "description": "Marks interface as MLAG peer-link" }' ``` --- ## Fabric Component Mapping ### Devices and Roles | Fabric Role | NetBox Device Role | Description | |-------------|-------------------|-------------| | Spine | `spine` | Spine switches (AS 65000) | | Leaf | `leaf` | Leaf switches (AS 65001-65004) | **Example Device Setup:** - `spine1`, `spine2` - Device Role: spine - `leaf1` through `leaf8` - Device Role: leaf ### Interfaces | Interface Type | NetBox Interface Type | Usage | |----------------|----------------------|-------| | Physical uplinks | `1000base-t` / `10gbase-x-sfpp` | Spine-Leaf connections | | Loopback0 | `virtual` | BGP Router-ID | | Loopback1 | `virtual` | VTEP source (shared by MLAG pair) | | Port-Channel | `lag` | MLAG peer-link, host bonds | | Vxlan1 | `virtual` | VXLAN tunnel interface | | SVI | `virtual` | VLAN interfaces (Vlan40, etc.) | ### IP Addressing Scheme Based on the reference topology: | Purpose | Prefix | Example | |---------|--------|---------| | Spine-Leaf P2P (Spine1) | `10.0.1.0/24` | `10.0.1.0/31`, `10.0.1.2/31`, ... | | Spine-Leaf P2P (Spine2) | `10.0.2.0/24` | `10.0.2.0/31`, `10.0.2.2/31`, ... | | MLAG iBGP Peer | `10.0.3.0/24` | `10.0.3.0/31` per MLAG pair | | MLAG Peer VLAN 4090 | `10.0.199.0/24` | `/31` per MLAG pair | | Loopback0 (Router-ID) | `10.0.250.0/24` | Spine: `.1-.2`, Leaf: `.11-.18` | | Loopback1 (VTEP) | `10.0.255.0/24` | `.11-.14` (shared per MLAG pair) | --- ## BGP Configuration ### ASN Assignments | Device(s) | ASN | Type | Custom Field | |-----------|-----|------|--------------| | spine1, spine2 | 65000 | eBGP | `asn: 65000` | | leaf1, leaf2 | 65001 | iBGP pair | `asn: 65001` | | leaf3, leaf4 | 65002 | iBGP pair | `asn: 65002` | | leaf5, leaf6 | 65003 | iBGP pair | `asn: 65003` | | leaf7, leaf8 | 65004 | iBGP pair | `asn: 65004` | ### BGP Sessions (Plugin) #### Underlay eBGP Sessions Each leaf has eBGP sessions to both spines over point-to-point interfaces: | Local Device | Local IP | Remote Device | Remote IP | Remote ASN | |--------------|----------|---------------|-----------|------------| | leaf1 | 10.0.1.1 | spine1 | 10.0.1.0 | 65000 | | leaf1 | 10.0.2.1 | spine2 | 10.0.2.0 | 65000 | #### Underlay iBGP Sessions Each MLAG pair has an iBGP session for redundancy: | Local Device | Local IP | Remote Device | Remote IP | Notes | |--------------|----------|---------------|-----------|-------| | leaf1 | 10.0.3.0 | leaf2 | 10.0.3.1 | next-hop-self | #### Overlay EVPN Sessions EVPN sessions use loopback addresses with `ebgp-multihop 3`: | Local Device | Local IP (Lo0) | Remote Device | Remote IP (Lo0) | AFI/SAFI | |--------------|----------------|---------------|-----------------|----------| | leaf1 | 10.0.250.11 | spine1 | 10.0.250.1 | L2VPN EVPN | | leaf1 | 10.0.250.11 | spine2 | 10.0.250.2 | L2VPN EVPN | ### BGP Peer Groups (Plugin) | Peer Group | Purpose | Key Settings | |------------|---------|--------------| | `underlay` | eBGP to spines | `remote-as 65000`, `maximum-routes 12000` | | `underlay_ibgp` | iBGP to MLAG peer | `next-hop-self` | | `evpn` | EVPN overlay | `update-source Loopback0`, `ebgp-multihop 3`, `send-community extended` | --- ## VXLAN / EVPN Configuration ### L2VPN for EVPN VNI Mappings NetBox's L2VPN model represents EVPN instances: | L2VPN Name | Type | Identifier (VNI) | Description | |------------|------|------------------|-------------| | `VLAN40-L2VNI` | EVPN | 100040 | L2 VXLAN for VLAN 40 | | `VRF-gold` | EVPN | 100001 | L3 VNI for VRF gold | ### L2VPN Terminations Link VLANs to L2VPNs on specific devices: | L2VPN | Device | Interface/VLAN | |-------|--------|----------------| | `VLAN40-L2VNI` | leaf1 | VLAN 40 | | `VLAN40-L2VNI` | leaf2 | VLAN 40 | | `VLAN40-L2VNI` | leaf5 | VLAN 40 | | `VLAN40-L2VNI` | leaf6 | VLAN 40 | ### Route Targets | VRF/VLAN | Import RT | Export RT | |----------|-----------|-----------| | VLAN 40 | `40:100040` | `40:100040` | | VRF gold | `1:100001` | `1:100001` | --- ## MLAG Configuration MLAG configuration uses Custom Fields since NetBox doesn't have native MLAG support. ### MLAG Pair Configuration | Device | Domain ID | Local IP | Peer IP | Virtual MAC | |--------|-----------|----------|---------|-------------| | leaf1 | leafs | 10.0.199.254 | 10.0.199.255 | c001.cafe.babe | | leaf2 | leafs | 10.0.199.255 | 10.0.199.254 | c001.cafe.babe | ### MLAG-Related VLANs | VLAN | Name | Purpose | Trunk Group | |------|------|---------|-------------| | 4090 | mlag-peer | MLAG peer communication | mlag-peer | | 4091 | mlag-ibgp | iBGP between MLAG peers | mlag-peer | --- ## VRF Configuration ### VRF Definition | VRF Name | RD | Import RT | Export RT | L3 VNI (custom field) | |----------|-------|-----------|-----------|----------------------| | gold | `10.0.250.X:1` | `1:100001` | `1:100001` | 100001 | > Note: RD uses device's Loopback0 IP for uniqueness ### VRF Interface Assignment SVIs are assigned to VRFs in NetBox. VRF membership is tracked via IP addresses assigned to interfaces: | Interface | VRF | IP Address | Virtual IP (custom field) | |-----------|-----|------------|---------------------------| | Vlan34 (leaf3) | gold | 10.34.34.2/24 | No | | Vlan34 (leaf4) | gold | 10.34.34.3/24 | No | | Vlan34 (leaf3) | gold | 10.34.34.1/24 | Yes (anycast) | | Vlan78 (leaf7) | gold | 10.78.78.2/24 | No | | Vlan78 (leaf8) | gold | 10.78.78.3/24 | No | | Vlan78 (leaf7) | gold | 10.78.78.1/24 | Yes (anycast) | --- ## Data Retrieval Strategy The fabric-orchestrator retrieves intent from NetBox using pynetbox: ```python import pynetbox nb = pynetbox.api('http://netbox.example.com', token='your-token') # Get all leaf devices leaves = nb.dcim.devices.filter(role='leaf') # Get device ASN from custom field device = nb.dcim.devices.get(name='leaf1') asn = device.custom_fields.get('asn') # Get BGP sessions for a device bgp_sessions = nb.plugins.bgp.sessions.filter(device='leaf1') # Get L2VPNs (EVPN) l2vpns = nb.vpn.l2vpns.filter(type='evpn') # Get VLAN-to-VNI mappings via L2VPN terminations terminations = nb.vpn.l2vpn_terminations.filter(l2vpn='VLAN40-L2VNI') # Get VRF with L3 VNI vrf = nb.ipam.vrfs.get(name='gold') l3vni = vrf.custom_fields.get('l3vni') ``` --- ## Relationship Diagram ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ NetBox │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌────────────┐ ┌────────────────┐ ┌───────────────┐ │ │ │ Device │─────│ Interface │─────│ IP Address │ │ │ │ (leaf1) │ │ (Loopback0) │ │(10.0.250.11) │ │ │ │ cf:asn │ │ cf:mlag_peer_ │ │ cf:virtual_ip │ │ │ └────────────┘ │ link │ └───────────────┘ │ │ │ └────────────────┘ │ │ │ │ │ │ custom_fields │ │ ▼ │ │ ┌────────────┐ │ │ │ cf:asn │ │ │ │ (65001) │ │ │ └────────────┘ │ │ │ │ ┌──────────────────┐ ┌───────────────────┐ │ │ │ BGP Session │─────│ Peer Group │ │ │ │ (plugin) │ │ (plugin) │ │ │ └──────────────────┘ └───────────────────┘ │ │ │ │ ┌────────────┐ ┌───────────────────────┐ ┌────────────┐ │ │ │ VLAN │─────│ L2VPN Termination │─────│ L2VPN │ │ │ │ (40) │ │ │ │ (EVPN) │ │ │ └────────────┘ └───────────────────────┘ └────────────┘ │ │ │ │ │ │ identifier │ │ ▼ │ │ ┌────────────┐ │ │ │ 100040 │ │ │ │ (VNI) │ │ │ └────────────┘ │ │ │ │ ┌────────────┐ ┌───────────────────┐ │ │ │ VRF │─────│ Route Target │ │ │ │ (gold) │ │ (1:100001) │ │ │ │ cf:l3vni │ └───────────────────┘ │ │ └────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` --- ## API Filter Compatibility Notes ### Working Filters (NetBox 4.4) | Endpoint | Filter | Example | |----------|--------|---------| | `/api/dcim/devices/` | `role`, `name`, `site` | `?role=leaf` | | `/api/dcim/interfaces/` | `device`, `type`, `name` | `?device=leaf1&type=virtual` | | `/api/ipam/ip-addresses/` | `device`, `interface`, `vrf` | `?device=leaf1&vrf=gold` | | `/api/ipam/vlans/` | `vid`, `site`, `group` | `?vid=40` | | `/api/vpn/l2vpns/` | `type`, `name` | `?type=evpn` | | `/api/vpn/l2vpn-terminations/` | `l2vpn`, `vlan_id` | `?l2vpn=VLAN40-L2VNI` | | `/api/plugins/bgp/sessions/` | `device`, `peer_group` | `?device=leaf1` | ### Non-Working Filters (Require Workarounds) | Endpoint | Invalid Filter | Workaround | |----------|----------------|------------| | `/api/ipam/asns/` | `device` | Use custom field `asn` on Device | | `/api/vpn/l2vpn-terminations/` | `device` | Filter by `vlan_id` then correlate | | `/api/dcim/interfaces/` | `vrf` | Query IPs with VRF filter, get interface IDs | --- ## Next Steps 1. **Custom Fields Setup** - Create all custom fields listed above in NetBox 2. **Data Population** - Enter fabric topology data into NetBox 3. **NetBox Client** - Update `src/netbox/client.py` to use custom fields 4. **Validation** - Verify data retrieval matches expected fabric config