QEMU virtualization

Updated 11 November 2026

QEMU

KVM (Kernel-based Virtual Machine) is hardware virtualization support at the Linux kernel level for Intel VT and AMD SVM processors. QEMU is a hardware emulator that also works without KVM, but with KVM guest systems run much faster, so the QEMU + KVM combination is the main way to virtualize in Calculate. libvirt is a daemon and an interface for managing virtual machines of different technologies; many applications and web interfaces have been released for it; the graphical virt-manager is useful out of the box.

Calculate supports two ways to virtualize, and you have to choose between them:

task what to use
several isolated Linux systems on a shared kernel LXC containers and cl-lxc
run a ready-made image (.iso, .qcow2) or another OS with a single command QEMU directly
a permanent set of guest machines: console, snapshots, networking from a graphical editor virt-manager on top of libvirt
work with a guest machine disk without booting the machine qemu-nbd

Checking KVM support

Hardware acceleration requires CPU virtualization flags and the /dev/kvm device:

grep -m1 'model name' /proc/cpuinfo

grep -m1 '^flags' /proc/cpuinfo | grep -o -m1 'vmx|svm'
vmx

A non-empty vmx (Intel) or svm (AMD) response means the processor supports virtualization; empty output means the flags are missing (for example, inside another virtual machine without extension passthrough). If the flags are present but /dev/kvm is not, virtualization is usually disabled in the BIOS. Modules are loaded on demand:

modprobe kvm; modprobe kvm_intel

For AMD, replace kvm_intel with kvm_amd. Without KVM, QEMU remains functional on the built-in processor emulator (TCG), but is noticeably slower.

Installation

The basic set is QEMU and the libvirt daemon:

emerge -aq --getbinpkg qemu libvirt

The --getbinpkg option first tries the binary packages from the Calculate mirror. For 3D acceleration and shared folders via virtiofs, you need flags that are not enabled by default - add them before installing:

/etc/portage/package.use/custom

app-emulation/qemu opengl virgl fuse spice usbredir vhost-net
app-emulation/libvirt virtiofsd
app-emulation/spice -smartcard

The fuse flag for qemu is not enabled in either the Calculate profile or the binary package from the mirror - with it, the package is rebuilt from source. Check after installation:

equery b /usr/bin/qemu-img /usr/bin/qemu-nbd /usr/bin/qemu-storage-daemon /usr/sbin/libvirtd
app-emulation/libvirt-12.6.0
app-emulation/qemu-10.2.3-r3
app-emulation/qemu-10.2.3-r3
app-emulation/qemu-10.2.3-r3

The graphical manager and the domain installer are installed separately:

emerge -aq virt-manager

libvirtd daemon

The service is called libvirtd - start it and add it to autostart:

rc-service libvirtd start; rc-update add libvirtd default

rc-service libvirtd start
* Starting libvirtd ... [ ok ]

The virsh client checks the connection to the daemon and that QEMU is available to the hypervisor:

virsh --version
12.6.0
virsh uri
qemu:///system
virsh net-list --all
Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

To manage machines without the root password, add the user you log in as to the libvirt group:

gpasswd -a user libvirt

Log in to this account again: group membership is applied at login time. The libvirt package is built with polkit support, so group membership decides - without it a non-root user gets an authentication failure, with it the user gets the list of machines:

virsh -c qemu:///system list --all
Id   Name    State
-----------------------
 1    docvm   running

Kernel modules for networking

A virtual network and accelerated network processing require the tun and vhost_net modules:

modprobe -a tun vhost_net

To load them at boot, list them in a /etc/modules-load.d/qemu.conf file:

/etc/modules-load.d/qemu.conf

tun
vhost_net

Working with disk images

A new dynamic qcow2 disk is created with a single command; the size is specified with the M and G suffixes, and the file fills up as it is written:

qemu-img create -f qcow2 disk.qcow2 1G
Formatting 'disk.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16
qemu-img info disk.qcow2
image: disk.qcow2
file format: qcow2
virtual size: 1 GiB (1073741824 bytes)
disk size: 196 KiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
    extended l2: false

