I am an obstinate git, which is why I’m currently running my internet router/firewall as a pfSense VM guest on a FreeBSD server.
As you can imagine, this makes setting up my home network very … interesting, because first I have to set up FreeBSD and then my router?
Bhyve is the FreeBSD-native hypervisor for running virtual machines. I know that FreeBSD supports being a host for something more industrial like Xen but that is pretty damn heavyweight and actually loses a bunch of functionality in FreeBSD compared to running it on Linux.
Bhyve is a pretty low-level tool. Just as with FreeBSD jails, one doesn’t normally interact with the built-into-FreeBSD low-level commands directly, one uses a helper package to streamline the VM creation/operation/configuration process, and to start up VMs on bootup, etc…
But those tools aren’t installed on a freshly-installed FreeBSD install, and I didn’t want to first have to configure my networking stack to work using a consumer hardware router device and then reconfigure everything back into my FreeBSD-server-centric system…..
OK what I mean to say is that I had this working and then I screwed up my server and I needed to rebuild it and wanted to figure out a lazier way to do so :)
Anyway I’ll just spit out the raw instructions and then maybe I’ll explain what’s going on. I don’t think any of this isn’t explained in the FreeBSD handbook or by reading example bhyve scripts, but I wanted a nice simple handy reference for the future.
I guess in theory you need the Internet to get these resources, as well as a USB stick, but it can’t be turtles all the way down!
/home/<yourname>/pfsense.img
or whatever.bridge
interface via ifconfig
./vm/pfsense.dsk
. But it doesn’t matter, and feel free to use ZFS as per the handbook (I did!)bhyveload -c /dev/nmdm0A -m 1G -d /home/<yourname>/pfsense.img
bhyve -m 1G -AHP -s 0,hostbridge -s 1,lpc -s 2:0,virtio-blk,/vm/pfsense.dsk -s 3:0,virtio-net,tap0 -s 4:0,virtio-net,tap1 -s 31:0,virtio-blk,/home/<yourname>/pfsense.img -l com1,/dev/nmdm0A pfsense
cu /dev/nmdm0B
Voila! You now have access to the initial pfSense console setup! Finish setting things up until it restarts, which will be a lie, restarting actually terminates the bhyve process.bhyvectl --destroy --vm=pfsense
. Don’t worry! Because you’ve installed things to disk, all settings and such still remain on /vm/pfsense.img! (It’s weird I don’t know why that resource state still exists. I guess it’s like the machine is suspended at the point it’s telling its (virtualized) hardware to shut down?bhyveload -c /dev/nmdm0A -m 1G -d /vm/pfsense.dsk
. Note that we’re now giving the HDD image!bhyve -m 1G -AHP -s 0,hostbridge -s 1,lpc -s 2:0,virtio-blk,/vm/pfsense.dsk -s 3:0,virtio-net,tap0 -s 4:0,virtio-net,tap1 -l com1,/dev/nmdm0A pfsense
. Note that we aren’t referencing the install image now!But you now have a working pfSense …. until you restart FreeBSD :) At this point you have enough internet to configure your FreeBSD host to have its own IP address (again see my previous pfSense/FreeBSD post) and install your Bhyve wrapper of choice (at this time of writing, iohyve
or vm-bhyve
have been used by me and I like both equally). Usually what I do is use their command-line tools to set up a new permanent pfsense instance, kill the one I was manually running, and move the /vm/pfsense.img file where the wrapper exists the disk drive to be. You’ll have to read up on your preferred tool to do that, but at least you have the internet now :)
I’m not going to explain the stuff that feels obvious from the manpage, but …. ok, for some reason, bhyve uses bhyveload
to load the FreeBSD kernel into the VM and prep it for booting. Did I mention that pfSense is based on FreeBSD? I guess now you know :)
Afterwards you run bhyve
which actually creates the generic virtual hardware and such. My understanding is that if you wanted to boot into Linux for example, instead of bhyveload
you use something called bhyve-grub
which is the equivalent for loading the Linux kernel but I don’t know how it works or if shares the same arguments.
Anyway the bhyveload
kernel loader you’re basically telling it the amount of memory you want the system to have, the FreeBSD console device to use for terminal output, and boot media. You then tell all that to the bhyve
program as well.
The bhyve
manpage explains -AHP pretty well and why you want to use them. All those -s
params basically set up hardware. In something like -s 3:0,virtio-blk,/vm/pfsense.dsk
, it’s basically saying “Hardware device 3 is a virtualized block (i.e. disk) device, and here’s an argument (which here means the actual disk image file used to store the emulated hard drive’s data).” I don’t think it matters which device is in which “slot”, as it were, I can use basically any number up to at least 31 I think.
The hostbridge
and lpc
devices are core and necessary to any VM. The rest are obviously network and disk images.
The -l
flag seems to set up the console device.
Anyway hopefully that explains a little bit more about how Bhyve works. It feels pretty simple now, but the documentation is always written in that nerd style that’s way more imposing than it needs to be!
If you use PCI passthru on any of your networking devices, as I did a la this page, you’ll have to add -S
to both the bhyveload
and bhyve
commands.