All of lore.kernel.org
 help / color / mirror / Atom feed
From: Amos Kong <akong@redhat.com>
To: Lucas Meneghel Rodrigues <lmr@redhat.com>
Cc: autotest@test.kernel.org, kvm@vger.kernel.org,
	Jason Wang <jasowang@redhat.com>
Subject: Re: [PATCH 2/5] KVM test: Add helpers to control the TAP/bridge
Date: Mon, 23 May 2011 14:16:01 +0800	[thread overview]
Message-ID: <20110523061601.GA4445@t400> (raw)
In-Reply-To: <1305951810-5933-3-git-send-email-lmr@redhat.com>

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

# ../../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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2011-05-23  6:16 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 ` [PATCH 2/5] KVM test: Add helpers to control the TAP/bridge Lucas Meneghel Rodrigues
2011-05-23  6:16   ` Amos Kong [this message]
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
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=20110523061601.GA4445@t400 \
    --to=akong@redhat.com \
    --cc=autotest@test.kernel.org \
    --cc=jasowang@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=lmr@redhat.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.