Skip to content

Fix manual_underlay_allocation with TOR switches - #866

Open
ccoueffe wants to merge 7 commits into
netascode:developfrom
ccoueffe:fix/manual_allocation_with_tor
Open

Fix manual_underlay_allocation with TOR switches#866
ccoueffe wants to merge 7 commits into
netascode:developfrom
ccoueffe:fix/manual_allocation_with_tor

Conversation

@ccoueffe

@ccoueffe ccoueffe commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Related Issue(s)

Fixes #867

Fixes TOR switch support with manual_underlay_allocation: true. Without this fix, the validate role and underlay IP template fail when TOR switches are present in the topology.

Related Collection Role

  • cisco.nac_dc_vxlan.validate
  • cisco.nac_dc_vxlan.dtc.create
  • cisco.nac_dc_vxlan.dtc.deploy
  • cisco.nac_dc_vxlan.dtc.remove
  • other

Related Data Model Element

  • vxlan.fabric
  • vxlan.global
  • vxlan.topology
  • vxlan.underlay
  • vxlan.overlay
  • vxlan.overlay_extensions
  • vxlan.policy
  • vxlan.multisite
  • defaults.vxlan
  • other

Proposed Changes

TOR switches do not participate in the VXLAN underlay — they have no loopback IPs, no VTEP, no vtep_vip, and no underlay P2P or backup links. When manual_underlay_allocation: true, the validate rule and underlay IP template must skip TOR switches entirely and warn if underlay configuration is incorrectly provided for TOR.

Rule 208 (208_manual_ipaddress_allocation.py)

TOR exclusions (nothing mandatory for TOR):

Fix Description
Skip TOR in loopback validation TOR switches no longer require Loopback0 or Loopback1 with IPv4
Skip TOR vPC peers in vtep_vip validation TOR vPC pairs no longer require vtep_vip
Skip TOR in validate_fabric_links switch list TOR excluded from "missing fabric link" checks in P2P mode
Skip TOR vPC peers in fabric link peer check TOR pairs with fabric_peering: false no longer require a fabric link entry

Error if TOR has underlay config (catch misconfigurations):

Check Error message
TOR switch with underlay loopback + IPv4 "TOR switch 'X': underlay loopback 'Loopback0' with IPv4 should not be defined..."
TOR vPC pair with vtep_vip defined "vPC peer 'X-Y': vtep_vip should not be defined for TOR switches..."
Fabric link with IPv4 involving a TOR switch "Fabric link 'X' → 'Y': IPv4 underlay configuration should not be defined for TOR switch..."

Fix fabric_peering: false + unnumbered interaction:

Fix Description
New method validate_vpc_peer_fabric_link() When fabric_interface_numbering: unnumbered, only validates the specific vPC peer-link between two peers (not all fabric links for all switches)

Underlay IP template (ndfc_underlay_ip_address.j2)

Fix Description
Skip TOR in loopback resource generation TOR switches no longer generate LOOPBACK0_IP_POOL or LOOPBACK1_IP_POOL entries
Skip TOR vPC peers in vtep_vip resource TOR vPC pairs no longer generate vtep_vip resource manager entries

Data Model Example (TOR topology)

vxlan:
  underlay:
    general:
      manual_underlay_allocation: true
      fabric_interface_numbering: unnumbered
  topology:
    vpc_peers:
      - peer1: dc1-lf1
        peer2: dc1-lf2
        domain_id: 10
        fabric_peering: true
        vtep_vip: 100.2.0.10
      - peer1: dc1-tor-1       # TOR pair — no underlay config needed
        peer2: dc1-tor-2
        domain_id: 12
        fabric_peering: false
    tor_peers:
      - parent_leaf1: dc1-lf1
        parent_leaf2: dc1-lf2
        tor1: dc1-tor-1
        tor2: dc1-tor-2
    switches:
      - name: dc1-lf1
        role: leaf
        interfaces:             # Loopbacks with IPv4 required
          - name: Loopback0
            ipv4_address: 100.0.0.1
          - name: Loopback1
            ipv4_address: 100.1.0.1
      - name: dc1-tor-1
        role: tor               # No underlay IP configuration needed