If the space for the disk is allocated in advance, the guest system will not have to allocate it while running, and it will be faster. This is how metadata preallocation works:

qemu-img create -f qcow2 -o preallocation=metadata prealloc.qcow2 1G
Formatting 'prealloc.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=metadata compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16

The difference is visible in the space used - for a regular image the metadata has not been created yet (196 KiB), for a preallocated one it is allocated (324 KiB):

qemu-img info prealloc.qcow2 | grep -E 'virtual size|disk size'
virtual size: 1 GiB (1073741824 bytes)
disk size: 324 KiB

Converting raw to compressed qcow2 and checking consistency:

qemu-img convert -f raw -O qcow2 -c seed.bin seed.qcow2

qemu-img check disk.qcow2
No errors were found on the image.
Image end offset: 262144

Disk contents without starting the machine

The image is available as a kernel block device via NBD - this is how you create partitions on it, format it, and mount it to a regular directory. Keep the guest machine powered off while doing this. Run everything as root on the host:

modprobe nbd max_part=8; qemu-nbd -c /dev/nbd0 -f qcow2 disk.qcow2
(no output; the device appears in /dev)
ls -la /dev/nbd0
brw-rw---- 1 root disk 43, 0 Nov 10 00:52 /dev/nbd0

Next, work with /dev/nbd0 as you would with a real disk - partitioning, filesystem, mounting:

parted -s /dev/nbd0 mklabel msdos mkpart primary ext4 1MiB 100%

mkfs.ext4 -q /dev/nbd0p1

mkdir -p /mnt/nbd; mount /dev/nbd0p1 /mnt/nbd

Checking that the data goes into the qcow2 image itself:

echo nbd-marker > /mnt/nbd/MARKER; cat /mnt/nbd/MARKER
nbd-marker

Once done, unmount and disconnect the image - without the second step the disk remains busy:

umount /mnt/nbd; qemu-nbd -d /dev/nbd0
/dev/nbd0 disconnected

The same method is available without the nbd module via the FUSE block export: the QEMU daemon exposes a block node as a file, which is then mounted like a regular image:

truncate -s 0 fs.raw.fuse
qemu-storage-daemon --blockdev node-name=n0,driver=raw,file.driver=file,file.filename=fs.raw --export fuse,id=e0,node-name=n0,mountpoint=fs.raw.fuse

Once the daemon is running, a representation of the image appears instead of the file:

ls -la fs.raw.fuse
-r-------- 1 root root 134217728 Nov 10 00:52 fs.raw.fuse

