Set up qemu-kvm for CentOS 7

Synopsis

On a kvm-capable x86_64 host running CentOS Linux 7.9 with a single wired network adapter and a static ipv4 address:

Set up network bridge [1] [2] [3] [4]

Install bridge utilities (and dependencies) on the host:

> sudo dnf install bridge-utils

Identify the host's active network adapter (e.g. enp1s0) and settings:

> nmcli device show
...
GENERAL.DEVICE:   enp1s0
GENERAL.TYPE:     ethernet
GENERAL.HWADDR:   1A:2B:3C:4D:5E:6F
...
IP4.ADDRESS[1]:   192.168.1.99/24
IP4.GATEWAY:      192.168.1.1
...
IP4.DNS[1]:       192.168.1.1
IP4.DNS[2]:       8.8.8.8
IP4.DNS[3]:       9.9.9.9
...

Create a network config script for the bridge:

> sudo /bin/cat <<'_EOF_' > /etc/sysconfig/network-scripts/ifcfg-br0
> DEVICE="br0"
> BOOTPROTO="static"
> GATEWAY="192.168.1.1"
> IPADDR="192.168.1.99"
> PREFIX="24"
> ONBOOT="yes"
> TYPE="Bridge"
> NM_CONTROLLED="no"
> _EOF_

Verify packet filtering is disabled for bridges on the host:

> cat /usr/lib/sysctl.d/00-system.conf
...
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0
...

Disable and save the active network adapter's existing config script:

> sudo /bin/mv /etc/sysconfig/network-scripts/ifcfg-enp1s0 \
> /etc/sysconfg/network-scripts/ifcfg-enp1so.disabled

Create a new config script (e.g. as eth0) for the active adapter:

> sudo /bin/cat <<'_EOF_' > /etc/sysconfig/network-scripts/ifcfg-eth0
> DEVICE="eth0"
> BOOTPROTO="none"
> BRIDGE="br0"
> HWADDR="1A:2B:3C:4D:5E:6F"
> ONBOOT="yes"
> TYPE="Ethernet"
> NM_CONTROLLED="no"
> _EOF_

Add the following lines if not already present in /etc/sysconfig/network-scripts/ifcfg-lo:

ONBOOT="yes"
NM_CONTROLLED="no"

Ensure /etc/resolv.conf exists and contains valid nameserver entries:

> cat /etc/resolv.conf
...
nameserver 192.168.1.1
nameserver 8.8.8.8
nameserver 9.9.9.9
...

Edit /etc/default/grub and add the params net.ifnames=0 and biosdevname=0 to the existing params of the GRUB_CMDLINE_LINUX entry:

> sudoedit /etc/default/grub
...
GRUB_CMDLINE_LINUX="crashkernel=auto net.ifnames=0 biosdevname=0 ... "
...

Regenerate the grub config file:

> sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Stop and disable NetworkManager

> sudo systemctl stop NetworkManager.service
> sudo systemctl disable NetworkManager.service

Enable the network service:

> sudo systemctl enable network.service

Reboot the host.

Verify the bridge is enabled:

> brctl show
bridge name    bridge id            STP enabled    interfaces
br0            8000.1c1b0d36ca12    no             eth0

Enable spanning tree protocol (STP) on the bridge if it will not be the only bridge on the host:

> sudo brctl br0 stp on
> brctl show
bridge name    bridge id            STP enabled    interfaces
br0            8000.1c1b0d36ca12    yes            eth0

If network comes up OK on reboot it's safe to delete /etc/sysconfg/network-scripts/ifcfg-enp1so.disabled

Install qemu-kvm-ev [5] [6] [7] [8] [9]

Verify host is x86_64 arch with AMD (smx) or Intel (vmx) cpu flags:

> grep -Eq '(svm|vmx)' /proc/cpuinfo || echo 'No kvm on this host'

Install base package (and dependencies) on the host:

> sudo dnf install qemu-kvm

Upgrade to qemu-kvm-ev (latest available version is 2.12) and dependencies:

sudo dnf install centos-release-qemu-ev
sudo dnf install centos-release-ceph-nautilus
sudo dnf install qemu-kvm-ev

We need Open Virtual Machine Firmware for UEFI boot:

> sudo dnf install OVMF.noarch

View and verify the package contents:

