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;
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
'';
};
}

View file

@ -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")
'';
})