On Mon, 2011-05-23 at 14:16 +0800, Amos Kong wrote:
> On Sat, May 21, 2011 at 01:23:27AM -0300, Lucas Meneghel Rodrigues wrote:
> > This patch adds some helpers to assist virt test to setup the bridge or
> > macvtap based guest networking.
> >
> > Changes from v1:
> > * Fixed undefined variable errors on the exception class definitions
> >
> > Signed-off-by: Jason Wang <[email protected]>
> > Signed-off-by: Lucas Meneghel Rodrigues <[email protected]>
> > ---
> > client/virt/virt_utils.py | 218
> > +++++++++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 218 insertions(+), 0 deletions(-)
> >
> > diff --git a/client/virt/virt_utils.py b/client/virt/virt_utils.py
> > index 5510c89..96b9c84 100644
> > --- a/client/virt/virt_utils.py
> > +++ b/client/virt/virt_utils.py
> > @@ -6,6 +6,7 @@ KVM test utility functions.
> >
> > import time, string, random, socket, os, signal, re, logging, commands,
> > cPickle
> > import fcntl, shelve, ConfigParser, threading, sys, UserDict, inspect
> > +import struct
> > from autotest_lib.client.bin import utils, os_dep
> > from autotest_lib.client.common_lib import error, logging_config
> > import rss_client, aexpect
> > @@ -15,6 +16,20 @@ try:
> > except ImportError:
> > KOJI_INSTALLED = False
> >
> > +# From include/linux/sockios.h
> > +SIOCSIFHWADDR = 0x8924
> > +SIOCGIFHWADDR = 0x8927
> > +SIOCSIFFLAGS = 0x8914
> > +SIOCGIFINDEX = 0x8933
> > +SIOCBRADDIF = 0x89a2
> > +# From linux/include/linux/if_tun.h
> > +TUNSETIFF = 0x400454ca
> > +TUNGETIFF = 0x800454d2
> > +TUNGETFEATURES = 0x800454cf
> > +IFF_UP = 0x1
> > +IFF_TAP = 0x0002
> > +IFF_NO_PI = 0x1000
> > +IFF_VNET_HDR = 0x4000
> >
> > def _lock_file(filename):
> > f = open(filename, "w")
> > @@ -36,6 +51,76 @@ def is_vm(obj):
> > return obj.__class__.__name__ == "VM"
> >
> >
> > +class NetError(Exception):
> > + pass
> > +
> > +
> > +class TAPModuleError(NetError):
> > + def __init__(self, devname):
> > + NetError.__init__(self, devname)
> > + self.devname = devname
> > +
> > + def __str__(self):
> > + return "Can't open %s" % self.devname
> > +
> > +class TAPNotExistError(NetError):
> > + def __init__(self, ifname):
> > + NetError.__init__(self, ifname)
> > + self.ifname = ifname
> > +
> > + def __str__(self):
> > + return "Interface %s does not exist" % self.ifname
> > +
> > +
> > +class TAPCreationError(NetError):
> > + def __init__(self, ifname):
> > + NetError.__init__(self, ifname)
> > + self.ifname = ifname
> > +
> > + def __str__(self):
> > + return "Cannot create TAP device %s" % self.ifname
> > +
> > +
> > +class TAPBringUpError(NetError):
> > + def __init__(self, ifname):
> > + NetError.__init__(self, ifname)
> > + self.ifname = ifname
> > +
> > + def __str__(self):
> > + return "Cannot bring up TAP %s" % self.ifname
> > +
> > +
> > +class BRAddIfError(NetError):
> > + def __init__(self, ifname, brname, details):
> > + NetError.__init__(self, ifname, brname, details)
> > + self.ifname = ifname
> > + self.brname = brname
> > + self.details = details
> > +
> > + def __str__(self):
> > + return ("Can not add if %s to bridge %s: %s" %
> > + (self.ifname, self.brname, self.details))
> > +
> > +
> > +class HwAddrSetError(NetError):
> > + def __init__(self, ifname, mac):
> > + NetError.__init__(self, ifname, mac)
> > + self.ifname = ifname
> > + self.mac = mac
> > +
> > + def __str__(self):
> > + return "Can not set mac %s to interface %s" % (self.mac,
> > self.ifname)
> > +
> > +
> > +class HwAddrGetError(NetError):
> > + def __init__(self, ifname):
> > + NetError.__init__(self, ifname)
> > + self.ifname = ifname
> > +
> > + def __str__(self):
> > + return "Can not get mac of interface %s" % self.ifname
> > +
> > +
> > class Env(UserDict.IterableUserDict):
> > """
> > A dict-like object containing global objects used by tests.
> > @@ -2307,3 +2392,136 @@ def install_host_kernel(job, params):
> > else:
> > logging.info('Chose %s, using the current kernel for the host',
> > install_type)
> > +
> > +
> > +def bridge_auto_detect():
> > + """
> > + Automatically detect a bridge for tap through brctl.
> > + """
> > + try:
> > + brctl_output = utils.system_output("ip route list",
> > + retain_output=True)
> > + brname = re.findall("default.*dev (.*) ", brctl_output)[0]
> > + except:
> > + raise BRAutoDetectError
> > + return brname
> > +
> > +
> > +def if_nametoindex(ifname):
> > + """
> > + Map an interface name into its corresponding index.
> > + Returns 0 on error, as 0 is not a valid index
> > +
> > + @param ifname: interface name
> > + """
> > + index = 0
> > + ctrl_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
> > + ifr = struct.pack("16si", ifname, 0)
> > + r = fcntl.ioctl(ctrl_sock, SIOCGIFINDEX, ifr)
> > + index = struct.unpack("16si", r)[1]
> > + ctrl_sock.close()
> > + return index
> > +
> > +
> > +def vnet_hdr_probe(tapfd):
> > + """
> > + Check if the IFF_VNET_HDR is support by tun.
> > +
> > + @param tapfd: the file descriptor of /dev/net/tun
> > + """
> > + u = struct.pack("I", 0)
> > + r = fcntl.ioctl(tapfd, TUNGETFEATURES, u)
> > + flags = struct.unpack("I", r)[0]
> > + if flags & IFF_VNET_HDR:
> > + return True
> > + else:
> > + return False
>
> # ../../bin/autotest control --verbose --args="kill_vm=yes only=boot
> iterations=2"
>
> 05/23 13:24:41 INFO | test:0286| Test started. Number of iterations: 2
> 05/23 13:24:41 INFO | test:0289| Executing iteration 1 of 2
> _PASS_
>
> 05/23 13:25:36 INFO | test:0289| Executing iteration 2 of 2
> ...
> File "/project/rh/autotest-upstream/client/virt/virt_env_process.py", line
> 185, in process
> vm_func(test, vm_params, env, vm_name)
> File "/project/rh/autotest-upstream/client/virt/virt_env_process.py", line
> 82, in preprocess_vm
> migration_mode=params.get("migration_mode"))
> File "/project/rh/autotest-upstream/client/common_lib/error.py", line 138,
> in new_fn
> return fn(*args, **kwargs)
> File "/project/rh/autotest-upstream/client/virt/kvm_vm.py", line 643, in
> create
> tapfd = virt_utils.open_tap("/dev/net/tun", ifname)
> File "/project/rh/autotest-upstream/client/virt/virt_utils.py", line 2461,
> in open_tap
> raise TAPCreationError(ifname)
> TAPCreationError: Cannot create TAP device t0-081158-LeCM
>
>
> Tap device is not closed after iteration.1, iteration.2 fails of creating an
> existed tap device.
> So we need a 'close_tap()' function, and call it in vm.destroy()
Oh, OK, let's do this.
Thanks for having noticed that, Amos!
> > +def open_tap(devname, ifname, vnet_hdr=True):
> > + """
> > + Open a tap device and returns its file descriptor which is used by
> > + fd=<fd> parameter of qemu-kvm.
> > +
> > + @param ifname: TAP interface name
> > + @param vnet_hdr: Whether enable the vnet header
> > + """
> > + try:
> > + tapfd = os.open(devname, os.O_RDWR)
> > + except OSError:
> > + raise TAPModuleError(devname)
> > + flags = IFF_TAP | IFF_NO_PI
> > + if vnet_hdr and vnet_hdr_probe(tapfd):
> > + flags |= IFF_VNET_HDR
> > +
> > + ifr = struct.pack("16sh", ifname, flags)
> > + try:
> > + r = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
> > + except IOError:
> > + raise TAPCreationError(ifname)
> > + ifname = struct.unpack("16sh", r)[0].strip("\x00")
> > + return tapfd
> > +
> > +
> > +def add_to_bridge(ifname, brname):
> > + """
> > + Add a TAP device to bridge
> > +
> > + @param ifname: Name of TAP device
> > + @param brname: Name of the bridge
> > + """
> > + ctrl_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
> > + index = if_nametoindex(ifname)
> > + if index == 0:
> > + raise TAPNotExistError(ifname)
> > + ifr = struct.pack("16si", brname, index)
> > + try:
> > + r = fcntl.ioctl(ctrl_sock, SIOCBRADDIF, ifr)
> > + except IOError, details:
> > + raise BRAddIfError(ifname, brname, details)
> > + ctrl_sock.close()
> > +
> > +
> > +def bring_up_ifname(ifname):
> > + """
> > + Bring up an interface
> > +
> > + @param ifname: Name of the interface
> > + """
> > + ctrl_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
> > + ifr = struct.pack("16si", ifname, IFF_UP)
> > + try:
> > + fcntl.ioctl(ctrl_sock, SIOCSIFFLAGS, ifr)
> > + except IOError:
> > + raise TAPBringUpError(ifname)
> > + ctrl_sock.close()
> > +
> > +
> > +def if_set_macaddress(ifname, mac):
> > + """
> > + Set the mac address for an interface
> > +
> > + @param ifname: Name of the interface
> > + @mac: Mac address
> > + """
> > + ctrl_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
> > +
> > + ifr = struct.pack("256s", ifname)
> > + try:
> > + mac_dev = fcntl.ioctl(ctrl_sock, SIOCGIFHWADDR, ifr)[18:24]
> > + mac_dev = ":".join(["%02x" % ord(m) for m in mac_dev])
> > + except IOError, e:
> > + raise HwAddrGetError(ifname)
> > +
> > + if mac_dev.lower() == mac.lower():
> > + return
> > +
> > + ifr = struct.pack("16sH14s", ifname, 1,
> > + "".join([chr(int(m, 16)) for m in mac.split(":")]))
> > + try:
> > + fcntl.ioctl(ctrl_sock, SIOCSIFHWADDR, ifr)
> > + except IOError, e:
> > + logging.info(e)
> > + raise HwAddrSetError(ifname, mac)
> > + ctrl_sock.close()
> > +
> > --
> > 1.7.5.1
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe kvm" in
> > the body of a message to [email protected]
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html