lol

Merge pull request #251290 from Majiir/systemd-initrd-networking-features

nixos/network-interfaces-systemd: support `vlans`, `bridges` in systemd-initrd

authored by

Will Fancher and committed by
GitHub
4bd4976b 801e33f5

+162 -26
+38 -26
nixos/modules/tasks/network-interfaces-systemd.nix
··· 173 173 }]; 174 174 })); 175 175 176 + bridgeNetworks = mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: { 177 + netdevs."40-${name}" = { 178 + netdevConfig = { 179 + Name = name; 180 + Kind = "bridge"; 181 + }; 182 + }; 183 + networks = listToAttrs (forEach bridge.interfaces (bi: 184 + nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { 185 + DHCP = mkOverride 0 (dhcpStr false); 186 + networkConfig.Bridge = name; 187 + } ]))); 188 + })); 189 + 190 + vlanNetworks = mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: { 191 + netdevs."40-${name}" = { 192 + netdevConfig = { 193 + Name = name; 194 + Kind = "vlan"; 195 + }; 196 + vlanConfig.Id = vlan.id; 197 + }; 198 + networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { 199 + vlan = [ name ]; 200 + } ]); 201 + })); 202 + 176 203 in 177 204 178 205 { ··· 182 209 # Note this is if initrd.network.enable, not if 183 210 # initrd.systemd.network.enable. By setting the latter and not the 184 211 # former, the user retains full control over the configuration. 185 - boot.initrd.systemd.network = mkMerge [(genericDhcpNetworks true) interfaceNetworks]; 212 + boot.initrd.systemd.network = mkMerge [ 213 + (genericDhcpNetworks true) 214 + interfaceNetworks 215 + bridgeNetworks 216 + vlanNetworks 217 + ]; 218 + boot.initrd.availableKernelModules = 219 + optional (cfg.bridges != {}) "bridge" ++ 220 + optional (cfg.vlans != {}) "8021q"; 186 221 }) 187 222 188 223 (mkIf cfg.useNetworkd { ··· 212 247 } 213 248 (genericDhcpNetworks false) 214 249 interfaceNetworks 215 - (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: { 216 - netdevs."40-${name}" = { 217 - netdevConfig = { 218 - Name = name; 219 - Kind = "bridge"; 220 - }; 221 - }; 222 - networks = listToAttrs (forEach bridge.interfaces (bi: 223 - nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { 224 - DHCP = mkOverride 0 (dhcpStr false); 225 - networkConfig.Bridge = name; 226 - } ]))); 227 - }))) 250 + bridgeNetworks 228 251 (mkMerge (flip mapAttrsToList cfg.bonds (name: bond: { 229 252 netdevs."40-${name}" = { 230 253 netdevConfig = { ··· 377 400 } ]); 378 401 }; 379 402 }))) 380 - (mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: { 381 - netdevs."40-${name}" = { 382 - netdevConfig = { 383 - Name = name; 384 - Kind = "vlan"; 385 - }; 386 - vlanConfig.Id = vlan.id; 387 - }; 388 - networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { 389 - vlan = [ name ]; 390 - } ]); 391 - }))) 403 + vlanNetworks 392 404 ]; 393 405 394 406 # We need to prefill the slaved devices with networking options
+2
nixos/tests/all-tests.nix
··· 764 764 systemd-cryptenroll = handleTest ./systemd-cryptenroll.nix {}; 765 765 systemd-credentials-tpm2 = handleTest ./systemd-credentials-tpm2.nix {}; 766 766 systemd-escaping = handleTest ./systemd-escaping.nix {}; 767 + systemd-initrd-bridge = handleTest ./systemd-initrd-bridge.nix {}; 767 768 systemd-initrd-btrfs-raid = handleTest ./systemd-initrd-btrfs-raid.nix {}; 768 769 systemd-initrd-luks-fido2 = handleTest ./systemd-initrd-luks-fido2.nix {}; 769 770 systemd-initrd-luks-keyfile = handleTest ./systemd-initrd-luks-keyfile.nix {}; ··· 778 779 systemd-initrd-networkd = handleTest ./systemd-initrd-networkd.nix {}; 779 780 systemd-initrd-networkd-ssh = handleTest ./systemd-initrd-networkd-ssh.nix {}; 780 781 systemd-initrd-networkd-openvpn = handleTest ./initrd-network-openvpn { systemdStage1 = true; }; 782 + systemd-initrd-vlan = handleTest ./systemd-initrd-vlan.nix {}; 781 783 systemd-journal = handleTest ./systemd-journal.nix {}; 782 784 systemd-machinectl = handleTest ./systemd-machinectl.nix {}; 783 785 systemd-networkd = handleTest ./systemd-networkd.nix {};
+63
nixos/tests/systemd-initrd-bridge.nix
··· 1 + import ./make-test-python.nix ({ lib, ... }: { 2 + name = "systemd-initrd-bridge"; 3 + meta.maintainers = [ lib.maintainers.majiir ]; 4 + 5 + # Tests bridge interface configuration in systemd-initrd. 6 + # 7 + # The 'a' and 'b' nodes are connected to a 'bridge' node through different 8 + # links. The 'bridge' node configures a bridge across them. It waits forever 9 + # in initrd (stage 1) with networking enabled. 'a' and 'b' ping 'bridge' to 10 + # test connectivity with the bridge interface. Then, 'a' pings 'b' to test 11 + # the bridge itself. 12 + 13 + nodes = { 14 + bridge = { config, lib, ... }: { 15 + boot.initrd.systemd.enable = true; 16 + boot.initrd.network.enable = true; 17 + boot.initrd.systemd.services.boot-blocker = { 18 + before = [ "initrd.target" ]; 19 + wantedBy = [ "initrd.target" ]; 20 + script = "sleep infinity"; 21 + serviceConfig.Type = "oneshot"; 22 + }; 23 + 24 + networking.primaryIPAddress = "192.168.1.${toString config.virtualisation.test.nodeNumber}"; 25 + 26 + virtualisation.vlans = [ 1 2 ]; 27 + networking.bridges.br0.interfaces = [ "eth1" "eth2" ]; 28 + 29 + networking.interfaces = { 30 + eth1.ipv4.addresses = lib.mkForce []; 31 + eth2.ipv4.addresses = lib.mkForce []; 32 + br0.ipv4.addresses = [{ 33 + address = config.networking.primaryIPAddress; 34 + prefixLength = 24; 35 + }]; 36 + }; 37 + }; 38 + 39 + a = { 40 + virtualisation.vlans = [ 1 ]; 41 + }; 42 + 43 + b = { config, ... }: { 44 + virtualisation.vlans = [ 2 ]; 45 + networking.primaryIPAddress = lib.mkForce "192.168.1.${toString config.virtualisation.test.nodeNumber}"; 46 + networking.interfaces.eth1.ipv4.addresses = lib.mkForce [{ 47 + address = config.networking.primaryIPAddress; 48 + prefixLength = 24; 49 + }]; 50 + }; 51 + }; 52 + 53 + testScript = '' 54 + start_all() 55 + a.wait_for_unit("network.target") 56 + b.wait_for_unit("network.target") 57 + 58 + a.succeed("ping -n -w 10 -c 1 bridge >&2") 59 + b.succeed("ping -n -w 10 -c 1 bridge >&2") 60 + 61 + a.succeed("ping -n -w 10 -c 1 b >&2") 62 + ''; 63 + })
+59
nixos/tests/systemd-initrd-vlan.nix
··· 1 + import ./make-test-python.nix ({ lib, ... }: { 2 + name = "systemd-initrd-vlan"; 3 + meta.maintainers = [ lib.maintainers.majiir ]; 4 + 5 + # Tests VLAN interface configuration in systemd-initrd. 6 + # 7 + # Two nodes are configured for a tagged VLAN. (Note that they also still have 8 + # their ordinary eth0 and eth1 interfaces, which are not VLAN-tagged.) 9 + # 10 + # The 'server' node waits forever in initrd (stage 1) with networking 11 + # enabled. The 'client' node pings it to test network connectivity. 12 + 13 + nodes = let 14 + network = id: { 15 + networking = { 16 + vlans."eth1.10" = { 17 + id = 10; 18 + interface = "eth1"; 19 + }; 20 + interfaces."eth1.10" = { 21 + ipv4.addresses = [{ 22 + address = "192.168.10.${id}"; 23 + prefixLength = 24; 24 + }]; 25 + }; 26 + }; 27 + }; 28 + in { 29 + # Node that will use initrd networking. 30 + server = network "1" // { 31 + boot.initrd.systemd.enable = true; 32 + boot.initrd.network.enable = true; 33 + boot.initrd.systemd.services.boot-blocker = { 34 + before = [ "initrd.target" ]; 35 + wantedBy = [ "initrd.target" ]; 36 + script = "sleep infinity"; 37 + serviceConfig.Type = "oneshot"; 38 + }; 39 + }; 40 + 41 + # Node that will ping the server. 42 + client = network "2"; 43 + }; 44 + 45 + testScript = '' 46 + start_all() 47 + client.wait_for_unit("network.target") 48 + 49 + # Wait for the regular (untagged) interface to be up. 50 + def server_is_up(_) -> bool: 51 + status, _ = client.execute("ping -n -c 1 server >&2") 52 + return status == 0 53 + with client.nested("waiting for server to come up"): 54 + retry(server_is_up) 55 + 56 + # Try to ping the (tagged) VLAN interface. 57 + client.succeed("ping -n -w 10 -c 1 192.168.10.1 >&2") 58 + ''; 59 + })