depot/third_party/nixpkgs/patches/networkd-global-options.patch
Luke Granger-Brown c41914e274 nixos/networkd: add support for configuring networkd.conf settings
networkd.conf controls a few interesting options, such as enabling
systemd-networkd's speed meterer and, crucially, allowing you to disable the
behaviour where networkd will delete any routes or policy-based routing rules
that it doesn't recognise.

This also adds support for configuring routing table names and mirroring them
into the iproute2 config.
2022-03-13 04:00:48 +00:00

232 lines
7.5 KiB
Diff

diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix
--- a/nixos/modules/system/boot/networkd.nix
+++ b/nixos/modules/system/boot/networkd.nix
@@ -10,6 +10,36 @@ let
check = {
+ global = {
+ sectionNetwork = checkUnitConfig "Network" [
+ (assertOnlyFields [
+ "SpeedMeter"
+ "SpeedMeterIntervalSec"
+ "ManageForeignRoutingPolicyRules"
+ "ManageForeignRoutes"
+ "RouteTable"
+ ])
+ (assertValueOneOf "SpeedMeter" boolValues)
+ (assertInt "SpeedMeterIntervalSec")
+ (assertValueOneOf "ManageForeignRoutingPolicyRules" boolValues)
+ (assertValueOneOf "ManageForeignRoutes" boolValues)
+ ];
+
+ sectionDHCPv4 = checkUnitConfig "DHCPv4" [
+ (assertOnlyFields [
+ "DUIDType"
+ "DUIDRawData"
+ ])
+ ];
+
+ sectionDHCPv6 = checkUnitConfig "DHCPv6" [
+ (assertOnlyFields [
+ "DUIDType"
+ "DUIDRawData"
+ ])
+ ];
+ };
+
link = {
sectionLink = checkUnitConfig "Link" [
@@ -871,6 +901,44 @@ let
};
};
+ networkdOptions = {
+ networkConfig = mkOption {
+ default = {};
+ example = { SpeedMeter = true; ManageForeignRoutingPolicyRules = false; };
+ type = types.addCheck (types.attrsOf unitOption) check.global.sectionNetwork;
+ description = ''
+ Each attribute in this set specifies an option in the
+ <literal>[Network]</literal> section of the networkd config.
+ See <citerefentry><refentrytitle>networkd.conf</refentrytitle>
+ <manvolnum>5</manvolnum></citerefentry> for details.
+ '';
+ };
+
+ dhcpV4Config = mkOption {
+ default = {};
+ example = { DUIDType = "vendor"; };
+ type = types.addCheck (types.attrsOf unitOption) check.global.sectionDHCPv4;
+ description = ''
+ Each attribute in this set specifies an option in the
+ <literal>[DHCPv4]</literal> section of the networkd config.
+ See <citerefentry><refentrytitle>networkd.conf</refentrytitle>
+ <manvolnum>5</manvolnum></citerefentry> for details.
+ '';
+ };
+
+ dhcpV6Config = mkOption {
+ default = {};
+ example = { DUIDType = "vendor"; };
+ type = types.addCheck (types.attrsOf unitOption) check.global.sectionDHCPv6;
+ description = ''
+ Each attribute in this set specifies an option in the
+ <literal>[DHCPv6]</literal> section of the networkd config.
+ See <citerefentry><refentrytitle>networkd.conf</refentrytitle>
+ <manvolnum>5</manvolnum></citerefentry> for details.
+ '';
+ };
+ };
+
linkOptions = commonNetworkOptions // {
# overwrite enable option from above
enable = mkOption {
@@ -1519,6 +1587,39 @@ let
};
};
+ networkdConfig = { config, ... }: {
+ options = {
+ routeTables = mkOption {
+ default = {};
+ example = { foo = 27; };
+ type = with types; attrsOf int;
+ description = ''
+ Defines route table names as an attrset of name to number.
+ See <citerefentry><refentrytitle>networkd.conf</refentrytitle>
+ <manvolnum>5</manvolnum></citerefentry> for details.
+ '';
+ };
+
+ addRouteTablesToIPRoute2 = mkOption {
+ default = true;
+ example = false;
+ type = types.bool;
+ description = ''
+ If true and routeTables are set, then the specified route tables
+ will also be installed into /etc/iproute2/rt_tables.
+ '';
+ };
+ };
+
+ config = {
+ networkConfig = optionalAttrs (config.routeTables != { }) {
+ RouteTable = mapAttrsToList
+ (name: number: "${name}:${toString number}")
+ config.routeTables;
+ };
+ };
+ };
+
commonMatchText = def: optionalString (def.matchConfig != { }) ''
[Match]
${attrsToSection def.matchConfig}
@@ -1600,6 +1701,20 @@ let
+ def.extraConfig;
};
+ renderConfig = def:
+ { text = ''
+ [Network]
+ ''
+ + attrsToSection def.networkConfig
+ + optionalString (def.dhcpV4Config != { }) ''
+ [DHCPv4]
+ ${attrsToSection def.dhcpV4Config}
+ ''
+ + optionalString (def.dhcpV6Config != { }) ''
+ [DHCPv6]
+ ${attrsToSection def.dhcpV6Config}
+ ''; };
+
networkToUnit = name: def:
{ inherit (def) enable;
text = commonMatchText def
@@ -1700,7 +1815,8 @@ let
unitFiles = listToAttrs (map (name: {
name = "systemd/network/${name}";
value.source = "${cfg.units.${name}.unit}/${name}";
- }) (attrNames cfg.units));
+ }) (attrNames cfg.units)) // {
+ };
in
{
@@ -1732,6 +1848,12 @@ in
description = "Definition of systemd networks.";
};
+ systemd.network.config = mkOption {
+ default = {};
+ type = with types; submodule [ { options = networkdOptions; } networkdConfig ];
+ description = "Definition of global systemd network config.";
+ };
+
systemd.network.units = mkOption {
description = "Definition of networkd units.";
default = {};
@@ -1776,7 +1898,9 @@ in
systemd.services.systemd-networkd = {
wantedBy = [ "multi-user.target" ];
aliases = [ "dbus-org.freedesktop.network1.service" ];
- restartTriggers = map (x: x.source) (attrValues unitFiles);
+ restartTriggers = map (x: x.source) (attrValues unitFiles) ++ [
+ config.environment.etc."systemd/networkd.conf".source
+ ];
};
systemd.services.systemd-networkd-wait-online = {
@@ -1795,6 +1919,17 @@ in
};
};
+ environment.etc."systemd/networkd.conf" = renderConfig cfg.config;
+
+ networking.iproute2 = mkIf (cfg.config.addRouteTablesToIPRoute2 && cfg.config.routeTables != { }) {
+ enable = mkDefault true;
+ rttablesExtraConfig = ''
+
+ # Extra tables defined in NixOS systemd.networkd.config.routeTables.
+ ${concatStringsSep "\n" (mapAttrsToList (name: number: "${toString number} ${name}") cfg.config.routeTables)}
+ '';
+ };
+
services.resolved.enable = mkDefault true;
})
];
diff --git a/nixos/tests/systemd-networkd.nix b/nixos/tests/systemd-networkd.nix
--- a/nixos/tests/systemd-networkd.nix
+++ b/nixos/tests/systemd-networkd.nix
@@ -8,6 +8,9 @@ let generateNodeConf = { lib, pkgs, conf
environment.systemPackages = with pkgs; [ wireguard-tools ];
systemd.network = {
enable = true;
+ config = {
+ routeTables.custom = 23;
+ };
netdevs = {
"90-wg0" = {
netdevConfig = { Kind = "wireguard"; Name = "wg0"; };
@@ -39,6 +42,7 @@ let generateNodeConf = { lib, pkgs, conf
address = [ "10.0.0.${nodeId}/32" ];
routes = [
{ routeConfig = { Gateway = "10.0.0.${nodeId}"; Destination = "10.0.0.0/24"; }; }
+ { routeConfig = { Gateway = "10.0.0.${nodeId}"; Destination = "10.0.0.0/24"; Table = "custom"; }; }
];
};
"30-eth1" = {
@@ -88,6 +92,12 @@ testScript = ''
node2.wait_for_unit("systemd-networkd-wait-online.service")
# ================================
+ # Networkd Config
+ # ================================
+ node1.succeed("grep RouteTable=custom:23 /etc/systemd/networkd.conf")
+ node1.succeed("sudo ip route show table custom | grep '10.0.0.0/24 via 10.0.0.1 dev wg0 proto static'")
+
+ # ================================
# Wireguard
# ================================
node1.succeed("ping -c 5 10.0.0.2")