The daemon runs while the command is running; to run it in the background, add --daemonize. Mounting such a file as a filesystem on this build failed (the kernel reported can't read superblock), so for practical work with the disk contents, use qemu-nbd from the previous section.

Creating a virtual machine

The easiest way to install a machine is with the virt-install utility from the virt-manager package - it creates the disk, the network, and the libvirt configuration on its own:

virt-install --name docvm --memory 1024 --vcpus 2 --import \
--disk path=/var/lib/libvirt/images/alpine.qcow2,format=qcow2 \
--osinfo alpinelinux3.20 --graphics none --connect qemu:///system

The guest operating system variant is chosen from the osinfo database; osinfo-query os gives the list. If the media and the disk are already ready, --import is enough. Next, the machine is managed through virt-manager or with virsh commands:

virsh start docvm; virsh console docvm

virsh list --all

virt-manager also provides the list of machines with their state and a CPU usage graph:

Virtual Machine Manager window with the list of domains

alt

An emergency stop is comparable to powering off:

virsh destroy docvm

For normal stop and restart, ACPI must be running in the guest machine; in a Calculate guest, this is done as follows:

emerge -aq acpid; rc-update add acpid boot

Autostart of the domain together with the daemon:

virsh autostart docvm

The domain configuration is stored in XML; it is viewed and edited with the virsh dumpxml and virsh edit commands. Typical elements are memory, vCPU, disk, and interface:

fragment of the domain XML configuration
<domain type='kvm'>
  <name>docvm</name>
  <memory unit='MiB'>1024</memory>
  <vcpu>2</vcpu>
  <devices>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/var/lib/libvirt/images/alpine.qcow2'/>
      <target dev='vda' bus='virtio'/>
    </disk>
    <interface type='network'>
      <source network='default'/>
    </interface>
  </devices>
</domain>

The same parameters can also be edited in the graphical domain editor: the Overview tab shows the machine hardware and the hypervisor properties - qemu-system-x86_64, the Q35 chipset, the BIOS firmware.

Overview tab of the domain in virt-manager

alt

Guest network

By default, an isolated network with NAT access to the external network is used; the built-in DHCP issues addresses:

virsh net-dumpxml default | grep -E 'forward|bridge|range'
<forward mode='nat'>
</forward>
<bridge name='virbr0' stp='on' delay='0'/>
    <range start='192.168.122.2' end='192.168.122.254'/>

Other modes are also possible: routed (no NAT, with routing configured externally), an isolated network without egress, a bridge with addresses from the real network, and PCI passthrough of a network card to the guest. The description of all modes is in the libvirt documentation on the Network XML format.

Graphics acceleration, shared folders, and clipboard

3D acceleration consists of three parts: the opengl and virgl flags for qemu (see the installation), the SPICE server of the machine and the virtio driver in the guest. In virt-manager, these are the Video section (virtio model, 3D acceleration enabled) and the Display section (Type: Spice server, Listen type: None, OpenGL enabled). The same set expressed in XML:

fragment of the domain XML configuration
<graphics type="spice">
  <listen type="none"/>
  <image compression="off"/>
  <gl enable="yes"/>
</graphics>

Works with open-source Mesa/virglrenderer drivers (including on AMD and Intel video cards); with proprietary ones, check the behavior of your specific configuration. In a Calculate or Gentoo guest, the virtual GPU needs the Mesa flag:

/etc/portage/package.use/custom (в гостевой машине)

media-libs/mesa video_cards_virgl

The shared clipboard requires the SPICE agent in the guest system:

emerge -aq spice-vdagent; rc-update add spice-vdagent default

For Windows guests, the spice-guest-tools package from the SPICE website provides the same functionality.

Shared folders are built on virtiofs: the host exports a directory through the virtiofsd daemon, and the machine mounts it as a virtiofs filesystem. Do not confuse it with the qemu virtfs flag, which enables the Calculate profile - this is the old 9p transport, not virtiofs. On the libvirt side, the package must be built with the virtiofsd flag; otherwise the device is unavailable. Shared memory is required (memory-backend with shared access). In the domain configuration, it looks like this:

fragment of the domain XML configuration
<memoryBacking>
  <source type="memfd"/>
  <access mode="shared"/>
</memoryBacking>

The host directory is set by the <filesystem> tag with a mount tag that the guest specifies when mounting:

fragment of the domain XML configuration
<filesystem accessmode='mapped'>
  <driver name='virtiofs' queue='1024'/>
  <source dir='/home/user/shared'/>
  <target dir='myshare'/>
</filesystem>

In the guest, the directory is mounted by its mount tag: mount -t virtiofs myshare /mnt/share.

Project history

QEMU development has been ongoing since 2005, and libvirt since 2005; the QEMU and KVM developers decided to integrate KVM support into the main QEMU branch (mainline), and hardware virtualization support itself entered the Linux kernel starting with version 2.6.20. In Calculate, the binary package mirror updates the branch, so you should rely on the versions actually present in the Portage tree:

package version in the tree
app-emulation/qemu 10.2.3-r3
app-emulation/libvirt 12.6.0
app-emulation/virt-manager 5.1.0-r1
app-emulation/virtiofsd 1.13.2
app-emulation/guestfs-tools 1.55.6

Current upstream releases: QEMU 11.1.x, libvirt 12.9.0, guestfs-tools 1.57.5 - the tree lag is explained by the time it takes to deliver updates to Portage, not by the state of Calculate.