{ config, pkgs, lib, self, ... }: let mainServers = [ "server2" ]; pillar = self.lib.saltPillarFor "*"; renameAttr = from: to: attrset: builtins.foldl' (result: name: if name == from then result // { "${to}" = attrset.${name}; } else result // { "${name}" = attrset.${name}; } ) {} (builtins.attrNames attrset); # HACK: `type = "phys"` works but once an LXC container is stopped # the VLAN interface is not moved back. forceVeth = interface: interface // { type = "veth"; }; netHasDHCP = net: net == "pub" || net == "serv" || builtins.match "priv[[:digit:]]+" net != null; in { options.salt-pillar = lib.mkOption {}; config.salt-pillar = pillar; config.site.net = lib.mkMerge ([ (builtins.mapAttrs (_: vlan: { vlan = vlan; }) pillar.vlans) (builtins.mapAttrs (_: subnet4: { inherit subnet4; }) pillar.subnets-inet) (builtins.mapAttrs (_: hosts4: { inherit hosts4; }) pillar.hosts-inet) (builtins.mapAttrs (net: dhcpData: { dhcp = { inherit (dhcpData) start end time max-time; server = if netHasDHCP net then "${net}-gw" else null; fixed-hosts = if dhcpData ? fixed-hosts then dhcpData.fixed-hosts else {}; router = dhcpData.host-opts.routers; }; domainName = dhcpData.string-opts.domain-name; }) pillar.dhcp) { core.ospf.secret = pillar.ospf.secret; } ] ++ ( map (ctx: builtins.mapAttrs (_: subnet: { subnets6.${ctx} = subnet; }) pillar.subnets-inet6.${ctx} ) (builtins.attrNames pillar.subnets-inet6) ) ++ ( map (ctx: builtins.mapAttrs (_: subnet: { hosts6.${ctx} = subnet; }) pillar.hosts-inet6.${ctx} ) (builtins.attrNames pillar.hosts-inet6) )); config.site.hosts = lib.mkMerge ( [ { # Static definitions mgmt-gw.firewall.enable = true; priv13-gw.firewall.enable = true; dnscache = { role = "container"; location = "server2"; interfaces.serv = { gw4 = "serv-gw"; gw6 = "serv-gw"; type = "veth"; }; services.dnscache.enable = true; }; c3d2-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" "freifunk" ]; serv-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" "freifunk" ]; cls-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" "freifunk" ]; mgmt-gw.ospf.allowedUpstreams = [ "upstream1" "upstream2" "freifunk" ]; bgp.ospf.allowedUpstreams = [ "upstream1" "upstream2" "freifunk" ]; anon1.ospf.allowedUpstreams = [ "upstream1" "upstream2" "freifunk" ]; pub-gw.ospf.allowedUpstreams = [ "anon1" "freifunk" ]; c3d2-anon.ospf.allowedUpstreams = [ "anon1" "freifunk" ]; } ( builtins.mapAttrs (hostName: _: { ospf.allowedUpstreams = [ "upstream2" "upstream1" "freifunk" ]; }) ( lib.filterAttrs (hostName: _: builtins.match "priv[[:digit:]]+-gw" hostName != null ) pillar.containers ) ) (builtins.foldl' (result: hostName: result // { "${hostName}" = { role = "server"; interfaces = builtins.mapAttrs (net: _: { type = "phys"; } // lib.optionalAttrs (net == "cluster") { gw4 = "cls-gw"; gw6 = "cls-gw"; }) ( lib.filterAttrs (_: hosts: hosts ? ${hostName}) ( pillar.hosts-inet // ( builtins.foldl' (result: hosts: result // hosts) {} (builtins.attrValues pillar.hosts-inet6) ) ) ); }; }) {} mainServers) (builtins.mapAttrs (_: switch: { inherit (switch) model location password; role = "switch"; }) pillar.switches) (builtins.mapAttrs (_: ap: { inherit (ap) model location password; role = "ap"; }) pillar.cpe) (builtins.mapAttrs (name: container: let ctPillar = self.lib.saltPillarFor name; in { role = "container"; location = "server2"; interfaces = builtins.mapAttrs (net: interface: renameAttr "gw" "gw4" (forceVeth interface) // { upstream = if ctPillar ? upstream && ctPillar.upstream.interface == net then { upBandwidth = ctPillar.upstream.up-bandwidth; } else null; } ) container.interfaces; wireguard = lib.optionalAttrs (ctPillar ? wireguard-instances) ( builtins.mapAttrs (net: wgData: { inherit (builtins.head wgData.peers) endpoint; publicKey = (builtins.head wgData.peers).public_key; privateKey = wgData.private_key; addresses = builtins.filter builtins.isString ( builtins.split "[, ]+" wgData.addr ); upBandwidth = ctPillar.upstream.up-bandwidth; }) ctPillar.wireguard-instances); ospf = let ospfConf = ctPillar.ospf; in lib.optionalAttrs (ctPillar ? ospf && ospfConf ? stubnets-inet) { stubNets4 = ospfConf.stubnets-inet; } // lib.optionalAttrs (ctPillar ? ospf && ospfConf ? stubnets-inet6) { stubNets6 = ospfConf.stubnets-inet6; }; bgp = if ctPillar ? bgp then let bgpConf = ctPillar.bgp; in { inherit (bgpConf) asn; peers = bgpConf.peers-inet // bgpConf.peers-inet6; } else null; forwardPorts = if ctPillar ? port-forwarding then map ({ proto, port, to }: { proto = proto; sourcePort = port; destination = to; }) ctPillar.port-forwarding else []; }) pillar.containers) ] ++ (map (net: builtins.mapAttrs (_: addr4: { }) pillar.hosts-inet.${net} ) (builtins.attrNames pillar.hosts-inet)) ++ (builtins.concatMap (ctx: map (net: builtins.mapAttrs (_: addr6: { }) pillar.hosts-inet6.${ctx}.${net} ) (builtins.attrNames pillar.hosts-inet6.${ctx}) ) (builtins.attrNames pillar.hosts-inet6)) ); config.site.ospf = { networks4 = [ "172.20.72.0/21" ]; networks6 = [ "fd23:42:c3d2:500::/56" "2a02:8106:208:5200::/56" "2a02:8106:211:e900::/56" ]; }; }