From patchwork Mon May 23 08:04:13 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lucas Meneghel Rodrigues X-Patchwork-Id: 807862 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p4N84DZU031213 for ; Mon, 23 May 2011 08:04:14 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752450Ab1EWIEJ (ORCPT ); Mon, 23 May 2011 04:04:09 -0400 Received: from mx1.redhat.com ([209.132.183.28]:35175 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751485Ab1EWIEI (ORCPT ); Mon, 23 May 2011 04:04:08 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p4N8479g007650 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 23 May 2011 04:04:07 -0400 Received: from freedom.redhat.com (vpn-11-250.rdu.redhat.com [10.11.11.250]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p4N845TI004057; Mon, 23 May 2011 04:04:05 -0400 From: Lucas Meneghel Rodrigues To: autotest@test.kernel.org Cc: kvm@vger.kernel.org, Lucas Meneghel Rodrigues , Jason Wang Subject: [PATCH 4/5] KVM test: setup tap fd and pass it to qemu-kvm v2 Date: Mon, 23 May 2011 05:04:13 -0300 Message-Id: <1306137853-13782-1-git-send-email-lmr@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 23 May 2011 08:04:14 +0000 (UTC) We used to use qemu-ifup to manage the tap which have several limitations: 1) If we want to specify a bridge, we must create a customized qemu-ifup file as the default script always match the first bridge. 2) It's hard to add support for macvtap device. So this patch let kvm subtest control the tap creation and setup then pass it to qemu-kvm. User could specify the bridge he want to used in configuration file. The original autoconfiguration was changed by private bridge setup. Changes from v1: * Combine the private bridge config and TAP fd in one patchset, dropped the "auto" mode * Close TAP fds on VM.destroy() (thanks to Amos Kong for finding the problem) Signed-off-by: Jason Wang Signed-off-by: Lucas Meneghel Rodrigues --- client/tests/kvm/scripts/qemu-ifup | 11 ------ client/virt/kvm_vm.py | 60 ++++++++++++++++++++++++------------ client/virt/virt_utils.py | 11 ++++-- 3 files changed, 47 insertions(+), 35 deletions(-) delete mode 100755 client/tests/kvm/scripts/qemu-ifup diff --git a/client/tests/kvm/scripts/qemu-ifup b/client/tests/kvm/scripts/qemu-ifup deleted file mode 100755 index c4debf5..0000000 --- a/client/tests/kvm/scripts/qemu-ifup +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -# The following expression selects the first bridge listed by 'brctl show'. -# Modify it to suit your needs. -switch=$(/usr/sbin/brctl show | awk 'NR==2 { print $1 }') - -/bin/echo 1 > /proc/sys/net/ipv6/conf/${switch}/disable_ipv6 -/sbin/ifconfig $1 0.0.0.0 up -/usr/sbin/brctl addif ${switch} $1 -/usr/sbin/brctl setfd ${switch} 0 -/usr/sbin/brctl stp ${switch} off diff --git a/client/virt/kvm_vm.py b/client/virt/kvm_vm.py index 57fc61b..5b1a27b 100644 --- a/client/virt/kvm_vm.py +++ b/client/virt/kvm_vm.py @@ -7,7 +7,7 @@ Utility classes and functions to handle Virtual Machine creation using qemu. import time, os, logging, fcntl, re, commands, glob from autotest_lib.client.common_lib import error from autotest_lib.client.bin import utils -import virt_utils, virt_vm, kvm_monitor, aexpect +import virt_utils, virt_vm, virt_test_setup, kvm_monitor, aexpect class VM(virt_vm.BaseVM): @@ -41,6 +41,7 @@ class VM(virt_vm.BaseVM): self.pci_assignable = None self.netdev_id = [] self.device_id = [] + self.tapfds = [] self.uuid = None @@ -231,19 +232,17 @@ class VM(virt_vm.BaseVM): cmd += ",id='%s'" % device_id return cmd - def add_net(help, vlan, mode, ifname=None, script=None, - downscript=None, tftp=None, bootfile=None, hostfwd=[], - netdev_id=None, netdev_extra_params=None): + def add_net(help, vlan, mode, ifname=None, tftp=None, bootfile=None, + hostfwd=[], netdev_id=None, netdev_extra_params=None, + tapfd=None): if has_option(help, "netdev"): cmd = " -netdev %s,id=%s" % (mode, netdev_id) if netdev_extra_params: cmd += ",%s" % netdev_extra_params else: cmd = " -net %s,vlan=%d" % (mode, vlan) - if mode == "tap": - if ifname: cmd += ",ifname='%s'" % ifname - if script: cmd += ",script='%s'" % script - cmd += ",downscript='%s'" % (downscript or "no") + if mode == "tap" and tapfd: + cmd += ",fd=%d" % tapfd elif mode == "user": if tftp and "[,tftp=" in help: cmd += ",tftp='%s'" % tftp @@ -413,20 +412,22 @@ class VM(virt_vm.BaseVM): qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac, device_id, netdev_id, nic_params.get("nic_extra_params")) # Handle the '-net tap' or '-net user' or '-netdev' part - script = nic_params.get("nic_script") - downscript = nic_params.get("nic_downscript") tftp = nic_params.get("tftp") - if script: - script = virt_utils.get_path(root_dir, script) - if downscript: - downscript = virt_utils.get_path(root_dir, downscript) if tftp: tftp = virt_utils.get_path(root_dir, tftp) - qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"), - vm.get_ifname(vlan), - script, downscript, tftp, + if nic_params.get("nic_mode") == "tap": + try: + tapfd = vm.tapfds[vlan] + except IndexError: + tapfd = None + else: + tapfd = None + qemu_cmd += add_net(help, vlan, + nic_params.get("nic_mode", "user"), + vm.get_ifname(vlan), tftp, nic_params.get("bootp"), redirs, netdev_id, - nic_params.get("netdev_extra_params")) + nic_params.get("netdev_extra_params"), + tapfd) # Proceed to next NIC vlan += 1 @@ -549,6 +550,10 @@ class VM(virt_vm.BaseVM): @raise VMBadPATypeError: If an unsupported PCI assignment type is requested @raise VMPAError: If no PCI assignable devices could be assigned + @raise TAPCreationError: If fail to create tap fd + @raise BRAddIfError: If fail to add a tap to a bridge + @raise TAPBringUpError: If fail to bring up a tap + @raise PrivateBridgeError: If fail to bring the private bridge """ error.context("creating '%s'" % self.name) self.destroy(free_mac_addresses=False) @@ -612,12 +617,24 @@ class VM(virt_vm.BaseVM): guest_port = int(redir_params.get("guest_port")) self.redirs[guest_port] = host_ports[i] - # Generate netdev/device IDs for all NICs + # Generate netdev IDs for all NICs and create TAP fd self.netdev_id = [] - self.device_id = [] + self.tapfds = [] + vlan = 0 for nic in params.objects("nics"): self.netdev_id.append(virt_utils.generate_random_id()) self.device_id.append(virt_utils.generate_random_id()) + nic_params = params.object_params(nic) + if nic_params.get("nic_mode") == "tap": + ifname = self.get_ifname(vlan) + brname = nic_params.get("bridge") + if brname == "private": + brname = virt_test_setup.PrivateBridgeConfig().brname + tapfd = virt_utils.open_tap("/dev/net/tun", ifname) + virt_utils.add_to_bridge(ifname, brname) + virt_utils.bring_up_ifname(ifname) + self.tapfds.append(tapfd) + vlan += 1 # Find available VNC port, if needed if params.get("display") == "vnc": @@ -856,6 +873,9 @@ class VM(virt_vm.BaseVM): num_nics = len(self.params.objects("nics")) for vlan in range(num_nics): self.free_mac_address(vlan) + if self.tapfds: + for tapfd in self.tapfds: + os.close(tapfd) @property diff --git a/client/virt/virt_utils.py b/client/virt/virt_utils.py index 96b9c84..a1c9df2 100644 --- a/client/virt/virt_utils.py +++ b/client/virt/virt_utils.py @@ -56,12 +56,15 @@ class NetError(Exception): class TAPModuleError(NetError): - def __init__(self, devname): + def __init__(self, devname, action="open", details=None): NetError.__init__(self, devname) self.devname = devname def __str__(self): - return "Can't open %s" % self.devname + e_msg = "Can't %s %s" % (self.action, self.devname) + if self.details is not None: + e_msg += " : %s" % details + class TAPNotExistError(NetError): def __init__(self, ifname): @@ -2448,8 +2451,8 @@ def open_tap(devname, ifname, vnet_hdr=True): """ try: tapfd = os.open(devname, os.O_RDWR) - except OSError: - raise TAPModuleError(devname) + 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