wiki-vault/Sources/Homelab/2026-05-08-homelab-vlan-renumber-switch-chip-to-bridge-alignment.md
Travis Herbranson 34a268d8dc migration: copy 62 notes from pbs-projects and homelab-projects
Two-layer structure: Sources (raw notes) + Wiki (compile output)
Four domains: Dev (40), Venture (3), Homelab (23), Reference (0)
Includes CLAUDE.md spec, index pages at all levels, compile log

Co-Authored-By: Lovebug <lovebug@herbylab.dev>
2026-05-08 17:21:13 -04:00

5.8 KiB

created path project status tags type updated
2026-05-08 Sources/Homelab homelab-vlan-renumber completed
proxmox
automation
session-notes 2026-05-08

Homelab VLAN Renumber — Switch Chip to Bridge Alignment

Outcome

Renumbered OpenWrt's hardware switch chip VLANs to match the bridge VLAN filtering layer. Lab and private VLANs now use the same VID end-to-end (11 and 21) from the wire through the chip, sub-interface, and bridge. Unblocked Phase 1.3 — Knot LXC successfully reaches 10.0.11.1 over a tagged trunk from PVE.

The Problem

OpenWrt was running two layers of VLAN configuration with different VID numbering:

  • Switch chip (swconfig): VID 1, 2, 3 (lab), 4 (private)
  • Bridge VLAN filtering: VID 11, 21, 31, 61, 71

Bridge VLAN filtering rules quietly translated between them via :u* (untagged + PVID) on the sub-interface ports. NAS frames came up tagged VID 3 from the chip, hit eth1.3 configured as :u* on bridge VID 11 — bridge applied PVID 11 to ingressing untagged frames. PVE same pattern: VID 4 → eth1.4:u* → bridge PVID 21.

The translation worked, but it meant configuring PVE to send tag=11 for "VLAN 11 lab" actually required sending tag=3 (the chip's wire VID), which is the kind of hidden mismatch that loses an hour of debugging six months later.

The Architecture Change

Switch chip — added entries with bridge-matching VIDs:

VLAN 11: ports='3 4t 6t'  (NAS untagged on 3, PVE tagged on 4, CPU tagged on 6)
VLAN 21: ports='4 6t'     (PVE untagged on 4, CPU tagged on 6)

Linux — created explicit 8021q sub-interfaces:

config device
    option type '8021q'
    option ifname 'eth1'
    option vid '11'
    option name 'eth1.11'

config device
    option type '8021q'
    option ifname 'eth1'
    option vid '21'
    option name 'eth1.21'

These were created explicitly rather than relying on the legacy implicit eth1.<N> auto-creation. The previous eth1.3 and eth1.4 ports never had explicit device entries — Linux auto-spawned them when referenced in the bridge ports list. The explicit form is the modern OpenWrt-recommended pattern and makes the config self-documenting.

Bridge — homebridge ports updated:

ports='eth1.3' → ports='eth1.21' 'eth1.11'

(eth1.3 retained for ports 1/2 still on legacy VID 3 — see Open Items.)

Bridge VLAN filtering — sub-interfaces wired to matching VIDs:

VID 11: 'eth1.11' tagged member, 'eth1.3:u*' (NAS legacy translation, retained)
VID 21: 'eth1.21:u*' (PVE untagged + PVID)

How the Migration Stayed Live

Parallel-build pattern. Built the new VID 21 plumbing alongside the existing VID 4 path before tearing anything down. PVE management kept flowing on the legacy path until the new path was verified, then eth1.4 was removed in one cutover. Same approach for VID 11. PVE never dropped, NAS never dropped.

Hybrid Trunk on PVE Port

Port 4 ended as a hybrid trunk: VID 21 untagged (PVE management default) + VID 11 tagged (LXC traffic). This required the LXC's tag=11 parameter to match the wire VID for the first time — previously this would have needed tag=3 due to the translation layer.

Key Learnings

  • swconfig VIDs are real wire VIDs. Earlier in the session I (Claude) misframed them as "internal slots" — they're actual 802.1Q tags on frames between the switch silicon and the CPU. The number you see in swconfig is the number on the wire.
  • Tagged port ≠ port adds tag. Tagged means "expect frames to already carry an 802.1Q tag and preserve it." The sending device adds the tag. PVID on an untagged port is what tags ingressing untagged frames.
  • VLANs only do anything when something downstream enforces them. A VID on a frame is just a number unless a switch or bridge filters on it. The original setup "worked" because the bridge wasn't VLAN-aware yet — turning on bridge-vlan-aware yes is what surfaced the latent chip/bridge mismatch.
  • Two VID namespaces stacked on top of each other is a footgun. The translation pattern works but creates cognitive overhead every time you debug. Aligning the layers eliminates a class of "which number do I use here?" questions forever.
  • Explicit 8021q device entries beat implicit sub-interface auto-spawn. Self-documenting, idiomatic for current OpenWrt, easier to grep for in the config. The implicit form is legacy and hides the dependency on bridge ports list references.
  • uci add_list is non-destructive on bridge ports. Adding a sub-interface to a bridge port list during a parallel build doesn't disrupt existing members. Both paths run side-by-side until the old one is removed.
  • Parallel-build > rename for live infrastructure. Renaming eth1.4eth1.21 in place would have required atomically updating the device, bridge, and switch_vlan in one reload. Building eth1.21 alongside, verifying, then removing eth1.4 is recoverable at every step.

Open Items

  • Switch chip still has VID 3 with ports 1 and 2 as members (link down on 1, link up on 2). Need to identify what's on port 2 before retiring VID 3 entirely.
  • Cosmetic: eth1.21 listed as redundant tagged member on bridge VID 11 (harmless, future cleanup).
  • Cosmetic: switch_vlan descriptions still say lab-new / private-new. Should rename to lab / private once VID 3 is fully retired.
  • Document new wiring on Knot LXC — Phase 1.3 resume notes can now move from "blocked" to "infrastructure ready."

Final State

Layer VID 11 (lab) VID 21 (private)
Switch chip 3 4t 6t 4 6t
Sub-interface eth1.11 (explicit 8021q) eth1.21 (explicit 8021q)
Bridge port eth1.11 tagged, eth1.3:u* legacy eth1.21:u*
End-to-end VID 11 (NAS untagged on chip, all else 11) 21 (PVE untagged on chip, all else 21)

NAS reachable, PVE management reachable, Knot LXC pinging gateway. Phase 1.3 unblocked.