I’m trying to write a module which I can use in my nixos flake for all systems.
Running:
nix eval ".#nixosConfigurations.mysystem.config.systemd.network.networks"
gives only the enp2, and not both networks. When I comment out enp2, I do see enp1.
I think I’m improperly using concatMapAttrs , but I don’t know what do change.
I have something like this in the flake for a particular system:
ncfg.networking.wired-interfaces = {
"enp1" = {
assignment = "dynamic";
metric = 30;
};
"enp2" = {
assignment = "static";
metric = 100;
requiredForOnline = false;
description = "Air-gapped network: 192.168.1.0/24";
ipv4.addr = "192.168.1.10/24";
ipv4.gateway = "192.168.1.1";
ipv6.addr = "fd00:192:168:1::10/64";
};
};
The networking module
{
pkgs,
config,
lib,
...
}:
let
cfg = config.ncfg.networking;
in
{
options.ncfg.networking = {
wired-interfaces = lib.mkOption {
description = ''
wired interfaces
'';
default = { };
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
assignment = lib.mkOption {
type = lib.types.nullOr (
lib.types.enum [
"dynamic"
"static"
]
);
default = "dynamic";
description = ''
Dynamic or Static assignment of the interface: ${name}
'';
};
metric = lib.mkOption {
type = lib.types.ints.between 0 4294967295;
default = 1000;
description = "The unit name";
};
requiredForOnline = lib.mkOption {
type = lib.types.bool;
default = true;
description = "interface not required for online";
};
description = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = "The description";
};
ipv4 = {
addr = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "ipv4 address including subnet mask";
example = "192.0.2.100/24";
};
gateway = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "ipv4 gateway";
};
};
ipv6 = {
addr = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "ipv6 address including subnet mask";
example = "2001:DB8::2/64";
};
gateway = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "ipv6 gateway";
};
};
};
}
)
);
};
};
config = lib.mkIf (cfg.wired-interfaces != { }) (
lib.mkMerge [
{
systemd.network.enable = true;
# # Don't block boot/nixos-rebuild on all interfaces, wired usually unplugged
systemd.network.wait-online.enable = false;
systemd.network.wait-online.anyInterface = true;
}
{
systemd.network = lib.concatMapAttrs (interface: attrs: {
networks."${toString attrs.metric}-${interface}" = {
matchConfig = {
Name = "${interface}"; # Match the interface by name
};
networkConfig = lib.mkIf (attrs.assignment == "dynamic") {
# start a DHCP Client for IPv4 Addressing/Routing
DHCP = "ipv4";
# accept Router Advertisements for Stateless IPv6 Autoconfiguraton (SLAAC)
IPv6AcceptRA = true;
};
dhcpV4Config.RouteMetric = lib.mkIf (attrs.assignment == "dynamic") attrs.metric;
dhcpV6Config.RouteMetric = lib.mkIf (attrs.assignment == "dynamic") attrs.metric;
### dhcpV4Config.Metric = attrs.metric;
### dhcpV6Config.Metric = attrs.metric;
address =
# configure addresses including subnet mask
lib.optionals (attrs.assignment == "static" && attrs.ipv6.addr != null) [
attrs.ipv6.addr
]
++ lib.optionals (attrs.assignment == "static" && attrs.ipv4.addr != null) [
attrs.ipv4.addr
];
routes =
# create default routes for both IPv6 and IPv4
lib.optionals (attrs.assignment == "static" && attrs.ipv6.gateway != null) [
{ Gateway = attrs.ipv6.gateway; }
]
++ lib.optionals (attrs.assignment == "static" && attrs.ipv4.gateway != null) [
{ Gateway = attrs.ipv4.gateway; }
];
# Make the routes on this interface a dependency for network-online.target
linkConfig.RequiredForOnline = lib.mkIf attrs.requiredForOnline "routable";
};
}) cfg.wired-interfaces;
}
]
);
}