From patchwork Wed Feb 11 17:11:35 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 6700 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 n1BHEEv7015835 for ; Wed, 11 Feb 2009 17:14:14 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758009AbZBKRNv (ORCPT ); Wed, 11 Feb 2009 12:13:51 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1758003AbZBKRNv (ORCPT ); Wed, 11 Feb 2009 12:13:51 -0500 Received: from g4t0014.houston.hp.com ([15.201.24.17]:17754 "EHLO g4t0014.houston.hp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758002AbZBKRNt (ORCPT ); Wed, 11 Feb 2009 12:13:49 -0500 Received: from g5t0029.atlanta.hp.com (g5t0029.atlanta.hp.com [16.228.8.141]) by g4t0014.houston.hp.com (Postfix) with ESMTP id D1624247AB; Wed, 11 Feb 2009 17:13:48 +0000 (UTC) Received: from ldl.fc.hp.com (ldl.fc.hp.com [15.11.146.30]) by g5t0029.atlanta.hp.com (Postfix) with ESMTP id 7B74E100BB; Wed, 11 Feb 2009 17:13:48 +0000 (UTC) Received: from localhost (ldl.fc.hp.com [127.0.0.1]) by ldl.fc.hp.com (Postfix) with ESMTP id 1679939C007; Wed, 11 Feb 2009 10:13:48 -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 TeLb+bT-pP-Z; Wed, 11 Feb 2009 10:13:46 -0700 (MST) Received: from kvm.aw (lart.fc.hp.com [15.11.146.31]) by ldl.fc.hp.com (Postfix) with ESMTP id 7EA9839C003; Wed, 11 Feb 2009 10:13:46 -0700 (MST) From: Alex Williamson Subject: [PATCH 4/4] qemu:e1000: Add support for qemu_vlan_rxfilter To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, alex.williamson@hp.com Date: Wed, 11 Feb 2009 10:11:35 -0700 Message-ID: <20090211170957.13756.38106.stgit@kvm.aw> In-Reply-To: <20090210212902.9760.6747.stgit@kvm.aw> References: <20090210212902.9760.6747.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 --- Updated to address e1000 multicast hash table. hw/e1000.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 79 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/e1000.c b/hw/e1000.c index 6f841d6..e3e5fa5 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -85,6 +85,7 @@ typedef struct E1000State_st { uint32_t rxbuf_size; uint32_t rxbuf_min_shift; int check_rxov; + int vlan_rxfilter; struct e1000_tx { unsigned char header[256]; unsigned char vlan_header[4]; @@ -143,6 +144,66 @@ static const char phy_regcap[0x20] = { [PHY_ID2] = PHY_R, [M88E1000_PHY_SPEC_STATUS] = PHY_R }; +static void e1000_set_vlan_rxfilter(E1000State *s) +{ + static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + uint32_t rctl = s->mac_reg[RCTL], ra[2], *rp; + uint8_t *buf; + int i, flags = 0; + + /* + * If the guest has encoded anything in the multicast hash table, + * we're stuck doing the filtering ourselves. This should only + * happen if the guest has already consumed the RAR table. + */ + for (i = 0; i < 128; i++) { + if (s->mac_reg[MTA + i]) { + qemu_vlan_rxfilter(s->vc, QEMU_NET_PROMISC, 0, NULL); + s->vlan_rxfilter = 0; + return; + } + } + + if (rctl & E1000_RCTL_UPE) + flags |= QEMU_NET_PROMISC; + if (rctl & E1000_RCTL_MPE) + flags |= QEMU_NET_ALLMULTI; + + /* Allocate for maximum size, 16 + bcast */ + buf = qemu_mallocz(17 * 6); + + for (i = 0, rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) { + if (!(rp[1] & E1000_RAH_AV)) + continue; + ra[0] = cpu_to_le32(rp[0]); + ra[1] = cpu_to_le32(rp[1]); + memcpy(&buf[i * 6], (uint8_t *)ra, 6); + i++; + } + + if (rctl & E1000_RCTL_BAM) { + memcpy(&buf[i * 6], bcast, 6); + i++; + } + + s->vlan_rxfilter = qemu_vlan_rxfilter(s->vc, flags, i, buf); + qemu_free(buf); +} + +static void e1000_vlan_client_added(void *opaque) +{ + E1000State *s = opaque; + + s->vlan_rxfilter = 0; +} + +static void e1000_vlan_client_removed(void *opaque) +{ + E1000State *s = opaque; + + e1000_set_vlan_rxfilter(s); +} + static void ioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) @@ -198,6 +259,7 @@ set_rx_control(E1000State *s, int index, uint32_t val) s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], s->mac_reg[RCTL]); + e1000_set_vlan_rxfilter(s); } static void @@ -532,6 +594,9 @@ receive_filter(E1000State *s, const uint8_t *buf, int size) return 0; } + if (s->vlan_rxfilter) + return 1; + if (rctl & E1000_RCTL_UPE) // promiscuous return 1; @@ -715,6 +780,13 @@ mac_writereg(E1000State *s, int index, uint32_t val) } static void +mac_writereg_rx(E1000State *s, int index, uint32_t val) +{ + s->mac_reg[index] = val; + e1000_set_vlan_rxfilter(s); +} + +static void set_rdt(E1000State *s, int index, uint32_t val) { s->check_rxov = 0; @@ -790,8 +862,8 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = { [TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt, [IMC] = set_imc, [IMS] = set_ims, [ICR] = set_icr, [EECD] = set_eecd, [RCTL] = set_rx_control, - [RA ... RA+31] = &mac_writereg, - [MTA ... MTA+127] = &mac_writereg, + [RA ... RA+31] = &mac_writereg_rx, + [MTA ... MTA+127] = &mac_writereg_rx, [VFTA ... VFTA+127] = &mac_writereg, }; enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) }; @@ -964,6 +1036,9 @@ nic_load(QEMUFile *f, void *opaque, int version_id) for (j = 0; j < mac_regarraystosave[i].size; j++) qemu_get_be32s(f, s->mac_reg + mac_regarraystosave[i].array0 + j); + + e1000_set_vlan_rxfilter(s); + return 0; } @@ -1088,6 +1163,8 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn) d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, e1000_receive, e1000_can_receive, d); d->vc->link_status_changed = e1000_set_link_status; + d->vc->vlan_client_added = e1000_vlan_client_added; + d->vc->vlan_client_removed = e1000_vlan_client_removed; qemu_format_nic_info_str(d->vc, d->nd->macaddr);