From patchwork Tue Feb 10 21:28:57 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 6524 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 n1ALVIj4008987 for ; Tue, 10 Feb 2009 21:31:19 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753547AbZBJVbR (ORCPT ); Tue, 10 Feb 2009 16:31:17 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755563AbZBJVbR (ORCPT ); Tue, 10 Feb 2009 16:31:17 -0500 Received: from g1t0028.austin.hp.com ([15.216.28.35]:14408 "EHLO g1t0028.austin.hp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755537AbZBJVbQ (ORCPT ); Tue, 10 Feb 2009 16:31:16 -0500 Received: from g5t0030.atlanta.hp.com (g5t0030.atlanta.hp.com [16.228.8.142]) by g1t0028.austin.hp.com (Postfix) with ESMTP id AA0D91C358; Tue, 10 Feb 2009 21:31:15 +0000 (UTC) Received: from ldl.fc.hp.com (ldl.fc.hp.com [15.11.146.30]) by g5t0030.atlanta.hp.com (Postfix) with ESMTP id 4153624087; Tue, 10 Feb 2009 21:31:15 +0000 (UTC) Received: from localhost (ldl.fc.hp.com [127.0.0.1]) by ldl.fc.hp.com (Postfix) with ESMTP id D861939C06E; Tue, 10 Feb 2009 14:31:14 -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 T61s0c7Vcb7E; Tue, 10 Feb 2009 14:31:12 -0700 (MST) Received: from kvm.aw (lart.fc.hp.com [15.11.146.31]) by ldl.fc.hp.com (Postfix) with ESMTP id B2DC339C00E; Tue, 10 Feb 2009 14:31:11 -0700 (MST) From: Alex Williamson Subject: [PATCH 3/4] qemu:virtio-net: Add support for qemu_vlan_rxfilter To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, alex.williamson@hp.com Date: Tue, 10 Feb 2009 14:28:57 -0700 Message-ID: <20090210212857.9760.31288.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 Make use of qemu_vlan_rxfilter so that we can filter at a lower level. We implement callbacks for devices being added and removed so that we can fall back to our own filtering or make another attempt to push filtering off to someone else. Signed-off-by: Alex Williamson --- hw/virtio-net.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 54 insertions(+), 2 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/hw/virtio-net.c b/hw/virtio-net.c index 62153e9..3e4f526 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -35,6 +35,7 @@ typedef struct VirtIONet int mergeable_rx_bufs; int promisc; int allmulti; + int vlan_rxfilter; struct { int in_use; uint8_t *macs; @@ -51,6 +52,43 @@ static VirtIONet *to_virtio_net(VirtIODevice *vdev) return (VirtIONet *)vdev; } +static void virtio_net_set_vlan_rxfilter(VirtIONet *n) +{ + static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + uint8_t *buf; + int flags = 0; + + if (n->promisc) + flags |= QEMU_NET_PROMISC; + if (n->allmulti) + flags |= QEMU_NET_ALLMULTI; + + buf = qemu_mallocz((n->mac_table.in_use + 2) * ETH_ALEN); + + memcpy(&buf[ETH_ALEN*0], n->mac, ETH_ALEN); + memcpy(&buf[ETH_ALEN*1], n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); + /* broadcast is a multicast addr, so add it at the end */ + memcpy(&buf[ETH_ALEN*(n->mac_table.in_use + 1)], bcast, ETH_ALEN); + + n->vlan_rxfilter = qemu_vlan_rxfilter(n->vc, flags, + n->mac_table.in_use + 2, buf); + qemu_free(buf); +} + +static void virtio_net_vlan_client_added(void *opaque) +{ + VirtIONet *n = opaque; + + n->vlan_rxfilter = 0; +} + +static void virtio_net_vlan_client_removed(void *opaque) +{ + VirtIONet *n = opaque; + + virtio_net_set_vlan_rxfilter(n); +} + static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) { VirtIONet *n = to_virtio_net(vdev); @@ -70,6 +108,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) if (memcmp(netcfg.mac, n->mac, ETH_ALEN)) { memcpy(n->mac, netcfg.mac, ETH_ALEN); + virtio_net_set_vlan_rxfilter(n); qemu_format_nic_info_str(n->vc, n->mac); } } @@ -99,6 +138,7 @@ static void virtio_net_reset(VirtIODevice *vdev) /* Flush any MAC and VLAN filter table state */ n->mac_table.in_use = 0; memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); + virtio_net_set_vlan_rxfilter(n); memset(n->vlans, 0, MAX_VLAN >> 3); } @@ -247,6 +287,10 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) virtqueue_push(vq, &elem, sizeof(status)); virtio_notify(vdev, vq); + + if (ctrl.class == VIRTIO_NET_CTRL_RX_MODE || + ctrl.class == VIRTIO_NET_CTRL_MAC) + virtio_net_set_vlan_rxfilter(n); } } @@ -334,15 +378,19 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) return 0; } - if ((ptr[0] & 1) && n->allmulti) + /* If hw filtering is complete, no need to continue */ + if (n->vlan_rxfilter) return 1; - if (!memcmp(ptr, bcast, sizeof(bcast))) + if ((ptr[0] & 1) && n->allmulti) return 1; if (!memcmp(ptr, n->mac, ETH_ALEN)) return 1; + if (!memcmp(ptr, bcast, sizeof(bcast))) + return 1; + for (i = 0; i < n->mac_table.in_use; i++) { if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) return 1; @@ -552,6 +600,8 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) if (version_id >= 6) qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); + virtio_net_set_vlan_rxfilter(n); + if (n->tx_timer_active) { qemu_mod_timer(n->tx_timer, qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL); @@ -589,6 +639,8 @@ void virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) n->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, virtio_net_receive, virtio_net_can_receive, n); n->vc->link_status_changed = virtio_net_set_link_status; + n->vc->vlan_client_added = virtio_net_vlan_client_added; + n->vc->vlan_client_removed = virtio_net_vlan_client_removed; qemu_format_nic_info_str(n->vc, n->mac);