From f173887228ba8e22f1c5edcb3520528ac43c8baf Mon Sep 17 00:00:00 2001 From: alexion Date: Wed, 7 Oct 2026 21:29:52 -0400 Subject: [PATCH] refactor(nixos): consolidate VLAN networking --- configs/nixos/hosts/pikachu/default.nix | 42 +-------- configs/nixos/modules/network/vlans.nix | 111 +++++++----------------- 2 files changed, 34 insertions(+), 119 deletions(-) diff --git a/configs/nixos/hosts/pikachu/default.nix b/configs/nixos/hosts/pikachu/default.nix index bff75e9..939008d 100644 --- a/configs/nixos/hosts/pikachu/default.nix +++ b/configs/nixos/hosts/pikachu/default.nix @@ -15,46 +15,10 @@ hardware.cpu.intel.updateMicrocode = true; - systemd.network = { - enable = true; - netdevs = { - "40-br-vlan20".netdevConfig = { - Name = "br-vlan20"; - Kind = "bridge"; - }; - "40-vlan20" = { - netdevConfig = { - Name = "vlan20"; - Kind = "vlan"; - }; - vlanConfig.Id = 20; - }; - }; - - networks = { - "10-uplink" = { - matchConfig = { - Name = "enp2s0"; - MACAddress = "78:55:36:07:af:49"; - }; - networkConfig.DHCP = "yes"; - vlan = [ "vlan20" ]; - linkConfig.RequiredForOnline = "routable"; - }; - "40-vlan20" = { - matchConfig.Name = "vlan20"; - networkConfig.Bridge = "br-vlan20"; - linkConfig.RequiredForOnline = "no"; - }; - "40-br-vlan20" = { - matchConfig.Name = "br-vlan20"; - linkConfig.RequiredForOnline = "no"; - }; - }; + modules.network.vlans = { + interface = "enp2s0"; + ids = [ 20 ]; }; - networking.useDHCP = false; - - modules.network.vlans.ids = [ 20 ]; boot.zfs.forceImportRoot = false; diff --git a/configs/nixos/modules/network/vlans.nix b/configs/nixos/modules/network/vlans.nix index 25d75de..bf06a57 100644 --- a/configs/nixos/modules/network/vlans.nix +++ b/configs/nixos/modules/network/vlans.nix @@ -4,24 +4,17 @@ util, ... }: -# The host networking foundation: per-VLAN bridges over a tagged trunk. +# Configures bridges for tagged VLANs on a physical interface that uses DHCP. let cfg = config.modules.network.vlans; # NOLINT(let_order) - - inherit (util) bridgeName; - - vlanName = id: "${cfg.trunk}.${toString id}"; in { options.modules.network.vlans = { - enable = lib.mkEnableOption "host VLAN bridges over a tagged trunk"; - - trunk = lib.mkOption { + interface = lib.mkOption { type = lib.types.str; example = "enp1s0"; description = '' - Physical interface that carries 802.1Q-tagged traffic for every VLAN. - Each declared VLAN attaches to its own bridge. + Names the physical interface that carries untagged DHCP traffic and tagged VLANs. ''; }; @@ -34,67 +27,37 @@ in 30 ]; description = '' - Tagged VLAN ids to materialize. - Each id N creates one bridge named `br-vlanN`. + Creates bridges for the specified tagged VLAN IDs. + + VLAN ID N creates bridge `br-vlanN`. ''; }; - - management = { - vlan = lib.mkOption { - type = lib.types.nullOr (lib.types.ints.between 1 4094); - default = null; - description = '' - VLAN whose bridge carries the host's own management address. - The value must be one of `ids`. - Left null, the host takes no address on any bridge. - ''; - }; - - address = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - example = "10.0.10.2/24"; - description = '' - Host static management address in CIDR form. - Left null, the host takes its management address by DHCP. - ''; - }; - }; }; - config = lib.mkIf cfg.enable { - assertions = [ - { - assertion = cfg.management.vlan == null || lib.elem cfg.management.vlan cfg.ids; - message = "modules.network.vlans.management.vlan (${toString cfg.management.vlan}) must name one of modules.network.vlans.ids."; - } - { - assertion = cfg.management.address == null || cfg.management.vlan != null; - message = "modules.network.vlans.management.address needs modules.network.vlans.management.vlan to say which bridge carries it."; - } - ]; - - # networkd owns these interfaces so NetworkManager does not contend for them. - networking.networkmanager.unmanaged = [ - "interface-name:${cfg.trunk}" - ] - ++ map (id: "interface-name:${bridgeName id}") cfg.ids - ++ map (id: "interface-name:${vlanName id}") cfg.ids; + config = lib.mkIf (cfg.ids != [ ]) { + networking = { + useDHCP = false; + networkmanager.unmanaged = [ + "interface-name:${cfg.interface}" + ] + ++ map (id: "interface-name:${util.bridgeName id}") cfg.ids + ++ map (id: "interface-name:vlan${toString id}") cfg.ids; + }; systemd.network = { enable = true; netdevs = lib.mkMerge ( map (id: { - "40-${bridgeName id}" = { + "40-${util.bridgeName id}" = { netdevConfig = { - Name = bridgeName id; + Name = util.bridgeName id; Kind = "bridge"; }; }; - "40-${vlanName id}" = { + "40-vlan${toString id}" = { netdevConfig = { - Name = vlanName id; + Name = "vlan${toString id}"; Kind = "vlan"; }; vlanConfig.Id = id; @@ -104,37 +67,25 @@ in networks = lib.mkMerge ( [ - # The trunk carries only tagged frames and takes no address. { - "30-${cfg.trunk}" = { - matchConfig.Name = cfg.trunk; - networkConfig.LinkLocalAddressing = "no"; - linkConfig.RequiredForOnline = "no"; - vlan = map vlanName cfg.ids; + "10-${cfg.interface}" = { + matchConfig.Name = cfg.interface; + networkConfig.DHCP = "yes"; + vlan = map (id: "vlan${toString id}") cfg.ids; + linkConfig.RequiredForOnline = "routable"; }; } ] ++ map (id: { - # Enslaved to its bridge, carrying no address itself. - "40-${vlanName id}" = { - matchConfig.Name = vlanName id; - networkConfig.Bridge = bridgeName id; + "40-vlan${toString id}" = { + matchConfig.Name = "vlan${toString id}"; + networkConfig.Bridge = util.bridgeName id; + linkConfig.RequiredForOnline = "no"; + }; + "40-${util.bridgeName id}" = { + matchConfig.Name = util.bridgeName id; linkConfig.RequiredForOnline = "no"; }; - # The management bridge carries the host address. - # Other bridges provide L2 segments for guests. - "40-${bridgeName id}" = lib.mkMerge [ - { - matchConfig.Name = bridgeName id; - linkConfig.RequiredForOnline = "no"; - } - (lib.mkIf (cfg.management.vlan == id) ( - if cfg.management.address == null then - { networkConfig.DHCP = "yes"; } - else - { address = [ cfg.management.address ]; } - )) - ]; }) cfg.ids ); };