{ config, lib, inputs, ... }: let cfg = config.os.srv.opnsense; makePciArgs = ids: builtins.concatLists ( map (id: [ "-device" "vfio-pci,host=${id},rombar=0" ]) ids ); in { imports = [ inputs.microvm.nixosModules.host ]; options.os.srv.opnsense = { enable = lib.mkEnableOption "enables an opnsense microvm"; pciIDs = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; example = [ "03:00.0" "03:00.1" ]; description = "List of PCI bus addresses to pass through directly to OPNsense."; }; vendorIDs = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; example = [ "8086:1563" ]; description = "List of Vendor:Device IDs to bind explicitly to the vfio-pci driver."; }; imagePath = lib.mkOption { type = lib.types.path; default = /var/lib/microvm/images/opnsense.qcow2; description = "Path to the OPNsense qcow2 drive image block."; }; }; config = lib.mkIf cfg.enable { boot = { kernelParams = [ "intel_iommu=on" "iommu=pt" ]; kernelModules = [ "vfio_pci" "vfio" "vfio_iommu_type1" ]; extraModprobeConfig = '' options vfio-pci ids=${lib.concatStringsSep "," (lib.unique cfg.vendorIDs)} ''; }; microvm.vms.opnsense = { autostart = true; config = { imports = [ inputs.microvm.nixosModules.microvm ]; networking.hostName = "opnsense"; microvm = { vcpu = 4; mem = 4096; hypervisor = "qemu"; interfaces = [ { type = "bridge"; id = "vtnet0"; bridge = "br-srv"; } ]; qemu.extraArgs = [ "-machine" "q35,accel=kvm,kernel-irqchip=on" "-cpu" "host,migratable=off,+invtsc" ] ++ (makePciArgs cfg.pciIDs); }; }; }; }; }