OpenBSD has this small, nice virtual machine monitor (VMM) you can use to run accelerated virtual machines (VM) on OpenBSD. This article describes how to set up vmm(4) and how to run various operating systems.
I run -current on my personal machine and thus all of the following applies to the version as of September 2018.
Sometimes, it's not desired to create a disk image plus a VM configuration, e.g., if you only want to fire up an ISO image to see if it boots. Use
vmctl start and the
-r option to specify the path to the ISO. Additionally, set
-c to see the serial console output.
vmctl will ask you for a name so set a random one since the name doesn't matter here:
# vmctl start foo -r cd64.iso -c vmctl: starting without disks vmctl: starting without network interfaces Connected to /dev/ttypc (speed 115200) SeaBIOS (version 1.11.0p0-OpenBSD-vmm) CD-ROM: E0 Loading /6.4/AMD64/CDBOOT probing: pc0 com0 mem[638K 510M a20=on] disk: cd0 >> OpenBSD/amd64 CDBOOT 3.40 boot> cannot open cd0a:/etc/random.seed: No such file or directory booting cd0a:/6.4/amd64/bsd.rd: 3511114+1500160+3887944+0+593920 [372415+111+440712+293098]=0xa1e528 entry point at 0x1000158 Copyright (c) 1982, 1986, 1989, 1991, 1993 The Regents of the University of California. All rights reserved. Copyright (c) 1995-2018 OpenBSD. All rights reserved. https://www.OpenBSD.org OpenBSD 6.4-beta (RAMDISK_CD) #305: Sun Sep 23 23:34:36 MDT 2018 firstname.lastname@example.org:/usr/src/sys/arch/amd64/compile/RAMDISK_CD [...]
In most cases, you want to have a persistent storage for your VM. Use
qemu-img to create a new hard disk. It doesn't matter if you create the image with vmctl or qemu-img, however, the first one is include in base. Use
-f to switch between raw and the more modern qcow2 format. The following command creates a qcow2 format disk images with a maximum size of 10 GB:
$ vmctl create vm-disk.img -s 10G -f qcow2 vmctl: imagefile created $ ll -ls vm-disk.img 1 -rw------- 1 xhr wheel - 256K Sep 24 12:34 vm-disk.img
There are several ways to connect guest VMs to the network. The simplest one and the one I use is called local interfaces. A local interface is added to a VM by using the
-L option with
vmctl start. You will get a vio(4) interface within the VM connected to a tap(4) interface on the host. All IP addresses come from the shared, globally non-routed 100.64.0.0/10 address pool and served from a buit-in DHCP server. For the logic on how the IP addresses in the VM and the host are choose read the excellent man page of vmctl.
In the following example I use the same command as above but this time with the
-L option. Note how the vio0 interface gets an IP address via the built-in DHCP server:
$ doas vmctl start foo -r cd64.iso -c -L [...] Welcome to the OpenBSD/amd64 6.4 installation program. (I)nstall, (U)pgrade, (A)utoinstall or (S)hell? s # dhclient vio0 vio0: bound to 100.64.8.3 from 100.64.8.2 (fe:e1:bb:d1:5e:b4) # ifconfig vio0 vio0: flags=8b43<UP,BROADCAST,RUNNING,PROMISC,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500 lladdr fe:e1:bb:d1:5e:b3 llprio 3 groups: egress media: Ethernet autoselect status: active inet 100.64.8.3 netmask 0xfffffffe
On the host, a tap(4) interface is now visible:
tap0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 lladdr fe:e1:ba:d0:85:ce description: vm8-if0-foo index 7 priority 0 llprio 3 groups: tap status: active inet 100.64.8.2 netmask 0xfffffffe
This is sufficient if you just want to have a connection between the VM and the host, If you want to grant Internet access to the VM via NAT you have to set up some pf(4) rules on the host. Add the following lines to your
pf.conf and set the variables accordingly. The second rule is only needed if you want to redirect the VM's DNS traffic to
$dns_server. Usually, the DHCP sets the IP address of the host as DNS server.
match out on $ext_if from 100.64.0.0/10 to any nat-to $ext_if pass out on $ext_if from 100.64.0.0/10 to any nat-to $ext_if pass in proto udp from 100.64.0.0/10 to any port domain \ rdr-to $dns_server port domain
On the host you also have to enable IP forwarding via
sysctl. To persistently enable forwarding set the value in
/etc/sysctl.conf. While the former is active immediately, the latters needs a reboot.
# sysctl net.inet.ip.forwarding=1 net.inet.ip.forwarding: 0 -> 1 # grep forwarding /etc/sysctl.conf net.inet.ip.forwarding=1 # 1=Permit forwarding (routing) of IPv4 packets
Installing OpenBSD on vmm is really simple. Create a hard disk as described above and use the last
vmctl command from above and add the
-d option with the path to the disk image to the start command. If you use a qcow2 disk image, you have to prefix the path with qcow2:. For raw disks no prefix is needed. By default, a VM gets 512M RAM assigned, if you need more, just use
# vmctl start foo -r cd64.iso -c -L -m 1024M -d qcow2:vm-disk.img Welcome to the OpenBSD/amd64 6.4 installation program. (I)nstall, (U)pgrade, (A)utoinstall or (S)hell? i At any prompt except password prompts you can escape to a shell by typing '!'. Default answers are shown in 's and are selected by pressing RETURN. You can exit this program at any time by pressing Control-C, but this can leave your system in an inconsistent state. Terminal type? [vt220] System hostname? (short form, e.g. 'foo') test Available network interfaces are: vio0 vlan0. Which network interface do you wish to configure? (or 'done') [vio0] IPv4 address for vio0? (or 'dhcp' or 'none') [dhcp] vio0: bound to 100.64.11.3 from 100.64.11.2 (fe:e1:bb:d1:d0:83) IPv6 address for vio0? (or 'autoconf' or 'none') [none] Available network interfaces are: vio0 vlan0. Which network interface do you wish to configure? (or 'done') [done] DNS domain name? (e.g. 'example.com') [my.domain] Using DNS nameservers at 100.64.11.2 Password for root account? (will not echo) Password for root account? (again) Start sshd(8) by default? [yes] Change the default console to com0? [yes] Available speeds are: 9600 19200 38400 57600 115200. Which speed should com0 use? (or 'done')  Setup a user? (enter a lower-case loginname, or 'no') [no] Since no user was setup, root logins via sshd(8) might be useful. WARNING: root is targeted by password guessing attacks, pubkeys are safer. Allow root ssh login? (yes, no, prohibit-password) [no] yes Which disk is the root disk? ('?' for details) [sd0] No valid MBR or GPT. Use (W)hole disk MBR, whole disk (G)PT or (E)dit? [whole] Setting OpenBSD MBR partition to whole sd0...done. The auto-allocated layout for sd0 is: # size offset fstype [fsize bsize cpg] a: 152.7M 64 4.2BSD 2048 16384 1 # / b: 85.5M 312864 swap c: 10240.0M 0 unused d: 124.4M 487904 4.2BSD 2048 16384 1 # /tmp e: 87.1M 742624 4.2BSD 2048 16384 1 # /var f: 902.7M 921024 4.2BSD 2048 16384 1 # /usr g: 385.6M 2769824 4.2BSD 2048 16384 1 # /usr/X11R6 h: 1032.2M 3559616 4.2BSD 2048 16384 1 # /usr/local i: 1301.1M 5673568 4.2BSD 2048 16384 1 # /usr/src j: 5122.2M 8338208 4.2BSD 2048 16384 1 # /usr/obj k: 1043.1M 18828448 4.2BSD 2048 16384 1 # /home Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a] newfs: reduced number of fragments per cylinder group from 19544 to 19464 to enlarge last cylinder group /dev/rsd0a: 152.7MB in 312800 sectors of 512 bytes 5 cylinder groups of 38.02MB, 2433 blocks, 4992 inodes each /dev/rsd0k: 1043.1MB in 2136352 sectors of 512 bytes 6 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each /dev/rsd0d: 124.4MB in 254720 sectors of 512 bytes 4 cylinder groups of 31.09MB, 1990 blocks, 4096 inodes each /dev/rsd0f: 902.7MB in 1848800 sectors of 512 bytes 5 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each newfs: reduced number of fragments per cylinder group from 49360 to 49160 to enlarge last cylinder group /dev/rsd0g: 385.6MB in 789792 sectors of 512 bytes 5 cylinder groups of 96.02MB, 6145 blocks, 12416 inodes each /dev/rsd0h: 1032.2MB in 2113952 sectors of 512 bytes 6 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each /dev/rsd0j: 5122.2MB in 10490240 sectors of 512 bytes 26 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each /dev/rsd0i: 1301.1MB in 2664640 sectors of 512 bytes 7 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each newfs: reduced number of fragments per cylinder group from 11144 to 11096 to enlarge last cylinder group /dev/rsd0e: 87.1MB in 178400 sectors of 512 bytes 5 cylinder groups of 21.67MB, 1387 blocks, 2816 inodes each /dev/sd0a (817470d5e8e2306d.a) on /mnt type ffs (rw, asynchronous, local) /dev/sd0k (817470d5e8e2306d.k) on /mnt/home type ffs (rw, asynchronous, local, nodev, nosuid) /dev/sd0d (817470d5e8e2306d.d) on /mnt/tmp type ffs (rw, asynchronous, local, nodev, nosuid) /dev/sd0f (817470d5e8e2306d.f) on /mnt/usr type ffs (rw, asynchronous, local, nodev) /dev/sd0g (817470d5e8e2306d.g) on /mnt/usr/X11R6 type ffs (rw, asynchronous, local, nodev) /dev/sd0h (817470d5e8e2306d.h) on /mnt/usr/local type ffs (rw, asynchronous, local, nodev) /dev/sd0j (817470d5e8e2306d.j) on /mnt/usr/obj type ffs (rw, asynchronous, local, nodev, nosuid) /dev/sd0i (817470d5e8e2306d.i) on /mnt/usr/src type ffs (rw, asynchronous, local, nodev, nosuid) /dev/sd0e (817470d5e8e2306d.e) on /mnt/var type ffs (rw, asynchronous, local, nodev, nosuid) Let's install the sets! Location of sets? (cd0 disk http or 'done') [cd0] [...]
As of today, vmm(4) does not support enhanced graphics like VGA output so you need a guest operating system that supports a serial console. Since the serial console is not always active by default you can either try to activate it by modifying the ISO/boot image or you just install the guest operating system in qemu, activate the serial console and attach the disk to vmm(4) later. Be advised that vmm(4) currently does not support all Unix-like operating systems you might like. If in doubt, just give it a try or search the mailing list archive.
It doesn't matter on which system you choose to install via qemu, so I prefer to do this on Linux since qemu on OpenBSD is not accelerated. An non-accelerated Debian Linux installation could easily take an hour. Since qemu and vmm(4) both supports the qcow2 disk format it is my preferred choice.
If you want to go with OpenBSD, install qemu via
# pkg_add qemu
Create a qcow2 disk image file as mentioned above and use the following command to boot the specified ISO image. This will give a graphical VGA console and you can easily install the operating system of your choice. In the following example I use Debian Linux.
# qemu-system-x86_64 -m 512 -no-fd-bootchk -net nic,model=e1000,macaddr=0a:54:00:4e:62:8a -net user \ -cdrom /tmp/debian-9.5.0-amd64-netinst.iso -boot d debian.img
$Id: vmm.md,v 1.6 2020/05/16 07:44:02 cvs Exp $