When an RFP, a migration plan or a vendor slide says “KVM”, it almost never means only the kernel module called kvm. It means a stack of three cooperating pieces: KVM in the Linux kernel, QEMU in userspace, and very often libvirt as the management layer. Knowing where one ends and the next begins tells you where to look when something breaks, which component a CVE actually affects, and what a product built “on KVM” really depends on.

The stack at a glance#

Layer Component Runs as Job
Management platform Incus, Proxmox VE, OpenStack Nova, KubeVirt, … Daemons and APIs Clusters, placement, storage and network orchestration, users, UI
Management API libvirt (virtqemud or libvirtd) One daemon per host Stable API and XML model for VMs (“domains”); starts and supervises QEMU
Device model QEMU One process per VM Emulates the machine: chipset, firmware, disks, NICs, display; runs vCPUs as threads
Hypervisor core KVM (kvm.ko plus kvm_intel.ko or kvm_amd.ko) Kernel modules Runs guest code on the real CPU using VT-x or AMD-V; virtualizes memory via EPT/NPT
Hardware CPU with VT-x/AMD-V, IOMMU Hardware virtualization and DMA isolation

Not every platform uses every layer. Libvirt is optional: some platforms drive QEMU directly. KVM is what makes QEMU fast, but QEMU can run without it.

KVM: the kernel part#

KVM is a set of Linux kernel modules. The generic kvm module carries the common code, and a vendor module (kvm_intel for Intel VT-x, kvm_amd for AMD-V/SVM) uses the processor’s hardware virtualization extensions. With them, guest instructions run directly on the physical CPU in a special guest mode, and the CPU’s second-level address translation (Intel EPT, AMD NPT) maps guest memory without the hypervisor trapping every page-table change.

KVM exposes itself to userspace as a character device, /dev/kvm. The kernel’s KVM API documentation describes three classes of ioctls on it:

  • System ioctls on the /dev/kvm file descriptor, including KVM_CREATE_VM, which returns a new file descriptor for a VM.
  • VM ioctls on that descriptor, which set things like the memory layout and create vCPUs with KVM_CREATE_VCPU.
  • vCPU ioctls on each vCPU descriptor, most importantly KVM_RUN, which enters the guest.

KVM_RUN returns to userspace when the guest does something KVM does not handle itself, such as a port I/O or MMIO access to an emulated device. That is the boundary: KVM virtualizes the CPU and memory, and hands device emulation back to a userspace program. KVM on its own has no notion of a disk, a NIC or a BIOS.

Check that a host has the pieces:

# Does the CPU advertise hardware virtualization? (vmx = Intel, svm = AMD)
grep -m1 -o -w -E 'vmx|svm' /proc/cpuinfo

# Are the modules loaded?
lsmod | grep kvm

# Does the device exist, and who may open it?
ls -l /dev/kvm

On an AMD host the output looks like this:

svm
kvm_amd               212992  0
kvm                  1404928  1 kvm_amd
irqbypass              12288  1 kvm
crw-rw---- 1 root kvm 10, 232 Oct  7 01:37 /dev/kvm

If grep prints nothing, virtualization is either absent or disabled in firmware. If /dev/kvm is missing even though the flag is present, the vendor module failed to load; dmesg usually says why (commonly “disabled by bios”).

QEMU: the machine around the CPU#

QEMU is a userspace emulator and virtualizer. For each VM it runs one process that contains the whole virtual machine: memory is mapped into that process, and each vCPU is a thread that loops on KVM_RUN. When a vCPU exits for I/O, QEMU’s device model handles it and resumes the guest.

QEMU defines:

  • The machine type. On x86 the two common ones are q35 (a Q35 chipset with PCIe) and pc (the older i440FX with PCI). Machine types are versioned, for example pc-q35-9.2, so a guest sees the same virtual hardware after a QEMU upgrade; that stability is also what lets a VM live-migrate between hosts running different QEMU builds. qemu-system-x86_64 -machine help lists what your build supports.
  • Emulated devices. Disk controllers (AHCI, LSI SCSI, NVMe), NICs (e1000, rtl8139), USB controllers, VGA, TPM front ends, and the firmware itself (SeaBIOS for legacy BIOS, OVMF for UEFI).
  • VirtIO devices. Paravirtual devices (virtio-blk, virtio-scsi, virtio-net, virtio-balloon and others) designed for virtualization rather than copied from real hardware. They avoid the many costly exits that emulating a real register interface causes. Linux has the drivers built in; Windows needs the virtio-win drivers. Some data paths can move out of QEMU entirely, for example vhost-net, which handles virtio-net packets in the kernel.

KVM acceleration in QEMU. QEMU can run guests without KVM using TCG, its dynamic binary translator. That is how it emulates other architectures, and it is far slower. Acceleration is a startup option: -accel kvm (or -machine accel=kvm); the older -enable-kvm spelling still works. The QEMU documentation notes that TCG is the default if you choose nothing. A minimal KVM guest started by hand:

qemu-system-x86_64 \
  -accel kvm \
  -machine q35 \
  -cpu host \
  -smp 2 -m 4G \
  -drive file=disk.qcow2,if=virtio \
  -nic user,model=virtio-net-pci

qemu-system-x86_64 -accel help lists the accelerators compiled in. On RHEL and its rebuilds the binary is /usr/libexec/qemu-kvm rather than qemu-system-x86_64.

Running QEMU by hand is fine for a lab, but the command lines for real VMs run to dozens of options, and QEMU itself keeps no inventory: when the process exits, the VM’s definition is gone. Management tools control a running QEMU over QMP, the QEMU Machine Protocol, a JSON interface on a socket.

