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.
This commit is contained in:
Franz Pletz 2020-02-08 12:11:13 +01:00
parent 44e289f93b
commit ea7d02406b
No known key found for this signature in database
GPG Key ID: 846FDED7792617B4
2 changed files with 42 additions and 12 deletions

View File

@ -6,7 +6,11 @@ let
cfg = config.boot.initrd.network; 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" 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 { boot.initrd.network.udhcpc.extraArgs = mkOption {
default = []; default = [];
type = types.listOf types.str; type = types.listOf types.str;
@ -95,31 +109,29 @@ in
boot.initrd.preLVMCommands = mkBefore ( boot.initrd.preLVMCommands = mkBefore (
# Search for interface definitions in command line. # Search for interface definitions in command line.
'' ''
ifaces=""
for o in $(cat /proc/cmdline); do for o in $(cat /proc/cmdline); do
case $o in case $o in
ip=*) ip=*)
ipconfig $o && hasNetwork=1 ipconfig $o && hasNetwork=1 \
&& ifaces="$ifaces $(echo $o | cut -d: -f6)"
;; ;;
esac esac
done done
'' ''
# Otherwise, use DHCP. # Otherwise, use DHCP.
+ optionalString (config.networking.useDHCP || dhcpinterfaces != []) '' + optionalString doDhcp ''
if [ -z "$hasNetwork" ]; then if [ -z "$hasNetwork" ]; then
# Bring up all interfaces. # Bring up all interfaces.
for iface in $(ls /sys/class/net/); do for iface in ${dhcpIfShellExpr}; do
echo "bringing up network interface $iface..." echo "bringing up network interface $iface..."
ip link set "$iface" up ip link set "$iface" up && ifaces="$ifaces $iface"
done done
# Acquire DHCP leases. # Acquire DHCP leases.
for iface in ${ if config.networking.useDHCP then for iface in ${dhcpIfShellExpr}; do
"$(ls /sys/class/net/ | grep -v ^lo$)"
else
lib.concatMapStringsSep " " lib.escapeShellArg dhcpinterfaces
}; do
echo "acquiring IP address via DHCP on $iface..." echo "acquiring IP address via DHCP on $iface..."
udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1 udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1
done done
@ -133,6 +145,13 @@ in
fi fi
''); '');
boot.initrd.postMountCommands = mkIf cfg.flushBeforeStage2 ''
for iface in $ifaces; do
ip address flush "$iface"
ip link down "$iface"
done
'';
}; };
} }

View File

@ -1,4 +1,4 @@
import ./make-test-python.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, lib, ...} : {
name = "initrd-network"; name = "initrd-network";
meta.maintainers = [ pkgs.stdenv.lib.maintainers.eelco ]; 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.enable = true;
boot.initrd.network.postCommands = boot.initrd.network.postCommands =
'' ''
ip addr show
ip route show
ip addr | grep 10.0.2.15 || exit 1 ip addr | grep 10.0.2.15 || exit 1
ping -c1 10.0.2.2 || 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 = testScript =
'' ''
start_all() start_all()
machine.wait_for_unit("multi-user.target") machine.wait_for_unit("multi-user.target")
machine.succeed("ip link >&2") machine.succeed("ip addr show >&2")
machine.succeed("ip route show >&2")
''; '';
}) })