docs: add complete custom fields reference and API compatibility notes
- Add comprehensive custom fields table for Device, Interface, VRF, and IP Address - Include API examples for custom field creation - Document working vs non-working API filters for NetBox 4.4 - Add workarounds for filters that don't exist (ASN by device, L2VPN terminations by device) - Update VRF interface assignment to show IP-based VRF membership - Add virtual_ip custom field for anycast gateway support
This commit is contained in:
@@ -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
|
## Fabric Component Mapping
|
||||||
|
|
||||||
### Devices and Roles
|
### Devices and Roles
|
||||||
@@ -88,13 +156,13 @@ Based on the reference topology:
|
|||||||
|
|
||||||
### ASN Assignments
|
### ASN Assignments
|
||||||
|
|
||||||
| Device(s) | ASN | Type |
|
| Device(s) | ASN | Type | Custom Field |
|
||||||
|-----------|-----|------|
|
|-----------|-----|------|--------------|
|
||||||
| spine1, spine2 | 65000 | eBGP |
|
| spine1, spine2 | 65000 | eBGP | `asn: 65000` |
|
||||||
| leaf1, leaf2 | 65001 | iBGP pair |
|
| leaf1, leaf2 | 65001 | iBGP pair | `asn: 65001` |
|
||||||
| leaf3, leaf4 | 65002 | iBGP pair |
|
| leaf3, leaf4 | 65002 | iBGP pair | `asn: 65002` |
|
||||||
| leaf5, leaf6 | 65003 | iBGP pair |
|
| leaf5, leaf6 | 65003 | iBGP pair | `asn: 65003` |
|
||||||
| leaf7, leaf8 | 65004 | iBGP pair |
|
| leaf7, leaf8 | 65004 | iBGP pair | `asn: 65004` |
|
||||||
|
|
||||||
### BGP Sessions (Plugin)
|
### BGP Sessions (Plugin)
|
||||||
|
|
||||||
@@ -167,17 +235,7 @@ Link VLANs to L2VPNs on specific devices:
|
|||||||
|
|
||||||
## MLAG Configuration
|
## MLAG Configuration
|
||||||
|
|
||||||
MLAG configuration requires Custom Fields since NetBox doesn't have native MLAG support.
|
MLAG configuration uses 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 Pair Configuration
|
### MLAG Pair Configuration
|
||||||
|
|
||||||
@@ -199,22 +257,24 @@ MLAG configuration requires Custom Fields since NetBox doesn't have native MLAG
|
|||||||
|
|
||||||
### VRF Definition
|
### 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 |
|
| gold | `10.0.250.X:1` | `1:100001` | `1:100001` | 100001 |
|
||||||
|
|
||||||
> Note: RD uses device's Loopback0 IP for uniqueness
|
> Note: RD uses device's Loopback0 IP for uniqueness
|
||||||
|
|
||||||
### VRF Interface Assignment
|
### 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 |
|
| Interface | VRF | IP Address | Virtual IP (custom field) |
|
||||||
|-----------|-----|------------|------------|
|
|-----------|-----|------------|---------------------------|
|
||||||
| Vlan34 (leaf3) | gold | 10.34.34.2/24 | 10.34.34.1 |
|
| Vlan34 (leaf3) | gold | 10.34.34.2/24 | No |
|
||||||
| Vlan34 (leaf4) | gold | 10.34.34.3/24 | 10.34.34.1 |
|
| Vlan34 (leaf4) | gold | 10.34.34.3/24 | No |
|
||||||
| Vlan78 (leaf7) | gold | 10.78.78.2/24 | 10.78.78.1 |
|
| Vlan34 (leaf3) | gold | 10.34.34.1/24 | Yes (anycast) |
|
||||||
| Vlan78 (leaf8) | gold | 10.78.78.3/24 | 10.78.78.1 |
|
| 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
|
# Get all leaf devices
|
||||||
leaves = nb.dcim.devices.filter(role='leaf')
|
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
|
# Get BGP sessions for a device
|
||||||
bgp_sessions = nb.plugins.bgp.sessions.filter(device='leaf1')
|
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
|
# Get VLAN-to-VNI mappings via L2VPN terminations
|
||||||
terminations = nb.vpn.l2vpn_terminations.filter(l2vpn='VLAN40-L2VNI')
|
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
|
## Relationship Diagram
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ NetBox │
|
│ NetBox │
|
||||||
├─────────────────────────────────────────────────────────────────┤
|
├─────────────────────────────────────────────────────────────────────────────┤
|
||||||
│ │
|
│ │
|
||||||
│ ┌──────────┐ ┌──────────────┐ ┌─────────────┐ │
|
│ ┌────────────┐ ┌────────────────┐ ┌───────────────┐ │
|
||||||
│ │ Device │────▶│ Interface │────▶│ IP Address │ │
|
│ │ Device │─────│ Interface │─────│ IP Address │ │
|
||||||
│ │ (leaf1) │ │ (Loopback0) │ │(10.0.250.11)│ │
|
│ │ (leaf1) │ │ (Loopback0) │ │(10.0.250.11) │ │
|
||||||
│ └──────────┘ └──────────────┘ └─────────────┘ │
|
│ │ cf:asn │ │ cf:mlag_peer_ │ │ cf:virtual_ip │ │
|
||||||
|
│ └────────────┘ │ link │ └───────────────┘ │
|
||||||
|
│ │ └────────────────┘ │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ │ ASN assignment │
|
│ │ custom_fields │
|
||||||
│ ▼ │
|
│ ▼ │
|
||||||
│ ┌──────────┐ │
|
│ ┌────────────┐ │
|
||||||
│ │ ASN │ │
|
│ │ cf:asn │ │
|
||||||
│ │ (65001) │ │
|
│ │ (65001) │ │
|
||||||
│ └──────────┘ │
|
│ └────────────┘ │
|
||||||
│ │
|
│ │
|
||||||
│ ┌──────────────┐ ┌─────────────────┐ │
|
│ ┌──────────────────┐ ┌───────────────────┐ │
|
||||||
│ │ BGP Session │────▶│ Peer Group │ │
|
│ │ BGP Session │─────│ Peer Group │ │
|
||||||
│ │ (plugin) │ │ (plugin) │ │
|
│ │ (plugin) │ │ (plugin) │ │
|
||||||
│ └──────────────┘ └─────────────────┘ │
|
│ └──────────────────┘ └───────────────────┘ │
|
||||||
│ │
|
│ │
|
||||||
│ ┌──────────┐ ┌─────────────────────┐ ┌──────────┐ │
|
│ ┌────────────┐ ┌───────────────────────┐ ┌────────────┐ │
|
||||||
│ │ VLAN │────▶│ L2VPN Termination │────▶│ L2VPN │ │
|
│ │ VLAN │─────│ L2VPN Termination │─────│ L2VPN │ │
|
||||||
│ │ (40) │ │ │ │ (EVPN) │ │
|
│ │ (40) │ │ │ │ (EVPN) │ │
|
||||||
│ └──────────┘ └─────────────────────┘ └──────────┘ │
|
│ └────────────┘ └───────────────────────┘ └────────────┘ │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ │ VNI │
|
│ │ identifier │
|
||||||
│ ▼ │
|
│ ▼ │
|
||||||
│ ┌──────────┐ │
|
│ ┌────────────┐ │
|
||||||
│ │ 100040 │ │
|
│ │ 100040 │ │
|
||||||
│ └──────────┘ │
|
│ │ (VNI) │ │
|
||||||
|
│ └────────────┘ │
|
||||||
│ │
|
│ │
|
||||||
│ ┌──────────┐ ┌─────────────────┐ │
|
│ ┌────────────┐ ┌───────────────────┐ │
|
||||||
│ │ VRF │────▶│ Route Target │ │
|
│ │ VRF │─────│ Route Target │ │
|
||||||
│ │ (gold) │ │ (1:100001) │ │
|
│ │ (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
|
## 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
|
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
|
4. **Validation** - Verify data retrieval matches expected fabric config
|
||||||
|
|||||||
Reference in New Issue
Block a user