This document is a WORK IN PROGRESS.
This is just a quick personal cheat sheet: treat its contents with caution!
QEMU with KVM¶
QEMU is a generic and open source machine emulator and virtualizer. When used as a machine emulator, QEMU can run OSes and programs made for one machine (e.g. an ARM board) on a different machine (e.g. your x86 PC). By using dynamic translation, it achieves very good performance. QEMU can use other hypervisors like Xen or KVM to use CPU extensions (HVM) for virtualization. When used as a virtualizer, QEMU achieves near native performances by executing the guest code directly on the host CPU.
KVM, is a hypervisor built into the Linux kernel. It is similar to Xen in purpose but much simpler to get running. Unlike native QEMU, which uses emulation, KVM is a special operating mode of QEMU that uses CPU extensions (HVM) for virtualization via a kernel module.
Reference(s)
- https://wiki.qemu.org/Documentation
- https://wiki.qemu.org/Main_Page
- https://wiki.gentoo.org/wiki/QEMU
- https://wiki.archlinux.org/index.php/QEMU
- https://en.wikipedia.org/wiki/QEMU
- https://wiki.archlinux.org/index.php/KVM
- https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine
- https://www.unixmen.com/how-to-install-and-configure-qemu-in-ubuntu/
Table of contents¶
Install¶
BIOS
You might need to enable CPU virtualization in your BIOS settings.
Gentoo kernel
A correct kernel config is needed:
$ cd /usr/src/linux
# make nconfig # or `# make menuconfig`
# Enable KVM support
####################
# Double check here: <https://wiki.gentoo.org/wiki/QEMU#Kernel>
#
> [*] Virtualization ---> # Symbol: VIRTUALIZATION [=y]
> <*> Kernel-based Virtual Machine (KVM) support # Symbol: KVM [=y]
#
# Enable KVM support for Intel processors:
> <M> KVM for Intel processors support # Symbol: KVM_INTEL [=y]
#
# Enable KVM support for AMD processors:
> <M> KVM for AMD processors support # Symbol: KVM_AMD [=y]
#
# [Recommeded] vhost-net USE flag support:
> <*> Host kernel accelerator for virtio net # Symbol: VHOST_NET [=y]
#
# [Optional] advanced networking support:
> Device Drivers --->
> [*] Network device support ---> # Symbol: NETDEVICES [=y]
> [*] Network core driver support # Symbol: NET_CORE [=y]
> <*> Universal TUN/TAP device driver support # Symbol: TUN [=y]
#
# [Optional] Enabling 802.1d Ethernet Bridging support:
> [*] Networking support ---> # Symbol: NET [=y]
> Networking options --->
> <*> The IPv6 protocol # Symbol: IPV6 [=y]
> <*> 802.1d Ethernet Bridging # Symbol: BRIDGE [=y]
#
# [Optional] python USE flag for file capabilities support:
> Kernel hacking --->
> Compile-time checks and compiler options --->
> [*] Debug Filesystem # Symbol: DEBUG_FS [=y]
#
# [Optional] Ext4 kvm_stat support (if using ext4):
> File systems --->
> <*> The Extended 4 (ext4) filesystem # Symbol: EXT4_FS [=y]
> [*] Ext4 Security Labels # Symbol: EXT4_FS_SECURITY [=y]
After configuring the kernel don't forget to do a kernel make and rebuild!
Specify targets, for each target a qemu
executable will be built:
# vi /etc/portage/make.conf
> ...
> QEMU_SOFTMMU_TARGETS="x86_64"
> QEMU_USER_TARGETS="x86_64"
> ...
And install qemu:
Config¶
KVM¶
In order to run a KVM accelerated virtual machine without logging as root, add your user name to
the kvm
group:
Use¶
TODO:
- Resize
qcow
? - Try with
vdi
,vmdk
,vhd
andhdd
- USB forwarding
- Full screen
- Forward HTTP
natnetwork
? In order for multiple VMs to share the same network? With or without internet access.- Choose IP address
- Allow ping (ICMP protocol)
Networking¶
WIP
By default, QEMU do not support the ICMP protocol (e.g. used by ping
)! So do not assume that
you have no internet connection if you can't ping
anything!
To completely disable the networking use -nic none
.
Redirect an unused host port (e.g. 60022
) to the guest default SSH port (22
) by adding the
following option: -nic user,hostfwd=tcp::60022-:22
This way, you can SSH from host to guest with: $ ssh -p 60022 user_name@localhost
Image creation¶
WIP
qcow
image: an optimized file format for disk image files used by QEMU:
Start script¶
WIP
Use the -cpu host
option to make QEMU emulate the host's exact CPU rather than a more generic
CPU.
UEFI¶
By default QEMU don't use UEFI. But if wanted, it's possible to install and use UEFI firmware for 64-bit x86 virtual machines:
Now, those startup options should be added in order to use UEFI:
$ qemu-system-x86_64 \
-bios /usr/share/OVMF/OVMF_CODE.fd `# Path to UEFI firmware` \
-net none `# disable iPXE` \
...
Mac address¶
In order to specify a mac address (e.g. 00:00:00:11:11:11
):
Check it inside the host with:
$ cat /sys/class/net/eth0/address # e.g. for eth0
$ cat /sys/class/net/*/address # e.g. for all devices
Tip
- Get random mac addresses here: https://onlinerandomtools.com/generate-random-mac
- Create meaningful mac addresses here: https://onlinetexttools.com/convert-text-to-hexadecimal
WIP
By giving the -net nic
argument to QEMU, it will, by default, assign a virtual machine a network
interface with the link-level address 52:54:00:12:34:56
. However, when using bridged networking
with multiple virtual machines, it is essential that each virtual machine has a unique link-level
(MAC) address on the virtual machine side of the tap device. Otherwise, the bridge will not work
correctly, because it will receive packets from multiple sources that have the same link-level
address. This problem occurs even if the tap devices themselves have unique link-level addresses
because the source link-level address is not rewritten as packets pass through the tap device.
Make sure that each virtual machine has a unique link-level address, but it should always start
with 52:54:
. Use the following option, replace X with arbitrary hexadecimal digit:
Generating unique link-level addresses can be done in several ways:
1. Manually specify unique link-level address for each NIC. The benefit is that the DHCP server
will assign the same IP address each time the virtual machine is run, but it is unusable for
large number of virtual machines.
2. Generate random link-level address each time the virtual machine is run. Practically zero
probability of collisions, but the downside is that the DHCP server will assign a different
IP address each time. You can use the following command in a script to generate random
link-level address in a `macaddr` variable:
```console
$ printf -v macaddr "52:54:%02x:%02x:%02x:%02x" $(( $RANDOM & 0xff)) $(( $RANDOM & 0xff )) $(( $RANDOM & 0xff)) $(( $RANDOM & 0xff ))
$ qemu-system-x86_64 -net nic,macaddr="$macaddr" -net vde disk_image
```
3. Use the following script `qemu-mac-hasher.py` to generate the link-level address from the
virtual machine name using a hashing function. Given that the names of virtual machines are
unique, this method combines the benefits of the aforementioned methods: it generates the
same link-level address each time the script is run, yet it preserves the practically zero
probability of collisions.
```console
qemu-mac-hasher.py
#!/usr/bin/env python
# usage: qemu-mac-hasher.py <VMName>
import sys
import zlib
crc = str(hex(zlib.crc32(sys.argv[1].encode("utf-8")))).replace("x", "")[-8:]
print("52:54:%s%s:%s%s:%s%s:%s%s" % tuple(crc))
```
In a script, you can use for example:
```console
vm_name="VM Name"
qemu-system-x86_64 -name "$vm_name" -net nic,macaddr=$(qemu-mac-hasher.py "$vm_name") -net vde disk_image
```
virtio
¶
WIP
QEMU offers guests the ability to use paravirtualized block and network devices using the virtio
drivers, which provide better performance and lower overhead.
A virtio
block device requires the option -drive
for passing a disk image, with parameter
if=virtio
:
Almost the same goes for the network:
Note: This will only work if the guest machine has drivers for virtio
devices. Linux does, most
distributions will include the required drivers, but there is no guarantee that virtio
devices
will work with other operating systems.
Example with Artix (on Gentoo host with UEFI)¶
-
Download e.g. the 20200413 Artix, based on Runit, ISO image:
-
Create, e.g. a 20 GB
qcow
image calledartix_base_runit.img
for Artix: -
Since QEMU requires a lot of options, it's nice to put them into a shell script, e.g.:
$ vi start_artix_base_runit.sh > #!/bin/sh > > exec qemu-system-x86_64 \ > -name "artix_base_runit" `# Sets the name of the guest` \ > -enable-kvm `# enable KVM full virtualization support` \ > -cpu host `# [recommended] emulate the host processor` \ > -drive file=artix_base_runit.img,if=virtio `# Set virtio hdd with specified img` \ > -netdev user,id=vmnic,hostname=artix_base_runit `# [recommended] pass-through` \ > -device virtio-net,netdev=vmnic `# [recommended] viritio support` \ > -m 4G `# amount of memory (default: 128 MB) ram the guest is permitted to use` \ > -smp 2 `# number of cores the guest is permitted to use` \ > -monitor stdio `# Redirect the monitor to host device in non graphical mode` \ > -bios /usr/share/edk2-ovmf/OVMF_CODE.fd `# Path to UEFI firmware` \ > -net none `# disable iPXE, required for UEFI` \ > "$@" $ chmod +x start_artix_base-runit.sh
-
Boot the disk image:
-
After the disk image installation, subsequent boot can simply be run like this:
Example with NixOS (on Gentoo host with UEFI) without KVM¶
-
Download e.g. the 21.11 NixOS minimal ISO image:
-
Create e.g. a 20 GB (
qcow
image callednixos_vm.img
for NixOS: -
Since QEMU requires a lot of options, it's nice to put them into a shell script, e.g.:
$ vi start_nixos_vm.sh > #!/bin/sh > > exec qemu-system-x86_64 \ > -name nixos_vm \ > -drive file=nixos_vm.img,if=virtio \ > -m 4G \ > -smp 2 \ > -nic user,hostname=nixos_vm,hostfwd=tcp::60022-:22,model=virtio-net-pci \ > -bios /usr/share/edk2-ovmf/OVMF_CODE.fd `# Path to UEFI firmware` \ > -net none `# disable iPXE, required for UEFI` \ > "$@" $ chmod +x start_nixos_vm.sh
-
Boot the disk image:
-
After the disk image installation, subsequent boot can simply be run like this:
Troubleshooting¶
Cannot release cursor focus from QEMU/Cannot get cursor back¶
Press Ctrl+Alt+G
See https://unix.stackexchange.com/questions/107633/how-do-i-get-my-mouse-back-from-qemu-kvm.
Could not access KVM kernel module
error¶
If you get the bellow error message:
Could not access KVM kernel module: No such file or directory
qemu-system-x86_64: failed to initialize kvm: No such file or directory
Then you might want to following the bellow troubleshooting steps:
-
If using Gentoo, make sure you followed the associated installation instructions (for the Gentoo kernel and
/etc/portage/make.conf
configuration). -
Make sure you followed the configuration instructions.
-
Make sure your CPU has virtualization support:
Should return eitherAMD-V
(for AMD CPUs) orVT-x
(for Intel CPUs).If there is no virtualization support for your processor, then KVM will not work at all on that machine.
-
On most distributions, KVM will be included as a module in the kernel (i.e. not built-in)
Note that if you modified your Linux kernel yourself (e.g. as usual on Gentoo), then you might have a built-in KVM. In this case, ignore this step.
-
By default, the virtualization support may not be enabled by all CPU vendors. In such cases, the
modprobe kvm
command will work butmodprobe kvm_amd
(ofmodprobe kvm_intel
) will give error.If you check the
dmesg
output after running thosemodprobe
commands, you might seekvm: disabled by bios
andkvm: no hardware support
. In this case you will have to enable virtualization in your BIOS. E.g. in the "Advanced" settings tab -> "CPU configuration" (or "Chipset Control") -> enable "Secure Virtual Machine Mode" (or "Intel Virtualization Technology", or "Intel VT-x", or "Virtualization Extensions").
After running the QEMU start shell script, you might see the following message:
This is because QEMU is using the VNC protocol for graphics output. It might use VNC because the GTK/SDL libraries needed by QEMU are not present (see https://stackoverflow.com/a/65233851)In this case, you can either install the QEMU dependencies for GTK/SDL and restart the QEMU
shell script, or you can install VNC (in this case, just execute
vncviewer 127.0.0.1:5900
in order to get the graphics output of your QEMU virtual machine).
If this cheat sheet has been useful to you, then please consider leaving a star here.