QEMU on Mac and Linux
Disk Image
qemu-img create -f raw pg1.img 20G qemu-img create -f raw pg1-data.img 50G
Generating MAC addresses
#!/usr/local/bin/python3 import random def random_mac(): mac = [ 0x00, 0x16, 0x3e, random.randint(0x00, 0x7f), random.randint(0x00, 0xff), random.randint(0x00, 0xff) ] return ':'.join(map(lambda x: "%02x" % x, mac)) print(random_mac())
The prefix
00:16:3e
is one of several ranges sometimes used for virtual machines.
QEMU on Linux
qemu-system-x86_64 \ -accel kvm \ -m 1024 \ -cpu host \ -bios /usr/share/edk2/ovmf/OVMF_CODE.fd \ -drive file=/vm/pg1.img,format=raw,if=virtio \ -nic tap,ifname=tap0,model=virtio-net-pci,mac=00:16:3e:02:63:dc \ -nographic \ -serial tcp::4444,server,telnet
The
edk2-ovmf
package provides a UEFI firmware image that will try a network boot
nmcli con add type bridge ifname br0 con-name br0 nmcli con add type bridge-slave ifname eno1 master br0 nmcli con mod br0 ipv4.address "10.200.1.1/24" nmcli con mod br0 ipv6.address "fd00:c8:1::1/64" nmcli device reapply br0
The Linux bridge interface takes over member interfaces, so the external IP addess must be assigned to bridge.
Two helper scripts are used to set up networking
# /etc/qemu-ifup ip link set $1 master br0 ip link set dev $1 up
# /etc/qemu-ifdown ip link delete $1 master br0
Create
/etc/systemd/system/qemu@.service
[Unit] Description=QEMU virtual machine After=network-online.target [Service] ExecStart=/root/start-vm.sh %i [Install] WantedBy=multi-user.target
Enable each VM using it's name
systemctl enable qemu@pg1
OpenBSD on Mac
qemu-system-aarch64 \ -M virt \ -accel hvf \ -m 2048 \ -cpu cortex-a57 \ -bios /opt/homebrew/Cellar/qemu/10.0.2_2/share/qemu/edk2-aarch64-code.fd \ -drive file=miniroot78.img,format=raw,if=virtio \ -drive file=openbsd.qcow2,format=qcow2,if=virtio \ -nic vmnet-bridged,ifname=en0 \ -nographic \ -serial tcp::4444,server,telnet
Supported options are shown by
qemu-system-aarch64 -help.
vmnet-shared
will provide an address on a private subnet.
vmnet-bridge
allows a virtual machine to get an address
on the local area network, but must be run as root.
ifconfig
will show the interface added to a new bridge
bridge100: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=3<RXCSUM,TXCSUM>
ether 4e:20:b8:1e:da:64
Configuration:
id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
ipfilter disabled flags 0x0
member: en0 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 6 priority 0 path cost 0
member: vmenet0 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 21 priority 0 path cost 0
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
Docker Images for Alternate Architectures
Docker images can be launched using QEMU to emulate other architectures
apt install -y docker.io apt install -y qemu-user-static usermod -a -G docker $USER
The
Dockerfile
consists of the base image, and the emulator to be used as the starting point
FROM arm32v6/alpine:latest COPY tmp/qemu-arm-static /usr/bin/qemu-arm-static RUN apk add musl-dev make gcc git tmux bash
To build the image run
mkdir tmp cp /usr/bin/qemu-arm-static tmp/ docker run --rm --privileged multiarch/qemu-user-static:register --reset docker build -t radman/arm-vm .