From patchwork Tue Feb 10 21:28:52 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 6523 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n1ALVEug008977 for ; Tue, 10 Feb 2009 21:31:14 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754131AbZBJVbM (ORCPT ); Tue, 10 Feb 2009 16:31:12 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755537AbZBJVbM (ORCPT ); Tue, 10 Feb 2009 16:31:12 -0500 Received: from g5t0006.atlanta.hp.com ([15.192.0.43]:3632 "EHLO g5t0006.atlanta.hp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754131AbZBJVbK (ORCPT ); Tue, 10 Feb 2009 16:31:10 -0500 Received: from g4t0009.houston.hp.com (g4t0009.houston.hp.com [16.234.32.26]) by g5t0006.atlanta.hp.com (Postfix) with ESMTP id 3D646C548; Tue, 10 Feb 2009 21:31:10 +0000 (UTC) Received: from ldl.fc.hp.com (ldl.fc.hp.com [15.11.146.30]) by g4t0009.houston.hp.com (Postfix) with ESMTP id 0589EC0B8; Tue, 10 Feb 2009 21:31:10 +0000 (UTC) Received: from localhost (ldl.fc.hp.com [127.0.0.1]) by ldl.fc.hp.com (Postfix) with ESMTP id A2DF039C074; Tue, 10 Feb 2009 14:31:09 -0700 (MST) X-Virus-Scanned: Debian amavisd-new at ldl.fc.hp.com Received: from ldl.fc.hp.com ([127.0.0.1]) by localhost (ldl.fc.hp.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id OFrh0K+k459T; Tue, 10 Feb 2009 14:31:06 -0700 (MST) Received: from kvm.aw (lart.fc.hp.com [15.11.146.31]) by ldl.fc.hp.com (Postfix) with ESMTP id 8957639C06F; Tue, 10 Feb 2009 14:31:06 -0700 (MST) From: Alex Williamson Subject: [PATCH 2/4] qemu:net: Add TAP support for RX filtering on Linux To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, alex.williamson@hp.com Date: Tue, 10 Feb 2009 14:28:52 -0700 Message-ID: <20090210212852.9760.6710.stgit@kvm.aw> In-Reply-To: <20090210212841.9760.96780.stgit@kvm.aw> References: <20090210212841.9760.96780.stgit@kvm.aw> User-Agent: StGIT/0.14.2 MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org The Linux tap driver provides an ioctl to set a TX filter. Setting this restricts the packets received onto the vlan. We provide a hotplug callback to clear the filter when a new device gets added. The new rxfilter=off option can be used to disable exporting this feature to backend drivers. Signed-off-by: Alex Williamson --- net.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++------ qemu-doc.texi | 6 ++++-- vl.c | 3 ++- 3 files changed, 56 insertions(+), 9 deletions(-) -- 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 diff --git a/net.c b/net.c index e68cb40..973efea 100644 --- a/net.c +++ b/net.c @@ -724,6 +724,38 @@ static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, } #endif +#ifdef TUNSETTXFILTER +static int tap_rxfilter(void *opaque, unsigned int flags, int count, + uint8_t *list) +{ + TAPState *s = opaque; + struct tun_filter *filter; + int ret; + + if (flags & QEMU_NET_PROMISC) + count = 0; + + filter = qemu_mallocz(sizeof(*filter) + (count * ETH_ALEN)); + + memcpy(filter->addr, list, count * ETH_ALEN); + filter->count = count; + + if (flags & QEMU_NET_ALLMULTI) + filter->flags |= TUN_FLT_ALLMULTI; + + ret = ioctl(s->fd, TUNSETTXFILTER, filter); + + qemu_free(filter); + + return ret; +} + +static void tap_vlan_client_added(void *opaque) +{ + tap_rxfilter(opaque, 0, 0, NULL); +} +#endif + static void tap_receive(void *opaque, const uint8_t *buf, int size) { TAPState *s = opaque; @@ -762,7 +794,7 @@ static void tap_send(void *opaque) static TAPState *net_tap_fd_init(VLANState *vlan, const char *model, const char *name, - int fd) + int fd, int rxfilter) { TAPState *s; @@ -772,6 +804,12 @@ static TAPState *net_tap_fd_init(VLANState *vlan, #ifdef HAVE_IOVEC s->vc->fd_readv = tap_receive_iov; #endif +#ifdef TUNSETTXFILTER + if (rxfilter) { + s->vc->fd_rxfilter = tap_rxfilter; + s->vc->vlan_client_added = tap_vlan_client_added; + } +#endif qemu_set_fd_handler(s->fd, tap_send, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd); return s; @@ -1005,7 +1043,8 @@ static int launch_script(const char *setup_script, const char *ifname, int fd) static int net_tap_init(VLANState *vlan, const char *model, const char *name, const char *ifname1, - const char *setup_script, const char *down_script) + const char *setup_script, const char *down_script, + int rxfilter) { TAPState *s; int fd; @@ -1025,7 +1064,7 @@ static int net_tap_init(VLANState *vlan, const char *model, if (launch_script(setup_script, ifname, fd)) return -1; } - s = net_tap_fd_init(vlan, model, name, fd); + s = net_tap_fd_init(vlan, model, name, fd, rxfilter); if (!s) return -1; snprintf(s->vc->info_str, sizeof(s->vc->info_str), @@ -1663,13 +1702,18 @@ int net_client_init(const char *device, const char *p) if (!strcmp(device, "tap")) { char ifname[64]; char setup_script[1024], down_script[1024]; - int fd; + int fd, rxfilter = 1; vlan->nb_host_devs++; + + if (get_param_value(buf, sizeof(buf), "rxfilter", p) > 0) + if (!strcmp(buf, "off")) + rxfilter = 0; + if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { fd = strtol(buf, NULL, 0); fcntl(fd, F_SETFL, O_NONBLOCK); ret = -1; - if (net_tap_fd_init(vlan, device, name, fd)) + if (net_tap_fd_init(vlan, device, name, fd, rxfilter)) ret = 0; } else { if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { @@ -1681,7 +1725,7 @@ int net_client_init(const char *device, const char *p) if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) { pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT); } - ret = net_tap_init(vlan, device, name, ifname, setup_script, down_script); + ret = net_tap_init(vlan, device, name, ifname, setup_script, down_script, rxfilter); } } else #endif diff --git a/qemu-doc.texi b/qemu-doc.texi index efb88d2..9a3957c 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -643,7 +643,7 @@ Use the user mode network stack which requires no administrator privilege to run. @option{hostname=name} can be used to specify the client hostname reported by the builtin DHCP server. -@item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}] +@item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,rxfilter=on|off] Connect the host TAP network interface @var{name} to VLAN @var{n}, use the network script @var{file} to configure it and the network script @var{dfile} to deconfigure it. If @var{name} is not provided, the OS @@ -651,7 +651,9 @@ automatically provides one. @option{fd}=@var{h} can be used to specify the handle of an already opened host TAP interface. The default network configure script is @file{/etc/qemu-ifup} and the default network deconfigure script is @file{/etc/qemu-ifdown}. Use @option{script=no} -or @option{downscript=no} to disable script execution. Example: +or @option{downscript=no} to disable script execution. The rxfilter +(Linux-only) option enables or disables availability of the tap device +MAC filtering (default on). Example: @example qemu linux.img -net nic -net tap diff --git a/vl.c b/vl.c index aff2b2c..96ab696 100644 --- a/vl.c +++ b/vl.c @@ -3909,12 +3909,13 @@ static void help(int exitcode) "-net tap[,vlan=n][,name=str],ifname=name\n" " connect the host TAP network interface to VLAN 'n'\n" #else - "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile]\n" + "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,rxfilter=on|off]\n" " connect the host TAP network interface to VLAN 'n' and use the\n" " network scripts 'file' (default=%s)\n" " and 'dfile' (default=%s);\n" " use '[down]script=no' to disable script execution;\n" " use 'fd=h' to connect to an already opened TAP interface\n" + " rxfilter enables|disables use of the tap MAC filter (default on)\n" #endif "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n" " connect the vlan 'n' to another VLAN using a socket connection\n"