nixos/networkd: configure /etc/systemd/networkd.conf
The networkd.conf file controls a variety of interesting settings which don't seem to be configurable at the moment, including adding names to route tables (for networkd only, although this commit also exports them into iproute2 for convenience's sake), and the speed metering functionality built into networkd. Importantly, however, this also allows disabling the systemd functionality where it likes to delete all the routes and routing rules that haven't been configured through networkd whenever something causes it to perform a reconfiguration.
This commit is contained in:
parent
12769bc7e1
commit
f47caf769b
@ -10,6 +10,36 @@ let
|
|||||||
|
|
||||||
check = {
|
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 = {
|
link = {
|
||||||
|
|
||||||
sectionLink = checkUnitConfig "Link" [
|
sectionLink = checkUnitConfig "Link" [
|
||||||
@ -867,6 +897,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 // {
|
linkOptions = commonNetworkOptions // {
|
||||||
# overwrite enable option from above
|
# overwrite enable option from above
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
@ -1515,6 +1583,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 != { }) ''
|
commonMatchText = def: optionalString (def.matchConfig != { }) ''
|
||||||
[Match]
|
[Match]
|
||||||
${attrsToSection def.matchConfig}
|
${attrsToSection def.matchConfig}
|
||||||
@ -1596,6 +1697,20 @@ let
|
|||||||
+ def.extraConfig;
|
+ 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:
|
networkToUnit = name: def:
|
||||||
{ inherit (def) enable;
|
{ inherit (def) enable;
|
||||||
text = commonMatchText def
|
text = commonMatchText def
|
||||||
@ -1728,6 +1843,12 @@ in
|
|||||||
description = "Definition of systemd networks.";
|
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 {
|
systemd.network.units = mkOption {
|
||||||
description = "Definition of networkd units.";
|
description = "Definition of networkd units.";
|
||||||
default = {};
|
default = {};
|
||||||
@ -1772,7 +1893,9 @@ in
|
|||||||
systemd.services.systemd-networkd = {
|
systemd.services.systemd-networkd = {
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
aliases = [ "dbus-org.freedesktop.network1.service" ];
|
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 = {
|
systemd.services.systemd-networkd-wait-online = {
|
||||||
@ -1791,6 +1914,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;
|
services.resolved.enable = mkDefault true;
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
@ -8,6 +8,9 @@ let generateNodeConf = { lib, pkgs, config, privk, pubk, peerId, nodeId, ...}: {
|
|||||||
environment.systemPackages = with pkgs; [ wireguard-tools ];
|
environment.systemPackages = with pkgs; [ wireguard-tools ];
|
||||||
systemd.network = {
|
systemd.network = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
config = {
|
||||||
|
routeTables.custom = 23;
|
||||||
|
};
|
||||||
netdevs = {
|
netdevs = {
|
||||||
"90-wg0" = {
|
"90-wg0" = {
|
||||||
netdevConfig = { Kind = "wireguard"; Name = "wg0"; };
|
netdevConfig = { Kind = "wireguard"; Name = "wg0"; };
|
||||||
@ -39,6 +42,7 @@ let generateNodeConf = { lib, pkgs, config, privk, pubk, peerId, nodeId, ...}: {
|
|||||||
address = [ "10.0.0.${nodeId}/32" ];
|
address = [ "10.0.0.${nodeId}/32" ];
|
||||||
routes = [
|
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"; }; }
|
||||||
|
{ routeConfig = { Gateway = "10.0.0.${nodeId}"; Destination = "10.0.0.0/24"; Table = "custom"; }; }
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
"30-eth1" = {
|
"30-eth1" = {
|
||||||
@ -87,6 +91,12 @@ testScript = ''
|
|||||||
node1.wait_for_unit("systemd-networkd-wait-online.service")
|
node1.wait_for_unit("systemd-networkd-wait-online.service")
|
||||||
node2.wait_for_unit("systemd-networkd-wait-online.service")
|
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
|
# Wireguard
|
||||||
# ================================
|
# ================================
|
||||||
|
Loading…
Reference in New Issue
Block a user