Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/{networkd,dhcpcd}: remove udev-settle hack #107382

Merged
merged 6 commits into from
Feb 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nixos/doc/manual/configuration/networking.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
<xi:include href="firewall.xml" />
<xi:include href="wireless.xml" />
<xi:include href="ad-hoc-network-config.xml" />
<xi:include href="renaming-interfaces.xml" />
<!-- TODO: OpenVPN, NAT -->
</chapter>
67 changes: 67 additions & 0 deletions nixos/doc/manual/configuration/renaming-interfaces.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-rename-ifs">
<title>Renaming network interfaces</title>

<para>
NixOS uses the udev
<link xlink:href="https://systemd.io/PREDICTABLE_INTERFACE_NAMES/">predictable naming scheme</link>
to assign names to network interfaces. This means that by default
cards are not given the traditional names like
<literal>eth0</literal> or <literal>eth1</literal>, whose order can
change unpredictably across reboots. Instead, relying on physical
locations and firmware information, the scheme produces names like
<literal>ens1</literal>, <literal>enp2s0</literal>, etc.
</para>

<para>
These names are predictable but less memorable and not necessarily
stable: for example installing new hardware or changing firmware
settings can result in a
<link xlink:href="https://github.com/systemd/systemd/issues/3715#issue-165347602">name change</link>.
If this is undesirable, for example if you have a single ethernet
card, you can revert to the traditional scheme by setting
<xref linkend="opt-networking.usePredictableInterfaceNames"/> to
<literal>false</literal>.
</para>

<section xml:id="sec-custom-ifnames">
<title>Assigning custom names</title>
<para>
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 <literal>wan</literal> to the interface
with MAC address <literal>52:54:00:12:01:01</literal> using a
netword link unit:
</para>
<programlisting>
<link linkend="opt-systemd.network.links">systemd.network.links."10-wan"</link> = {
matchConfig.MACAddress = "52:54:00:12:01:01";
linkConfig.Name = "wan";
};
</programlisting>
<para>
Note that links are directly read by udev, <emphasis>not networkd</emphasis>,
and will work even if networkd is disabled.
</para>
<para>
Alternatively, we can use a plain old udev rule:
</para>
<programlisting>
<link linkend="opt-services.udev.initrdRules">services.udev.initrdRules</link> = ''
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", \
ATTR{address}=="52:54:00:12:01:01", KERNEL=="eth*", NAME="wan"
'';
</programlisting>

<warning><para>
The rule must be installed in the initrd using
<literal>services.udev.initrdRules</literal>, not the usual
<literal>services.udev.extraRules</literal> option. This is to avoid race
conditions with other programs controlling the interface.
</para></warning>
</section>

</section>
10 changes: 10 additions & 0 deletions nixos/doc/manual/release-notes/rl-2105.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@
</para>

<itemizedlist>
<listitem>
<para>
If you are using <option>services.udev.extraRules</option> 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 <option>services.udev.initrdRules</option> or see the new
<link linkend="sec-custom-ifnames">Assigning custom names</link> section
of the NixOS manual for an example using networkd links.
</para>
</listitem>
<listitem>
<para>
<literal>systemd-journal2gelf</literal> no longer parses json and expects the receiving system to handle it. How to achieve this with Graylog is described in this <link xlink:href="https://github.com/parse-nl/SystemdJournal2Gelf/issues/10">GitHub issue</link>.
Expand Down
23 changes: 22 additions & 1 deletion nixos/modules/services/hardware/udev.nix
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,26 @@ in
'';
};

extraRules = mkOption {
initrdRules = mkOption {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmph not particularily fond of having this option defined here. This module is for configuring systemd-udevd in stage 2; not stage 1

how about instead of having an initrdRules here; we move this option to stage-1.nix and name it boot.initrd.extraUdevRules ? It's a bit weird to have the the option for initrd defined here as udevd in initrd and udevd in stage-2 might be two completely different udevd implementations at this moment.

I'm working on an alternative initrd implementation using systemd. But it's hard to introduce this change as now the udev module in stage-2 has a hard dependency on the stage-1.nix module. Because now the stage-2 udev module calls out to stage-1.nix I can not disable stage-1.nix in disabledModules

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll send a draft PR with these suggested changes and i'll backlink it here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think renaming this option is fine - as long as we do this before the 20.05 branchoff, it probably doesn't even need the mkRenamedOption alias.

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 = ''
<command>udev</command> rules to include in the initrd
<emphasis>only</emphasis>. They'll be written into file
<filename>99-local.rules</filename>. 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 <command>udev</command> rules. They'll be written
into file <filename>99-local.rules</filename>. Thus they are
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions nixos/modules/services/networking/dhcpcd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 ];

Expand Down
3 changes: 0 additions & 3 deletions nixos/modules/system/boot/networkd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
13 changes: 11 additions & 2 deletions nixos/modules/system/boot/stage-1.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 ];
Expand Down
24 changes: 24 additions & 0 deletions nixos/tests/networking.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down