From 1c4192ada7504e673fe4e574ac7de64217c0d91d Mon Sep 17 00:00:00 2001 From: Christian Theune Date: Fri, 19 Apr 2024 15:29:51 +0200 Subject: [PATCH] network: simplify network interface units to make them more reliable All network interface now use "-netdev.service" units, even if they have underlying physical devices and were previously depending on systemd device units. This proved to be unreliable when trying to transform systems between complex configuration states without requiring a reboot and ended up in undefined states. Includes a backport of https://github.com/NixOS/nixpkgs/pull/240295 Re PL-132441 --- .../tasks/network-interfaces-scripted.nix | 34 ++++++++----------- nixos/modules/tasks/network-interfaces.nix | 2 +- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index 11bd159319a3e..f4ccea530985e 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -67,18 +67,8 @@ let systemd.services = let - deviceDependency = dev: - # Use systemd service if we manage device creation, else - # trust udev when not in a container - if (hasAttr dev (filterAttrs (k: v: v.virtual) cfg.interfaces)) || - (hasAttr dev cfg.bridges) || - (hasAttr dev cfg.bonds) || - (hasAttr dev cfg.macvlans) || - (hasAttr dev cfg.sits) || - (hasAttr dev cfg.vlans) || - (hasAttr dev cfg.vswitches) - then [ "${dev}-netdev.service" ] - else optional (dev != null && dev != "lo" && !config.boot.isContainer) (subsystemDevice dev); + deviceDependency = dev: + if (dev != null && dev != "lo" && !config.boot.isContainer) then [ "${dev}-netdev.service" ] else []; hasDefaultGatewaySet = (cfg.defaultGateway != null && cfg.defaultGateway.address != "") || (cfg.enableIPv6 && cfg.defaultGateway6 != null && cfg.defaultGateway6.address != ""); @@ -94,8 +84,10 @@ let after = [ "network-pre.target" "systemd-udevd.service" "systemd-sysctl.service" ]; before = [ "network.target" "shutdown.target" ]; wants = [ "network.target" ]; + # exclude bridges from the partOf relationship to fix container networking bug #47210 - partOf = map (i: "network-addresses-${i.name}.service") (filter (i: !(hasAttr i.name cfg.bridges)) interfaces); + requiredBy = map (i: "network-addresses-${i.name}.service") (filter (i: !(hasAttr i.name cfg.bridges)) interfaces); + conflicts = [ "shutdown.target" ]; wantedBy = [ "multi-user.target" ] ++ optional hasDefaultGatewaySet "network-online.target"; @@ -174,10 +166,12 @@ let wantedBy = [ "network-setup.service" "network.target" + "multi-user.target" ]; # order before network-setup because the routes that are configured # there may need ip addresses configured before = [ "network-setup.service" ]; + requires = [ "network-setup.service" ]; bindsTo = deviceDependency i.name; after = [ "network-pre.target" ] ++ (deviceDependency i.name); serviceConfig.Type = "oneshot"; @@ -256,7 +250,7 @@ let bindsTo = optional (!config.boot.isContainer) "dev-net-tun.device"; after = optional (!config.boot.isContainer) "dev-net-tun.device" ++ [ "network-pre.target" ]; wantedBy = [ "network-setup.service" (subsystemDevice i.name) ]; - partOf = [ "network-setup.service" ]; + requires = [ "network-setup.service" ]; before = [ "network-setup.service" ]; path = [ pkgs.iproute2 ]; serviceConfig = { @@ -278,7 +272,7 @@ let { description = "Bridge Interface ${n}"; wantedBy = [ "network-setup.service" (subsystemDevice n) ]; bindsTo = deps ++ optional v.rstp "mstpd.service"; - partOf = [ "network-setup.service" ] ++ optional v.rstp "mstpd.service"; + requires = [ "network-setup.service" ] ++ optional v.rstp "mstpd.service"; after = [ "network-pre.target" ] ++ deps ++ optional v.rstp "mstpd.service" ++ map (i: "network-addresses-${i}.service") v.interfaces; before = [ "network-setup.service" ]; @@ -366,7 +360,7 @@ let # should work without internalConfigs dependencies because address/link configuration depends # on the device, which is created by ovs-vswitchd with type=internal, but it does not... before = [ "network-setup.service" ] ++ internalConfigs; - partOf = [ "network-setup.service" ]; # shutdown the bridge when network is shutdown + requires = [ "network-setup.service" ]; # shutdown the bridge when network is shutdown bindsTo = [ "ovs-vswitchd.service" ]; # requires ovs-vswitchd to be alive at all times after = [ "network-pre.target" "ovs-vswitchd.service" ] ++ deps; # start switch after physical interfaces and vswitch daemon wants = deps; # if one or more interface fails, the switch should continue to run @@ -407,7 +401,7 @@ let { description = "Bond Interface ${n}"; wantedBy = [ "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; - partOf = [ "network-setup.service" ]; + requires = [ "network-setup.service" ]; after = [ "network-pre.target" ] ++ deps ++ map (i: "network-addresses-${i}.service") v.interfaces; before = [ "network-setup.service" ]; @@ -446,7 +440,7 @@ let { description = "Vlan Interface ${n}"; wantedBy = [ "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; - partOf = [ "network-setup.service" ]; + requires = [ "network-setup.service" ]; after = [ "network-pre.target" ] ++ deps; before = [ "network-setup.service" ]; serviceConfig.Type = "oneshot"; @@ -471,7 +465,7 @@ let { description = "6-to-4 Tunnel Interface ${n}"; wantedBy = [ "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; - partOf = [ "network-setup.service" ]; + requires = [ "network-setup.service" ]; after = [ "network-pre.target" ] ++ deps; before = [ "network-setup.service" ]; serviceConfig.Type = "oneshot"; @@ -499,7 +493,7 @@ let { description = "Vlan Interface ${n}"; wantedBy = [ "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; - partOf = [ "network-setup.service" ]; + requires = [ "network-setup.service" ]; after = [ "network-pre.target" ] ++ deps; before = [ "network-setup.service" ]; serviceConfig.Type = "oneshot"; diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 879f077332e38..5cd6bca95d782 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -1249,7 +1249,7 @@ in in '' # override to ${msg} for ${i.name} - ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr=${val}" + ACTION=="add", SUBSYSTEM=="net", NAME=="${i.name}", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr=${val}" '') (filter (i: i.tempAddress != cfg.tempAddresses) interfaces); }) ] ++ lib.optional (cfg.wlanInterfaces != {})