Re: [PATCH 2/5] KVM test: Add helpers to control the TAP/bridge

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <jasowang@xxxxxxxxxx>
> > Signed-off-by: Lucas Meneghel Rodrigues <lmr@xxxxxxxxxx>
> > ---
> >  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 majordomo@xxxxxxxxxxxxxxx
> > 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 majordomo@xxxxxxxxxxxxxxx
> 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux