public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Lucas Meneghel Rodrigues <lmr@redhat.com>
To: autotest@test.kernel.org
Cc: kvm@vger.kernel.org, Lucas Meneghel Rodrigues <lmr@redhat.com>,
	Jason Wang <jasowang@redhat.com>
Subject: [PATCH 2/5] KVM test: Add helpers to control the TAP/bridge
Date: Sat, 21 May 2011 01:23:27 -0300	[thread overview]
Message-ID: <1305951810-5933-3-git-send-email-lmr@redhat.com> (raw)
In-Reply-To: <1305951810-5933-1-git-send-email-lmr@redhat.com>

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@redhat.com>
Signed-off-by: Lucas Meneghel Rodrigues <lmr@redhat.com>
---
 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
+
+
+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


  parent reply	other threads:[~2011-05-21  4:23 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-21  4:23 [PATCH 0/5] Setup private bridge in KVM autotest, get rid of ifup scripts Lucas Meneghel Rodrigues
2011-05-21  4:23 ` [PATCH 1/5] KVM test: Adding framework code to control bridge creation Lucas Meneghel Rodrigues
2011-05-21  4:23 ` Lucas Meneghel Rodrigues [this message]
2011-05-23  6:16   ` [PATCH 2/5] KVM test: Add helpers to control the TAP/bridge Amos Kong
2011-05-23  7:16     ` Lucas Meneghel Rodrigues
2011-05-21  4:23 ` [PATCH 3/5] KVM test: virt_env_process: Setup private bridge during postprocessing Lucas Meneghel Rodrigues
2011-05-21  4:23 ` [PATCH 4/5] KVM test: setup tap fd and pass it to qemu-kvm Lucas Meneghel Rodrigues
2011-05-21  4:23 ` [PATCH 5/5] KVM test: Changing KVM autotest default to private bridge Lucas Meneghel Rodrigues
  -- strict thread matches above, loose matches on Subject: below --
2011-05-24  7:03 [PATCH 0/5] Setup private bridge in KVM autotest, get rid of ifup scripts Lucas Meneghel Rodrigues
2011-05-24  7:03 ` [PATCH 2/5] KVM test: Add helpers to control the TAP/bridge Lucas Meneghel Rodrigues
2011-06-02  4:23 [PATCH 0/5] Create private bridge, get rid of qemu ifup scripts v3 Lucas Meneghel Rodrigues
2011-06-02  4:23 ` [PATCH 2/5] KVM test: Add helpers to control the TAP/bridge Lucas Meneghel Rodrigues

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1305951810-5933-3-git-send-email-lmr@redhat.com \
    --to=lmr@redhat.com \
    --cc=autotest@test.kernel.org \
    --cc=jasowang@redhat.com \
    --cc=kvm@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox