On a kvm-capable x86_64 host running CentOS Linux 7.9 with a single wired network adapter and a static ipv4 address:
Disable NetworkManager and set up a network bridge.
Add a tun/tap device to the bridge for pass-thru networking with qemu guests.
Install and configure qemu-kvm and related packages with support for guests requiring both UEFI and legacy BIOS boot.
Test boot an iso image with UEFI boot.
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
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
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=?
Guest is in a qemu-managed private LAN.-netdev user,id=id[,option][,option][,...]
host bridge --> tap device --> guest NIC-netdev tap,id=id[,fd=h][,ifname=name][,script=file][,downscript=dfile] [,helper=helper]
-netdev bridge,id=id[,br=bridge][,helper=helper]
-netdev socket,id=id[,fd=h][,listen=[host]:port][,connect=host:port]
-netdev vde,id=id[,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]
-netdev hubport,id=id,hubid=hubid
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.
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