I've been playing around with qemu and wanted to make the guest OS instance visible on my network. This meant getting bridging and tun/tap working. After getting things working by pasting command from the CentOS wiki article plus adding a few enhancements, I decided to capture the process in a shell script that would be suitable for a user in the sudoers file to fire off. Not sure why (which is why I'm posting this) but I couldn't get the same result from the shell script as I got from pasting commands onto the command line or using the shell history.
After a lot of very tedious debugging, I finally got the script to work by adding a couple of short sleeps at selected locations. The script now looks like:
cat upBridge.sh #!/bin/bash # # Script for setting up a bridge accessible by a qemu VM. # # First, make sure we're starting with a clean slate. /usr/bin/sudo /sbin/rmmod bridge /usr/bin/sudo /sbin/rmmod tun /usr/bin/sudo /sbin/service network restart # # Grab the IP address of the given interface so we can restore it later. # oldIP=`/sbin/ifconfig $1 | /bin/grep 'inet addr' | /usr/bin/awk -F : '{print substr($2,0,index($2, " ")) ; }'` echo "$1 currently has IP address $oldIP" # # Create the bridge. # /usr/bin/sudo /usr/sbin/brctl addbr br0 /usr/bin/sudo /sbin/ifconfig $1 0.0.0.0
sleep 2
/usr/bin/sudo /usr/sbin/brctl addif br0 $1 # # Stop any dhclient still running. # /usr/bin/sudo /usr/bin/killall dhclient # # Get and IP address and routing information for the bridge # /usr/bin/sudo /sbin/dhclient br0 # # Make sure the tun module is loaded, assign it to our user and bring it up. # /usr/bin/sudo /sbin/modprobe tun echo "Did tun load?" lsmod | grep tun /usr/bin/sudo /usr/sbin/tunctl -b -u $USER
sleep 2
/usr/bin/sudo /sbin/ifconfig tap0 up # # Connect the bridge and the tap. # /usr/bin/sudo /usr/sbin/brctl addif br0 tap0 /usr/bin/sudo /bin/chown $USER:users /dev/net/tun /usr/bin/sudo /sbin/iptables -I RH-Firewall-1-INPUT -i br0 -j ACCEPT # # restore the IP address of our "normal" interface. # /usr/bin/sudo /sbin/ifconfig $1 $oldIP
So, my question is, why do I need to have a short sleep in these two locations in my script?
Without a sleep after the "ifconfig eth0 0.0.0.0", eth0 retains its original IP address instead of having no address. The qemu guest VM still functions correctly but the host system loses connectivity. Likewise, without a sleep after the tunctl command, the device /dev/net/tun isn't present when the next command executes. With the sleeps the script executes as expected and sets up the bridge. Without the sleeps the script fails.
Oh yeah. There's another script called downBridge.sh that undoes the bridge if anyone is interested.
Cheers, Dave
On Mon, Feb 09, 2009 at 08:22:02PM -0700, David G. Miller wrote:
I've been playing around with qemu and wanted to make the guest OS instance visible on my network. This meant getting bridging and tun/tap working. After getting things working by pasting command from the
[snippage]
I do it differently for my UML instances, but I don't see why this shouldn't work with qemu as well.
Firstly I have a simple boot script that creates the bridge and binds the real interface (eth1 in my case) to the bridge.
#!/bin/sh
# BRIDGE Create br0 with just eth1 bound # # chkconfig: 2345 09 91 # description: Activates br0
case "$1" in start) touch /var/lock/subsys/BRIDGE
/sbin/ifconfig eth1 0.0.0.0 promisc up
/usr/sbin/brctl addbr br0 /usr/sbin/brctl stp br0 off /usr/sbin/brctl setfd br0 1 /usr/sbin/brctl sethello br0 1 /usr/sbin/brctl addif br0 eth1 ;; stop) # Do nothing rm -f /var/lock/subsys/BRIDGE ;; status) echo $"Configured devices:" /usr/sbin/brctl show ;; restart|reload) # No nothing ;; *) echo $"Usage: $0 {start|stop|restart|reload|status}" exit 1 esac
exit 0
Then in my /etc/sysconfig/network-scripts area, I have br0 with the IP address I want. In my case, it's static
% cat /etc/sysconfig/network-scripts/ifcfg-br0 DEVICE=br0 ONBOOT=yes BOOTPROTO=static BROADCAST=10.0.0.255 IPADDR=10.0.0.136 NETMASK=255.255.255.0 NETWORK=10.0.0.0 TYPE=Ethernet
So what this means is that at bootup time the system will come up with br0 connected to the network and everything runs as normal. Basically, at this stage you can treat your machine as if 'br0' is the network device.
Now adding a new tap device to the bridge would be as simple as int=`tunctl -b -t $TAPNAME` ifconfig $int 0.0.0.0 promisc up brctl addif br0 $int
Now the new tap device is connected to the external network and the other side of the tap (the guest) can get an external IP address (eg via dhcp, or static) as normal.
On the host, only br0 shows as an IP address. The physical device (eth1) and added taps don't have an address when viewed with "ifconfig".