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 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()

> +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


[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