150 lines
No EOL
6 KiB
Nix
150 lines
No EOL
6 KiB
Nix
{ 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;
|
|
mac = tapCfg.mac;
|
|
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: macvtapVmCfg:
|
|
let
|
|
macvtapNetworkCfg = config.vmix.networks.${netCfg.name}.bridges.macvtaps.${macvtapName};
|
|
macvtapInterfaceName = "mt-${vmCfg.name}-${macvtapNetworkCfg.uplink.iface}";
|
|
in
|
|
{
|
|
name = macvtapName;
|
|
iface = macvtapInterfaceName;
|
|
mac = macvtapVmCfg.mac;
|
|
create = ''
|
|
ip link add link ${macvtapNetworkCfg.uplink.iface} name ${macvtapInterfaceName} type macvtap mode bridge
|
|
${lib.optionalString (macvtapVmCfg.mac != null) "ip link set dev ${macvtapInterfaceName} address ${macvtapVmCfg.mac}"}
|
|
ip link set ${macvtapInterfaceName} netns ${netName}.vmix
|
|
ip netns exec ${netName}.vmix ip link set dev ${macvtapInterfaceName} up
|
|
'';
|
|
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;
|
|
commands = ''
|
|
truncate /etc/machine-id
|
|
run-command systemd-machine-id-setup
|
|
run-command ssh-keygen -A
|
|
'';
|
|
};
|
|
|
|
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},mac=${tapCfg.mac} \
|
|
-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"} \
|
|
${concatStrings (imap1 (i: macvtap: ''
|
|
-device virtio-net-pci,netdev=macvtap-${macvtap.name},mac=$(ip l show ${macvtap.iface} | awk '/link\/ether/{print $2}') \
|
|
-netdev tap,id=macvtap-${macvtap.name},fd=${toString (i+2)} ${toString (i+2)}<>/dev/tap$(ip l show ${macvtap.iface} | awk -F':' '/${macvtap.iface}/{print $1}') \
|
|
'') allMacvtaps)} \
|
|
#${optionalString (length vmCfg.boot.order > 0) "-boot order=${concatStringsSep "," vmCfg.boot.order}"} \
|
|
'';
|
|
in
|
|
{
|
|
"vm.vmix@${vmCfg.name}" = rec {
|
|
bindsTo = [ "net.vmix@${netCfg.name}.target" "macvtaps.vm.vmix@${vmCfg.name}.service" ];
|
|
unitConfig.JoinsNamespaceOf = "ns.net.vmix@${netCfg.name}.service";
|
|
after = bindsTo;
|
|
path = with pkgs; [ iproute2 qemu gawk ];
|
|
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;
|
|
} |