{ config, lib, inputs, ... }: let cfg = config.os.srv.opnsense; makePciArgs = ids: builtins.concatLists ( map (id: [ "-device" "vfio-pci,host=${id}" ]) 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 = [ "01:00.0" "01:00.1" "01:00.2" "01:00.3" ]; description = "List of PCI bus addresses to pass through to the VM."; }; vendorIDs = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; example = [ "8086:1521" ]; description = "List of Vendor:Device IDs to bind 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 image"; }; }; config = lib.mkIf cfg.enable { networking = { bridges."br-lan".interfaces = [ ]; # TODO configure this interfaces."br-lan".ipv4.addresses = [ { address = "10.0.0.2"; prefixLenght = 16; } ]; }; boot = { kernelParams = [ "intel_iommu=on" "iommu=pt" ]; kernelModules = [ "vfio_pci" "vfio" "vfio_iommu_type1" ]; extraModprobeConfig = '' options vfio-pci ids=${lib.concatStringsSep "," cfg.vendorIDs} ''; }; microvm.vms.opnsense = { autostart = true; config = { imports = [ inputs.microvm.nixosModules.microvm ]; networking.hostName = "opnsense"; microvm = { vcpu = 2; mem = 4096; hypervisor = "qemu"; interfaces = [ { type = "bridge"; id = "vm-lan"; bridge = "br-lan"; } ]; qemu.extraArgs = [ "-machine" "q35,accel=kvm,kernel-irqchip=on" "-cpu" "host" ] ++ (makePciArgs cfg.pciIDs); }; }; }; }; }