Files
dotfiles/.claude/tasks/0003-network-vlan-foundation.md
alexion b87076ebd3 feat(network): add host VLAN-bridge networking foundation
Introduce `modules.network`, the host-level networking foundation a Host
declares once. A Host states its trunk interface and the tagged VLAN ids to
materialize, and the module emits one systemd-networkd bridge per VLAN, named
by the `br-vlan<id>` convention, plus the host's own management address on a
chosen VLAN's bridge.

The trunk and every bridge set `RequiredForOnline = "no"` so wait-online never
blocks boot on a carrier-less link, and the module owns its own NetworkManager
`unmanaged` guard so enabling it is self-sufficient. Two assertions tie the
management VLAN to the declared VLANs and a management address to a VLAN, so an
address can never be silently dropped.

Enabled on neogaia as a tracer with placeholder values, proving the host build
and bridge-name evaluation through `nix flake check`. No Guest is wired to a
bridge yet.
2026-07-25 14:51:49 -04:00

2.3 KiB

spec
spec
guests

What to build

The host-level networking foundation, modules.network, that a Host declares once and every Guest attaches to. A Host states its trunk interface and the set of VLANs to materialize, and the Module emits one bridge per tagged VLAN using systemd-networkd, named by the br-vlan<id> convention, and manages the Host's own management address. This is a standalone host-level Module and does not yet wire any Guest to a bridge — that is the Guest networking placement slice.

Acceptance criteria

  • modules.network declares an enable option and its option path mirrors its file location per the Namespace convention.
  • A Host declares its trunk interface and its set of VLAN ids through the Module's options.
  • Enabling the Module emits exactly one systemd-networkd bridge per declared VLAN, each named br-vlan<id>, and manages the Host's own management address.
  • A Host enabling modules.network builds via nix flake check, and the emitted bridge names are verifiable by nix eval.

Implementation Notes

Each VLAN materializes as three networkd entries: a <trunk>.<id> tagged sub-interface stacked on the trunk, a br-vlan<id> bridge, and a network enslaving the sub-interface to the bridge. The trunk and every bridge set RequiredForOnline = "no", so systemd-networkd-wait-online never blocks boot on a link with no carrier.

The management address takes a static CIDR, or DHCP when left null, on the management VLAN's bridge alone. Two assertions guard it: the management VLAN must be one of the declared VLANs, and a declared management address must name a management VLAN, so an address can never be silently dropped for want of a bridge to carry it.

The Module owns its own NetworkManager unmanaged guard for the trunk, sub-interfaces, and bridges, so enabling it is self-sufficient on a host that also runs NetworkManager rather than pushing that wiring into every Host. A management.gateway option was considered and dropped as speculative for this slice, since the foundation carries no other routing.

Enabled on neogaia as a tracer with a placeholder trunk and VLAN ids, mirroring the walking-skeleton guest, so the host build and bridge-name evaluation are proven through this host's nix flake check. No Guest is wired to a bridge — that is the guest networking placement slice.