{ config, pkgs, lib, vmixLib, ... }: with lib; with vmixLib.network; let vmixCfg = config.vmix; mkServices4aVM = name: cfg: let vmCfg = cfg // { inherit name; }; netName = head (attrNames vmCfg.network.vmix); netCfg = vmCfg.network.vmix.${netName} // { name = netName; }; mkTap4aLan = lanName: tapCfg: let tapInterfaceName = "vt-${vmCfg.name}-${lanName}"; lanInterfaceName = "brx-${lanName}"; in { name = lanName; iface = tapInterfaceName; create = '' ip tuntap add dev ${tapInterfaceName} mode tap ip link set dev ${tapInterfaceName} up ip link set dev ${tapInterfaceName} master ${lanInterfaceName} ''; delete = '' ip link del ${tapInterfaceName} ''; }; mkMacvtap = macvtapName: macvtapCfg: let macvtapNetworkCfg = config.vmix.networks.${netCfg.name}.bridges.macvtaps.${macvtapName}; macvtapInterfaceName = "mt-${vmCfg.name}-${macvtapNetworkCfg.uplink.iface}"; in { name = macvtapName; iface = macvtapInterfaceName; create = '' ip link add link ${macvtapNetworkCfg.uplink.iface} name ${macvtapInterfaceName} type macvtap mode bridge ip link set ${macvtapInterfaceName} netns ${netName}.vmix ''; delete = '' ip netns exec ${netName}.vmix ip link del ${macvtapInterfaceName} ''; }; allTaps = (mapAttrsToList mkTap4aLan netCfg.lans); allMacvtaps = (mapAttrsToList mkMacvtap netCfg.macvtaps); createTapsforLansScript = pkgs.writeShellScript "${vmCfg.name}-taps-vmix" ( concatStringsSep "\n" (builtins.map (tap: tap.create) allTaps) ); deleteTapsforLansScript = pkgs.writeShellScript "${vmCfg.name}-taps-vmix" ( concatStringsSep "\n" (builtins.map (tap: tap.delete) allTaps) ); createMacvapsScript = pkgs.writeShellScript "${vmCfg.name}-taps-vmix" ( concatStringsSep "\n" (builtins.map (macvtap: macvtap.create) allMacvtaps) ); deleteMacvapsScript = pkgs.writeShellScript "${vmCfg.name}-taps-vmix" ( concatStringsSep "\n" (builtins.map (macvtap: macvtap.delete) allMacvtaps) ); osImage = vmixLib.customizeImage vmCfg.disks.os.file { name = vmCfg.name; }; qemuStartVMScript = pkgs.writeShellScript "${vmCfg.name}-qemu-vmix" '' exec qemu-system-${vmCfg.arch} \ -nographic \ ${optionalString vmCfg.kvm "-accel kvm"} \ -name ${vmCfg.name} \ -m ${toString vmCfg.mem.size} \ -smp cores=${toString vmCfg.cpu.cores} \ -cpu ${vmCfg.cpu.model} \ -machine type=${vmCfg.pc.type} \ ${optionalString vmCfg.bios.efi "-bios ${pkgs.OVMF.fd}/FV/OVMF.fd"} \ ${optionalString vmCfg.bios.tpm "-chardev socket,id=chrtpm,path=/tmp/mytpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0"} \ -drive file=${toString osImage},format=qcow2,if=virtio${optionalString (vmCfg.disks.os.persist == false) ",snapshot=on"} \ ${optionalString (vmCfg.disks.iso.file != null) "-drive file=${toString vmCfg.disks.iso.file},media=cdrom,readonly=on"} \ ${concatMapStrings (diskCfg: '' -drive file=${diskCfg.file},format=qcow2,if=${toString vmCfg.disks.bus} \ '') (attrValues vmCfg.disks.add)} \ ${concatMapStrings (shareCfg: '' -virtfs local,path=${toString shareCfg.source},security_model=passthrough,mount_tag=${shareCfg.target} \ '') (attrValues vmCfg.shares)} \ ${concatMapStrings (tapCfg: '' -device virtio-net-pci,netdev=lan-${tapCfg.name} \ -netdev tap,id=lan-${tapCfg.name},ifname=${tapCfg.iface},script=no,downscript=no \ '') allTaps} \ ${optionalString cfg.network.user.enable " -netdev user,id=user \ -device virtio-net-pci,netdev=user \ "} \ ${optionalString (vmCfg.boot.menu == true) "-boot menu=on"} \ #${optionalString (length vmCfg.boot.order > 0) "-boot order=${concatStringsSep "," vmCfg.boot.order}"} # ${concatMapStrings (macvtap: '' # -device virtio-net-pci,netdev=macvtap-${macvtap.name} \ # -netdev tap,id=macvtap-${macvtap.name},ifname=${macvtap.iface},script=no,downscript=no \ # '') allMacvtaps} \ ''; in { "vm.vmix@${vmCfg.name}" = rec { requires = [ "net.vmix@${netCfg.name}.target" "macvtaps.vm.vmix@${vmCfg.name}.service" ]; unitConfig.JoinsNamespaceOf = "ns.net.vmix@${netCfg.name}.service"; after = requires; path = with pkgs; [ iproute2 qemu ]; serviceConfig = { ExecStartPre = createTapsforLansScript; ExecStart = qemuStartVMScript; ExecStopPost = deleteTapsforLansScript; PrivateTmp = true; ProtectSystem = true; ProtectHome = true; PrivateNetwork = true; }; }; "macvtaps.vm.vmix@${vmCfg.name}" = rec { bindsTo = [ "net.vmix@${netCfg.name}.target" ]; after = bindsTo; partOf = [ "vm.vmix@${vmCfg.name}.service" ]; path = with pkgs; [ iproute2 ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStart = createMacvapsScript; ExecStop = deleteMacvapsScript; }; }; }; vmServices = concatMapAttrs mkServices4aVM vmixCfg.vms; in { config.systemd.services = vmServices; }