Test Notes

Tested with a VXLAN_EVPN fabric containing:

  • 1 spine, 1 border_gateway, 2 leaves, 1 border, 2 pre-provisioned leaves, 2 TOR switches
  • manual_underlay_allocation: true + fabric_interface_numbering: unnumbered
  • TOR vPC pair with fabric_peering: false
  • TOR switches have no underlay IPs (no loopbacks, no vtep_vip, no P2P IPs)
  • Validate passes cleanly
  • Template renders without 'dict object' has no attribute 'vtep_vip' error
  • Misconfigurations (loopback IPv4 on TOR, vtep_vip on TOR pair, IPv4 on TOR fabric link) correctly produce errors

Cisco Nexus Dashboard Version

12.4.1

Checklist

  • Latest commit is rebased from develop with merge conflicts resolved
  • New or updates to documentation has been made accordingly
  • Assigned the proper reviewers

@ccoueffe ccoueffe self-assigned this Aug 10, 2026
@ccoueffe ccoueffe changed the title Fix/manual allocation with tor Fix manual_underlay_allocation with TOR switches Aug 10, 2026
@ccoueffe
ccoueffe marked this pull request as ready for review August 10, 2026 15:12
@ccoueffe
ccoueffe requested a review from a team as a code owner August 10, 2026 15:12
@ccoueffe ccoueffe added the ready for review PR Ready for Review label Aug 10, 2026
@ccoueffe
ccoueffe requested a review from juburnet August 10, 2026 15:13
@ccoueffe ccoueffe added bug Something isn't working 0.9.0 Release 0.9.0 labels Aug 10, 2026
@juburnet
juburnet requested a review from skaszlik August 10, 2026 15:45
@juarocha
juarocha self-requested a review August 10, 2026 21:27

@juarocha juarocha left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Tested on 4.1 with VPC-to-Standalone ToR. before testing the data model shows an error: rule 208: Verify IP addresses when manual_underlay_allocation is true with tor switch. After testing with this branch, no error is shown; everything is configured correctly

@juburnet
juburnet requested a review from mikewiebe August 11, 2026 15:14
{%- endif %}
{%- endfor %}
{% if not ((switch.role == 'spine' or switch.role == 'super_spine') and loopback_id == vtep_lo_id) %}
{% if switch.role != 'tor' %}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: Existing ToR pool allocations are omitted but never released

Issue

The changed template stops rendering routing-loopback, VTEP-loopback, and vPC VIP resource-manager entries for ToR switches, but neither the create nor remove pipeline releases entries which were allocated by an earlier run. This is a state-transition defect: the desired file becomes correct while NDFC retains the old allocation.

Evidence

  • The new role gate omits ToR loopback allocations at ndfc_underlay_ip_address.j2:28, and the new peer-role gate similarly omits the vPC VIP entry at line 47.
  • underlay_ip_address is structurally diffed by entity_name. A focused old-versus-new fixture containing one former ToR allocation produced updated: 0, removed: 1, equal: 0.
  • Both active fabric registries invoke cisco.dcnm.dcnm_resource_manager with state: merged (resources/create_resources.yml, VXLAN_EVPN lines 96-108 and eBGP_VXLAN lines 286-298). In a selective run, ResourceManager._resolve_create_data() consumes only diff.updated; it never consumes diff.removed. In a full run, the remote audit compares only desired entries, so an omitted controller entry is not selected either.
  • There is no underlay_ip_address step in resources/remove_resources.yml. At both the declared floor cisco.dcnm 3.12.1 (6311b66ff02b8ed593cbbfed4abdd502607dd6d2) and current inspected ref 939c75bb667498631e9047ff9f62f424f00b98c2, the dcnm_resource_manager contract says merged leaves unspecified resources untouched and deleted releases resources explicitly supplied in config.

Practical example

Before this change, assume manual allocation created these controller resources for ToR TOR1:

