diff --git a/docs/netbox-data-model.md b/docs/netbox-data-model.md index 199c23a..20c08b5 100644 --- a/docs/netbox-data-model.md +++ b/docs/netbox-data-model.md @@ -45,6 +45,74 @@ The fabric-orchestrator uses NetBox as the **source of truth** for EVPN-VXLAN fa --- +## 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 @@ -88,13 +156,13 @@ Based on the reference topology: ### ASN Assignments -| Device(s) | ASN | Type | -|-----------|-----|------| -| spine1, spine2 | 65000 | eBGP | -| leaf1, leaf2 | 65001 | iBGP pair | -| leaf3, leaf4 | 65002 | iBGP pair | -| leaf5, leaf6 | 65003 | iBGP pair | -| leaf7, leaf8 | 65004 | iBGP pair | +| 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) @@ -167,17 +235,7 @@ Link VLANs to L2VPNs on specific devices: ## MLAG Configuration -MLAG configuration requires Custom Fields since NetBox doesn't have native MLAG support. - -### Custom Fields Required - -| Field Name | Object Type | Type | Description | -|------------|-------------|------|-------------| -| `mlag_domain_id` | Device | Text | MLAG domain identifier | -| `mlag_peer_address` | Device | Text (IP) | MLAG peer IP address | -| `mlag_local_address` | Device | Text (IP) | MLAG local IP address | -| `mlag_peer_link` | Interface | Boolean | Marks interface as MLAG peer-link | -| `mlag_virtual_mac` | Device | Text | Shared virtual-router MAC | +MLAG configuration uses Custom Fields since NetBox doesn't have native MLAG support. ### MLAG Pair Configuration @@ -199,22 +257,24 @@ MLAG configuration requires Custom Fields since NetBox doesn't have native MLAG ### VRF Definition -| VRF Name | RD | Import RT | Export RT | L3 VNI | -|----------|-------|-----------|-----------|--------| +| 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: +SVIs are assigned to VRFs in NetBox. VRF membership is tracked via IP addresses assigned to interfaces: -| Interface | VRF | IP Address | Virtual IP | -|-----------|-----|------------|------------| -| Vlan34 (leaf3) | gold | 10.34.34.2/24 | 10.34.34.1 | -| Vlan34 (leaf4) | gold | 10.34.34.3/24 | 10.34.34.1 | -| Vlan78 (leaf7) | gold | 10.78.78.2/24 | 10.78.78.1 | -| Vlan78 (leaf8) | gold | 10.78.78.3/24 | 10.78.78.1 | +| 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) | --- @@ -230,6 +290,10 @@ 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') @@ -238,6 +302,10 @@ 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') ``` --- @@ -245,51 +313,79 @@ terminations = nb.vpn.l2vpn_terminations.filter(l2vpn='VLAN40-L2VNI') ## Relationship Diagram ``` -┌─────────────────────────────────────────────────────────────────┐ -│ NetBox │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌──────────┐ ┌──────────────┐ ┌─────────────┐ │ -│ │ Device │────▶│ Interface │────▶│ IP Address │ │ -│ │ (leaf1) │ │ (Loopback0) │ │(10.0.250.11)│ │ -│ └──────────┘ └──────────────┘ └─────────────┘ │ -│ │ │ -│ │ ASN assignment │ -│ ▼ │ -│ ┌──────────┐ │ -│ │ ASN │ │ -│ │ (65001) │ │ -│ └──────────┘ │ -│ │ -│ ┌──────────────┐ ┌─────────────────┐ │ -│ │ BGP Session │────▶│ Peer Group │ │ -│ │ (plugin) │ │ (plugin) │ │ -│ └──────────────┘ └─────────────────┘ │ -│ │ -│ ┌──────────┐ ┌─────────────────────┐ ┌──────────┐ │ -│ │ VLAN │────▶│ L2VPN Termination │────▶│ L2VPN │ │ -│ │ (40) │ │ │ │ (EVPN) │ │ -│ └──────────┘ └─────────────────────┘ └──────────┘ │ -│ │ │ -│ │ VNI │ -│ ▼ │ -│ ┌──────────┐ │ -│ │ 100040 │ │ -│ └──────────┘ │ -│ │ -│ ┌──────────┐ ┌─────────────────┐ │ -│ │ VRF │────▶│ Route Target │ │ -│ │ (gold) │ │ (1:100001) │ │ -│ └──────────┘ └─────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────┘ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ 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 MLAG-related custom fields in NetBox +1. **Custom Fields Setup** - Create all custom fields listed above in NetBox 2. **Data Population** - Enter fabric topology data into NetBox -3. **NetBox Client** - Implement `src/netbox/client.py` using pynetbox +3. **NetBox Client** - Update `src/netbox/client.py` to use custom fields 4. **Validation** - Verify data retrieval matches expected fabric config