docs: add cabling section for fabric topology
- Document NetBox Cable model usage - Add complete spine-leaf cabling matrix - Add MLAG peer-link cabling - Add host dual-homing connections - Include pynetbox examples for cable retrieval - Reference arista-evpn-vxlan-clab topology Relates to #5
This commit is contained in:
@@ -11,6 +11,14 @@ The fabric-orchestrator uses NetBox as the **source of truth** for EVPN-VXLAN fa
|
|||||||
- NetBox 4.4.x
|
- NetBox 4.4.x
|
||||||
- NetBox BGP Plugin v0.17.x
|
- NetBox BGP Plugin v0.17.x
|
||||||
|
|
||||||
|
### Reference Topology
|
||||||
|
|
||||||
|
This data model represents the fabric defined in [arista-evpn-vxlan-clab](https://gitea.arnodo.fr/Damien/arista-evpn-vxlan-clab):
|
||||||
|
|
||||||
|
- 2 Spine switches (spine1, spine2)
|
||||||
|
- 8 Leaf switches in 4 MLAG pairs (leaf1-2, leaf3-4, leaf5-6, leaf7-8)
|
||||||
|
- 4 Hosts dual-homed to MLAG pairs
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Data Model Summary
|
## Data Model Summary
|
||||||
@@ -22,6 +30,7 @@ The fabric-orchestrator uses NetBox as the **source of truth** for EVPN-VXLAN fa
|
|||||||
| **Devices** | `dcim.Device` | `/api/dcim/devices/` |
|
| **Devices** | `dcim.Device` | `/api/dcim/devices/` |
|
||||||
| **Interfaces** | `dcim.Interface` | `/api/dcim/interfaces/` |
|
| **Interfaces** | `dcim.Interface` | `/api/dcim/interfaces/` |
|
||||||
| **LAGs/Port-Channels** | `dcim.Interface` (type=LAG) | `/api/dcim/interfaces/` |
|
| **LAGs/Port-Channels** | `dcim.Interface` (type=LAG) | `/api/dcim/interfaces/` |
|
||||||
|
| **Cables** | `dcim.Cable` | `/api/dcim/cables/` |
|
||||||
| **VLANs** | `ipam.VLAN` | `/api/ipam/vlans/` |
|
| **VLANs** | `ipam.VLAN` | `/api/ipam/vlans/` |
|
||||||
| **VLAN Groups** | `ipam.VLANGroup` | `/api/ipam/vlan-groups/` |
|
| **VLAN Groups** | `ipam.VLANGroup` | `/api/ipam/vlan-groups/` |
|
||||||
| **VRFs** | `ipam.VRF` | `/api/ipam/vrfs/` |
|
| **VRFs** | `ipam.VRF` | `/api/ipam/vrfs/` |
|
||||||
@@ -152,6 +161,138 @@ Based on the reference topology:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Cabling
|
||||||
|
|
||||||
|
NetBox's native `dcim.Cable` model represents physical connections between devices. This enables topology visualization (via plugins like `netbox-topology-views`) and validation of the fabric infrastructure.
|
||||||
|
|
||||||
|
### Cable Model
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `a_terminations` | Source interface(s) |
|
||||||
|
| `b_terminations` | Destination interface(s) |
|
||||||
|
| `type` | Cable type (e.g., `cat6a`, `mmf-om4`, `dac-passive`) |
|
||||||
|
| `status` | `connected`, `planned`, `decommissioning` |
|
||||||
|
| `label` | Optional identifier |
|
||||||
|
| `length` | Cable length (with unit) |
|
||||||
|
|
||||||
|
### Spine-Leaf Cabling Matrix
|
||||||
|
|
||||||
|
Based on the [arista-evpn-vxlan-clab](https://gitea.arnodo.fr/Damien/arista-evpn-vxlan-clab) topology:
|
||||||
|
|
||||||
|
#### Spine1 to Leafs
|
||||||
|
|
||||||
|
| Spine1 Interface | Leaf | Leaf Interface | Description |
|
||||||
|
|------------------|------|----------------|-------------|
|
||||||
|
| Ethernet1 | leaf1 | Ethernet11 | Underlay uplink |
|
||||||
|
| Ethernet2 | leaf2 | Ethernet11 | Underlay uplink |
|
||||||
|
| Ethernet3 | leaf3 | Ethernet11 | Underlay uplink |
|
||||||
|
| Ethernet4 | leaf4 | Ethernet11 | Underlay uplink |
|
||||||
|
| Ethernet5 | leaf5 | Ethernet11 | Underlay uplink |
|
||||||
|
| Ethernet6 | leaf6 | Ethernet11 | Underlay uplink |
|
||||||
|
| Ethernet7 | leaf7 | Ethernet11 | Underlay uplink |
|
||||||
|
| Ethernet8 | leaf8 | Ethernet11 | Underlay uplink |
|
||||||
|
|
||||||
|
#### Spine2 to Leafs
|
||||||
|
|
||||||
|
| Spine2 Interface | Leaf | Leaf Interface | Description |
|
||||||
|
|------------------|------|----------------|-------------|
|
||||||
|
| Ethernet1 | leaf1 | Ethernet12 | Underlay uplink |
|
||||||
|
| Ethernet2 | leaf2 | Ethernet12 | Underlay uplink |
|
||||||
|
| Ethernet3 | leaf3 | Ethernet12 | Underlay uplink |
|
||||||
|
| Ethernet4 | leaf4 | Ethernet12 | Underlay uplink |
|
||||||
|
| Ethernet5 | leaf5 | Ethernet12 | Underlay uplink |
|
||||||
|
| Ethernet6 | leaf6 | Ethernet12 | Underlay uplink |
|
||||||
|
| Ethernet7 | leaf7 | Ethernet12 | Underlay uplink |
|
||||||
|
| Ethernet8 | leaf8 | Ethernet12 | Underlay uplink |
|
||||||
|
|
||||||
|
### MLAG Peer-Link Cabling
|
||||||
|
|
||||||
|
Each MLAG pair has a dedicated peer-link connection:
|
||||||
|
|
||||||
|
| MLAG Pair | Device A | Interface A | Device B | Interface B | Description |
|
||||||
|
|-----------|----------|-------------|----------|-------------|-------------|
|
||||||
|
| VTEP1 | leaf1 | Ethernet10 | leaf2 | Ethernet10 | MLAG peer-link |
|
||||||
|
| VTEP2 | leaf3 | Ethernet10 | leaf4 | Ethernet10 | MLAG peer-link |
|
||||||
|
| VTEP3 | leaf5 | Ethernet10 | leaf6 | Ethernet10 | MLAG peer-link |
|
||||||
|
| VTEP4 | leaf7 | Ethernet10 | leaf8 | Ethernet10 | MLAG peer-link |
|
||||||
|
|
||||||
|
> Note: In production, peer-links typically use multiple interfaces in a Port-Channel for redundancy (e.g., Ethernet10 + Ethernet13 → Port-Channel10).
|
||||||
|
|
||||||
|
### Host Dual-Homing Cabling
|
||||||
|
|
||||||
|
Hosts are dual-homed to MLAG pairs using LACP bonding:
|
||||||
|
|
||||||
|
| Host | Leaf A | Leaf A Interface | Leaf B | Leaf B Interface | MLAG ID |
|
||||||
|
|------|--------|------------------|--------|------------------|---------|
|
||||||
|
| host1 | leaf1 | Ethernet1 | leaf2 | Ethernet1 | 1 |
|
||||||
|
| host2 | leaf3 | Ethernet1 | leaf4 | Ethernet1 | 1 |
|
||||||
|
| host3 | leaf5 | Ethernet1 | leaf6 | Ethernet1 | 1 |
|
||||||
|
| host4 | leaf7 | Ethernet1 | leaf8 | Ethernet1 | 1 |
|
||||||
|
|
||||||
|
### Cabling Conventions
|
||||||
|
|
||||||
|
| Interface Range | Purpose |
|
||||||
|
|-----------------|---------|
|
||||||
|
| Ethernet1-9 | Host-facing (downlinks) |
|
||||||
|
| Ethernet10 | MLAG peer-link |
|
||||||
|
| Ethernet11-12 | Spine uplinks |
|
||||||
|
|
||||||
|
### Cable Retrieval via API
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pynetbox
|
||||||
|
|
||||||
|
nb = pynetbox.api('http://netbox.example.com', token='your-token')
|
||||||
|
|
||||||
|
# Get all cables for a device
|
||||||
|
cables = nb.dcim.cables.filter(device='leaf1')
|
||||||
|
for cable in cables:
|
||||||
|
a_term = cable.a_terminations[0]
|
||||||
|
b_term = cable.b_terminations[0]
|
||||||
|
print(f"{a_term.device.name}:{a_term.name} <-> {b_term.device.name}:{b_term.name}")
|
||||||
|
|
||||||
|
# Get spine-leaf cables only
|
||||||
|
spine_cables = nb.dcim.cables.filter(device='spine1')
|
||||||
|
|
||||||
|
# Get peer-link cables (filter by interface name pattern)
|
||||||
|
leaf1_interfaces = nb.dcim.interfaces.filter(device='leaf1', name='Ethernet10')
|
||||||
|
for iface in leaf1_interfaces:
|
||||||
|
if iface.cable:
|
||||||
|
cable = nb.dcim.cables.get(iface.cable.id)
|
||||||
|
print(f"Peer-link: {cable}")
|
||||||
|
|
||||||
|
# Validate expected connections
|
||||||
|
def validate_spine_leaf_cabling(nb, spine_name, expected_leafs):
|
||||||
|
"""Validate that spine has cables to all expected leafs."""
|
||||||
|
cables = nb.dcim.cables.filter(device=spine_name)
|
||||||
|
connected_devices = set()
|
||||||
|
for cable in cables:
|
||||||
|
for term in cable.b_terminations:
|
||||||
|
connected_devices.add(term.device.name)
|
||||||
|
|
||||||
|
missing = set(expected_leafs) - connected_devices
|
||||||
|
if missing:
|
||||||
|
print(f"WARNING: {spine_name} missing connections to: {missing}")
|
||||||
|
return len(missing) == 0
|
||||||
|
|
||||||
|
# Example validation
|
||||||
|
validate_spine_leaf_cabling(nb, 'spine1',
|
||||||
|
['leaf1', 'leaf2', 'leaf3', 'leaf4', 'leaf5', 'leaf6', 'leaf7', 'leaf8'])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Topology Visualization
|
||||||
|
|
||||||
|
With cables properly defined, the `netbox-topology-views` plugin can automatically generate fabric diagrams. The plugin uses cable data to draw connections between devices.
|
||||||
|
|
||||||
|
Key benefits:
|
||||||
|
- **Auto-generated diagrams**: No manual drawing required
|
||||||
|
- **Real-time updates**: Topology reflects current NetBox data
|
||||||
|
- **Drill-down**: Click devices/cables for details
|
||||||
|
- **Export**: SVG/PNG export for documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## BGP Configuration
|
## BGP Configuration
|
||||||
|
|
||||||
### ASN Assignments
|
### ASN Assignments
|
||||||
@@ -258,7 +399,7 @@ MLAG configuration uses Custom Fields since NetBox doesn't have native MLAG supp
|
|||||||
### VRF Definition
|
### VRF Definition
|
||||||
|
|
||||||
| VRF Name | RD | Import RT | Export RT | L3 VNI (custom field) |
|
| 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
|
||||||
@@ -313,48 +454,48 @@ l3vni = vrf.custom_fields.get('l3vni')
|
|||||||
## 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 │ │
|
│ │ cf:asn │ │ cf:mlag_peer_ │ │ cf:virtual_ip │ │
|
||||||
│ └────────────┘ │ link │ └───────────────┘ │
|
│ └────────────┘ │ link │ └───────────────┘ │
|
||||||
│ │ └────────────────┘ │
|
│ │ └────────────────┘ │
|
||||||
│ │ │
|
│ │ │ │
|
||||||
│ │ custom_fields │
|
│ │ custom_fields │ │
|
||||||
│ ▼ │
|
│ ▼ ▼ │
|
||||||
│ ┌────────────┐ │
|
│ ┌────────────┐ ┌────────────────┐ │
|
||||||
│ │ cf:asn │ │
|
│ │ cf:asn │ │ Cable │ │
|
||||||
│ │ (65001) │ │
|
│ │ (65001) │ │ (connections) │ │
|
||||||
│ └────────────┘ │
|
│ └────────────┘ └────────────────┘ │
|
||||||
│ │
|
│ │
|
||||||
│ ┌──────────────────┐ ┌───────────────────┐ │
|
│ ┌──────────────────┐ ┌───────────────────┐ │
|
||||||
│ │ BGP Session │─────│ Peer Group │ │
|
│ │ BGP Session │─────│ Peer Group │ │
|
||||||
│ │ (plugin) │ │ (plugin) │ │
|
│ │ (plugin) │ │ (plugin) │ │
|
||||||
│ └──────────────────┘ └───────────────────┘ │
|
│ └──────────────────┘ └───────────────────┘ │
|
||||||
│ │
|
│ │
|
||||||
│ ┌────────────┐ ┌───────────────────────┐ ┌────────────┐ │
|
│ ┌────────────┐ ┌───────────────────────┐ ┌────────────┐ │
|
||||||
│ │ VLAN │─────│ L2VPN Termination │─────│ L2VPN │ │
|
│ │ VLAN │─────│ L2VPN Termination │─────│ L2VPN │ │
|
||||||
│ │ (40) │ │ │ │ (EVPN) │ │
|
│ │ (40) │ │ │ │ (EVPN) │ │
|
||||||
│ └────────────┘ └───────────────────────┘ └────────────┘ │
|
│ └────────────┘ └───────────────────────┘ └────────────┘ │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ │ identifier │
|
│ │ identifier │
|
||||||
│ ▼ │
|
│ ▼ │
|
||||||
│ ┌────────────┐ │
|
│ ┌────────────┐ │
|
||||||
│ │ 100040 │ │
|
│ │ 100040 │ │
|
||||||
│ │ (VNI) │ │
|
│ │ (VNI) │ │
|
||||||
│ └────────────┘ │
|
│ └────────────┘ │
|
||||||
│ │
|
│ │
|
||||||
│ ┌────────────┐ ┌───────────────────┐ │
|
│ ┌────────────┐ ┌───────────────────┐ │
|
||||||
│ │ VRF │─────│ Route Target │ │
|
│ │ VRF │─────│ Route Target │ │
|
||||||
│ │ (gold) │ │ (1:100001) │ │
|
│ │ (gold) │ │ (1:100001) │ │
|
||||||
│ │ cf:l3vni │ └───────────────────┘ │
|
│ │ cf:l3vni │ └───────────────────┘ │
|
||||||
│ └────────────┘ │
|
│ └────────────┘ │
|
||||||
│ │
|
│ │
|
||||||
└─────────────────────────────────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -367,6 +508,7 @@ l3vni = vrf.custom_fields.get('l3vni')
|
|||||||
|----------|--------|---------|
|
|----------|--------|---------|
|
||||||
| `/api/dcim/devices/` | `role`, `name`, `site` | `?role=leaf` |
|
| `/api/dcim/devices/` | `role`, `name`, `site` | `?role=leaf` |
|
||||||
| `/api/dcim/interfaces/` | `device`, `type`, `name` | `?device=leaf1&type=virtual` |
|
| `/api/dcim/interfaces/` | `device`, `type`, `name` | `?device=leaf1&type=virtual` |
|
||||||
|
| `/api/dcim/cables/` | `device`, `site`, `rack` | `?device=leaf1` |
|
||||||
| `/api/ipam/ip-addresses/` | `device`, `interface`, `vrf` | `?device=leaf1&vrf=gold` |
|
| `/api/ipam/ip-addresses/` | `device`, `interface`, `vrf` | `?device=leaf1&vrf=gold` |
|
||||||
| `/api/ipam/vlans/` | `vid`, `site`, `group` | `?vid=40` |
|
| `/api/ipam/vlans/` | `vid`, `site`, `group` | `?vid=40` |
|
||||||
| `/api/vpn/l2vpns/` | `type`, `name` | `?type=evpn` |
|
| `/api/vpn/l2vpns/` | `type`, `name` | `?type=evpn` |
|
||||||
@@ -386,6 +528,7 @@ l3vni = vrf.custom_fields.get('l3vni')
|
|||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
1. **Custom Fields Setup** - Create all custom fields listed above in NetBox
|
1. **Custom Fields Setup** - Create all custom fields listed above in NetBox
|
||||||
2. **Data Population** - Enter fabric topology data into NetBox
|
2. **Cabling Setup** - Create cables for spine-leaf, peer-links, and host connections
|
||||||
3. **NetBox Client** - Update `src/netbox/client.py` to use custom fields
|
3. **Data Population** - Enter fabric topology data into NetBox
|
||||||
4. **Validation** - Verify data retrieval matches expected fabric config
|
4. **NetBox Client** - Update `src/netbox/client.py` to use custom fields and cables
|
||||||
|
5. **Validation** - Verify data retrieval matches expected fabric config
|
||||||
|
|||||||
Reference in New Issue
Block a user