From 355908755a54d1f0c7311284185fcc5b60fb5f68 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Mon, 5 Jan 2026 09:57:43 +0100 Subject: [PATCH 1/4] nixos/network-interfaces: remove network-setup This change solves some big design flaws in the scripted networking backend. 1. When the module was reworked in 072c1dcc4a31 to use the new systemd targets, network-setup.service was used to: a. order the services and link network.target to the boot sequence b. perform some perform final network configuration, specifically setting the default gateways and nameservers (/etc/resolv.conf). Later (ec00b4bb1186) however, network-setup.service was made optional: if resolvconf is not used and a default gateway is not set, the service is not be defined (because it would result in an empty script). Doing so, however, has the unintended effect of unlinking network.target from multi-uset.target, meaning no network configuration at all is performed. Note: this can be easily seen by adding `networking.resolvconf.enable = false` to the nixosTests.networking.scripted.static test. 2. The network-addresses-*.service are linked to network.target, which, in turn, is linked to multi-uset.target. This means that if a hardware interface is not found, the boot will hang until this service times out (issue #154737). To solve issue 1. this change removes network-target entirely while - moving the default gateway setup into the relative network-addresses-*.service unit; - moving the nameservers setup into networking.localCommands; (incidentally, this also fixes issue #445496) - directly linking network.target to multi-user.target. To solve issue 2. this removes the Wants=network.target dependency of network-addresses-*.service and solely relies on the underlying interface unit (*-netdev.service for virtual, *.device for physical) to start the service. Note: for NixOS containers, the dependency is kept, because the .device unit are not available in this case. Finally, if an interface is the default gateway, network-online.target is added as an extra dependency, so the target is not reached until the interface has been plugged in and configured. --- .../tasks/network-interfaces-scripted.nix | 290 +++++++++--------- nixos/modules/tasks/network-interfaces.nix | 21 +- .../networking/networkd-and-scripted.nix | 47 ++- 3 files changed, 212 insertions(+), 146 deletions(-) diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index 4b457e078e77..fe6f6e5a1cb8 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -51,6 +51,71 @@ let (lib.concatStringsSep " ") ]; + # Converts an IPv4 address literal to a list of bits + parseAddr.ipv4 = + addr: + let + pad = b: lib.replicate (8 - builtins.length b) 0 ++ b; + toBin = n: pad (lib.toBaseDigits 2 (lib.toInt n)); + in + lib.concatMap toBin (builtins.splitVersion addr); + + # Converts an IPv6 address literal to a list of bits + parseAddr.ipv6 = + addr: + let + pad = b: lib.replicate (16 - builtins.length b) 0 ++ b; + fromHex = n: (builtins.fromTOML "n = 0x${n}").n; + toBin = n: pad (lib.toBaseDigits 2 (fromHex n)); + normal = (lib.network.ipv6.fromString addr).address; + in + lib.concatMap toBin (lib.splitString ":" normal); + + # Checks if `addr` is part of the `net` subnet + inSubnet = + v: net: addr: + let + prefix = lib.take net.prefixLength (parseAddr.${v} net.address); + match = lib.zipListsWith (a: b: a == b) prefix (parseAddr.${v} addr); + in + lib.all lib.id match; + + # Checks if the netmask of all addresses on interface `iface` includes + # the IP address of `gateway` + # + # Note: this is used to check whether networking.defaultGateway relies on + # the given interface, either explicitly, via the `interface` (optional), + # or explicitly, by using an address in a subnet of this interface. + # + # Configuration of the default gateway is then performed as part of that + # interface setup in `configureAddrs`, below. + isGateway = + v: gateway: iface: + lib.any lib.id ( + [ (iface.name == gateway.interface) ] + ++ map (net: inSubnet v net gateway.address) iface.${v}.addresses + ); + + # Checks if `gateway` uses an address from `iface` as default source + # + # Note: this is needed to delay the configuration of the gateway and default + # source until the right interfaces and address have been set up, otherwise + # the commands will fail. + hasSource = + v: gateway: iface: + builtins.elem gateway.source (map (i: i.address) iface.${v}.addresses); + + # Interfaces corresponding to the default gateways + gateway4Iface = builtins.filter (isGateway "ipv4" cfg.defaultGateway) interfaces; + gateway6Iface = builtins.filter (isGateway "ipv6" cfg.defaultGateway6) interfaces; + + # Interfaces corresponding to the default source addresses + # + # Note: the use of `head` here is safe because these expressions + # are evaluated only when `needsSourceIface`, see `configureAddrs` below. + source4Iface = builtins.head (builtins.filter (hasSource "ipv4" cfg.defaultGateway) interfaces); + source6Iface = builtins.head (builtins.filter (hasSource "ipv6" cfg.defaultGateway6) interfaces); + # warn that these attributes are deprecated (2017-2-2) # Should be removed in the release after next bondDeprecation = rec { @@ -118,121 +183,70 @@ let else optional (!config.boot.isContainer) (subsystemDevice dev); - hasDefaultGatewaySet = - (cfg.defaultGateway != null && cfg.defaultGateway.address != "") - || (cfg.enableIPv6 && cfg.defaultGateway6 != null && cfg.defaultGateway6.address != ""); - - needNetworkSetup = - cfg.resolvconf.enable || cfg.defaultGateway != null || cfg.defaultGateway6 != null; - - networkLocalCommands = lib.mkIf needNetworkSetup { - after = [ "network-setup.service" ]; - bindsTo = [ "network-setup.service" ]; - }; - - networkSetup = lib.mkIf needNetworkSetup { - description = "Networking Setup"; - - after = [ "network-pre.target" ]; - 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 - ); - conflicts = [ "shutdown.target" ]; - wantedBy = [ "multi-user.target" ] ++ optional hasDefaultGatewaySet "network-online.target"; - - unitConfig.ConditionCapability = "CAP_NET_ADMIN"; - - path = [ pkgs.iproute2 ]; - - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - - unitConfig.DefaultDependencies = false; - - script = '' - ${optionalString config.networking.resolvconf.enable '' - # Set the static DNS configuration, if given. - ${pkgs.openresolv}/sbin/resolvconf -m 1 -a static <, create a job ‘network-addresses-.service" - # that performs static address configuration. It has a "wants" - # dependency on ‘.service’, which is supposed to create - # the interface and need not exist (i.e. for hardware - # interfaces). It has a binds-to dependency on the actual - # network device, so it only gets started after the interface - # has appeared, and it's stopped when the interface - # disappears. + # For each interface , creates a network-addresses-.service + # job that performs static address configuration. + # + # It has a Wants dependency on -netdev.service, which creates + # create the interface, or on a device unit (for hardware interfaces). + # It also has a BindsTo dependency on the device unit: so, it only gets + # started after the interface has appeared and it's stopped when the + # interface disappears. + # + # Unless in a container, the job is not made part of network.target, so + # if an interface is not found (e.g. a USB interface not plugged in) it + # will not hang the boot sequence. + # + # If the interface is the default gateway, the job will also set the + # default gateway and delay network-online.target. configureAddrs = i: let ips = interfaceIps i; + isDefaultGateway4 = cfg.defaultGateway != null && builtins.elem i gateway4Iface; + isDefaultGateway6 = cfg.defaultGateway6 != null && builtins.elem i gateway6Iface; + needsSourceIface4 = + isDefaultGateway4 && cfg.defaultGateway.source != null && i.name != source4Iface.name; + needsSourceIface6 = + isDefaultGateway6 && cfg.defaultGateway6.source != null && i.name != source6Iface.name; + + configureGateway = + version: gateway: + optionalString (gateway.address != "") '' + echo -n "setting ${i.name} as default IPv${version} gateway... " + ${optionalString (gateway.interface != null) '' + ip -${version} route replace ${gateway.address} proto static ${ + formatIpArgs { + metric = gateway.metric; + dev = gateway.interface; + } + } + ''} + ip -${version} route replace default proto static ${ + formatIpArgs { + metric = gateway.metric; + via = gateway.address; + window = cfg.defaultGatewayWindowSize; + dev = gateway.interface; + src = gateway.source; + } + } + echo "done" + ''; in nameValuePair "network-addresses-${i.name}" { description = "Address configuration of ${i.name}"; - wantedBy = [ - "network-setup.service" - "network.target" - ]; - # order before network-setup because the routes that are configured - # there may need ip addresses configured - before = [ "network-setup.service" ]; + + wantedBy = + deviceDependency i.name + ++ optional config.boot.isContainer "network.target" + ++ optional (isDefaultGateway4 || isDefaultGateway6) "network-online.target"; bindsTo = deviceDependency i.name; - after = [ "network-pre.target" ] ++ (deviceDependency i.name); + after = [ + "network-pre.target" + ] + ++ optional needsSourceIface4 "network-addresses-${source4Iface.name}.service" + ++ optional needsSourceIface6 "network-addresses-${source6Iface.name}.service" + ++ deviceDependency i.name; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; # Restart rather than stop+start this unit to prevent the @@ -284,6 +298,10 @@ let fi '' )} + + # Set the default gateway + ${optionalString isDefaultGateway4 (configureGateway "4" cfg.defaultGateway)} + ${optionalString isDefaultGateway6 (configureGateway "6" cfg.defaultGateway6)} ''; preStop = '' state="/run/nixos/network/routes/${i.name}" @@ -314,10 +332,9 @@ let after = optional (!config.boot.isContainer) "dev-net-tun.device" ++ [ "network-pre.target" ]; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice i.name) ]; - before = [ "network-setup.service" ]; + before = [ "network.target" ]; path = [ pkgs.iproute2 ]; serviceConfig = { Type = "oneshot"; @@ -343,18 +360,18 @@ let description = "Bridge Interface ${n}"; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice n) ]; bindsTo = deps ++ optional v.rstp "mstpd.service"; - partOf = [ "network-setup.service" ] ++ optional v.rstp "mstpd.service"; + partOf = [ "network.target" ] + ++ 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" ]; + before = [ "network.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; path = [ pkgs.iproute2 ]; @@ -448,15 +465,11 @@ let description = "Open vSwitch Interface ${n}"; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice n) ] ++ internalConfigs; - # before = [ "network-setup.service" ]; - # 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 + before = [ "network.target" ] ++ internalConfigs; + partOf = [ "network.target" ]; # shutdown the bridge when network is shutdown bindsTo = [ "ovs-vswitchd.service" ]; # requires ovs-vswitchd to be alive at all times after = [ "network-pre.target" @@ -521,12 +534,11 @@ let description = "Bond Interface ${n}"; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; after = [ "network-pre.target" ] ++ deps ++ map (i: "network-addresses-${i}.service") v.interfaces; - before = [ "network-setup.service" ]; + before = [ "network.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; path = [ @@ -570,12 +582,11 @@ let description = "MACVLAN Interface ${n}"; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; after = [ "network-pre.target" ] ++ deps; - before = [ "network-setup.service" ]; + before = [ "network.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; path = [ pkgs.iproute2 ]; @@ -602,12 +613,12 @@ let description = "IPVLAN Interface ${n}"; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; + partOf = [ "networking-scripted.target" ]; after = [ "network-pre.target" ] ++ deps; - before = [ "network-setup.service" ]; + before = [ "network.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; path = [ pkgs.iproute2 ]; @@ -647,12 +658,11 @@ let description = "FOU endpoint ${n}"; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; after = [ "network-pre.target" ] ++ deps; - before = [ "network-setup.service" ]; + before = [ "network.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; path = [ pkgs.iproute2 ]; @@ -677,12 +687,11 @@ let description = "IPv6 in IPv4 Tunnel Interface ${n}"; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; after = [ "network-pre.target" ] ++ deps; - before = [ "network-setup.service" ]; + before = [ "network.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; path = [ pkgs.iproute2 ]; @@ -720,12 +729,11 @@ let description = "IP in IP Tunnel Interface ${n}"; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; after = [ "network-pre.target" ] ++ deps; - before = [ "network-setup.service" ]; + before = [ "network.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; path = [ pkgs.iproute2 ]; @@ -768,12 +776,11 @@ let description = "GRE Tunnel Interface ${n}"; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; after = [ "network-pre.target" ] ++ deps; - before = [ "network-setup.service" ]; + before = [ "network.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; path = [ pkgs.iproute2 ]; @@ -803,13 +810,12 @@ let description = "VLAN Interface ${n}"; wantedBy = [ "network.target" - "network-setup.service" (subsystemDevice n) ]; bindsTo = deps; - partOf = [ "network-setup.service" ]; + partOf = [ "network.target" ]; after = [ "network-pre.target" ] ++ deps; - before = [ "network-setup.service" ]; + before = [ "network.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; path = [ pkgs.iproute2 ]; @@ -845,10 +851,20 @@ let // mapAttrs' createGreDevice cfg.greTunnels // mapAttrs' createVlanDevice cfg.vlans // { - network-setup = networkSetup; - network-local-commands = networkLocalCommands; + network-local-commands = { + after = [ "network-pre.target" ]; + wantedBy = [ "network.target" ]; + }; }; + # Note: the scripted networking backend consistent of many + # independent services that are linked to the network.target. + # Since there is no daemon (e.g systemd-networkd) that is + # started as part of the system and pulls in network.target. + # Thus, to start these services we link network.target directly + # to multi-user.target, this has the same result. + systemd.targets.network.wantedBy = [ "multi-user.target" ]; + services.udev.extraRules = '' KERNEL=="tun", TAG+="systemd" ''; diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 83d60ba80e40..d0fe0ed8443f 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -747,10 +747,9 @@ in default = ""; example = "text=anything; echo You can put $text here."; description = '' - Shell commands to be executed at the end of the - `network-setup` systemd service. Note that if - you are using DHCP to obtain the network configuration, - interfaces may not be fully configured yet. + Shell commands to be executed after all the network + interfaces have been created, but not necessarily + fully configured. ''; }; @@ -1851,6 +1850,20 @@ in ''; }; }; + + networking.localCommands = lib.mkIf config.networking.resolvconf.enable '' + # Set the static DNS configuration, if given. + ${pkgs.openresolv}/sbin/resolvconf -m 1 -a static < Date: Wed, 21 Jan 2026 00:49:00 +0100 Subject: [PATCH 2/4] nixos/networking-interfaces: add networking-scripted.target This adds a target that groups together all the services of the scripted backend. It has no role during the boot, but provides a quick way to reset the network configuration. For example, if addresses/routes are added/removed or an interface has been stopped manually, running systemctl restart networking-scripted.target will undo all the changes. --- .../tasks/network-interfaces-scripted.nix | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index fe6f6e5a1cb8..4bf274d4157f 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -241,6 +241,7 @@ let ++ optional config.boot.isContainer "network.target" ++ optional (isDefaultGateway4 || isDefaultGateway6) "network-online.target"; bindsTo = deviceDependency i.name; + partOf = [ "networking-scripted.target" ]; after = [ "network-pre.target" ] @@ -329,6 +330,7 @@ let nameValuePair "${i.name}-netdev" { description = "Virtual Network Interface ${i.name}"; bindsTo = optional (!config.boot.isContainer) "dev-net-tun.device"; + partOf = [ "networking-scripted.target" ]; after = optional (!config.boot.isContainer) "dev-net-tun.device" ++ [ "network-pre.target" ]; wantedBy = [ "network.target" @@ -363,7 +365,10 @@ let (subsystemDevice n) ]; bindsTo = deps ++ optional v.rstp "mstpd.service"; - partOf = [ "network.target" ] + partOf = [ + "network.target" + "networking-scripted.target" + ] ++ optional v.rstp "mstpd.service"; after = [ "network-pre.target" @@ -469,7 +474,10 @@ let ] ++ internalConfigs; before = [ "network.target" ] ++ internalConfigs; - partOf = [ "network.target" ]; # shutdown the bridge when network is shutdown + partOf = [ + "network.target" + "networking-scripted.target" + ]; # shutdown the bridge when network is shutdown bindsTo = [ "ovs-vswitchd.service" ]; # requires ovs-vswitchd to be alive at all times after = [ "network-pre.target" @@ -537,6 +545,7 @@ let (subsystemDevice n) ]; bindsTo = deps; + partOf = [ "networking-scripted.target" ]; after = [ "network-pre.target" ] ++ deps ++ map (i: "network-addresses-${i}.service") v.interfaces; before = [ "network.target" ]; serviceConfig.Type = "oneshot"; @@ -585,6 +594,7 @@ let (subsystemDevice n) ]; bindsTo = deps; + partOf = [ "networking-scripted.target" ]; after = [ "network-pre.target" ] ++ deps; before = [ "network.target" ]; serviceConfig.Type = "oneshot"; @@ -661,6 +671,7 @@ let (subsystemDevice n) ]; bindsTo = deps; + partOf = [ "networking-scripted.target" ]; after = [ "network-pre.target" ] ++ deps; before = [ "network.target" ]; serviceConfig.Type = "oneshot"; @@ -732,6 +743,7 @@ let (subsystemDevice n) ]; bindsTo = deps; + partOf = [ "networking-scripted.target" ]; after = [ "network-pre.target" ] ++ deps; before = [ "network.target" ]; serviceConfig.Type = "oneshot"; @@ -779,6 +791,7 @@ let (subsystemDevice n) ]; bindsTo = deps; + partOf = [ "networking-scripted.target" ]; after = [ "network-pre.target" ] ++ deps; before = [ "network.target" ]; serviceConfig.Type = "oneshot"; @@ -813,7 +826,10 @@ let (subsystemDevice n) ]; bindsTo = deps; - partOf = [ "network.target" ]; + partOf = [ + "network.target" + "networking-scripted.target" + ]; after = [ "network-pre.target" ] ++ deps; before = [ "network.target" ]; serviceConfig.Type = "oneshot"; @@ -865,6 +881,13 @@ let # to multi-user.target, this has the same result. systemd.targets.network.wantedBy = [ "multi-user.target" ]; + # This target serves no purpose during the boot, but can be + # used to quickly reset the network configuration by running + # systemctl restart networking-scripted.target + systemd.targets.networking-scripted = { + description = "NixOS scripted networking setup"; + }; + services.udev.extraRules = '' KERNEL=="tun", TAG+="systemd" ''; From 8bc8c596ead9703f76af1f65a62f3e31560b0f1e Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Tue, 6 Jan 2026 00:47:45 +0100 Subject: [PATCH 3/4] nixos/doc: update networking chapter --- .../ad-hoc-network-config.section.md | 20 ++++++++++++++----- .../configuration/ipv4-config.section.md | 13 +++++++++--- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/nixos/doc/manual/configuration/ad-hoc-network-config.section.md b/nixos/doc/manual/configuration/ad-hoc-network-config.section.md index 7ef24825526d..611f3e3956ee 100644 --- a/nixos/doc/manual/configuration/ad-hoc-network-config.section.md +++ b/nixos/doc/manual/configuration/ad-hoc-network-config.section.md @@ -1,14 +1,24 @@ # Ad-Hoc Configuration {#ad-hoc-network-config} -You can use [](#opt-networking.localCommands) to -specify shell commands to be run at the end of `network-setup.service`. This -is useful for doing network configuration not covered by the existing NixOS -modules. For instance, to statically configure an IPv6 address: +You can use [](#opt-networking.localCommands) to specify shell commands to be +run after the network interfaces have been created, but not necessarily fully +configured. +This is useful for doing network configuration not covered by the existing +NixOS modules. For example, you can create a network namespace and a pair +of virtual ethernet devices like this: ```nix { networking.localCommands = '' - ip -6 addr add 2001:610:685:1::1/64 dev eth0 + ip netns add mynet + ip link add name veth-in type veth peer name veth-out + ip link set dev veth-out netns mynet ''; } ``` + +::: {.note} +The commands should ideally be idempotent, so it's recommended to perform +cleanups of the state you create (e.g. virtual interfaces), or at least make +sure possible failures are handled. +::: diff --git a/nixos/doc/manual/configuration/ipv4-config.section.md b/nixos/doc/manual/configuration/ipv4-config.section.md index ed0db9da8c3e..ceb9a350b680 100644 --- a/nixos/doc/manual/configuration/ipv4-config.section.md +++ b/nixos/doc/manual/configuration/ipv4-config.section.md @@ -26,9 +26,16 @@ servers: ``` ::: {.note} -Statically configured interfaces are set up by the systemd service -`interface-name-cfg.service`. The default gateway and name server -configuration is performed by `network-setup.service`. +Addresses and routes for statically configured interfaces and the default +gateway are set up by systemd services named +`network-addresses-.service`. The name servers configuration, +instead, is performed by `network-local-commands.service` using resolvconf. +::: + +::: {.note} +If needed, for example if addresses/routes were added/removed, +you can reset the network configuration by running +`systemctl restart networking-scripted.target` ::: The host name is set using [](#opt-networking.hostName): From 1623fe233169fc86917ee79b23710eaa6695d109 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Sat, 14 Mar 2026 14:50:00 +0100 Subject: [PATCH 4/4] nixos/release-notes: explain network-interfaces changes --- nixos/doc/manual/release-notes/rl-2605.section.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nixos/doc/manual/release-notes/rl-2605.section.md b/nixos/doc/manual/release-notes/rl-2605.section.md index b6df37e26327..a98528159278 100644 --- a/nixos/doc/manual/release-notes/rl-2605.section.md +++ b/nixos/doc/manual/release-notes/rl-2605.section.md @@ -178,6 +178,13 @@ See . Note for NetworkManager users: before these changes NetworkManager used to spawn its own wpa_supplicant daemon, but now it relies on `networking.wireless`. So, if you had `networking.wireless.enable = false` in your configuration, you should remove that line. +- Some implementation details of the NixOS network-interfaces module have been changed: + + - In the "scripted" backend, `network-setup.service` has been removed and the network configuration services are now part of `network.target`, which is now directly pulled into `multi-user.target`. + - Interface addresses, routes and default gateways are now configured asynchronously as soon as the underlying network devices become available (fixes issue [#154737](https://github.com/NixOS/nixpkgs/issues/154737)). + - In both "networkd" and "scripted" backends, the configuration of name servers is now part of `network-local-commands.service` (fixes issue [#445496](https://github.com/NixOS/nixpkgs/issues/445496)). + - The issue that resulted in a completely unconfigured network if both `resolvconf` was disabled and no default gateway configured, has also been fixed. + - `kratos` has been updated from 1.3.1 to [25.4.0](https://github.com/ory/kratos/releases/tag/v25.4.0). Upstream switched to a new versioning scheme (year.major.minor). Notable breaking changes: - The `migrate sql` CLI command is now `migrate sql up`