{ config, lib, notnft, ... }: let inherit (lib) mapAttrsToList mkOption hasAttr types traceVal flip mapAttrs' mapAttrs nameValuePair ; # a = [ # [ (is.eq ip.protocol (f: with f; set [ tcp ])) (is.eq ip.daddr "10.80.1.2") (is.eq th.dport "22") accept ] # ]; cfg = config.microvm; protocolEnumToNft = f: proto: f.${proto}; tcpUdpServiceOptions.options = { hostName = mkOption { type = types.str; }; port = mkOption { type = types.port; }; protocol = mkOption { type = types.listOf (types.enum ["tcp" "udp"]); }; }; httpServiceOptions.options = { hostName = mkOption { type = types.str; }; port = mkOption { type = types.port; }; }; icmpServiceOptions.options = { hostName = mkOption { type = types.str; }; }; tcpUdpConnectionOptions.options = { target = mkOption { type = types.str; }; }; icmpConnectionOptions.options = { target = mkOption { type = types.str; }; }; httpConnectionOptions.options = { target = mkOption { type = types.str; }; }; lookupService = name: type: context: if hasAttr name cfg.services.${type} then cfg.services.${type}.${name} else throw "Unknown ${type} service ${name} at ${context}"; lookupIds = hostName: context: if hasAttr hostName subConfigurations then { inherit (subConfigurations.${hostName}.config.config.microvm) groupId taskId ; } else throw "Unknown hostName ${hostName} at ${context}"; subConfigurations = cfg.vms; in { options.microvm = { services = { tcpUdp = mkOption { type = with types; types.attrsOf (submodule tcpUdpServiceOptions); default = {}; }; icmp = mkOption { type = with types; types.attrsOf (submodule icmpServiceOptions); default = {}; }; http = mkOption { type = with types; types.attrsOf (submodule httpServiceOptions); default = {}; }; }; connections = { tcpUdp = mkOption { type = with types; listOf (submodule tcpUdpConnectionOptions); default = []; }; icmp = mkOption { type = with types; listOf (submodule icmpConnectionOptions); default = []; }; http = mkOption { type = with types; listOf (submodule httpConnectionOptions); default = []; }; }; }; config.microvm.services.tcpUdp = flip mapAttrs' cfg.services.http ( n: v: nameValuePair (n + "@http") { inherit (v) hostName port ; protocol = ["tcp"]; } ); config.microvm.connections.tcpUdp = flip map cfg.connections.http ( v: { target = v.target + "@http"; } ); config.networking.notnft.rules = with notnft.dsl; with payload; ruleset { bridge-t = add table {family = f: f.bridge;} { output-body = lib.foldl (acc: x: acc x) (add chain) ((flip mapAttrsToList subConfigurations ( n: v: let microvmConfig = v.config.config.microvm; tcpUdpRules = flip map microvmConfig.connections.tcpUdp (connection: let service = lookupService connection.target "tcpUdp" n; ids = lookupIds service.hostName n; in [ (is.eq meta.oifname "mvm-${microvmConfig.hostName}") (is.eq ip.protocol (f: with f; set (map (protocolEnumToNft f) service.protocol))) (is.eq ip.saddr "10.80.${toString microvmConfig.groupId}.${toString microvmConfig.taskId}") (is.eq ip.daddr "10.80.${toString ids.groupId}.${toString ids.taskId}") (is.eq th.dport service.port) accept ]); icmpRules = flip map microvmConfig.connections.icmp (connection: let service = lookupService connection.target "icmp" n; ids = lookupIds service.hostName n; in [ (is.eq meta.oifname "mvm-${microvmConfig.hostName}") (is.eq ip.protocol (f: with f; icmp)) (is.eq ip.saddr "10.80.${toString microvmConfig.groupId}.${toString microvmConfig.taskId}") (is.eq ip.daddr "10.80.${toString ids.groupId}.${toString ids.taskId}") accept ]); in tcpUdpRules ++ icmpRules )) ++ (flip map cfg.connections.icmp ( connection: let service = lookupService connection.target "icmp" "host"; ids = lookupIds service.hostName "host"; in [ (is.eq meta.oifname "mvm-${service.hostName}") (is.eq ip.protocol (f: with f; icmp)) (is.eq ip.saddr "10.80.${toString ids.groupId}.1") (is.eq ip.daddr "10.80.${toString ids.groupId}.${toString ids.taskId}") accept ] )) ++ (flip map cfg.connections.tcpUdp ( connection: let service = lookupService connection.target "tcpUdp" "host"; ids = lookupIds service.hostName "host"; in [ (is.eq meta.oifname "mvm-${service.hostName}") (is.eq ip.protocol (f: with f; set (map (protocolEnumToNft f) service.protocol))) (is.eq ip.saddr "10.80.${toString ids.groupId}.1") (is.eq ip.daddr "10.80.${toString ids.groupId}.${toString ids.taskId}") (is.eq th.dport service.port) accept ] ))); }; }; }