From patchwork Tue Jan 12 17:21:28 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Greg Kurz X-Patchwork-Id: 566631 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)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 6148014031E for ; Wed, 13 Jan 2016 04:22:06 +1100 (AEDT) Received: from localhost ([::1]:33344 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aJ2dw-0000b1-6o for incoming@patchwork.ozlabs.org; Tue, 12 Jan 2016 12:22:04 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44054) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aJ2dU-0008LZ-JZ for qemu-devel@nongnu.org; Tue, 12 Jan 2016 12:21:39 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aJ2dR-0003zj-BT for qemu-devel@nongnu.org; Tue, 12 Jan 2016 12:21:36 -0500 Received: from e06smtp07.uk.ibm.com ([195.75.94.103]:56683) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aJ2dR-0003zR-2I for qemu-devel@nongnu.org; Tue, 12 Jan 2016 12:21:33 -0500 Received: from localhost by e06smtp07.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 12 Jan 2016 17:21:32 -0000 Received: from d06dlp01.portsmouth.uk.ibm.com (9.149.20.13) by e06smtp07.uk.ibm.com (192.168.101.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 12 Jan 2016 17:21:29 -0000 X-IBM-Helo: d06dlp01.portsmouth.uk.ibm.com X-IBM-MailFrom: gkurz@linux.vnet.ibm.com X-IBM-RcptTo: qemu-devel@nongnu.org Received: from b06cxnps3074.portsmouth.uk.ibm.com (d06relay09.portsmouth.uk.ibm.com [9.149.109.194]) by d06dlp01.portsmouth.uk.ibm.com (Postfix) with ESMTP id 83F6517D805A for ; Tue, 12 Jan 2016 17:21:30 +0000 (GMT) Received: from d06av08.portsmouth.uk.ibm.com (d06av08.portsmouth.uk.ibm.com [9.149.37.249]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u0CHLS685177806 for ; Tue, 12 Jan 2016 17:21:28 GMT Received: from d06av08.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av08.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id u0CHLSjG024526 for ; Tue, 12 Jan 2016 10:21:28 -0700 Received: from smtp.lab.toulouse-stg.fr.ibm.com (srv01.lab.toulouse-stg.fr.ibm.com [9.101.4.1]) by d06av08.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id u0CHLS2V024509; Tue, 12 Jan 2016 10:21:28 -0700 Received: from bahia.lab.toulouse-stg.fr.ibm.com (bahia.lab.toulouse-stg.fr.ibm.com [9.101.4.41]) by smtp.lab.toulouse-stg.fr.ibm.com (Postfix) with ESMTP id 0C9A022011B; Tue, 12 Jan 2016 18:21:28 +0100 (CET) From: Greg Kurz To: "Michael S. Tsirkin" Date: Tue, 12 Jan 2016 18:21:28 +0100 Message-ID: <20160112172110.21438.47514.stgit@bahia.lab.toulouse-stg.fr.ibm.com> In-Reply-To: <20160112170912.21438.67163.stgit@bahia.lab.toulouse-stg.fr.ibm.com> References: <20160112170912.21438.67163.stgit@bahia.lab.toulouse-stg.fr.ibm.com> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16011217-0029-0000-0000-0000056EA0A3 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 195.75.94.103 Cc: qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH v3 1/6] virtio-net: use the backend cross-endian capabilities 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 When running a fully emulated device in cross-endian conditions, including a virtio 1.0 device offered to a big endian guest, we need to fix the vnet headers. This is currently handled by the virtio_net_hdr_swap() function in the core virtio-net code but it should actually be handled by the net backend. With this patch, virtio-net now tries to configure the backend to do the endian fixing when the device starts (i.e. drivers sets the CONFIG_OK bit). If the backend cannot support the requested endiannes, we have to fallback onto virtio_net_hdr_swap(): this is recorded in the needs_vnet_hdr_swap flag, to be used in the TX and RX paths. Note that we reset the backend to the default behaviour (guest native endianness) when the device stops (i.e. device status had CONFIG_OK bit and driver unsets it). This is needed, with the linux tap backend at least, otherwise the guest may lose network connectivity if rebooted into a different endianness. The current vhost-net code also tries to configure net backends. This will be no more needed and will be reverted in a subsequent patch. Reviewed-by: Cornelia Huck Reviewed-by: Laurent Vivier Signed-off-by: Greg Kurz --- hw/net/virtio-net.c | 49 +++++++++++++++++++++++++++++++++++-- include/hw/virtio/virtio-access.h | 9 ------- include/hw/virtio/virtio-net.h | 1 + 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index a877614e3e7a..7aaf0b89981b 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -128,6 +128,13 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) if (!n->vhost_started) { int r, i; + if (n->needs_vnet_hdr_swap) { + error_report("backend does not support %s vnet headers; " + "falling back on userspace virtio", + virtio_is_big_endian(vdev) ? "BE" : "LE"); + return; + } + /* Any packets outstanding? Purge them to avoid touching rings * when vhost is running. */ @@ -152,6 +159,40 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) } } +static void virtio_net_vnet_status(VirtIONet *n, uint8_t status) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(n); + NetClientState *peer = qemu_get_queue(n->nic)->peer; + + if (virtio_net_started(n, status)) { + int r; + + /* Before using the device, we tell the network backend about the + * endianness to use when parsing vnet headers. If the backend can't + * do it, we fallback onto fixing the headers in the core virtio-net + * code. + */ + if (virtio_is_big_endian(vdev)) { + r = qemu_set_vnet_be(peer, true); + } else { + r = qemu_set_vnet_le(peer, true); + } + + n->needs_vnet_hdr_swap = !!r; + } else if (virtio_net_started(n, vdev->status)) { + /* After using the device, we need to reset the network backend to + * the default (guest native endianness), otherwise the guest may + * lose network connectivity if it is rebooted into a different + * endianness. + */ + if (virtio_is_big_endian(vdev)) { + qemu_set_vnet_be(peer, false); + } else { + qemu_set_vnet_le(peer, false); + } + } +} + static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) { VirtIONet *n = VIRTIO_NET(vdev); @@ -159,6 +200,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) int i; uint8_t queue_status; + virtio_net_vnet_status(n, status); virtio_net_vhost_status(n, status); for (i = 0; i < n->max_queues; i++) { @@ -957,7 +999,10 @@ static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt, void *wbuf = (void *)buf; work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, size - n->host_hdr_len); - virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf); + + if (n->needs_vnet_hdr_swap) { + virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf); + } iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr)); } else { struct virtio_net_hdr hdr = { @@ -1167,7 +1212,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) error_report("virtio-net header incorrect"); exit(1); } - if (virtio_needs_swap(vdev)) { + if (n->needs_vnet_hdr_swap) { virtio_net_hdr_swap(vdev, (void *) &mhdr); sg2[0].iov_base = &mhdr; sg2[0].iov_len = n->guest_hdr_len; diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h index 8aec843c8ff3..a01fff2e51d7 100644 --- a/include/hw/virtio/virtio-access.h +++ b/include/hw/virtio/virtio-access.h @@ -143,15 +143,6 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr) } } -static inline bool virtio_needs_swap(VirtIODevice *vdev) -{ -#ifdef HOST_WORDS_BIGENDIAN - return virtio_access_is_big_endian(vdev) ? false : true; -#else - return virtio_access_is_big_endian(vdev) ? true : false; -#endif -} - static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s) { #ifdef HOST_WORDS_BIGENDIAN diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index f3cc25feca2b..27bc868fbc7d 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -94,6 +94,7 @@ typedef struct VirtIONet { uint64_t curr_guest_offloads; QEMUTimer *announce_timer; int announce_counter; + bool needs_vnet_hdr_swap; } VirtIONet; void virtio_net_set_netclient_name(VirtIONet *n, const char *name,