Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions docs/backends/device_discovery/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The device discovery backend uses [Diode Python SDK](https://github.com/netboxla
* [IP Address](https://github.com/netboxlabs/diode-sdk-python/blob/develop/docs/examples/ip_address.py)
* [Prefix](https://github.com/netboxlabs/diode-sdk-python/blob/develop/docs/examples/prefix.py)
* [VLAN](https://github.com/netboxlabs/diode-sdk-python/blob/develop/docs/examples/vlan.py)
* [VRF](https://github.com/netboxlabs/diode-sdk-python/blob/develop/docs/examples/vrf.py)
* [VirtualChassis](https://github.com/netboxlabs/diode-sdk-python/blob/develop/docs/examples/virtual_chassis_example.py)
* [Module](https://github.com/netboxlabs/diode-sdk-python/blob/develop/docs/examples/module.py)
* [ModuleBay](https://github.com/netboxlabs/diode-sdk-python/blob/develop/docs/examples/module_bay.py)
Expand All @@ -26,6 +27,8 @@ When a target is a switch stack / Virtual Chassis (NetBox `VirtualChassis`), dev

When a target is a modular chassis and the `discover_modules` policy option is enabled, device-discovery additionally emits `Module` and `ModuleBay` entities for each chassis slot (and, in `full` mode, each transceiver sub-bay) — see [Modules / ModuleBays](#modules--modulebays) below. Defaults to `off`, so existing operators see zero behaviour change.

When the `discover_vrfs` policy option is enabled, device-discovery emits a `VRF` entity for each VRF configured on the device and attaches it to the IP addresses and prefixes of the interfaces inside that VRF — see [VRFs](#vrfs) below. Defaults to `false`, so existing operators see zero behaviour change.

## Configuration
The `device_discovery` backend does not require any special configuration, though overriding `host` and `port` values can be specified. The backend will use the `diode` settings specified in the `common` subsection to forward discovery results.

Expand Down Expand Up @@ -71,6 +74,7 @@ Current supported options:
| create_unknown_vlans | bool | When discovering interface↔VLAN associations, auto-emit a VLAN entity for any VID referenced on an interface but absent from the device's VLAN database. Stubs inherit attributes from `defaults.vlan` for stable matching. Defaults to `True`. Set `False` to drop unknown VIDs from interface associations entirely (requires every referenced VLAN to already exist in NetBox). Only drivers that implement `get_interfaces_vlans()` populate these associations — see the [supported platforms page](./supported_platforms.md). |
| discover_modules | str | Controls emission of `Module` / `ModuleBay` entities on modular chassis. One of `off` (default — no modules emitted, zero behaviour change), `linecards` (one Module per chassis slot — line cards, supervisors, etc. — transceiver sub-bays skipped), or `full` (linecards plus one Module per transceiver sub-bay; interfaces carry a `module=` ref to the transceiver they're connected to). Only drivers that implement `get_modules()` populate module data — see the [supported platforms page](./supported_platforms.md#modules--modulebays). See [Modules / ModuleBays](#modules--modulebays) for the emission shape and current sub-bay rendering trade-off. |
| propagate_defaults_to_prefix_scope | bool | When `True` AND no explicit `defaults.prefix.scope_*` is set, `defaults.site` cascades to `Prefix.scope_site` (the literal placeholder `"undefined"` is skipped) and `defaults.location` cascades to `Prefix.scope_location`. Defaults to `False`. Setting any explicit `defaults.prefix.scope_*` puts the operator in "explicit mode" and the cascade is skipped wholesale. |
| discover_vrfs | bool | When `True`, discovers VRFs from the device via the driver's `get_network_instances()` and attaches each VRF to the IP addresses and prefixes of its member interfaces. A discovered VRF takes precedence over the `defaults.*.vrf` / `vrf_ipv4` / `vrf_ipv6` settings for those interfaces; interfaces in the default routing table keep the configured defaults. Defaults to `False`. Only drivers that implement `get_network_instances()` populate VRF data — see the [supported platforms page](./supported_platforms.md#vrfs). See [VRFs](#vrfs) for filtering rules and route-distinguisher handling. |

#### Defaults
Current supported defaults:
Expand Down Expand Up @@ -341,6 +345,24 @@ When a driver implements module discovery and the `discover_modules` policy opti

**Supported drivers.** Module discovery is opt-in per driver (analogous to interface↔VLAN associations and stack discovery). See the [supported platforms page](./supported_platforms.md#modules--modulebays) for the current list; vendors land as follow-up PRs as the underlying drivers gain module-discovery support.

## VRFs

When the `discover_vrfs` policy option is enabled (defaults to `false`), device-discovery calls the driver's standard NAPALM `get_network_instances()` getter and emits a NetBox `VRF` entity per VRF configured on the device. Each discovered VRF is attached to the `IPAddress` and `Prefix` entities of the interfaces inside that VRF; interfaces in the default routing table carry no discovered VRF and keep whatever `defaults.*.vrf` configuration is in effect.

**Precedence.** Device state beats policy defaults: for an interface inside a discovered VRF, the discovered VRF wins over `defaults.ipaddress.vrf` / `vrf_ipv4` / `vrf_ipv6` (and the `defaults.prefix` equivalents). The defaults remain the fallback for all other interfaces, so mixed configurations work as expected.

**Filtering.** Not every network instance a device reports is an operator-meaningful VRF. The following are skipped:

* the default instance (the global routing table),
* L2 instance types (VPLS / EVPN / L2VPN instances — these have no NetBox VRF equivalent),
* platform-internal instances whose names start with `__` (e.g. Cisco's `__Platform_iVRF:_ID00_`).

Management VRFs (e.g. Cisco `Mgmt-vrf`, Junos `mgmt_junos`) are real VRFs and are kept.

**Route distinguisher.** The `rd` field is set only when the device reports a real value. Devices without MPLS routinely report an empty or placeholder RD — those stay off the wire, so the VRF matches a NetBox VRF record whose RD is empty rather than creating one with a bogus RD. Note the Diode reconciliation caveat: an ingested VRF without an RD only matches NetBox VRFs whose RD is unset. If a VRF with the same name already exists in NetBox **with** an RD configured, the first discovery cycle creates a separate RD-less VRF record alongside it (subsequent cycles converge on the RD-less record). If you pre-seed VRFs in NetBox and want discovery to match them, either leave their RD unset or make sure the device reports the same RD.

**Supported drivers.** VRF discovery is available on drivers that implement `get_network_instances()` — see the [supported platforms page](./supported_platforms.md#vrfs) for the current list. On drivers without support, enabling the option logs a warning per cycle and discovery continues without VRF data.

## What NAPALM Collects Automatically

The tables below show which fields are populated automatically from the device versus which must be provided via `defaults` in the policy configuration.
Expand Down Expand Up @@ -383,7 +405,7 @@ The tables below show which fields are populated automatically from the device v
| Address (with prefix length) | `get_interfaces_ip()` | Auto-collected; IPv4 and IPv6 |
| Assigned interface | — | Automatically linked to the interface |
| Role | **Not collected** | Must be set via `defaults.ipaddress.role` |
| VRF | **Not collected** | Must be set via `defaults.ipaddress.vrf` |
| VRF | `get_network_instances()` when `options.discover_vrfs: true` | Otherwise set via `defaults.ipaddress.vrf` (a discovered VRF wins over the defaults — see [VRFs](#vrfs)) |
| Tenant | **Not collected** | Must be set via `defaults.ipaddress.tenant` |

### Prefix
Expand All @@ -393,7 +415,8 @@ Prefixes are derived from IP addresses discovered on interfaces. The network add
| Field | Source | Notes |
|-------|--------|-------|
| Prefix (network address) | Derived from IP address | Auto-computed |
| VRF / Role / Tenant | **Not collected** | Must be set via `defaults.prefix.*` |
| VRF | `get_network_instances()` when `options.discover_vrfs: true` | Otherwise set via `defaults.prefix.vrf` (a discovered VRF wins over the defaults — see [VRFs](#vrfs)) |
| Role / Tenant | **Not collected** | Must be set via `defaults.prefix.*` |
| Scope (site / location) | **Not collected** | Set via `defaults.prefix.scope_*` (see Nested Defaults) or opt into the cascade via `options.propagate_defaults_to_prefix_scope` |

Prefix scope is a `oneof` — a Prefix carries one of `scope_site` or `scope_location`. When both `defaults.prefix.scope_*` are set, the most-specific wins on the wire: `scope_location` > `scope_site`. By default `defaults.site` does NOT auto-fill `Prefix.scope_site` — set `options.propagate_defaults_to_prefix_scope: true` to enable the cascade. Any explicit `defaults.prefix.scope_*` puts the operator in "explicit mode" and the cascade is skipped wholesale, so a cascaded more-specific scope can't override an operator's explicit less-specific choice. Clearing an existing scope requires editing NetBox directly.
Expand Down
34 changes: 34 additions & 0 deletions docs/backends/device_discovery/supported_platforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,40 @@ Drivers that implement `get_modules()` discover the per-slot module inventory on

**Extreme EXOS (`extreme_exos`).** Module discovery is scoped to the BlackDiamond X8 modular chassis. Other EXOS hardware in the field — the X670 / X870 fixed pizza-boxes, the BD-X8-X32 stackable variant — share the `X8` family token in their model strings but are not modular and must not produce module entries. Family detection scans the **full `show version` output** (not just `System Type:`, which Extreme's command-reference BD-X8 example omits in favour of `Switch :` / `Chassis :` / `Slot-*` / `FM-*` lines) using a regex with a negative-lookahead anchor (`(?:BD-|BLACKDIAMOND\s+)X8(?![-\w])`) rather than a Python `\b` word-boundary, because `\b` fires between the digit `8` and the dash in `BD-X8-32` and would accept the wrong model. For BD-X8 chassis the driver parses `show slot detail` directly — no `extreme_exos_show_slot_detail` ntc-template exists, so a block-per-slot regex walks each `Slot-N information:` / `MSM-A information:` / `FM-1 information:` block (case-insensitive) and extracts the `Hw Module Type` and `Serial number` fields. The serial capture is whitespace-tolerant: real BD-X8 prints two whitespace-separated tokens (`Serial number: 800432-00-09 1534G-01368` — part-number plus unique serial), and the parser collapses internal whitespace runs to a single space so the persisted value is stable. The classifier maps `BDX-MM` (Management Module) to `supervisor` and the I/O / Fabric Module families (`BDXA-FM` / `BDXA-` / `BDXB-`) to `linecard`; Fabric Modules emit as `linecard` because NetBox has no fabric module type today. Any hypothetical `BDXB-FM*` SKU still classifies as linecard via the generic `BDXB-` fallback. Slot header parsing tolerates both `Slot-N` and `Slot N` (space-separator) layouts that EXOS releases interchangeably emit; space variants are normalised to hyphenated bay names (`Slot 1` → `Slot-1`) so bay identifiers stay consistent across releases. Single-member envelope keyed by `None`; EXOS has no stack-of-modular dispatch in v1.

## VRFs

Drivers that implement the standard NAPALM `get_network_instances()` getter discover the VRFs configured on the device and attach them to the IP addresses and prefixes of each VRF's member interfaces. Emission is gated by the `discover_vrfs` policy option (defaults to `false`); see the [device discovery README](./README.md#vrfs) for the filtering rules, route-distinguisher handling, and precedence over the `defaults.*.vrf` settings.

| Driver | Status |
|--------|--------|
| `ios` | Supported (Cisco IOS / IOS-XE) — upstream NAPALM `get_network_instances()` (`show vrf detail` + `show ip interface brief`). |
| `eos` | Supported (Arista EOS) — upstream NAPALM `get_network_instances()`. |
| `junos` | Supported (Juniper Junos) — upstream NAPALM `get_network_instances()`; both `vrf` (L3VPN) and `virtual-router` (VRF-lite, incl. `mgmt_junos`) routing instances translate to VRFs. |
| `nxos` | Supported (Cisco NX-OS via NX-API) — upstream NAPALM `get_network_instances()` (`show vrf detail \| json` + `show vrf interface \| json`). |
| `nxos_ssh` | Supported (Cisco NX-OS via SSH) — same coverage as `nxos`. |
| `iosxr` | Supported (Cisco IOS-XR via pyIOSXR / XML-Agent over SSH) — `show vrf all detail` parsed driver-locally (the cisco_xr ntc-template FSM mis-parses VRF blocks without an address family or with import/export route policies attached, so a stuck-state-free block parser is used instead). An unconfigured RD (`not set`) is treated as absent. |
| `iosxr_netconf` | Supported (Cisco IOS-XR via NETCONF) — one subtree-filtered get on the `Cisco-IOS-XR-mpls-vpn-oper` `l3vpn/vrfs` model, the same data source the CLI command renders. Same coverage as `iosxr`. |
| `nokia_sros` | Supported (Nokia SR OS via NETCONF) — VPRN services map to VRFs (one get on `configure/service/vprn`); the route distinguisher comes from `bgp-ipvpn/mpls` and is absent on VPRNs without an MPLS L3VPN backbone. VPRN member interfaces are keyed `<service>/<interface>`, matching how the driver names them for IP discovery. The Base router is the default routing table. |
| `nokia_srl` | Supported (Nokia SR Linux via SSH) — network instances are SR Linux's native routing model; three targeted `info from state network-instance` calls discover types, interface membership, and the BGP-VPN route distinguisher. `ip-vrf` instances map to VRFs; `mac-vrf` (L2) and the `default` instance are excluded. |
| `huawei_vrp` | Supported (Huawei VRP via SSH) — VPN instances map to VRFs: names and member interfaces from `display ip vpn-instance interface`, route distinguishers from the `display ip vpn-instance` summary (both the `ipv4-family` and plain `IPv4`/`IPv6` address-family column forms are handled; VRP configures the RD per address family and the first configured one wins). |
| `hp_comware` | Supported (HPE / H3C Comware via SSH) — VPN instances map to VRFs: `display ip vpn-instance` enumerates them, one `display ip vpn-instance instance-name <name>` per instance supplies the RD and member interfaces (wrapped multi-member lists handled). |
| `cumulus_linux` | Supported (NVIDIA Cumulus Linux via SSH) — Linux VRF devices from `ip vrf show`, member interfaces from `ip link show master <vrf>` (kernel `@parent` decorations stripped). Linux VRFs carry no kernel-level route distinguisher (it lives in FRR BGP), so VRFs are always emitted without an RD. |
| `dell_sonic` | Supported (Dell Enterprise SONiC via SSH) — VRFs and their member interfaces from `show vrf`. The management VRF (`mgmt`) is a real VRF and is kept. SONiC's `show vrf` carries no route distinguisher, so VRFs are always emitted without an RD. |
| `nokia_sros_ssh` | Supported (Nokia SR OS via SSH CLI) — VPRN services map to VRFs: `show service service-using vprn` enumerates them (parsed driver-locally because SR OS service names are optional and the ntc-template rejects the unnamed form; unnamed services fall back to the numeric service id), one `show service id <id> interface` per service lists members, keyed `<service>/<interface>` like the NETCONF sibling. Route distinguishers are not collected on the classic CLI in this first pass. |
| `aruba_aoscx` | Supported (Aruba AOS-CX via REST) — VRFs from the `system/vrfs` resource (EVPN route distinguisher carried when the firmware exposes it); member interfaces from each interface's VRF reference. The factory `default` VRF is the global routing table. `aruba_aoscx_ssh` is not yet supported for VRF discovery. |
| `cisco_viptela_ssh` | Supported (Cisco SD-WAN / Viptela via SSH) — VPN segments map to VRFs named by VPN number, derived from the VPN column of `show interface`. Transport VPN 0 is the underlay (default instance); the management VPN 512 is kept as a real VRF. No route distinguisher at this layer. |
| `paloalto_panos` | Supported (PaloAlto PAN-OS via XML API) — virtual routers map to VRFs (`vr:<name>`, or `logical-router:<name>` with Advanced Routing on PAN-OS 10.2+), derived from the forwarding field of `show interface all`. VSYS are never mapped. The factory `default` virtual router is the global routing table. Virtual routers with no interfaces assigned are not discovered. |
| `paloalto_panos_ssh` | Supported (PaloAlto PAN-OS via SSH CLI) — same mapping as `paloalto_panos`, from the FORWARDING column of `show interface logical`; both transports emit identical results for the same configuration. |
| `extreme_slx` | Supported (Extreme SLX-OS via SSH) — VRF membership from the Vrf column of `show ip interface brief` (the same rows IP discovery parses). `default-vrf` is the global routing table; `mgmt-vrf` is a real VRF and is kept. Route distinguishers are not collected, and VRFs with no L3 interfaces are not discovered (enumeration is membership-derived). |
| `dell_ftos` | Supported (Dell EMC OS9 / FTOS via SSH) — VRFs and member interfaces from `show ip vrf`; abbreviated member names (`Gi 1/2`) expand to the full forms interface discovery uses, including wrapped lists and trailing-number ranges. `default` is the global routing table; the `management` VRF is kept. RD not collected. Built from the vendor-documented output format — please report any live-device parse gaps. |
| `brocade_netiron` | Supported (Brocade/Extreme NetIron via SSH) — VRFs, default RDs, and member interfaces from `show vrf`; member shorthand (`ve2`, `e1/1`) is canonicalised to the names interface discovery emits. Built from the vendor-documented output format — please report any live-device parse gaps. |
| `extreme_vsp` | Supported (Extreme VOSS / VSP via SSH) — `show ip vrf` enumerates VRFs (incl. L3VSNs); one `show ip interface vrf <name>` per VRF lists members. `GlobalRouter` is the global routing table; `MgmtRouter` is kept. RD not collected. Built from the vendor-documented output format — please report any live-device parse gaps. |
| other drivers | See below — remaining drivers are either permanently N/A (no VRF concept) or demand-driven. Enabling `discover_vrfs` on them logs a warning per discovery cycle and discovery continues without VRF data. |

**Permanently N/A** (no L3 VRF concept on the platform — no implementation planned): `aruba_os`, `aruba_osswitch`, `hp_procurve`, `avaya_ers`, `dell_powerconnect`, `cisco_s300`, `ciena_saos`, `cisco_fxos`, `cisco_wlc`, `checkpoint_gaia` (VSX virtual systems are firewall contexts, not VRFs), `huawei_smartax`, `ubiquiti_edgerouter`, `ubiquiti_edgeswitch`, `ubiquiti_unifiswitch`.

**Demand-driven** (the platform has a VRF or VRF-like concept; implementation awaits a real-device output capture — open an issue with one if you need it): `brocade_fastiron` (ICX VRF-lite), `alcatel_aos` (OmniSwitch VRF), `aruba_aoscx_ssh` (use the REST `aruba_aoscx` driver meanwhile), `mikrotik_routeros` (RouterOS v7 `/ip/vrf` only — v6 routing marks will not be mapped), `fortinet_fortios_ssh` (only explicit interface VRF ids would be mapped — VDOMs are firewall contexts, never VRFs), `cisco_asa` / `cisco_asa_ssh` / `cisco_ftd_ssh` (multi-context/virtual-router semantics need design), `cisco_apic` (ACI tenant VRFs are fabric-level objects, out of scope for per-device discovery), `ericsson_ipos`, `mellanox_mlnxos`.

## Querying supported drivers at runtime

device-discovery exposes its effective driver list via its capabilities endpoint:
Expand Down
Loading