diff --git a/nixos/doc/manual/configuration/networking.xml b/nixos/doc/manual/configuration/networking.xml
index 02cf811e0bd..8369e9c9c85 100644
--- a/nixos/doc/manual/configuration/networking.xml
+++ b/nixos/doc/manual/configuration/networking.xml
@@ -15,5 +15,6 @@
+
diff --git a/nixos/doc/manual/configuration/renaming-interfaces.xml b/nixos/doc/manual/configuration/renaming-interfaces.xml
new file mode 100644
index 00000000000..d760bb3a4da
--- /dev/null
+++ b/nixos/doc/manual/configuration/renaming-interfaces.xml
@@ -0,0 +1,67 @@
+
+ Renaming network interfaces
+
+
+ NixOS uses the udev
+ predictable naming scheme
+ to assign names to network interfaces. This means that by default
+ cards are not given the traditional names like
+ eth0 or eth1, whose order can
+ change unpredictably across reboots. Instead, relying on physical
+ locations and firmware information, the scheme produces names like
+ ens1, enp2s0, etc.
+
+
+
+ These names are predictable but less memorable and not necessarily
+ stable: for example installing new hardware or changing firmware
+ settings can result in a
+ name change.
+ If this is undesirable, for example if you have a single ethernet
+ card, you can revert to the traditional scheme by setting
+ to
+ false.
+
+
+
+ Assigning custom names
+
+ In case there are multiple interfaces of the same type, it’s better to
+ assign custom names based on the device hardware address. For
+ example, we assign the name wan to the interface
+ with MAC address 52:54:00:12:01:01 using a
+ netword link unit:
+
+
+ systemd.network.links."10-wan" = {
+ matchConfig.MACAddress = "52:54:00:12:01:01";
+ linkConfig.Name = "wan";
+ };
+
+
+ Note that links are directly read by udev, not networkd,
+ and will work even if networkd is disabled.
+
+
+ Alternatively, we can use a plain old udev rule:
+
+
+ services.udev.initrdRules = ''
+ SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", \
+ ATTR{address}=="52:54:00:12:01:01", KERNEL=="eth*", NAME="wan"
+ '';
+
+
+
+ The rule must be installed in the initrd using
+ services.udev.initrdRules, not the usual
+ services.udev.extraRules option. This is to avoid race
+ conditions with other programs controlling the interface.
+
+
+
+
diff --git a/nixos/doc/manual/release-notes/rl-2105.xml b/nixos/doc/manual/release-notes/rl-2105.xml
index 3760c52d363..9894ab02500 100644
--- a/nixos/doc/manual/release-notes/rl-2105.xml
+++ b/nixos/doc/manual/release-notes/rl-2105.xml
@@ -91,6 +91,16 @@
+
+
+ If you are using to assign
+ custom names to network interfaces, this may stop working due to a change
+ in the initialisation of dhcpcd and systemd networkd. To avoid this, either
+ move them to or see the new
+ Assigning custom names section
+ of the NixOS manual for an example using networkd links.
+
+
The systemConfig kernel parameter is no longer added to boot loader entries. It has been unused since September 2010, but if do have a system generation from that era, you will now be unable to boot into them.
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 63027f7744d..d48b5444677 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -202,12 +202,26 @@ in
'';
};
- extraRules = mkOption {
+ initrdRules = mkOption {
default = "";
example = ''
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:1D:60:B9:6D:4F", KERNEL=="eth*", NAME="my_fast_network_card"
'';
type = types.lines;
+ description = ''
+ udev rules to include in the initrd
+ only. They'll be written into file
+ 99-local.rules. Thus they are read and applied
+ after the essential initrd rules.
+ '';
+ };
+
+ extraRules = mkOption {
+ default = "";
+ example = ''
+ ENV{ID_VENDOR_ID}=="046d", ENV{ID_MODEL_ID}=="0825", ENV{PULSE_IGNORE}="1"
+ '';
+ type = types.lines;
description = ''
Additional udev rules. They'll be written
into file 99-local.rules. Thus they are
@@ -284,6 +298,13 @@ in
boot.kernelParams = mkIf (!config.networking.usePredictableInterfaceNames) [ "net.ifnames=0" ];
+ boot.initrd.extraUdevRulesCommands = optionalString (cfg.initrdRules != "")
+ ''
+ cat <<'EOF' > $out/99-local.rules
+ ${cfg.initrdRules}
+ EOF
+ '';
+
environment.etc =
{
"udev/rules.d".source = udevRules;
diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix
index d10bffd9147..31e4b6ad298 100644
--- a/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixos/modules/services/networking/dhcpcd.nix
@@ -191,9 +191,8 @@ in
{ description = "DHCP Client";
wantedBy = [ "multi-user.target" ] ++ optional (!hasDefaultGatewaySet) "network-online.target";
- wants = [ "network.target" "systemd-udev-settle.service" ];
+ wants = [ "network.target" ];
before = [ "network-online.target" ];
- after = [ "systemd-udev-settle.service" ];
restartTriggers = [ exitHook ];
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index 3b01bc00baf..914d3e62eb4 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -1553,9 +1553,6 @@ in
wantedBy = [ "multi-user.target" ];
aliases = [ "dbus-org.freedesktop.network1.service" ];
restartTriggers = map (x: x.source) (attrValues unitFiles);
- # prevent race condition with interface renaming (#39069)
- requires = [ "systemd-udev-settle.service" ];
- after = [ "systemd-udev-settle.service" ];
};
systemd.services.systemd-networkd-wait-online = {
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 44287f3cf09..4074f2e0235 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -205,13 +205,22 @@ 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.
linkUnits = pkgs.runCommand "link-units" {
allowedReferences = [ extraUtils ];
preferLocalBuild = true;
- } ''
+ } (''
mkdir -p $out
cp -v ${udev}/lib/systemd/network/*.link $out/
- '';
+ '' + (
+ let
+ links = filterAttrs (n: v: hasSuffix ".link" n) config.systemd.network.units;
+ files = mapAttrsToList (n: v: "${v.unit}/${n}") links;
+ in
+ concatMapStringsSep "\n" (file: "cp -v ${file} $out/") files
+ ));
udevRules = pkgs.runCommand "udev-rules" {
allowedReferences = [ extraUtils ];
diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix
index 58adab9d40a..1ea61f99a95 100644
--- a/nixos/tests/networking.nix
+++ b/nixos/tests/networking.nix
@@ -672,6 +672,30 @@ let
), "The IPv6 routing table has not been properly cleaned:\n{}".format(ipv6Residue)
'';
};
+ rename = {
+ name = "RenameInterface";
+ machine = { pkgs, ... }: {
+ virtualisation.vlans = [ 1 ];
+ networking = {
+ useNetworkd = networkd;
+ useDHCP = false;
+ };
+ } //
+ (if networkd
+ then { systemd.network.links."10-custom_name" = {
+ matchConfig.MACAddress = "52:54:00:12:01:01";
+ linkConfig.Name = "custom_name";
+ };
+ }
+ else { services.udev.initrdRules = ''
+ SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="52:54:00:12:01:01", KERNEL=="eth*", NAME="custom_name"
+ '';
+ });
+ testScript = ''
+ machine.succeed("udevadm settle")
+ print(machine.succeed("ip link show dev custom_name"))
+ '';
+ };
# even with disabled networkd, systemd.network.links should work
# (as it's handled by udev, not networkd)
link = {