nixos/initrd-network: flush interfaces before stage 2

Depending on the network management backend being used, if the interface
configuration in stage 1 is not cleared, there might still be some old
addresses or routes from stage 1 present in stage 2 after network
configuration has finished.

+42 -12
+29 -10
nixos/modules/system/boot/initrd-network.nix
··· 6 6 7 7 cfg = config.boot.initrd.network; 8 8 9 - dhcpinterfaces = lib.attrNames (lib.filterAttrs (iface: v: v.useDHCP == true) (config.networking.interfaces or {})); 9 + dhcpInterfaces = lib.attrNames (lib.filterAttrs (iface: v: v.useDHCP == true) (config.networking.interfaces or {})); 10 + doDhcp = config.networking.useDHCP || dhcpInterfaces != []; 11 + dhcpIfShellExpr = if config.networking.useDHCP 12 + then "$(ls /sys/class/net/ | grep -v ^lo$)" 13 + else lib.concatMapStringsSep " " lib.escapeShellArg dhcpInterfaces; 10 14 11 15 udhcpcScript = pkgs.writeScript "udhcp-script" 12 16 '' ··· 62 66 ''; 63 67 }; 64 68 69 + boot.initrd.network.flushBeforeStage2 = mkOption { 70 + type = types.bool; 71 + default = true; 72 + description = '' 73 + Whether to clear the configuration of the interfaces that were set up in 74 + the initrd right before stage 2 takes over. Stage 2 will do the regular network 75 + configuration based on the NixOS networking options. 76 + ''; 77 + }; 78 + 65 79 boot.initrd.network.udhcpc.extraArgs = mkOption { 66 80 default = []; 67 81 type = types.listOf types.str; ··· 95 109 boot.initrd.preLVMCommands = mkBefore ( 96 110 # Search for interface definitions in command line. 97 111 '' 112 + ifaces="" 98 113 for o in $(cat /proc/cmdline); do 99 114 case $o in 100 115 ip=*) 101 - ipconfig $o && hasNetwork=1 116 + ipconfig $o && hasNetwork=1 \ 117 + && ifaces="$ifaces $(echo $o | cut -d: -f6)" 102 118 ;; 103 119 esac 104 120 done 105 121 '' 106 122 107 123 # Otherwise, use DHCP. 108 - + optionalString (config.networking.useDHCP || dhcpinterfaces != []) '' 124 + + optionalString doDhcp '' 109 125 if [ -z "$hasNetwork" ]; then 110 126 111 127 # Bring up all interfaces. 112 - for iface in $(ls /sys/class/net/); do 128 + for iface in ${dhcpIfShellExpr}; do 113 129 echo "bringing up network interface $iface..." 114 - ip link set "$iface" up 130 + ip link set "$iface" up && ifaces="$ifaces $iface" 115 131 done 116 132 117 133 # Acquire DHCP leases. 118 - for iface in ${ if config.networking.useDHCP then 119 - "$(ls /sys/class/net/ | grep -v ^lo$)" 120 - else 121 - lib.concatMapStringsSep " " lib.escapeShellArg dhcpinterfaces 122 - }; do 134 + for iface in ${dhcpIfShellExpr}; do 123 135 echo "acquiring IP address via DHCP on $iface..." 124 136 udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1 125 137 done ··· 132 144 ${cfg.postCommands} 133 145 fi 134 146 ''); 147 + 148 + boot.initrd.postMountCommands = mkIf cfg.flushBeforeStage2 '' 149 + for iface in $ifaces; do 150 + ip address flush "$iface" 151 + ip link down "$iface" 152 + done 153 + ''; 135 154 136 155 }; 137 156
+13 -2
nixos/tests/initrd-network.nix
··· 1 - import ./make-test-python.nix ({ pkgs, ...} : { 1 + import ./make-test-python.nix ({ pkgs, lib, ...} : { 2 2 name = "initrd-network"; 3 3 4 4 meta.maintainers = [ pkgs.stdenv.lib.maintainers.eelco ]; ··· 8 8 boot.initrd.network.enable = true; 9 9 boot.initrd.network.postCommands = 10 10 '' 11 + ip addr show 12 + ip route show 11 13 ip addr | grep 10.0.2.15 || exit 1 12 14 ping -c1 10.0.2.2 || exit 1 13 15 ''; 16 + # Check if cleanup was done correctly 17 + boot.initrd.postMountCommands = lib.mkAfter 18 + '' 19 + ip addr show 20 + ip route show 21 + ip addr | grep 10.0.2.15 && exit 1 22 + ping -c1 10.0.2.2 && exit 1 23 + ''; 14 24 }; 15 25 16 26 testScript = 17 27 '' 18 28 start_all() 19 29 machine.wait_for_unit("multi-user.target") 20 - machine.succeed("ip link >&2") 30 + machine.succeed("ip addr show >&2") 31 + machine.succeed("ip route show >&2") 21 32 ''; 22 33 })