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 7 cfg = config.boot.initrd.network; 8 9 - dhcpinterfaces = lib.attrNames (lib.filterAttrs (iface: v: v.useDHCP == true) (config.networking.interfaces or {})); 10 11 udhcpcScript = pkgs.writeScript "udhcp-script" 12 '' ··· 62 ''; 63 }; 64 65 boot.initrd.network.udhcpc.extraArgs = mkOption { 66 default = []; 67 type = types.listOf types.str; ··· 95 boot.initrd.preLVMCommands = mkBefore ( 96 # Search for interface definitions in command line. 97 '' 98 for o in $(cat /proc/cmdline); do 99 case $o in 100 ip=*) 101 - ipconfig $o && hasNetwork=1 102 ;; 103 esac 104 done 105 '' 106 107 # Otherwise, use DHCP. 108 - + optionalString (config.networking.useDHCP || dhcpinterfaces != []) '' 109 if [ -z "$hasNetwork" ]; then 110 111 # Bring up all interfaces. 112 - for iface in $(ls /sys/class/net/); do 113 echo "bringing up network interface $iface..." 114 - ip link set "$iface" up 115 done 116 117 # 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 123 echo "acquiring IP address via DHCP on $iface..." 124 udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1 125 done ··· 132 ${cfg.postCommands} 133 fi 134 ''); 135 136 }; 137
··· 6 7 cfg = config.boot.initrd.network; 8 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; 14 15 udhcpcScript = pkgs.writeScript "udhcp-script" 16 '' ··· 66 ''; 67 }; 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 + 79 boot.initrd.network.udhcpc.extraArgs = mkOption { 80 default = []; 81 type = types.listOf types.str; ··· 109 boot.initrd.preLVMCommands = mkBefore ( 110 # Search for interface definitions in command line. 111 '' 112 + ifaces="" 113 for o in $(cat /proc/cmdline); do 114 case $o in 115 ip=*) 116 + ipconfig $o && hasNetwork=1 \ 117 + && ifaces="$ifaces $(echo $o | cut -d: -f6)" 118 ;; 119 esac 120 done 121 '' 122 123 # Otherwise, use DHCP. 124 + + optionalString doDhcp '' 125 if [ -z "$hasNetwork" ]; then 126 127 # Bring up all interfaces. 128 + for iface in ${dhcpIfShellExpr}; do 129 echo "bringing up network interface $iface..." 130 + ip link set "$iface" up && ifaces="$ifaces $iface" 131 done 132 133 # Acquire DHCP leases. 134 + for iface in ${dhcpIfShellExpr}; do 135 echo "acquiring IP address via DHCP on $iface..." 136 udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1 137 done ··· 144 ${cfg.postCommands} 145 fi 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 + ''; 154 155 }; 156
+13 -2
nixos/tests/initrd-network.nix
··· 1 - import ./make-test-python.nix ({ pkgs, ...} : { 2 name = "initrd-network"; 3 4 meta.maintainers = [ pkgs.stdenv.lib.maintainers.eelco ]; ··· 8 boot.initrd.network.enable = true; 9 boot.initrd.network.postCommands = 10 '' 11 ip addr | grep 10.0.2.15 || exit 1 12 ping -c1 10.0.2.2 || exit 1 13 ''; 14 }; 15 16 testScript = 17 '' 18 start_all() 19 machine.wait_for_unit("multi-user.target") 20 - machine.succeed("ip link >&2") 21 ''; 22 })
··· 1 + import ./make-test-python.nix ({ pkgs, lib, ...} : { 2 name = "initrd-network"; 3 4 meta.maintainers = [ pkgs.stdenv.lib.maintainers.eelco ]; ··· 8 boot.initrd.network.enable = true; 9 boot.initrd.network.postCommands = 10 '' 11 + ip addr show 12 + ip route show 13 ip addr | grep 10.0.2.15 || exit 1 14 ping -c1 10.0.2.2 || exit 1 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 + ''; 24 }; 25 26 testScript = 27 '' 28 start_all() 29 machine.wait_for_unit("multi-user.target") 30 + machine.succeed("ip addr show >&2") 31 + machine.succeed("ip route show >&2") 32 ''; 33 })