Today I’ll document how to create a bridge network for a qemu virtual machine on macos.

The default virtual NIC created by qemu uses user mode. The virtual machine can communicate with the outside world normally, but the host cannot access the virtual machine directly.

If you want to give the outside world direct access to the virtual machine, the easiest way is to build a bridged network. Most of what is currently available online utilizes the tap mode. However, macos does not support tap devices and relies on the third-party TunTap project. Since the newer versions of macos have deprecated the use of kernel extensions, the TunTap project is no longer being developed.

Isn’t there a solution? Yes, starting with 10.10 Yosemite, macos provides Hypervisor.framework, a virtualization framework native to the BSD kernel, somewhat similar to Linux’s KVM module. hypervisor.framework supports the creation of bridged networks for virtual machines. qeum will start supporting hypervisor.framework around the end of 2021. Hypervisor.framework, which can be found here.

The complete start-up command is as follows.

1
2
3
4
sudo qemu-system-x86_64 path/to/disk \
         -M accel=hvf \
        -cpu host -smp cpus=8 -m 256 \
        -nic vmnet-bridged,ifname=en0

where -M accel=hvf specifies the use of the Hypervisor.framework framework, which is only valid on macos platforms. The following line is set to the number of cpu cores and memory size. The following -nic vmnet-bridged,ifname=en0 specifies to create a bridged network. ifname specifies the NIC to be bridged.

My wireless NIC is en0, so the above command will bridge the virtual machine’s NIC to the macos wireless NIC. Once the virtual machine starts up, it will be assigned the same network segment IP address as the host, and it will support IPv6 networks.

qemu has two parameters, netdev and nic. theoretically, the type of the NIC is specified by nic, and then the other parameters of the NIC are specified in detail by netdev. However, I found that using netdev did not work, but instead I could use the nic parameter directly.

The complete parameter structure is as follows.

1
2
3
4
5
6
7
-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]
                configure a vmnet network backend in bridged mode with ID 'str',
                use 'ifname=name' to select a physical network interface to be bridged,
                isolate this interface from others with 'isolated'
-nic [tap|bridge|user|vde|vhost-user|vmnet-host|vmnet-shared|vmnet-bridged|socket][,option][,...][mac=macaddr]
                initialize an on-board / default host NIC (using MAC address
                macaddr) and connect it to the given host network backend

Specifying only the netdev parameter will throw an exception: qemu-system-x86_64: warning: netdev bridge1 has no peer.

If only the -nic bridge parameter is specified, an exception is thrown: qemu-system-x86_64: -nic vmnet-bridged: Parameter 'ifname' is missing.

So let’s just use -nic vmnet-bridged,ifname=en0 😄

qemu also supports two other network modes.

  • vmnet-host Virtual machines can only access each other with the host, but cannot access the external network
  • vmnet-shared Virtual machines can access each other, but the host cannot access the virtual machines

Both of these are not as convenient as bridging, so I won’t go into detail.