summary refs log tree commit diff
diff options
context:
space:
mode:
authorWill Fancher <elvishjerricco@gmail.com>2022-06-29 01:01:59 -0400
committerWill Fancher <elvishjerricco@gmail.com>2023-04-17 16:41:34 -0400
commitdd392d7c7694c762812f84b4d0a3ba8157ac8a73 (patch)
treeb691eeae88e0a58c87410e9f90783fcd1eb6d012
parente70b42bf612e65693c95fab37ff0de725858ed8e (diff)
downloadnixpkgs-dd392d7c7694c762812f84b4d0a3ba8157ac8a73.tar
nixpkgs-dd392d7c7694c762812f84b4d0a3ba8157ac8a73.tar.gz
nixpkgs-dd392d7c7694c762812f84b4d0a3ba8157ac8a73.tar.bz2
nixpkgs-dd392d7c7694c762812f84b4d0a3ba8157ac8a73.tar.lz
nixpkgs-dd392d7c7694c762812f84b4d0a3ba8157ac8a73.tar.xz
nixpkgs-dd392d7c7694c762812f84b4d0a3ba8157ac8a73.tar.zst
nixpkgs-dd392d7c7694c762812f84b4d0a3ba8157ac8a73.zip
systemd-initrd: networkd
-rw-r--r--nixos/modules/services/hardware/udev.nix11
-rw-r--r--nixos/modules/system/boot/networkd.nix132
-rw-r--r--nixos/modules/system/boot/systemd/initrd.nix9
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/predictable-interface-names.nix39
-rw-r--r--nixos/tests/systemd-initrd-networkd.nix45
6 files changed, 184 insertions, 53 deletions
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index d9526133241..95c2a4fc5c3 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -16,16 +16,6 @@ let
   '';
 
 
