diff --git a/nixos/doc/manual/release-notes/rl-1809.xml b/nixos/doc/manual/release-notes/rl-1809.xml
index d831f85144662..c977aa389695b 100644
--- a/nixos/doc/manual/release-notes/rl-1809.xml
+++ b/nixos/doc/manual/release-notes/rl-1809.xml
@@ -200,6 +200,22 @@ $ nix-instantiate -E '(import <nixpkgsunstable> {}).gitFull'
from your config without any issues.
+
+
+ The following changes apply if system.stateVersion is
+ changed to 18.09 or higher. For system.stateVersion = "18.03" or lower
+ the old behavior is preserved.
+
+
+
+
+ If predictable interface names are enabled (networking.usePredictableInterfaceNames = true ),
+ interfaces are already renamed in Stage 1 (initrd). This may break existing configurations
+ that require networking in Stage 1 (initrd) to boot. In the worst case, your system may become unbootable.
+
+
+
+
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 0266286aaacf9..5094be3997fa4 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -266,6 +266,9 @@ in
change randomly across reboots; for instance, you may find
eth0 and eth1 flipping
unpredictably.
+ For configurations with system.stateVersion >= 18.09,
+ interfaces are renamed to predictable names in Stage 1 (initrd).
+ Changing this option's value may require a reboot to take effect.
'';
};
diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
index c11aaeaeb6dcd..79eb69ff1c99e 100644
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -844,7 +844,10 @@ in
systemd.services.systemd-networkd = {
wantedBy = [ "multi-user.target" ];
restartTriggers = map (f: f.source) (unitFiles);
+ } // optionalAttrs (versionOlder config.system.stateVersion "18.09") {
# prevent race condition with interface renaming (#39069)
+ # This is not necessary for newer configs (stateVersion>=18.09)
+ # since they do interface renaming in stage 1
requires = [ "systemd-udev-settle.service" ];
after = [ "systemd-udev-settle.service" ];
};
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index f58b68cb3353d..f5f8649211796 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -195,9 +195,11 @@ let
fi
''; # */
+ # use same rules as stage 2 for renaming network interfaces to predictable names
+ netSetupLinkRules = ../../services/hardware/80-net-setup-link.rules;
udevRules = pkgs.runCommand "udev-rules"
- { allowedReferences = [ extraUtils ]; }
+ { allowedReferences = [ netSetupLinkRules extraUtils ]; }
''
mkdir -p $out
@@ -206,6 +208,12 @@ let
cp -v ${udev}/lib/udev/rules.d/60-cdrom_id.rules $out/
cp -v ${udev}/lib/udev/rules.d/60-persistent-storage.rules $out/
cp -v ${udev}/lib/udev/rules.d/80-drivers.rules $out/
+ # rename interfaces to predictable names in stage 1 for newer configs
+ ${optionalString (config.networking.usePredictableInterfaceNames &&
+ lib.versionAtLeast config.system.stateVersion "18.09") ''
+ cp -v ${udev}/lib/udev/rules.d/75-net-description.rules $out/
+ cp -v ${netSetupLinkRules} $out/80-net-setup-link.rules
+ ''}
cp -v ${pkgs.lvm2}/lib/udev/rules.d/*.rules $out/
${config.boot.initrd.extraUdevRulesCommands}
diff --git a/nixos/release.nix b/nixos/release.nix
index b25c684ff47a8..5397cb31f6442 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -314,7 +314,7 @@ in rec {
tests.hydra = callTest tests/hydra {};
tests.i3wm = callTest tests/i3wm.nix {};
tests.iftop = callTest tests/iftop.nix {};
- tests.initrd-network-ssh = callTest tests/initrd-network-ssh {};
+ tests.initrd-network-ssh = callSubTests tests/initrd-network-ssh {};
tests.installer = callSubTests tests/installer.nix {};
tests.influxdb = callTest tests/influxdb.nix {};
tests.ipv6 = callTest tests/ipv6.nix {};
diff --git a/nixos/tests/initrd-network-ssh/default.nix b/nixos/tests/initrd-network-ssh/default.nix
index b2209f297a4f8..6222a4c9c856c 100644
--- a/nixos/tests/initrd-network-ssh/default.nix
+++ b/nixos/tests/initrd-network-ssh/default.nix
@@ -1,59 +1,76 @@
-import ../make-test.nix ({ lib, ... }:
+{ system ? builtins.currentSystem }:
-{
- name = "initrd-network-ssh";
- meta = with lib.maintainers; {
- maintainers = [ willibutz ];
- };
+let
+ inherit (import ../../lib/testing.nix { inherit system; }) makeTest pkgs;
+in
+ with pkgs; lib.listToAttrs ( map (predictable: {
- nodes = with lib; rec {
- server =
- { config, ... }:
- {
- boot.kernelParams = [
- "ip=${config.networking.primaryIPAddress}:::255.255.255.0::eth1:none"
- ];
- boot.initrd.network = {
- enable = true;
- ssh = {
- enable = true;
- authorizedKeys = [ "${readFile ./openssh.pub}" ];
- port = 22;
- hostRSAKey = ./dropbear.priv;
- };
- };
- boot.initrd.preLVMCommands = ''
- while true; do
- if [ -f fnord ]; then
- poweroff
- fi
- sleep 1
- done
- '';
+ name = if predictable then "predictable" else "unpredictable";
+
+ value = makeTest {
+ name = "initrd-network-ssh"+ lib.optionalString predictable "predictable";
+ meta = with lib.maintainers; {
+ maintainers = [ willibutz xeji ];
};
- client =
- { config, ... }:
- {
- environment.etc.knownHosts = {
- text = concatStrings [
- "server,"
- "${toString (head (splitString " " (
- toString (elemAt (splitString "\n" config.networking.extraHosts) 2)
- )))} "
- "${readFile ./dropbear.pub}"
- ];
- };
+ nodes = with lib;
+ let interface2 = if predictable then "ens4" else "eth1";
+ in rec {
+ server =
+ { config, ... }:
+ {
+ # for stateVersion < 18.09 this doesn't make a difference in initrd
+ system.stateVersion = "18.09";
+ networking.usePredictableInterfaceNames = mkForce predictable;
+ boot.kernelParams = [
+ "ip=${config.networking.primaryIPAddress}:::255.255.255.0::${interface2}:none"
+ ];
+ boot.initrd.network = {
+ enable = true;
+ # for initrd networking with predictable interface names,
+ # udhcpc must be given the name as an argument
+ udhcpc.extraArgs = [ (lib.optionalString predictable "-i ${interface2}")];
+ ssh = {
+ enable = true;
+ authorizedKeys = [ "${readFile ./openssh.pub}" ];
+ port = 22;
+ hostRSAKey = ./dropbear.priv;
+ };
+ };
+ boot.initrd.preLVMCommands = ''
+ while true; do
+ if [ -f fnord ]; then
+ poweroff
+ fi
+ sleep 1
+ done
+ '';
+ };
+
+ client =
+ { config, ... }:
+ {
+ environment.etc.knownHosts = {
+ text = concatStrings [
+ "server,"
+ "${toString (head (splitString " " (
+ toString (elemAt (splitString "\n" config.networking.extraHosts) 2)
+ )))} "
+ "${readFile ./dropbear.pub}"
+ ];
+ };
+ };
};
- };
- testScript = ''
- startAll;
- $client->waitForUnit("network.target");
- $client->copyFileFromHost("${./openssh.priv}","/etc/sshKey");
- $client->succeed("chmod 0600 /etc/sshKey");
- $client->waitUntilSucceeds("ping -c 1 server");
- $client->succeed("ssh -i /etc/sshKey -o UserKnownHostsFile=/etc/knownHosts server 'touch /fnord'");
- $client->shutdown;
- '';
-})
+ testScript = ''
+ $client->waitForUnit("network.target");
+ $client->copyFileFromHost("${./openssh.priv}","/etc/sshKey");
+ $client->succeed("chmod 0600 /etc/sshKey");
+ $server->start;
+ $client->waitUntilSucceeds("ping -c 1 server");
+ $client->succeed("ssh -i /etc/sshKey -o UserKnownHostsFile=/etc/knownHosts server 'touch /fnord'");
+ $client->shutdown;
+ '';
+ };
+ }) [false true]
+)
diff --git a/nixos/tests/predictable-interface-names.nix b/nixos/tests/predictable-interface-names.nix
index 0d73436c1c3f5..4497e42d71462 100644
--- a/nixos/tests/predictable-interface-names.nix
+++ b/nixos/tests/predictable-interface-names.nix
@@ -2,17 +2,22 @@
let
inherit (import ../lib/testing.nix { inherit system; }) makeTest pkgs;
-in pkgs.lib.listToAttrs (pkgs.lib.crossLists (predictable: withNetworkd: {
+in pkgs.lib.listToAttrs (pkgs.lib.crossLists (predictable: withNetworkd: stateV: {
name = pkgs.lib.optionalString (!predictable) "un" + "predictable"
- + pkgs.lib.optionalString withNetworkd "Networkd";
+ + pkgs.lib.optionalString withNetworkd "Networkd"
+ + builtins.replaceStrings ["."] [""] stateV;
value = makeTest {
- name = "${if predictable then "" else "un"}predictableInterfaceNames${if withNetworkd then "-with-networkd" else ""}";
+ name = "${if predictable then "" else "un"}predictableInterfaceNames${if withNetworkd then "-with-networkd" else ""}-${stateV}";
meta = {};
machine = { lib, ... }: {
networking.usePredictableInterfaceNames = lib.mkForce predictable;
networking.useNetworkd = withNetworkd;
networking.dhcpcd.enable = !withNetworkd;
+ # So we can see the initrd device names in the log
+ # although we don't add an automated test here
+ boot.initrd.network.enable = (stateV == "18.09");
+ system.stateVersion = stateV;
};
testScript = ''
@@ -21,4 +26,4 @@ in pkgs.lib.listToAttrs (pkgs.lib.crossLists (predictable: withNetworkd: {
$machine->fail("ip link show ${if predictable then "eth0" else "ens3"}");
'';
};
-}) [[true false] [true false]])
+}) [[true false] [true false] ["18.03" "18.09"]])