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. No host commits an enablement: the only host is a wifi laptop that cannot present guests as L2 citizens and whose DNS the module's networkd/resolved would disturb, so the standing enablement waits for the first wired server host. The build and bridge-name evaluation were verified by enabling the module ad hoc, and stay reproducible through `extendModules`.
3.0 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.networkdeclares anenableoption 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.networkbuilds vianix flake check, and the emitted bridge names are verifiable bynix eval. Verified by temporarily enabling it onneogaia; the enablement is not committed (see notes).
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.
No host commits an enablement of this Module.
The repo's only host is neogaia, a wifi laptop on an access port, and enabling the Module there turns on systemd-networkd and pulls in systemd-resolved, which takes over the laptop's DNS.
That is an unwanted change to a daily machine that cannot present guests as L2 citizens anyway (wifi does not bridge), so the standing enablement waits for the first wired server host.
The build and bridge-name evaluation were verified by temporarily enabling the Module on neogaia (nix flake check passed, nix eval showed br-vlan10/br-vlan20), then reverting.
Both stay reproducible from the committed tree by enabling the Module ad hoc through nixosConfigurations.neogaia.extendModules, leaving the host file untouched.
No Guest is wired to a bridge — that is the guest networking placement slice.