From 44e289f93bcf6d04c3eab231bac57dade06fc0c6 Mon Sep 17 00:00:00 2001 From: Franz Pletz Date: Sun, 22 Sep 2019 17:14:47 +0200 Subject: [PATCH 1/5] nixos/stage-1: fix predictable interfaces names This makes predictable interfaces names available as soon as possible with udev by adding the default network link units to initrd which are read by udev. Also adds some udev rules that are needed but which would normally loaded from the udev store path which is not included in the initrd. --- nixos/modules/system/boot/stage-1-init.sh | 6 ++++-- nixos/modules/system/boot/stage-1.nix | 15 +++++++++++++-- nixos/tests/predictable-interface-names.nix | 6 ++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index 8736613c3d25..607aec87f01e 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -210,6 +210,8 @@ done # Create device nodes in /dev. @preDeviceCommands@ echo "running udev..." +mkdir -p /etc/systemd +ln -sfn @linkUnits@ /etc/systemd/network mkdir -p /etc/udev ln -sfn @udevRules@ /etc/udev/rules.d mkdir -p /dev/.mdadm @@ -266,7 +268,7 @@ checkFS() { return 0 fi - # Device might be already mounted manually + # Device might be already mounted manually # e.g. NBD-device or the host filesystem of the file which contains encrypted root fs if mount | grep -q "^$device on "; then echo "skip checking already mounted $device" @@ -351,7 +353,7 @@ mountFS() { elif [ "$fsType" = f2fs ]; then echo "resizing $device..." fsck.f2fs -fp "$device" - resize.f2fs "$device" + resize.f2fs "$device" fi ;; esac diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index 4c2d130d5a5d..26117cffeda2 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -120,6 +120,7 @@ let # Copy udev. copy_bin_and_libs ${udev}/lib/systemd/systemd-udevd + copy_bin_and_libs ${udev}/lib/systemd/systemd-sysctl copy_bin_and_libs ${udev}/bin/udevadm for BIN in ${udev}/lib/udev/*_id; do copy_bin_and_libs $BIN @@ -198,6 +199,14 @@ let ''; # */ + linkUnits = pkgs.runCommand "link-units" { + allowedReferences = [ extraUtils ]; + preferLocalBuild = true; + } '' + mkdir -p $out + cp -v ${udev}/lib/systemd/network/*.link $out/ + ''; + udevRules = pkgs.runCommand "udev-rules" { allowedReferences = [ extraUtils ]; preferLocalBuild = true; @@ -208,7 +217,9 @@ let cp -v ${udev}/lib/udev/rules.d/60-cdrom_id.rules $out/ cp -v ${udev}/lib/udev/rules.d/60-persistent-storage.rules $out/ + cp -v ${udev}/lib/udev/rules.d/75-net-description.rules $out/ cp -v ${udev}/lib/udev/rules.d/80-drivers.rules $out/ + cp -v ${udev}/lib/udev/rules.d/80-net-setup-link.rules $out/ cp -v ${pkgs.lvm2}/lib/udev/rules.d/*.rules $out/ ${config.boot.initrd.extraUdevRulesCommands} @@ -222,7 +233,7 @@ let --replace ${pkgs.lvm2}/sbin ${extraUtils}/bin \ --replace ${pkgs.mdadm}/sbin ${extraUtils}/sbin \ --replace ${pkgs.bash}/bin/sh ${extraUtils}/bin/sh \ - --replace ${udev}/bin/udevadm ${extraUtils}/bin/udevadm + --replace ${udev} ${extraUtils} done # Work around a bug in QEMU, which doesn't implement the "READ @@ -257,7 +268,7 @@ let ${pkgs.buildPackages.busybox}/bin/ash -n $target ''; - inherit udevRules extraUtils modulesClosure; + inherit linkUnits udevRules extraUtils modulesClosure; inherit (config.boot) resumeDevice; diff --git a/nixos/tests/predictable-interface-names.nix b/nixos/tests/predictable-interface-names.nix index 83883477a5cc..bab091d57acf 100644 --- a/nixos/tests/predictable-interface-names.nix +++ b/nixos/tests/predictable-interface-names.nix @@ -17,6 +17,12 @@ in pkgs.lib.listToAttrs (pkgs.lib.crossLists (predictable: withNetworkd: { networking.useNetworkd = withNetworkd; networking.dhcpcd.enable = !withNetworkd; networking.useDHCP = !withNetworkd; + + # Check if predictable interface names are working in stage-1 + boot.initrd.postDeviceCommands = '' + ip link + ip link show eth0 ${if predictable then "&&" else "||"} exit 1 + ''; }; testScript = '' From ea7d02406b000b8b9a951fba262174492ff4572f Mon Sep 17 00:00:00 2001 From: Franz Pletz Date: Sat, 8 Feb 2020 12:11:13 +0100 Subject: [PATCH 2/5] 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. --- nixos/modules/system/boot/initrd-network.nix | 39 +++++++++++++++----- nixos/tests/initrd-network.nix | 15 +++++++- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix index cb8fc957a990..cdffdf29f2d9 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 4796ff9b7c8d..9c35b7305768 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") ''; }) From 4ba8086aa17e014bec3843e16c0c7eddee9bdf40 Mon Sep 17 00:00:00 2001 From: Franz Pletz Date: Sat, 8 Feb 2020 14:30:51 +0100 Subject: [PATCH 3/5] klibc: 2.0.4 -> 2.0.7 --- pkgs/os-specific/linux/klibc/default.nix | 13 ++++++++----- .../linux/klibc/no-reinstall-kernel-headers.patch | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pkgs/os-specific/linux/klibc/default.nix b/pkgs/os-specific/linux/klibc/default.nix index 8e224c8f33b8..a92970726dca 100644 --- a/pkgs/os-specific/linux/klibc/default.nix +++ b/pkgs/os-specific/linux/klibc/default.nix @@ -1,4 +1,4 @@ -{ stdenv, fetchurl, linuxHeaders, perl }: +{ lib, stdenv, fetchurl, linuxHeaders, perl }: let commonMakeFlags = [ @@ -9,11 +9,11 @@ in stdenv.mkDerivation rec { pname = "klibc"; - version = "2.0.4"; + version = "2.0.7"; src = fetchurl { url = "mirror://kernel/linux/libs/klibc/2.0/klibc-${version}.tar.xz"; - sha256 = "7f9a0850586def7cf4faeeb75e5d0f66e613674c524f6e77b0f4d93a26c801cb"; + sha256 = "08li3aj9bvzabrih98jdxi3m19h85cp53s8cr7cqad42r8vjdvxb"; }; patches = [ ./no-reinstall-kernel-headers.patch ]; @@ -35,7 +35,6 @@ stdenv.mkDerivation rec { dir=$out/lib/klibc/bin.static mkdir $dir cp $(find $(find . -name static) -type f ! -name "*.g" -a ! -name ".*") $dir/ - cp usr/dash/sh $dir/ for file in ${linuxHeaders}/include/*; do ln -sv $file $out/lib/klibc/include @@ -43,6 +42,10 @@ stdenv.mkDerivation rec { ''; meta = { - platforms = [ "x86_64-linux" ]; + description = "Minimalistic libc subset for initramfs usage"; + homepage = "https://kernel.org/pub/linux/libs/klibc/"; + maintainers = with lib.maintainers; [ fpletz ]; + license = lib.licenses.bsd3; + platforms = lib.platforms.linux; }; } diff --git a/pkgs/os-specific/linux/klibc/no-reinstall-kernel-headers.patch b/pkgs/os-specific/linux/klibc/no-reinstall-kernel-headers.patch index d3e55fc8731d..709dd30f8c7e 100644 --- a/pkgs/os-specific/linux/klibc/no-reinstall-kernel-headers.patch +++ b/pkgs/os-specific/linux/klibc/no-reinstall-kernel-headers.patch @@ -5,7 +5,7 @@ diff -Naur klibc-2.0.3-orig/scripts/Kbuild.install klibc-2.0.3/scripts/Kbuild.in $(Q)mkdir -p $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)include $(Q)mkdir -p $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)lib $(Q)mkdir -p $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)bin -- $(Q)$(MAKE) -C $(KLIBCKERNELSRC) ARCH=$(KLIBCARCH) INSTALL_HDR_PATH=$(INSTALLROOT)$(INSTALLDIR)/$(KCROSS) headers_install +- $(Q)cp -rfL $(KLIBCKERNELSRC)/include/. $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)include/. $(Q)cp -rf usr/include/. $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)include/. $(Q)chmod -R a+rX $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)include $(Q)$(install-data) $(srctree)/klcc/klcc.1 $(INSTALLROOT)$(mandir)/man1/$(KCROSS)klcc.1 From d25c1a8fdc383b8997f6e7b4e1479875df1f06b2 Mon Sep 17 00:00:00 2001 From: Franz Pletz Date: Sat, 8 Feb 2020 14:29:04 +0100 Subject: [PATCH 4/5] nixos/initrd-network: use ipconfig from klibc This apparently has features that the version from Arch's mkinitcpio-nfs-utils does not have. Fixes #75314. --- nixos/modules/system/boot/initrd-network.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix index cdffdf29f2d9..d36850c2a16f 100644 --- a/nixos/modules/system/boot/initrd-network.nix +++ b/nixos/modules/system/boot/initrd-network.nix @@ -103,7 +103,7 @@ in boot.initrd.kernelModules = [ "af_packet" ]; boot.initrd.extraUtilsCommands = '' - copy_bin_and_libs ${pkgs.mkinitcpio-nfs-utils}/bin/ipconfig + copy_bin_and_libs ${pkgs.klibc}/lib/klibc/bin.static/ipconfig ''; boot.initrd.preLVMCommands = mkBefore ( From 589789997fe882668eae25f1f0578230d8576506 Mon Sep 17 00:00:00 2001 From: Franz Pletz Date: Sat, 8 Feb 2020 14:55:29 +0100 Subject: [PATCH 5/5] nixos/initrd-network: always run postCommands As outlined in #71447, postCommands should always be run if networking in initrd is enabled. regardless if the configuration actually succeeded. --- nixos/modules/system/boot/initrd-network.nix | 33 +++++++------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix index d36850c2a16f..0ab6e626b340 100644 --- a/nixos/modules/system/boot/initrd-network.nix +++ b/nixos/modules/system/boot/initrd-network.nix @@ -113,8 +113,7 @@ in for o in $(cat /proc/cmdline); do case $o in ip=*) - ipconfig $o && hasNetwork=1 \ - && ifaces="$ifaces $(echo $o | cut -d: -f6)" + ipconfig $o && ifaces="$ifaces $(echo $o | cut -d: -f6)" ;; esac done @@ -122,28 +121,20 @@ in # Otherwise, use DHCP. + optionalString doDhcp '' - if [ -z "$hasNetwork" ]; then + # Bring up all interfaces. + for iface in ${dhcpIfShellExpr}; do + echo "bringing up network interface $iface..." + ip link set "$iface" up && ifaces="$ifaces $iface" + done - # Bring up all interfaces. - for iface in ${dhcpIfShellExpr}; do - echo "bringing up network interface $iface..." - ip link set "$iface" up && ifaces="$ifaces $iface" - done - - # Acquire DHCP leases. - 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 - fi + # Acquire DHCP leases. + for iface in ${dhcpIfShellExpr}; do + echo "acquiring IP address via DHCP on $iface..." + udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs} + done '' - + '' - if [ -n "$hasNetwork" ]; then - echo "networking is up!" - ${cfg.postCommands} - fi - ''); + + cfg.postCommands); boot.initrd.postMountCommands = mkIf cfg.flushBeforeStage2 '' for iface in $ifaces; do