* [PATCH v6 00/19] virtio-net: live-TAP local migration
@ 2025-09-23 10:00 Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 01/19] net/tap: net_init_tap_one(): drop extra error propagation Vladimir Sementsov-Ogievskiy
` (20 more replies)
0 siblings, 21 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:00 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Hi all!
Here is a new migration parameter backend-transfer, which allows to
enable local migration of TAP virtio-net backend, including its
properties and open fds.
With this new option, management software doesn't need to
initialize new TAP and do a switch to it. Nothing should be
done around virtio-net in local migration: it just migrates
and continues to use same TAP device. So we avoid extra logic
in management software, extra allocations in kernel (for new TAP),
and corresponding extra delay in migration downtime.
v6:
- rebase on master (to solve conflict with merged
"io: deal with blocking/non-blocking fds")
- use name "backend-transfer" for the whole feature consistently
though the whole series. (live-backend is good, but actually,
we are already in "live-migration", so every its feature may
have "live-" prefix, and it seems redundant)
03-04: new, making changes in 05 correct
08-09: split "net/tap: rework tap_set_sndbuf()" into two commits
15: fix windows compilation
16: move has_ = true, to _params_init
18: use shorter name
and some other cosmetic changes.
Vladimir Sementsov-Ogievskiy (19):
net/tap: net_init_tap_one(): drop extra error propagation
net/tap: net_init_tap_one(): move parameter checking earlier
net/tap: rework net_tap_init()
net/tap: pass NULL to net_init_tap_one() in cases when scripts are
NULL
net/tap: rework scripts handling
net/tap: setup exit notifier only when needed
net/tap: split net_tap_fd_init()
net/tap: tap_set_sndbuf(): add return value
net/tap: rework tap_set_sndbuf()
net/tap: rework sndbuf handling
net/tap: introduce net_tap_setup()
net/tap: move vhost fd initialization to net_tap_new()
net/tap: finalize net_tap_set_fd() logic
migration: add MIG_EVENT_PRE_INCOMING
net/tap: postpone tap setup to pre-incoming
qapi: add interface for backend-transfer virtio-net/tap migration
virtio-net: support backend-transfer migration for virtio-net/tap
tests/functional: add skipWithoutSudo() decorator
tests/functional: add test_x86_64_tap_migration
hw/net/virtio-net.c | 138 +++++-
include/migration/misc.h | 1 +
include/net/tap.h | 5 +
include/qapi/util.h | 17 +
migration/migration.c | 8 +-
migration/options.c | 27 +
migration/options.h | 2 +
net/tap-bsd.c | 3 +-
net/tap-linux.c | 19 +-
net/tap-solaris.c | 3 +-
net/tap-stub.c | 3 +-
net/tap-win32.c | 5 +
net/tap.c | 467 ++++++++++++++----
net/tap_int.h | 4 +-
qapi/migration.json | 47 +-
tests/functional/qemu_test/decorators.py | 16 +
tests/functional/test_x86_64_tap_migration.py | 344 +++++++++++++
17 files changed, 974 insertions(+), 135 deletions(-)
create mode 100644 tests/functional/test_x86_64_tap_migration.py
--
2.48.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v6 01/19] net/tap: net_init_tap_one(): drop extra error propagation
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:00 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 02/19] net/tap: net_init_tap_one(): move parameter checking earlier Vladimir Sementsov-Ogievskiy
` (19 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:00 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index f37133e301..5d91658660 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -723,9 +723,8 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
}
if (vhostfdname) {
- vhostfd = monitor_fd_param(monitor_cur(), vhostfdname, &err);
+ vhostfd = monitor_fd_param(monitor_cur(), vhostfdname, errp);
if (vhostfd == -1) {
- error_propagate(errp, err);
goto failed;
}
if (!qemu_set_blocking(vhostfd, false, errp)) {
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 02/19] net/tap: net_init_tap_one(): move parameter checking earlier
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 01/19] net/tap: net_init_tap_one(): drop extra error propagation Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:00 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 03/19] net/tap: rework net_tap_init() Vladimir Sementsov-Ogievskiy
` (18 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:00 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Let's keep all similar argument checking in net_init_tap() function.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index 5d91658660..8cccf71002 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -755,9 +755,6 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
"vhost-net requested but could not be initialized");
goto failed;
}
- } else if (vhostfdname) {
- error_setg(errp, "vhostfd(s)= is not valid without vhost");
- goto failed;
}
return;
@@ -819,6 +816,11 @@ int net_init_tap(const Netdev *netdev, const char *name,
return -1;
}
+ if (tap->has_vhost && !tap->vhost && (tap->vhostfds || tap->vhostfd)) {
+ error_setg(errp, "vhostfd(s)= is not valid without vhost");
+ return -1;
+ }
+
if (tap->fd) {
if (tap->ifname || tap->script || tap->downscript ||
tap->has_vnet_hdr || tap->helper || tap->has_queues ||
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 03/19] net/tap: rework net_tap_init()
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 01/19] net/tap: net_init_tap_one(): drop extra error propagation Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 02/19] net/tap: net_init_tap_one(): move parameter checking earlier Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:00 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 04/19] net/tap: pass NULL to net_init_tap_one() in cases when scripts are NULL Vladimir Sementsov-Ogievskiy
` (17 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:00 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
In future (to support backend-transfer migration for virtio-net/tap,
which includes fds passing through unix socket) we'll want to postpone
fd-initialization to the later point, when QAPI structured parameters
are not available. So, let's now rework the function to interface
without "tap" parameter.
Also, rename to net_tap_open(), as it's just a wrapper on tap_open(),
and having net_tap_init() and net_init_tap() functions in one file
is confusing.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index 8cccf71002..506dc9d226 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -642,20 +642,12 @@ int net_init_bridge(const Netdev *netdev, const char *name,
return 0;
}
-static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr,
+static int net_tap_open(int *vnet_hdr, bool vnet_hdr_required,
const char *setup_script, char *ifname,
size_t ifname_sz, int mq_required, Error **errp)
{
Error *err = NULL;
- int fd, vnet_hdr_required;
-
- if (tap->has_vnet_hdr) {
- *vnet_hdr = tap->vnet_hdr;
- vnet_hdr_required = *vnet_hdr;
- } else {
- *vnet_hdr = 1;
- vnet_hdr_required = 0;
- }
+ int fd;
fd = RETRY_ON_EINTR(tap_open(ifname, ifname_sz, vnet_hdr, vnet_hdr_required,
mq_required, errp));
@@ -964,6 +956,8 @@ free_fail:
} else {
g_autofree char *default_script = NULL;
g_autofree char *default_downscript = NULL;
+ bool vnet_hdr_required = tap->has_vnet_hdr && tap->vnet_hdr;
+
if (tap->vhostfds) {
error_setg(errp, "vhostfds= is invalid if fds= wasn't specified");
return -1;
@@ -984,7 +978,9 @@ free_fail:
}
for (i = 0; i < queues; i++) {
- fd = net_tap_init(tap, &vnet_hdr, i >= 1 ? "no" : script,
+ vnet_hdr = tap->has_vnet_hdr ? tap->vnet_hdr : 1;
+ fd = net_tap_open(&vnet_hdr, vnet_hdr_required,
+ i >= 1 ? "no" : script,
ifname, sizeof ifname, queues > 1, errp);
if (fd == -1) {
return -1;
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 04/19] net/tap: pass NULL to net_init_tap_one() in cases when scripts are NULL
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (2 preceding siblings ...)
2025-09-23 10:00 ` [PATCH v6 03/19] net/tap: rework net_tap_init() Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:00 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 05/19] net/tap: rework scripts handling Vladimir Sementsov-Ogievskiy
` (16 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:00 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Directly pass NULL in cases where we report an error if script or
downscript are set.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index 506dc9d226..e42c7ca044 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -787,8 +787,6 @@ int net_init_tap(const Netdev *netdev, const char *name,
const NetdevTapOptions *tap;
int fd, vnet_hdr = 0, i = 0, queues;
/* for the no-fd, no-helper case */
- const char *script;
- const char *downscript;
Error *err = NULL;
const char *vhostfdname;
char ifname[128];
@@ -798,8 +796,6 @@ int net_init_tap(const Netdev *netdev, const char *name,
tap = &netdev->u.tap;
queues = tap->has_queues ? tap->queues : 1;
vhostfdname = tap->vhostfd;
- script = tap->script;
- downscript = tap->downscript;
/* QEMU hubs do not support multiqueue tap, in this case peer is set.
* For -netdev, peer is always NULL. */
@@ -840,7 +836,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
}
net_init_tap_one(tap, peer, "tap", name, NULL,
- script, downscript,
+ NULL, NULL,
vhostfdname, vnet_hdr, fd, &err);
if (err) {
error_propagate(errp, err);
@@ -901,7 +897,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
}
net_init_tap_one(tap, peer, "tap", name, ifname,
- script, downscript,
+ NULL, NULL,
tap->vhostfds ? vhost_fds[i] : NULL,
vnet_hdr, fd, &err);
if (err) {
@@ -946,7 +942,7 @@ free_fail:
}
net_init_tap_one(tap, peer, "bridge", name, ifname,
- script, downscript, vhostfdname,
+ NULL, NULL, vhostfdname,
vnet_hdr, fd, &err);
if (err) {
error_propagate(errp, err);
@@ -954,6 +950,8 @@ free_fail:
return -1;
}
} else {
+ const char *script = tap->script;
+ const char *downscript = tap->downscript;
g_autofree char *default_script = NULL;
g_autofree char *default_downscript = NULL;
bool vnet_hdr_required = tap->has_vnet_hdr && tap->vnet_hdr;
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 05/19] net/tap: rework scripts handling
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (3 preceding siblings ...)
2025-09-23 10:00 ` [PATCH v6 04/19] net/tap: pass NULL to net_init_tap_one() in cases when scripts are NULL Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:00 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:39 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 06/19] net/tap: setup exit notifier only when needed Vladimir Sementsov-Ogievskiy
` (15 subsequent siblings)
20 siblings, 1 reply; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:00 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Simplify handling scripts: parse all these "no" and '\0' once, and
then keep simpler logic for net_tap_open() and net_init_tap_one(): NULL
means no script to run, otherwise run script.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 45 +++++++++++++++++++++++++--------------------
1 file changed, 25 insertions(+), 20 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index e42c7ca044..084ee4f649 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -88,6 +88,21 @@ static void launch_script(const char *setup_script, const char *ifname,
static void tap_send(void *opaque);
static void tap_writable(void *opaque);
+static char *tap_parse_script(const char *script_arg, const char *default_path)
+{
+ g_autofree char *res = g_strdup(script_arg);
+
+ if (!res) {
+ res = get_relocated_path(default_path);
+ }
+
+ if (res[0] == '\0' || strcmp(res, "no") == 0) {
+ return NULL;
+ }
+
+ return g_steal_pointer(&res);
+}
+
static void tap_update_fd_handler(TAPState *s)
{
qemu_set_fd_handler(s->fd,
@@ -655,9 +670,7 @@ static int net_tap_open(int *vnet_hdr, bool vnet_hdr_required,
return -1;
}
- if (setup_script &&
- setup_script[0] != '\0' &&
- strcmp(setup_script, "no") != 0) {
+ if (setup_script) {
launch_script(setup_script, ifname, fd, &err);
if (err) {
error_propagate(errp, err);
@@ -693,9 +706,9 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
qemu_set_info_str(&s->nc, "helper=%s", tap->helper);
} else {
qemu_set_info_str(&s->nc, "ifname=%s,script=%s,downscript=%s", ifname,
- script, downscript);
+ script ?: "no", downscript ?: "no");
- if (strcmp(downscript, "no") != 0) {
+ if (downscript) {
snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
snprintf(s->down_script_arg, sizeof(s->down_script_arg),
"%s", ifname);
@@ -950,10 +963,10 @@ free_fail:
return -1;
}
} else {
- const char *script = tap->script;
- const char *downscript = tap->downscript;
- g_autofree char *default_script = NULL;
- g_autofree char *default_downscript = NULL;
+ g_autofree char *script =
+ tap_parse_script(tap->script, DEFAULT_NETWORK_SCRIPT);
+ g_autofree char *downscript =
+ tap_parse_script(tap->script, DEFAULT_NETWORK_DOWN_SCRIPT);
bool vnet_hdr_required = tap->has_vnet_hdr && tap->vnet_hdr;
if (tap->vhostfds) {
@@ -961,14 +974,6 @@ free_fail:
return -1;
}
- if (!script) {
- script = default_script = get_relocated_path(DEFAULT_NETWORK_SCRIPT);
- }
- if (!downscript) {
- downscript = default_downscript =
- get_relocated_path(DEFAULT_NETWORK_DOWN_SCRIPT);
- }
-
if (tap->ifname) {
pstrcpy(ifname, sizeof ifname, tap->ifname);
} else {
@@ -978,7 +983,7 @@ free_fail:
for (i = 0; i < queues; i++) {
vnet_hdr = tap->has_vnet_hdr ? tap->vnet_hdr : 1;
fd = net_tap_open(&vnet_hdr, vnet_hdr_required,
- i >= 1 ? "no" : script,
+ i >= 1 ? NULL : script,
ifname, sizeof ifname, queues > 1, errp);
if (fd == -1) {
return -1;
@@ -993,8 +998,8 @@ free_fail:
}
net_init_tap_one(tap, peer, "tap", name, ifname,
- i >= 1 ? "no" : script,
- i >= 1 ? "no" : downscript,
+ i >= 1 ? NULL : script,
+ i >= 1 ? NULL : downscript,
vhostfdname, vnet_hdr, fd, &err);
if (err) {
error_propagate(errp, err);
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 06/19] net/tap: setup exit notifier only when needed
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (4 preceding siblings ...)
2025-09-23 10:00 ` [PATCH v6 05/19] net/tap: rework scripts handling Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:00 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 07/19] net/tap: split net_tap_fd_init() Vladimir Sementsov-Ogievskiy
` (14 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:00 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
No reason to setup notifier on each queue of multique tap,
when we actually want to run downscript only once.
As well, let's not setup notifier, when downscript is
not enabled (downsciprt="no").
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index 084ee4f649..a7ae7ab04a 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -316,11 +316,9 @@ static void tap_exit_notify(Notifier *notifier, void *data)
TAPState *s = container_of(notifier, TAPState, exit);
Error *err = NULL;
- if (s->down_script[0]) {
- launch_script(s->down_script, s->down_script_arg, s->fd, &err);
- if (err) {
- error_report_err(err);
- }
+ launch_script(s->down_script, s->down_script_arg, s->fd, &err);
+ if (err) {
+ error_report_err(err);
}
}
@@ -336,8 +334,11 @@ static void tap_cleanup(NetClientState *nc)
qemu_purge_queued_packets(nc);
- tap_exit_notify(&s->exit, NULL);
- qemu_remove_exit_notifier(&s->exit);
+ if (s->exit.notify) {
+ tap_exit_notify(&s->exit, NULL);
+ qemu_remove_exit_notifier(&s->exit);
+ s->exit.notify = NULL;
+ }
tap_read_poll(s, false);
tap_write_poll(s, false);
@@ -430,9 +431,6 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
tap_read_poll(s, true);
s->vhost_net = NULL;
- s->exit.notify = tap_exit_notify;
- qemu_add_exit_notifier(&s->exit);
-
return s;
}
@@ -712,6 +710,8 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
snprintf(s->down_script_arg, sizeof(s->down_script_arg),
"%s", ifname);
+ s->exit.notify = tap_exit_notify;
+ qemu_add_exit_notifier(&s->exit);
}
}
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 07/19] net/tap: split net_tap_fd_init()
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (5 preceding siblings ...)
2025-09-23 10:00 ` [PATCH v6 06/19] net/tap: setup exit notifier only when needed Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:00 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 08/19] net/tap: tap_set_sndbuf(): add return value Vladimir Sementsov-Ogievskiy
` (13 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:00 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Split the function into separate net_tap_new() and net_tap_set_fd().
We start move to the following picture:
net_tap_new() - take QAPI @tap parameter, but don't have @fd,
initialize the net client, called during initialization.
net_tap_setup() - don't have @tap (QAPI), but have @fd parameter,
may be called at later point.
In this commit we introduce the first function.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 28 +++++++++++++++-------------
1 file changed, 15 insertions(+), 13 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index a7ae7ab04a..048d130247 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -401,19 +401,19 @@ static NetClientInfo net_tap_info = {
.get_vhost_net = tap_get_vhost_net,
};
-static TAPState *net_tap_fd_init(NetClientState *peer,
- const char *model,
- const char *name,
- int fd,
- int vnet_hdr)
+static TAPState *net_tap_new(NetClientState *peer, const char *model,
+ const char *name)
{
- NetClientState *nc;
- TAPState *s;
+ NetClientState *nc = qemu_new_net_client(&net_tap_info, peer, model, name);
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
- nc = qemu_new_net_client(&net_tap_info, peer, model, name);
+ s->fd = -1;
- s = DO_UPCAST(TAPState, nc, nc);
+ return s;
+}
+static void net_tap_set_fd(TAPState *s, int fd, int vnet_hdr)
+{
s->fd = fd;
s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
s->using_vnet_hdr = false;
@@ -430,8 +430,6 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
}
tap_read_poll(s, true);
s->vhost_net = NULL;
-
- return s;
}
static void close_all_fds_after_fork(int excluded_fd)
@@ -648,7 +646,9 @@ int net_init_bridge(const Netdev *netdev, const char *name,
close(fd);
return -1;
}
- s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr);
+
+ s = net_tap_new(peer, "bridge", name);
+ net_tap_set_fd(s, fd, vnet_hdr);
qemu_set_info_str(&s->nc, "helper=%s,br=%s", helper, br);
@@ -689,9 +689,11 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
int vnet_hdr, int fd, Error **errp)
{
Error *err = NULL;
- TAPState *s = net_tap_fd_init(peer, model, name, fd, vnet_hdr);
+ TAPState *s = net_tap_new(peer, model, name);
int vhostfd;
+ net_tap_set_fd(s, fd, vnet_hdr);
+
tap_set_sndbuf(s->fd, tap, &err);
if (err) {
error_propagate(errp, err);
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 08/19] net/tap: tap_set_sndbuf(): add return value
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (6 preceding siblings ...)
2025-09-23 10:00 ` [PATCH v6 07/19] net/tap: split net_tap_fd_init() Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:00 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 09/19] net/tap: rework tap_set_sndbuf() Vladimir Sementsov-Ogievskiy
` (12 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:00 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Follow common recommendations in include/qapi/error.h of having
a return value together with errp. This allows to avoid error propagation.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap-bsd.c | 3 ++-
net/tap-linux.c | 5 ++++-
net/tap-solaris.c | 3 ++-
net/tap-stub.c | 3 ++-
net/tap.c | 5 +----
net/tap_int.h | 2 +-
6 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index 3f98d0ea82..501bf9d3eb 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -206,8 +206,9 @@ error:
}
#endif /* __FreeBSD__ */
-void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
+bool tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
{
+ return true;
}
int tap_probe_vnet_hdr(int fd, Error **errp)
diff --git a/net/tap-linux.c b/net/tap-linux.c
index e832810665..8cb9dc0787 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -145,7 +145,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
*/
#define TAP_DEFAULT_SNDBUF 0
-void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
+bool tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
{
int sndbuf;
@@ -159,7 +159,10 @@ void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
if (ioctl(fd, TUNSETSNDBUF, &sndbuf) == -1 && tap->has_sndbuf) {
error_setg_errno(errp, errno, "TUNSETSNDBUF ioctl failed");
+ return false;
}
+
+ return true;
}
int tap_probe_vnet_hdr(int fd, Error **errp)
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
index af2ebb16f5..496c1323fc 100644
--- a/net/tap-solaris.c
+++ b/net/tap-solaris.c
@@ -207,8 +207,9 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
return fd;
}
-void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
+bool tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
{
+ return true;
}
int tap_probe_vnet_hdr(int fd, Error **errp)
diff --git a/net/tap-stub.c b/net/tap-stub.c
index 38673434cb..8e328c679f 100644
--- a/net/tap-stub.c
+++ b/net/tap-stub.c
@@ -33,8 +33,9 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
return -1;
}
-void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
+bool tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
{
+ return true;
}
int tap_probe_vnet_hdr(int fd, Error **errp)
diff --git a/net/tap.c b/net/tap.c
index 048d130247..95cbd75fe4 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -688,15 +688,12 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
const char *downscript, const char *vhostfdname,
int vnet_hdr, int fd, Error **errp)
{
- Error *err = NULL;
TAPState *s = net_tap_new(peer, model, name);
int vhostfd;
net_tap_set_fd(s, fd, vnet_hdr);
- tap_set_sndbuf(s->fd, tap, &err);
- if (err) {
- error_propagate(errp, err);
+ if (!tap_set_sndbuf(s->fd, tap, errp)) {
goto failed;
}
diff --git a/net/tap_int.h b/net/tap_int.h
index 8857ff299d..08c40094b8 100644
--- a/net/tap_int.h
+++ b/net/tap_int.h
@@ -33,7 +33,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen);
-void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp);
+bool tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp);
int tap_probe_vnet_hdr(int fd, Error **errp);
int tap_probe_has_ufo(int fd);
int tap_probe_has_uso(int fd);
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 09/19] net/tap: rework tap_set_sndbuf()
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (7 preceding siblings ...)
2025-09-23 10:00 ` [PATCH v6 08/19] net/tap: tap_set_sndbuf(): add return value Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 10/19] net/tap: rework sndbuf handling Vladimir Sementsov-Ogievskiy
` (11 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Keep NetdevTapOptions related logic in tap.c, and make tap_set_sndbuf a
simple system call wrapper, more like other functions in tap-linux.c
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap-bsd.c | 2 +-
net/tap-linux.c | 16 ++--------------
net/tap-solaris.c | 2 +-
net/tap-stub.c | 2 +-
net/tap.c | 6 +++++-
net/tap_int.h | 4 +---
6 files changed, 11 insertions(+), 21 deletions(-)
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index 501bf9d3eb..7dd9f0aeda 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -206,7 +206,7 @@ error:
}
#endif /* __FreeBSD__ */
-bool tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
+bool tap_set_sndbuf(int fd, int sndbuf, Error **errp)
{
return true;
}
diff --git a/net/tap-linux.c b/net/tap-linux.c
index 8cb9dc0787..e3e71b713d 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -143,21 +143,9 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
* Ethernet NICs generally have txqueuelen=1000, so 1Mb is
* a good value, given a 1500 byte MTU.
*/
-#define TAP_DEFAULT_SNDBUF 0
-
-bool tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
+bool tap_set_sndbuf(int fd, int sndbuf, Error **errp)
{
- int sndbuf;
-
- sndbuf = !tap->has_sndbuf ? TAP_DEFAULT_SNDBUF :
- tap->sndbuf > INT_MAX ? INT_MAX :
- tap->sndbuf;
-
- if (!sndbuf) {
- sndbuf = INT_MAX;
- }
-
- if (ioctl(fd, TUNSETSNDBUF, &sndbuf) == -1 && tap->has_sndbuf) {
+ if (ioctl(fd, TUNSETSNDBUF, &sndbuf) == -1) {
error_setg_errno(errp, errno, "TUNSETSNDBUF ioctl failed");
return false;
}
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
index 496c1323fc..79e01a9de3 100644
--- a/net/tap-solaris.c
+++ b/net/tap-solaris.c
@@ -207,7 +207,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
return fd;
}
-bool tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
+bool tap_set_sndbuf(int fd, int sndbuf, Error **errp)
{
return true;
}
diff --git a/net/tap-stub.c b/net/tap-stub.c
index 8e328c679f..326e76843e 100644
--- a/net/tap-stub.c
+++ b/net/tap-stub.c
@@ -33,7 +33,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
return -1;
}
-bool tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
+bool tap_set_sndbuf(int fd, int sndbuf, Error **errp)
{
return true;
}
diff --git a/net/tap.c b/net/tap.c
index 95cbd75fe4..e6431d0e08 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -690,10 +690,14 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
{
TAPState *s = net_tap_new(peer, model, name);
int vhostfd;
+ bool sndbuf_required = tap->has_sndbuf;
+ int sndbuf =
+ (tap->has_sndbuf && tap->sndbuf) ? MIN(tap->sndbuf, INT_MAX) : INT_MAX;
net_tap_set_fd(s, fd, vnet_hdr);
- if (!tap_set_sndbuf(s->fd, tap, errp)) {
+ if (!tap_set_sndbuf(fd, sndbuf, sndbuf_required ? errp : NULL) &&
+ sndbuf_required) {
goto failed;
}
diff --git a/net/tap_int.h b/net/tap_int.h
index 08c40094b8..08e4a592a0 100644
--- a/net/tap_int.h
+++ b/net/tap_int.h
@@ -26,14 +26,12 @@
#ifndef NET_TAP_INT_H
#define NET_TAP_INT_H
-#include "qapi/qapi-types-net.h"
-
int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
int vnet_hdr_required, int mq_required, Error **errp);
ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen);
-bool tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp);
+bool tap_set_sndbuf(int fd, int sndbuf, Error **errp);
int tap_probe_vnet_hdr(int fd, Error **errp);
int tap_probe_has_ufo(int fd);
int tap_probe_has_uso(int fd);
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 10/19] net/tap: rework sndbuf handling
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (8 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 09/19] net/tap: rework tap_set_sndbuf() Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 11/19] net/tap: introduce net_tap_setup() Vladimir Sementsov-Ogievskiy
` (10 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Continue the main idea: avoid dependency on @tap in net_tap_setup().
So, move QAPI parsing to net_tap_new().
Move setting sndbuf to net_tap_set_fd(), as it's more appropriate place
(other initial fd settings are here).
Note that net_tap_new() and net_tap_set_fd() are shared with
net_init_bridge(), which didn't set sndbuf. Handle this case by sndbuf=0
(we never pass zero to tap_set_sndbuf(), so let this specific value mean
that we don't want touch sndbuf).
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 38 ++++++++++++++++++++++++++------------
1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index e6431d0e08..5a74cb325f 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -80,6 +80,9 @@ typedef struct TAPState {
VHostNetState *vhost_net;
unsigned host_vnet_hdr_len;
Notifier exit;
+
+ bool sndbuf_required;
+ int sndbuf;
} TAPState;
static void launch_script(const char *setup_script, const char *ifname,
@@ -402,17 +405,25 @@ static NetClientInfo net_tap_info = {
};
static TAPState *net_tap_new(NetClientState *peer, const char *model,
- const char *name)
+ const char *name, const NetdevTapOptions *tap)
{
NetClientState *nc = qemu_new_net_client(&net_tap_info, peer, model, name);
TAPState *s = DO_UPCAST(TAPState, nc, nc);
s->fd = -1;
+ if (!tap) {
+ return s;
+ }
+
+ s->sndbuf_required = tap->has_sndbuf;
+ s->sndbuf =
+ (tap->has_sndbuf && tap->sndbuf) ? MIN(tap->sndbuf, INT_MAX) : INT_MAX;
+
return s;
}
-static void net_tap_set_fd(TAPState *s, int fd, int vnet_hdr)
+static bool net_tap_set_fd(TAPState *s, int fd, int vnet_hdr, Error **errp)
{
s->fd = fd;
s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
@@ -430,6 +441,15 @@ static void net_tap_set_fd(TAPState *s, int fd, int vnet_hdr)
}
tap_read_poll(s, true);
s->vhost_net = NULL;
+
+ if (s->sndbuf) {
+ Error **e = s->sndbuf_required ? errp : NULL;
+ if (!tap_set_sndbuf(s->fd, s->sndbuf, e) && s->sndbuf_required) {
+ return false;
+ }
+ }
+
+ return true;
}
static void close_all_fds_after_fork(int excluded_fd)
@@ -647,8 +667,8 @@ int net_init_bridge(const Netdev *netdev, const char *name,
return -1;
}
- s = net_tap_new(peer, "bridge", name);
- net_tap_set_fd(s, fd, vnet_hdr);
+ s = net_tap_new(peer, "bridge", name, NULL);
+ net_tap_set_fd(s, fd, vnet_hdr, &error_abort);
qemu_set_info_str(&s->nc, "helper=%s,br=%s", helper, br);
@@ -688,16 +708,10 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
const char *downscript, const char *vhostfdname,
int vnet_hdr, int fd, Error **errp)
{
- TAPState *s = net_tap_new(peer, model, name);
+ TAPState *s = net_tap_new(peer, model, name, tap);
int vhostfd;
- bool sndbuf_required = tap->has_sndbuf;
- int sndbuf =
- (tap->has_sndbuf && tap->sndbuf) ? MIN(tap->sndbuf, INT_MAX) : INT_MAX;
-
- net_tap_set_fd(s, fd, vnet_hdr);
- if (!tap_set_sndbuf(fd, sndbuf, sndbuf_required ? errp : NULL) &&
- sndbuf_required) {
+ if (!net_tap_set_fd(s, fd, vnet_hdr, errp)) {
goto failed;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 11/19] net/tap: introduce net_tap_setup()
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (9 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 10/19] net/tap: rework sndbuf handling Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 12/19] net/tap: move vhost fd initialization to net_tap_new() Vladimir Sementsov-Ogievskiy
` (9 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Move most of net_init_tap_one() to net_tap_setup() - future pair
for net_tap_new(), for postponed setup.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 39 +++++++++++++++++++++++++--------------
1 file changed, 25 insertions(+), 14 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index 5a74cb325f..877564405a 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -85,6 +85,10 @@ typedef struct TAPState {
int sndbuf;
} TAPState;
+static bool net_tap_setup(TAPState *s, const NetdevTapOptions *tap,
+ const char *vhostfdname,
+ int fd, int vnet_hdr, Error **errp);
+
static void launch_script(const char *setup_script, const char *ifname,
int fd, Error **errp);
@@ -709,11 +713,6 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
int vnet_hdr, int fd, Error **errp)
{
TAPState *s = net_tap_new(peer, model, name, tap);
- int vhostfd;
-
- if (!net_tap_set_fd(s, fd, vnet_hdr, errp)) {
- goto failed;
- }
if (tap->fd || tap->fds) {
qemu_set_info_str(&s->nc, "fd=%d", fd);
@@ -732,6 +731,21 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
}
}
+ if (!net_tap_setup(s, tap, vhostfdname, fd, vnet_hdr, errp)) {
+ qemu_del_net_client(&s->nc);
+ }
+}
+
+static bool net_tap_setup(TAPState *s, const NetdevTapOptions *tap,
+ const char *vhostfdname,
+ int fd, int vnet_hdr, Error **errp)
+{
+ int vhostfd;
+
+ if (!net_tap_set_fd(s, fd, vnet_hdr, errp)) {
+ return false;
+ }
+
if (tap->has_vhost ? tap->vhost :
vhostfdname || (tap->has_vhostforce && tap->vhostforce)) {
VhostNetOptions options;
@@ -747,20 +761,20 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
if (vhostfdname) {
vhostfd = monitor_fd_param(monitor_cur(), vhostfdname, errp);
if (vhostfd == -1) {
- goto failed;
+ return false;
}
if (!qemu_set_blocking(vhostfd, false, errp)) {
- goto failed;
+ return false;
}
} else {
vhostfd = open("/dev/vhost-net", O_RDWR);
if (vhostfd < 0) {
error_setg_errno(errp, errno,
"tap: open vhost char device failed");
- goto failed;
+ return false;
}
if (!qemu_set_blocking(vhostfd, false, errp)) {
- goto failed;
+ return false;
}
}
options.opaque = (void *)(uintptr_t)vhostfd;
@@ -775,14 +789,11 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
if (!s->vhost_net) {
error_setg(errp,
"vhost-net requested but could not be initialized");
- goto failed;
+ return false;
}
}
- return;
-
-failed:
- qemu_del_net_client(&s->nc);
+ return true;
}
static int get_fds(char *str, char *fds[], int max)
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 12/19] net/tap: move vhost fd initialization to net_tap_new()
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (10 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 11/19] net/tap: introduce net_tap_setup() Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 13/19] net/tap: finalize net_tap_set_fd() logic Vladimir Sementsov-Ogievskiy
` (8 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Continue the track to avoid dependency on @tap in net_tap_setup(),
no move the vhost fd initialization to net_tap_new(). So in
net_tap_setup() we simply check, do we have and vhostfd at this
point or not.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 90 ++++++++++++++++++++++++++++++-------------------------
1 file changed, 50 insertions(+), 40 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index 877564405a..dbd1eb3a17 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -83,11 +83,11 @@ typedef struct TAPState {
bool sndbuf_required;
int sndbuf;
+ int vhostfd;
+ uint32_t vhost_busyloop_timeout;
} TAPState;
-static bool net_tap_setup(TAPState *s, const NetdevTapOptions *tap,
- const char *vhostfdname,
- int fd, int vnet_hdr, Error **errp);
+static bool net_tap_setup(TAPState *s, int fd, int vnet_hdr, Error **errp);
static void launch_script(const char *setup_script, const char *ifname,
int fd, Error **errp);
@@ -351,6 +351,11 @@ static void tap_cleanup(NetClientState *nc)
tap_write_poll(s, false);
close(s->fd);
s->fd = -1;
+
+ if (s->vhostfd != -1) {
+ close(s->vhostfd);
+ s->vhostfd = -1;
+ }
}
static void tap_poll(NetClientState *nc, bool enable)
@@ -409,12 +414,14 @@ static NetClientInfo net_tap_info = {
};
static TAPState *net_tap_new(NetClientState *peer, const char *model,
- const char *name, const NetdevTapOptions *tap)
+ const char *name, const NetdevTapOptions *tap,
+ const char *vhostfdname, Error **errp)
{
NetClientState *nc = qemu_new_net_client(&net_tap_info, peer, model, name);
TAPState *s = DO_UPCAST(TAPState, nc, nc);
s->fd = -1;
+ s->vhostfd = -1;
if (!tap) {
return s;
@@ -424,7 +431,36 @@ static TAPState *net_tap_new(NetClientState *peer, const char *model,
s->sndbuf =
(tap->has_sndbuf && tap->sndbuf) ? MIN(tap->sndbuf, INT_MAX) : INT_MAX;
+ if (tap->has_vhost ? tap->vhost :
+ vhostfdname || (tap->has_vhostforce && tap->vhostforce)) {
+ if (vhostfdname) {
+ s->vhostfd = monitor_fd_param(monitor_cur(), vhostfdname, errp);
+ if (s->vhostfd == -1) {
+ goto failed;
+ }
+ if (!qemu_set_blocking(s->vhostfd, false, errp)) {
+ goto failed;
+ }
+ } else {
+ s->vhostfd = open("/dev/vhost-net", O_RDWR);
+ if (s->vhostfd < 0) {
+ error_setg_errno(errp, errno,
+ "tap: open vhost char device failed");
+ goto failed;
+ }
+ if (!qemu_set_blocking(s->vhostfd, false, errp)) {
+ goto failed;
+ }
+ }
+
+ s->vhost_busyloop_timeout = tap->has_poll_us ? tap->poll_us : 0;
+ }
+
return s;
+
+failed:
+ qemu_del_net_client(&s->nc);
+ return NULL;
}
static bool net_tap_set_fd(TAPState *s, int fd, int vnet_hdr, Error **errp)
@@ -671,7 +707,7 @@ int net_init_bridge(const Netdev *netdev, const char *name,
return -1;
}
- s = net_tap_new(peer, "bridge", name, NULL);
+ s = net_tap_new(peer, "bridge", name, NULL, NULL, &error_abort);
net_tap_set_fd(s, fd, vnet_hdr, &error_abort);
qemu_set_info_str(&s->nc, "helper=%s,br=%s", helper, br);
@@ -712,7 +748,10 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
const char *downscript, const char *vhostfdname,
int vnet_hdr, int fd, Error **errp)
{
- TAPState *s = net_tap_new(peer, model, name, tap);
+ TAPState *s = net_tap_new(peer, model, name, tap, vhostfdname, errp);
+ if (!s) {
+ return;
+ }
if (tap->fd || tap->fds) {
qemu_set_info_str(&s->nc, "fd=%d", fd);
@@ -731,53 +770,24 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
}
}
- if (!net_tap_setup(s, tap, vhostfdname, fd, vnet_hdr, errp)) {
+ if (!net_tap_setup(s, fd, vnet_hdr, errp)) {
qemu_del_net_client(&s->nc);
}
}
-static bool net_tap_setup(TAPState *s, const NetdevTapOptions *tap,
- const char *vhostfdname,
- int fd, int vnet_hdr, Error **errp)
+static bool net_tap_setup(TAPState *s, int fd, int vnet_hdr, Error **errp)
{
- int vhostfd;
-
if (!net_tap_set_fd(s, fd, vnet_hdr, errp)) {
return false;
}
- if (tap->has_vhost ? tap->vhost :
- vhostfdname || (tap->has_vhostforce && tap->vhostforce)) {
+ if (s->vhostfd != -1) {
VhostNetOptions options;
options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
options.net_backend = &s->nc;
- if (tap->has_poll_us) {
- options.busyloop_timeout = tap->poll_us;
- } else {
- options.busyloop_timeout = 0;
- }
-
- if (vhostfdname) {
- vhostfd = monitor_fd_param(monitor_cur(), vhostfdname, errp);
- if (vhostfd == -1) {
- return false;
- }
- if (!qemu_set_blocking(vhostfd, false, errp)) {
- return false;
- }
- } else {
- vhostfd = open("/dev/vhost-net", O_RDWR);
- if (vhostfd < 0) {
- error_setg_errno(errp, errno,
- "tap: open vhost char device failed");
- return false;
- }
- if (!qemu_set_blocking(vhostfd, false, errp)) {
- return false;
- }
- }
- options.opaque = (void *)(uintptr_t)vhostfd;
+ options.busyloop_timeout = s->vhost_busyloop_timeout;
+ options.opaque = (void *)(uintptr_t)s->vhostfd;
options.nvqs = 2;
options.feature_bits = kernel_feature_bits;
options.get_acked_features = NULL;
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 13/19] net/tap: finalize net_tap_set_fd() logic
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (11 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 12/19] net/tap: move vhost fd initialization to net_tap_new() Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 14/19] migration: add MIG_EVENT_PRE_INCOMING Vladimir Sementsov-Ogievskiy
` (7 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Let net_tap_set_fd() do only fd-related setup.
Actually, for further backend-transfer migration for virtio-net/tap
we'll want to skip net_tap_set_fd() (as incoming fds are already
prepared by source QEMU). So move tap_read_poll() to net_tap_setup().
Don't care about using_vnet_hdr and vhost_net, the state is
zero-initialized.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
net/tap.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/net/tap.c b/net/tap.c
index dbd1eb3a17..340d8d0cda 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -467,7 +467,6 @@ static bool net_tap_set_fd(TAPState *s, int fd, int vnet_hdr, Error **errp)
{
s->fd = fd;
s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
- s->using_vnet_hdr = false;
s->has_ufo = tap_probe_has_ufo(s->fd);
s->has_uso = tap_probe_has_uso(s->fd);
s->enabled = true;
@@ -479,8 +478,6 @@ static bool net_tap_set_fd(TAPState *s, int fd, int vnet_hdr, Error **errp)
if (vnet_hdr) {
tap_fd_set_vnet_hdr_len(s->fd, s->host_vnet_hdr_len);
}
- tap_read_poll(s, true);
- s->vhost_net = NULL;
if (s->sndbuf) {
Error **e = s->sndbuf_required ? errp : NULL;
@@ -781,6 +778,8 @@ static bool net_tap_setup(TAPState *s, int fd, int vnet_hdr, Error **errp)
return false;
}
+ tap_read_poll(s, true);
+
if (s->vhostfd != -1) {
VhostNetOptions options;
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 14/19] migration: add MIG_EVENT_PRE_INCOMING
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (12 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 13/19] net/tap: finalize net_tap_set_fd() logic Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-09-30 19:25 ` Peter Xu
2025-09-23 10:01 ` [PATCH v6 15/19] net/tap: postpone tap setup to pre-incoming Vladimir Sementsov-Ogievskiy
` (6 subsequent siblings)
20 siblings, 1 reply; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
We are going to implement backend-transfer migration feature for
virtio-net/tap. When it's enabled (by setting migration parameter), TAP
device is passed through migration channel (which should be a unix
socket to pass fds) to a new QEMU.
So we need to know during TAP initialization, should we open TAP
device, or wait for incoming fds. But we can't check for migration
parameter at TAP creation time, as use may set migration parameter
later (especially when TAP is added by command line parameter).
To solve this, we have prepared TAP initialization code so that
opening the device may be postponed to later point. And this later
point is obviously the early beginning of qmp_migrate_incoming():
here we already know all migration parameters and capabilities,
but we are not in downtime, so we can continue initialization
of TAP device.
This commit introduces MIG_EVENT_PRE_INCOMING, to be used by TAP
code in following commit.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
include/migration/misc.h | 1 +
migration/migration.c | 8 +++++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/include/migration/misc.h b/include/migration/misc.h
index a261f99d89..5765fcc204 100644
--- a/include/migration/misc.h
+++ b/include/migration/misc.h
@@ -63,6 +63,7 @@ typedef enum MigrationEventType {
MIG_EVENT_PRECOPY_SETUP,
MIG_EVENT_PRECOPY_DONE,
MIG_EVENT_PRECOPY_FAILED,
+ MIG_EVENT_PRE_INCOMING,
MIG_EVENT_MAX
} MigrationEventType;
diff --git a/migration/migration.c b/migration/migration.c
index e1ac4d73c2..4c356e0b92 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1696,7 +1696,8 @@ int migration_call_notifiers(MigrationState *s, MigrationEventType type,
e.type = type;
ret = notifier_with_return_list_notify(&migration_state_notifiers[mode],
&e, errp);
- assert(!ret || type == MIG_EVENT_PRECOPY_SETUP);
+ assert(!ret || type == MIG_EVENT_PRECOPY_SETUP ||
+ type == MIG_EVENT_PRE_INCOMING);
return ret;
}
@@ -1936,6 +1937,11 @@ void qmp_migrate_incoming(const char *uri, bool has_channels,
return;
}
+ if (migration_call_notifiers(migrate_get_current(), MIG_EVENT_PRE_INCOMING,
+ errp)) {
+ return;
+ }
+
if (!yank_register_instance(MIGRATION_YANK_INSTANCE, errp)) {
return;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 15/19] net/tap: postpone tap setup to pre-incoming
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (13 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 14/19] migration: add MIG_EVENT_PRE_INCOMING Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration Vladimir Sementsov-Ogievskiy
` (5 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
As described in previous commit, to support backend-transfer migration
for virtio-net/tap, we need to postpone the decision to open the device
or to wait for incoming fds up to pre-incoming point (when we actually
can decide).
This commit only postpones TAP-open case of initialization.
We don't try to postpone the all cases of initialization, as it will
require a lot more work of refactoring the code.
So we postpone only the simple case, for which we are going to support
fd-incoming migration:
1. No fds / fd parameters: obviously, if user give fd/fds the should
be used, no incoming backend-transfer migration is possible.
2. No helper: just for simplicity. It probably possible to allow it (and
just ignore in case of backend-transfer migration), to allow user use
same cmdline on target QEMU.. But that questionable, and postponable.
3. No sciprt/downscript. It's not simple to support downscript:
we should pass the responsiblity to call it on target QEMU with
migration.. And back to source QEMU on migration failure. It
feasible, but may be implemented later on demand.
3. Concrete ifname: to not try to share it between queues, when we only
can setup queues as separate entities. Supporting undecided ifname will
require to create some extra netdev state, connecting all the taps, to
be able to iterate through them.
No part of backend-transfer migration is here, we only prepare the code
for future implementation of it.
Are net-drivers prepared to postponed initialization of NICs?
For future feature of backend-transfer migration, we are mainly
interested in virtio-net. So, let's prepare virtio-net to work with
postponed initialization of TAP (two places about early set/get
features) and for other drivers let's simply finalize initialization on
setting netdev property. Support for other drivers may be added later if
needed.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
hw/net/virtio-net.c | 65 ++++++++++++++++-
include/net/tap.h | 2 +
net/tap-win32.c | 5 ++
net/tap.c | 172 +++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 242 insertions(+), 2 deletions(-)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 6b5b5dace3..70f688fc3a 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -688,6 +688,21 @@ default_value:
return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE;
}
+static bool peer_wait_incoming(VirtIONet *n)
+{
+ NetClientState *nc = qemu_get_queue(n->nic);
+
+ if (!nc->peer) {
+ return false;
+ }
+
+ if (nc->peer->info->type != NET_CLIENT_DRIVER_TAP) {
+ return false;
+ }
+
+ return tap_wait_incoming(nc->peer);
+}
+
static int peer_attach(VirtIONet *n, int index)
{
NetClientState *nc = qemu_get_subqueue(n->nic, index);
@@ -2999,7 +3014,17 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
n->multiqueue = multiqueue;
virtio_net_change_num_queues(n, max * 2 + 1);
- virtio_net_set_queue_pairs(n);
+ /*
+ * virtio_net_set_multiqueue() called from set_features(0) on early
+ * reset, when peer may wait for incoming (and is not initialized
+ * yet).
+ * Don't worry about it: virtio_net_set_queue_pairs() will be called
+ * later form virtio_net_post_load_device(), and anyway will be
+ * noop for local incoming migration with live backend passing.
+ */
+ if (!peer_wait_incoming(n)) {
+ virtio_net_set_queue_pairs(n);
+ }
}
static int virtio_net_pre_load_queues(VirtIODevice *vdev, uint32_t n)
@@ -3028,6 +3053,17 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
virtio_add_feature(&features, VIRTIO_NET_F_MAC);
+ if (peer_wait_incoming(n)) {
+ /*
+ * Excessive feature set is OK for early initialization when
+ * we wait for local incoming migration: actual guest-negotiated
+ * features will come with migration stream anyway. And we are sure
+ * that we support same host-features as source, because the backend
+ * is the same (the same TAP device, for example).
+ */
+ return features;
+ }
+
if (!peer_has_vnet_hdr(n)) {
virtio_clear_feature(&features, VIRTIO_NET_F_CSUM);
virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO4);
@@ -3106,6 +3142,32 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
return features;
}
+static int virtio_net_update_host_features(VirtIONet *n)
+{
+ Error *local_err = NULL;
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
+
+ peer_test_vnet_hdr(n);
+
+ vdev->host_features = virtio_net_get_features(vdev, vdev->host_features,
+ &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int virtio_net_pre_load_device(void *opaque)
+{
+ /*
+ * Probably backend initialization was postponed to
+ * pre-incoming point. So, update information now.
+ */
+ return virtio_net_update_host_features(opaque);
+}
+
static int virtio_net_post_load_device(void *opaque, int version_id)
{
VirtIONet *n = opaque;
@@ -3498,6 +3560,7 @@ static const VMStateDescription vmstate_virtio_net_device = {
.name = "virtio-net-device",
.version_id = VIRTIO_NET_VM_VERSION,
.minimum_version_id = VIRTIO_NET_VM_VERSION,
+ .pre_load = virtio_net_pre_load_device,
.post_load = virtio_net_post_load_device,
.fields = (const VMStateField[]) {
VMSTATE_UINT8_ARRAY(mac, VirtIONet, ETH_ALEN),
diff --git a/include/net/tap.h b/include/net/tap.h
index 6f34f13eae..c6f9c1aeb1 100644
--- a/include/net/tap.h
+++ b/include/net/tap.h
@@ -33,4 +33,6 @@ int tap_disable(NetClientState *nc);
int tap_get_fd(NetClientState *nc);
+bool tap_wait_incoming(NetClientState *nc);
+
#endif /* QEMU_NET_TAP_H */
diff --git a/net/tap-win32.c b/net/tap-win32.c
index 38baf90e0b..d526c42b7b 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -766,3 +766,8 @@ int tap_disable(NetClientState *nc)
{
abort();
}
+
+bool tap_wait_incoming(NetClientState *nc)
+{
+ return false;
+}
diff --git a/net/tap.c b/net/tap.c
index 340d8d0cda..b959547492 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -35,7 +35,9 @@
#include "net/eth.h"
#include "net/net.h"
#include "clients.h"
+#include "migration/misc.h"
#include "monitor/monitor.h"
+#include "system/runstate.h"
#include "system/system.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
@@ -85,8 +87,20 @@ typedef struct TAPState {
int sndbuf;
int vhostfd;
uint32_t vhost_busyloop_timeout;
+
+ /* for postponed setup */
+ QTAILQ_ENTRY(TAPState) next;
+ bool vnet_hdr_required;
+ int vnet_hdr;
+ bool mq_required;
+ char *ifname;
} TAPState;
+static QTAILQ_HEAD(, TAPState) postponed_taps =
+ QTAILQ_HEAD_INITIALIZER(postponed_taps);
+static NotifierWithReturn pre_incoming_notifier;
+
+static bool tap_postponed_init(TAPState *s, Error **errp);
static bool net_tap_setup(TAPState *s, int fd, int vnet_hdr, Error **errp);
static void launch_script(const char *setup_script, const char *ifname,
@@ -356,6 +370,8 @@ static void tap_cleanup(NetClientState *nc)
close(s->vhostfd);
s->vhostfd = -1;
}
+
+ g_free(s->ifname);
}
static void tap_poll(NetClientState *nc, bool enable)
@@ -373,6 +389,25 @@ static bool tap_set_steering_ebpf(NetClientState *nc, int prog_fd)
return tap_fd_set_steering_ebpf(s->fd, prog_fd) == 0;
}
+static bool tap_check_peer_type(NetClientState *nc, ObjectClass *oc,
+ Error **errp)
+{
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
+ const char *driver = object_class_get_name(oc);
+
+ if (!g_str_has_prefix(driver, "virtio-net-")) {
+ /*
+ * Only virtio-net support postponed TAP initialization, so
+ * for other drivers let's finalize initialization now.
+ */
+ if (tap_wait_incoming(nc)) {
+ return tap_postponed_init(s, errp);
+ }
+ }
+
+ return true;
+}
+
int tap_get_fd(NetClientState *nc)
{
TAPState *s = DO_UPCAST(TAPState, nc, nc);
@@ -411,6 +446,7 @@ static NetClientInfo net_tap_info = {
.set_vnet_be = tap_set_vnet_be,
.set_steering_ebpf = tap_set_steering_ebpf,
.get_vhost_net = tap_get_vhost_net,
+ .check_peer_type = tap_check_peer_type,
};
static TAPState *net_tap_new(NetClientState *peer, const char *model,
@@ -831,6 +867,124 @@ static int get_fds(char *str, char *fds[], int max)
return i;
}
+#define TAP_OPEN_IFNAME_SZ 128
+
+static bool tap_postponed_init(TAPState *s, Error **errp)
+{
+ char ifname[TAP_OPEN_IFNAME_SZ];
+ int vnet_hdr = s->vnet_hdr;
+ int fd;
+
+ pstrcpy(ifname, sizeof(ifname), s->ifname);
+ fd = net_tap_open(&vnet_hdr, s->vnet_hdr_required, NULL,
+ ifname, sizeof(ifname),
+ s->mq_required, errp);
+ if (fd < 0) {
+ goto fail;
+ }
+
+ if (!net_tap_setup(s, fd, vnet_hdr, errp)) {
+ goto fail;
+ }
+
+ QTAILQ_REMOVE(&postponed_taps, s, next);
+ return true;
+
+fail:
+ QTAILQ_REMOVE(&postponed_taps, s, next);
+ qemu_del_net_client(&s->nc);
+ return false;
+}
+
+static int tap_pre_incoming(NotifierWithReturn *notifier,
+ MigrationEvent *e,
+ Error **errp)
+{
+ TAPState *s;
+ bool ok = true;
+
+ if (e->type != MIG_EVENT_PRE_INCOMING) {
+ return 0;
+ }
+
+ while (!QTAILQ_EMPTY(&postponed_taps)) {
+ s = QTAILQ_FIRST(&postponed_taps);
+ if (ok) {
+ ok = tap_postponed_init(s, errp);
+ } else {
+ QTAILQ_REMOVE(&postponed_taps, s, next);
+ qemu_del_net_client(&s->nc);
+ }
+ }
+
+ return ok ? 0 : -1;
+}
+
+static bool check_no_script(const char *script_arg)
+{
+ return script_arg &&
+ (script_arg[0] == '\0' || strcmp(script_arg, "no") == 0);
+}
+
+static bool tap_postpone_init(const NetdevTapOptions *tap,
+ const char *name, NetClientState *peer,
+ bool *postponed, Error **errp)
+{
+ int queues = tap->has_queues ? tap->queues : 1;
+
+ *postponed = false;
+
+ if (!runstate_check(RUN_STATE_INMIGRATE)) {
+ return true;
+ }
+
+ if (tap->fd || tap->fds || tap->helper || tap->vhostfds) {
+ return true;
+ }
+
+ if (!tap->ifname || tap->ifname[0] == '\0' ||
+ strstr(tap->ifname, "%d") != NULL) {
+ /*
+ * It's hard to postpone logic of parsing template or
+ * absent ifname
+ */
+ return true;
+ }
+
+ /*
+ * Supporting downscipt means understanding and realizing the logic of
+ * transfer of responsibility to call it in target QEMU process. Or in
+ * source QEMU process in case of migration failure. So for simplicity we
+ * don't support scripts together with fds migration.
+ */
+ if (!check_no_script(tap->script) || !check_no_script(tap->downscript)) {
+ return true;
+ }
+
+ for (int i = 0; i < queues; i++) {
+ TAPState *s = net_tap_new(peer, "tap", name, tap, NULL, errp);
+ if (!s) {
+ return false;
+ }
+
+ s->vnet_hdr_required = tap->has_vnet_hdr && tap->vnet_hdr;
+ s->vnet_hdr = tap->has_vnet_hdr ? tap->vnet_hdr : 1;
+ s->mq_required = queues > 1;
+ s->ifname = g_strdup(tap->ifname);
+ qemu_set_info_str(&s->nc, "ifname=%s,script=no,downscript=no",
+ tap->ifname);
+
+ QTAILQ_INSERT_TAIL(&postponed_taps, s, next);
+ }
+
+ if (!pre_incoming_notifier.notify) {
+ migration_add_notifier(&pre_incoming_notifier, tap_pre_incoming);
+ }
+
+ *postponed = true;
+ return true;
+}
+
int net_init_tap(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
{
@@ -839,8 +993,9 @@ int net_init_tap(const Netdev *netdev, const char *name,
/* for the no-fd, no-helper case */
Error *err = NULL;
const char *vhostfdname;
- char ifname[128];
+ char ifname[TAP_OPEN_IFNAME_SZ];
int ret = 0;
+ bool postponed = false;
assert(netdev->type == NET_CLIENT_DRIVER_TAP);
tap = &netdev->u.tap;
@@ -859,6 +1014,14 @@ int net_init_tap(const Netdev *netdev, const char *name,
return -1;
}
+ if (!tap_postpone_init(tap, name, peer, &postponed, errp)) {
+ return -1;
+ }
+
+ if (postponed) {
+ return 0;
+ }
+
if (tap->fd) {
if (tap->ifname || tap->script || tap->downscript ||
tap->has_vnet_hdr || tap->helper || tap->has_queues ||
@@ -1083,3 +1246,10 @@ int tap_disable(NetClientState *nc)
return ret;
}
}
+
+bool tap_wait_incoming(NetClientState *nc)
+{
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
+
+ return s->fd == -1;
+}
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (14 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 15/19] net/tap: postpone tap setup to pre-incoming Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-10-06 13:23 ` Markus Armbruster
2025-09-23 10:01 ` [PATCH v6 17/19] virtio-net: support backend-transfer migration for virtio-net/tap Vladimir Sementsov-Ogievskiy
` (4 subsequent siblings)
20 siblings, 1 reply; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
To migrate virtio-net TAP device backend (including open fds) locally,
user should simply set migration parameter
backend-transfer = ["virtio-net-tap"]
Why not simple boolean? To simplify migration to further versions,
when more devices will support backend-transfer migration.
Alternatively, we may add per-device option to disable backend-transfer
migration, but still:
1. It's more comfortable to set same capabilities/parameters on both
source and target QEMU, than care about each device.
2. To not break the design, that machine-type + device options +
migration capabilities and parameters are fully define the resulting
migration stream. We'll break this if add in future more
backend-transfer support in devices under same backend-transfer=true
parameter.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
include/qapi/util.h | 17 ++++++++++++++++
migration/options.c | 32 ++++++++++++++++++++++++++++++
migration/options.h | 2 ++
qapi/migration.json | 47 ++++++++++++++++++++++++++++++++++++---------
4 files changed, 89 insertions(+), 9 deletions(-)
diff --git a/include/qapi/util.h b/include/qapi/util.h
index 29bc4eb865..b953402416 100644
--- a/include/qapi/util.h
+++ b/include/qapi/util.h
@@ -69,4 +69,21 @@ int parse_qapi_name(const char *name, bool complete);
_len; \
})
+/*
+ * For any GenericList @list, return true if it contains specified
+ * element.
+ */
+#define QAPI_LIST_CONTAINS(list, el) \
+ ({ \
+ bool _found = false; \
+ typeof_strip_qual(list) _tail; \
+ for (_tail = list; _tail != NULL; _tail = _tail->next) { \
+ if (_tail->value == el) { \
+ _found = true; \
+ break; \
+ } \
+ } \
+ _found; \
+ })
+
#endif
diff --git a/migration/options.c b/migration/options.c
index 4e923a2e07..137ca2147e 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
+#include "qapi/util.h"
#include "exec/target_page.h"
#include "qapi/clone-visitor.h"
#include "qapi/error.h"
@@ -262,6 +263,14 @@ bool migrate_mapped_ram(void)
return s->capabilities[MIGRATION_CAPABILITY_MAPPED_RAM];
}
+bool migrate_virtio_net_tap(void)
+{
+ MigrationState *s = migrate_get_current();
+
+ return QAPI_LIST_CONTAINS(s->parameters.backend_transfer,
+ BACKEND_TRANSFER_VIRTIO_NET_TAP);
+}
+
bool migrate_ignore_shared(void)
{
MigrationState *s = migrate_get_current();
@@ -960,6 +969,12 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
params->has_direct_io = true;
params->direct_io = s->parameters.direct_io;
+ if (s->parameters.backend_transfer) {
+ params->has_backend_transfer = true;
+ params->backend_transfer = QAPI_CLONE(BackendTransferList,
+ s->parameters.backend_transfer);
+ }
+
return params;
}
@@ -993,6 +1008,7 @@ void migrate_params_init(MigrationParameters *params)
params->has_mode = true;
params->has_zero_page_detection = true;
params->has_direct_io = true;
+ params->has_backend_transfer = true;
}
/*
@@ -1179,6 +1195,11 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
return false;
}
+ if (params->has_backend_transfer) {
+ error_setg(errp, "Not implemented");
+ return false;
+ }
+
return true;
}
@@ -1297,6 +1318,10 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
if (params->has_direct_io) {
dest->direct_io = params->direct_io;
}
+
+ if (params->has_backend_transfer) {
+ dest->backend_transfer = params->backend_transfer;
+ }
}
static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
@@ -1429,6 +1454,13 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
if (params->has_direct_io) {
s->parameters.direct_io = params->direct_io;
}
+
+ if (params->has_backend_transfer) {
+ qapi_free_BackendTransferList(s->parameters.backend_transfer);
+
+ s->parameters.backend_transfer = QAPI_CLONE(BackendTransferList,
+ params->backend_transfer);
+ }
}
void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
diff --git a/migration/options.h b/migration/options.h
index 82d839709e..55c0345433 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -87,6 +87,8 @@ const char *migrate_tls_hostname(void);
uint64_t migrate_xbzrle_cache_size(void);
ZeroPageDetection migrate_zero_page_detection(void);
+bool migrate_virtio_net_tap(void);
+
/* parameters helpers */
bool migrate_params_check(MigrationParameters *params, Error **errp);
diff --git a/qapi/migration.json b/qapi/migration.json
index 2387c21e9c..e39785dc07 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -747,6 +747,18 @@
'*transform': 'BitmapMigrationBitmapAliasTransform'
} }
+##
+# @BackendTransfer:
+#
+# @virtio-net-tap: Enable backend-transfer migration for virtio-net/tap. When
+# enabled, TAP fds and all related state is passed to target QEMU through
+# migration channel (which should be unix socket).
+#
+# Since: 10.2
+##
+{ 'enum': 'BackendTransfer',
+ 'data': [ 'virtio-net-tap' ] }
+
##
# @BitmapMigrationNodeAlias:
#
@@ -924,10 +936,14 @@
# only has effect if the @mapped-ram capability is enabled.
# (Since 9.1)
#
+# @backend-transfer: List of targets to enable backend-transfer
+# migration for. This requires migration channel to be a unix
+# socket (to pass fds through). (Since 10.2)
+#
# Features:
#
-# @unstable: Members @x-checkpoint-delay and
-# @x-vcpu-dirty-limit-period are experimental.
+# @unstable: Members @x-checkpoint-delay,
+# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
#
# Since: 2.4
##
@@ -950,7 +966,8 @@
'vcpu-dirty-limit',
'mode',
'zero-page-detection',
- 'direct-io'] }
+ 'direct-io',
+ 'backend-transfer' ] }
##
# @MigrateSetParameters:
@@ -1105,10 +1122,14 @@
# only has effect if the @mapped-ram capability is enabled.
# (Since 9.1)
#
+# @backend-transfer: List of targets to enable backend-transfer
+# migration for. This requires migration channel to be a unix
+# socket (to pass fds through). (Since 10.2)
+#
# Features:
#
-# @unstable: Members @x-checkpoint-delay and
-# @x-vcpu-dirty-limit-period are experimental.
+# @unstable: Members @x-checkpoint-delay,
+# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
#
# TODO: either fuse back into `MigrationParameters`, or make
# `MigrationParameters` members mandatory
@@ -1146,7 +1167,9 @@
'*vcpu-dirty-limit': 'uint64',
'*mode': 'MigMode',
'*zero-page-detection': 'ZeroPageDetection',
- '*direct-io': 'bool' } }
+ '*direct-io': 'bool',
+ '*backend-transfer': { 'type': [ 'BackendTransfer' ],
+ 'features': [ 'unstable' ] } } }
##
# @migrate-set-parameters:
@@ -1315,10 +1338,14 @@
# only has effect if the @mapped-ram capability is enabled.
# (Since 9.1)
#
+# @backend-transfer: List of targets to enable backend-transfer
+# migration for. This requires migration channel to be a unix
+# socket (to pass fds through). (Since 10.2)
+#
# Features:
#
-# @unstable: Members @x-checkpoint-delay and
-# @x-vcpu-dirty-limit-period are experimental.
+# @unstable: Members @x-checkpoint-delay,
+# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
#
# Since: 2.4
##
@@ -1353,7 +1380,9 @@
'*vcpu-dirty-limit': 'uint64',
'*mode': 'MigMode',
'*zero-page-detection': 'ZeroPageDetection',
- '*direct-io': 'bool' } }
+ '*direct-io': 'bool',
+ '*backend-transfer': { 'type': [ 'BackendTransfer' ],
+ 'features': [ 'unstable' ] } } }
##
# @query-migrate-parameters:
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 17/19] virtio-net: support backend-transfer migration for virtio-net/tap
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (15 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 18/19] tests/functional: add skipWithoutSudo() decorator Vladimir Sementsov-Ogievskiy
` (3 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Finally implement the new migration option
backend-transfer = ["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 <vsementsov@yandex-team.ru>
---
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 = NULL;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
+ if (peer_wait_incoming(n)) {
+ /* It's too early for updating options. */
+ return 0;
+ }
+
peer_test_vnet_hdr(n);
vdev->host_features = virtio_net_get_features(vdev, vdev->host_features,
@@ -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;
};
/* The 2nd and subsequent tx_waiting flags are loaded later than
@@ -3556,6 +3567,65 @@ static const VMStateDescription vhost_user_net_backend_state = {
}
};
+static bool virtio_net_is_tap_mig(void *opaque, int version_id)
+{
+ VirtIONet *n = opaque;
+ NetClientState *nc;
+
+ nc = qemu_get_queue(n->nic);
+
+ return migrate_virtio_net_tap() && nc->peer &&
+ nc->peer->info->type == NET_CLIENT_DRIVER_TAP;
+}
+
+static int virtio_net_nic_pre_save(void *opaque)
+{
+ struct VirtIONetMigTmp *tmp = opaque;
+
+ tmp->ncs = tmp->parent->nic->ncs;
+ tmp->max_queue_pairs = 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 = opaque;
+
+ return virtio_net_update_host_features(tmp->parent);
+}
+
+static const VMStateDescription vmstate_virtio_net_nic_nc = {
+ .name = "virtio-net-nic-nc",
+ .fields = (const VMStateField[]) {
+ VMSTATE_STRUCT_POINTER(peer, NetClientState, vmstate_tap,
+ NetClientState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_virtio_net_nic = {
+ .name = "virtio-net-nic",
+ .pre_load = virtio_net_nic_pre_load,
+ .pre_save = virtio_net_nic_pre_save,
+ .post_load = virtio_net_nic_post_load,
+ .fields = (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 = {
.name = "virtio-net-device",
.version_id = VIRTIO_NET_VM_VERSION,
@@ -3588,6 +3658,9 @@ static const VMStateDescription vmstate_virtio_net_device = {
* 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
+#include "qemu/typedefs.h"
#include "standard-headers/linux/virtio_net.h"
int tap_enable(NetClientState *nc);
@@ -35,4 +36,6 @@ int tap_get_fd(NetClientState *nc);
bool tap_wait_incoming(NetClientState *nc);
+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 *params, Error **errp)
return false;
}
- if (params->has_backend_transfer) {
- error_setg(errp, "Not implemented");
- return false;
- }
-
return true;
}
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;
static QTAILQ_HEAD(, TAPState) postponed_taps =
@@ -405,6 +407,8 @@ static bool tap_check_peer_type(NetClientState *nc, ObjectClass *oc,
}
}
+ s->attached_to_virtio_net = true;
+
return true;
}
@@ -810,7 +814,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
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 != -1 && !net_tap_set_fd(s, fd, vnet_hdr, errp)) {
return false;
}
@@ -902,6 +906,7 @@ static int tap_pre_incoming(NotifierWithReturn *notifier,
{
TAPState *s;
bool ok = true;
+ bool mig_fds = migrate_virtio_net_tap();
if (e->type != MIG_EVENT_PRE_INCOMING) {
return 0;
@@ -910,6 +915,11 @@ static int tap_pre_incoming(NotifierWithReturn *notifier,
while (!QTAILQ_EMPTY(&postponed_taps)) {
s = 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 = tap_postponed_init(s, errp);
} else {
QTAILQ_REMOVE(&postponed_taps, s, next);
@@ -1247,6 +1257,48 @@ int tap_disable(NetClientState *nc)
}
}
+static int tap_pre_load(void *opaque)
+{
+ TAPState *s = opaque;
+
+ if (s->fd != -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 = opaque;
+ Error *local_err = 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 = {
+ .name = "net-tap",
+ .pre_load = tap_pre_load,
+ .post_load = tap_post_load,
+ .fields = (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 = DO_UPCAST(TAPState, nc, nc);
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 18/19] tests/functional: add skipWithoutSudo() decorator
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (16 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 17/19] virtio-net: support backend-transfer migration for virtio-net/tap Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 19/19] tests/functional: add test_x86_64_tap_migration Vladimir Sementsov-Ogievskiy
` (2 subsequent siblings)
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
To be used in the next commit: that would be a test for TAP
networking, and it will need to setup TAP device.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
tests/functional/qemu_test/decorators.py | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/tests/functional/qemu_test/decorators.py b/tests/functional/qemu_test/decorators.py
index c0d1567b14..d1e97f7995 100644
--- a/tests/functional/qemu_test/decorators.py
+++ b/tests/functional/qemu_test/decorators.py
@@ -6,6 +6,7 @@
import os
import platform
import resource
+import subprocess
from unittest import skipIf, skipUnless
from .cmd import which
@@ -149,3 +150,18 @@ def skipLockedMemoryTest(locked_memory):
ulimit_memory == resource.RLIM_INFINITY or ulimit_memory >= locked_memory * 1024,
f'Test required {locked_memory} kB of available locked memory',
)
+
+'''
+Decorator to skip execution of a test if passwordless
+sudo command is not available.
+'''
+def skipWithoutSudo():
+ proc = subprocess.run(["sudo", "-n", "/bin/true"],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ universal_newlines=True,
+ check=False)
+
+ return skipUnless(proc.returncode == 0,
+ f'requires password-less sudo access: {proc.stdout}')
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v6 19/19] tests/functional: add test_x86_64_tap_migration
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (17 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 18/19] tests/functional: add skipWithoutSudo() decorator Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:01 ` Vladimir Sementsov-Ogievskiy
2025-09-24 8:02 ` [PATCH v6 00/19] virtio-net: live-TAP local migration Lei Yang
2025-10-01 16:33 ` Maksim Davydov
20 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:01 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core, vsementsov
Add test for a new backend-transfer migration of virtio-net/tap, with fd
passing through unix socket.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
tests/functional/test_x86_64_tap_migration.py | 344 ++++++++++++++++++
1 file changed, 344 insertions(+)
create mode 100644 tests/functional/test_x86_64_tap_migration.py
diff --git a/tests/functional/test_x86_64_tap_migration.py b/tests/functional/test_x86_64_tap_migration.py
new file mode 100644
index 0000000000..5337df8aff
--- /dev/null
+++ b/tests/functional/test_x86_64_tap_migration.py
@@ -0,0 +1,344 @@
+#!/usr/bin/env python3
+#
+# Functional test that tests TAP local migration
+# with fd passing
+#
+# Copyright (c) Yandex Technologies LLC, 2025
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import time
+import subprocess
+from subprocess import run
+import signal
+from typing import Tuple
+
+from qemu_test import (
+ LinuxKernelTest,
+ Asset,
+ exec_command_and_wait_for_pattern,
+)
+from qemu_test.decorators import skipWithoutSudo
+
+GUEST_IP = "10.0.1.2"
+GUEST_IP_MASK = f"{GUEST_IP}/24"
+GUEST_MAC = "d6:0d:75:f8:0f:b7"
+HOST_IP = "10.0.1.1"
+HOST_IP_MASK = f"{HOST_IP}/24"
+TAP_ID = "tap0"
+TAP_MAC = "e6:1d:44:b5:03:5d"
+
+
+def del_tap() -> None:
+ run(
+ ["sudo", "ip", "tuntap", "del", TAP_ID, "mode", "tap", "multi_queue"],
+ check=True,
+ )
+
+
+def init_tap() -> None:
+ run(
+ ["sudo", "ip", "tuntap", "add", "dev", TAP_ID, "mode", "tap", "multi_queue"],
+ check=True,
+ )
+ run(["sudo", "ip", "link", "set", "dev", TAP_ID, "address", TAP_MAC], check=True)
+ run(["sudo", "ip", "addr", "add", HOST_IP_MASK, "dev", TAP_ID], check=True)
+ run(["sudo", "ip", "link", "set", TAP_ID, "up"], check=True)
+
+
+def parse_ping_line(line: str) -> float:
+ # suspect lines like
+ # [1748524876.590509] 64 bytes from 94.245.155.3 \
+ # (94.245.155.3): icmp_seq=1 ttl=250 time=101 ms
+ spl = line.split()
+ return float(spl[0][1:-1])
+
+
+def parse_ping_output(out) -> Tuple[bool, float, float]:
+ lines = [x for x in out.split("\n") if x.startswith("[")]
+
+ try:
+ first_no_ans = next(
+ (ind for ind in range(len(lines)) if lines[ind][20:26] == "no ans")
+ )
+ except StopIteration:
+ return False, parse_ping_line(lines[0]), parse_ping_line(lines[-1])
+
+ last_no_ans = next(
+ (ind for ind in range(len(lines) - 1, -1, -1) if lines[ind][20:26] == "no ans")
+ )
+
+ return (
+ True,
+ parse_ping_line(lines[first_no_ans]),
+ parse_ping_line(lines[last_no_ans]),
+ )
+
+
+def wait_migration_finish(source_vm, target_vm):
+ migr_events = (
+ ("MIGRATION", {"data": {"status": "completed"}}),
+ ("MIGRATION", {"data": {"status": "failed"}}),
+ )
+
+ source_e = source_vm.events_wait(migr_events)["data"]
+ target_e = target_vm.events_wait(migr_events)["data"]
+
+ source_s = source_vm.cmd("query-status")["status"]
+ target_s = target_vm.cmd("query-status")["status"]
+
+ assert (
+ source_e["status"] == "completed"
+ and target_e["status"] == "completed"
+ and source_s == "postmigrate"
+ and target_s == "paused"
+ ), f"""Migration failed:
+ SRC status: {source_s}
+ SRC event: {source_e}
+ TGT status: {target_s}
+ TGT event:{target_e}"""
+
+
+@skipWithoutSudo()
+class VhostUserBlkFdMigration(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ (
+ "https://archives.fedoraproject.org/pub/archive/fedora/linux/releases"
+ "/31/Server/x86_64/os/images/pxeboot/vmlinuz"
+ ),
+ "d4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129",
+ )
+
+ ASSET_INITRD = Asset(
+ (
+ "https://archives.fedoraproject.org/pub/archive/fedora/linux/releases"
+ "/31/Server/x86_64/os/images/pxeboot/initrd.img"
+ ),
+ "277cd6c7adf77c7e63d73bbb2cded8ef9e2d3a2f100000e92ff1f8396513cd8b",
+ )
+
+ ASSET_ALPINE_ISO = Asset(
+ (
+ "https://dl-cdn.alpinelinux.org/"
+ "alpine/v3.22/releases/x86_64/alpine-standard-3.22.1-x86_64.iso"
+ ),
+ "96d1b44ea1b8a5a884f193526d92edb4676054e9fa903ad2f016441a0fe13089",
+ )
+
+ def setUp(self):
+ super().setUp()
+
+ init_tap()
+
+ self.outer_ping_proc = None
+
+ def tearDown(self):
+ try:
+ del_tap()
+
+ if self.outer_ping_proc:
+ self.stop_outer_ping()
+ finally:
+ super().tearDown()
+
+ def start_outer_ping(self) -> None:
+ assert self.outer_ping_proc is None
+ self.outer_ping_log = self.scratch_file("ping.log")
+ with open(self.outer_ping_log, "w") as f:
+ self.outer_ping_proc = subprocess.Popen(
+ ["ping", "-i", "0", "-O", "-D", GUEST_IP],
+ text=True,
+ stdout=f,
+ )
+
+ def stop_outer_ping(self) -> str:
+ assert self.outer_ping_proc
+ self.outer_ping_proc.send_signal(signal.SIGINT)
+
+ self.outer_ping_proc.communicate(timeout=5)
+ self.outer_ping_proc = None
+
+ with open(self.outer_ping_log) as f:
+ return f.read()
+
+ def stop_ping_and_check(self, stop_time, resume_time):
+ ping_res = self.stop_outer_ping()
+
+ discon, a, b = parse_ping_output(ping_res)
+
+ if not discon:
+ text = f"STOP: {stop_time}, RESUME: {resume_time}," f"PING: {a} - {b}"
+ if a > stop_time or b < resume_time:
+ self.fail(f"PING failed: {text}")
+ self.log.info(f"PING: no packets lost: {text}")
+ return
+
+ text = (
+ f"STOP: {stop_time}, RESUME: {resume_time}," f"PING: disconnect: {a} - {b}"
+ )
+ self.log.info(text)
+ eps = 0.01
+ if a < stop_time - eps or b > resume_time + eps:
+ self.fail(text)
+
+ def one_ping_from_guest(self, vm) -> None:
+ exec_command_and_wait_for_pattern(
+ self,
+ f"ping -c 1 -W 1 {HOST_IP}",
+ "1 packets transmitted, 1 packets received",
+ "1 packets transmitted, 0 packets received",
+ vm=vm,
+ )
+ self.wait_for_console_pattern("# ", vm=vm)
+
+ def one_ping_from_host(self) -> None:
+ run(["ping", "-c", "1", "-W", "1", GUEST_IP])
+
+ def setup_shared_memory(self):
+ shm_path = f"/dev/shm/qemu_test_{os.getpid()}"
+
+ try:
+ with open(shm_path, "wb") as f:
+ f.write(b"\0" * (1024 * 1024 * 1024)) # 1GB
+ except Exception as e:
+ self.fail(f"Failed to create shared memory file: {e}")
+
+ return shm_path
+
+ def prepare_and_launch_vm(self, shm_path, vhost, incoming=False, vm=None):
+ if not vm:
+ vm = self.vm
+
+ vm.set_console()
+ vm.add_args("-accel", "kvm")
+ vm.add_args("-device", "pcie-pci-bridge,id=pci.1,bus=pcie.0")
+ vm.add_args("-m", "1G")
+
+ vm.add_args(
+ "-object",
+ f"memory-backend-file,id=ram0,size=1G,mem-path={shm_path},share=on",
+ )
+ vm.add_args("-machine", "memory-backend=ram0")
+
+ vm.add_args(
+ "-drive", f"file={self.ASSET_ALPINE_ISO.fetch()},media=cdrom,format=raw"
+ )
+
+ vm.add_args("-S")
+
+ if incoming:
+ vm.add_args("-incoming", "defer")
+
+ vm_s = "target" if incoming else "source"
+ self.log.info(f"Launching {vm_s} VM")
+ vm.launch()
+
+ self.set_migration_capabilities(vm)
+ self.add_virtio_net(vm, vhost)
+
+ def add_virtio_net(self, vm, vhost: bool):
+ netdev_params = {
+ "id": "netdev.1",
+ "vhost": vhost,
+ "type": "tap",
+ "ifname": "tap0",
+ "script": "no",
+ "downscript": "no",
+ "queues": 4,
+ "vnet_hdr": True,
+ }
+
+ vm.cmd("netdev_add", netdev_params)
+
+ vm.cmd(
+ "device_add",
+ driver="virtio-net-pci",
+ romfile="",
+ id="vnet.1",
+ netdev="netdev.1",
+ mq=True,
+ vectors=18,
+ bus="pci.1",
+ mac=GUEST_MAC,
+ disable_legacy="off",
+ )
+
+ def set_migration_capabilities(self, vm):
+ capabilities = [
+ {"capability": "events", "state": True},
+ {"capability": "x-ignore-shared", "state": True},
+ ]
+ vm.cmd("migrate-set-capabilities", {"capabilities": capabilities})
+ vm.cmd("migrate-set-parameters",
+ {"backend-transfer": ["virtio-net-tap"]})
+
+ def setup_guest_network(self) -> None:
+ exec_command_and_wait_for_pattern(self, "ip addr", "# ")
+ exec_command_and_wait_for_pattern(
+ self,
+ f"ip addr add {GUEST_IP_MASK} dev eth0 && ip link set eth0 up && echo OK",
+ "OK",
+ )
+ self.wait_for_console_pattern("# ")
+
+ def do_test_tap_fd_migration(self, vhost):
+ self.require_accelerator("kvm")
+ self.set_machine("q35")
+
+ socket_dir = self.socket_dir()
+ migration_socket = os.path.join(socket_dir.name, "migration.sock")
+
+ shm_path = self.setup_shared_memory()
+
+ self.prepare_and_launch_vm(shm_path, vhost)
+ self.vm.cmd("cont")
+ self.wait_for_console_pattern("login:")
+ exec_command_and_wait_for_pattern(self, "root", "# ")
+
+ self.setup_guest_network()
+
+ self.one_ping_from_guest(self.vm)
+ self.one_ping_from_host()
+ self.start_outer_ping()
+
+ # Get some successful pings before migration
+ time.sleep(0.5)
+
+ target_vm = self.get_vm(name="target")
+ self.prepare_and_launch_vm(shm_path, vhost, incoming=True, vm=target_vm)
+
+ target_vm.cmd("migrate-incoming", {"uri": f"unix:{migration_socket}"})
+
+ self.log.info("Starting migration")
+ freeze_start = time.time()
+ self.vm.cmd("migrate", {"uri": f"unix:{migration_socket}"})
+
+ self.log.info("Waiting for migration completion")
+ wait_migration_finish(self.vm, target_vm)
+
+ target_vm.cmd("cont")
+ freeze_end = time.time()
+
+ self.vm.shutdown()
+
+ self.log.info("Verifying PING on target VM after migration")
+ self.one_ping_from_guest(target_vm)
+ self.one_ping_from_host()
+
+ # And a bit more pings after source shutdown
+ time.sleep(0.3)
+ self.stop_ping_and_check(freeze_start, freeze_end)
+
+ target_vm.shutdown()
+
+ def test_tap_fd_migration(self):
+ self.do_test_tap_fd_migration(False)
+
+ def test_tap_fd_migration_vhost(self):
+ self.do_test_tap_fd_migration(True)
+
+
+if __name__ == "__main__":
+ LinuxKernelTest.main()
--
2.48.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v6 05/19] net/tap: rework scripts handling
2025-09-23 10:00 ` [PATCH v6 05/19] net/tap: rework scripts handling Vladimir Sementsov-Ogievskiy
@ 2025-09-23 10:39 ` Vladimir Sementsov-Ogievskiy
0 siblings, 0 replies; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-09-23 10:39 UTC (permalink / raw)
To: mst
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core
On 23.09.25 13:00, Vladimir Sementsov-Ogievskiy wrote:
> Simplify handling scripts: parse all these "no" and '\0' once, and
> then keep simpler logic for net_tap_open() and net_init_tap_one(): NULL
> means no script to run, otherwise run script.
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> ---
> net/tap.c | 45 +++++++++++++++++++++++++--------------------
> 1 file changed, 25 insertions(+), 20 deletions(-)
>
[..]
> "%s", ifname);
> @@ -950,10 +963,10 @@ free_fail:
> return -1;
> }
> } else {
> - const char *script = tap->script;
> - const char *downscript = tap->downscript;
> - g_autofree char *default_script = NULL;
> - g_autofree char *default_downscript = NULL;
> + g_autofree char *script =
> + tap_parse_script(tap->script, DEFAULT_NETWORK_SCRIPT);
> + g_autofree char *downscript =
> + tap_parse_script(tap->script, DEFAULT_NETWORK_DOWN_SCRIPT);
Ohh, tap->downscript of-course
> bool vnet_hdr_required = tap->has_vnet_hdr && tap->vnet_hdr;
>
> if (tap->vhostfds) {
> @@ -961,14 +974,6 @@ free_fail:
> return -1;
> }
>
--
Best regards,
Vladimir
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v6 00/19] virtio-net: live-TAP local migration
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (18 preceding siblings ...)
2025-09-23 10:01 ` [PATCH v6 19/19] tests/functional: add test_x86_64_tap_migration Vladimir Sementsov-Ogievskiy
@ 2025-09-24 8:02 ` Lei Yang
2025-10-01 16:33 ` Maksim Davydov
20 siblings, 0 replies; 31+ messages in thread
From: Lei Yang @ 2025-09-24 8:02 UTC (permalink / raw)
To: Vladimir Sementsov-Ogievskiy
Cc: mst, qemu-devel, philmd, thuth, eblake, michael.roth, armbru,
farosas, peterx, berrange, jasowang, steven.sistare, davydov-max,
yc-core
Tested this series of patches with virtio-net regression tests,
everything works fine.
Tested-by: Lei Yang <leiyang@redhat.com>
On Tue, Sep 23, 2025 at 6:01 PM Vladimir Sementsov-Ogievskiy
<vsementsov@yandex-team.ru> wrote:
>
> Hi all!
>
> Here is a new migration parameter backend-transfer, which allows to
> enable local migration of TAP virtio-net backend, including its
> properties and open fds.
>
> With this new option, management software doesn't need to
> initialize new TAP and do a switch to it. Nothing should be
> done around virtio-net in local migration: it just migrates
> and continues to use same TAP device. So we avoid extra logic
> in management software, extra allocations in kernel (for new TAP),
> and corresponding extra delay in migration downtime.
>
> v6:
> - rebase on master (to solve conflict with merged
> "io: deal with blocking/non-blocking fds")
> - use name "backend-transfer" for the whole feature consistently
> though the whole series. (live-backend is good, but actually,
> we are already in "live-migration", so every its feature may
> have "live-" prefix, and it seems redundant)
>
> 03-04: new, making changes in 05 correct
> 08-09: split "net/tap: rework tap_set_sndbuf()" into two commits
> 15: fix windows compilation
> 16: move has_ = true, to _params_init
> 18: use shorter name
>
> and some other cosmetic changes.
>
> Vladimir Sementsov-Ogievskiy (19):
> net/tap: net_init_tap_one(): drop extra error propagation
> net/tap: net_init_tap_one(): move parameter checking earlier
> net/tap: rework net_tap_init()
> net/tap: pass NULL to net_init_tap_one() in cases when scripts are
> NULL
> net/tap: rework scripts handling
> net/tap: setup exit notifier only when needed
> net/tap: split net_tap_fd_init()
> net/tap: tap_set_sndbuf(): add return value
> net/tap: rework tap_set_sndbuf()
> net/tap: rework sndbuf handling
> net/tap: introduce net_tap_setup()
> net/tap: move vhost fd initialization to net_tap_new()
> net/tap: finalize net_tap_set_fd() logic
> migration: add MIG_EVENT_PRE_INCOMING
> net/tap: postpone tap setup to pre-incoming
> qapi: add interface for backend-transfer virtio-net/tap migration
> virtio-net: support backend-transfer migration for virtio-net/tap
> tests/functional: add skipWithoutSudo() decorator
> tests/functional: add test_x86_64_tap_migration
>
> hw/net/virtio-net.c | 138 +++++-
> include/migration/misc.h | 1 +
> include/net/tap.h | 5 +
> include/qapi/util.h | 17 +
> migration/migration.c | 8 +-
> migration/options.c | 27 +
> migration/options.h | 2 +
> net/tap-bsd.c | 3 +-
> net/tap-linux.c | 19 +-
> net/tap-solaris.c | 3 +-
> net/tap-stub.c | 3 +-
> net/tap-win32.c | 5 +
> net/tap.c | 467 ++++++++++++++----
> net/tap_int.h | 4 +-
> qapi/migration.json | 47 +-
> tests/functional/qemu_test/decorators.py | 16 +
> tests/functional/test_x86_64_tap_migration.py | 344 +++++++++++++
> 17 files changed, 974 insertions(+), 135 deletions(-)
> create mode 100644 tests/functional/test_x86_64_tap_migration.py
>
> --
> 2.48.1
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v6 14/19] migration: add MIG_EVENT_PRE_INCOMING
2025-09-23 10:01 ` [PATCH v6 14/19] migration: add MIG_EVENT_PRE_INCOMING Vladimir Sementsov-Ogievskiy
@ 2025-09-30 19:25 ` Peter Xu
0 siblings, 0 replies; 31+ messages in thread
From: Peter Xu @ 2025-09-30 19:25 UTC (permalink / raw)
To: Vladimir Sementsov-Ogievskiy
Cc: mst, qemu-devel, philmd, thuth, eblake, michael.roth, armbru,
farosas, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core
On Tue, Sep 23, 2025 at 01:01:05PM +0300, Vladimir Sementsov-Ogievskiy wrote:
> We are going to implement backend-transfer migration feature for
> virtio-net/tap. When it's enabled (by setting migration parameter), TAP
> device is passed through migration channel (which should be a unix
> socket to pass fds) to a new QEMU.
>
> So we need to know during TAP initialization, should we open TAP
> device, or wait for incoming fds. But we can't check for migration
> parameter at TAP creation time, as use may set migration parameter
> later (especially when TAP is added by command line parameter).
>
> To solve this, we have prepared TAP initialization code so that
> opening the device may be postponed to later point. And this later
> point is obviously the early beginning of qmp_migrate_incoming():
> here we already know all migration parameters and capabilities,
> but we are not in downtime, so we can continue initialization
> of TAP device.
>
> This commit introduces MIG_EVENT_PRE_INCOMING, to be used by TAP
> code in following commit.
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Acked-by: Peter Xu <peterx@redhat.com>
--
Peter Xu
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v6 00/19] virtio-net: live-TAP local migration
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
` (19 preceding siblings ...)
2025-09-24 8:02 ` [PATCH v6 00/19] virtio-net: live-TAP local migration Lei Yang
@ 2025-10-01 16:33 ` Maksim Davydov
20 siblings, 0 replies; 31+ messages in thread
From: Maksim Davydov @ 2025-10-01 16:33 UTC (permalink / raw)
To: Vladimir Sementsov-Ogievskiy
Cc: qemu-devel, philmd, thuth, eblake, michael.roth, armbru, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, yc-core, mst
Hi!
With "[PATCH v6 05/19] net/tap: rework scripts handling" fixed
Reviewed-by: davydov-max@yandex-team.ru
On 9/23/25 13:00, Vladimir Sementsov-Ogievskiy wrote:
> Hi all!
>
> Here is a new migration parameter backend-transfer, which allows to
> enable local migration of TAP virtio-net backend, including its
> properties and open fds.
>
> With this new option, management software doesn't need to
> initialize new TAP and do a switch to it. Nothing should be
> done around virtio-net in local migration: it just migrates
> and continues to use same TAP device. So we avoid extra logic
> in management software, extra allocations in kernel (for new TAP),
> and corresponding extra delay in migration downtime.
>
> v6:
> - rebase on master (to solve conflict with merged
> "io: deal with blocking/non-blocking fds")
> - use name "backend-transfer" for the whole feature consistently
> though the whole series. (live-backend is good, but actually,
> we are already in "live-migration", so every its feature may
> have "live-" prefix, and it seems redundant)
>
> 03-04: new, making changes in 05 correct
> 08-09: split "net/tap: rework tap_set_sndbuf()" into two commits
> 15: fix windows compilation
> 16: move has_ = true, to _params_init
> 18: use shorter name
>
> and some other cosmetic changes.
>
> Vladimir Sementsov-Ogievskiy (19):
> net/tap: net_init_tap_one(): drop extra error propagation
> net/tap: net_init_tap_one(): move parameter checking earlier
> net/tap: rework net_tap_init()
> net/tap: pass NULL to net_init_tap_one() in cases when scripts are
> NULL
> net/tap: rework scripts handling
> net/tap: setup exit notifier only when needed
> net/tap: split net_tap_fd_init()
> net/tap: tap_set_sndbuf(): add return value
> net/tap: rework tap_set_sndbuf()
> net/tap: rework sndbuf handling
> net/tap: introduce net_tap_setup()
> net/tap: move vhost fd initialization to net_tap_new()
> net/tap: finalize net_tap_set_fd() logic
> migration: add MIG_EVENT_PRE_INCOMING
> net/tap: postpone tap setup to pre-incoming
> qapi: add interface for backend-transfer virtio-net/tap migration
> virtio-net: support backend-transfer migration for virtio-net/tap
> tests/functional: add skipWithoutSudo() decorator
> tests/functional: add test_x86_64_tap_migration
>
> hw/net/virtio-net.c | 138 +++++-
> include/migration/misc.h | 1 +
> include/net/tap.h | 5 +
> include/qapi/util.h | 17 +
> migration/migration.c | 8 +-
> migration/options.c | 27 +
> migration/options.h | 2 +
> net/tap-bsd.c | 3 +-
> net/tap-linux.c | 19 +-
> net/tap-solaris.c | 3 +-
> net/tap-stub.c | 3 +-
> net/tap-win32.c | 5 +
> net/tap.c | 467 ++++++++++++++----
> net/tap_int.h | 4 +-
> qapi/migration.json | 47 +-
> tests/functional/qemu_test/decorators.py | 16 +
> tests/functional/test_x86_64_tap_migration.py | 344 +++++++++++++
> 17 files changed, 974 insertions(+), 135 deletions(-)
> create mode 100644 tests/functional/test_x86_64_tap_migration.py
>
--
Best regards,
Maksim Davydov
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration
2025-09-23 10:01 ` [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration Vladimir Sementsov-Ogievskiy
@ 2025-10-06 13:23 ` Markus Armbruster
2025-10-06 13:33 ` Michael S. Tsirkin
2025-10-07 8:57 ` Vladimir Sementsov-Ogievskiy
0 siblings, 2 replies; 31+ messages in thread
From: Markus Armbruster @ 2025-10-06 13:23 UTC (permalink / raw)
To: Vladimir Sementsov-Ogievskiy
Cc: mst, qemu-devel, philmd, thuth, eblake, michael.roth, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core
Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:
> To migrate virtio-net TAP device backend (including open fds) locally,
> user should simply set migration parameter
>
> backend-transfer = ["virtio-net-tap"]
>
> Why not simple boolean? To simplify migration to further versions,
> when more devices will support backend-transfer migration.
>
> Alternatively, we may add per-device option to disable backend-transfer
> migration, but still:
>
> 1. It's more comfortable to set same capabilities/parameters on both
> source and target QEMU, than care about each device.
>
> 2. To not break the design, that machine-type + device options +
> migration capabilities and parameters are fully define the resulting
> migration stream. We'll break this if add in future more
> backend-transfer support in devices under same backend-transfer=true
> parameter.
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> ---
> include/qapi/util.h | 17 ++++++++++++++++
> migration/options.c | 32 ++++++++++++++++++++++++++++++
> migration/options.h | 2 ++
> qapi/migration.json | 47 ++++++++++++++++++++++++++++++++++++---------
> 4 files changed, 89 insertions(+), 9 deletions(-)
>
> diff --git a/include/qapi/util.h b/include/qapi/util.h
> index 29bc4eb865..b953402416 100644
> --- a/include/qapi/util.h
> +++ b/include/qapi/util.h
> @@ -69,4 +69,21 @@ int parse_qapi_name(const char *name, bool complete);
> _len; \
> })
>
> +/*
> + * For any GenericList @list, return true if it contains specified
> + * element.
> + */
> +#define QAPI_LIST_CONTAINS(list, el) \
> + ({ \
> + bool _found = false; \
> + typeof_strip_qual(list) _tail; \
> + for (_tail = list; _tail != NULL; _tail = _tail->next) { \
> + if (_tail->value == el) { \
> + _found = true; \
> + break; \
> + } \
> + } \
> + _found; \
> + })
> +
Not a fan of lengthy macros.
There's a single use below: migrate_virtio_net_tap(). I can't see
potential uses for such a search in existing code.
Open-code it in migrate_virtio_net_tap()?
> #endif
> diff --git a/migration/options.c b/migration/options.c
> index 4e923a2e07..137ca2147e 100644
> --- a/migration/options.c
> +++ b/migration/options.c
> @@ -13,6 +13,7 @@
>
> #include "qemu/osdep.h"
> #include "qemu/error-report.h"
> +#include "qapi/util.h"
> #include "exec/target_page.h"
> #include "qapi/clone-visitor.h"
> #include "qapi/error.h"
> @@ -262,6 +263,14 @@ bool migrate_mapped_ram(void)
> return s->capabilities[MIGRATION_CAPABILITY_MAPPED_RAM];
> }
>
> +bool migrate_virtio_net_tap(void)
> +{
> + MigrationState *s = migrate_get_current();
> +
> + return QAPI_LIST_CONTAINS(s->parameters.backend_transfer,
> + BACKEND_TRANSFER_VIRTIO_NET_TAP);
> +}
> +
> bool migrate_ignore_shared(void)
> {
> MigrationState *s = migrate_get_current();
> @@ -960,6 +969,12 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
> params->has_direct_io = true;
> params->direct_io = s->parameters.direct_io;
>
> + if (s->parameters.backend_transfer) {
> + params->has_backend_transfer = true;
> + params->backend_transfer = QAPI_CLONE(BackendTransferList,
> + s->parameters.backend_transfer);
> + }
> +
> return params;
> }
>
> @@ -993,6 +1008,7 @@ void migrate_params_init(MigrationParameters *params)
> params->has_mode = true;
> params->has_zero_page_detection = true;
> params->has_direct_io = true;
> + params->has_backend_transfer = true;
> }
>
> /*
> @@ -1179,6 +1195,11 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
> return false;
> }
>
> + if (params->has_backend_transfer) {
> + error_setg(errp, "Not implemented");
> + return false;
> + }
> +
This goes away in the next patch. Fine, but mentioning the gap in the
commit message can save reviewer a bit of work.
> return true;
> }
>
> @@ -1297,6 +1318,10 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
> if (params->has_direct_io) {
> dest->direct_io = params->direct_io;
> }
> +
> + if (params->has_backend_transfer) {
> + dest->backend_transfer = params->backend_transfer;
> + }
> }
>
> static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
> @@ -1429,6 +1454,13 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
> if (params->has_direct_io) {
> s->parameters.direct_io = params->direct_io;
> }
> +
> + if (params->has_backend_transfer) {
> + qapi_free_BackendTransferList(s->parameters.backend_transfer);
> +
> + s->parameters.backend_transfer = QAPI_CLONE(BackendTransferList,
> + params->backend_transfer);
> + }
> }
>
> void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
> diff --git a/migration/options.h b/migration/options.h
> index 82d839709e..55c0345433 100644
> --- a/migration/options.h
> +++ b/migration/options.h
> @@ -87,6 +87,8 @@ const char *migrate_tls_hostname(void);
> uint64_t migrate_xbzrle_cache_size(void);
> ZeroPageDetection migrate_zero_page_detection(void);
>
> +bool migrate_virtio_net_tap(void);
> +
> /* parameters helpers */
>
> bool migrate_params_check(MigrationParameters *params, Error **errp);
> diff --git a/qapi/migration.json b/qapi/migration.json
> index 2387c21e9c..e39785dc07 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -747,6 +747,18 @@
> '*transform': 'BitmapMigrationBitmapAliasTransform'
> } }
>
> +##
> +# @BackendTransfer:
> +#
> +# @virtio-net-tap: Enable backend-transfer migration for virtio-net/tap. When
> +# enabled, TAP fds and all related state is passed to target QEMU through
> +# migration channel (which should be unix socket).
Suggest "are passed to the destination in the migration channel" and
"should be a UNIX domain socket".
docs/devel/qapi-code-gen.rst:
For legibility, wrap text paragraphs so every line is at most 70
characters long.
Separate sentences with two spaces.
> +#
> +# Since: 10.2
> +##
> +{ 'enum': 'BackendTransfer',
> + 'data': [ 'virtio-net-tap' ] }
> +
> ##
> # @BitmapMigrationNodeAlias:
> #
> @@ -924,10 +936,14 @@
> # only has effect if the @mapped-ram capability is enabled.
> # (Since 9.1)
> #
> +# @backend-transfer: List of targets to enable backend-transfer
> +# migration for. This requires migration channel to be a unix
> +# socket (to pass fds through). (Since 10.2)
Elsewhere, we describe the same restriction like this:
This CPR channel must support
# file descriptor transfer with SCM_RIGHTS, i.e. it must be a
# UNIX domain socket.
> +#
> # Features:
> #
> -# @unstable: Members @x-checkpoint-delay and
> -# @x-vcpu-dirty-limit-period are experimental.
> +# @unstable: Members @x-checkpoint-delay,
> +# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
List members in alphabetical order, please.
> #
> # Since: 2.4
> ##
> @@ -950,7 +966,8 @@
> 'vcpu-dirty-limit',
> 'mode',
> 'zero-page-detection',
> - 'direct-io'] }
> + 'direct-io',
> + 'backend-transfer' ] }
Forgot feature 'unstable'?
>
> ##
> # @MigrateSetParameters:
> @@ -1105,10 +1122,14 @@
> # only has effect if the @mapped-ram capability is enabled.
> # (Since 9.1)
> #
> +# @backend-transfer: List of targets to enable backend-transfer
> +# migration for. This requires migration channel to be a unix
> +# socket (to pass fds through). (Since 10.2)
> +#
> # Features:
> #
> -# @unstable: Members @x-checkpoint-delay and
> -# @x-vcpu-dirty-limit-period are experimental.
> +# @unstable: Members @x-checkpoint-delay,
> +# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
> #
> # TODO: either fuse back into `MigrationParameters`, or make
> # `MigrationParameters` members mandatory
> @@ -1146,7 +1167,9 @@
> '*vcpu-dirty-limit': 'uint64',
> '*mode': 'MigMode',
> '*zero-page-detection': 'ZeroPageDetection',
> - '*direct-io': 'bool' } }
> + '*direct-io': 'bool',
> + '*backend-transfer': { 'type': [ 'BackendTransfer' ],
> + 'features': [ 'unstable' ] } } }
>
> ##
> # @migrate-set-parameters:
> @@ -1315,10 +1338,14 @@
> # only has effect if the @mapped-ram capability is enabled.
> # (Since 9.1)
> #
> +# @backend-transfer: List of targets to enable backend-transfer
> +# migration for. This requires migration channel to be a unix
> +# socket (to pass fds through). (Since 10.2)
> +#
> # Features:
> #
> -# @unstable: Members @x-checkpoint-delay and
> -# @x-vcpu-dirty-limit-period are experimental.
> +# @unstable: Members @x-checkpoint-delay,
> +# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
> #
> # Since: 2.4
> ##
> @@ -1353,7 +1380,9 @@
> '*vcpu-dirty-limit': 'uint64',
> '*mode': 'MigMode',
> '*zero-page-detection': 'ZeroPageDetection',
> - '*direct-io': 'bool' } }
> + '*direct-io': 'bool',
> + '*backend-transfer': { 'type': [ 'BackendTransfer' ],
> + 'features': [ 'unstable' ] } } }
>
> ##
> # @query-migrate-parameters:
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration
2025-10-06 13:23 ` Markus Armbruster
@ 2025-10-06 13:33 ` Michael S. Tsirkin
2025-10-06 14:38 ` Markus Armbruster
2025-10-07 8:57 ` Vladimir Sementsov-Ogievskiy
1 sibling, 1 reply; 31+ messages in thread
From: Michael S. Tsirkin @ 2025-10-06 13:33 UTC (permalink / raw)
To: Markus Armbruster
Cc: Vladimir Sementsov-Ogievskiy, qemu-devel, philmd, thuth, eblake,
michael.roth, farosas, peterx, berrange, jasowang, steven.sistare,
leiyang, davydov-max, yc-core
On Mon, Oct 06, 2025 at 03:23:06PM +0200, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:
>
> > To migrate virtio-net TAP device backend (including open fds) locally,
> > user should simply set migration parameter
> >
> > backend-transfer = ["virtio-net-tap"]
> >
> > Why not simple boolean? To simplify migration to further versions,
> > when more devices will support backend-transfer migration.
> >
> > Alternatively, we may add per-device option to disable backend-transfer
> > migration, but still:
> >
> > 1. It's more comfortable to set same capabilities/parameters on both
> > source and target QEMU, than care about each device.
> >
> > 2. To not break the design, that machine-type + device options +
> > migration capabilities and parameters are fully define the resulting
> > migration stream. We'll break this if add in future more
> > backend-transfer support in devices under same backend-transfer=true
> > parameter.
> >
> > Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> > ---
> > include/qapi/util.h | 17 ++++++++++++++++
> > migration/options.c | 32 ++++++++++++++++++++++++++++++
> > migration/options.h | 2 ++
> > qapi/migration.json | 47 ++++++++++++++++++++++++++++++++++++---------
> > 4 files changed, 89 insertions(+), 9 deletions(-)
> >
> > diff --git a/include/qapi/util.h b/include/qapi/util.h
> > index 29bc4eb865..b953402416 100644
> > --- a/include/qapi/util.h
> > +++ b/include/qapi/util.h
> > @@ -69,4 +69,21 @@ int parse_qapi_name(const char *name, bool complete);
> > _len; \
> > })
> >
> > +/*
> > + * For any GenericList @list, return true if it contains specified
> > + * element.
> > + */
> > +#define QAPI_LIST_CONTAINS(list, el) \
> > + ({ \
> > + bool _found = false; \
> > + typeof_strip_qual(list) _tail; \
> > + for (_tail = list; _tail != NULL; _tail = _tail->next) { \
> > + if (_tail->value == el) { \
> > + _found = true; \
> > + break; \
> > + } \
> > + } \
> > + _found; \
> > + })
> > +
>
> Not a fan of lengthy macros.
>
> There's a single use below: migrate_virtio_net_tap(). I can't see
> potential uses for such a search in existing code.
However, QAPI_LIST_FOR_EACH can potentially be used to implement
QAPI_LIST_LENGTH.
#define QAPI_LIST_FOR_EACH(list, tail) \
for (tail = list; tail != NULL; tail = tail->next)
and
#define QAPI_LIST_LENGTH(list) \
({ \
size_t _len = 0; \
typeof_strip_qual(list) _tail; \
QAPI_LIST_FOR_EACH(list, tail) { \
_len++; \
} \
_len; \
})
> Open-code it in migrate_virtio_net_tap()?
>
> > #endif
> > diff --git a/migration/options.c b/migration/options.c
> > index 4e923a2e07..137ca2147e 100644
> > --- a/migration/options.c
> > +++ b/migration/options.c
> > @@ -13,6 +13,7 @@
> >
> > #include "qemu/osdep.h"
> > #include "qemu/error-report.h"
> > +#include "qapi/util.h"
> > #include "exec/target_page.h"
> > #include "qapi/clone-visitor.h"
> > #include "qapi/error.h"
> > @@ -262,6 +263,14 @@ bool migrate_mapped_ram(void)
> > return s->capabilities[MIGRATION_CAPABILITY_MAPPED_RAM];
> > }
> >
> > +bool migrate_virtio_net_tap(void)
> > +{
> > + MigrationState *s = migrate_get_current();
> > +
> > + return QAPI_LIST_CONTAINS(s->parameters.backend_transfer,
> > + BACKEND_TRANSFER_VIRTIO_NET_TAP);
> > +}
> > +
> > bool migrate_ignore_shared(void)
> > {
> > MigrationState *s = migrate_get_current();
> > @@ -960,6 +969,12 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
> > params->has_direct_io = true;
> > params->direct_io = s->parameters.direct_io;
> >
> > + if (s->parameters.backend_transfer) {
> > + params->has_backend_transfer = true;
> > + params->backend_transfer = QAPI_CLONE(BackendTransferList,
> > + s->parameters.backend_transfer);
> > + }
> > +
> > return params;
> > }
> >
> > @@ -993,6 +1008,7 @@ void migrate_params_init(MigrationParameters *params)
> > params->has_mode = true;
> > params->has_zero_page_detection = true;
> > params->has_direct_io = true;
> > + params->has_backend_transfer = true;
> > }
> >
> > /*
> > @@ -1179,6 +1195,11 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
> > return false;
> > }
> >
> > + if (params->has_backend_transfer) {
> > + error_setg(errp, "Not implemented");
> > + return false;
> > + }
> > +
>
> This goes away in the next patch. Fine, but mentioning the gap in the
> commit message can save reviewer a bit of work.
>
> > return true;
> > }
> >
> > @@ -1297,6 +1318,10 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
> > if (params->has_direct_io) {
> > dest->direct_io = params->direct_io;
> > }
> > +
> > + if (params->has_backend_transfer) {
> > + dest->backend_transfer = params->backend_transfer;
> > + }
> > }
> >
> > static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
> > @@ -1429,6 +1454,13 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
> > if (params->has_direct_io) {
> > s->parameters.direct_io = params->direct_io;
> > }
> > +
> > + if (params->has_backend_transfer) {
> > + qapi_free_BackendTransferList(s->parameters.backend_transfer);
> > +
> > + s->parameters.backend_transfer = QAPI_CLONE(BackendTransferList,
> > + params->backend_transfer);
> > + }
> > }
> >
> > void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
> > diff --git a/migration/options.h b/migration/options.h
> > index 82d839709e..55c0345433 100644
> > --- a/migration/options.h
> > +++ b/migration/options.h
> > @@ -87,6 +87,8 @@ const char *migrate_tls_hostname(void);
> > uint64_t migrate_xbzrle_cache_size(void);
> > ZeroPageDetection migrate_zero_page_detection(void);
> >
> > +bool migrate_virtio_net_tap(void);
> > +
> > /* parameters helpers */
> >
> > bool migrate_params_check(MigrationParameters *params, Error **errp);
> > diff --git a/qapi/migration.json b/qapi/migration.json
> > index 2387c21e9c..e39785dc07 100644
> > --- a/qapi/migration.json
> > +++ b/qapi/migration.json
> > @@ -747,6 +747,18 @@
> > '*transform': 'BitmapMigrationBitmapAliasTransform'
> > } }
> >
> > +##
> > +# @BackendTransfer:
> > +#
> > +# @virtio-net-tap: Enable backend-transfer migration for virtio-net/tap. When
> > +# enabled, TAP fds and all related state is passed to target QEMU through
> > +# migration channel (which should be unix socket).
>
> Suggest "are passed to the destination in the migration channel" and
> "should be a UNIX domain socket".
>
> docs/devel/qapi-code-gen.rst:
>
> For legibility, wrap text paragraphs so every line is at most 70
> characters long.
>
> Separate sentences with two spaces.
>
> > +#
> > +# Since: 10.2
> > +##
> > +{ 'enum': 'BackendTransfer',
> > + 'data': [ 'virtio-net-tap' ] }
> > +
> > ##
> > # @BitmapMigrationNodeAlias:
> > #
> > @@ -924,10 +936,14 @@
> > # only has effect if the @mapped-ram capability is enabled.
> > # (Since 9.1)
> > #
> > +# @backend-transfer: List of targets to enable backend-transfer
> > +# migration for. This requires migration channel to be a unix
> > +# socket (to pass fds through). (Since 10.2)
>
> Elsewhere, we describe the same restriction like this:
>
> This CPR channel must support
> # file descriptor transfer with SCM_RIGHTS, i.e. it must be a
> # UNIX domain socket.
>
> > +#
> > # Features:
> > #
> > -# @unstable: Members @x-checkpoint-delay and
> > -# @x-vcpu-dirty-limit-period are experimental.
> > +# @unstable: Members @x-checkpoint-delay,
> > +# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
>
> List members in alphabetical order, please.
>
> > #
> > # Since: 2.4
> > ##
> > @@ -950,7 +966,8 @@
> > 'vcpu-dirty-limit',
> > 'mode',
> > 'zero-page-detection',
> > - 'direct-io'] }
> > + 'direct-io',
> > + 'backend-transfer' ] }
>
> Forgot feature 'unstable'?
>
> >
> > ##
> > # @MigrateSetParameters:
> > @@ -1105,10 +1122,14 @@
> > # only has effect if the @mapped-ram capability is enabled.
> > # (Since 9.1)
> > #
> > +# @backend-transfer: List of targets to enable backend-transfer
> > +# migration for. This requires migration channel to be a unix
> > +# socket (to pass fds through). (Since 10.2)
> > +#
> > # Features:
> > #
> > -# @unstable: Members @x-checkpoint-delay and
> > -# @x-vcpu-dirty-limit-period are experimental.
> > +# @unstable: Members @x-checkpoint-delay,
> > +# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
> > #
> > # TODO: either fuse back into `MigrationParameters`, or make
> > # `MigrationParameters` members mandatory
> > @@ -1146,7 +1167,9 @@
> > '*vcpu-dirty-limit': 'uint64',
> > '*mode': 'MigMode',
> > '*zero-page-detection': 'ZeroPageDetection',
> > - '*direct-io': 'bool' } }
> > + '*direct-io': 'bool',
> > + '*backend-transfer': { 'type': [ 'BackendTransfer' ],
> > + 'features': [ 'unstable' ] } } }
> >
> > ##
> > # @migrate-set-parameters:
> > @@ -1315,10 +1338,14 @@
> > # only has effect if the @mapped-ram capability is enabled.
> > # (Since 9.1)
> > #
> > +# @backend-transfer: List of targets to enable backend-transfer
> > +# migration for. This requires migration channel to be a unix
> > +# socket (to pass fds through). (Since 10.2)
> > +#
> > # Features:
> > #
> > -# @unstable: Members @x-checkpoint-delay and
> > -# @x-vcpu-dirty-limit-period are experimental.
> > +# @unstable: Members @x-checkpoint-delay,
> > +# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
> > #
> > # Since: 2.4
> > ##
> > @@ -1353,7 +1380,9 @@
> > '*vcpu-dirty-limit': 'uint64',
> > '*mode': 'MigMode',
> > '*zero-page-detection': 'ZeroPageDetection',
> > - '*direct-io': 'bool' } }
> > + '*direct-io': 'bool',
> > + '*backend-transfer': { 'type': [ 'BackendTransfer' ],
> > + 'features': [ 'unstable' ] } } }
> >
> > ##
> > # @query-migrate-parameters:
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration
2025-10-06 13:33 ` Michael S. Tsirkin
@ 2025-10-06 14:38 ` Markus Armbruster
2025-10-06 14:55 ` Michael S. Tsirkin
0 siblings, 1 reply; 31+ messages in thread
From: Markus Armbruster @ 2025-10-06 14:38 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Vladimir Sementsov-Ogievskiy, qemu-devel, philmd, thuth, eblake,
michael.roth, farosas, peterx, berrange, jasowang, steven.sistare,
leiyang, davydov-max, yc-core
"Michael S. Tsirkin" <mst@redhat.com> writes:
> On Mon, Oct 06, 2025 at 03:23:06PM +0200, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:
>>
>> > To migrate virtio-net TAP device backend (including open fds) locally,
>> > user should simply set migration parameter
>> >
>> > backend-transfer = ["virtio-net-tap"]
>> >
>> > Why not simple boolean? To simplify migration to further versions,
>> > when more devices will support backend-transfer migration.
>> >
>> > Alternatively, we may add per-device option to disable backend-transfer
>> > migration, but still:
>> >
>> > 1. It's more comfortable to set same capabilities/parameters on both
>> > source and target QEMU, than care about each device.
>> >
>> > 2. To not break the design, that machine-type + device options +
>> > migration capabilities and parameters are fully define the resulting
>> > migration stream. We'll break this if add in future more
>> > backend-transfer support in devices under same backend-transfer=true
>> > parameter.
>> >
>> > Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
>> > ---
>> > include/qapi/util.h | 17 ++++++++++++++++
>> > migration/options.c | 32 ++++++++++++++++++++++++++++++
>> > migration/options.h | 2 ++
>> > qapi/migration.json | 47 ++++++++++++++++++++++++++++++++++++---------
>> > 4 files changed, 89 insertions(+), 9 deletions(-)
>> >
>> > diff --git a/include/qapi/util.h b/include/qapi/util.h
>> > index 29bc4eb865..b953402416 100644
>> > --- a/include/qapi/util.h
>> > +++ b/include/qapi/util.h
>> > @@ -69,4 +69,21 @@ int parse_qapi_name(const char *name, bool complete);
>> > _len; \
>> > })
>> >
>> > +/*
>> > + * For any GenericList @list, return true if it contains specified
>> > + * element.
>> > + */
>> > +#define QAPI_LIST_CONTAINS(list, el) \
>> > + ({ \
>> > + bool _found = false; \
>> > + typeof_strip_qual(list) _tail; \
>> > + for (_tail = list; _tail != NULL; _tail = _tail->next) { \
>> > + if (_tail->value == el) { \
>> > + _found = true; \
>> > + break; \
>> > + } \
>> > + } \
>> > + _found; \
>> > + })
>> > +
>>
>> Not a fan of lengthy macros.
>>
>> There's a single use below: migrate_virtio_net_tap(). I can't see
>> potential uses for such a search in existing code.
>
> However, QAPI_LIST_FOR_EACH can potentially be used to implement
> QAPI_LIST_LENGTH.
>
> #define QAPI_LIST_FOR_EACH(list, tail) \
> for (tail = list; tail != NULL; tail = tail->next)
>
> and
>
> #define QAPI_LIST_LENGTH(list) \
> ({ \
> size_t _len = 0; \
> typeof_strip_qual(list) _tail; \
> QAPI_LIST_FOR_EACH(list, tail) { \
> _len++; \
> } \
> _len; \
> })
Yes, but would QAPI_LIST_FOR_EACH be better than the straightfoward &
simple for-loop?
[...]
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration
2025-10-06 14:38 ` Markus Armbruster
@ 2025-10-06 14:55 ` Michael S. Tsirkin
2025-10-06 17:06 ` Markus Armbruster
0 siblings, 1 reply; 31+ messages in thread
From: Michael S. Tsirkin @ 2025-10-06 14:55 UTC (permalink / raw)
To: Markus Armbruster
Cc: Vladimir Sementsov-Ogievskiy, qemu-devel, philmd, thuth, eblake,
michael.roth, farosas, peterx, berrange, jasowang, steven.sistare,
leiyang, davydov-max, yc-core
On Mon, Oct 06, 2025 at 04:38:32PM +0200, Markus Armbruster wrote:
> "Michael S. Tsirkin" <mst@redhat.com> writes:
>
> > On Mon, Oct 06, 2025 at 03:23:06PM +0200, Markus Armbruster wrote:
> >> Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:
> >>
> >> > To migrate virtio-net TAP device backend (including open fds) locally,
> >> > user should simply set migration parameter
> >> >
> >> > backend-transfer = ["virtio-net-tap"]
> >> >
> >> > Why not simple boolean? To simplify migration to further versions,
> >> > when more devices will support backend-transfer migration.
> >> >
> >> > Alternatively, we may add per-device option to disable backend-transfer
> >> > migration, but still:
> >> >
> >> > 1. It's more comfortable to set same capabilities/parameters on both
> >> > source and target QEMU, than care about each device.
> >> >
> >> > 2. To not break the design, that machine-type + device options +
> >> > migration capabilities and parameters are fully define the resulting
> >> > migration stream. We'll break this if add in future more
> >> > backend-transfer support in devices under same backend-transfer=true
> >> > parameter.
> >> >
> >> > Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> >> > ---
> >> > include/qapi/util.h | 17 ++++++++++++++++
> >> > migration/options.c | 32 ++++++++++++++++++++++++++++++
> >> > migration/options.h | 2 ++
> >> > qapi/migration.json | 47 ++++++++++++++++++++++++++++++++++++---------
> >> > 4 files changed, 89 insertions(+), 9 deletions(-)
> >> >
> >> > diff --git a/include/qapi/util.h b/include/qapi/util.h
> >> > index 29bc4eb865..b953402416 100644
> >> > --- a/include/qapi/util.h
> >> > +++ b/include/qapi/util.h
> >> > @@ -69,4 +69,21 @@ int parse_qapi_name(const char *name, bool complete);
> >> > _len; \
> >> > })
> >> >
> >> > +/*
> >> > + * For any GenericList @list, return true if it contains specified
> >> > + * element.
> >> > + */
> >> > +#define QAPI_LIST_CONTAINS(list, el) \
> >> > + ({ \
> >> > + bool _found = false; \
> >> > + typeof_strip_qual(list) _tail; \
> >> > + for (_tail = list; _tail != NULL; _tail = _tail->next) { \
> >> > + if (_tail->value == el) { \
> >> > + _found = true; \
> >> > + break; \
> >> > + } \
> >> > + } \
> >> > + _found; \
> >> > + })
> >> > +
> >>
> >> Not a fan of lengthy macros.
> >>
> >> There's a single use below: migrate_virtio_net_tap(). I can't see
> >> potential uses for such a search in existing code.
> >
> > However, QAPI_LIST_FOR_EACH can potentially be used to implement
> > QAPI_LIST_LENGTH.
> >
> > #define QAPI_LIST_FOR_EACH(list, tail) \
> > for (tail = list; tail != NULL; tail = tail->next)
> >
> > and
> >
> > #define QAPI_LIST_LENGTH(list) \
> > ({ \
> > size_t _len = 0; \
> > typeof_strip_qual(list) _tail; \
> > QAPI_LIST_FOR_EACH(list, tail) { \
> > _len++; \
> > } \
> > _len; \
> > })
>
> Yes, but would QAPI_LIST_FOR_EACH be better than the straightfoward &
> simple for-loop?
>
> [...]
Well I don't really remember off hand how QAPI lists work so for me I'd
have to otherwise go read the code to check this is the right way to
walk this list.
Which reminds me, why are these custom like this and not just QLIST?
--
MST
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration
2025-10-06 14:55 ` Michael S. Tsirkin
@ 2025-10-06 17:06 ` Markus Armbruster
0 siblings, 0 replies; 31+ messages in thread
From: Markus Armbruster @ 2025-10-06 17:06 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Vladimir Sementsov-Ogievskiy, qemu-devel, philmd, thuth, eblake,
michael.roth, farosas, peterx, berrange, jasowang, steven.sistare,
leiyang, davydov-max, yc-core
"Michael S. Tsirkin" <mst@redhat.com> writes:
> On Mon, Oct 06, 2025 at 04:38:32PM +0200, Markus Armbruster wrote:
>> "Michael S. Tsirkin" <mst@redhat.com> writes:
>> > However, QAPI_LIST_FOR_EACH can potentially be used to implement
>> > QAPI_LIST_LENGTH.
>> >
>> > #define QAPI_LIST_FOR_EACH(list, tail) \
>> > for (tail = list; tail != NULL; tail = tail->next)
>> >
>> > and
>> >
>> > #define QAPI_LIST_LENGTH(list) \
>> > ({ \
>> > size_t _len = 0; \
>> > typeof_strip_qual(list) _tail; \
>> > QAPI_LIST_FOR_EACH(list, tail) { \
>> > _len++; \
>> > } \
>> > _len; \
>> > })
>>
>> Yes, but would QAPI_LIST_FOR_EACH be better than the straightfoward &
>> simple for-loop?
>>
>> [...]
>
> Well I don't really remember off hand how QAPI lists work so for me I'd
> have to otherwise go read the code to check this is the right way to
> walk this list.
>
> Which reminds me, why are these custom like this and not just QLIST?
Beats me, I inherited them :)
A linked list would not be my choice for representing JSON arrays.
Bigger fish to fry...
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration
2025-10-06 13:23 ` Markus Armbruster
2025-10-06 13:33 ` Michael S. Tsirkin
@ 2025-10-07 8:57 ` Vladimir Sementsov-Ogievskiy
2025-10-07 11:42 ` Markus Armbruster
1 sibling, 1 reply; 31+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2025-10-07 8:57 UTC (permalink / raw)
To: Markus Armbruster
Cc: mst, qemu-devel, philmd, thuth, eblake, michael.roth, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core
On 06.10.25 16:23, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:
>
>> To migrate virtio-net TAP device backend (including open fds) locally,
>> user should simply set migration parameter
>>
>> backend-transfer = ["virtio-net-tap"]
>>
>> Why not simple boolean? To simplify migration to further versions,
>> when more devices will support backend-transfer migration.
>>
>> Alternatively, we may add per-device option to disable backend-transfer
>> migration, but still:
>>
>> 1. It's more comfortable to set same capabilities/parameters on both
>> source and target QEMU, than care about each device.
>>
>> 2. To not break the design, that machine-type + device options +
>> migration capabilities and parameters are fully define the resulting
>> migration stream. We'll break this if add in future more
>> backend-transfer support in devices under same backend-transfer=true
>> parameter.
>>
>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
>> ---
>> include/qapi/util.h | 17 ++++++++++++++++
>> migration/options.c | 32 ++++++++++++++++++++++++++++++
>> migration/options.h | 2 ++
>> qapi/migration.json | 47 ++++++++++++++++++++++++++++++++++++---------
>> 4 files changed, 89 insertions(+), 9 deletions(-)
>>
>> diff --git a/include/qapi/util.h b/include/qapi/util.h
>> index 29bc4eb865..b953402416 100644
>> --- a/include/qapi/util.h
>> +++ b/include/qapi/util.h
>> @@ -69,4 +69,21 @@ int parse_qapi_name(const char *name, bool complete);
>> _len; \
>> })
>>
>> +/*
>> + * For any GenericList @list, return true if it contains specified
>> + * element.
>> + */
>> +#define QAPI_LIST_CONTAINS(list, el) \
>> + ({ \
>> + bool _found = false; \
>> + typeof_strip_qual(list) _tail; \
>> + for (_tail = list; _tail != NULL; _tail = _tail->next) { \
>> + if (_tail->value == el) { \
>> + _found = true; \
>> + break; \
>> + } \
>> + } \
>> + _found; \
>> + })
>> +
>
> Not a fan of lengthy macros.
>
> There's a single use below: migrate_virtio_net_tap(). I can't see
> potential uses for such a search in existing code.
>
> Open-code it in migrate_virtio_net_tap()?
Ok, not a problem
>
>> #endif
>> diff --git a/migration/options.c b/migration/options.c
>> index 4e923a2e07..137ca2147e 100644
>> --- a/migration/options.c
>> +++ b/migration/options.c
>> @@ -13,6 +13,7 @@
>>
>> #include "qemu/osdep.h"
>> #include "qemu/error-report.h"
>> +#include "qapi/util.h"
>> #include "exec/target_page.h"
>> #include "qapi/clone-visitor.h"
>> #include "qapi/error.h"
>> @@ -262,6 +263,14 @@ bool migrate_mapped_ram(void)
>> return s->capabilities[MIGRATION_CAPABILITY_MAPPED_RAM];
>> }
>>
>> +bool migrate_virtio_net_tap(void)
>> +{
>> + MigrationState *s = migrate_get_current();
>> +
>> + return QAPI_LIST_CONTAINS(s->parameters.backend_transfer,
>> + BACKEND_TRANSFER_VIRTIO_NET_TAP);
>> +}
>> +
>> bool migrate_ignore_shared(void)
>> {
>> MigrationState *s = migrate_get_current();
>> @@ -960,6 +969,12 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
>> params->has_direct_io = true;
>> params->direct_io = s->parameters.direct_io;
>>
>> + if (s->parameters.backend_transfer) {
>> + params->has_backend_transfer = true;
>> + params->backend_transfer = QAPI_CLONE(BackendTransferList,
>> + s->parameters.backend_transfer);
>> + }
>> +
>> return params;
>> }
>>
>> @@ -993,6 +1008,7 @@ void migrate_params_init(MigrationParameters *params)
>> params->has_mode = true;
>> params->has_zero_page_detection = true;
>> params->has_direct_io = true;
>> + params->has_backend_transfer = true;
>> }
>>
>> /*
>> @@ -1179,6 +1195,11 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
>> return false;
>> }
>>
>> + if (params->has_backend_transfer) {
>> + error_setg(errp, "Not implemented");
>> + return false;
>> + }
>> +
>
> This goes away in the next patch. Fine, but mentioning the gap in the
> commit message can save reviewer a bit of work.
Right :(
>
>> return true;
>> }
>>
>> @@ -1297,6 +1318,10 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
>> if (params->has_direct_io) {
>> dest->direct_io = params->direct_io;
>> }
>> +
>> + if (params->has_backend_transfer) {
>> + dest->backend_transfer = params->backend_transfer;
>> + }
>> }
>>
>> static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
>> @@ -1429,6 +1454,13 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
>> if (params->has_direct_io) {
>> s->parameters.direct_io = params->direct_io;
>> }
>> +
>> + if (params->has_backend_transfer) {
>> + qapi_free_BackendTransferList(s->parameters.backend_transfer);
>> +
>> + s->parameters.backend_transfer = QAPI_CLONE(BackendTransferList,
>> + params->backend_transfer);
>> + }
>> }
>>
>> void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
>> diff --git a/migration/options.h b/migration/options.h
>> index 82d839709e..55c0345433 100644
>> --- a/migration/options.h
>> +++ b/migration/options.h
>> @@ -87,6 +87,8 @@ const char *migrate_tls_hostname(void);
>> uint64_t migrate_xbzrle_cache_size(void);
>> ZeroPageDetection migrate_zero_page_detection(void);
>>
>> +bool migrate_virtio_net_tap(void);
>> +
>> /* parameters helpers */
>>
>> bool migrate_params_check(MigrationParameters *params, Error **errp);
>> diff --git a/qapi/migration.json b/qapi/migration.json
>> index 2387c21e9c..e39785dc07 100644
>> --- a/qapi/migration.json
>> +++ b/qapi/migration.json
>> @@ -747,6 +747,18 @@
>> '*transform': 'BitmapMigrationBitmapAliasTransform'
>> } }
>>
>> +##
>> +# @BackendTransfer:
>> +#
>> +# @virtio-net-tap: Enable backend-transfer migration for virtio-net/tap. When
>> +# enabled, TAP fds and all related state is passed to target QEMU through
>> +# migration channel (which should be unix socket).
>
> Suggest "are passed to the destination in the migration channel" and
> "should be a UNIX domain socket".
>
> docs/devel/qapi-code-gen.rst:
>
> For legibility, wrap text paragraphs so every line is at most 70
> characters long.
>
> Separate sentences with two spaces.
Ok. We do lack this check in checkpatch
>
>> +#
>> +# Since: 10.2
>> +##
>> +{ 'enum': 'BackendTransfer',
>> + 'data': [ 'virtio-net-tap' ] }
>> +
>> ##
>> # @BitmapMigrationNodeAlias:
>> #
>> @@ -924,10 +936,14 @@
>> # only has effect if the @mapped-ram capability is enabled.
>> # (Since 9.1)
>> #
>> +# @backend-transfer: List of targets to enable backend-transfer
>> +# migration for. This requires migration channel to be a unix
>> +# socket (to pass fds through). (Since 10.2)
>
> Elsewhere, we describe the same restriction like this:
>
> This CPR channel must support
> # file descriptor transfer with SCM_RIGHTS, i.e. it must be a
> # UNIX domain socket.
>
Thanks, I'll copy this phrasing to be consistent.
>> +#
>> # Features:
>> #
>> -# @unstable: Members @x-checkpoint-delay and
>> -# @x-vcpu-dirty-limit-period are experimental.
>> +# @unstable: Members @x-checkpoint-delay,
>> +# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
>
> List members in alphabetical order, please.
>
>> #
>> # Since: 2.4
>> ##
>> @@ -950,7 +966,8 @@
>> 'vcpu-dirty-limit',
>> 'mode',
>> 'zero-page-detection',
>> - 'direct-io'] }
>> + 'direct-io',
>> + 'backend-transfer' ] }
>
> Forgot feature 'unstable'?
Opps. Interesting, how it compiles? Usually, inconsistencies between
QAPI comments and definitions are hardly checked.
>
>>
>> ##
>> # @MigrateSetParameters:
>> @@ -1105,10 +1122,14 @@
>> # only has effect if the @mapped-ram capability is enabled.
>> # (Since 9.1)
>> #
>> +# @backend-transfer: List of targets to enable backend-transfer
>> +# migration for. This requires migration channel to be a unix
>> +# socket (to pass fds through). (Since 10.2)
>> +#
>> # Features:
>> #
>> -# @unstable: Members @x-checkpoint-delay and
>> -# @x-vcpu-dirty-limit-period are experimental.
>> +# @unstable: Members @x-checkpoint-delay,
>> +# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
>> #
>> # TODO: either fuse back into `MigrationParameters`, or make
>> # `MigrationParameters` members mandatory
>> @@ -1146,7 +1167,9 @@
>> '*vcpu-dirty-limit': 'uint64',
>> '*mode': 'MigMode',
>> '*zero-page-detection': 'ZeroPageDetection',
>> - '*direct-io': 'bool' } }
>> + '*direct-io': 'bool',
>> + '*backend-transfer': { 'type': [ 'BackendTransfer' ],
>> + 'features': [ 'unstable' ] } } }
>>
>> ##
>> # @migrate-set-parameters:
>> @@ -1315,10 +1338,14 @@
>> # only has effect if the @mapped-ram capability is enabled.
>> # (Since 9.1)
>> #
>> +# @backend-transfer: List of targets to enable backend-transfer
>> +# migration for. This requires migration channel to be a unix
>> +# socket (to pass fds through). (Since 10.2)
>> +#
>> # Features:
>> #
>> -# @unstable: Members @x-checkpoint-delay and
>> -# @x-vcpu-dirty-limit-period are experimental.
>> +# @unstable: Members @x-checkpoint-delay,
>> +# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
>> #
>> # Since: 2.4
>> ##
>> @@ -1353,7 +1380,9 @@
>> '*vcpu-dirty-limit': 'uint64',
>> '*mode': 'MigMode',
>> '*zero-page-detection': 'ZeroPageDetection',
>> - '*direct-io': 'bool' } }
>> + '*direct-io': 'bool',
>> + '*backend-transfer': { 'type': [ 'BackendTransfer' ],
>> + 'features': [ 'unstable' ] } } }
>>
>> ##
>> # @query-migrate-parameters:
>
Thanks for reviewing, I'll fix all notes in v7.
--
Best regards,
Vladimir
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration
2025-10-07 8:57 ` Vladimir Sementsov-Ogievskiy
@ 2025-10-07 11:42 ` Markus Armbruster
0 siblings, 0 replies; 31+ messages in thread
From: Markus Armbruster @ 2025-10-07 11:42 UTC (permalink / raw)
To: Vladimir Sementsov-Ogievskiy
Cc: mst, qemu-devel, philmd, thuth, eblake, michael.roth, farosas,
peterx, berrange, jasowang, steven.sistare, leiyang, davydov-max,
yc-core
Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:
> On 06.10.25 16:23, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:
>>
>>> To migrate virtio-net TAP device backend (including open fds) locally,
>>> user should simply set migration parameter
>>>
>>> backend-transfer = ["virtio-net-tap"]
>>>
>>> Why not simple boolean? To simplify migration to further versions,
>>> when more devices will support backend-transfer migration.
>>>
>>> Alternatively, we may add per-device option to disable backend-transfer
>>> migration, but still:
>>>
>>> 1. It's more comfortable to set same capabilities/parameters on both
>>> source and target QEMU, than care about each device.
>>>
>>> 2. To not break the design, that machine-type + device options +
>>> migration capabilities and parameters are fully define the resulting
>>> migration stream. We'll break this if add in future more
>>> backend-transfer support in devices under same backend-transfer=true
>>> parameter.
>>>
>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
[...]
>>> diff --git a/migration/options.h b/migration/options.h
>>> index 82d839709e..55c0345433 100644
>>> --- a/migration/options.h
>>> +++ b/migration/options.h
>>> @@ -87,6 +87,8 @@ const char *migrate_tls_hostname(void);
>>> uint64_t migrate_xbzrle_cache_size(void);
>>> ZeroPageDetection migrate_zero_page_detection(void);
>>>
>>> +bool migrate_virtio_net_tap(void);
>>> +
>>> /* parameters helpers */
>>>
>>> bool migrate_params_check(MigrationParameters *params, Error **errp);
>>> diff --git a/qapi/migration.json b/qapi/migration.json
>>> index 2387c21e9c..e39785dc07 100644
>>> --- a/qapi/migration.json
>>> +++ b/qapi/migration.json
>>> @@ -747,6 +747,18 @@
>>> '*transform': 'BitmapMigrationBitmapAliasTransform'
>>> } }
>>>
>>> +##
>>> +# @BackendTransfer:
>>> +#
>>> +# @virtio-net-tap: Enable backend-transfer migration for virtio-net/tap. When
>>> +# enabled, TAP fds and all related state is passed to target QEMU through
>>> +# migration channel (which should be unix socket).
>>
>> Suggest "are passed to the destination in the migration channel" and
>> "should be a UNIX domain socket".
>>
>> docs/devel/qapi-code-gen.rst:
>>
>> For legibility, wrap text paragraphs so every line is at most 70
>> characters long.
>>
>> Separate sentences with two spaces.
>
> Ok. We do lack this check in checkpatch
Would be nice, yes.
>>> +#
>>> +# Since: 10.2
>>> +##
>>> +{ 'enum': 'BackendTransfer',
>>> + 'data': [ 'virtio-net-tap' ] }
>>> +
>>> ##
>>> # @BitmapMigrationNodeAlias:
>>> #
>>> @@ -924,10 +936,14 @@
>>> # only has effect if the @mapped-ram capability is enabled.
>>> # (Since 9.1)
>>> #
>>> +# @backend-transfer: List of targets to enable backend-transfer
>>> +# migration for. This requires migration channel to be a unix
>>> +# socket (to pass fds through). (Since 10.2)
>>
>> Elsewhere, we describe the same restriction like this:
>>
>> This CPR channel must support
>> # file descriptor transfer with SCM_RIGHTS, i.e. it must be a
>> # UNIX domain socket.
>>
>
> Thanks, I'll copy this phrasing to be consistent.
>
>>> +#
>>> # Features:
>>> #
>>> -# @unstable: Members @x-checkpoint-delay and
>>> -# @x-vcpu-dirty-limit-period are experimental.
>>> +# @unstable: Members @x-checkpoint-delay,
>>> +# @x-vcpu-dirty-limit-period and @backend-transfer are experimental.
>>
>> List members in alphabetical order, please.
>>
>>> #
>>> # Since: 2.4
>>> ##
>>> @@ -950,7 +966,8 @@
>>> 'vcpu-dirty-limit',
>>> 'mode',
>>> 'zero-page-detection',
>>> - 'direct-io'] }
>>> + 'direct-io',
>>> + 'backend-transfer' ] }
>>
>> Forgot feature 'unstable'?
>
> Opps. Interesting, how it compiles? Usually, inconsistencies between
> QAPI comments and definitions are hardly checked.
You found a gap in the checking.
[...]
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2025-10-07 11:43 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-23 10:00 [PATCH v6 00/19] virtio-net: live-TAP local migration Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 01/19] net/tap: net_init_tap_one(): drop extra error propagation Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 02/19] net/tap: net_init_tap_one(): move parameter checking earlier Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 03/19] net/tap: rework net_tap_init() Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 04/19] net/tap: pass NULL to net_init_tap_one() in cases when scripts are NULL Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 05/19] net/tap: rework scripts handling Vladimir Sementsov-Ogievskiy
2025-09-23 10:39 ` Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 06/19] net/tap: setup exit notifier only when needed Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 07/19] net/tap: split net_tap_fd_init() Vladimir Sementsov-Ogievskiy
2025-09-23 10:00 ` [PATCH v6 08/19] net/tap: tap_set_sndbuf(): add return value Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 09/19] net/tap: rework tap_set_sndbuf() Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 10/19] net/tap: rework sndbuf handling Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 11/19] net/tap: introduce net_tap_setup() Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 12/19] net/tap: move vhost fd initialization to net_tap_new() Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 13/19] net/tap: finalize net_tap_set_fd() logic Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 14/19] migration: add MIG_EVENT_PRE_INCOMING Vladimir Sementsov-Ogievskiy
2025-09-30 19:25 ` Peter Xu
2025-09-23 10:01 ` [PATCH v6 15/19] net/tap: postpone tap setup to pre-incoming Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 16/19] qapi: add interface for backend-transfer virtio-net/tap migration Vladimir Sementsov-Ogievskiy
2025-10-06 13:23 ` Markus Armbruster
2025-10-06 13:33 ` Michael S. Tsirkin
2025-10-06 14:38 ` Markus Armbruster
2025-10-06 14:55 ` Michael S. Tsirkin
2025-10-06 17:06 ` Markus Armbruster
2025-10-07 8:57 ` Vladimir Sementsov-Ogievskiy
2025-10-07 11:42 ` Markus Armbruster
2025-09-23 10:01 ` [PATCH v6 17/19] virtio-net: support backend-transfer migration for virtio-net/tap Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 18/19] tests/functional: add skipWithoutSudo() decorator Vladimir Sementsov-Ogievskiy
2025-09-23 10:01 ` [PATCH v6 19/19] tests/functional: add test_x86_64_tap_migration Vladimir Sementsov-Ogievskiy
2025-09-24 8:02 ` [PATCH v6 00/19] virtio-net: live-TAP local migration Lei Yang
2025-10-01 16:33 ` Maksim Davydov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).