From nobody Sun Sep 28 16:35:28 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=yandex-team.ru ARC-Seal: i=1; a=rsa-sha256; t=1758621843; cv=none; d=zohomail.com; s=zohoarc; b=k2Adot0yIHjlCq9OX0SI4Ri9MkKFMEjz3Kr0CJiOmd/mbSChhGRKVK6RlZfHg/kErm6sS0+qLWdX1nMPKASL1qrQQtMyr2OF/aAEFq8iRefOswwKbuWXiUghAh0oOSfAdv3pBSvGrSyLxqkq4dvjf4UDISbkIBO407V6VWc5pTI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1758621843; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=rioAl/ubyEER0xno3M72Ijf4+vaU5tOXleX9shfbfio=; b=ICoeySMYI08DijIuW9U2t2SOlmh0MhybDwrZ9w9qjI4OIYiiaBP/VjQqh7B6zXKrYsazRA8Q0h4PnqkfUEssREBkQOTszwXsQZHexkIawQVVcBCLBg5WJYY99XZKmKaL5LfCpV9s+k64U5BuTDj+YCwGqjYKPDvtoTUaFSHtiEI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1758621843802925.0314667907736; Tue, 23 Sep 2025 03:04:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1v0zqb-00039D-6N; Tue, 23 Sep 2025 06:02:09 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1v0zqF-0002sN-Bi for qemu-devel@nongnu.org; Tue, 23 Sep 2025 06:01:48 -0400 Received: from forwardcorp1d.mail.yandex.net ([2a02:6b8:c41:1300:1:45:d181:df01]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1v0zpv-0000vE-Ok for qemu-devel@nongnu.org; Tue, 23 Sep 2025 06:01:47 -0400 Received: from mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net (mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net [IPv6:2a02:6b8:c42:cf2d:0:640:140f:0]) by forwardcorp1d.mail.yandex.net (Yandex) with ESMTPS id 2B8AD8081E; Tue, 23 Sep 2025 13:01:23 +0300 (MSK) Received: from vsementsov-lin.. (unknown [2a02:6bf:8080:b38::1:12]) by mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net (smtpcorp/Yandex) with ESMTPSA id C1Ug0C0Fha60-xoLeCjei; Tue, 23 Sep 2025 13:01:22 +0300 Precedence: bulk X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex-team.ru; s=default; t=1758621682; bh=rioAl/ubyEER0xno3M72Ijf4+vaU5tOXleX9shfbfio=; h=Message-ID:Date:In-Reply-To:Cc:Subject:References:To:From; b=VnW8PFjoIcUruCGw7v+x4uWzq9LXs8yfyomqSgHrjZPxfU6FCzkCYhri71OVTPqgN M2UVR+K5f8ykENDxvB+q1so9VtDOynB3rJnPTlcMeb8Y6VcLGMsU1iF9yyQImQImsI 7SNVPyTrefCIBx7j+Zdv/lAloHV9auDS1fDsM21c= Authentication-Results: mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net; dkim=pass header.i=@yandex-team.ru From: Vladimir Sementsov-Ogievskiy To: mst@redhat.com Cc: qemu-devel@nongnu.org, philmd@linaro.org, thuth@redhat.com, eblake@redhat.com, michael.roth@amd.com, armbru@redhat.com, farosas@suse.de, peterx@redhat.com, berrange@redhat.com, jasowang@redhat.com, steven.sistare@oracle.com, leiyang@redhat.com, davydov-max@yandex-team.ru, yc-core@yandex-team.ru, vsementsov@yandex-team.ru Subject: [PATCH v6 17/19] virtio-net: support backend-transfer migration for virtio-net/tap Date: Tue, 23 Sep 2025 13:01:08 +0300 Message-ID: <20250923100110.70862-18-vsementsov@yandex-team.ru> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250923100110.70862-1-vsementsov@yandex-team.ru> References: <20250923100110.70862-1-vsementsov@yandex-team.ru> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2a02:6b8:c41:1300:1:45:d181:df01; envelope-from=vsementsov@yandex-team.ru; helo=forwardcorp1d.mail.yandex.net X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 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-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @yandex-team.ru) X-ZM-MESSAGEID: 1758621845813116600 Content-Type: text/plain; charset="utf-8" Finally implement the new migration option backend-transfer =3D ["virtio-net-tap"]. With this enabled (both on source and target) of-course, and with unix-socket used as migration-channel, we do "migrate" the virtio-net backend - TAP device, with all its fds. This way management tool should not care about creating new TAP, and should not handle switching to it. Migration downtime become shorter. How it works: 1. For incoming migration, we postpone TAP initialization up to pre-incoming point. 2. At pre-incoming point we see that "virtio-net-tap" is set for backend-transfer, so we postpone TAP initialization up to post-load 3. During virtio-load, we get TAP state (and fds) as part of virtio-net state 4. In post-load we finalize TAP initialization Signed-off-by: Vladimir Sementsov-Ogievskiy --- hw/net/virtio-net.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ include/net/tap.h | 3 ++ migration/options.c | 5 ---- net/tap.c | 54 ++++++++++++++++++++++++++++++++- 4 files changed, 129 insertions(+), 6 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 70f688fc3a..73e4053c41 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -26,6 +26,7 @@ #include "qemu/option.h" #include "qemu/option_int.h" #include "qemu/config-file.h" +#include "qemu/typedefs.h" #include "qobject/qdict.h" #include "hw/virtio/virtio-net.h" #include "net/vhost_net.h" @@ -38,6 +39,8 @@ #include "qapi/qapi-events-migration.h" #include "hw/virtio/virtio-access.h" #include "migration/misc.h" +#include "migration/migration.h" +#include "migration/options.h" #include "standard-headers/linux/ethtool.h" #include "system/system.h" #include "system/replay.h" @@ -3147,6 +3150,11 @@ static int virtio_net_update_host_features(VirtIONet= *n) Error *local_err =3D NULL; VirtIODevice *vdev =3D VIRTIO_DEVICE(n); =20 + if (peer_wait_incoming(n)) { + /* It's too early for updating options. */ + return 0; + } + peer_test_vnet_hdr(n); =20 vdev->host_features =3D virtio_net_get_features(vdev, vdev->host_featu= res, @@ -3287,6 +3295,9 @@ struct VirtIONetMigTmp { uint16_t curr_queue_pairs_1; uint8_t has_ufo; uint32_t has_vnet_hdr; + + NetClientState *ncs; + uint32_t max_queue_pairs; }; =20 /* The 2nd and subsequent tx_waiting flags are loaded later than @@ -3556,6 +3567,65 @@ static const VMStateDescription vhost_user_net_backe= nd_state =3D { } }; =20 +static bool virtio_net_is_tap_mig(void *opaque, int version_id) +{ + VirtIONet *n =3D opaque; + NetClientState *nc; + + nc =3D qemu_get_queue(n->nic); + + return migrate_virtio_net_tap() && nc->peer && + nc->peer->info->type =3D=3D NET_CLIENT_DRIVER_TAP; +} + +static int virtio_net_nic_pre_save(void *opaque) +{ + struct VirtIONetMigTmp *tmp =3D opaque; + + tmp->ncs =3D tmp->parent->nic->ncs; + tmp->max_queue_pairs =3D tmp->parent->max_queue_pairs; + + return 0; +} + +static int virtio_net_nic_pre_load(void *opaque) +{ + /* Reuse the pointer setup from save */ + virtio_net_nic_pre_save(opaque); + + return 0; +} + +static int virtio_net_nic_post_load(void *opaque, int version_id) +{ + struct VirtIONetMigTmp *tmp =3D opaque; + + return virtio_net_update_host_features(tmp->parent); +} + +static const VMStateDescription vmstate_virtio_net_nic_nc =3D { + .name =3D "virtio-net-nic-nc", + .fields =3D (const VMStateField[]) { + VMSTATE_STRUCT_POINTER(peer, NetClientState, vmstate_tap, + NetClientState), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_virtio_net_nic =3D { + .name =3D "virtio-net-nic", + .pre_load =3D virtio_net_nic_pre_load, + .pre_save =3D virtio_net_nic_pre_save, + .post_load =3D virtio_net_nic_post_load, + .fields =3D (const VMStateField[]) { + VMSTATE_STRUCT_VARRAY_POINTER_UINT32(ncs, struct VirtIONetMigTmp, + max_queue_pairs, + vmstate_virtio_net_nic_nc, + struct NetClientState), + VMSTATE_END_OF_LIST() + }, +}; + static const VMStateDescription vmstate_virtio_net_device =3D { .name =3D "virtio-net-device", .version_id =3D VIRTIO_NET_VM_VERSION, @@ -3588,6 +3658,9 @@ static const VMStateDescription vmstate_virtio_net_de= vice =3D { * but based on the uint. */ VMSTATE_BUFFER_POINTER_UNSAFE(vlans, VirtIONet, 0, MAX_VLAN >> 3), + VMSTATE_WITH_TMP_TEST(VirtIONet, virtio_net_is_tap_mig, + struct VirtIONetMigTmp, + vmstate_virtio_net_nic), VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, vmstate_virtio_net_has_vnet), VMSTATE_UINT8(mac_table.multi_overflow, VirtIONet), diff --git a/include/net/tap.h b/include/net/tap.h index c6f9c1aeb1..0be083f8da 100644 --- a/include/net/tap.h +++ b/include/net/tap.h @@ -26,6 +26,7 @@ #ifndef QEMU_NET_TAP_H #define QEMU_NET_TAP_H =20 +#include "qemu/typedefs.h" #include "standard-headers/linux/virtio_net.h" =20 int tap_enable(NetClientState *nc); @@ -35,4 +36,6 @@ int tap_get_fd(NetClientState *nc); =20 bool tap_wait_incoming(NetClientState *nc); =20 +extern const VMStateDescription vmstate_tap; + #endif /* QEMU_NET_TAP_H */ diff --git a/migration/options.c b/migration/options.c index 137ca2147e..38460e9b1b 100644 --- a/migration/options.c +++ b/migration/options.c @@ -1195,11 +1195,6 @@ bool migrate_params_check(MigrationParameters *param= s, Error **errp) return false; } =20 - if (params->has_backend_transfer) { - error_setg(errp, "Not implemented"); - return false; - } - return true; } =20 diff --git a/net/tap.c b/net/tap.c index b959547492..10180daf03 100644 --- a/net/tap.c +++ b/net/tap.c @@ -36,6 +36,7 @@ #include "net/net.h" #include "clients.h" #include "migration/misc.h" +#include "migration/options.h" #include "monitor/monitor.h" #include "system/runstate.h" #include "system/system.h" @@ -94,6 +95,7 @@ typedef struct TAPState { int vnet_hdr; bool mq_required; char *ifname; + bool attached_to_virtio_net; } TAPState; =20 static QTAILQ_HEAD(, TAPState) postponed_taps =3D @@ -405,6 +407,8 @@ static bool tap_check_peer_type(NetClientState *nc, Obj= ectClass *oc, } } =20 + s->attached_to_virtio_net =3D true; + return true; } =20 @@ -810,7 +814,7 @@ static void net_init_tap_one(const NetdevTapOptions *ta= p, NetClientState *peer, =20 static bool net_tap_setup(TAPState *s, int fd, int vnet_hdr, Error **errp) { - if (!net_tap_set_fd(s, fd, vnet_hdr, errp)) { + if (fd !=3D -1 && !net_tap_set_fd(s, fd, vnet_hdr, errp)) { return false; } =20 @@ -902,6 +906,7 @@ static int tap_pre_incoming(NotifierWithReturn *notifie= r, { TAPState *s; bool ok =3D true; + bool mig_fds =3D migrate_virtio_net_tap(); =20 if (e->type !=3D MIG_EVENT_PRE_INCOMING) { return 0; @@ -910,6 +915,11 @@ static int tap_pre_incoming(NotifierWithReturn *notifi= er, while (!QTAILQ_EMPTY(&postponed_taps)) { s =3D QTAILQ_FIRST(&postponed_taps); if (ok) { + if (mig_fds && s->attached_to_virtio_net) { + /* We'll get fds from incoming migration */ + QTAILQ_REMOVE(&postponed_taps, s, next); + continue; + } ok =3D tap_postponed_init(s, errp); } else { QTAILQ_REMOVE(&postponed_taps, s, next); @@ -1247,6 +1257,48 @@ int tap_disable(NetClientState *nc) } } =20 +static int tap_pre_load(void *opaque) +{ + TAPState *s =3D opaque; + + if (s->fd !=3D -1) { + error_report( + "TAP is already initialized and cannot receive incoming fd"); + return -EINVAL; + } + + return 0; +} + +static int tap_post_load(void *opaque, int version_id) +{ + TAPState *s =3D opaque; + Error *local_err =3D NULL; + + if (!net_tap_setup(s, -1, -1, &local_err)) { + error_report_err(local_err); + qemu_del_net_client(&s->nc); + return -EINVAL; + } + + return 0; +} + +const VMStateDescription vmstate_tap =3D { + .name =3D "net-tap", + .pre_load =3D tap_pre_load, + .post_load =3D tap_post_load, + .fields =3D (const VMStateField[]) { + VMSTATE_FD(fd, TAPState), + VMSTATE_BOOL(using_vnet_hdr, TAPState), + VMSTATE_BOOL(has_ufo, TAPState), + VMSTATE_BOOL(has_uso, TAPState), + VMSTATE_BOOL(enabled, TAPState), + VMSTATE_UINT32(host_vnet_hdr_len, TAPState), + VMSTATE_END_OF_LIST() + } +}; + bool tap_wait_incoming(NetClientState *nc) { TAPState *s =3D DO_UPCAST(TAPState, nc, nc); --=20 2.48.1