From patchwork Mon Sep 9 12:51:42 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincenzo Maffione X-Patchwork-Id: 273552 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 1FF682C013B for ; Mon, 9 Sep 2013 20:52:16 +1000 (EST) Received: from localhost ([::1]:50357 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VIz4o-0003fg-13 for incoming@patchwork.ozlabs.org; Mon, 09 Sep 2013 06:52:14 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53375) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VIz4S-0003fY-Ko for qemu-devel@nongnu.org; Mon, 09 Sep 2013 06:51:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VIz4N-0007P1-2F for qemu-devel@nongnu.org; Mon, 09 Sep 2013 06:51:52 -0400 Received: from mail-ea0-x230.google.com ([2a00:1450:4013:c01::230]:36469) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VIz4M-0007Ox-Mf for qemu-devel@nongnu.org; Mon, 09 Sep 2013 06:51:46 -0400 Received: by mail-ea0-f176.google.com with SMTP id q16so3009724ead.7 for ; Mon, 09 Sep 2013 03:51:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=c7n2kkFMZX2VAWzDbC3owm6t1aZNk99DLlNN5HEU3H4=; b=N7gr3uWZO7IUODhe+WlrC+g93e1hxuR2FBXACOSLKZa4R++cZMLhMoPMbn/GuqiSoS ssYCHvnAJJ0OX6jJX7f5tptBGAEFlos8uNqRjQ3iESvPUdvLZ6I9MaTqYY5LpfZbW67x Wm1mCO9KS/qTyVB0SMC2gMGomzmhV+WR5jnXFZcILkwbJUXfED09ie/vqA+RBWkN5Apm 3mEDgsY5lxOYWKqRGoJ3KU7/VDXdct67ZP5LQbl3BABbypv12RXRMmYh44cMjxBsGCoV 0AeGlc0jyFi6lqV1Ot/YKiM0bVbwALaYgISb3bS0o20DlabmeoTwOJ/HKcib/RMPFihQ 1dZQ== X-Received: by 10.14.175.2 with SMTP id y2mr300420eel.83.1378723904986; Mon, 09 Sep 2013 03:51:44 -0700 (PDT) Received: from localhost.localdomain (prova.iet.unipi.it. [131.114.58.86]) by mx.google.com with ESMTPSA id h52sm21026074eez.3.1969.12.31.16.00.00 (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 09 Sep 2013 03:51:44 -0700 (PDT) From: Vincenzo Maffione To: qemu-devel@nongnu.org Date: Mon, 9 Sep 2013 14:51:42 +0200 Message-Id: <1378731102-4005-1-git-send-email-v.maffione@gmail.com> X-Mailer: git-send-email 1.8.4 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:4013:c01::230 Cc: anthony@codemonkey.ws, mst@redhat.com, jasowang@redhat.com, Vincenzo Maffione , stefanha@redhat.com, pbonzini@redhat.com Subject: [Qemu-devel] [PATCH] e1000: NetClientInfo.receive_iov implemented X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch implements the NetClientInfo.receive_iov method for the e1000 device emulation. In this way a network backend that uses qemu_sendv_packet() can deliver the fragmented packet without requiring an additional copy in the frontend/backend network code (nc_sendv_compat() function). The existing method NetClientInfo.receive has been reimplemented using the new method. Signed-off-by: Vincenzo Maffione --- hw/net/e1000.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 12 deletions(-) I propose this patch also because our research group (University of Pisa, Department of Computer Engineering) is working on the e1000 device (optimizations and paravirtual extensions) and we have patches to support the VALE switch as a network backend (see http://info.iet.unipi.it/~luigi/vale/). The VALE backend uses qemu_sendv_packet() to send fragmented packets: For this reason we think it could be interesting to better support these packets with e1000. diff --git a/hw/net/e1000.c b/hw/net/e1000.c index f5ebed4..70ab17f 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -32,6 +32,7 @@ #include "hw/loader.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" +#include "qemu/iov.h" #include "e1000_regs.h" @@ -64,6 +65,8 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); /* this is the size past which hardware will drop packets when setting LPE=1 */ #define MAXIMUM_ETHERNET_LPE_SIZE 16384 +#define MAXIMUM_ETHERNET_HDR_LEN (14+4) + /* * HW models: * E1000_DEV_ID_82540EM works with Windows and Linux @@ -825,7 +828,7 @@ static uint64_t rx_desc_base(E1000State *s) } static ssize_t -e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) +e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) { E1000State *s = qemu_get_nic_opaque(nc); PCIDevice *d = PCI_DEVICE(s); @@ -834,11 +837,14 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) unsigned int n, rdt; uint32_t rdh_start; uint16_t vlan_special = 0; - uint8_t vlan_status = 0, vlan_offset = 0; + uint8_t vlan_status = 0; uint8_t min_buf[MIN_BUF_SIZE]; size_t desc_offset; size_t desc_size; size_t total_size; + size_t size = iov_size(iov, iovcnt), iov_ofs = 0; + struct iovec iv; + uint8_t *filter_buf = iov->iov_base; if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) { return -1; @@ -850,10 +856,16 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) /* Pad to minimum Ethernet frame length */ if (size < sizeof(min_buf)) { - memcpy(min_buf, buf, size); + iov_to_buf(iov, iovcnt, 0, min_buf, size); memset(&min_buf[size], 0, sizeof(min_buf) - size); - buf = min_buf; - size = sizeof(min_buf); + iv.iov_base = filter_buf = min_buf; + iv.iov_len = size = sizeof(min_buf); + iovcnt = 1; + iov = &iv; + } else if (iov->iov_len < MAXIMUM_ETHERNET_HDR_LEN) { + /* This is very unlikely, but may happen. */ + iov_to_buf(iov, iovcnt, 0, min_buf, MAXIMUM_ETHERNET_HDR_LEN); + filter_buf = min_buf; } /* Discard oversized packets if !LPE and !SBP. */ @@ -864,14 +876,24 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) return size; } - if (!receive_filter(s, buf, size)) + if (!receive_filter(s, filter_buf, size)) { return size; + } - if (vlan_enabled(s) && is_vlan_packet(s, buf)) { - vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14))); - memmove((uint8_t *)buf + 4, buf, 12); + if (vlan_enabled(s) && is_vlan_packet(s, filter_buf)) { + vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(filter_buf + + 14))); + iov_ofs = 4; + if (filter_buf == iov->iov_base) { + memmove(filter_buf + 4, filter_buf, 12); + } else { + iov_from_buf(iov, iovcnt, 4, filter_buf, 12); + while (iov->iov_len <= iov_ofs) { + iov_ofs -= iov->iov_len; + iov++; + } + } vlan_status = E1000_RXD_STAT_VP; - vlan_offset = 4; size -= 4; } @@ -893,12 +915,24 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) desc.status |= (vlan_status | E1000_RXD_STAT_DD); if (desc.buffer_addr) { if (desc_offset < size) { + size_t iov_copy, copied = 0; + hwaddr ba = le64_to_cpu(desc.buffer_addr); size_t copy_size = size - desc_offset; if (copy_size > s->rxbuf_size) { copy_size = s->rxbuf_size; } - pci_dma_write(d, le64_to_cpu(desc.buffer_addr), - buf + desc_offset + vlan_offset, copy_size); + do { + iov_copy = MIN(copy_size, iov->iov_len - iov_ofs); + pci_dma_write(d, ba + copied, + iov->iov_base + iov_ofs, iov_copy); + copy_size -= iov_copy; + copied += iov_copy; + iov_ofs += iov_copy; + if (iov_ofs == iov->iov_len) { + iov++; + iov_ofs = 0; + } + } while (copy_size); } desc_offset += desc_size; desc.length = cpu_to_le16(desc_size); @@ -948,6 +982,17 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) return size; } +static ssize_t +e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) +{ + const struct iovec iov = { + .iov_base = (uint8_t *)buf, + .iov_len = size + }; + + return e1000_receive_iov(nc, &iov, 1); +} + static uint32_t mac_readreg(E1000State *s, int index) { @@ -1326,6 +1371,7 @@ static NetClientInfo net_e1000_info = { .size = sizeof(NICState), .can_receive = e1000_can_receive, .receive = e1000_receive, + .receive_iov = e1000_receive_iov, .cleanup = e1000_cleanup, .link_status_changed = e1000_set_link_status, };