Skip to content

Instantly share code, notes, and snippets.

@tatumroaquin
Last active September 19, 2024 17:32
Show Gist options
  • Save tatumroaquin/c6464e1ccaef40fd098a4f31db61ab22 to your computer and use it in GitHub Desktop.
Save tatumroaquin/c6464e1ccaef40fd098a4f31db61ab22 to your computer and use it in GitHub Desktop.
QEMU-KVM Installation for Arch Linux

QEMU-KVM in Arch Linux

Check Virtualization Support

Check CPU has VM capabilities

lscpu | grep -i Virtualization
  • VT-x for Intel
  • AMD-Vi for AMD

Ensure that your kernel includes KVM modules

zgrep CONFIG_KVM /proc/config.gz
  • y = Yes (always installed)
  • m = Loadable module

Install QEMU, libvirt, viewers, and tools

sudo pacman -S qemu-full qemu-img libvirt virt-install virt-manager virt-viewer \
edk2-ovmf swtpm guestfs-tools libosinfo

yay -S tuned
  • qemu-full - user-space KVM emulator, manages communication between hosts and VMs
  • qemu-img - provides create, convert, modify, and snapshot, offline disk images
  • libvirt - an open-source API, daemon, and tool for managing platform virtualization
  • virt-install - CLI tool to create guest VMs
  • virt-manager - GUI tool to create and manage guest VMs
  • virt-viewer - GUI console to connect to running VMs
  • edk2-ovmf - enables UEFI support for VMs
  • swtpm - TPM (Trusted Platform Module) emulator for VMs
  • guestfs-tools - provides a set of extended CLI tools for managing VMs
  • libosinfo - a library for managing OS information for virtualization.
  • tuned - system tuning service for linux allows us to optimise the hypervisor for speed.

VirtIO Drivers for Windows Guests

Go to the Fedora People repository and download virtio-win.iso.

Save it anywhere on disk, and attach it to a CD-ROM it when creating Windows VM.

