diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix index cb8fc957a99..cdffdf29f2d 100644 --- a/nixos/modules/system/boot/initrd-network.nix +++ b/nixos/modules/system/boot/initrd-network.nix @@ -6,7 +6,11 @@ let cfg = config.boot.initrd.network; - dhcpinterfaces = lib.attrNames (lib.filterAttrs (iface: v: v.useDHCP == true) (config.networking.interfaces or {})); + dhcpInterfaces = lib.attrNames (lib.filterAttrs (iface: v: v.useDHCP == true) (config.networking.interfaces or {})); + doDhcp = config.networking.useDHCP || dhcpInterfaces != []; + dhcpIfShellExpr = if config.networking.useDHCP + then "$(ls /sys/class/net/ | grep -v ^lo$)" + else lib.concatMapStringsSep " " lib.escapeShellArg dhcpInterfaces; udhcpcScript = pkgs.writeScript "udhcp-script" '' @@ -62,6 +66,16 @@ in ''; }; + boot.initrd.network.flushBeforeStage2 = mkOption { + type = types.bool; + default = true; + description = '' + Whether to clear the configuration of the interfaces that were set up in + the initrd right before stage 2 takes over. Stage 2 will do the regular network + configuration based on the NixOS networking options. + ''; + }; + boot.initrd.network.udhcpc.extraArgs = mkOption { default = []; type = types.listOf types.str; @@ -95,31 +109,29 @@ in boot.initrd.preLVMCommands = mkBefore ( # Search for interface definitions in command line. '' + ifaces="" for o in $(cat /proc/cmdline); do case $o in ip=*) - ipconfig $o && hasNetwork=1 + ipconfig $o && hasNetwork=1 \ + && ifaces="$ifaces $(echo $o | cut -d: -f6)" ;; esac done '' # Otherwise, use DHCP. - + optionalString (config.networking.useDHCP || dhcpinterfaces != []) '' + + optionalString doDhcp '' if [ -z "$hasNetwork" ]; then # Bring up all interfaces. - for iface in $(ls /sys/class/net/); do + for iface in ${dhcpIfShellExpr}; do echo "bringing up network interface $iface..." - ip link set "$iface" up + ip link set "$iface" up && ifaces="$ifaces $iface" done # Acquire DHCP leases. - for iface in ${ if config.networking.useDHCP then - "$(ls /sys/class/net/ | grep -v ^lo$)" - else - lib.concatMapStringsSep " " lib.escapeShellArg dhcpinterfaces - }; do + for iface in ${dhcpIfShellExpr}; do echo "acquiring IP address via DHCP on $iface..." udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1 done @@ -133,6 +145,13 @@ in fi ''); + boot.initrd.postMountCommands = mkIf cfg.flushBeforeStage2 '' + for iface in $ifaces; do + ip address flush "$iface" + ip link down "$iface" + done + ''; + }; } diff --git a/nixos/tests/initrd-network.nix b/nixos/tests/initrd-network.nix index 4796ff9b7c8..9c35b730576 100644 --- a/nixos/tests/initrd-network.nix +++ b/nixos/tests/initrd-network.nix @@ -1,4 +1,4 @@ -import ./make-test-python.nix ({ pkgs, ...} : { +import ./make-test-python.nix ({ pkgs, lib, ...} : { name = "initrd-network"; meta.maintainers = [ pkgs.stdenv.lib.maintainers.eelco ]; @@ -8,15 +8,26 @@ import ./make-test-python.nix ({ pkgs, ...} : { boot.initrd.network.enable = true; boot.initrd.network.postCommands = '' + ip addr show + ip route show ip addr | grep 10.0.2.15 || exit 1 ping -c1 10.0.2.2 || exit 1 ''; + # Check if cleanup was done correctly + boot.initrd.postMountCommands = lib.mkAfter + '' + ip addr show + ip route show + ip addr | grep 10.0.2.15 && exit 1 + ping -c1 10.0.2.2 && exit 1 + ''; }; testScript = '' start_all() machine.wait_for_unit("multi-user.target") - machine.succeed("ip link >&2") + machine.succeed("ip addr show >&2") + machine.succeed("ip route show >&2") ''; })