Luke Granger-Brown
c41914e274
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.
232 lines
7.5 KiB
Diff
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")
|