libvirt: the management API#

libvirt is a C library, a daemon and a set of tools that give VMs a stable API across hypervisors (QEMU/KVM, Xen, LXC, bhyve and others). For QEMU/KVM it:

  • stores persistent VM definitions, called domains, as XML;
  • builds the QEMU command line from that XML, starts QEMU, and talks to it over QMP;
  • manages the surrounding host objects: storage pools and volumes, virtual networks, host devices for passthrough, secrets;
  • applies cgroups, SELinux or AppArmor labels, and namespaces to each QEMU process;
  • runs migration, snapshots and hotplug through one API, used by virsh, virt-manager, Cockpit and language bindings.

A trimmed domain definition shows the mapping back to QEMU:

<domain type='kvm'>
  <name>web01</name>
  <memory unit='GiB'>4</memory>
  <vcpu>2</vcpu>
  <os>
    <type arch='x86_64' machine='q35'>hvm</type>
  </os>
  <cpu mode='host-model'/>
  <devices>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/var/lib/libvirt/images/web01.qcow2'/>
      <target dev='vda' bus='virtio'/>
    </disk>
    <interface type='network'>
      <source network='default'/>
      <model type='virtio'/>
    </interface>
  </devices>
</domain>

type='kvm' asks for KVM acceleration; machine='q35' is the QEMU machine type (libvirt records the versioned name it resolves to); bus='virtio' and model type='virtio' select VirtIO devices.

Modular daemons. Historically one daemon, libvirtd, carried every driver. libvirt now also ships modular daemons, one per driver: virtqemud for QEMU, and virtnetworkd, virtstoraged, virtnodedevd, virtsecretd, virtnwfilterd and virtinterfaced for the secondary drivers, plus virtproxyd for remote access and for clients that still use the old libvirtd socket path. Red Hat’s RHEL 9 documentation marks the monolithic libvirtd as deprecated and recommends the modular daemons. Client commands do not change: virsh -c qemu:///system reaches virtqemud.

Useful inspection commands:

virt-host-validate qemu                  # host checks for the QEMU/KVM driver
virsh -c qemu:///system list --all       # defined and running domains
virsh -c qemu:///system dumpxml web01    # the domain XML, including expanded defaults
virsh -c qemu:///system domcapabilities  # what this host's QEMU and KVM can offer a VM

virt-host-validate is a quick way to see the whole stack at once. Excerpt from a host where the user is not in the kvm group:

  QEMU: Checking for hardware virtualization                 : PASS
  QEMU: Checking if device /dev/kvm exists                   : PASS
  QEMU: Checking if device /dev/kvm is accessible            : FAIL (Check /dev/kvm is world writable or you are in a group that is allowed to access it)
  QEMU: Checking if device /dev/vhost-net exists             : PASS
  QEMU: Checking for device assignment IOMMU support         : PASS
  QEMU: Checking if IOMMU is enabled by kernel               : PASS

The layers above#

Higher-level platforms add clustering, scheduling, storage and networking orchestration, multi-tenancy and a UI. They differ in whether they go through libvirt:

Platform Talks to How a VM runs
Incus QEMU directly Incus generates the QEMU configuration and controls each VM over QMP; its documentation states that “virtual machines are implemented through the use of QEMU”. No libvirt.
Proxmox VE QEMU directly qemu-server and the qm tool build the QEMU command line; the Proxmox wiki states it does not use libvirt.
OpenStack Nova libvirt The libvirt compute driver turns a Nova instance into a libvirt domain on the chosen compute node.
KubeVirt libvirt, inside a pod Each VM gets a virt-launcher pod. KubeVirt’s component documentation: “An instance of libvirtd is present in every VMI pod. virt-launcher uses libvirtd to manage the life-cycle of the VMI process.” virt-handler on each node coordinates with the kubelet.

In all four cases the guest ends up as a QEMU process using /dev/kvm. The difference is in who writes the configuration and supervises the process. That explains why, for example, a QEMU security fix matters to every one of them, while a libvirt bug may affect OpenStack and KubeVirt but not Incus or Proxmox VE.

Why “KVM” is shorthand for the stack#

KVM is the piece that makes Linux a hypervisor, so the name stuck to the whole arrangement. In practice:

  • “KVM supports device X” really means QEMU emulates X, or the host can pass it through via VFIO.
  • “KVM live migration” is QEMU’s migration code, usually driven by libvirt or by the platform above, with KVM providing dirty-page tracking.
  • “KVM version” is ambiguous. Ask for the kernel, QEMU, and (if used) libvirt versions separately; behavior such as available machine types and CPU models comes from QEMU and libvirt, not from the kernel module.

When troubleshooting, map the symptom to the layer:

Symptom Look at first
/dev/kvm missing, “KVM not available”, VMs extremely slow Firmware settings, kvm_intel/kvm_amd load, dmesg
Guest cannot see a disk or NIC, wrong firmware, device errors QEMU device configuration (virsh dumpxml, or the platform’s generated config)
VM definition lost, permissions, SELinux denials, pools and networks libvirt (journalctl -u virtqemud) or the platform that replaces it
Placement, quotas, HA, users The management platform

Where Victor fits#

Victor is a control plane and console that sits at the top layer. For KVM virtual machines it runs upstream Incus (the “Classic” runtime), so QEMU and KVM do the work without libvirt, and for VMs on Kubernetes it drives KubeVirt, whose virt-launcher pods run libvirt and QEMU. Both appear in one inventory. Its host check (victor-hwcheck) fails a machine without virtualization extensions or /dev/kvm, which are the same bottom-layer checks shown above.

See Victor's architecture