- entity_name: TOR-SERIAL-1~loopback0
  pool_name: LOOPBACK0_IP_POOL
  resource: 10.10.0.21
- entity_name: TOR-SERIAL-1~loopback1
  pool_name: LOOPBACK1_IP_POOL
  resource: 10.20.0.21

After upgrading, the user removes those ToR loopbacks from the model to comply with the new validation. The desired file correctly omits them, and the structural result is effectively:

updated: []
removed:
  - entity_name: TOR-SERIAL-1~loopback0
  - entity_name: TOR-SERIAL-1~loopback1

The selective create path has nothing in diff.updated, and no remove step consumes these two entries. A forced full run still uses state: merged, so omission does not release them. NDFC therefore continues to reserve 10.10.0.21 and 10.20.0.21 for TOR1; a later attempt to reuse either address can fail even though neither appears in the current NaC model.

Existing PR overlap

No matching existing PR comment found. The visible approval tested creation from a happy-path ToR topology; it did not test migration from a previously rendered ToR allocation or the last-item-removed transition.

Impact

An environment that previously ran manual allocation with ToR loopbacks or a ToR vPC VIP can continue to reserve those IPs after upgrading to this fix. The stale reservations can exhaust pools, block reuse, or make controller state disagree with the saved NaC artifact. Both diff_run=true and a full reconciliation leave them untouched.

Suggested fix

Add an underlay-resource removal step that sends underlay_ip_address.diff.removed to cisco.dcnm.dcnm_resource_manager with state: deleted, with appropriate opt-in/safety semantics if resource release is intentionally guarded. Test one removed ToR loopback, one removed ToR vPC VIP, mixed removed-and-updated entries, the last allocation removed, a full run, a selective run, and a no-change rerun.

cls.validate_vpc_peers_and_vtep_vip(data_model)

# Check if TOR switches have IPv4 on fabric links
cls.validate_tor_no_fabric_link_ipv4(data_model)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: ToR restrictions do not run for eBGP VXLAN fabrics

Issue

The new ToR semantic checks were added only to the iBGP Rule 208 path. The modified underlay resource template is active for both VXLAN_EVPN and eBGP_VXLAN, so an eBGP model can still render prohibited ToR fabric-link allocations.

Evidence

  • The new fabric-link check is called from 208_manual_ipaddress_allocation.py:84, under roles/validate/files/rules/ibgp_vxlan/.
  • VXLAN_EVPN loads ibgp_vxlan, while eBGP_VXLAN loads its separate rule directory, which currently contains no equivalent check.
  • ndfc_underlay_ip_address.j2 is active for both fabric types. Its new ToR conditions cover loopbacks and the vPC VIP, but the fabric-link section relies on semantic validation.
  • A full eBGP preparation/render fixture containing a leaf-to-ToR IPv4 link emitted allocations for both endpoints.
  • The authoritative model documentation supports ToR pairing in both iBGP and eBGP fabrics.

Existing PR overlap

No matching existing PR comment was found. The approval reports VXLAN_EVPN testing only and does not cover eBGP routing.

Impact

Equivalent ToR models behave differently depending on fabric type. On eBGP_VXLAN, underlay allocations can reach NDFC for a ToR that this PR says should not participate in the VXLAN underlay.

Suggested fix

Move the fabric-independent manual-allocation and ToR checks into common_vxlan, or add and maintain an equivalent eBGP rule. Also guard fabric-link rendering against ToR endpoints as defense in depth. Add positive and negative eBGP tests for omitted ToR loopbacks/VIP and prohibited ToR-involving IPv4 fabric links.

for link in fabric_links:
src = link.get("source_device", "")
dst = link.get("dest_device", "")
if (src == peer1 and dst == peer2) or (src == peer2 and dst == peer1):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: The new peer-link validator rejects a valid later match

Issue

validate_vpc_peer_fabric_link() stops at the first fabric-link object whose endpoints match the vPC pair. If that first object has no complete IPv4 block, it reports an error even when a later link between the same devices contains the required subnet and endpoint addresses.

