dotfiles/nixos/modules/router/netns-if.nix

90 lines
2.1 KiB
Nix
Raw Normal View History

{
config,
lib,
pkgs,
...
}: let
inherit
(lib)
mkOption
mkIf
mkMerge
types
getExe'
flip
mapAttrs'
flatten
mapAttrsToList
nameValuePair
concatMapStringsSep
mkEnableOption
;
cfg = config.networking.netnsIf;
in {
options.networking.netnsIf = {
assignments = mkOption {
description = ''
Assign network interfaces to a network namespaces by MAC address.
'';
type = types.attrsOf (types.listOf types.str);
default = {};
};
};
config =
mkIf (cfg.assignments != {})
{
systemd.services = mkMerge [
{
"netns@" = {
description = "Ensure the %I network namespace exists";
serviceConfig = {
Type = "oneshot";
};
scriptArgs = "%I";
script = ''
set -eo pipefail
_network_namespace="$1"
if ! [ -n "$(${getExe' pkgs.iproute2 "ip"} netns list | grep "$_network_namespace")" ] ; then
${getExe' pkgs.iproute2 "ip"} netns add "$_network_namespace"
fi
'';
};
}
(flip mapAttrs' cfg.assignments (n: _:
nameValuePair "netns-${n}-if@" {
description = "Move %I interface to namespace";
requires = ["netns@${n}.service"];
after = ["netns@${n}.service"];
scriptArgs = "%I";
script = ''
set -eo pipefail
_kernel_name="$(basename "$1")"
${getExe' pkgs.iproute2 "ip"} link set "$_kernel_name" netns "${n}"
'';
}))
];
services.udev.extraRules =
flip (concatMapStringsSep "\n") (flatten (mapAttrsToList (n: v:
map (x: {
interface = x;
namespace = n;
})
v)
cfg.assignments)) ({
interface,
namespace,
}: ''
SUBSYSTEM=="net", ACTION=="add", DEVPATH!="/devices/virtual/*", ATTR{address}=="${interface}", TAG+="systemd", ENV{SYSTEMD_WANTS}="netns-${namespace}-if@.service"
'');
};
}