{ pkgs, lib, ... }: let inherit (lib) imap flatten listToAttrs ; access-topology = [ [ 1000 1001 1002 1003 ] [ 1000 1001 1002 1003 ] ]; br_name = sw: vni: "sw${toString sw}-vni${toString vni}"; client_name = sw: vni: "h-${br_name sw vni}"; vtep_name = sw: vni: "v-${toString sw}-${toString vni}"; sw_name = sw: "sw${toString sw}"; vtep_br_name = sw: vni: "br${vtep_name sw vni}"; vtep_vxlan_name = sw: vni: "x${vtep_name sw vni}"; clients = listToAttrs <| flatten <| imap ( sw: map (vni: { name = client_name sw vni; value = { privateNetwork = true; ephemeral = true; hostBridge = br_name sw vni; autoStart = true; config = { imports = [ ./common.nix ]; networking.hostName = client_name sw vni; services.resolved.enable = false; systemd.network.networks = { "10-eth0" = { name = "eth0"; address = [ "10.0.${toString sw}.${toString (vni - 999)}/16" ]; linkConfig.Promiscuous = true; }; }; }; }; }) ) access-topology; switchs = listToAttrs <| imap (sw: vnis: { name = sw_name sw; value = { privateNetwork = true; ephemeral = true; hostBridge = "br0"; autoStart = true; extraVeths = listToAttrs <| map (vni: { name = vtep_name sw vni; value.hostBridge = br_name sw vni; }) vnis; config = { imports = [ ./common.nix ]; networking.hostName = sw_name sw; services.resolved.enable = false; systemd.network = { networks = { "10-eth0" = { name = "eth0"; address = [ "10.0.0.${toString (sw + 1)}/24" ]; networkConfig.VXLAN = map (vtep_vxlan_name sw) vnis; linkConfig.Promiscuous = true; }; } // listToAttrs ( flatten <| map (vni: [ { name = "10-${vtep_name sw vni}"; value = { name = vtep_name sw vni; linkConfig.Promiscuous = true; networkConfig = { Bridge = vtep_br_name sw vni; LinkLocalAddressing = false; LLDP = false; EmitLLDP = false; IPv6AcceptRA = false; IPv6SendRA = false; }; }; } { name = "10-${vtep_br_name sw vni}"; value = { name = vtep_br_name sw vni; linkConfig.Promiscuous = true; networkConfig = { LinkLocalAddressing = false; LLDP = false; EmitLLDP = false; IPv6AcceptRA = false; IPv6SendRA = false; }; }; } { name = "10-${vtep_vxlan_name sw vni}"; value = { name = vtep_vxlan_name sw vni; linkConfig.Promiscuous = true; networkConfig = { Bridge = vtep_br_name sw vni; LinkLocalAddressing = false; LLDP = false; EmitLLDP = false; IPv6AcceptRA = false; IPv6SendRA = false; }; }; } ]) vnis ); netdevs = listToAttrs ( flatten <| map (vni: [ { name = "10-${vtep_br_name sw vni}"; value = { netdevConfig = { Name = vtep_br_name sw vni; Kind = "bridge"; }; bridgeConfig.STP = false; }; } { name = "10-${vtep_vxlan_name sw vni}"; value = { netdevConfig = { Name = vtep_vxlan_name sw vni; Kind = "vxlan"; }; vxlanConfig = { VNI = vni; Remote = "10.0.0.1"; Local = "10.0.0.${toString (sw + 1)}"; DestinationPort = 4789; PortRange = 4789; }; }; } ]) vnis ); }; }; }; }) access-topology; in { virtualisation = { memorySize = 4 * 1024; cores = 4; diskImage = null; forwardPorts = [ { from = "host"; host.port = 2222; guest.port = 22; } ]; }; nixos-shell.mounts = { mountHome = false; extraMounts."/vxlan" = { target = ./..; cache = "none"; }; }; imports = [ ./common.nix ]; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; }; environment.defaultPackages = [ pkgs.pwru ]; containers = { "router" = { privateNetwork = true; ephemeral = true; hostBridge = "br0"; bindMounts."/vxlan".hostPath = "/vxlan"; autoStart = true; config = { imports = [ ./common.nix ]; services.resolved.enable = false; systemd.network.networks = { "10-eth0" = { name = "eth0"; address = [ "10.0.0.1/24" ]; }; }; }; }; } // switchs // clients; systemd.network = let brs = [ "br0" ] ++ flatten (imap (sw: map (br_name sw)) access-topology); in { networks = listToAttrs <| map (name: { name = "10-${name}"; value = { inherit name; linkConfig.Promiscuous = true; networkConfig = { LinkLocalAddressing = false; LLDP = false; EmitLLDP = false; IPv6AcceptRA = false; IPv6SendRA = false; }; }; }) brs ++ flatten ( imap ( sw: map (vni: { name = "10-${vtep_name sw vni}"; value = { name = vtep_name sw vni; linkConfig.Promiscuous = true; networkConfig = { LinkLocalAddressing = false; LLDP = false; EmitLLDP = false; IPv6AcceptRA = false; IPv6SendRA = false; }; }; }) ) access-topology ); netdevs = listToAttrs <| map (name: { name = "10-${name}"; value = { netdevConfig = { Name = name; Kind = "bridge"; }; bridgeConfig.STP = false; }; }) brs; }; }