> rpm -ql OVMF.noarch
/usr/share/OVMF
/usr/share/OVMF/OVMF_CODE.secboot.fd
/usr/share/OVMF/OVMF_VARS.fd
/usr/share/OVMF/OVMF_VARS.secboot.fd
/usr/share/OVMF/UefiShell.iso
/usr/share/doc/OVMF/Licenses
/usr/share/doc/OVMF/Licenses/OpensslLib-License.txt
/usr/share/doc/OVMF/Licenses/OvmfPkg-License.txt
/usr/share/doc/OVMF/Licenses/edk2-License.txt
/usr/share/doc/OVMF/README
/usr/share/doc/OVMF/ovmf-whitepaper-c770f8c.txt
/usr/share/qemu
/usr/share/qemu/firmware
/usr/share/qemu/firmware/50-ovmf-sb.json
/usr/share/qemu/firmware/60-ovmf.json

Qemu guest network setup

Must specify guest network setup with the -nic and -netdev params.

Get available NIC adapter types with /usr/libexec/qemu-kvm -nic model=?

Guest must have driver support for the selected type. For best throughput enable virtio support with -net nic,model=virtio

Get available network setup types with /usr/libexec/qemu-kvm -netdev type=?

User (default)

Guest is in a qemu-managed private LAN.
-netdev user,id=id[,option][,option][,...]

Tap

host bridge --> tap device --> guest NIC
-netdev tap,id=id[,fd=h][,ifname=name][,script=file][,downscript=dfile] [,helper=helper]

Bridge

-netdev bridge,id=id[,br=bridge][,helper=helper]

Socket

-netdev socket,id=id[,fd=h][,listen=[host]:port][,connect=host:port]

VDE

-netdev vde,id=id[,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]

Hubport

-netdev hubport,id=id,hubid=hubid

Test the installation [10] [11] [12] [13] [14]

Ensure kvm kernel module is loaded:

> sudo lsmod | grep kvm

Add your USER account to the kvm and qemu groups:

> sudo usermod -aG kvm,qemu $USER

You will have to log out and back in for the group adds to take effect, or use the newgrp command.

The firmware will run with secure boot enabled (SECURE_VARS) or disabled (EFI_VARS):

OVMF='/usr/share/OVMF'
EFI_CODE='OVMF_CODE.secboot.fd'
EFI_VARS='OVMF_VARS.fd'
SECURE_VARS='OVMF_VARS.secboot.fd'

Qemu handles PC system flash storage (persistent flash storage) as a parallel flash image (i.e. as a block device with a pflash interface) so we must create block devices for the EFI_CODE and EFI_VARS files; changes to firmware settings will not be saved as the EFI_VARS file is writable only by root; in production we would make a user-writable copy of EFI_VARS; here we test with secure boot disabled; EFI_CODE must be declared before EFI_VARS; boot target is the UEFI shell iso image:

> /usr/libexec/qemu-kvm \
> -blockdev node-name=CODE,driver=file,filename=${OVMF}/${EFI_CODE},read-only=on \
> -blockdev node-name=VARS,driver=file,filename=${OVMF}/${EFI_VARS},read-only=on \
> -machine type=q35,pflash0=CODE,pflash1=VARS \
> -drive media=cdrom,file=${OVMF}/UefiShell.iso \
> -net none -serial stdio -display none -m 256M -cpu host

The OVMF command line interface should appear in your terminal (stdio). Type exit to enter the UEFI shell interface. Press Ctrl-C to shut down the VM.

Additional VM management tools

Install these packages to import and manage guest images with qemu-kvm:

> sudo dnf install libguestfs libguestfs-tools libguestfs-winsupport virt-dib \
> virt-v2v virt-p2v-maker
References
  1. How to Create A Network Bridge on CentOS 7
  2. CentOS/RHEL 7: How to modify Network Interface names
  3. Understanding the Network interface configuration file
  4. Disable Network Manager on CentOS 7
  5. UEFI boot for VM
  6. qemu-kvm-ev
  7. Windows 10 VM
  8. libvirt networking
  9. Use virt-manager as a non-root user on Linux
  10. edk2 quickstart for virtualization
  11. Open Virtual Machine Firmware (OVMF) Status Report
  12. How to boot Windows partition virtually under KVM with UEFI firmware
  13. UEFI, PC boot process and UEFI with QEMU
  14. Setting up QEMU with OVMF (UEFI) and swtpm (software TPM emulation)