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