systemd-initrd: networkd
This commit is contained in:
parent
e70b42bf61
commit
dd392d7c76
6 changed files with 184 additions and 53 deletions
|
@ -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 = [
|
||||
|
|
|
@ -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;
|
||||
})
|
||||
];
|
||||
}
|
||||
|
|
|
@ -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 = [
|
||||
|
|
|
@ -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 {};
|
||||
|
|
|
@ -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 = ''
|
||||
|
|
45
nixos/tests/systemd-initrd-networkd.nix
Normal file
45
nixos/tests/systemd-initrd-networkd.nix
Normal file
|
@ -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")
|
||||
'';
|
||||
})
|
Loading…
Reference in a new issue