Evidence

  • The new search assigns the first endpoint match and immediately breaks at 208_manual_ipaddress_allocation.py:210; only that one object is checked at lines 220-223.
  • The source schema models fabric_links as a list and imposes no one-link-per-device-pair uniqueness rule. Link identity includes interfaces, so parallel links between the same switches are representable.
  • A focused unnumbered fixture with fabric_peering: false, two leaf1/leaf2 link objects, no IPv4 on the first, and a complete /31 IPv4 block on the second produced: Fabric link between 'leaf1' and 'leaf2' is missing IPv4 configuration....

Practical example

A vPC pair can have two modeled links between the same switches:

vxlan:
  topology:
    vpc_peers:
      - peer1: dc1-leaf1
        peer2: dc1-leaf2
        fabric_peering: false

    fabric_links:
      # Valid unnumbered physical link
      - source_device: dc1-leaf1
        source_interface: Ethernet1/49
        dest_device: dc1-leaf2
        dest_interface: Ethernet1/49

      # Numbered backup link required for underlay peering
      - source_device: dc1-leaf1
        source_interface: Vlan3600
        dest_device: dc1-leaf2
        dest_interface: Vlan3600
        ipv4:
          subnet: 10.5.0.0/31
          source_ipv4: 10.5.0.0
          dest_ipv4: 10.5.0.1

The loop examines only the device names and stops at the first match:

for link in fabric_links:
    if link connects dc1-leaf1 and dc1-leaf2:
        peer_link = link
        break

It therefore selects Ethernet1/49, sees no ipv4 block, and reports:

Fabric link between 'dc1-leaf1' and 'dc1-leaf2' is missing IPv4 configuration

The complete Vlan3600 entry is never examined. Simply placing that entry first makes the same topology pass, so validation depends on list order rather than intent:

Order Result
Unnumbered link first, numbered link second Incorrect validation failure
Numbered link first, unnumbered link second Validation passes

Existing PR overlap

No matching existing PR comment found.

Impact

Validation becomes dependent on list order and can reject a topology that contains a complete configured vPC backup link. Reordering the same two links can change the result without changing intent.

Suggested fix

Collect all endpoint matches and succeed when any matching link has subnet, source_ipv4, and dest_ipv4; report missing-link only when there are no endpoint matches and missing-IPv4 only when matches exist but none is complete. Add zero-match, one complete, one incomplete, incomplete-then-complete, complete-then-incomplete, and reversed-endpoint tests.

switch_name = switch.get("name")
switch_role = switch.get("role", "").lower()

if switch_role == "tor":

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: The source documentation still instructs users to configure values the PR rejects

Issue

The implementation introduces a ToR exception to manual underlay allocation, but the authoritative model documentation still says every non-spine needs routing and VTEP loopback addresses and broadly describes vtep_vip as required when manual allocation is enabled. No companion documentation change explains the ToR contract.

Evidence

  • Rule 208 now skips ToR underlay requirements and actively rejects ToR loopback IPv4 at 208_manual_ipaddress_allocation.py:53, while its vPC logic rejects a ToR vtep_vip at lines 156-164.
  • At current model ref f997000b00b383725a9853c7f200b3a2c38cbb08, docs/templates/vxlan/underlay/underlay_general.md:89-91 gives only a spine exception, and docs/templates/vxlan/topology/topology_vpc_peer.md:74-96 does not describe the ToR exception.
  • PR 866 changes only two implementation files; it adds no model-doc companion, example, changelog entry, or durable behavioral test.

Practical example

A user following the current manual-allocation documentation could reasonably configure this ToR vPC pair:

