kvm nat over host wireless

After using virtualbox as my only virtualization for quite some time, I have decided to try out QEMU/KVM. So far, I find this approach to be a better solution for my personal virtualization needs (a couple of BSD/Linux guest machines running on a Linux host), but because of the elusive and fragmented nature of documentation for the project, especially in regards to the available networking options and their various benefits and limitations, I have decided to write up some of my experiences in hopes that they will be useful to others.

I am sure that there are easier ways to accomplish the same goals, and if you have a better idea, please email me at the contact link on the front page of this site. Anyways, time to get to the point.

First of all, I am not using libvirt or any gui application to manage any of my virtual machines. Also, while I do have TigerVNC installed, I use it mostly for the initial installation of virtual machines, before I am able to enable SSH. Mostly I am trying to do things using the command line tools and tend to access the virtual machines via SSH with and without X-forwarding from the host.

With that being said, to launch a virtual machine from the command line I would type something like:

$ qemu-system-x86_64 -enable-kvm \
	-cpu host \
	-smp 4,cores=4 \
	-m 2048 \
	-boot order=c -drive file=/home/$USER/virtual_drive,if=virtio \
	-net nic,vlan=0 -net tap,vlan=0

In this case, the relevant part of the syntax is the last section: “-net nic,vlan=0 -net tap,vlan=0,” which tells QEMU/KVM which type of networking interface to use as well as what to call it. It should be noted, however, that according to this page, this syntax is obsolete. I have been unable to get the proper syntax working, so for now, we will use this older method.

Next, we need to have two scripts in our /etc directory. By default they should be called qemu-ifup and qemu-ifdown. Additionally, they have variables that are configured in /etc/qemu/qemu-if.conf, so we need to create this file also.

/etc/qemu-ifup

#!/bin/sh

. /etc/qemu/qemu-if.conf

echo "$0:"
echo "Setting up the network bridge for $1"
brctl addbr "$BRIDGE"
brctl addif "$BRIDGE" "$1"
ifconfig "$BRIDGE" "$HOST" netmask "$MASK"
ip link set "$1" up
ip link set "$BRIDGE" up

if iptables -t nat -L POSTROUTING -n | grep ^MASQUERADE | \
  awk '{print $4}' | cut -d/ -f1 | grep "$NETWORK" >/dev/null
then
  echo "IP masquerading already set up"
else
  echo "Setting up IP masquerading"
  iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
  iptables -I FORWARD 1 -i tap0 -j ACCEPT
  iptables -I FORWARD 1 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT
fi

echo "Setting up IP forwarding"
sysctl net.ipv4.ip_forward=1

exit 0

This script sets up an ethernet bridge interface as well as the necessary iptables rules. This is for a wirelesss configuration, but you should be able to substitute your interface name in place of wlan0 with similar results.

/etc/qemu-ifdown

#!/bin/sh

. /etc/qemu/qemu-if.conf

echo "$0:"

echo "Tearing down network bridge for $1"
ip link set $1 down
brctl delif "$BRIDGE" $1

ifconfig kvmnat 0.0.0.0
ip link set "$BRIDGE" down
brctl delbr "$BRIDGE"

exit 0

This script is used to tear down our bridge interface. Note that if you change the value of BRIDGE in the following configuration file that you must update this script to reflect that also.

The variable used by the previous up/down scripts are set in the following file. You probably don’t need to change the value for MASK but feel free to rename BRIDGE to something else if you like. You can also change NETWORK and HOST as these are somewhat arbitrary, but be consistent with the first three groups of numbers or it will not work. Also NETWORK must end with a “0” but you could use something like 10.0.2.0.

/etc/qemu/qemu-if.conf

BRIDGE=kvmnat
NETWORK=192.168.2.0
HOST=192.168.2.1
MASK=255.255.255.0

If you are planning on running multiple virtual machines simultaneously, then you may want to disable the downscript from being called on machine shutdown, so that you don’t tear down you ethernet bridge when you choose to poweroff one virtual machine. To do this simply append “,downscript=no” to the end of you startup options so that this:

$ qemu-system-x86_64 -enable-kvm \
	-cpu host \
	-smp 4,cores=4 \
	-m 2048 \
	-boot order=c \
	-drive file=/home/$USER/virtual_drive,if=virtio \
	-net nic,vlan=0 -net tap,vlan=0

becomes:

$ qemu-system-x86_64 -enable-kvm \
	-cpu host -smp 4,cores=4 \
	-m 2048 \
	-boot order=c \
	-drive file=/home/$USER/virtual_drive,if=virtio \
	-net nic,vlan=0 -net tap,vlan=0,downscript=no

Well, that pretty much does it regarding this little network tutorial. If you happen to have any suggestions, send a mail. Enjoy using your wireless network card with your virtual machines in QEMU/KVM.