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/kvmfile descriptor, includingKVM_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) andpc(the older i440FX with PCI). Machine types are versioned, for examplepc-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 helplists 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-balloonand 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 examplevhost-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.