@@ -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,80 @@ 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, details=None):
+ NetError.__init__(self, ifname, details)
+ self.ifname = ifname
+ self.details = details
+
+ def __str__(self):
+ e_msg = "Cannot create TAP device %s" % self.ifname
+ if self.details is not None:
+ e_msg += ": %s" % self.details
+ return e_msg
+
+
+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 +2396,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
+
+
+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, e:
+ raise TAPModuleError(devname, "open", e)
+ 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, details:
+ raise TAPCreationError(ifname, details)
+ 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()
+