From nobody Mon Feb 9 04:44:24 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1486139254364111.60109965569552; Fri, 3 Feb 2017 08:27:34 -0800 (PST) Received: from localhost ([::1]:35631 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cZghv-0007th-R3 for importer@patchew.org; Fri, 03 Feb 2017 11:27:31 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41883) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cZgO5-0007T4-5Z for qemu-devel@nongnu.org; Fri, 03 Feb 2017 11:07:02 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cZgO3-0007Sn-7n for qemu-devel@nongnu.org; Fri, 03 Feb 2017 11:07:01 -0500 Received: from mx1.redhat.com ([209.132.183.28]:49128) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cZgO2-0007SQ-Vk for qemu-devel@nongnu.org; Fri, 03 Feb 2017 11:06:59 -0500 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 280B23B731 for ; Fri, 3 Feb 2017 16:06:59 +0000 (UTC) Received: from dgilbert-t530.redhat.com (ovpn-117-144.ams2.redhat.com [10.36.117.144]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v13G6r0p014461; Fri, 3 Feb 2017 11:06:58 -0500 From: "Dr. David Alan Gilbert (git)" To: qemu-devel@nongnu.org, mst@redhat.com, quintela@redhat.com Date: Fri, 3 Feb 2017 16:06:51 +0000 Message-Id: <20170203160651.19917-5-dgilbert@redhat.com> In-Reply-To: <20170203160651.19917-1-dgilbert@redhat.com> References: <20170203160651.19917-1-dgilbert@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Fri, 03 Feb 2017 16:06:59 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 4/4] virtio/migration: Migrate virtio-net to VMState X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: "Dr. David Alan Gilbert" Signed-off-by: Dr. David Alan Gilbert --- hw/net/virtio-net.c | 316 +++++++++++++++++++++++++++----------= ---- include/hw/virtio/virtio-net.h | 4 +- 2 files changed, 213 insertions(+), 107 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 7b3ad4a..41723a4 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1557,119 +1557,22 @@ static void virtio_net_set_multiqueue(VirtIONet *n= , int multiqueue) virtio_net_set_queues(n); } =20 -static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f) +static int virtio_net_post_load_device(void *opaque, int version_id) { - VirtIONet *n =3D VIRTIO_NET(vdev); - int i; - - qemu_put_buffer(f, n->mac, ETH_ALEN); - qemu_put_be32(f, n->vqs[0].tx_waiting); - qemu_put_be32(f, n->mergeable_rx_bufs); - qemu_put_be16(f, n->status); - qemu_put_byte(f, n->promisc); - qemu_put_byte(f, n->allmulti); - qemu_put_be32(f, n->mac_table.in_use); - qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); - qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); - qemu_put_be32(f, n->has_vnet_hdr); - qemu_put_byte(f, n->mac_table.multi_overflow); - qemu_put_byte(f, n->mac_table.uni_overflow); - qemu_put_byte(f, n->alluni); - qemu_put_byte(f, n->nomulti); - qemu_put_byte(f, n->nouni); - qemu_put_byte(f, n->nobcast); - qemu_put_byte(f, n->has_ufo); - if (n->max_queues > 1) { - qemu_put_be16(f, n->max_queues); - qemu_put_be16(f, n->curr_queues); - for (i =3D 1; i < n->curr_queues; i++) { - qemu_put_be32(f, n->vqs[i].tx_waiting); - } - } - - if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { - qemu_put_be64(f, n->curr_guest_offloads); - } -} - -static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, - int version_id) -{ - VirtIONet *n =3D VIRTIO_NET(vdev); + VirtIONet *n =3D opaque; + VirtIODevice *vdev =3D VIRTIO_DEVICE(n); int i, link_down; =20 - qemu_get_buffer(f, n->mac, ETH_ALEN); - n->vqs[0].tx_waiting =3D qemu_get_be32(f); - - virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f), + virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs, virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)= ); =20 - n->status =3D qemu_get_be16(f); - - n->promisc =3D qemu_get_byte(f); - n->allmulti =3D qemu_get_byte(f); - - n->mac_table.in_use =3D qemu_get_be32(f); /* MAC_TABLE_ENTRIES may be different from the saved image */ - if (n->mac_table.in_use <=3D MAC_TABLE_ENTRIES) { - qemu_get_buffer(f, n->mac_table.macs, - n->mac_table.in_use * ETH_ALEN); - } else { - int64_t i; - - /* Overflow detected - can happen if source has a larger MAC table. - * We simply set overflow flag so there's no need to maintain the - * table of addresses, discard them all. - * Note: 64 bit math to avoid integer overflow. - */ - for (i =3D 0; i < (int64_t)n->mac_table.in_use * ETH_ALEN; ++i) { - qemu_get_byte(f); - } - n->mac_table.multi_overflow =3D n->mac_table.uni_overflow =3D 1; + if (n->mac_table.in_use > MAC_TABLE_ENTRIES) { n->mac_table.in_use =3D 0; } -=20 - qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); - - if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) { - error_report("virtio-net: saved image requires vnet_hdr=3Don"); - return -1; - } - - n->mac_table.multi_overflow =3D qemu_get_byte(f); - n->mac_table.uni_overflow =3D qemu_get_byte(f); - - n->alluni =3D qemu_get_byte(f); - n->nomulti =3D qemu_get_byte(f); - n->nouni =3D qemu_get_byte(f); - n->nobcast =3D qemu_get_byte(f); - - if (qemu_get_byte(f) && !peer_has_ufo(n)) { - error_report("virtio-net: saved image requires TUN_F_UFO support"); - return -1; - } =20 - if (n->max_queues > 1) { - if (n->max_queues !=3D qemu_get_be16(f)) { - error_report("virtio-net: different max_queues "); - return -1; - } - - n->curr_queues =3D qemu_get_be16(f); - if (n->curr_queues > n->max_queues) { - error_report("virtio-net: curr_queues %x > max_queues %x", - n->curr_queues, n->max_queues); - return -1; - } - for (i =3D 1; i < n->curr_queues; i++) { - n->vqs[i].tx_waiting =3D qemu_get_be32(f); - } - } - - if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { - n->curr_guest_offloads =3D qemu_get_be64(f); - } else { + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { n->curr_guest_offloads =3D virtio_net_supported_guest_offloads(n); } =20 @@ -1703,6 +1606,210 @@ static int virtio_net_load_device(VirtIODevice *vde= v, QEMUFile *f, return 0; } =20 +/* tx_waiting field of a VirtIONetQueue */ +static const VMStateDescription vmstate_virtio_net_queue_tx_waiting =3D { + .name =3D "virtio-net-queue-tx_waiting", + .fields =3D (VMStateField[]) { + VMSTATE_UINT32(tx_waiting, VirtIONetQueue), + VMSTATE_END_OF_LIST() + }, +}; + +static bool max_queues_gt_1(void *opaque, int version_id) +{ + return VIRTIO_NET(opaque)->max_queues > 1; +} + +static bool has_ctrl_guest_offloads(void *opaque, int version_id) +{ + return virtio_vdev_has_feature(VIRTIO_DEVICE(opaque), + VIRTIO_NET_F_CTRL_GUEST_OFFLOADS); +} + +static bool mac_table_fits(void *opaque, int version_id) +{ + return VIRTIO_NET(opaque)->mac_table.in_use <=3D MAC_TABLE_ENTRIES; +} + +static bool mac_table_doesnt_fit(void *opaque, int version_id) +{ + return !mac_table_fits(opaque, version_id); +} + +/* This temporary type is shared by all the WITH_TMP methods + * although only some fields are used by each. + */ +struct VirtIONetMigTmp { + VirtIONet *parent; + VirtIONetQueue *vqs_1; + uint16_t curr_queues_1; + uint8_t has_ufo; + uint32_t has_vnet_hdr; +}; + +/* The 2nd and subsequent tx_waiting flags are loaded later than + * the 1st entry in the queues and only if there's more than one + * entry. We use the tmp mechanism to calculate a temporary + * pointer and count and also validate the count. + */ + +static void virtio_net_tx_waiting_pre_save(void *opaque) +{ + struct VirtIONetMigTmp *tmp =3D opaque; + + tmp->vqs_1 =3D tmp->parent->vqs + 1; + tmp->curr_queues_1 =3D tmp->parent->curr_queues - 1; + if (tmp->parent->curr_queues =3D=3D 0) { + tmp->curr_queues_1 =3D 0; + } +} + +static int virtio_net_tx_waiting_pre_load(void *opaque) +{ + struct VirtIONetMigTmp *tmp =3D opaque; + + /* Reuse the pointer setup from save */ + virtio_net_tx_waiting_pre_save(opaque); + + if (tmp->parent->curr_queues > tmp->parent->max_queues) { + error_report("virtio-net: curr_queues %x > max_queues %x", + tmp->parent->curr_queues, tmp->parent->max_queues); + + return -EINVAL; + } + + return 0; /* all good */ +} + +static const VMStateDescription vmstate_virtio_net_tx_waiting =3D { + .name =3D "virtio-net-tx_waiting", + .pre_load =3D virtio_net_tx_waiting_pre_load, + .pre_save =3D virtio_net_tx_waiting_pre_save, + .fields =3D (VMStateField[]) { + VMSTATE_STRUCT_VARRAY_POINTER_UINT16(vqs_1, struct VirtIONetMigTmp, + curr_queues_1, + vmstate_virtio_net_queue_tx_waiting, + struct VirtIONetQueue), + VMSTATE_END_OF_LIST() + }, +}; + +/* the 'has_ufo' flag is just tested; if the incoming stream has the + * flag set we need to check that we have it + */ +static int virtio_net_ufo_post_load(void *opaque, int version_id) +{ + struct VirtIONetMigTmp *tmp =3D opaque; + + if (tmp->has_ufo && !peer_has_ufo(tmp->parent)) { + error_report("virtio-net: saved image requires TUN_F_UFO support"); + return -EINVAL; + } + + return 0; +} + +static void virtio_net_ufo_pre_save(void *opaque) +{ + struct VirtIONetMigTmp *tmp =3D opaque; + + tmp->has_ufo =3D tmp->parent->has_ufo; +} + +static const VMStateDescription vmstate_virtio_net_has_ufo =3D { + .name =3D "virtio-net-ufo", + .post_load =3D virtio_net_ufo_post_load, + .pre_save =3D virtio_net_ufo_pre_save, + .fields =3D (VMStateField[]) { + VMSTATE_UINT8(has_ufo, struct VirtIONetMigTmp), + VMSTATE_END_OF_LIST() + }, +}; + +/* the 'has_vnet_hdr' flag is just tested; if the incoming stream has the + * flag set we need to check that we have it + */ +static int virtio_net_vnet_post_load(void *opaque, int version_id) +{ + struct VirtIONetMigTmp *tmp =3D opaque; + + if (tmp->has_vnet_hdr && !peer_has_vnet_hdr(tmp->parent)) { + error_report("virtio-net: saved image requires vnet_hdr=3Don"); + return -EINVAL; + } + + return 0; +} + +static void virtio_net_vnet_pre_save(void *opaque) +{ + struct VirtIONetMigTmp *tmp =3D opaque; + + tmp->has_vnet_hdr =3D tmp->parent->has_vnet_hdr; +} + +static const VMStateDescription vmstate_virtio_net_has_vnet =3D { + .name =3D "virtio-net-vnet", + .post_load =3D virtio_net_vnet_post_load, + .pre_save =3D virtio_net_vnet_pre_save, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32(has_vnet_hdr, struct VirtIONetMigTmp), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_virtio_net_device =3D { + .name =3D "virtio-net-device", + .version_id =3D VIRTIO_NET_VM_VERSION, + .minimum_version_id =3D VIRTIO_NET_VM_VERSION, + .post_load =3D virtio_net_post_load_device, + .fields =3D (VMStateField[]) { + VMSTATE_UINT8_ARRAY(mac, VirtIONet, ETH_ALEN), + VMSTATE_STRUCT_POINTER(vqs, VirtIONet, + vmstate_virtio_net_queue_tx_waiting, + VirtIONetQueue), + VMSTATE_UINT32(mergeable_rx_bufs, VirtIONet), + VMSTATE_UINT16(status, VirtIONet), + VMSTATE_UINT8(promisc, VirtIONet), + VMSTATE_UINT8(allmulti, VirtIONet), + VMSTATE_UINT32(mac_table.in_use, VirtIONet), + + /* Guarded pair: If it fits we load it, else we throw it away + * - can happen if source has a larger MAC table.; post-load + * sets flags in this case. + */ + VMSTATE_VBUFFER_MULTIPLY(mac_table.macs, VirtIONet, + 0, mac_table_fits, 0, mac_table.in_use, + ETH_ALEN), + VMSTATE_UNUSED_VARRAY_UINT32(VirtIONet, mac_table_doesnt_fit, 0, + mac_table.in_use, ETH_ALEN), + + /* Note: This is an array of uint32's that's always been saved as a + * buffer; hold onto your endiannesses; it's actually used as a bi= tmap + * but based on the uint. + */ + VMSTATE_BUFFER_POINTER_UNSAFE(vlans, VirtIONet, 0, MAX_VLAN >> 3), + VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, + vmstate_virtio_net_has_vnet), + VMSTATE_UINT8(mac_table.multi_overflow, VirtIONet), + VMSTATE_UINT8(mac_table.uni_overflow, VirtIONet), + VMSTATE_UINT8(alluni, VirtIONet), + VMSTATE_UINT8(nomulti, VirtIONet), + VMSTATE_UINT8(nouni, VirtIONet), + VMSTATE_UINT8(nobcast, VirtIONet), + VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, + vmstate_virtio_net_has_ufo), + VMSTATE_SINGLE_TEST(max_queues, VirtIONet, max_queues_gt_1, 0, + vmstate_info_uint16_equal, uint16_t), + VMSTATE_UINT16_TEST(curr_queues, VirtIONet, max_queues_gt_1), + VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, + vmstate_virtio_net_tx_waiting), + VMSTATE_UINT64_TEST(curr_guest_offloads, VirtIONet, + has_ctrl_guest_offloads), + VMSTATE_END_OF_LIST() + }, +}; + static NetClientInfo net_virtio_info =3D { .type =3D NET_CLIENT_DRIVER_NIC, .size =3D sizeof(NICState), @@ -1989,9 +2096,8 @@ static void virtio_net_class_init(ObjectClass *klass,= void *data) vdc->set_status =3D virtio_net_set_status; vdc->guest_notifier_mask =3D virtio_net_guest_notifier_mask; vdc->guest_notifier_pending =3D virtio_net_guest_notifier_pending; - vdc->load =3D virtio_net_load_device; - vdc->save =3D virtio_net_save_device; vdc->legacy_features |=3D (0x1 << VIRTIO_NET_F_GSO); + vdc->vmsd =3D &vmstate_virtio_net_device; } =20 static const TypeInfo virtio_net_info =3D { diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 8ea56a8..1eec9a2 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -47,7 +47,7 @@ typedef struct VirtIONetQueue { VirtQueue *tx_vq; QEMUTimer *tx_timer; QEMUBH *tx_bh; - int tx_waiting; + uint32_t tx_waiting; struct { VirtQueueElement *elem; } async_tx; @@ -68,7 +68,7 @@ typedef struct VirtIONet { size_t guest_hdr_len; uint32_t host_features; uint8_t has_ufo; - int mergeable_rx_bufs; + uint32_t mergeable_rx_bufs; uint8_t promisc; uint8_t allmulti; uint8_t alluni; --=20 2.9.3