diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix index cb8fc957a990b0..0ab6e626b340ee 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; @@ -89,49 +103,45 @@ 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 ( # 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 && ifaces="$ifaces $(echo $o | cut -d: -f6)" ;; esac done '' # Otherwise, use DHCP. - + optionalString (config.networking.useDHCP || dhcpinterfaces != []) '' - if [ -z "$hasNetwork" ]; then - - # Bring up all interfaces. - for iface in $(ls /sys/class/net/); do - echo "bringing up network interface $iface..." - ip link set "$iface" up - done + + optionalString doDhcp '' + # 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 ${ if config.networking.useDHCP then - "$(ls /sys/class/net/ | grep -v ^lo$)" - else - lib.concatMapStringsSep " " lib.escapeShellArg dhcpinterfaces - }; 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 + ip address flush "$iface" + ip link down "$iface" + done + ''; }; diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index 8736613c3d256f..607aec87f01e5a 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 4c2d130d5a5d7b..26117cffeda250 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/initrd-network.nix b/nixos/tests/initrd-network.nix index 4796ff9b7c8dd4..9c35b7305768f8 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") ''; }) diff --git a/nixos/tests/predictable-interface-names.nix b/nixos/tests/predictable-interface-names.nix index 83883477a5ccf9..bab091d57acf1e 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 = '' diff --git a/pkgs/os-specific/linux/klibc/default.nix b/pkgs/os-specific/linux/klibc/default.nix index 8e224c8f33b8d3..a92970726dca4a 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 d3e55fc8731dc7..709dd30f8c7edf 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