LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Networking (http://www.linuxquestions.org/questions/linux-networking-3/)
-   -   KVM / QEMU and NAT on the host machine (mini-tutorial) (http://www.linuxquestions.org/questions/linux-networking-3/kvm-qemu-and-nat-on-the-host-machine-mini-tutorial-697980/)

heby 01-17-2009 02:46 PM

KVM / QEMU and NAT on the host machine (mini-tutorial)
 
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...

stress_junkie 01-17-2009 04:38 PM

Thank you. I've wanted to play with KVM for some time. This article is just the startup help to get me moving.

usman_minhas 01-28-2009 03:16 PM

I am new to linux. I would be rateful if you could please provide us with the KVM installation tutorial for Fedora 10. would appreciate your response.
regards,
Usman

heby 02-09-2009 03:49 PM

Same setup but run kvm as a user
 
I normally wouldn't reply to my own post but when I was initially playing with kvm (which is when I made the original post), I didn't much care that I had to start it as root. Now that I want to use it in a production environment, things are a bit different. So here are some very brief instructions on how to do the same thing but allow a user to start kvm. Since the network startup and teardown scripts /etc/kvm/kvm-ifup and /etc/kvm/kvm-ifdown are executed as the user, they become useless for setting up the network and hence should be empty (note that the default kvm-ifup file in debian tries to set up a bridge to the physical network card - obviously we don't want that, so you will have to delete the corresponding lines). Instead, I added the following lines to /etc/rc.local to set up the bridge and tap interface at boot time:

Code:

USER=heby
BRIDGE=kvmnat
NETWORK=192.168.172.0
HOST=192.168.172.1
MASK=255.255.255.0
IF=`tunctl -b -u $USER`
brctl addbr "$BRIDGE"
brctl addif "$BRIDGE" "$IF"
ifconfig "$BRIDGE" "$HOST" netmask "$MASK"
ip link set "$IF" up
ip link set "$BRIDGE" up
iptables -t nat -A POSTROUTING -s "$NETWORK/$MASK" -d ! "$NETWORK/$MASK" -j MASQUERADE
sysctl net.ipv4.ip_forward=1

Obviously, you may want to replace "heby" by your own user id... Reboot your computer (or execute the script as root) and start kvm as user. Note that the name of the tap interface needs to be explicitly passed to kvm (tap0 in this case). This may be different for you if you have more than one tap interface, in which case you may want to come up with a smarter solution than hardcoding it. Since I don't use any other tap interfaces this works well for me:

Code:

kvm -hda /home/heby/kvm/diskimage.qc2 -m 1024 -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 -localtime -soundhw all

enriqueaf 10-19-2010 10:49 AM

Late but thanks
 
I know have passed so much time ( 1 year :D ) but I have to say thanks. This looks really nice, haven't tried yet but it is a clever solution.

Thanks
Enrique

BiFo 05-16-2012 10:17 AM

Hi!
I've tried this and works very well.
But the only way it works its if i start the virtual machine like you.
Is there a way to configure virt-manager to start it with those "-net" parameters?

Thanks in advance.
Bye!


All times are GMT -5. The time now is 07:33 PM.