vxlan:
  underlay:
    general:
      manual_underlay_allocation: true
      underlay_routing_loopback_id: 0
      underlay_vtep_loopback_id: 1

  topology:
    switches:
      - name: dc1-tor1
        role: tor
        interfaces:
          - name: Loopback0
            mode: fabric_loopback
            ipv4_address: 10.0.0.31
          - name: Loopback1
            mode: fabric_loopback
            ipv4_address: 10.1.0.31

      - name: dc1-tor2
        role: tor
        interfaces:
          - name: Loopback0
            mode: fabric_loopback
            ipv4_address: 10.0.0.32
          - name: Loopback1
            mode: fabric_loopback
            ipv4_address: 10.1.0.32

    vpc_peers:
      - peer1: dc1-tor1
        peer2: dc1-tor2
        fabric_peering: false
        vtep_vip: 10.1.0.30

This follows the documented interpretation: routing and VTEP loopback IPs are required for every role except spine, and the vPC guide says manual allocation requires vtep_vip; neither passage identifies tor as an exception. PR 866 now rejects the model with errors equivalent to:

TOR switch 'dc1-tor1': underlay loopback 'Loopback0' with IPv4
should not be defined (TOR switches do not participate in VXLAN underlay).

TOR switch 'dc1-tor1': underlay loopback 'Loopback1' with IPv4
should not be defined (TOR switches do not participate in VXLAN underlay).

TOR switch 'dc1-tor2': underlay loopback 'Loopback0' with IPv4
should not be defined (TOR switches do not participate in VXLAN underlay).

TOR switch 'dc1-tor2': underlay loopback 'Loopback1' with IPv4
should not be defined (TOR switches do not participate in VXLAN underlay).

vPC peer 'dc1-tor1-dc1-tor2': vtep_vip should not be defined for
TOR switches (TOR switches do not participate in VXLAN underlay).

To pass the new validation, the user must remove the ToR underlay loopback addresses and vtep_vip, but the current documentation never tells them to do that.

Existing PR overlap

No matching existing PR comment found.

Impact

Users following the current source documentation can add ToR loopbacks or a ToR VIP and receive the new Rule 208 errors. Conversely, users cannot discover from the manual-allocation guide which ToR values must be omitted.

Suggested fix

Update the model repository's manual-allocation and vPC/ToR documentation in the coordinated change, including iBGP/eBGP applicability, ToR loopback/VIP/fabric-link rules, and a minimal ToR example. Add a changelog/release note if that is the project's release convention.

- Move TOR underlay restriction checks to common_vxlan/406 (runs for iBGP and eBGP)
- Remove TOR error methods from ibgp_vxlan/208 (keep skip logic only)
- Fix validate_vpc_peer_fabric_link: check all matching links, not just first
- Add super_spine exclusion for VTEP loopback requirement
- Add TOR guard on fabric links section in ndfc_underlay_ip_address.j2
@ccoueffe

Copy link
Copy Markdown
Collaborator Author

Hi Mike, thanks for the detailed review.

Point 1 — Stale ToR resource allocations:
By design, NaC never removes allocated resources — they are released when the device is removed from NDFC. TOR with manual allocation is a new scenario; TOR switches are Layer-2 only and never had allocations in practice. If a user previously misconfigured TOR with loopbacks, removing the device and re-adding it clears the stale entries.

Point 2 — TOR checks only in iBGP (fixed):
Agreed. Moved TOR underlay restrictions to a new common_vxlan/406_tor_no_underlay_allocation.py rule that runs for both iBGP and eBGP fabrics. The iBGP rule 208 now only skips TOR from mandatory checks without duplicating the error logic. Additionally, added a TOR guard in the ndfc_underlay_ip_address.j2 template on the fabric links section as defense-in-depth.

Point 3 — Peer-link validator stops at first match (fixed):
Agreed. Changed validate_vpc_peer_fabric_link() to collect all matching links between the pair and succeed if any one has complete IPv4 config. This handles the case where a vPC pair has both an L2 peer-link (unnumbered) and a separate L3 backup link (with IPv4) — the validator no longer depends on list order.

Point 4 — Documentation:
Will open a companion PR on nac-vxlan to document the TOR exception for manual allocation.

@ccoueffe
ccoueffe requested a review from mikewiebe August 13, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

0.9.0 Release 0.9.0 bug Something isn't working ready for review PR Ready for Review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TOR switches fail with manual_underlay_allocation: true

3 participants