{ pkgs, lib, config, ... }: with lib; let cfg = config.services.netns; # Escape as required by: https://www.freedesktop.org/software/systemd/man/systemd.unit.html escapeUnitName = name: lib.concatMapStrings (s: if lib.isList s then "-" else s) (builtins.split "[^a-zA-Z0-9_.\\-]+" name); in { options.services.netns = { namespaces = mkOption { description = "netns namespaces to create"; type = types.attrsOf (types.submodule ({ name, ... }: { options = { nftables = mkOption { type = types.lines; default = ""; description = '' Nftables ruleset. ''; }; sysctl = mkOption { type = with types; attrsOf (nullOr (oneOf [bool str int])); default = {}; description = '' Kernel sysctl. ''; }; service = mkOption { type = types.attrs; default = {}; description = '' Systemd configuration specific to this netns service. ''; }; }; })); default = {}; }; }; config = { systemd.services = mapAttrs' (name: c: nameValuePair "netns-${escapeUnitName name}" (mkMerge [ { description = "${name} network namespace"; before = [ "network.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; PrivateNetwork = true; ExecStart = "${pkgs.iproute}/bin/ip netns add ${escapeShellArg name}"; ExecStartPost = optional config.networking.nftables.enable "${pkgs.iproute}/bin/ip netns exec ${escapeShellArg name} ${pkgs.writeScript "nftables-ruleset" '' #!${pkgs.nftables}/bin/nft -f flush ruleset ${c.nftables} ''}"; ExecStop = "${pkgs.iproute}/bin/ip netns del ${escapeShellArg name}"; }; } #cfg.service c.service ])) cfg.namespaces; meta.maintainers = with lib.maintainers; [ julm ]; }; }