nixos/network-interfaces-systemd: fix DHCP setting

The networkd backend logic for setting DHCP= on an interface is bugged
and inconsistent with the scripted logic. Consider this simple NixOS
configuration:

    {
      networking.useNetworkd = true;
      networking.interfaces.eth0.wakeOnLan.enable = true;
    }

The default value of networking.useDHCP is true, so we expect our eth0
interface to have DHCP enabled. With the scripted backend, this works.
But the networkd backend generates the following 40-eth0.network file:

    [Match]
    Name=eth0

    [Network]
    DHCP=no
    IPv6PrivacyExtensions=kernel

This is happening because the wakeOnLan configuration creates a key in
networking.interfaces, and the networkd backend erroneously checks that
instead of for explicitly configured IP addresses as in the scripted
backend. The documentation is also inconsistent across various options.

This change aligns the networkd backend and option documentation to the
actual behavior of the scripted backend, and updates a test to account
for this behavior for both backends.
This commit is contained in:
Majiir Paktu 2023-10-07 12:40:42 -04:00
parent af4598273b
commit c4228b6c8f
3 changed files with 14 additions and 10 deletions

View file

@ -92,7 +92,7 @@ let
networks."40-${i.name}" = mkMerge [ (genericNetwork id) { networks."40-${i.name}" = mkMerge [ (genericNetwork id) {
name = mkDefault i.name; name = mkDefault i.name;
DHCP = mkForce (dhcpStr DHCP = mkForce (dhcpStr
(if i.useDHCP != null then i.useDHCP else false)); (if i.useDHCP != null then i.useDHCP else (config.networking.useDHCP && i.ipv4.addresses == [ ])));
address = forEach (interfaceIps i) address = forEach (interfaceIps i)
(ip: "${ip.address}/${toString ip.prefixLength}"); (ip: "${ip.address}/${toString ip.prefixLength}");
routes = forEach (interfaceRoutes i) routes = forEach (interfaceRoutes i)

View file

@ -190,9 +190,11 @@ let
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;
description = lib.mdDoc '' description = lib.mdDoc ''
Whether this interface should be configured with dhcp. Whether this interface should be configured with DHCP. Overrides the
Null implies the old behavior which depends on whether ip addresses default set by {option}`networking.useDHCP`. If `null` (the default),
are specified or not. DHCP is enabled if the interface has no IPv4 addresses configured
with {option}`networking.interfaces.<name>.ipv4.addresses`, and
disabled otherwise.
''; '';
}; };
@ -640,9 +642,7 @@ in
} ]; } ];
}; };
description = lib.mdDoc '' description = lib.mdDoc ''
The configuration for each network interface. If The configuration for each network interface.
{option}`networking.useDHCP` is true, then every
interface not listed here will be configured using DHCP.
Please note that {option}`systemd.network.netdevs` has more features Please note that {option}`systemd.network.netdevs` has more features
and is better maintained. When building new things, it is advised to and is better maintained. When building new things, it is advised to
@ -1304,8 +1304,8 @@ in
default = true; default = true;
description = lib.mdDoc '' description = lib.mdDoc ''
Whether to use DHCP to obtain an IP address and other Whether to use DHCP to obtain an IP address and other
configuration for all network interfaces that are not manually configuration for all network interfaces that do not have any manually
configured. configured IPv4 addresses.
''; '';
}; };

View file

@ -185,7 +185,11 @@ let
nodes.router = router; nodes.router = router;
nodes.client = { lib, ... }: { nodes.client = { lib, ... }: {
# Disable test driver default config # Disable test driver default config
networking.interfaces = lib.mkForce {}; networking.interfaces = lib.mkForce {
# Make sure DHCP defaults correctly even when some unrelated config
# is set on the interface (nothing, in this case).
enp1s0 = {};
};
networking.useNetworkd = networkd; networking.useNetworkd = networkd;
virtualisation.interfaces.enp1s0.vlan = 1; virtualisation.interfaces.enp1s0.vlan = 1;
}; };