The default location on Debian/RedHat based is `/usr/share/virtio-win/

Enable the libvirt daemon

  • Here is the documentation detailing the difference between monolithic and modular daemons.
  • Choose between option 1 and 2 and then do a reboot.

Option 1: Enable the modular daemon.

for drv in qemu interface network nodedev nwfilter secret storage; do
    sudo systemctl enable virt${drv}d.service;
    sudo systemctl enable virt${drv}d{,-ro,-admin}.socket;
done
  • loop through virtualization systemd services necessary for the libvirt modular daemon.

Option 2: Enable the monolithic daemon.

sudo systemctl enable libvirtd.service

Verify Host Virtualization

sudo virt-host-validate qemu

If you receive warnings, proceed to their respective sections. Re-run the above command to check your changes.

Intel CPU IOMMU Support

WARN (IOMMU appears to be disabled in the kernel. Add intel_iommu=on to kernel cmdline arguments)

Enable IOMMU using GRUB

  1. Open your GRUB config
sudo vim /etc/default/grub
  1. Add the following kernel module entries
# /etc/default/grub
GRUB_CMDLINE_LINUX="... intel_iommu=on iommu=pt"
  1. Regenerate your grub.cfg file
sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo reboot

AMD SEV Support

For AMU CPUs with SEV feature, you might receive this warning:

WARN (AMD Secure Encrypted Virtualization appears to be disabled in kernel. Add kvm_amd.sev=1 to the kernel cmdline arguments)

If you are in Intel you may ignore the warning below, as this only affects AMD CPUs.

WARN (Unknown if this platform has Secure Guest support).

You may refer to this bug report:

Or this libvirt documentation:

Option 1: Enable AMD SEV using modprobe

echo "options kvm_amd sev=1" >> /etc/modprobe.d/amd-sev.conf
sudo reboot

Option 2: Enable AMD SEV using GRUB

  1. Open your GRUB config and add kernel modules
sudo vim /etc/default/grub
# /etc/default/grub
GRUB_CMDLINE_LINUX="... mem_encrypt=on kvm_amd.sev=1"
  1. Regenerate your grub.cfg file
sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo reboot

Optimise Host with TuneD

  1. Enable TuneD daemon
sudo systemctl enable --now tuned.service
  1. Check active TuneD profile
tuned-adm active

Current active profile: balanced

  • balanced - generic profile not specialised for KVM, we will change this.
  1. List all TuneD profiles
tuned-adm list
  1. Set profile to virtual-host
sudo tuned-adm profile virtual-host
  1. Verify that TuneD profile
tuned-adm active

Current active profile: virtual-host

sudo tuned-adm verify

Verification succeeded, current system settings match the preset profile. See TuneD log file ('/var/log/tuned/tuned/log') for details.

KVM Networking (optional)

  • By default all virtual machines will connect to the built-in default NAT network.
  • To make VMs accessible via the LAN you must create a network bridge.
  • Keep in mind that network bridges won't work with hosts running on Wireless NICs.
  • All configuration steps below is done using NetworkManager. If you use a different program to manage networking use that instead.

Default NAT network XML dump:

<network>
    <uuid>...</uuid>
    <forward mode='nat'>
        <nat>
            <port start='1024' end='65535'/>
        </nat>
    </forward>
    <bridge name='virbr0' stp='on' delay='0'/>
    <mac address='AB:CD:EF:AB:CD:EF'/>
    <ip address='10.1.1.1' netmask='255.255.255.0'>
        <dhcp>
            <range start="10.1.1.2" end="10.1.1.254"/>
        </dhcp>
    </ip>
</network>

Sample Netfilter (nftables) rules for default NAT

The rules below is my personal config for my laptop machine. Which works nicely with the autogenerated libvirt network rules.

#!/usr/bin/nft -f

flush ruleset;

define qemu_iface = "virbr0";

table inet filter {
	chain input {
		type filter hook input priority filter; policy drop;

		ct state established,related accept;

		iifname "lo" accept comment "allow loopback";
		iifname $qemu_iface accept comment "allow qemu";

		tcp dport http accept comment "allow sending http";
		tcp dport https accept comment "allow sending https";
		udp dport 67 udp sport 68 accept comment "allow sending dhcp";
		tcp dport ssh accept comment "allow ssh";

		counter drop;
	}

	chain forward {
		type filter hook forward priority filter; policy drop;

		ct state established,related accept;

		iifname $qemu_iface accept comment "forward qemu input";
		oifname $qemu_iface accept comment "forward qemu output";

		counter drop;
	}
}

table ip nat {
	chain postrouting {
		type nat hook postrouting priority srcnat; policy accept;
		ip saddr 10.1.1.0/24 masquerade;
	}
}

Configure bridge interface

  1. find the interface name of your ethernet connection.
sudo nmcli device status
DEVICE TYPE STATE CONNECTION
enp2s0 ethernet connected Wired connection 1
lo loopback connected (externally) lo
virbr0 bridge connected (externally) virbr0
  1. create a bridge interface using nmcli
sudo nmcli connection add type bridge con-name bridge0 ifname bridge0
  1. connect the ethernet interface to the bridge
sudo nmcli connection add type ethernet slave-type bridge con-name 'Bridge connection 1' \
ifname enp2s0 master bridge0
  1. active the newly created connection
sudo nmcli connection up bridge 0
  1. enable connection.autoconnect-slaves parameter.
sudo nmcli connection modify bridge0 connection.autoconnect-slaves 1
  1. reactivate the bridge and verify connection.
sudo nmcli connection up bridge0
sudo nmcli device status
DEVICE TYPE STATE CONNECTION
bridge0 bridge connected bridge0
lo loopback connected (externally) lo
virbr0 bridge connected (externally) virbr0
enp2s0 ethernet connected Bridge connection 1

Configure bridge network

  1. create an XML file called nwbridge.xml.
vim nwbridge.xml
  1. post the following XML
<network>
    <name>nwbridge</name>
    <forward mode="bridge" />
    <bridge name="bridge0" />
</network>
  1. define the bridge network
sudo virsh net-define nwbridge.xml

Network nwbridge defined from nwbridge.xml

  1. start the bridge network
sudo virsh net-start nwbridge
  1. auto-start bridge network on boot
sudo virsh net-autostart nwbridge
  1. delete nwbridge.xml file
rm nwbridge.xml
  1. verify that nwbridge network exists.
sudo virsh net-list --all
Name State Autostart Persistent
default active yes yes
nwbridge active yes yes

Removing bridge network and interface

If you want to revert the changes to your network, do the following:

sudo virsh net-destroy nwbridge
sudo virsh net-undefine nwbridge
sudo nmcli connection up 'Wired connection 1'
sudo nmcli connection del bridge0
sudo nmcli connection del 'Bridge connection 1'

Libvirt connection modes

libvirt as two methods for connecting to the KVM Hypervisor.

Session Mode

In session mode, a regular user is connected to a per-user instance. Allowing each user to manage their own pool of virtual machines. This is also the default mode.

The advantage of this mode is, permissions are not an issue. As no root access is required.

The disadvantage is this mode uses QEMU User Networking (SLIRP). This is a user-space IP stack, which yields overhead resulting in poor networking performance.

And if you want to implement an option that requires root privileges. You will be unable to do so.

System Mode

In the system mode you are granted access to all system resources.

Granting system-wide access to regular user.

  1. check current mode
sudo virsh uri

qemu:///session

  1. add the current user to the libvirt group
sudo usermod -aG libvirt $USER
  1. set env variable with the default uri and check
echo 'export LIBVIRT_DEFAULT_URI="qemu:///system"' >> ~/.bashrc
sudo virsh uri

Set ACL for the KVM images directory

  1. check permissions on the images directory
sudo getfacl /var/lib/libvirt/images
getfacl: Removing leading '/' from absolute path names
# file : var/lib/libvirt/images/
# owner: root
# group: root
user::rwx
group::--x
other::--x
  1. recursively remove existing ACL permissions
sudo setfacl -R -b /var/lib/libvirt/images/
  1. recursively grant permission to the current user
sudo setfacl -R -m u:${USER}:rwX /var/lib/libvirt/images/
  • uppercase X states that execution permission only applied to child folders and not child files.
  1. enable special permissions default ACL
sudo setfacl -m d:u:${USER}:rwx /var/lib/libvirt/images/
  • if this step is omitted, new dirs or files created within the images directory will not have this ACL set.
  1. verify your ACL permissions within the images directory.
sudo getfacl /var/lib/libvirt/images/
getfacl: Removing leading '/' from absolute path names
# file : var/lib/libvirt/images/
# owner: root
# group: root
user::rwx
user:tatum:rwx
group::--x
mask::rwx
other::--x
default:user::rwx
default:user:tatum:rwx
default:group::--x
default:mask::rwx
default:other::--x
@tuananh
Copy link

tuananh commented Apr 13, 2024

@tatumroaquin I'm getting error error: target not found: qemu-arch-extra. Looks like that package doesn't exists?

@tatumroaquin
Copy link
Author

@tuananh I think the package did exists at the time of writing this gist, I guess either they've renamed the package to something else or they've demoted it to the AUR.

But the qemu-arch-extra-git package is still available in the AUR, you can check it with yay -Ss qemu-arch-extra, you may want to use that instead.

@tuananh
Copy link

tuananh commented Apr 13, 2024

@tatumroaquin thanks. lemme try that

@tatumroaquin
Copy link
Author

@tuananh Do keep in mind that the network config recipe here has only been tested on direct cable Ethernet connection. I did not manage to make it work via hosts running on wireless card (Wi-Fi), such as laptop machines.

This gist is quite old, I've not updated it in two years, so if it works for you that's great, if not don't waste too much time on it.

@KSHMR1337
Copy link

Nice and quick guide, kudos!

@NullifyDev
Copy link

I have gotten this error from building qemu-arch-extra-git:

FAILED: libqemu-hexagon-linux-user.fa.p/target_hexagon_op_helper.c.o 
cc -m64 -mcx16 -Ilibqemu-hexagon-linux-user.fa.p -I. -I.. -Itarget/hexagon -I../target/hexagon -I../common-user/host/x86_64 -I../linux-user/include/host/x86_64 -I../linux-user/include -Ilinux-user -I../linux-user -I../linux-user/hexagon -Iqapi -Itrace -Iui -Iui/shader -I/usr/include/capstone -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/sysprof-6 -fdiagnostics-color=auto -Wall -Winvalid-pch -std=gnu11 -O2 -g -fstack-protector-strong -Wempty-body -Wendif-labels -Wexpansion-to-defined -Wformat-security -Wformat-y2k -Wignored-qualifiers -Wimplicit-fallthrough=2 -Winit-self -Wmissing-format-attribute -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls -Wshadow=local -Wstrict-prototypes -Wtype-limits -Wundef -Wvla -Wwrite-strings -Wno-missing-include-dirs -Wno-psabi -Wno-shift-negative-value -isystem /home/saturn/.cache/paru/clone/qemu-git/src/qemu/linux-headers -isystem linux-headers -iquote . -iquote /home/saturn/.cache/paru/clone/qemu-git/src/qemu -iquote /home/saturn/.cache/paru/clone/qemu-git/src/qemu/include -iquote /home/saturn/.cache/paru/clone/qemu-git/src/qemu/host/include/x86_64 -iquote /home/saturn/.cache/paru/clone/qemu-git/src/qemu/host/include/generic -iquote /home/saturn/.cache/paru/clone/qemu-git/src/qemu/tcg/i386 -Wno-unused-function -pthread -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -ftrivial-auto-var-init=zero -fzero-call-used-regs=used-gpr -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=3 -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -fPIE -isystem../linux-headers -isystemlinux-headers -DCOMPILING_PER_TARGET '-DCONFIG_TARGET="hexagon-linux-user-config-target.h"' '-DCONFIG_DEVICES="hexagon-linux-user-config-devices.h"' -MD -MQ libqemu-hexagon-linux-user.fa.p/target_hexagon_op_helper.c.o -MF libqemu-hexagon-linux-user.fa.p/target_hexagon_op_helper.c.o.d -o libqemu-hexagon-linux-user.fa.p/target_hexagon_op_helper.c.o -c ../target/hexagon/op_helper.c
during RTL pass: ira
In file included from ../target/hexagon/op_helper.c:1496:
target/hexagon/helper_funcs_generated.c.inc: In function ‘helper_V6_vgathermw’:
target/hexagon/helper_funcs_generated.c.inc:2347:1: internal compiler error: Segmentation fault
 2347 | }
      | ^
0x1905658 internal_error(char const*, ...)
	???:0
0xa9fb38 ira_soft_conflict(ira_allocno*, ira_allocno*)
	???:0
0xa74469 ira_traverse_loop_tree(bool, ira_loop_tree_node*, void (*)(ira_loop_tree_node*), void (*)(ira_loop_tree_node*))
	???:0
0xab06d4 ira_color()
	???:0
Please submit a full bug report, with preprocessed source (by using -freport-bug).
Please include the complete backtrace with any bug report.
See <https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues> for instructions.
[3611/9734] Compiling C object libqemu-hexagon-linux-user.fa.p/target_hexagon_genptr.c.o
ninja: build stopped: subcommand failed.
==> ERROR: A failure occurred in build().
    Aborting...
error: failed to build 'qemu-git-22:9.0.0.r92.g88daa112d4-1 (qemu-git qemu-arch-extra-git)': 
error: packages failed to build: qemu-git-22:9.0.0.r92.g88daa112d4-1 (qemu-git qemu-arch-extra-git)

Does anyone know about this error? Im on Endeavour OS v6.8.7-zen1-2-zen

@KSHMR1337
Copy link

I have gotten this error from building qemu-arch-extra-git:

FAILED: libqemu-hexagon-linux-user.fa.p/target_hexagon_op_helper.c.o 
cc -m64 -mcx16 -Ilibqemu-hexagon-linux-user.fa.p -I. -I.. -Itarget/hexagon -I../target/hexagon -I../common-user/host/x86_64 -I../linux-user/include/host/x86_64 -I../linux-user/include -Ilinux-user -I../linux-user -I../linux-user/hexagon -Iqapi -Itrace -Iui -Iui/shader -I/usr/include/capstone -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/sysprof-6 -fdiagnostics-color=auto -Wall -Winvalid-pch -std=gnu11 -O2 -g -fstack-protector-strong -Wempty-body -Wendif-labels -Wexpansion-to-defined -Wformat-security -Wformat-y2k -Wignored-qualifiers -Wimplicit-fallthrough=2 -Winit-self -Wmissing-format-attribute -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls -Wshadow=local -Wstrict-prototypes -Wtype-limits -Wundef -Wvla -Wwrite-strings -Wno-missing-include-dirs -Wno-psabi -Wno-shift-negative-value -isystem /home/saturn/.cache/paru/clone/qemu-git/src/qemu/linux-headers -isystem linux-headers -iquote . -iquote /home/saturn/.cache/paru/clone/qemu-git/src/qemu -iquote /home/saturn/.cache/paru/clone/qemu-git/src/qemu/include -iquote /home/saturn/.cache/paru/clone/qemu-git/src/qemu/host/include/x86_64 -iquote /home/saturn/.cache/paru/clone/qemu-git/src/qemu/host/include/generic -iquote /home/saturn/.cache/paru/clone/qemu-git/src/qemu/tcg/i386 -Wno-unused-function -pthread -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -ftrivial-auto-var-init=zero -fzero-call-used-regs=used-gpr -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=3 -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -fPIE -isystem../linux-headers -isystemlinux-headers -DCOMPILING_PER_TARGET '-DCONFIG_TARGET="hexagon-linux-user-config-target.h"' '-DCONFIG_DEVICES="hexagon-linux-user-config-devices.h"' -MD -MQ libqemu-hexagon-linux-user.fa.p/target_hexagon_op_helper.c.o -MF libqemu-hexagon-linux-user.fa.p/target_hexagon_op_helper.c.o.d -o libqemu-hexagon-linux-user.fa.p/target_hexagon_op_helper.c.o -c ../target/hexagon/op_helper.c
during RTL pass: ira
In file included from ../target/hexagon/op_helper.c:1496:
target/hexagon/helper_funcs_generated.c.inc: In function ‘helper_V6_vgathermw’:
target/hexagon/helper_funcs_generated.c.inc:2347:1: internal compiler error: Segmentation fault
 2347 | }
      | ^
0x1905658 internal_error(char const*, ...)
	???:0
0xa9fb38 ira_soft_conflict(ira_allocno*, ira_allocno*)
	???:0
0xa74469 ira_traverse_loop_tree(bool, ira_loop_tree_node*, void (*)(ira_loop_tree_node*), void (*)(ira_loop_tree_node*))
	???:0
0xab06d4 ira_color()
	???:0
Please submit a full bug report, with preprocessed source (by using -freport-bug).
Please include the complete backtrace with any bug report.
See <https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues> for instructions.
[3611/9734] Compiling C object libqemu-hexagon-linux-user.fa.p/target_hexagon_genptr.c.o
ninja: build stopped: subcommand failed.
==> ERROR: A failure occurred in build().
    Aborting...
error: failed to build 'qemu-git-22:9.0.0.r92.g88daa112d4-1 (qemu-git qemu-arch-extra-git)': 
error: packages failed to build: qemu-git-22:9.0.0.r92.g88daa112d4-1 (qemu-git qemu-arch-extra-git)

Does anyone know about this error? Im on Endeavour OS v6.8.7-zen1-2-zen

The package no longer exists. Just continue without it.

@Gadrawingz
Copy link

This installation guide is helpful, but How about full configuration?

@Yewsernaem
Copy link

I followed the guide, but I'm not listed as one of the default users not sure what to do

@tatumroaquin
Copy link
Author

tatumroaquin commented Aug 12, 2024

I followed the guide, but I'm not listed as one of the default users not sure what to do

@Yewsernaem What do you mean not listed as "default user", which part of the guide do you have difficulty with?

@Yewsernaem
Copy link

I followed the guide, but I'm not listed as one of the default users not sure what to do

@Yewsernaem What do you mean not listed as "default user", which part of the guide do you have difficulty with?

at 4. enable special permissions default ACL
I've run through the whole thing, however when I run the final check, default : user : ${user} : rxw does not appear. I'm assuming that sudo setfacl -m d:u:${USER}:rwx /var/lib/libvirt/images/
isn't working, however I don't get any complaints when I run the command.

@tatumroaquin
Copy link
Author

@Yewsernaem Ok I'm assuming you mean rwx and not rxw. Try doing the same commands and replace ${USER} with $USER without the curly brace.

@Yewsernaem
Copy link

@Yewsernaem Ok I'm assuming you mean rwx and not rxw. Try doing the same commands and replace ${USER} with $USER without the curly brace.

I have been, but ran it through a third time just to be sure and still not there. sorry for the typos, I've not run vm's before so I've been reading several resources for hours and it feels like my eyes are about to bleed.

@tatumroaquin
Copy link
Author

@Yewsernaem Well I'm out of ideas, try double quoting " the permission string like this. Also try rebooting your machine.

sudo setfacl -R -m "u:${USER}:rwX" /var/lib/libvirt/images/
sudo setfacl -m "d:u:${USER}:rwx" /var/lib/libvirt/images/
sudo setfacl -R -m "u:$USER:rwX" /var/lib/libvirt/images/
sudo setfacl -m "d:u:$USER:rwx" /var/lib/libvirt/images/

@Yewsernaem
Copy link

@Yewsernaem Well I'm out of ideas, try double quoting " the permission string like this. Also try rebooting your machine.

sudo setfacl -R -m "u:${USER}:rwX" /var/lib/libvirt/images/
sudo setfacl -m "d:u:${USER}:rwx" /var/lib/libvirt/images/
sudo setfacl -R -m "u:$USER:rwX" /var/lib/libvirt/images/
sudo setfacl -m "d:u:$USER:rwx" /var/lib/libvirt/images/

I'll run it back tomorrow, tough I'd bet you money a reboot would do it. Turning it off and on again, the great mystery of computers. XD

@Yewsernaem
Copy link

@Yewsernaem Well I'm out of ideas, try double quoting " the permission string like this. Also try rebooting your machine.

sudo setfacl -R -m "u:${USER}:rwX" /var/lib/libvirt/images/
sudo setfacl -m "d:u:${USER}:rwx" /var/lib/libvirt/images/
sudo setfacl -R -m "u:$USER:rwX" /var/lib/libvirt/images/
sudo setfacl -m "d:u:$USER:rwx" /var/lib/libvirt/images/

so it seems that using ${USER} was the issue. using just {USER} sans the $ was how i resolved the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment