I was setting up a virtual machine with Windows XP as a guest on my Debian Lenny host system and has the hardest time finding any information about how to set up the specific networking configuration I wanted. To save other people from having an almost sleepless night over something that should be straightforward (and it actually is, once you figure it out), here's a little tutorial on how to set up KVM with NAT so the guest shares the host's IP address. Of course you could simply use the "user" networking option, which provides a simple NAT, but that doesn't properly work for UDP, ICMP and port forwarding and there is evidence that it doesn't perform very well either. Bridged networking doesn't work with all wireless cards and it is not an option if you have only one IP address. Long story short, here is what I wanted to set up:
network (192.168.0.0/24) ---- (192.168.0.100) host with NAT (192.168.172.1) ---- (192.168.172.13) guest
On Lenny at least, kvm comes with a network setup script (/etc/kvm/kvm-ifup) which works if (and only if, it seems) the network device used for the default route is a bridge, which then in turn has the physical ethernet network card as one of its interfaces. That's not what we want, so let's move it out of the way.
Code:
mv /etc/kvm/kvm-ifup /etc/kvm/kvm-ifup.orig
We then create three files:
1: /etc/kvm/kvm-if.conf
Code:
BRIDGE=kvmnat
NETWORK=192.168.172.0
HOST=192.168.172.1
MASK=255.255.255.0
which contains the configuration for the network that will link the host and the guest.
2: /etc/kvm/kvm-ifup
Code:
#!/bin/sh
. /etc/kvm/kvm-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 -s "$NETWORK"/"$MASK" -d ! "$NETWORK"/"$MASK" -j MASQUERADE
fi
echo "Setting up IP forwarding"
sysctl net.ipv4.ip_forward=1
exit 0
This script is called by kvm upon startup of the virtual machine. It creates a bridge and connects to it the tap interface that kvm creates for the virtual machine. It then assigns the bridge an IP address on the host side, sets up the NAT (if not already present) and activates IP forwarding on the host. Note that the two "ip link <interface> up" commands are necessary here, not sure what shuts them down in the first place but at that point of the script the interfaces are down.
2: /etc/kvm/kvm-ifdown
Code:
#!/bin/sh
. /etc/kvm/kvm-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
Finally, this script is responsible for cleaning up after the virtual machine shuts down. Note that it doesn't remove the masquerading or IP forwarding because they could be active for other reasons as well and we don't want to shut those down.
Now you can start your guest operating system
Code:
kvm -hda disk.img -net nic,vlan=0 -net tap,vlan=0
plus whatever other parameters you need. On the guest system, I used a simple static network setup:
IP address: 192.168.172.13
Netmask: 255.255.255.0
Gateway: 192.168.7.1
DNS: 192.168.0.1
Note that the DNS server is the one that the host uses - this will likely be different for you. Of course, if one wanted to be a bit more sophisticated, one could set up a proxy DNS server and use 192.168.172.1 as the resolver for the guest. Even better, run a DHCP server on the host to provide the guest with a complete network setup automatically.
Now you should be all set to forward host ports to the guest via iptables, and to use UDP and ICMP on the guest system. I hope this is useful to somebody...