-  # networkd link files are used early by udev to set up interfaces early.
-  # This must be done in stage 1 to avoid race conditions between udev and
-  # network daemons.
-  # TODO move this into the initrd-network module when it exists
-  initrdLinkUnits = pkgs.runCommand "initrd-link-units" {} ''
-    mkdir -p $out
-    ln -s ${udev}/lib/systemd/network/*.link $out/
-    ${lib.concatMapStringsSep "\n" (file: "ln -s ${file} $out/") (lib.mapAttrsToList (n: v: "${v.unit}/${n}") (lib.filterAttrs (n: _: hasSuffix ".link" n) config.systemd.network.units))}
-  '';
-
   extraUdevRules = pkgs.writeTextFile {
     name = "extra-udev-rules";
     text = cfg.extraRules;
@@ -398,7 +388,6 @@ in
         systemd = config.boot.initrd.systemd.package;
         binPackages = config.boot.initrd.services.udev.binPackages ++ [ config.boot.initrd.systemd.contents."/bin".source ];
       };
-      "/etc/systemd/network".source = initrdLinkUnits;
     };
     # Insert initrd rules
     boot.initrd.services.udev.packages = [
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index 05a667a09ef..e325a33a9e3 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -6,8 +6,6 @@ with lib;
 
 let
 
-  cfg = config.systemd.network;
-
   check = {
 
     global = {
@@ -2941,14 +2939,12 @@ let
         + def.extraConfig;
     };
 
-  unitFiles = listToAttrs (map (name: {
-    name = "systemd/network/${name}";
+  mkUnitFiles = prefix: cfg: listToAttrs (map (name: {
+    name = "${prefix}systemd/network/${name}";
     value.source = "${cfg.units.${name}.unit}/${name}";
   }) (attrNames cfg.units));
-in
 
-{
-  options = {
+  commonOptions = {
 
     systemd.network.enable = mkOption {
       default = false;
@@ -3051,12 +3047,11 @@ in
 
   };
 
-  config = mkMerge [
+  commonConfig = config: let cfg = config.systemd.network; in mkMerge [
 
     # .link units are honored by udev, no matter if systemd-networkd is enabled or not.
     {
       systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links;
-      environment.etc = unitFiles;
 
       systemd.network.wait-online.extraArgs =
         [ "--timeout=${toString cfg.wait-online.timeout}" ]
@@ -3066,14 +3061,6 @@ in
 
     (mkIf config.systemd.network.enable {
 
-      users.users.systemd-network.group = "systemd-network";
-
-      systemd.additionalUpstreamSystemUnits = [
-        "systemd-networkd-wait-online.service"
-        "systemd-networkd.service"
-        "systemd-networkd.socket"
-      ];
-
       systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs
         // mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.networks;
 
@@ -3082,14 +3069,6 @@ in
       # networkd.
       systemd.sockets.systemd-networkd.wantedBy = [ "sockets.target" ];
 
-      systemd.services.systemd-networkd = {
-        wantedBy = [ "multi-user.target" ];
-        aliases = [ "dbus-org.freedesktop.network1.service" ];
-        restartTriggers = map (x: x.source) (attrValues unitFiles) ++ [
-          config.environment.etc."systemd/networkd.conf".source
-        ];
-      };
-
       systemd.services.systemd-networkd-wait-online = {
         inherit (cfg.wait-online) enable;
         wantedBy = [ "network-online.target" ];
@@ -3111,8 +3090,37 @@ in
         };
       };
 
+    })
+  ];
+
+  stage2Config = let
+    cfg = config.systemd.network;
+    unitFiles = mkUnitFiles "" cfg;
+  in mkMerge [
+    (commonConfig config)
+
+    { environment.etc = unitFiles; }
+
+    (mkIf config.systemd.network.enable {
+
+      users.users.systemd-network.group = "systemd-network";
+
+      systemd.additionalUpstreamSystemUnits = [
+        "systemd-networkd-wait-online.service"
+        "systemd-networkd.service"
+        "systemd-networkd.socket"
+      ];
+
       environment.etc."systemd/networkd.conf" = renderConfig cfg.config;
 
+      systemd.services.systemd-networkd = {
+        wantedBy = [ "multi-user.target" ];
+        restartTriggers = map (x: x.source) (attrValues unitFiles) ++ [
+          config.environment.etc."systemd/networkd.conf".source
+        ];
+        aliases = [ "dbus-org.freedesktop.network1.service" ];
+      };
+
       networking.iproute2 = mkIf (cfg.config.addRouteTablesToIPRoute2 && cfg.config.routeTables != { }) {
         enable = mkDefault true;
         rttablesExtraConfig = ''
@@ -3123,6 +3131,80 @@ in
       };
 
       services.resolved.enable = mkDefault true;
+
+    })
+  ];
+
+  stage1Config = let
+    cfg = config.boot.initrd.systemd.network;
+  in mkMerge [
+    (commonConfig config.boot.initrd)
+
+    {
+      systemd.network.enable = mkDefault config.boot.initrd.network.enable;
+      systemd.contents = mkUnitFiles "/etc/" cfg;
+
+      # Networkd link files are used early by udev to set up interfaces early.
+      # This must be done in stage 1 to avoid race conditions between udev and
+      # network daemons.
+      systemd.network.units = lib.filterAttrs (n: _: hasSuffix ".link" n) config.systemd.network.units;
+      systemd.storePaths = ["${config.boot.initrd.systemd.package}/lib/systemd/network/99-default.link"];
+    }
+
+    (mkIf cfg.enable {
+
+      systemd.package = pkgs.systemdStage1Network;
+
+      systemd.additionalUpstreamUnits = [
+        "systemd-networkd-wait-online.service"
+        "systemd-networkd.service"
+        "systemd-networkd.socket"
+        "systemd-network-generator.service"
+        "network-online.target"
+        "network-pre.target"
+        "network.target"
+        "nss-lookup.target"
+        "nss-user-lookup.target"
+        "remote-fs-pre.target"
+        "remote-fs.target"
+      ];
+      systemd.users.systemd-network = {};
+      systemd.groups.systemd-network = {};
+
+      systemd.contents."/etc/systemd/networkd.conf" = renderConfig cfg.config;
+
+      systemd.services.systemd-networkd.wantedBy = [ "initrd.target" ];
+      systemd.services.systemd-network-generator.wantedBy = [ "sysinit.target" ];
+
+      systemd.storePaths = [
+        "${config.boot.initrd.systemd.package}/lib/systemd/systemd-networkd"
+        "${config.boot.initrd.systemd.package}/lib/systemd/systemd-networkd-wait-online"
+        "${config.boot.initrd.systemd.package}/lib/systemd/systemd-network-generator"
+      ];
+      kernelModules = [ "af_packet" ];
+
+    })
+  ];
+
+in
+
+{
+  options = commonOptions // {
+    boot.initrd = commonOptions;
+  };
+
+  config = mkMerge [
+    stage2Config
+    (mkIf config.boot.initrd.systemd.enable {
+      assertions = [{
+        assertion = config.boot.initrd.network.udhcpc.extraArgs == [];
+        message = ''
+          boot.initrd.network.udhcpc.extraArgs is not supported when
+          boot.initrd.systemd.enable is enabled
+        '';
+      }];
+
+      boot.initrd = stage1Config;
     })
   ];
 }
diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix
index e11ab5c824d..d623eddf699 100644
--- a/nixos/modules/system/boot/systemd/initrd.nix
+++ b/nixos/modules/system/boot/systemd/initrd.nix
@@ -72,15 +72,6 @@ let
     "systemd-tmpfiles-setup.service"
     "timers.target"
     "umount.target"
-
-    # TODO: Networking
-    # "network-online.target"
-    # "network-pre.target"
-    # "network.target"
-    # "nss-lookup.target"
-    # "nss-user-lookup.target"
-    # "remote-fs-pre.target"
-    # "remote-fs.target"
   ] ++ cfg.additionalUpstreamUnits;
 
   upstreamWants = [
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 0783f3bf68e..00a637b460f 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -677,6 +677,7 @@ in {
   systemd-initrd-simple = handleTest ./systemd-initrd-simple.nix {};
   systemd-initrd-swraid = handleTest ./systemd-initrd-swraid.nix {};
   systemd-initrd-vconsole = handleTest ./systemd-initrd-vconsole.nix {};
+  systemd-initrd-networkd = handleTest ./systemd-initrd-networkd.nix {};
   systemd-journal = handleTest ./systemd-journal.nix {};
   systemd-machinectl = handleTest ./systemd-machinectl.nix {};
   systemd-networkd = handleTest ./systemd-networkd.nix {};
diff --git a/nixos/tests/predictable-interface-names.nix b/nixos/tests/predictable-interface-names.nix
index 684df9c3924..42183625c7c 100644
--- a/nixos/tests/predictable-interface-names.nix
+++ b/nixos/tests/predictable-interface-names.nix
@@ -8,25 +8,48 @@ let
   testCombinations = pkgs.lib.cartesianProductOfSets {
     predictable = [true false];
     withNetworkd = [true false];
+    systemdStage1 = [true false];
   };
-in pkgs.lib.listToAttrs (builtins.map ({ predictable, withNetworkd }: {
+in pkgs.lib.listToAttrs (builtins.map ({ predictable, withNetworkd, systemdStage1 }: {
   name = pkgs.lib.optionalString (!predictable) "un" + "predictable"
-       + pkgs.lib.optionalString withNetworkd "Networkd";
+       + pkgs.lib.optionalString withNetworkd "Networkd"
+       + pkgs.lib.optionalString systemdStage1 "SystemdStage1";
   value = makeTest {
-    name = "${pkgs.lib.optionalString (!predictable) "un"}predictableInterfaceNames${pkgs.lib.optionalString withNetworkd "-with-networkd"}";
+    name = pkgs.lib.optionalString (!predictable) "un" + "predictableInterfaceNames"
+         + pkgs.lib.optionalString withNetworkd "-with-networkd"
+         + pkgs.lib.optionalString systemdStage1 "-systemd-stage-1";
     meta = {};
 
-    nodes.machine = { lib, ... }: {
+    nodes.machine = { lib, ... }: let
+      script = ''
+        ip link
+        if ${lib.optionalString predictable "!"} ip link show eth0; then
+          echo Success
+        else
+          exit 1
+        fi
+      '';
+    in {
       networking.usePredictableInterfaceNames = lib.mkForce predictable;
       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
-      '';
+      boot.initrd.postDeviceCommands = script;
+
+      boot.initrd.systemd = lib.mkIf systemdStage1 {
+        enable = true;
+        initrdBin = [ pkgs.iproute2 ];
+        services.systemd-udev-settle.wantedBy = ["initrd.target"];
+        services.check-interfaces = {
+          requiredBy = ["initrd.target"];
+          after = ["systemd-udev-settle.service"];
+          serviceConfig.Type = "oneshot";
+          path = [ pkgs.iproute2 ];
+          inherit script;
+        };
+      };
     };
 
     testScript = ''
diff --git a/nixos/tests/systemd-initrd-networkd.nix b/nixos/tests/systemd-initrd-networkd.nix
new file mode 100644
index 00000000000..872a8cd64b2
--- /dev/null
+++ b/nixos/tests/systemd-initrd-networkd.nix
@@ -0,0 +1,45 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "systemd-initrd-network";
+  meta.maintainers = [ lib.maintainers.elvishjerricco ];
+
+  nodes = {
+    basic = { ... }: {
+      boot.initrd.network.enable = true;
+
+      boot.initrd.systemd = {
+        enable = true;
+        network.networks."99-eth0" = {
+          matchConfig.Name = "eth0";
+          DHCP = "yes";
+        };
+        network.wait-online.timeout = 10;
+        # Drop the boot into emergency mode if we timeout
+        targets.network-online.requiredBy = [ "initrd.target" ];
+        services.systemd-networkd-wait-online.requiredBy =
+          [ "network-online.target" ];
+
+          initrdBin = [ pkgs.iproute2 pkgs.iputils pkgs.gnugrep ];
+          services.check = {
+            requiredBy = [ "initrd.target" ];
+            before = [ "initrd.target" ];
+            after = [ "network-online.target" ];
+            serviceConfig.Type = "oneshot";
+            path = [ pkgs.iproute2 pkgs.iputils pkgs.gnugrep ];
+            script = ''
+              ip addr | grep 10.0.2.15 || exit 1
+              ping -c1 10.0.2.2 || exit 1
+            '';
+          };
+      };
+    };
+  };
+
+  testScript = ''
+    start_all()
+    basic.wait_for_unit("multi-user.target")
+    # Make sure the systemd-network user was set correctly in initrd
+    basic.succeed("[ $(stat -c '%U,%G' /run/systemd/netif/links) = systemd-network,systemd-network ]")
+    basic.succeed("ip addr show >&2")
+    basic.succeed("ip route show >&2")
+  '';
+})