All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/51] migration: Unify capabilities and parameters
@ 2025-12-15 21:59 Fabiano Rosas
  2025-12-15 21:59 ` [PATCH v3 01/51] migration: Fix leak of block_bitmap_mapping Fabiano Rosas
                   ` (51 more replies)
  0 siblings, 52 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

Hi, the scope of this series is the same as the previous versions, but
to be explicit, these are various parts of which it's comprised:

1) Remove duplication of migration parameters documentation in
   migration.json.

2) Merge migration capabilities and parameters in MigrationState (as
   visible internally in migration code).

3) Deprecate migration capabilities QMP commands. Functionality
   previously provided by "capabilities" commands are now provided by
   "parameters" commands.

4) Introduce new 'config' argument to migration commands taking the
   entire set of options to use for a migration. Obsoletes the usage
   of migrate-set-parameters, except for "runtime" options, which are
   as of yet uncovered by this proposal.

5) Adapt all migration-test(s) to use the new config API exclusively.

Notable changes in this v3:

- Added the setter for the new StrOrNull qdev property
- Move the visitor code into a new QAPI_MERGE macro
- Converted all tests to use config
  - Unfortunate side-quest: rework the TLS test hooks to support
    setting options before migrate_start.

CI run: https://gitlab.com/farosas/qemu/-/pipelines/2216127826

v2:
https://lore.kernel.org/r/20250630195913.28033-1-farosas@suse.de

v1:
https://lore.kernel.org/r/20250603013810.4772-1-farosas@suse.de

RFC:
https://lore.kernel.org/r/20250411191443.22565-1-farosas@suse.de

Fabiano Rosas (51):
  migration: Fix leak of block_bitmap_mapping
  migration: Fix leak of cpr_exec_command
  migration: Add a qdev property for StrOrNull
  tests/qtest/migration: Add a NULL parameters test for TLS
  migration: Normalize tls arguments
  migration: Remove MigrateSetParameters
  qapi/migration: Don't document MigrationParameter
  migration: Run a post update routine after setting parameters
  migration: Add a flag to track block-bitmap-mapping input
  migration: Remove checks for s->parameters has_* fields
  migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE
  migration: Extract code to mark all parameters as present
  migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters
  migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply
  migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply
  qapi: Add QAPI_MERGE
  migration: Use QAPI_MERGE in migrate_params_test_apply
  migration: Cleanup hmp_info_migrate_parameters
  migration: Add capabilities into MigrationParameters
  migration: Remove s->capabilities
  qapi/migration: Deprecate capabilities commands
  migration: Store the initial values used for s->parameters
  migration: Allow migrate commands to provide the migration config
  migration: Allow incoming cmdline to take config
  tests/qtest/migration: Pass MigrateCommon into test functions
  tests/qtest/migration: Pass MigrateStart into cancel tests
  tests/qtest/migration: Fix misuse of listen_uri
  tests/qtest/migration: Stop invoking migrate_incoming from hooks
  tests/qtest/migration: Add config QDict
  tests/qtest/migration: Add temporary code to toggle usage of config
  tests/qtest/migration: Add a function for default capabilities
  tests/qtest/migration: Adapt convergence routines to config
  tests/qtest/migration: Adapt the incoming cmdline for config passing
  tests/qtest/migration: Use migrate_incoming_qmp where possible
  tests/qtest/migration: Add a config parameter to migrate_qmp functions
  tests/qtest/migration: Move tls hook data out of specific hooks
  tests/qtest/migration: Add new hook with data
  tests/qtest/migration: TLS x509: Refactor to use full hook
  tests/qtest/migration: TLS x509: Add init/cleanup routines
  tests/qtest/migration: TLS PSK: Refactor to use full hook
  tests/qtest/migration: TLS PSK: Add init/cleanup routines
  tests/qtest/migration: Remove multifd compression hook
  tests/qtest/migration: Convert postcopy tests to use config
  tests/qtest/migration: Convert TLS PSK tests to use config
  tests/qtest/migration: Convert TLS x509 tests to use config
  tests/qtest/migration: Convert compression tests to use config
  tests/qtest/migration: Convert file tests to use config
  tests/qtest/migration: Convert misc-tests to use config
  tests/qtest/migration: Convert precopy tests to use config
  tests/qtest/migration: Remove migrate_set_capabilities and code around
    it
  tests/qtest/migration: Further simplify TLS tests

 docs/about/deprecated.rst                 |   10 +
 include/qapi/type-helpers.h               |   29 +
 migration/migration-hmp-cmds.c            |  503 ++++++---
 migration/migration.c                     |   52 +-
 migration/migration.h                     |   14 +-
 migration/options.c                       | 1183 ++++++++++-----------
 migration/options.h                       |   30 +-
 migration/page_cache.c                    |    6 +-
 migration/ram.c                           |    5 +-
 migration/savevm.c                        |    8 +-
 migration/tls.c                           |    2 +-
 qapi/migration.json                       |  569 ++++------
 qapi/pragma.json                          |    1 +
 system/vl.c                               |  111 +-
 tests/qtest/migration/compression-tests.c |  179 ++--
 tests/qtest/migration/cpr-tests.c         |  137 +--
 tests/qtest/migration/file-tests.c        |  209 ++--
 tests/qtest/migration/framework.c         |  158 +--
 tests/qtest/migration/framework.h         |   29 +-
 tests/qtest/migration/migration-qmp.c     |   64 +-
 tests/qtest/migration/migration-qmp.h     |   21 +-
 tests/qtest/migration/migration-util.c    |   72 +-
 tests/qtest/migration/migration-util.h    |    9 +-
 tests/qtest/migration/misc-tests.c        |  132 +--
 tests/qtest/migration/postcopy-tests.c    |   80 +-
 tests/qtest/migration/precopy-tests.c     |  535 +++++-----
 tests/qtest/migration/tls-tests.c         |  897 +++++++---------
 tests/qtest/virtio-net-failover.c         |   24 +-
 28 files changed, 2512 insertions(+), 2557 deletions(-)

-- 
2.51.0



^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH v3 01/51] migration: Fix leak of block_bitmap_mapping
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-15 21:59 ` [PATCH v3 02/51] migration: Fix leak of cpr_exec_command Fabiano Rosas
                   ` (50 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

Caught by inspection, but ASAN also reports:

Direct leak of 16 byte(s) in 1 object(s) allocated from:
 #0 in malloc
 #1 in g_malloc
 #2 in g_memdup
 #3 in qapi_clone_start_struct ../qapi/qapi-clone-visitor.c:40:12
 #4 in qapi_clone_start_list ../qapi/qapi-clone-visitor.c:59:12
 #5 in visit_start_list ../qapi/qapi-visit-core.c:80:10
 #6 in visit_type_BitmapMigrationNodeAliasList qapi/qapi-visit-migration.c:639:10
 #7 in migrate_params_apply ../migration/options.c:1407:13
 #8 in qmp_migrate_set_parameters ../migration/options.c:1463:5
 #9 in qmp_marshal_migrate_set_parameters qapi/qapi-commands-migration.c:214:5
 #10 in do_qmp_dispatch_bh ../qapi/qmp-dispatch.c:128:5

Note that this is entirely harmless because the migration object which
contains the MigrationParameters structure is kept until the QEMU
process exits.

Reviewed-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/migration/migration.c b/migration/migration.c
index b316ee01ab..c2e1dedf93 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -4147,6 +4147,7 @@ static void migration_instance_finalize(Object *obj)
 {
     MigrationState *ms = MIGRATION_OBJ(obj);
 
+    qapi_free_BitmapMigrationNodeAliasList(ms->parameters.block_bitmap_mapping);
     qemu_mutex_destroy(&ms->error_mutex);
     qemu_mutex_destroy(&ms->qemu_file_lock);
     qemu_sem_destroy(&ms->wait_unplug_sem);
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 02/51] migration: Fix leak of cpr_exec_command
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
  2025-12-15 21:59 ` [PATCH v3 01/51] migration: Fix leak of block_bitmap_mapping Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-16 16:48   ` Peter Xu
  2025-12-15 21:59 ` [PATCH v3 03/51] migration: Add a qdev property for StrOrNull Fabiano Rosas
                   ` (49 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/migration/migration.c b/migration/migration.c
index c2e1dedf93..92c84c3177 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -4148,6 +4148,7 @@ static void migration_instance_finalize(Object *obj)
     MigrationState *ms = MIGRATION_OBJ(obj);
 
     qapi_free_BitmapMigrationNodeAliasList(ms->parameters.block_bitmap_mapping);
+    qapi_free_strList(ms->parameters.cpr_exec_command);
     qemu_mutex_destroy(&ms->error_mutex);
     qemu_mutex_destroy(&ms->qemu_file_lock);
     qemu_sem_destroy(&ms->wait_unplug_sem);
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 03/51] migration: Add a qdev property for StrOrNull
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
  2025-12-15 21:59 ` [PATCH v3 01/51] migration: Fix leak of block_bitmap_mapping Fabiano Rosas
  2025-12-15 21:59 ` [PATCH v3 02/51] migration: Fix leak of cpr_exec_command Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-16 16:57   ` Peter Xu
  2025-12-15 21:59 ` [PATCH v3 04/51] tests/qtest/migration: Add a NULL parameters test for TLS Fabiano Rosas
                   ` (48 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

The MigrationState is a QOM object with TYPE_DEVICE as a parent. This
was done about eight years ago so the migration code could make use of
qdev properties to define the defaults for the migration parameters
and to be able to expose migration knobs for debugging via the
'-global migration' command line option.

Due to unrelated historical reasons, three of the migration parameters
(TLS options) received different types when used via the
query-migrate-parameters QMP command than with the
migrate-set-parameters command. This has created a lot of duplication
in the migration code and in the QAPI documentation because the whole
of MigrationParameters had to be duplicated as well.

The migration code is now being fixed to remove the duplication and
for that to happen the offending fields need to be reconciled into a
single type. The StrOrNull type is going to be used.

To keep the command line compatibility, the parameters need to
continue being exposed via qdev properties accessible from the command
line. Introduce a qdev property StrOrNull just for that.

Note that this code is being kept in migration/options.c as this
version of StrOrNull doesn't need to handle QNULL because it was never
a valid option in the previous command line, which took a string.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/options.c | 67 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/migration/options.c b/migration/options.c
index e78324b80c..5f387437d1 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -83,6 +83,11 @@
 #define DEFINE_PROP_MIG_CAP(name, x)             \
     DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)
 
+const PropertyInfo qdev_prop_StrOrNull;
+#define DEFINE_PROP_STR_OR_NULL(_name, _state, _field)                  \
+    DEFINE_PROP(_name, _state, _field, qdev_prop_StrOrNull, StrOrNull *, \
+                .set_default = true)
+
 #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD     1000    /* milliseconds */
 #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT            1       /* MB/s */
 
@@ -206,6 +211,68 @@ const Property migration_properties[] = {
 };
 const size_t migration_properties_count = ARRAY_SIZE(migration_properties);
 
+static void get_StrOrNull(Object *obj, Visitor *v, const char *name,
+                          void *opaque, Error **errp)
+{
+    const Property *prop = opaque;
+    StrOrNull **ptr = object_field_prop_ptr(obj, prop);
+    StrOrNull *str_or_null = *ptr;
+
+    if (!str_or_null) {
+        str_or_null = g_new0(StrOrNull, 1);
+        str_or_null->type = QTYPE_QSTRING;
+        str_or_null->u.s = g_strdup("");
+    } else {
+        /* the setter doesn't allow QNULL */
+        assert(str_or_null->type != QTYPE_QNULL);
+    }
+    visit_type_str(v, name, &str_or_null->u.s, errp);
+}
+
+static void set_StrOrNull(Object *obj, Visitor *v, const char *name,
+                          void *opaque, Error **errp)
+{
+    const Property *prop = opaque;
+    StrOrNull **ptr = object_field_prop_ptr(obj, prop);
+    StrOrNull *str_or_null = g_new0(StrOrNull, 1);
+
+    /*
+     * Only str to keep compatibility, QNULL was never used via
+     * command line.
+     */
+    str_or_null->type = QTYPE_QSTRING;
+    if (!visit_type_str(v, name, &str_or_null->u.s, errp)) {
+        return;
+    }
+
+    qapi_free_StrOrNull(*ptr);
+    *ptr = str_or_null;
+}
+
+static void release_StrOrNull(Object *obj, const char *name, void *opaque)
+{
+    const Property *prop = opaque;
+    qapi_free_StrOrNull(*(StrOrNull **)object_field_prop_ptr(obj, prop));
+}
+
+static void set_default_value_tls_opt(ObjectProperty *op, const Property *prop)
+{
+    object_property_set_default_str(op, "");
+}
+
+/*
+ * String property like qdev_prop_string, except it's backed by a
+ * StrOrNull instead of a char *.  This is intended for
+ * TYPE_MIGRATION's TLS options.
+ */
+const PropertyInfo qdev_prop_StrOrNull = {
+    .type  = "StrOrNull",
+    .get = get_StrOrNull,
+    .set = set_StrOrNull,
+    .release = release_StrOrNull,
+    .set_default_value = set_default_value_tls_opt,
+};
+
 bool migrate_auto_converge(void)
 {
     MigrationState *s = migrate_get_current();
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 04/51] tests/qtest/migration: Add a NULL parameters test for TLS
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (2 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 03/51] migration: Add a qdev property for StrOrNull Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-16 17:03   ` Peter Xu
  2025-12-15 21:59 ` [PATCH v3 05/51] migration: Normalize tls arguments Fabiano Rosas
                   ` (47 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Make sure the TLS options handling is working correctly with a NULL
parameter. This is relevant due to the usage of StrOrNull for the
tls-creds, tls-authz and tls-hostname options.

With this, all manners of passing TLS options are somehow covered by
the tests, we should not need to do manual testing when touching TLS
options code.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/migration-qmp.c |  9 +++++
 tests/qtest/migration/migration-qmp.h |  1 +
 tests/qtest/migration/tls-tests.c     | 56 +++++++++++++++++++++++++++
 3 files changed, 66 insertions(+)

diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
index c803fcee9d..5c46ceb3e6 100644
--- a/tests/qtest/migration/migration-qmp.c
+++ b/tests/qtest/migration/migration-qmp.c
@@ -458,6 +458,15 @@ void migrate_set_parameter_strv(QTestState *who, const char *parameter,
     qtest_qmp_assert_success(who, command, parameter);
 }
 
+void migrate_set_parameter_null(QTestState *who, const char *parameter)
+{
+    qtest_qmp_assert_success(who,
+                             "{ 'execute': 'migrate-set-parameters',"
+                             "'arguments': { %s: null } }",
+                             parameter);
+    migrate_check_parameter_str(who, parameter, "");
+}
+
 static long long migrate_get_parameter_bool(QTestState *who,
                                             const char *parameter)
 {
diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
index 44482d250f..940ffd5950 100644
--- a/tests/qtest/migration/migration-qmp.h
+++ b/tests/qtest/migration/migration-qmp.h
@@ -36,6 +36,7 @@ void migrate_set_parameter_str(QTestState *who, const char *parameter,
                                const char *value);
 void migrate_set_parameter_strv(QTestState *who, const char *parameter,
                                 char **strv);
+void migrate_set_parameter_null(QTestState *who, const char *parameter);
 void migrate_set_parameter_bool(QTestState *who, const char *parameter,
                                 int value);
 void migrate_ensure_non_converge(QTestState *who);
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 21e9fec87d..e0e8a7335c 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -507,6 +507,57 @@ static void test_precopy_tcp_tls_psk_mismatch(void)
     test_precopy_common(&args);
 }
 
+static void *migrate_hook_start_no_tls(QTestState *from, QTestState *to)
+{
+    struct TestMigrateTLSPSKData *data =
+        g_new0(struct TestMigrateTLSPSKData, 1);
+
+    migrate_set_parameter_null(from, "tls-creds");
+    migrate_set_parameter_null(to, "tls-creds");
+
+    return data;
+}
+
+static void test_precopy_tcp_no_tls(void)
+{
+    MigrateCommon args = {
+        .listen_uri = "tcp:127.0.0.1:0",
+        .start_hook = migrate_hook_start_no_tls,
+        .end_hook = migrate_hook_end_tls_psk,
+    };
+
+    test_precopy_common(&args);
+}
+
+static void *
+migrate_hook_start_tls_x509_no_host(QTestState *from, QTestState *to)
+{
+    TestMigrateTLSX509 args = {
+        .verifyclient = true,
+        .clientcert = true,
+        .authzclient = true,
+    };
+    TestMigrateTLSX509Data *data = migrate_hook_start_tls_x509_common(from, to,
+                                                                      &args);
+    migrate_set_parameter_null(from, "tls-hostname");
+    migrate_set_parameter_null(to, "tls-hostname");
+
+    return data;
+}
+
+static void test_precopy_tcp_tls_no_hostname(void)
+{
+    MigrateCommon args = {
+        .listen_uri = "tcp:127.0.0.1:0",
+        .start_hook = migrate_hook_start_tls_x509_no_host,
+        .end_hook = migrate_hook_end_tls_x509,
+        .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
+        .start.hide_stderr = true,
+    };
+
+    test_precopy_common(&args);
+}
+
 #ifdef CONFIG_TASN1
 static void test_precopy_tcp_tls_x509_default_host(void)
 {
@@ -799,6 +850,11 @@ void migration_test_add_tls(MigrationTestEnv *env)
         return;
     }
 
+    migration_test_add("/migration/precopy/tcp/no-tls",
+                       test_precopy_tcp_no_tls);
+    migration_test_add("/migration/precopy/tcp/tls/no-hostname",
+                       test_precopy_tcp_tls_no_hostname);
+
     migration_test_add("/migration/precopy/unix/tls/psk",
                        test_precopy_unix_tls_psk);
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 05/51] migration: Normalize tls arguments
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (3 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 04/51] tests/qtest/migration: Add a NULL parameters test for TLS Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-16 17:24   ` Peter Xu
  2025-12-15 21:59 ` [PATCH v3 06/51] migration: Remove MigrateSetParameters Fabiano Rosas
                   ` (46 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Eric Blake

The migration parameters tls_creds, tls_authz and tls_hostname
currently have a non-uniform handling. When used as arguments to
migrate-set-parameters, their type is StrOrNull and when used as
return value from query-migrate-parameters their type is a plain
string.

Not only having to convert between the types is cumbersome, but it
also creates the issue of requiring two different QAPI types to be
used, one for each command. MigrateSetParameters is used for
migrate-set-parameters with the TLS arguments as StrOrNull while
MigrationParameters is used for query-migrate-parameters with the TLS
arguments as str.

Since StrOrNull could be considered a superset of str, change the type
of the TLS arguments in MigrationParameters to StrOrNull. Also ensure
that QTYPE_QNULL is never used.

1) migrate-set-parameters will always write QTYPE_QSTRING to
  s->parameters, either an empty or non-empty string.

2) query-migrate-parameters will always return a QTYPE_QSTRING, either
  empty or non-empty.

3) the migrate_tls_* helpers will always return a non-empty string or
  NULL, for the internal migration code's consumption.

Points (1) and (2) above help simplify the parameters validation and
the query command handling because s->parameters is already kept in
the format that query-migrate-parameters (and info migrate_paramters)
expect. Point (3) is so people don't need to care about StrOrNull in
migration code.

This will allow the type duplication to be removed in the next
patches.

Note that the type of @tls_creds, @tls-hostname, @tls-authz changes
from str to StrOrNull in introspection of the query-migrate-parameters
command. We accept this imprecision to enable de-duplication.

There's no need to free the TLS options in
migration_instance_finalize() because they're freed by the qdev
properties .release method.

Temporary in this patch:
migrate_params_test_apply() copies s->parameters into a temporary
structure, so it's necessary to drop the references to the TLS options
if they were not set by the user to avoid double-free. This is fixed
in the next patches.

Acked-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration-hmp-cmds.c |   9 ++-
 migration/options.c            | 144 +++++++++++++++++++--------------
 migration/options.h            |   1 +
 migration/tls.c                |   2 +-
 qapi/migration.json            |   6 +-
 5 files changed, 96 insertions(+), 66 deletions(-)

diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 79426bf5d7..dbab5028c2 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -360,15 +360,15 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
         assert(params->tls_creds);
         monitor_printf(mon, "%s: '%s'\n",
             MigrationParameter_str(MIGRATION_PARAMETER_TLS_CREDS),
-            params->tls_creds);
+                       params->tls_creds->u.s);
         assert(params->tls_hostname);
         monitor_printf(mon, "%s: '%s'\n",
             MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME),
-            params->tls_hostname);
+                       params->tls_hostname->u.s);
         assert(params->tls_authz);
         monitor_printf(mon, "%s: '%s'\n",
             MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ),
-            params->tls_authz);
+                       params->tls_authz->u.s);
         assert(params->has_max_bandwidth);
         monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
             MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH),
@@ -403,6 +403,9 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
         monitor_printf(mon, "%s: %" PRIu64 " bytes\n",
             MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE),
             params->xbzrle_cache_size);
+        monitor_printf(mon, "%s: %" PRIu64 "\n",
+            MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH),
+            params->max_postcopy_bandwidth);
 
         if (params->has_block_bitmap_mapping) {
             const BitmapMigrationNodeAliasList *bmnal;
diff --git a/migration/options.c b/migration/options.c
index 5f387437d1..4ca6ff0fe9 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -167,9 +167,10 @@ const Property migration_properties[] = {
     DEFINE_PROP_SIZE("announce-step", MigrationState,
                       parameters.announce_step,
                       DEFAULT_MIGRATE_ANNOUNCE_STEP),
-    DEFINE_PROP_STRING("tls-creds", MigrationState, parameters.tls_creds),
-    DEFINE_PROP_STRING("tls-hostname", MigrationState, parameters.tls_hostname),
-    DEFINE_PROP_STRING("tls-authz", MigrationState, parameters.tls_authz),
+    DEFINE_PROP_STR_OR_NULL("tls-creds", MigrationState, parameters.tls_creds),
+    DEFINE_PROP_STR_OR_NULL("tls-hostname", MigrationState,
+                            parameters.tls_hostname),
+    DEFINE_PROP_STR_OR_NULL("tls-authz", MigrationState, parameters.tls_authz),
     DEFINE_PROP_UINT64("x-vcpu-dirty-limit-period", MigrationState,
                        parameters.x_vcpu_dirty_limit_period,
                        DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD),
@@ -257,6 +258,11 @@ static void release_StrOrNull(Object *obj, const char *name, void *opaque)
 
 static void set_default_value_tls_opt(ObjectProperty *op, const Property *prop)
 {
+    /*
+     * Initialization to the empty string here is important so
+     * query-migrate-parameters doesn't need to deal with a NULL value
+     * when it's called before any TLS option has been set.
+     */
     object_property_set_default_str(op, "");
 }
 
@@ -448,13 +454,6 @@ bool migrate_rdma(void)
     return s->rdma_migration;
 }
 
-bool migrate_tls(void)
-{
-    MigrationState *s = migrate_get_current();
-
-    return s->parameters.tls_creds && *s->parameters.tls_creds;
-}
-
 typedef enum WriteTrackingSupport {
     WT_SUPPORT_UNKNOWN = 0,
     WT_SUPPORT_ABSENT,
@@ -929,21 +928,38 @@ const char *migrate_tls_authz(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->parameters.tls_authz;
+    if (*s->parameters.tls_authz->u.s) {
+        return s->parameters.tls_authz->u.s;
+    }
+
+    return NULL;
 }
 
 const char *migrate_tls_creds(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->parameters.tls_creds;
+    if (*s->parameters.tls_creds->u.s) {
+        return s->parameters.tls_creds->u.s;
+    }
+
+    return NULL;
 }
 
 const char *migrate_tls_hostname(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->parameters.tls_hostname;
+    if (*s->parameters.tls_hostname->u.s) {
+        return s->parameters.tls_hostname->u.s;
+    }
+
+    return NULL;
+}
+
+bool migrate_tls(void)
+{
+    return !!migrate_tls_creds();
 }
 
 uint64_t migrate_vcpu_dirty_limit_period(void)
@@ -983,6 +999,25 @@ AnnounceParameters *migrate_announce_params(void)
     return &ap;
 }
 
+void migrate_tls_opts_free(MigrationParameters *params)
+{
+    qapi_free_StrOrNull(params->tls_creds);
+    qapi_free_StrOrNull(params->tls_hostname);
+    qapi_free_StrOrNull(params->tls_authz);
+}
+
+/* normalize QTYPE_QNULL to QTYPE_QSTRING "" */
+static void tls_opt_to_str(StrOrNull *opt)
+{
+    if (!opt || opt->type == QTYPE_QSTRING) {
+        return;
+    }
+
+    qobject_unref(opt->u.n);
+    opt->type = QTYPE_QSTRING;
+    opt->u.s = g_strdup("");
+}
+
 MigrationParameters *qmp_query_migrate_parameters(Error **errp)
 {
     MigrationParameters *params;
@@ -998,10 +1033,9 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
     params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
     params->has_cpu_throttle_tailslow = true;
     params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
-    params->tls_creds = g_strdup(s->parameters.tls_creds);
-    params->tls_hostname = g_strdup(s->parameters.tls_hostname);
-    params->tls_authz = g_strdup(s->parameters.tls_authz ?
-                                 s->parameters.tls_authz : "");
+    params->tls_creds = QAPI_CLONE(StrOrNull, s->parameters.tls_creds);
+    params->tls_hostname = QAPI_CLONE(StrOrNull, s->parameters.tls_hostname);
+    params->tls_authz = QAPI_CLONE(StrOrNull, s->parameters.tls_authz);
     params->has_max_bandwidth = true;
     params->max_bandwidth = s->parameters.max_bandwidth;
     params->has_avail_switchover_bandwidth = true;
@@ -1061,9 +1095,6 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
 
 void migrate_params_init(MigrationParameters *params)
 {
-    params->tls_hostname = g_strdup("");
-    params->tls_creds = g_strdup("");
-
     /* Set has_* up only for parameter checks */
     params->has_throttle_trigger_threshold = true;
     params->has_cpu_throttle_initial = true;
@@ -1241,7 +1272,7 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
 #ifdef CONFIG_LINUX
     if (migrate_zero_copy_send() &&
         ((params->has_multifd_compression && params->multifd_compression) ||
-         (params->tls_creds && *params->tls_creds))) {
+         *params->tls_creds->u.s)) {
         error_setg(errp,
                    "Zero copy only available for non-compressed non-TLS multifd migration");
         return false;
@@ -1303,18 +1334,24 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
     }
 
     if (params->tls_creds) {
-        assert(params->tls_creds->type == QTYPE_QSTRING);
-        dest->tls_creds = params->tls_creds->u.s;
+        dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
+    } else {
+        /* clear the reference, it's owned by s->parameters */
+        dest->tls_creds = NULL;
     }
 
     if (params->tls_hostname) {
-        assert(params->tls_hostname->type == QTYPE_QSTRING);
-        dest->tls_hostname = params->tls_hostname->u.s;
+        dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
+    } else {
+        /* clear the reference, it's owned by s->parameters */
+        dest->tls_hostname = NULL;
     }
 
     if (params->tls_authz) {
-        assert(params->tls_authz->type == QTYPE_QSTRING);
-        dest->tls_authz = params->tls_authz->u.s;
+        dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
+    } else {
+        /* clear the reference, it's owned by s->parameters */
+        dest->tls_authz = NULL;
     }
 
     if (params->has_max_bandwidth) {
@@ -1423,21 +1460,19 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
     }
 
     if (params->tls_creds) {
-        g_free(s->parameters.tls_creds);
-        assert(params->tls_creds->type == QTYPE_QSTRING);
-        s->parameters.tls_creds = g_strdup(params->tls_creds->u.s);
+        qapi_free_StrOrNull(s->parameters.tls_creds);
+        s->parameters.tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
     }
 
     if (params->tls_hostname) {
-        g_free(s->parameters.tls_hostname);
-        assert(params->tls_hostname->type == QTYPE_QSTRING);
-        s->parameters.tls_hostname = g_strdup(params->tls_hostname->u.s);
+        qapi_free_StrOrNull(s->parameters.tls_hostname);
+        s->parameters.tls_hostname = QAPI_CLONE(StrOrNull,
+                                                params->tls_hostname);
     }
 
     if (params->tls_authz) {
-        g_free(s->parameters.tls_authz);
-        assert(params->tls_authz->type == QTYPE_QSTRING);
-        s->parameters.tls_authz = g_strdup(params->tls_authz->u.s);
+        qapi_free_StrOrNull(s->parameters.tls_authz);
+        s->parameters.tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
     }
 
     if (params->has_max_bandwidth) {
@@ -1542,32 +1577,23 @@ void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
 {
     MigrationParameters tmp;
 
-    /* TODO Rewrite "" to null instead for all three tls_* parameters */
-    if (params->tls_creds
-        && params->tls_creds->type == QTYPE_QNULL) {
-        qobject_unref(params->tls_creds->u.n);
-        params->tls_creds->type = QTYPE_QSTRING;
-        params->tls_creds->u.s = strdup("");
-    }
-    if (params->tls_hostname
-        && params->tls_hostname->type == QTYPE_QNULL) {
-        qobject_unref(params->tls_hostname->u.n);
-        params->tls_hostname->type = QTYPE_QSTRING;
-        params->tls_hostname->u.s = strdup("");
-    }
-    if (params->tls_authz
-        && params->tls_authz->type == QTYPE_QNULL) {
-        qobject_unref(params->tls_authz->u.n);
-        params->tls_authz->type = QTYPE_QSTRING;
-        params->tls_authz->u.s = strdup("");
-    }
+    /*
+     * Convert QTYPE_QNULL and NULL to the empty string (""). Even
+     * though NULL is cleaner to deal with in C code, that would force
+     * query-migrate-parameters to convert it once more to the empty
+     * string, so avoid that. The migrate_tls_*() helpers that expose
+     * the options to the rest of the migration code already use
+     * return NULL when the empty string is found.
+     */
+    tls_opt_to_str(params->tls_creds);
+    tls_opt_to_str(params->tls_hostname);
+    tls_opt_to_str(params->tls_authz);
 
     migrate_params_test_apply(params, &tmp);
 
-    if (!migrate_params_check(&tmp, errp)) {
-        /* Invalid parameter */
-        return;
+    if (migrate_params_check(&tmp, errp)) {
+        migrate_params_apply(params, errp);
     }
 
-    migrate_params_apply(params, errp);
+    migrate_tls_opts_free(&tmp);
 }
diff --git a/migration/options.h b/migration/options.h
index a7b3262d1e..25fb316420 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -92,4 +92,5 @@ ZeroPageDetection migrate_zero_page_detection(void);
 
 bool migrate_params_check(MigrationParameters *params, Error **errp);
 void migrate_params_init(MigrationParameters *params);
+void migrate_tls_opts_free(MigrationParameters *params);
 #endif
diff --git a/migration/tls.c b/migration/tls.c
index 284a6194b2..56b5d1cc90 100644
--- a/migration/tls.c
+++ b/migration/tls.c
@@ -130,7 +130,7 @@ QIOChannelTLS *migration_tls_client_create(QIOChannel *ioc,
     }
 
     const char *tls_hostname = migrate_tls_hostname();
-    if (tls_hostname && *tls_hostname) {
+    if (tls_hostname) {
         hostname = tls_hostname;
     }
 
diff --git a/qapi/migration.json b/qapi/migration.json
index cf023bd29d..30a0eb2d7e 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1382,9 +1382,9 @@
             '*cpu-throttle-initial': 'uint8',
             '*cpu-throttle-increment': 'uint8',
             '*cpu-throttle-tailslow': 'bool',
-            '*tls-creds': 'str',
-            '*tls-hostname': 'str',
-            '*tls-authz': 'str',
+            '*tls-creds': 'StrOrNull',
+            '*tls-hostname': 'StrOrNull',
+            '*tls-authz': 'StrOrNull',
             '*max-bandwidth': 'size',
             '*avail-switchover-bandwidth': 'size',
             '*downtime-limit': 'uint64',
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 06/51] migration: Remove MigrateSetParameters
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (4 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 05/51] migration: Normalize tls arguments Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-15 21:59 ` [PATCH v3 07/51] qapi/migration: Don't document MigrationParameter Fabiano Rosas
                   ` (45 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Eric Blake

Now that the TLS options have been made the same between
migrate-set-parameters and query-migrate-parameters, a single type can
be used. Remove MigrateSetParameters.

The TLS options documentation from MigrationParameters were replaced
with the ones from MigrateSetParameters which was more complete.

Acked-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration-hmp-cmds.c |   4 +-
 migration/options.c            |   6 +-
 qapi/migration.json            | 243 ++++-----------------------------
 3 files changed, 28 insertions(+), 225 deletions(-)

diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index dbab5028c2..a83aba9630 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -581,7 +581,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
     const char *param = qdict_get_str(qdict, "parameter");
     const char *valuestr = qdict_get_str(qdict, "value");
     Visitor *v = string_input_visitor_new(valuestr);
-    MigrateSetParameters *p = g_new0(MigrateSetParameters, 1);
+    MigrationParameters *p = g_new0(MigrationParameters, 1);
     uint64_t valuebw = 0;
     uint64_t cache_size;
     Error *err = NULL;
@@ -768,7 +768,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
     qmp_migrate_set_parameters(p, &err);
 
  cleanup:
-    qapi_free_MigrateSetParameters(p);
+    qapi_free_MigrationParameters(p);
     visit_free(v);
     hmp_handle_error(mon, err);
 }
diff --git a/migration/options.c b/migration/options.c
index 4ca6ff0fe9..f14baa8561 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1310,7 +1310,7 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
     return true;
 }
 
-static void migrate_params_test_apply(MigrateSetParameters *params,
+static void migrate_params_test_apply(MigrationParameters *params,
                                       MigrationParameters *dest)
 {
     *dest = migrate_get_current()->parameters;
@@ -1437,7 +1437,7 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
     }
 }
 
-static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
+static void migrate_params_apply(MigrationParameters *params, Error **errp)
 {
     MigrationState *s = migrate_get_current();
 
@@ -1573,7 +1573,7 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
     }
 }
 
-void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
+void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
 {
     MigrationParameters tmp;
 
diff --git a/qapi/migration.json b/qapi/migration.json
index 30a0eb2d7e..fa4491b9b0 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -992,212 +992,10 @@
            'direct-io',
            'cpr-exec-command'] }
 
-##
-# @MigrateSetParameters:
-#
-# @announce-initial: Initial delay (in milliseconds) before sending
-#     the first announce (Since 4.0)
-#
-# @announce-max: Maximum delay (in milliseconds) between packets in
-#     the announcement (Since 4.0)
-#
-# @announce-rounds: Number of self-announce packets sent after
-#     migration (Since 4.0)
-#
-# @announce-step: Increase in delay (in milliseconds) between
-#     subsequent packets in the announcement (Since 4.0)
-#
-# @throttle-trigger-threshold: The ratio of bytes_dirty_period and
-#     bytes_xfer_period to trigger throttling.  It is expressed as
-#     percentage.  The default value is 50.  (Since 5.0)
-#
-# @cpu-throttle-initial: Initial percentage of time guest cpus are
-#     throttled when migration auto-converge is activated.  The
-#     default value is 20.  (Since 2.7)
-#
-# @cpu-throttle-increment: throttle percentage increase each time
-#     auto-converge detects that migration is not making progress.
-#     The default value is 10.  (Since 2.7)
-#
-# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage.
-#     At the tail stage of throttling, the Guest is very sensitive to
-#     CPU percentage while the @cpu-throttle -increment is excessive
-#     usually at tail stage.  If this parameter is true, we will
-#     compute the ideal CPU percentage used by the Guest, which may
-#     exactly make the dirty rate match the dirty rate threshold.
-#     Then we will choose a smaller throttle increment between the one
-#     specified by @cpu-throttle-increment and the one generated by
-#     ideal CPU percentage.  Therefore, it is compatible to
-#     traditional throttling, meanwhile the throttle increment won't
-#     be excessive at tail stage.  The default value is false.
-#     (Since 5.1)
-#
-# @tls-creds: ID of the 'tls-creds' object that provides credentials
-#     for establishing a TLS connection over the migration data
-#     channel.  On the outgoing side of the migration, the credentials
-#     must be for a 'client' endpoint, while for the incoming side the
-#     credentials must be for a 'server' endpoint.  Setting this to a
-#     non-empty string enables TLS for all migrations.  An empty
-#     string means that QEMU will use plain text mode for migration,
-#     rather than TLS.  This is the default.  (Since 2.7)
-#
-# @tls-hostname: migration target's hostname for validating the
-#     server's x509 certificate identity.  If empty, QEMU will use the
-#     hostname from the migration URI, if any.  A non-empty value is
-#     required when using x509 based TLS credentials and the migration
-#     URI does not include a hostname, such as fd: or exec: based
-#     migration.  (Since 2.7)
-#
-#     Note: empty value works only since 2.9.
-#
-# @tls-authz: ID of the 'authz' object subclass that provides access
-#     control checking of the TLS x509 certificate distinguished name.
-#     This object is only resolved at time of use, so can be deleted
-#     and recreated on the fly while the migration server is active.
-#     If missing, it will default to denying access (Since 4.0)
-#
-# @max-bandwidth: maximum speed for migration, in bytes per second.
-#     (Since 2.8)
-#
-# @avail-switchover-bandwidth: to set the available bandwidth that
-#     migration can use during switchover phase.  **Note:** this does
-#     not limit the bandwidth during switchover, but only for
-#     calculations when making decisions to switchover.  By default,
-#     this value is zero, which means QEMU will estimate the bandwidth
-#     automatically.  This can be set when the estimated value is not
-#     accurate, while the user is able to guarantee such bandwidth is
-#     available when switching over.  When specified correctly, this
-#     can make the switchover decision much more accurate.
-#     (Since 8.2)
-#
-# @downtime-limit: set maximum tolerated downtime for migration.
-#     maximum downtime in milliseconds (Since 2.8)
-#
-# @x-checkpoint-delay: The delay time (in ms) between two COLO
-#     checkpoints in periodic mode.  (Since 2.8)
-#
-# @multifd-channels: Number of channels used to migrate data in
-#     parallel.  This is the same number that the number of sockets
-#     used for migration.  The default value is 2 (since 4.0)
-#
-# @xbzrle-cache-size: cache size to be used by XBZRLE migration.  It
-#     needs to be a multiple of the target page size and a power of 2
-#     (Since 2.11)
-#
-# @max-postcopy-bandwidth: Background transfer bandwidth during
-#     postcopy.  Defaults to 0 (unlimited).  In bytes per second.
-#     (Since 3.0)
-#
-# @max-cpu-throttle: maximum cpu throttle percentage.  Defaults to 99.
-#     (Since 3.1)
-#
-# @multifd-compression: Which compression method to use.  Defaults to
-#     none.  (Since 5.0)
-#
-# @multifd-zlib-level: Set the compression level to be used in live
-#     migration, the compression level is an integer between 0 and 9,
-#     where 0 means no compression, 1 means the best compression
-#     speed, and 9 means best compression ratio which will consume
-#     more CPU.  Defaults to 1.  (Since 5.0)
-#
-# @multifd-qatzip-level: Set the compression level to be used in live
-#     migration.  The level is an integer between 1 and 9, where 1
-#     means the best compression speed, and 9 means the best
-#     compression ratio which will consume more CPU.  Defaults to 1.
-#     (Since 9.2)
-#
-# @multifd-zstd-level: Set the compression level to be used in live
-#     migration, the compression level is an integer between 0 and 20,
-#     where 0 means no compression, 1 means the best compression
-#     speed, and 20 means best compression ratio which will consume
-#     more CPU.  Defaults to 1.  (Since 5.0)
-#
-# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
-#     aliases for the purpose of dirty bitmap migration.  Such aliases
-#     may for example be the corresponding names on the opposite site.
-#     The mapping must be one-to-one, but not necessarily complete: On
-#     the source, unmapped bitmaps and all bitmaps on unmapped nodes
-#     will be ignored.  On the destination, encountering an unmapped
-#     alias in the incoming migration stream will result in a report,
-#     and all further bitmap migration data will then be discarded.
-#     Note that the destination does not know about bitmaps it does
-#     not receive, so there is no limitation or requirement regarding
-#     the number of bitmaps received, or how they are named, or on
-#     which nodes they are placed.  By default (when this parameter
-#     has never been set), bitmap names are mapped to themselves.
-#     Nodes are mapped to their block device name if there is one, and
-#     to their node name otherwise.  (Since 5.2)
-#
-# @x-vcpu-dirty-limit-period: Periodic time (in milliseconds) of dirty
-#     limit during live migration.  Should be in the range 1 to
-#     1000ms.  Defaults to 1000ms.  (Since 8.1)
-#
-# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
-#     Defaults to 1.  (Since 8.1)
-#
-# @mode: Migration mode.  See description in `MigMode`.  Default is
-#     'normal'.  (Since 8.2)
-#
-# @zero-page-detection: Whether and how to detect zero pages.  See
-#     description in `ZeroPageDetection`.  Default is 'multifd'.
-#     (since 9.0)
-#
-# @direct-io: Open migration files with O_DIRECT when possible.  This
-#     only has effect if the @mapped-ram capability is enabled.
-#     (Since 9.1)
-#
-# @cpr-exec-command: Command to start the new QEMU process when @mode
-#     is @cpr-exec.  The first list element is the program's filename,
-#     the remainder its arguments.  (Since 10.2)
-#
-# Features:
-#
-# @unstable: Members @x-checkpoint-delay and
-#     @x-vcpu-dirty-limit-period are experimental.
-#
-# TODO: either fuse back into `MigrationParameters`, or make
-#     `MigrationParameters` members mandatory
-#
-# Since: 2.4
-##
-{ 'struct': 'MigrateSetParameters',
-  'data': { '*announce-initial': 'size',
-            '*announce-max': 'size',
-            '*announce-rounds': 'size',
-            '*announce-step': 'size',
-            '*throttle-trigger-threshold': 'uint8',
-            '*cpu-throttle-initial': 'uint8',
-            '*cpu-throttle-increment': 'uint8',
-            '*cpu-throttle-tailslow': 'bool',
-            '*tls-creds': 'StrOrNull',
-            '*tls-hostname': 'StrOrNull',
-            '*tls-authz': 'StrOrNull',
-            '*max-bandwidth': 'size',
-            '*avail-switchover-bandwidth': 'size',
-            '*downtime-limit': 'uint64',
-            '*x-checkpoint-delay': { 'type': 'uint32',
-                                     'features': [ 'unstable' ] },
-            '*multifd-channels': 'uint8',
-            '*xbzrle-cache-size': 'size',
-            '*max-postcopy-bandwidth': 'size',
-            '*max-cpu-throttle': 'uint8',
-            '*multifd-compression': 'MultiFDCompression',
-            '*multifd-zlib-level': 'uint8',
-            '*multifd-qatzip-level': 'uint8',
-            '*multifd-zstd-level': 'uint8',
-            '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ],
-            '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
-                                            'features': [ 'unstable' ] },
-            '*vcpu-dirty-limit': 'uint64',
-            '*mode': 'MigMode',
-            '*zero-page-detection': 'ZeroPageDetection',
-            '*direct-io': 'bool',
-            '*cpr-exec-command': [ 'str' ]} }
-
 ##
 # @migrate-set-parameters:
 #
-# Set various migration parameters.
+# Set migration parameters.  All arguments are optional.
 #
 # Since: 2.4
 #
@@ -1208,13 +1006,11 @@
 #     <- { "return": {} }
 ##
 { 'command': 'migrate-set-parameters', 'boxed': true,
-  'data': 'MigrateSetParameters' }
+  'data': 'MigrationParameters' }
 
 ##
 # @MigrationParameters:
 #
-# The optional members aren't actually optional.
-#
 # @announce-initial: Initial delay (in milliseconds) before sending
 #     the first announce (Since 4.0)
 #
@@ -1232,12 +1028,12 @@
 #     percentage.  The default value is 50.  (Since 5.0)
 #
 # @cpu-throttle-initial: Initial percentage of time guest cpus are
-#     throttled when migration auto-converge is activated.
-#     (Since 2.7)
+#     throttled when migration auto-converge is activated.  The
+#     default value is 20.  (Since 2.7)
 #
 # @cpu-throttle-increment: throttle percentage increase each time
 #     auto-converge detects that migration is not making progress.
-#     (Since 2.7)
+#     The default value is 10.  (Since 2.7)
 #
 # @cpu-throttle-tailslow: Make CPU throttling slower at tail stage.
 #     At the tail stage of throttling, the Guest is very sensitive to
@@ -1256,21 +1052,25 @@
 #     for establishing a TLS connection over the migration data
 #     channel.  On the outgoing side of the migration, the credentials
 #     must be for a 'client' endpoint, while for the incoming side the
-#     credentials must be for a 'server' endpoint.  An empty string
-#     means that QEMU will use plain text mode for migration, rather
-#     than TLS.  (Since 2.7)
-#
-#     Note: 2.8 omits empty @tls-creds instead.
+#     credentials must be for a 'server' endpoint.  Setting this to a
+#     non-empty string enables TLS for all migrations.  An empty
+#     string means that QEMU will use plain text mode for migration,
+#     rather than TLS.  This is the default.  (Since 2.7)
 #
 # @tls-hostname: migration target's hostname for validating the
 #     server's x509 certificate identity.  If empty, QEMU will use the
-#     hostname from the migration URI, if any.  (Since 2.7)
+#     hostname from the migration URI, if any.  A non-empty value is
+#     required when using x509 based TLS credentials and the migration
+#     URI does not include a hostname, such as fd: or exec: based
+#     migration.  (Since 2.7)
 #
-#     Note: 2.8 omits empty @tls-hostname instead.
+#     Note: empty value works only since 2.9.
 #
 # @tls-authz: ID of the 'authz' object subclass that provides access
 #     control checking of the TLS x509 certificate distinguished name.
-#     (Since 4.0)
+#     This object is only resolved at time of use, so can be deleted
+#     and recreated on the fly while the migration server is active.
+#     If missing, it will default to denying access (Since 4.0)
 #
 # @max-bandwidth: maximum speed for migration, in bytes per second.
 #     (Since 2.8)
@@ -1289,8 +1089,8 @@
 # @downtime-limit: set maximum tolerated downtime for migration.
 #     maximum downtime in milliseconds (Since 2.8)
 #
-# @x-checkpoint-delay: the delay time between two COLO checkpoints.
-#     (Since 2.8)
+# @x-checkpoint-delay: The delay time (in ms) between two COLO
+#     checkpoints in periodic mode.  (Since 2.8)
 #
 # @multifd-channels: Number of channels used to migrate data in
 #     parallel.  This is the same number that the number of sockets
@@ -1410,7 +1210,10 @@
 ##
 # @query-migrate-parameters:
 #
-# Return information about the current migration parameters
+# Return information about the current migration parameters.  Optional
+# members of the return value are always present, except
+# @block-bitmap-mapping, which is only present if it has been
+# previously set.
 #
 # Since: 2.4
 #
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 07/51] qapi/migration: Don't document MigrationParameter
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (5 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 06/51] migration: Remove MigrateSetParameters Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-15 21:59 ` [PATCH v3 08/51] migration: Run a post update routine after setting parameters Fabiano Rosas
                   ` (44 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Eric Blake

The MigrationParameter (singular) enumeration is not part of the
migration QMP API, it's only used for nicely converting HMP strings
into MigrationParameters (plural) members and for providing readline
completion.

Documenting this enum only serves to duplicate documentation between
MigrationParameter and MigrationParameters.

Add an exception to QAPIs pragma.json and stop documenting it.

The generated "QEMU QMP Reference Manual" now lists the enum members
as "Not documented."  Tolerable.

Acked-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 qapi/migration.json | 154 +-------------------------------------------
 qapi/pragma.json    |   1 +
 2 files changed, 3 insertions(+), 152 deletions(-)

diff --git a/qapi/migration.json b/qapi/migration.json
index fa4491b9b0..201dedd982 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -806,158 +806,8 @@
 ##
 # @MigrationParameter:
 #
-# Migration parameters enumeration
-#
-# @announce-initial: Initial delay (in milliseconds) before sending
-#     the first announce (Since 4.0)
-#
-# @announce-max: Maximum delay (in milliseconds) between packets in
-#     the announcement (Since 4.0)
-#
-# @announce-rounds: Number of self-announce packets sent after
-#     migration (Since 4.0)
-#
-# @announce-step: Increase in delay (in milliseconds) between
-#     subsequent packets in the announcement (Since 4.0)
-#
-# @throttle-trigger-threshold: The ratio of bytes_dirty_period and
-#     bytes_xfer_period to trigger throttling.  It is expressed as
-#     percentage.  The default value is 50.  (Since 5.0)
-#
-# @cpu-throttle-initial: Initial percentage of time guest cpus are
-#     throttled when migration auto-converge is activated.  The
-#     default value is 20.  (Since 2.7)
-#
-# @cpu-throttle-increment: throttle percentage increase each time
-#     auto-converge detects that migration is not making progress.
-#     The default value is 10.  (Since 2.7)
-#
-# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage.
-#     At the tail stage of throttling, the Guest is very sensitive to
-#     CPU percentage while the @cpu-throttle -increment is excessive
-#     usually at tail stage.  If this parameter is true, we will
-#     compute the ideal CPU percentage used by the Guest, which may
-#     exactly make the dirty rate match the dirty rate threshold.
-#     Then we will choose a smaller throttle increment between the one
-#     specified by @cpu-throttle-increment and the one generated by
-#     ideal CPU percentage.  Therefore, it is compatible to
-#     traditional throttling, meanwhile the throttle increment won't
-#     be excessive at tail stage.  The default value is false.
-#     (Since 5.1)
-#
-# @tls-creds: ID of the 'tls-creds' object that provides credentials
-#     for establishing a TLS connection over the migration data
-#     channel.  On the outgoing side of the migration, the credentials
-#     must be for a 'client' endpoint, while for the incoming side the
-#     credentials must be for a 'server' endpoint.  Setting this to a
-#     non-empty string enables TLS for all migrations.  An empty
-#     string means that QEMU will use plain text mode for migration,
-#     rather than TLS.  (Since 2.7)
-#
-# @tls-hostname: migration target's hostname for validating the
-#     server's x509 certificate identity.  If empty, QEMU will use the
-#     hostname from the migration URI, if any.  A non-empty value is
-#     required when using x509 based TLS credentials and the migration
-#     URI does not include a hostname, such as fd: or exec: based
-#     migration.  (Since 2.7)
-#
-#     Note: empty value works only since 2.9.
-#
-# @tls-authz: ID of the 'authz' object subclass that provides access
-#     control checking of the TLS x509 certificate distinguished name.
-#     This object is only resolved at time of use, so can be deleted
-#     and recreated on the fly while the migration server is active.
-#     If missing, it will default to denying access (Since 4.0)
-#
-# @max-bandwidth: maximum speed for migration, in bytes per second.
-#     (Since 2.8)
-#
-# @avail-switchover-bandwidth: to set the available bandwidth that
-#     migration can use during switchover phase.  **Note:** this does
-#     not limit the bandwidth during switchover, but only for
-#     calculations when making decisions to switchover.  By default,
-#     this value is zero, which means QEMU will estimate the bandwidth
-#     automatically.  This can be set when the estimated value is not
-#     accurate, while the user is able to guarantee such bandwidth is
-#     available when switching over.  When specified correctly, this
-#     can make the switchover decision much more accurate.
-#     (Since 8.2)
-#
-# @downtime-limit: set maximum tolerated downtime for migration.
-#     maximum downtime in milliseconds (Since 2.8)
-#
-# @x-checkpoint-delay: The delay time (in ms) between two COLO
-#     checkpoints in periodic mode.  (Since 2.8)
-#
-# @multifd-channels: Number of channels used to migrate data in
-#     parallel.  This is the same number that the number of sockets
-#     used for migration.  The default value is 2 (since 4.0)
-#
-# @xbzrle-cache-size: cache size to be used by XBZRLE migration.  It
-#     needs to be a multiple of the target page size and a power of 2
-#     (Since 2.11)
-#
-# @max-postcopy-bandwidth: Background transfer bandwidth during
-#     postcopy.  Defaults to 0 (unlimited).  In bytes per second.
-#     (Since 3.0)
-#
-# @max-cpu-throttle: maximum cpu throttle percentage.  Defaults to 99.
-#     (Since 3.1)
-#
-# @multifd-compression: Which compression method to use.  Defaults to
-#     none.  (Since 5.0)
-#
-# @multifd-zlib-level: Set the compression level to be used in live
-#     migration, the compression level is an integer between 0 and 9,
-#     where 0 means no compression, 1 means the best compression
-#     speed, and 9 means best compression ratio which will consume
-#     more CPU.  Defaults to 1.  (Since 5.0)
-#
-# @multifd-qatzip-level: Set the compression level to be used in live
-#     migration.  The level is an integer between 1 and 9, where 1
-#     means the best compression speed, and 9 means the best
-#     compression ratio which will consume more CPU.  Defaults to 1.
-#     (Since 9.2)
-#
-# @multifd-zstd-level: Set the compression level to be used in live
-#     migration, the compression level is an integer between 0 and 20,
-#     where 0 means no compression, 1 means the best compression
-#     speed, and 20 means best compression ratio which will consume
-#     more CPU.  Defaults to 1.  (Since 5.0)
-#
-# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
-#     aliases for the purpose of dirty bitmap migration.  Such aliases
-#     may for example be the corresponding names on the opposite site.
-#     The mapping must be one-to-one, but not necessarily complete: On
-#     the source, unmapped bitmaps and all bitmaps on unmapped nodes
-#     will be ignored.  On the destination, encountering an unmapped
-#     alias in the incoming migration stream will result in a report,
-#     and all further bitmap migration data will then be discarded.
-#     Note that the destination does not know about bitmaps it does
-#     not receive, so there is no limitation or requirement regarding
-#     the number of bitmaps received, or how they are named, or on
-#     which nodes they are placed.  By default (when this parameter
-#     has never been set), bitmap names are mapped to themselves.
-#     Nodes are mapped to their block device name if there is one, and
-#     to their node name otherwise.  (Since 5.2)
-#
-# @x-vcpu-dirty-limit-period: Periodic time (in milliseconds) of dirty
-#     limit during live migration.  Should be in the range 1 to
-#     1000ms.  Defaults to 1000ms.  (Since 8.1)
-#
-# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
-#     Defaults to 1.  (Since 8.1)
-#
-# @mode: Migration mode.  See description in `MigMode`.  Default is
-#     'normal'.  (Since 8.2)
-#
-# @zero-page-detection: Whether and how to detect zero pages.  See
-#     description in `ZeroPageDetection`.  Default is 'multifd'.
-#     (since 9.0)
-#
-# @direct-io: Open migration files with O_DIRECT when possible.  This
-#     only has effect if the @mapped-ram capability is enabled.
-#     (Since 9.1)
+# Migration parameters enumeration.  The enumeration values mirror the
+# members of @MigrationParameters.
 #
 # @cpr-exec-command: Command to start the new QEMU process when @mode
 #     is @cpr-exec.  The first list element is the program's filename,
diff --git a/qapi/pragma.json b/qapi/pragma.json
index 023a2ef7bc..193bc39059 100644
--- a/qapi/pragma.json
+++ b/qapi/pragma.json
@@ -59,6 +59,7 @@
         'IscsiTransport',
         'KeyValueKind',
         'MemoryDeviceInfoKind',
+        'MigrationParameter',
         'NetClientDriver',
         'ObjectType',
         'QKeyCode',
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 08/51] migration: Run a post update routine after setting parameters
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (6 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 07/51] qapi/migration: Don't document MigrationParameter Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-15 21:59 ` [PATCH v3 09/51] migration: Add a flag to track block-bitmap-mapping input Fabiano Rosas
                   ` (43 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

Some migration parameters are updated immediately once they are set
via migrate-set-parameters. Move that work outside of
migrate_params_apply() and leave that function with the single
responsibility of setting s->parameters and not doing any
side-effects.

Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/options.c | 38 ++++++++++++++++++++++++++++----------
 migration/ram.c     |  2 +-
 2 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/migration/options.c b/migration/options.c
index f14baa8561..e7f4aeaf03 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1123,6 +1123,31 @@ void migrate_params_init(MigrationParameters *params)
     params->has_cpr_exec_command = true;
 }
 
+static void migrate_post_update_params(MigrationParameters *new, Error **errp)
+{
+    MigrationState *s = migrate_get_current();
+
+    if (new->has_max_bandwidth) {
+        if (s->to_dst_file && !migration_in_postcopy()) {
+            migration_rate_set(new->max_bandwidth);
+        }
+    }
+
+    if (new->has_x_checkpoint_delay) {
+        colo_checkpoint_delay_set();
+    }
+
+    if (new->has_xbzrle_cache_size) {
+        xbzrle_cache_resize(new->xbzrle_cache_size, errp);
+    }
+
+    if (new->has_max_postcopy_bandwidth) {
+        if (s->to_dst_file && migration_in_postcopy()) {
+            migration_rate_set(new->max_postcopy_bandwidth);
+        }
+    }
+}
+
 /*
  * Check whether the parameters are valid. Error will be put into errp
  * (if provided). Return true if valid, otherwise false.
@@ -1437,7 +1462,7 @@ static void migrate_params_test_apply(MigrationParameters *params,
     }
 }
 
-static void migrate_params_apply(MigrationParameters *params, Error **errp)
+static void migrate_params_apply(MigrationParameters *params)
 {
     MigrationState *s = migrate_get_current();
 
@@ -1477,9 +1502,6 @@ static void migrate_params_apply(MigrationParameters *params, Error **errp)
 
     if (params->has_max_bandwidth) {
         s->parameters.max_bandwidth = params->max_bandwidth;
-        if (s->to_dst_file && !migration_in_postcopy()) {
-            migration_rate_set(s->parameters.max_bandwidth);
-        }
     }
 
     if (params->has_avail_switchover_bandwidth) {
@@ -1492,7 +1514,6 @@ static void migrate_params_apply(MigrationParameters *params, Error **errp)
 
     if (params->has_x_checkpoint_delay) {
         s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
-        colo_checkpoint_delay_set();
     }
 
     if (params->has_multifd_channels) {
@@ -1512,13 +1533,9 @@ static void migrate_params_apply(MigrationParameters *params, Error **errp)
     }
     if (params->has_xbzrle_cache_size) {
         s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
-        xbzrle_cache_resize(params->xbzrle_cache_size, errp);
     }
     if (params->has_max_postcopy_bandwidth) {
         s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
-        if (s->to_dst_file && migration_in_postcopy()) {
-            migration_rate_set(s->parameters.max_postcopy_bandwidth);
-        }
     }
     if (params->has_max_cpu_throttle) {
         s->parameters.max_cpu_throttle = params->max_cpu_throttle;
@@ -1592,7 +1609,8 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
     migrate_params_test_apply(params, &tmp);
 
     if (migrate_params_check(&tmp, errp)) {
-        migrate_params_apply(params, errp);
+        migrate_params_apply(params);
+        migrate_post_update_params(params, errp);
     }
 
     migrate_tls_opts_free(&tmp);
diff --git a/migration/ram.c b/migration/ram.c
index 29f016cb25..a49afbd995 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -176,7 +176,7 @@ static void XBZRLE_cache_unlock(void)
 /**
  * xbzrle_cache_resize: resize the xbzrle cache
  *
- * This function is called from migrate_params_apply in main
+ * This function is called from migrate_post_update_params in main
  * thread, possibly while a migration is in progress.  A running
  * migration may be using the cache and might finish during this call,
  * hence changes to the cache are protected by XBZRLE.lock().
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 09/51] migration: Add a flag to track block-bitmap-mapping input
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (7 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 08/51] migration: Run a post update routine after setting parameters Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-15 21:59 ` [PATCH v3 10/51] migration: Remove checks for s->parameters has_* fields Fabiano Rosas
                   ` (42 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Kevin Wolf

The QAPI converts an empty list on the block-bitmap-mapping input into
a NULL BitmapMigrationNodeAliasList. The empty list is a valid input
for the block-bitmap-mapping option, so commit 3cba22c9ad ("migration:
Fix block_bitmap_mapping migration") started using the
s->parameters.has_block_bitmap_mapping field to tell when the user has
passed in an empty list vs. when no list has been passed at all.

Using s->parameters.has_block_bitmap_mapping field is only possible
because MigrationParameters has had its members made optional due to
historical reasons.

In order to make improvements to the way configuration options are set
for a migration, we'd like to reduce the open-coded usage of the has_*
fields of the global configuration object (s->parameters).

Add a separate boolean to track the status of the block_bitmap_mapping
option.

No functional change intended.

(this was verified to not regress iotest 300, which is the test that
3cba22c9ad refers to)

CC: Kevin Wolf <kwolf@redhat.com>
Acked-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration-hmp-cmds.c | 3 ++-
 migration/migration.h          | 7 +++++++
 migration/options.c            | 6 +++---
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index a83aba9630..4f9f5800de 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -321,6 +321,7 @@ static void monitor_print_cpr_exec_command(Monitor *mon, strList *args)
 void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
 {
     MigrationParameters *params;
+    MigrationState *s = migrate_get_current();
 
     params = qmp_query_migrate_parameters(NULL);
 
@@ -407,7 +408,7 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
             MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH),
             params->max_postcopy_bandwidth);
 
-        if (params->has_block_bitmap_mapping) {
+        if (s->has_block_bitmap_mapping) {
             const BitmapMigrationNodeAliasList *bmnal;
 
             monitor_printf(mon, "%s:\n",
diff --git a/migration/migration.h b/migration/migration.h
index 213b33fe6e..20802596fb 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -514,6 +514,13 @@ struct MigrationState {
     QemuEvent postcopy_package_loaded_event;
 
     GSource *hup_source;
+
+    /*
+     * The block-bitmap-mapping option is allowed to be an empty list,
+     * therefore we need a way to know whether the user has given
+     * anything as input.
+     */
+    bool has_block_bitmap_mapping;
 };
 
 void migrate_set_state(MigrationStatus *state, MigrationStatus old_state,
diff --git a/migration/options.c b/migration/options.c
index e7f4aeaf03..5ef30e0f8d 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -784,7 +784,7 @@ bool migrate_has_block_bitmap_mapping(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->parameters.has_block_bitmap_mapping;
+    return s->has_block_bitmap_mapping;
 }
 
 uint32_t migrate_checkpoint_delay(void)
@@ -1069,7 +1069,7 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
     params->has_announce_step = true;
     params->announce_step = s->parameters.announce_step;
 
-    if (s->parameters.has_block_bitmap_mapping) {
+    if (s->has_block_bitmap_mapping) {
         params->has_block_bitmap_mapping = true;
         params->block_bitmap_mapping =
             QAPI_CLONE(BitmapMigrationNodeAliasList,
@@ -1557,7 +1557,7 @@ static void migrate_params_apply(MigrationParameters *params)
         qapi_free_BitmapMigrationNodeAliasList(
             s->parameters.block_bitmap_mapping);
 
-        s->parameters.has_block_bitmap_mapping = true;
+        s->has_block_bitmap_mapping = true;
         s->parameters.block_bitmap_mapping =
             QAPI_CLONE(BitmapMigrationNodeAliasList,
                        params->block_bitmap_mapping);
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 10/51] migration: Remove checks for s->parameters has_* fields
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (8 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 09/51] migration: Add a flag to track block-bitmap-mapping input Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-16 18:50   ` Peter Xu
  2025-12-15 21:59 ` [PATCH v3 11/51] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE Fabiano Rosas
                   ` (41 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

The migration parameters validation produces a temporary structure
which is the merge of the current parameter values (s->parameters,
MigrationParameters) with the new parameters set by the user
(former MigrateSetParameters).

When copying the values from s->parameters into the temporary
structure, the has_* fields are copied along, but when merging the
user-input values they are not.

During migrate_params_check(), only the parameters that have the
corresponding has_* field will be checked, so only the parameters that
were initialized in migrate_params_init() will be validated.

This causes (almost) all of the migration parameters to be validated
every time a parameter is set, regardless of which fields the user
touched, but it also skips validation of any values that are not set
in migrate_params_init().

It's not clear what was the intention of the original code, whether to
validate all fields always, or only validate what the user input
changed. Since the current situation is closer to the former option,
make the choice of validating all parameters by removing the checks
for the has_* fields when validating.

Note that bringing the user input into the temporary structure for
validation still needs to look at the has_* fields, otherwise any
parameters not set by the user (i.e. 0) would override the
corresponding value in s->parameters.

The empty migrate_params_init() will be kept because subsequent
patches will add code to it.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration.c |   2 +-
 migration/options.c   | 102 ++++++++++++------------------------------
 2 files changed, 30 insertions(+), 74 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 92c84c3177..35c1826633 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2120,7 +2120,7 @@ static bool migrate_prepare(MigrationState *s, bool resume, Error **errp)
     }
 
     if (migrate_mode() == MIG_MODE_CPR_EXEC &&
-        !s->parameters.has_cpr_exec_command) {
+        !s->parameters.cpr_exec_command) {
         error_setg(errp, "cpr-exec mode requires setting cpr-exec-command");
         return false;
     }
diff --git a/migration/options.c b/migration/options.c
index 5ef30e0f8d..855fa980a3 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1095,32 +1095,6 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
 
 void migrate_params_init(MigrationParameters *params)
 {
-    /* Set has_* up only for parameter checks */
-    params->has_throttle_trigger_threshold = true;
-    params->has_cpu_throttle_initial = true;
-    params->has_cpu_throttle_increment = true;
-    params->has_cpu_throttle_tailslow = true;
-    params->has_max_bandwidth = true;
-    params->has_downtime_limit = true;
-    params->has_x_checkpoint_delay = true;
-    params->has_multifd_channels = true;
-    params->has_multifd_compression = true;
-    params->has_multifd_zlib_level = true;
-    params->has_multifd_qatzip_level = true;
-    params->has_multifd_zstd_level = true;
-    params->has_xbzrle_cache_size = true;
-    params->has_max_postcopy_bandwidth = true;
-    params->has_max_cpu_throttle = true;
-    params->has_announce_initial = true;
-    params->has_announce_max = true;
-    params->has_announce_rounds = true;
-    params->has_announce_step = true;
-    params->has_x_vcpu_dirty_limit_period = true;
-    params->has_vcpu_dirty_limit = true;
-    params->has_mode = true;
-    params->has_zero_page_detection = true;
-    params->has_direct_io = true;
-    params->has_cpr_exec_command = true;
 }
 
 static void migrate_post_update_params(MigrationParameters *new, Error **errp)
@@ -1156,34 +1130,31 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
 {
     ERRP_GUARD();
 
-    if (params->has_throttle_trigger_threshold &&
-        (params->throttle_trigger_threshold < 1 ||
-         params->throttle_trigger_threshold > 100)) {
+    if (params->throttle_trigger_threshold < 1 ||
+        params->throttle_trigger_threshold > 100) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "throttle_trigger_threshold",
                    "an integer in the range of 1 to 100");
         return false;
     }
 
-    if (params->has_cpu_throttle_initial &&
-        (params->cpu_throttle_initial < 1 ||
-         params->cpu_throttle_initial > 99)) {
+    if (params->cpu_throttle_initial < 1 ||
+        params->cpu_throttle_initial > 99) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "cpu_throttle_initial",
                    "an integer in the range of 1 to 99");
         return false;
     }
 
-    if (params->has_cpu_throttle_increment &&
-        (params->cpu_throttle_increment < 1 ||
-         params->cpu_throttle_increment > 99)) {
+    if (params->cpu_throttle_increment < 1 ||
+        params->cpu_throttle_increment > 99) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "cpu_throttle_increment",
                    "an integer in the range of 1 to 99");
         return false;
     }
 
-    if (params->has_max_bandwidth && (params->max_bandwidth > SIZE_MAX)) {
+    if (params->max_bandwidth > SIZE_MAX) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "max_bandwidth",
                    "an integer in the range of 0 to "stringify(SIZE_MAX)
@@ -1191,8 +1162,7 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
         return false;
     }
 
-    if (params->has_avail_switchover_bandwidth &&
-        (params->avail_switchover_bandwidth > SIZE_MAX)) {
+    if (params->avail_switchover_bandwidth > SIZE_MAX) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "avail_switchover_bandwidth",
                    "an integer in the range of 0 to "stringify(SIZE_MAX)
@@ -1200,8 +1170,7 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
         return false;
     }
 
-    if (params->has_downtime_limit &&
-        (params->downtime_limit > MAX_MIGRATE_DOWNTIME)) {
+    if (params->downtime_limit > MAX_MIGRATE_DOWNTIME) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "downtime_limit",
                    "an integer in the range of 0 to "
@@ -1211,93 +1180,82 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
 
     /* x_checkpoint_delay is now always positive */
 
-    if (params->has_multifd_channels && (params->multifd_channels < 1)) {
+    if (params->multifd_channels < 1) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "multifd_channels",
                    "a value between 1 and 255");
         return false;
     }
 
-    if (params->has_multifd_zlib_level &&
-        (params->multifd_zlib_level > 9)) {
+    if (params->multifd_zlib_level > 9) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zlib_level",
                    "a value between 0 and 9");
         return false;
     }
 
-    if (params->has_multifd_qatzip_level &&
-        ((params->multifd_qatzip_level > 9) ||
-        (params->multifd_qatzip_level < 1))) {
+    if (params->multifd_qatzip_level > 9 ||
+        params->multifd_qatzip_level < 1) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_qatzip_level",
                    "a value between 1 and 9");
         return false;
     }
 
-    if (params->has_multifd_zstd_level &&
-        (params->multifd_zstd_level > 20)) {
+    if (params->multifd_zstd_level > 20) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zstd_level",
                    "a value between 0 and 20");
         return false;
     }
 
-    if (params->has_xbzrle_cache_size &&
-        (params->xbzrle_cache_size < qemu_target_page_size() ||
-         !is_power_of_2(params->xbzrle_cache_size))) {
+    if (params->xbzrle_cache_size < qemu_target_page_size() ||
+        !is_power_of_2(params->xbzrle_cache_size)) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "xbzrle_cache_size",
                    "a power of two no less than the target page size");
         return false;
     }
 
-    if (params->has_max_cpu_throttle &&
-        (params->max_cpu_throttle < params->cpu_throttle_initial ||
-         params->max_cpu_throttle > 99)) {
+    if (params->max_cpu_throttle < params->cpu_throttle_initial ||
+        params->max_cpu_throttle > 99) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "max_cpu_throttle",
                    "an integer in the range of cpu_throttle_initial to 99");
         return false;
     }
 
-    if (params->has_announce_initial &&
-        params->announce_initial > 100000) {
+    if (params->announce_initial > 100000) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "announce_initial",
                    "a value between 0 and 100000");
         return false;
     }
-    if (params->has_announce_max &&
-        params->announce_max > 100000) {
+    if (params->announce_max > 100000) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "announce_max",
                    "a value between 0 and 100000");
        return false;
     }
-    if (params->has_announce_rounds &&
-        params->announce_rounds > 1000) {
+    if (params->announce_rounds > 1000) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "announce_rounds",
                    "a value between 0 and 1000");
        return false;
     }
-    if (params->has_announce_step &&
-        (params->announce_step < 1 ||
-        params->announce_step > 10000)) {
+    if (params->announce_step < 1 ||
+        params->announce_step > 10000) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "announce_step",
                    "a value between 0 and 10000");
        return false;
     }
 
-    if (params->has_block_bitmap_mapping &&
-        !check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
+    if (!check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
         error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: ");
         return false;
     }
 
 #ifdef CONFIG_LINUX
     if (migrate_zero_copy_send() &&
-        ((params->has_multifd_compression && params->multifd_compression) ||
-         *params->tls_creds->u.s)) {
+        (params->multifd_compression || *params->tls_creds->u.s)) {
         error_setg(errp,
                    "Zero copy only available for non-compressed non-TLS multifd migration");
         return false;
@@ -1311,23 +1269,21 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
         return false;
     }
 
-    if (params->has_x_vcpu_dirty_limit_period &&
-        (params->x_vcpu_dirty_limit_period < 1 ||
-         params->x_vcpu_dirty_limit_period > 1000)) {
+    if (params->x_vcpu_dirty_limit_period < 1 ||
+        params->x_vcpu_dirty_limit_period > 1000) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                    "x-vcpu-dirty-limit-period",
                    "a value between 1 and 1000");
         return false;
     }
 
-    if (params->has_vcpu_dirty_limit &&
-        (params->vcpu_dirty_limit < 1)) {
+    if (params->vcpu_dirty_limit < 1) {
         error_setg(errp,
                    "Parameter 'vcpu_dirty_limit' must be greater than 1 MB/s");
         return false;
     }
 
-    if (params->has_direct_io && params->direct_io && !qemu_has_direct_io()) {
+    if (params->direct_io && !qemu_has_direct_io()) {
         error_setg(errp, "No build-time support for direct-io");
         return false;
     }
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 11/51] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (9 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 10/51] migration: Remove checks for s->parameters has_* fields Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-15 21:59 ` [PATCH v3 12/51] migration: Extract code to mark all parameters as present Fabiano Rosas
                   ` (40 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

The QERR_INVALID_PARAMETER_VALUE macro is documented as not to be used
in new code. Remove the usage from migration/options.c.

Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration.c  |  3 +--
 migration/options.c    | 56 +++++++++++++++---------------------------
 migration/page_cache.c |  6 ++---
 migration/ram.c        |  3 +--
 4 files changed, 24 insertions(+), 44 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 35c1826633..2c8acd2ee1 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2327,8 +2327,7 @@ static void qmp_migrate_finish(MigrationAddress *addr, bool resume_requested,
     } else if (addr->transport == MIGRATION_ADDRESS_TYPE_FILE) {
         file_start_outgoing_migration(s, &addr->u.file, &local_err);
     } else {
-        error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "uri",
-                   "a valid migration protocol");
+        error_setg(&local_err, "uri is not a valid migration protocol");
         migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
                           MIGRATION_STATUS_FAILED);
     }
diff --git a/migration/options.c b/migration/options.c
index 855fa980a3..c72e63015c 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1132,120 +1132,105 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
 
     if (params->throttle_trigger_threshold < 1 ||
         params->throttle_trigger_threshold > 100) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "throttle_trigger_threshold",
+        error_setg(errp, "Option throttle_trigger_threshold expects "
                    "an integer in the range of 1 to 100");
         return false;
     }
 
     if (params->cpu_throttle_initial < 1 ||
         params->cpu_throttle_initial > 99) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "cpu_throttle_initial",
+        error_setg(errp, "Option cpu_throttle_initial expects "
                    "an integer in the range of 1 to 99");
         return false;
     }
 
     if (params->cpu_throttle_increment < 1 ||
         params->cpu_throttle_increment > 99) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "cpu_throttle_increment",
+        error_setg(errp, "Option cpu_throttle_increment expects "
                    "an integer in the range of 1 to 99");
         return false;
     }
 
     if (params->max_bandwidth > SIZE_MAX) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "max_bandwidth",
+        error_setg(errp, "Option max_bandwidth expects "
                    "an integer in the range of 0 to "stringify(SIZE_MAX)
                    " bytes/second");
         return false;
     }
 
     if (params->avail_switchover_bandwidth > SIZE_MAX) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "avail_switchover_bandwidth",
+        error_setg(errp, "Option avail_switchover_bandwidth expects "
                    "an integer in the range of 0 to "stringify(SIZE_MAX)
                    " bytes/second");
         return false;
     }
 
     if (params->downtime_limit > MAX_MIGRATE_DOWNTIME) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "downtime_limit",
+        error_setg(errp, "Option downtime_limit expects "
                    "an integer in the range of 0 to "
                     stringify(MAX_MIGRATE_DOWNTIME)" ms");
         return false;
     }
 
-    /* x_checkpoint_delay is now always positive */
-
     if (params->multifd_channels < 1) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "multifd_channels",
+        error_setg(errp, "Option multifd_channels expects "
                    "a value between 1 and 255");
         return false;
     }
 
     if (params->multifd_zlib_level > 9) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zlib_level",
+        error_setg(errp, "Option multifd_zlib_level expects "
                    "a value between 0 and 9");
         return false;
     }
 
     if (params->multifd_qatzip_level > 9 ||
         params->multifd_qatzip_level < 1) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_qatzip_level",
+        error_setg(errp, "Option multifd_qatzip_level expects "
                    "a value between 1 and 9");
         return false;
     }
 
     if (params->multifd_zstd_level > 20) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zstd_level",
+        error_setg(errp, "Option multifd_zstd_level expects "
                    "a value between 0 and 20");
         return false;
     }
 
     if (params->xbzrle_cache_size < qemu_target_page_size() ||
         !is_power_of_2(params->xbzrle_cache_size)) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "xbzrle_cache_size",
+        error_setg(errp, "Option xbzrle_cache_size expects "
                    "a power of two no less than the target page size");
         return false;
     }
 
     if (params->max_cpu_throttle < params->cpu_throttle_initial ||
         params->max_cpu_throttle > 99) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "max_cpu_throttle",
+        error_setg(errp, "max_Option cpu_throttle expects "
                    "an integer in the range of cpu_throttle_initial to 99");
         return false;
     }
 
     if (params->announce_initial > 100000) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "announce_initial",
+        error_setg(errp, "Option announce_initial expects "
                    "a value between 0 and 100000");
         return false;
     }
     if (params->announce_max > 100000) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "announce_max",
+        error_setg(errp, "Option announce_max expects "
                    "a value between 0 and 100000");
-       return false;
+        return false;
     }
     if (params->announce_rounds > 1000) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "announce_rounds",
+        error_setg(errp, "Option announce_rounds expects "
                    "a value between 0 and 1000");
-       return false;
+        return false;
     }
     if (params->announce_step < 1 ||
         params->announce_step > 10000) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "announce_step",
+        error_setg(errp, "Option announce_step expects "
                    "a value between 0 and 10000");
-       return false;
+        return false;
     }
 
     if (!check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
@@ -1271,8 +1256,7 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
 
     if (params->x_vcpu_dirty_limit_period < 1 ||
         params->x_vcpu_dirty_limit_period > 1000) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-                   "x-vcpu-dirty-limit-period",
+        error_setg(errp, "Option x-vcpu-dirty-limit-period expects "
                    "a value between 1 and 1000");
         return false;
     }
diff --git a/migration/page_cache.c b/migration/page_cache.c
index 6d4f7a9bbc..650b15e48c 100644
--- a/migration/page_cache.c
+++ b/migration/page_cache.c
@@ -45,15 +45,13 @@ PageCache *cache_init(uint64_t new_size, size_t page_size, Error **errp)
     PageCache *cache;
 
     if (new_size < page_size) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
-                   "is smaller than one target page size");
+        error_setg(errp, "cache size is smaller than target page size");
         return NULL;
     }
 
     /* round down to the nearest power of 2 */
     if (!is_power_of_2(num_pages)) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
-                   "is not a power of two number of pages");
+        error_setg(errp, "number of pages is not a power of two");
         return NULL;
     }
 
diff --git a/migration/ram.c b/migration/ram.c
index a49afbd995..3eda85b110 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -193,8 +193,7 @@ int xbzrle_cache_resize(uint64_t new_size, Error **errp)
 
     /* Check for truncation */
     if (new_size != (size_t)new_size) {
-        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
-                   "exceeding address space");
+        error_setg(errp, "xbzrle cache size integer overflow");
         return -1;
     }
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 12/51] migration: Extract code to mark all parameters as present
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (10 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 11/51] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-16 18:56   ` Peter Xu
  2025-12-15 21:59 ` [PATCH v3 13/51] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters Fabiano Rosas
                   ` (39 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Kevin Wolf

MigrationParameters needs to have all of its has_* fields marked as
true when used as the return of query_migrate_parameters because the
corresponding QMP command has all of its members non-optional by
design, despite them being marked as optional in migration.json.

Extract this code into a function and make it assert if any field is
missing. With this we ensure future changes will not inadvertently
leave any parameters missing.

Note that the block-bitmap-mapping is a special case because the empty
list is considered a valid value, so it has historically not been
present in the command's output if it has never been set.

CC: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/options.c | 89 ++++++++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 34 deletions(-)

diff --git a/migration/options.c b/migration/options.c
index c72e63015c..aafd688f5c 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1018,6 +1018,44 @@ static void tls_opt_to_str(StrOrNull *opt)
     opt->u.s = g_strdup("");
 }
 
+/*
+ * query-migrate-parameters expects all members of MigrationParameters
+ * to be present, but we cannot mark them non-optional in QAPI because
+ * the structure is also used for migrate-set-parameters, which needs
+ * the optionality. Force all parameters to be seen as present
+ * now. Note that this depends on some form of default being set for
+ * every member of MigrationParameters, currently done during qdev
+ * init using migration_properties defined in this file. The TLS
+ * options are a special case because they don't have a default and
+ * need to be normalized before use.
+ */
+static void migrate_mark_all_params_present(MigrationParameters *p)
+{
+    int len, n_str_args = 3; /* tls-creds, tls-hostname, tls-authz */
+    bool *has_fields[] = {
+        &p->has_throttle_trigger_threshold, &p->has_cpu_throttle_initial,
+        &p->has_cpu_throttle_increment, &p->has_cpu_throttle_tailslow,
+        &p->has_max_bandwidth, &p->has_avail_switchover_bandwidth,
+        &p->has_downtime_limit, &p->has_x_checkpoint_delay,
+        &p->has_multifd_channels, &p->has_multifd_compression,
+        &p->has_multifd_zlib_level, &p->has_multifd_qatzip_level,
+        &p->has_multifd_zstd_level, &p->has_xbzrle_cache_size,
+        &p->has_max_postcopy_bandwidth, &p->has_max_cpu_throttle,
+        &p->has_announce_initial, &p->has_announce_max, &p->has_announce_rounds,
+        &p->has_announce_step, &p->has_block_bitmap_mapping,
+        &p->has_x_vcpu_dirty_limit_period, &p->has_vcpu_dirty_limit,
+        &p->has_mode, &p->has_zero_page_detection, &p->has_direct_io,
+        &p->has_cpr_exec_command,
+    };
+
+    len = ARRAY_SIZE(has_fields);
+    assert(len + n_str_args == MIGRATION_PARAMETER__MAX);
+
+    for (int i = 0; i < len; i++) {
+        *has_fields[i] = true;
+    }
+}
+
 MigrationParameters *qmp_query_migrate_parameters(Error **errp)
 {
     MigrationParameters *params;
@@ -1025,70 +1063,53 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
 
     /* TODO use QAPI_CLONE() instead of duplicating it inline */
     params = g_malloc0(sizeof(*params));
-    params->has_throttle_trigger_threshold = true;
+
     params->throttle_trigger_threshold = s->parameters.throttle_trigger_threshold;
-    params->has_cpu_throttle_initial = true;
     params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
-    params->has_cpu_throttle_increment = true;
     params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
-    params->has_cpu_throttle_tailslow = true;
     params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
     params->tls_creds = QAPI_CLONE(StrOrNull, s->parameters.tls_creds);
     params->tls_hostname = QAPI_CLONE(StrOrNull, s->parameters.tls_hostname);
     params->tls_authz = QAPI_CLONE(StrOrNull, s->parameters.tls_authz);
-    params->has_max_bandwidth = true;
     params->max_bandwidth = s->parameters.max_bandwidth;
-    params->has_avail_switchover_bandwidth = true;
     params->avail_switchover_bandwidth = s->parameters.avail_switchover_bandwidth;
-    params->has_downtime_limit = true;
     params->downtime_limit = s->parameters.downtime_limit;
-    params->has_x_checkpoint_delay = true;
     params->x_checkpoint_delay = s->parameters.x_checkpoint_delay;
-    params->has_multifd_channels = true;
     params->multifd_channels = s->parameters.multifd_channels;
-    params->has_multifd_compression = true;
     params->multifd_compression = s->parameters.multifd_compression;
-    params->has_multifd_zlib_level = true;
     params->multifd_zlib_level = s->parameters.multifd_zlib_level;
-    params->has_multifd_qatzip_level = true;
     params->multifd_qatzip_level = s->parameters.multifd_qatzip_level;
-    params->has_multifd_zstd_level = true;
     params->multifd_zstd_level = s->parameters.multifd_zstd_level;
-    params->has_xbzrle_cache_size = true;
     params->xbzrle_cache_size = s->parameters.xbzrle_cache_size;
-    params->has_max_postcopy_bandwidth = true;
     params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth;
-    params->has_max_cpu_throttle = true;
     params->max_cpu_throttle = s->parameters.max_cpu_throttle;
-    params->has_announce_initial = true;
     params->announce_initial = s->parameters.announce_initial;
-    params->has_announce_max = true;
     params->announce_max = s->parameters.announce_max;
-    params->has_announce_rounds = true;
     params->announce_rounds = s->parameters.announce_rounds;
-    params->has_announce_step = true;
     params->announce_step = s->parameters.announce_step;
-
-    if (s->has_block_bitmap_mapping) {
-        params->has_block_bitmap_mapping = true;
-        params->block_bitmap_mapping =
-            QAPI_CLONE(BitmapMigrationNodeAliasList,
-                       s->parameters.block_bitmap_mapping);
-    }
-
-    params->has_x_vcpu_dirty_limit_period = true;
     params->x_vcpu_dirty_limit_period = s->parameters.x_vcpu_dirty_limit_period;
-    params->has_vcpu_dirty_limit = true;
     params->vcpu_dirty_limit = s->parameters.vcpu_dirty_limit;
-    params->has_mode = true;
     params->mode = s->parameters.mode;
-    params->has_zero_page_detection = true;
     params->zero_page_detection = s->parameters.zero_page_detection;
-    params->has_direct_io = true;
     params->direct_io = s->parameters.direct_io;
-    params->has_cpr_exec_command = true;
     params->cpr_exec_command = QAPI_CLONE(strList,
                                           s->parameters.cpr_exec_command);
+    params->block_bitmap_mapping =
+        QAPI_CLONE(BitmapMigrationNodeAliasList,
+                   s->parameters.block_bitmap_mapping);
+
+    migrate_mark_all_params_present(params);
+
+    /*
+     * The block-bitmap-mapping breaks the expected API of
+     * query-migrate-parameters of having all members present. To keep
+     * compatibility, only emit this field if it's actually been
+     * set. The empty list is a valid value.
+     */
+    if (!s->has_block_bitmap_mapping) {
+        params->has_block_bitmap_mapping = false;
+        qapi_free_BitmapMigrationNodeAliasList(params->block_bitmap_mapping);
+    }
 
     return params;
 }
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 13/51] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (11 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 12/51] migration: Extract code to mark all parameters as present Fabiano Rosas
@ 2025-12-15 21:59 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 14/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply Fabiano Rosas
                   ` (38 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 21:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

QAPI_CLONE_MEMBERS is a better option than copying parameters one by
one because it operates on the entire struct and follows pointers. It
also avoids the need to alter this function every time a new parameter
is added.

For this to work, the has_* fields of s->parameters need to be already
set beforehand, so move migrate_mark_all_params_present() to the init
routine.

Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/options.c | 43 +++----------------------------------------
 1 file changed, 3 insertions(+), 40 deletions(-)

diff --git a/migration/options.c b/migration/options.c
index aafd688f5c..6b60003a32 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1058,47 +1058,9 @@ static void migrate_mark_all_params_present(MigrationParameters *p)
 
 MigrationParameters *qmp_query_migrate_parameters(Error **errp)
 {
-    MigrationParameters *params;
     MigrationState *s = migrate_get_current();
-
-    /* TODO use QAPI_CLONE() instead of duplicating it inline */
-    params = g_malloc0(sizeof(*params));
-
-    params->throttle_trigger_threshold = s->parameters.throttle_trigger_threshold;
-    params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
-    params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
-    params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
-    params->tls_creds = QAPI_CLONE(StrOrNull, s->parameters.tls_creds);
-    params->tls_hostname = QAPI_CLONE(StrOrNull, s->parameters.tls_hostname);
-    params->tls_authz = QAPI_CLONE(StrOrNull, s->parameters.tls_authz);
-    params->max_bandwidth = s->parameters.max_bandwidth;
-    params->avail_switchover_bandwidth = s->parameters.avail_switchover_bandwidth;
-    params->downtime_limit = s->parameters.downtime_limit;
-    params->x_checkpoint_delay = s->parameters.x_checkpoint_delay;
-    params->multifd_channels = s->parameters.multifd_channels;
-    params->multifd_compression = s->parameters.multifd_compression;
-    params->multifd_zlib_level = s->parameters.multifd_zlib_level;
-    params->multifd_qatzip_level = s->parameters.multifd_qatzip_level;
-    params->multifd_zstd_level = s->parameters.multifd_zstd_level;
-    params->xbzrle_cache_size = s->parameters.xbzrle_cache_size;
-    params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth;
-    params->max_cpu_throttle = s->parameters.max_cpu_throttle;
-    params->announce_initial = s->parameters.announce_initial;
-    params->announce_max = s->parameters.announce_max;
-    params->announce_rounds = s->parameters.announce_rounds;
-    params->announce_step = s->parameters.announce_step;
-    params->x_vcpu_dirty_limit_period = s->parameters.x_vcpu_dirty_limit_period;
-    params->vcpu_dirty_limit = s->parameters.vcpu_dirty_limit;
-    params->mode = s->parameters.mode;
-    params->zero_page_detection = s->parameters.zero_page_detection;
-    params->direct_io = s->parameters.direct_io;
-    params->cpr_exec_command = QAPI_CLONE(strList,
-                                          s->parameters.cpr_exec_command);
-    params->block_bitmap_mapping =
-        QAPI_CLONE(BitmapMigrationNodeAliasList,
-                   s->parameters.block_bitmap_mapping);
-
-    migrate_mark_all_params_present(params);
+    MigrationParameters *params = QAPI_CLONE(MigrationParameters,
+                                             &s->parameters);
 
     /*
      * The block-bitmap-mapping breaks the expected API of
@@ -1116,6 +1078,7 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
 
 void migrate_params_init(MigrationParameters *params)
 {
+    migrate_mark_all_params_present(params);
 }
 
 static void migrate_post_update_params(MigrationParameters *new, Error **errp)
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 14/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (12 preceding siblings ...)
  2025-12-15 21:59 ` [PATCH v3 13/51] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-16 19:31   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 15/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply Fabiano Rosas
                   ` (37 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

Use QAPI_CLONE_MEMBERS instead of making an assignment. The QAPI
method makes the handling of the TLS strings more intuitive because it
clones them as well.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/options.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/migration/options.c b/migration/options.c
index 6b60003a32..2901b37228 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1262,9 +1262,9 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
 static void migrate_params_test_apply(MigrationParameters *params,
                                       MigrationParameters *dest)
 {
-    *dest = migrate_get_current()->parameters;
+    MigrationState *s = migrate_get_current();
 
-    /* TODO use QAPI_CLONE() instead of duplicating it inline */
+    QAPI_CLONE_MEMBERS(MigrationParameters, dest, &s->parameters);
 
     if (params->has_throttle_trigger_threshold) {
         dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
@@ -1283,24 +1283,18 @@ static void migrate_params_test_apply(MigrationParameters *params,
     }
 
     if (params->tls_creds) {
+        qapi_free_StrOrNull(dest->tls_creds);
         dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
-    } else {
-        /* clear the reference, it's owned by s->parameters */
-        dest->tls_creds = NULL;
     }
 
     if (params->tls_hostname) {
+        qapi_free_StrOrNull(dest->tls_hostname);
         dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
-    } else {
-        /* clear the reference, it's owned by s->parameters */
-        dest->tls_hostname = NULL;
     }
 
     if (params->tls_authz) {
+        qapi_free_StrOrNull(dest->tls_authz);
         dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
-    } else {
-        /* clear the reference, it's owned by s->parameters */
-        dest->tls_authz = NULL;
     }
 
     if (params->has_max_bandwidth) {
@@ -1357,7 +1351,6 @@ static void migrate_params_test_apply(MigrationParameters *params,
     }
 
     if (params->has_block_bitmap_mapping) {
-        dest->has_block_bitmap_mapping = true;
         dest->block_bitmap_mapping = params->block_bitmap_mapping;
     }
 
@@ -1532,6 +1525,14 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
 
     migrate_params_test_apply(params, &tmp);
 
+    /*
+     * Mark block_bitmap_mapping as present now while we have the
+     * params structure with the user input around.
+     */
+    if (params->has_block_bitmap_mapping) {
+        migrate_get_current()->has_block_bitmap_mapping = true;
+    }
+
     if (migrate_params_check(&tmp, errp)) {
         migrate_params_apply(params);
         migrate_post_update_params(params, errp);
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 15/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (13 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 14/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-16 20:26   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 16/51] qapi: Add QAPI_MERGE Fabiano Rosas
                   ` (36 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

Instead of setting parameters one by one, use the temporary object,
which already contains the current migration parameters plus the new
ones and was just validated by migration_params_check(). Use cloning
to overwrite it.

This avoids the need to alter this function every time a new parameter
is added.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/options.c | 134 ++++----------------------------------------
 1 file changed, 12 insertions(+), 122 deletions(-)

diff --git a/migration/options.c b/migration/options.c
index 2901b37228..03e63c918c 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -13,6 +13,7 @@
 
 #include "qemu/osdep.h"
 #include "qemu/error-report.h"
+#include "qemu/main-loop.h"
 #include "exec/target_page.h"
 #include "qapi/clone-visitor.h"
 #include "qapi/error.h"
@@ -1379,132 +1380,21 @@ static void migrate_params_test_apply(MigrationParameters *params,
     }
 }
 
+/*
+ * Caller must ensure all has_* fields of @params are true to ensure
+ * all fields get copied and the pointer members don't dangle.
+ */
 static void migrate_params_apply(MigrationParameters *params)
 {
     MigrationState *s = migrate_get_current();
+    MigrationParameters *cur = &s->parameters;
 
-    /* TODO use QAPI_CLONE() instead of duplicating it inline */
+    assert(bql_locked());
 
-    if (params->has_throttle_trigger_threshold) {
-        s->parameters.throttle_trigger_threshold = params->throttle_trigger_threshold;
-    }
-
-    if (params->has_cpu_throttle_initial) {
-        s->parameters.cpu_throttle_initial = params->cpu_throttle_initial;
-    }
-
-    if (params->has_cpu_throttle_increment) {
-        s->parameters.cpu_throttle_increment = params->cpu_throttle_increment;
-    }
-
-    if (params->has_cpu_throttle_tailslow) {
-        s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow;
-    }
-
-    if (params->tls_creds) {
-        qapi_free_StrOrNull(s->parameters.tls_creds);
-        s->parameters.tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
-    }
-
-    if (params->tls_hostname) {
-        qapi_free_StrOrNull(s->parameters.tls_hostname);
-        s->parameters.tls_hostname = QAPI_CLONE(StrOrNull,
-                                                params->tls_hostname);
-    }
-
-    if (params->tls_authz) {
-        qapi_free_StrOrNull(s->parameters.tls_authz);
-        s->parameters.tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
-    }
-
-    if (params->has_max_bandwidth) {
-        s->parameters.max_bandwidth = params->max_bandwidth;
-    }
-
-    if (params->has_avail_switchover_bandwidth) {
-        s->parameters.avail_switchover_bandwidth = params->avail_switchover_bandwidth;
-    }
-
-    if (params->has_downtime_limit) {
-        s->parameters.downtime_limit = params->downtime_limit;
-    }
-
-    if (params->has_x_checkpoint_delay) {
-        s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
-    }
-
-    if (params->has_multifd_channels) {
-        s->parameters.multifd_channels = params->multifd_channels;
-    }
-    if (params->has_multifd_compression) {
-        s->parameters.multifd_compression = params->multifd_compression;
-    }
-    if (params->has_multifd_qatzip_level) {
-        s->parameters.multifd_qatzip_level = params->multifd_qatzip_level;
-    }
-    if (params->has_multifd_zlib_level) {
-        s->parameters.multifd_zlib_level = params->multifd_zlib_level;
-    }
-    if (params->has_multifd_zstd_level) {
-        s->parameters.multifd_zstd_level = params->multifd_zstd_level;
-    }
-    if (params->has_xbzrle_cache_size) {
-        s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
-    }
-    if (params->has_max_postcopy_bandwidth) {
-        s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
-    }
-    if (params->has_max_cpu_throttle) {
-        s->parameters.max_cpu_throttle = params->max_cpu_throttle;
-    }
-    if (params->has_announce_initial) {
-        s->parameters.announce_initial = params->announce_initial;
-    }
-    if (params->has_announce_max) {
-        s->parameters.announce_max = params->announce_max;
-    }
-    if (params->has_announce_rounds) {
-        s->parameters.announce_rounds = params->announce_rounds;
-    }
-    if (params->has_announce_step) {
-        s->parameters.announce_step = params->announce_step;
-    }
-
-    if (params->has_block_bitmap_mapping) {
-        qapi_free_BitmapMigrationNodeAliasList(
-            s->parameters.block_bitmap_mapping);
-
-        s->has_block_bitmap_mapping = true;
-        s->parameters.block_bitmap_mapping =
-            QAPI_CLONE(BitmapMigrationNodeAliasList,
-                       params->block_bitmap_mapping);
-    }
-
-    if (params->has_x_vcpu_dirty_limit_period) {
-        s->parameters.x_vcpu_dirty_limit_period =
-            params->x_vcpu_dirty_limit_period;
-    }
-    if (params->has_vcpu_dirty_limit) {
-        s->parameters.vcpu_dirty_limit = params->vcpu_dirty_limit;
-    }
-
-    if (params->has_mode) {
-        s->parameters.mode = params->mode;
-    }
-
-    if (params->has_zero_page_detection) {
-        s->parameters.zero_page_detection = params->zero_page_detection;
-    }
-
-    if (params->has_direct_io) {
-        s->parameters.direct_io = params->direct_io;
-    }
-
-    if (params->has_cpr_exec_command) {
-        qapi_free_strList(s->parameters.cpr_exec_command);
-        s->parameters.cpr_exec_command =
-            QAPI_CLONE(strList, params->cpr_exec_command);
-    }
+    migrate_tls_opts_free(cur);
+    qapi_free_BitmapMigrationNodeAliasList(cur->block_bitmap_mapping);
+    qapi_free_strList(cur->cpr_exec_command);
+    QAPI_CLONE_MEMBERS(MigrationParameters, cur, params);
 }
 
 void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
@@ -1534,7 +1424,7 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
     }
 
     if (migrate_params_check(&tmp, errp)) {
-        migrate_params_apply(params);
+        migrate_params_apply(&tmp);
         migrate_post_update_params(params, errp);
     }
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 16/51] qapi: Add QAPI_MERGE
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (14 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 15/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-16 20:30   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 17/51] migration: Use QAPI_MERGE in migrate_params_test_apply Fabiano Rosas
                   ` (35 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Michael Roth

The migration subsystem currently has code to merge two objects of the
same type. It does so by checking which fields are present in a source
object and overwriting the corresponding fields on the destination
object. This leads to a lot of open-coded lines such as:

    if (src->has_foobar) {
        dst->foobar = src->foobar;
    }

This pattern could be replaced by a copy using visitors. Implement a
macro that extracts elements from a source object using an output
visitor and merges it with a destination object using an input
visitor.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 include/qapi/type-helpers.h | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/include/qapi/type-helpers.h b/include/qapi/type-helpers.h
index fc8352cdec..011716c6ad 100644
--- a/include/qapi/type-helpers.h
+++ b/include/qapi/type-helpers.h
@@ -10,6 +10,8 @@
  */
 
 #include "qapi/qapi-types-common.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
 
 HumanReadableText *human_readable_text_from_str(GString *str);
 
@@ -20,3 +22,30 @@ HumanReadableText *human_readable_text_from_str(GString *str);
  * cleanup.
  */
 char **strv_from_str_list(const strList *list);
+
+/*
+ * Merge @src over @dst by copying deep clones of the present members
+ * from @src to @dst. Non-present on @src are left untouched on @dst.
+ */
+#define QAPI_MERGE(type, dst_, src_)                                    \
+    ({                                                                  \
+        QObject *out_ = NULL;                                           \
+        Visitor *v_;                                                    \
+        /* read in from src */                                          \
+        v_ = qobject_output_visitor_new(&out_);                         \
+        visit_type_ ## type(v_, NULL, &src_, &error_abort);             \
+        visit_complete(v_, &out_);                                      \
+        visit_free(v_);                                                 \
+        /*                                                              \
+         * Write to dst but leave existing fields intact (except for    \
+         * has_* which will be updated according to their presence in   \
+         * src).                                                        \
+         */                                                             \
+        v_ = qobject_input_visitor_new(out_);                           \
+        visit_start_struct(v_, NULL, NULL, 0, &error_abort);            \
+        visit_type_ ## type ## _members(v_, dst_, &error_abort);        \
+        visit_check_struct(v_, &error_abort);                           \
+        visit_end_struct(v_, NULL);                                     \
+        visit_free(v_);                                                 \
+        qobject_unref(out_);                                            \
+    })
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 17/51] migration: Use QAPI_MERGE in migrate_params_test_apply
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (15 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 16/51] qapi: Add QAPI_MERGE Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-16 20:47   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 18/51] migration: Cleanup hmp_info_migrate_parameters Fabiano Rosas
                   ` (34 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

Convert the code in migrate_params_test_apply() from an open-coded
copy of every migration parameter to a copy using visitors. The
current code has conditionals for each parameter's has_* field, which
is exactly what the visitors do.

This hides the details of QAPI from the migration code and avoids the
need to update migrate_params_test_apply() every time a new migration
parameter is added. Both were very confusing and while the visitor
code can become a bit involved, there is no need for new contributors
to ever touch it.

Change the name of the function to a more direct reference of what it
does: merging the user params with the temporary copy.

Move the QAPI_CLONE_MEMBERS into the caller, so QAPI_CLONE can be used
and there's no need to allocate memory in the migration
code. Similarly, turn 'tmp' into a pointer so the proper qapi_free_
routine can be used.

An extra call to migrate_mark_all_params_present() is now needed
because the visitors update the has_ field for non-present fields, but
we actually want them all set so migrate_params_apply() can copy all
of them.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/options.c | 137 +++++++-------------------------------------
 1 file changed, 22 insertions(+), 115 deletions(-)

diff --git a/migration/options.c b/migration/options.c
index 03e63c918c..36feaa5fe6 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -20,6 +20,7 @@
 #include "qapi/qapi-commands-migration.h"
 #include "qapi/qapi-visit-migration.h"
 #include "qapi/qmp/qerror.h"
+#include "qapi/type-helpers.h"
 #include "qobject/qnull.h"
 #include "system/runstate.h"
 #include "migration/colo.h"
@@ -1260,124 +1261,28 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
     return true;
 }
 
-static void migrate_params_test_apply(MigrationParameters *params,
-                                      MigrationParameters *dest)
+static void migrate_params_merge(MigrationParameters *dst,
+                                 MigrationParameters *src)
 {
-    MigrationState *s = migrate_get_current();
-
-    QAPI_CLONE_MEMBERS(MigrationParameters, dest, &s->parameters);
-
-    if (params->has_throttle_trigger_threshold) {
-        dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
-    }
-
-    if (params->has_cpu_throttle_initial) {
-        dest->cpu_throttle_initial = params->cpu_throttle_initial;
-    }
-
-    if (params->has_cpu_throttle_increment) {
-        dest->cpu_throttle_increment = params->cpu_throttle_increment;
+    /* free memory from pointers that are about to be assigned */
+    if (src->has_block_bitmap_mapping) {
+        g_clear_pointer(&dst->block_bitmap_mapping,
+                        qapi_free_BitmapMigrationNodeAliasList);
     }
 
-    if (params->has_cpu_throttle_tailslow) {
-        dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow;
+    if (src->tls_creds) {
+        g_clear_pointer(&dst->tls_creds, qapi_free_StrOrNull);
     }
 
-    if (params->tls_creds) {
-        qapi_free_StrOrNull(dest->tls_creds);
-        dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
+    if (src->tls_hostname) {
+        g_clear_pointer(&dst->tls_hostname, qapi_free_StrOrNull);
     }
 
-    if (params->tls_hostname) {
-        qapi_free_StrOrNull(dest->tls_hostname);
-        dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
+    if (src->tls_authz) {
+        g_clear_pointer(&dst->tls_authz, qapi_free_StrOrNull);
     }
 
-    if (params->tls_authz) {
-        qapi_free_StrOrNull(dest->tls_authz);
-        dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
-    }
-
-    if (params->has_max_bandwidth) {
-        dest->max_bandwidth = params->max_bandwidth;
-    }
-
-    if (params->has_avail_switchover_bandwidth) {
-        dest->avail_switchover_bandwidth = params->avail_switchover_bandwidth;
-    }
-
-    if (params->has_downtime_limit) {
-        dest->downtime_limit = params->downtime_limit;
-    }
-
-    if (params->has_x_checkpoint_delay) {
-        dest->x_checkpoint_delay = params->x_checkpoint_delay;
-    }
-
-    if (params->has_multifd_channels) {
-        dest->multifd_channels = params->multifd_channels;
-    }
-    if (params->has_multifd_compression) {
-        dest->multifd_compression = params->multifd_compression;
-    }
-    if (params->has_multifd_qatzip_level) {
-        dest->multifd_qatzip_level = params->multifd_qatzip_level;
-    }
-    if (params->has_multifd_zlib_level) {
-        dest->multifd_zlib_level = params->multifd_zlib_level;
-    }
-    if (params->has_multifd_zstd_level) {
-        dest->multifd_zstd_level = params->multifd_zstd_level;
-    }
-    if (params->has_xbzrle_cache_size) {
-        dest->xbzrle_cache_size = params->xbzrle_cache_size;
-    }
-    if (params->has_max_postcopy_bandwidth) {
-        dest->max_postcopy_bandwidth = params->max_postcopy_bandwidth;
-    }
-    if (params->has_max_cpu_throttle) {
-        dest->max_cpu_throttle = params->max_cpu_throttle;
-    }
-    if (params->has_announce_initial) {
-        dest->announce_initial = params->announce_initial;
-    }
-    if (params->has_announce_max) {
-        dest->announce_max = params->announce_max;
-    }
-    if (params->has_announce_rounds) {
-        dest->announce_rounds = params->announce_rounds;
-    }
-    if (params->has_announce_step) {
-        dest->announce_step = params->announce_step;
-    }
-
-    if (params->has_block_bitmap_mapping) {
-        dest->block_bitmap_mapping = params->block_bitmap_mapping;
-    }
-
-    if (params->has_x_vcpu_dirty_limit_period) {
-        dest->x_vcpu_dirty_limit_period =
-            params->x_vcpu_dirty_limit_period;
-    }
-    if (params->has_vcpu_dirty_limit) {
-        dest->vcpu_dirty_limit = params->vcpu_dirty_limit;
-    }
-
-    if (params->has_mode) {
-        dest->mode = params->mode;
-    }
-
-    if (params->has_zero_page_detection) {
-        dest->zero_page_detection = params->zero_page_detection;
-    }
-
-    if (params->has_direct_io) {
-        dest->direct_io = params->direct_io;
-    }
-
-    if (params->has_cpr_exec_command) {
-        dest->cpr_exec_command = params->cpr_exec_command;
-    }
+    QAPI_MERGE(MigrationParameters, dst, src);
 }
 
 /*
@@ -1399,7 +1304,9 @@ static void migrate_params_apply(MigrationParameters *params)
 
 void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
 {
-    MigrationParameters tmp;
+    MigrationState *s = migrate_get_current();
+    g_autoptr(MigrationParameters) tmp = QAPI_CLONE(MigrationParameters,
+                                                    &s->parameters);
 
     /*
      * Convert QTYPE_QNULL and NULL to the empty string (""). Even
@@ -1413,7 +1320,7 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
     tls_opt_to_str(params->tls_hostname);
     tls_opt_to_str(params->tls_authz);
 
-    migrate_params_test_apply(params, &tmp);
+    migrate_params_merge(tmp, params);
 
     /*
      * Mark block_bitmap_mapping as present now while we have the
@@ -1423,10 +1330,10 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
         migrate_get_current()->has_block_bitmap_mapping = true;
     }
 
-    if (migrate_params_check(&tmp, errp)) {
-        migrate_params_apply(&tmp);
+    if (migrate_params_check(tmp, errp)) {
+        /* mark all present, so they're all copied */
+        migrate_mark_all_params_present(tmp);
+        migrate_params_apply(tmp);
         migrate_post_update_params(params, errp);
     }
-
-    migrate_tls_opts_free(&tmp);
 }
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 18/51] migration: Cleanup hmp_info_migrate_parameters
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (16 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 17/51] migration: Use QAPI_MERGE in migrate_params_test_apply Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 19/51] migration: Add capabilities into MigrationParameters Fabiano Rosas
                   ` (33 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

Do a cleanup of hmp_info_migrate_parameters() before adding more lines
into it:

- Make sure every parameter asserts that the has_* field is
  set. qmp_query_migrate_parameters should have set them all. (except
  for block-bitmap-mapping)

- Remove the if (params), qmp_query_migrate_parameters never returns
  NULL.

- Add a macro to encapsulate boilerplate.

- Line breaks for legibility.

Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration-hmp-cmds.c | 292 ++++++++++++++++++---------------
 1 file changed, 163 insertions(+), 129 deletions(-)

diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 4f9f5800de..670ddb047b 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -33,6 +33,11 @@
 #include "options.h"
 #include "migration.h"
 
+#define PARAM_INFO(_a, _f, _e, _v) do {                                 \
+        assert(_a);                                                     \
+        monitor_printf(mon, _f, MigrationParameter_str(_e), _v);        \
+    } while (0)
+
 static void migration_global_dump(Monitor *mon)
 {
     MigrationState *ms = migrate_get_current();
@@ -324,140 +329,169 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
     MigrationState *s = migrate_get_current();
 
     params = qmp_query_migrate_parameters(NULL);
+    assert(params);
 
-    if (params) {
-        monitor_printf(mon, "%s: %" PRIu64 " ms\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_INITIAL),
-            params->announce_initial);
-        monitor_printf(mon, "%s: %" PRIu64 " ms\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_MAX),
-            params->announce_max);
-        monitor_printf(mon, "%s: %" PRIu64 "\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_ROUNDS),
-            params->announce_rounds);
-        monitor_printf(mon, "%s: %" PRIu64 " ms\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_STEP),
-            params->announce_step);
-        assert(params->has_throttle_trigger_threshold);
-        monitor_printf(mon, "%s: %u\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD),
-            params->throttle_trigger_threshold);
-        assert(params->has_cpu_throttle_initial);
-        monitor_printf(mon, "%s: %u\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL),
-            params->cpu_throttle_initial);
-        assert(params->has_cpu_throttle_increment);
-        monitor_printf(mon, "%s: %u\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT),
-            params->cpu_throttle_increment);
-        assert(params->has_cpu_throttle_tailslow);
-        monitor_printf(mon, "%s: %s\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW),
-            params->cpu_throttle_tailslow ? "on" : "off");
-        assert(params->has_max_cpu_throttle);
-        monitor_printf(mon, "%s: %u\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_MAX_CPU_THROTTLE),
-            params->max_cpu_throttle);
-        assert(params->tls_creds);
-        monitor_printf(mon, "%s: '%s'\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_TLS_CREDS),
-                       params->tls_creds->u.s);
-        assert(params->tls_hostname);
-        monitor_printf(mon, "%s: '%s'\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME),
-                       params->tls_hostname->u.s);
-        assert(params->tls_authz);
-        monitor_printf(mon, "%s: '%s'\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ),
-                       params->tls_authz->u.s);
-        assert(params->has_max_bandwidth);
-        monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH),
-            params->max_bandwidth);
-        assert(params->has_avail_switchover_bandwidth);
-        monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_AVAIL_SWITCHOVER_BANDWIDTH),
-            params->avail_switchover_bandwidth);
-        assert(params->has_max_postcopy_bandwidth);
-        monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH),
-            params->max_postcopy_bandwidth);
-        assert(params->has_downtime_limit);
-        monitor_printf(mon, "%s: %" PRIu64 " ms\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_DOWNTIME_LIMIT),
-            params->downtime_limit);
-        assert(params->has_x_checkpoint_delay);
-        monitor_printf(mon, "%s: %u ms\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_X_CHECKPOINT_DELAY),
-            params->x_checkpoint_delay);
-        monitor_printf(mon, "%s: %u\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_CHANNELS),
-            params->multifd_channels);
-        monitor_printf(mon, "%s: %s\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_COMPRESSION),
-            MultiFDCompression_str(params->multifd_compression));
-        assert(params->has_zero_page_detection);
-        monitor_printf(mon, "%s: %s\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_ZERO_PAGE_DETECTION),
-            qapi_enum_lookup(&ZeroPageDetection_lookup,
-                params->zero_page_detection));
-        monitor_printf(mon, "%s: %" PRIu64 " bytes\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE),
-            params->xbzrle_cache_size);
-        monitor_printf(mon, "%s: %" PRIu64 "\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH),
-            params->max_postcopy_bandwidth);
-
-        if (s->has_block_bitmap_mapping) {
-            const BitmapMigrationNodeAliasList *bmnal;
-
-            monitor_printf(mon, "%s:\n",
-                           MigrationParameter_str(
-                               MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING));
-
-            for (bmnal = params->block_bitmap_mapping;
-                 bmnal;
-                 bmnal = bmnal->next)
-            {
-                const BitmapMigrationNodeAlias *bmna = bmnal->value;
-                const BitmapMigrationBitmapAliasList *bmbal;
-
-                monitor_printf(mon, "  '%s' -> '%s'\n",
-                               bmna->node_name, bmna->alias);
-
-                for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) {
-                    const BitmapMigrationBitmapAlias *bmba = bmbal->value;
-
-                    monitor_printf(mon, "    '%s' -> '%s'\n",
-                                   bmba->name, bmba->alias);
-                }
+    PARAM_INFO(params->has_announce_initial,
+               "%s: %" PRIu64 " ms\n",
+               MIGRATION_PARAMETER_ANNOUNCE_INITIAL,
+               params->announce_initial);
+
+    PARAM_INFO(params->has_announce_max,
+               "%s: %" PRIu64 " ms\n",
+               MIGRATION_PARAMETER_ANNOUNCE_MAX,
+               params->announce_max);
+
+    PARAM_INFO(params->has_announce_rounds,
+               "%s: %" PRIu64 "\n",
+               MIGRATION_PARAMETER_ANNOUNCE_ROUNDS,
+               params->announce_rounds);
+
+    PARAM_INFO(params->has_announce_step,
+               "%s: %" PRIu64 " ms\n",
+               MIGRATION_PARAMETER_ANNOUNCE_STEP,
+               params->announce_step);
+
+    PARAM_INFO(params->has_throttle_trigger_threshold,
+               "%s: %u\n",
+               MIGRATION_PARAMETER_THROTTLE_TRIGGER_THRESHOLD,
+               params->throttle_trigger_threshold);
+
+    PARAM_INFO(params->has_cpu_throttle_initial,
+               "%s: %u\n",
+               MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL,
+               params->cpu_throttle_initial);
+
+    PARAM_INFO(params->has_cpu_throttle_increment,
+               "%s: %u\n",
+               MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT,
+               params->cpu_throttle_increment);
+
+    PARAM_INFO(params->has_cpu_throttle_tailslow,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_CPU_THROTTLE_TAILSLOW,
+               params->cpu_throttle_tailslow ? "on" : "off");
+
+    PARAM_INFO(params->has_max_cpu_throttle,
+               "%s: %u\n",
+               MIGRATION_PARAMETER_MAX_CPU_THROTTLE,
+               params->max_cpu_throttle);
+
+    PARAM_INFO(params->tls_creds,
+               "%s: '%s'\n",
+               MIGRATION_PARAMETER_TLS_CREDS,
+               params->tls_creds->u.s);
+
+    PARAM_INFO(params->tls_hostname,
+               "%s: '%s'\n",
+               MIGRATION_PARAMETER_TLS_HOSTNAME,
+               params->tls_hostname->u.s);
+
+    PARAM_INFO(params->has_max_bandwidth,
+               "%s: %" PRIu64 " bytes/second\n",
+               MIGRATION_PARAMETER_MAX_BANDWIDTH,
+               params->max_bandwidth);
+
+    PARAM_INFO(params->has_avail_switchover_bandwidth,
+               "%s: %" PRIu64 " bytes/second\n",
+               MIGRATION_PARAMETER_AVAIL_SWITCHOVER_BANDWIDTH,
+               params->avail_switchover_bandwidth);
+
+    PARAM_INFO(params->has_downtime_limit,
+               "%s: %" PRIu64 " ms\n",
+               MIGRATION_PARAMETER_DOWNTIME_LIMIT,
+               params->downtime_limit);
+
+    PARAM_INFO(params->has_x_checkpoint_delay,
+               "%s: %u ms\n",
+               MIGRATION_PARAMETER_X_CHECKPOINT_DELAY,
+               params->x_checkpoint_delay);
+
+    PARAM_INFO(params->has_multifd_channels,
+               "%s: %u\n",
+               MIGRATION_PARAMETER_MULTIFD_CHANNELS,
+               params->multifd_channels);
+
+    PARAM_INFO(params->has_multifd_compression,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_MULTIFD_COMPRESSION,
+               qapi_enum_lookup(&MultiFDCompression_lookup,
+                                params->multifd_compression));
+
+    PARAM_INFO(params->has_zero_page_detection,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_ZERO_PAGE_DETECTION,
+               qapi_enum_lookup(&ZeroPageDetection_lookup,
+                                params->zero_page_detection));
+
+    PARAM_INFO(params->has_xbzrle_cache_size,
+               "%s: %" PRIu64 " bytes\n",
+               MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE,
+               params->xbzrle_cache_size);
+
+    PARAM_INFO(params->has_max_postcopy_bandwidth,
+               "%s: %" PRIu64 "\n",
+               MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH,
+               params->max_postcopy_bandwidth);
+
+    PARAM_INFO(params->tls_authz,
+               "%s: '%s'\n",
+               MIGRATION_PARAMETER_TLS_AUTHZ,
+               params->tls_authz->u.s);
+
+    if (s->has_block_bitmap_mapping) {
+        const BitmapMigrationNodeAliasList *bmnal;
+
+        monitor_printf(mon, "%s:\n",
+                       MigrationParameter_str(
+                           MIGRATION_PARAMETER_BLOCK_BITMAP_MAPPING));
+
+        for (bmnal = params->block_bitmap_mapping;
+             bmnal;
+             bmnal = bmnal->next)
+        {
+            const BitmapMigrationNodeAlias *bmna = bmnal->value;
+            const BitmapMigrationBitmapAliasList *bmbal;
+
+            monitor_printf(mon, "  '%s' -> '%s'\n",
+                           bmna->node_name, bmna->alias);
+
+            for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) {
+                const BitmapMigrationBitmapAlias *bmba = bmbal->value;
+
+                monitor_printf(mon, "    '%s' -> '%s'\n",
+                               bmba->name, bmba->alias);
             }
         }
-
-        monitor_printf(mon, "%s: %" PRIu64 " ms\n",
-        MigrationParameter_str(MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD),
-        params->x_vcpu_dirty_limit_period);
-
-        monitor_printf(mon, "%s: %" PRIu64 " MB/s\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_VCPU_DIRTY_LIMIT),
-            params->vcpu_dirty_limit);
-
-        assert(params->has_mode);
-        monitor_printf(mon, "%s: %s\n",
-            MigrationParameter_str(MIGRATION_PARAMETER_MODE),
-            qapi_enum_lookup(&MigMode_lookup, params->mode));
-
-        if (params->has_direct_io) {
-            monitor_printf(mon, "%s: %s\n",
-                           MigrationParameter_str(
-                               MIGRATION_PARAMETER_DIRECT_IO),
-                           params->direct_io ? "on" : "off");
-        }
-
-        assert(params->has_cpr_exec_command);
-        monitor_print_cpr_exec_command(mon, params->cpr_exec_command);
     }
 
+    PARAM_INFO(params->has_x_vcpu_dirty_limit_period,
+               "%s: %" PRIu64 " ms\n",
+               MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD,
+               params->x_vcpu_dirty_limit_period);
+
+    PARAM_INFO(params->has_vcpu_dirty_limit,
+               "%s: %" PRIu64 " MB/s\n",
+               MIGRATION_PARAMETER_VCPU_DIRTY_LIMIT,
+               params->vcpu_dirty_limit);
+
+    PARAM_INFO(params->has_mode,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_MODE,
+               qapi_enum_lookup(&MigMode_lookup, params->mode));
+
+    PARAM_INFO(params->has_direct_io,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_DIRECT_IO,
+               params->direct_io ? "on" : "off");
+
+    PARAM_INFO(params->has_max_postcopy_bandwidth,
+               "%s: %" PRIu64 "\n",
+               MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH,
+               params->max_postcopy_bandwidth);
+
+    assert(params->has_cpr_exec_command);
+    monitor_print_cpr_exec_command(mon, params->cpr_exec_command);
+
     qapi_free_MigrationParameters(params);
 }
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 19/51] migration: Add capabilities into MigrationParameters
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (17 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 18/51] migration: Cleanup hmp_info_migrate_parameters Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 20/51] migration: Remove s->capabilities Fabiano Rosas
                   ` (32 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Eric Blake

Add capabilities to MigrationParameters. This structure will hold all
migration options. Capabilities will go away in the next patch.

Also add capabilities to MigrationParameter as the enum needs to be
kept in sync with MigrationParameters. This affects the parsing of
migration HMP commands so make the necessary additions there too.

(while here, also ensure MigrationParameter has their members in the
same order relative to MigrationParameters)

From this point on, both QMP and HMP versions of
migrate-set-parameters and query-migrate-parameters gain the ability
to work with capabilities.

With MigrationParameters now having members for each capability, the
migration capabilities commands (query-migrate-capabilities,
migrate-set-capabilities) will soon be deprecated. Add a set of
helpers to convert between the old MigrationCapability representation
and the new representation as members of MigrationParameters.

Acked-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration-hmp-cmds.c | 198 +++++++++++++++++++++++++++++++++
 migration/migration.c          |   8 ++
 migration/options.c            | 130 +++++++++++++++++++++-
 migration/options.h            |   5 +
 qapi/migration.json            | 140 ++++++++++++++++++++++-
 5 files changed, 474 insertions(+), 7 deletions(-)

diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 670ddb047b..28b48c34bf 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -492,6 +492,116 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
     assert(params->has_cpr_exec_command);
     monitor_print_cpr_exec_command(mon, params->cpr_exec_command);
 
+    PARAM_INFO(params->has_xbzrle,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_XBZRLE,
+               params->xbzrle ? "on" : "off");
+
+    PARAM_INFO(params->has_rdma_pin_all,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_RDMA_PIN_ALL,
+               params->rdma_pin_all ? "on" : "off");
+
+    PARAM_INFO(params->has_auto_converge,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_AUTO_CONVERGE,
+               params->auto_converge ? "on" : "off");
+
+    PARAM_INFO(params->has_zero_blocks,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_ZERO_BLOCKS,
+               params->zero_blocks ? "on" : "off");
+
+    PARAM_INFO(params->has_events,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_EVENTS,
+               params->events ? "on" : "off");
+
+    PARAM_INFO(params->has_postcopy_ram,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_POSTCOPY_RAM,
+               params->postcopy_ram ? "on" : "off");
+
+    PARAM_INFO(params->has_x_colo,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_X_COLO,
+               params->x_colo ? "on" : "off");
+
+    PARAM_INFO(params->has_release_ram,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_RELEASE_RAM,
+               params->release_ram ? "on" : "off");
+
+    PARAM_INFO(params->has_return_path,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_RETURN_PATH,
+               params->return_path ? "on" : "off");
+
+    PARAM_INFO(params->has_pause_before_switchover,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_PAUSE_BEFORE_SWITCHOVER,
+               params->pause_before_switchover ? "on" : "off");
+
+    PARAM_INFO(params->has_multifd,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_MULTIFD,
+               params->multifd ? "on" : "off");
+
+    PARAM_INFO(params->has_dirty_bitmaps,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_DIRTY_BITMAPS,
+               params->dirty_bitmaps ? "on" : "off");
+
+    PARAM_INFO(params->has_postcopy_blocktime,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_POSTCOPY_BLOCKTIME,
+               params->postcopy_blocktime ? "on" : "off");
+
+    PARAM_INFO(params->has_late_block_activate,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_LATE_BLOCK_ACTIVATE,
+               params->late_block_activate ? "on" : "off");
+
+    PARAM_INFO(params->has_x_ignore_shared,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_X_IGNORE_SHARED,
+               params->x_ignore_shared ? "on" : "off");
+
+    PARAM_INFO(params->has_validate_uuid,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_VALIDATE_UUID,
+               params->validate_uuid ? "on" : "off");
+
+    PARAM_INFO(params->has_background_snapshot,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_BACKGROUND_SNAPSHOT,
+               params->background_snapshot ? "on" : "off");
+
+    PARAM_INFO(params->has_zero_copy_send,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_ZERO_COPY_SEND,
+               params->zero_copy_send ? "on" : "off");
+
+    PARAM_INFO(params->has_postcopy_preempt,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_POSTCOPY_PREEMPT,
+               params->postcopy_preempt ? "on" : "off");
+
+    PARAM_INFO(params->has_switchover_ack,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_SWITCHOVER_ACK,
+               params->switchover_ack ? "on" : "off");
+
+    PARAM_INFO(params->has_dirty_limit,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_DIRTY_LIMIT,
+               params->dirty_limit ? "on" : "off");
+
+    PARAM_INFO(params->has_mapped_ram,
+               "%s: %s\n",
+               MIGRATION_PARAMETER_MAPPED_RAM,
+               params->mapped_ram ? "on" : "off");
+
     qapi_free_MigrationParameters(params);
 }
 
@@ -792,6 +902,94 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
         p->has_cpr_exec_command = true;
         break;
     }
+    case MIGRATION_PARAMETER_XBZRLE:
+        p->has_xbzrle = true;
+        visit_type_bool(v, param, &p->xbzrle, &err);
+        break;
+    case MIGRATION_PARAMETER_RDMA_PIN_ALL:
+        p->has_rdma_pin_all = true;
+        visit_type_bool(v, param, &p->rdma_pin_all, &err);
+        break;
+    case MIGRATION_PARAMETER_AUTO_CONVERGE:
+        p->has_auto_converge = true;
+        visit_type_bool(v, param, &p->auto_converge, &err);
+        break;
+    case MIGRATION_PARAMETER_ZERO_BLOCKS:
+        p->has_zero_blocks = true;
+        visit_type_bool(v, param, &p->zero_blocks, &err);
+        break;
+    case MIGRATION_PARAMETER_EVENTS:
+        p->has_events = true;
+        visit_type_bool(v, param, &p->events, &err);
+        break;
+    case MIGRATION_PARAMETER_POSTCOPY_RAM:
+        p->has_postcopy_ram = true;
+        visit_type_bool(v, param, &p->postcopy_ram, &err);
+        break;
+    case MIGRATION_PARAMETER_X_COLO:
+        p->has_x_colo = true;
+        visit_type_bool(v, param, &p->x_colo, &err);
+        break;
+    case MIGRATION_PARAMETER_RELEASE_RAM:
+        p->has_release_ram = true;
+        visit_type_bool(v, param, &p->release_ram, &err);
+        break;
+    case MIGRATION_PARAMETER_RETURN_PATH:
+        p->has_return_path = true;
+        visit_type_bool(v, param, &p->return_path, &err);
+        break;
+    case MIGRATION_PARAMETER_PAUSE_BEFORE_SWITCHOVER:
+        p->has_pause_before_switchover = true;
+        visit_type_bool(v, param, &p->pause_before_switchover, &err);
+        break;
+    case MIGRATION_PARAMETER_MULTIFD:
+        p->has_multifd = true;
+        visit_type_bool(v, param, &p->multifd, &err);
+        break;
+    case MIGRATION_PARAMETER_DIRTY_BITMAPS:
+        p->has_dirty_bitmaps = true;
+        visit_type_bool(v, param, &p->dirty_bitmaps, &err);
+        break;
+    case MIGRATION_PARAMETER_POSTCOPY_BLOCKTIME:
+        p->has_postcopy_blocktime = true;
+        visit_type_bool(v, param, &p->postcopy_blocktime, &err);
+        break;
+    case MIGRATION_PARAMETER_LATE_BLOCK_ACTIVATE:
+        p->has_late_block_activate = true;
+        visit_type_bool(v, param, &p->late_block_activate, &err);
+        break;
+    case MIGRATION_PARAMETER_X_IGNORE_SHARED:
+        p->has_x_ignore_shared = true;
+        visit_type_bool(v, param, &p->x_ignore_shared, &err);
+        break;
+    case MIGRATION_PARAMETER_VALIDATE_UUID:
+        p->has_validate_uuid = true;
+        visit_type_bool(v, param, &p->validate_uuid, &err);
+        break;
+    case MIGRATION_PARAMETER_BACKGROUND_SNAPSHOT:
+        p->has_background_snapshot = true;
+        visit_type_bool(v, param, &p->background_snapshot, &err);
+        break;
+    case MIGRATION_PARAMETER_ZERO_COPY_SEND:
+        p->has_zero_copy_send = true;
+        visit_type_bool(v, param, &p->zero_copy_send, &err);
+        break;
+    case MIGRATION_PARAMETER_POSTCOPY_PREEMPT:
+        p->has_postcopy_preempt = true;
+        visit_type_bool(v, param, &p->postcopy_preempt, &err);
+        break;
+    case MIGRATION_PARAMETER_SWITCHOVER_ACK:
+        p->has_switchover_ack = true;
+        visit_type_bool(v, param, &p->switchover_ack, &err);
+        break;
+    case MIGRATION_PARAMETER_DIRTY_LIMIT:
+        p->has_dirty_limit = true;
+        visit_type_bool(v, param, &p->dirty_limit, &err);
+        break;
+    case MIGRATION_PARAMETER_MAPPED_RAM:
+        p->has_mapped_ram = true;
+        visit_type_bool(v, param, &p->mapped_ram, &err);
+        break;
     default:
         g_assert_not_reached();
     }
diff --git a/migration/migration.c b/migration/migration.c
index 2c8acd2ee1..f0e74cbf4b 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -4196,6 +4196,14 @@ static bool migration_object_check(MigrationState *ms, Error **errp)
         return false;
     }
 
+    /*
+     * FIXME: Temporarily while -global capabilties are still using
+     * s->capabilities. Will be gone by the end of the series.
+     */
+    for (int i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+        migrate_capability_set_compat(&ms->parameters, i, ms->capabilities[i]);
+    }
+
     return migrate_caps_check(old_caps, ms->capabilities, errp);
 }
 
diff --git a/migration/options.c b/migration/options.c
index 36feaa5fe6..b23dcc15f9 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -730,6 +730,111 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
     return true;
 }
 
+static bool *migrate_capability_get_addr(MigrationParameters *params, int i)
+{
+    bool *cap_addr = NULL;
+
+    switch (i) {
+    case MIGRATION_CAPABILITY_XBZRLE:
+        cap_addr = &params->xbzrle;
+        break;
+    case MIGRATION_CAPABILITY_RDMA_PIN_ALL:
+        cap_addr = &params->rdma_pin_all;
+        break;
+    case MIGRATION_CAPABILITY_AUTO_CONVERGE:
+        cap_addr = &params->auto_converge;
+        break;
+    case MIGRATION_CAPABILITY_ZERO_BLOCKS:
+        cap_addr = &params->zero_blocks;
+        break;
+    case MIGRATION_CAPABILITY_EVENTS:
+        cap_addr = &params->events;
+        break;
+    case MIGRATION_CAPABILITY_POSTCOPY_RAM:
+        cap_addr = &params->postcopy_ram;
+        break;
+    case MIGRATION_CAPABILITY_X_COLO:
+        cap_addr = &params->x_colo;
+        break;
+    case MIGRATION_CAPABILITY_RELEASE_RAM:
+        cap_addr = &params->release_ram;
+        break;
+    case MIGRATION_CAPABILITY_RETURN_PATH:
+        cap_addr = &params->return_path;
+        break;
+    case MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER:
+        cap_addr = &params->pause_before_switchover;
+        break;
+    case MIGRATION_CAPABILITY_MULTIFD:
+        cap_addr = &params->multifd;
+        break;
+    case MIGRATION_CAPABILITY_DIRTY_BITMAPS:
+        cap_addr = &params->dirty_bitmaps;
+        break;
+    case MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME:
+        cap_addr = &params->postcopy_blocktime;
+        break;
+    case MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE:
+        cap_addr = &params->late_block_activate;
+        break;
+    case MIGRATION_CAPABILITY_X_IGNORE_SHARED:
+        cap_addr = &params->x_ignore_shared;
+        break;
+    case MIGRATION_CAPABILITY_VALIDATE_UUID:
+        cap_addr = &params->validate_uuid;
+        break;
+    case MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT:
+        cap_addr = &params->background_snapshot;
+        break;
+    case MIGRATION_CAPABILITY_ZERO_COPY_SEND:
+        cap_addr = &params->zero_copy_send;
+        break;
+    case MIGRATION_CAPABILITY_POSTCOPY_PREEMPT:
+        cap_addr = &params->postcopy_preempt;
+        break;
+    case MIGRATION_CAPABILITY_SWITCHOVER_ACK:
+        cap_addr = &params->switchover_ack;
+        break;
+    case MIGRATION_CAPABILITY_DIRTY_LIMIT:
+        cap_addr = &params->dirty_limit;
+        break;
+    case MIGRATION_CAPABILITY_MAPPED_RAM:
+        cap_addr = &params->mapped_ram;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    return cap_addr;
+}
+
+/* Compatibility for code that reads capabilities in a loop */
+bool migrate_capability_get_compat(MigrationParameters *params, int i)
+{
+    return *(migrate_capability_get_addr(params, i));
+}
+
+/* Compatibility for code that writes capabilities in a loop */
+void migrate_capability_set_compat(MigrationParameters *params, int i, bool val)
+{
+    *(migrate_capability_get_addr(params, i)) = val;
+}
+
+/*
+ * Set capabilities for compatibility with the old
+ * migrate-set-capabilities command.
+ */
+void migrate_capabilities_set_compat(MigrationParameters *params,
+                                     MigrationCapabilityStatusList *caps)
+{
+    MigrationCapabilityStatusList *cap;
+
+    for (cap = caps; cap; cap = cap->next) {
+        migrate_capability_set_compat(params, cap->value->capability,
+                                      cap->value->state);
+    }
+}
+
 MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
 {
     MigrationCapabilityStatusList *head = NULL, **tail = &head;
@@ -771,6 +876,8 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
     for (cap = params; cap; cap = cap->next) {
         s->capabilities[cap->value->capability] = cap->value->state;
     }
+
+    migrate_capabilities_set_compat(&s->parameters, params);
 }
 
 /* parameters */
@@ -1047,7 +1154,15 @@ static void migrate_mark_all_params_present(MigrationParameters *p)
         &p->has_announce_step, &p->has_block_bitmap_mapping,
         &p->has_x_vcpu_dirty_limit_period, &p->has_vcpu_dirty_limit,
         &p->has_mode, &p->has_zero_page_detection, &p->has_direct_io,
-        &p->has_cpr_exec_command,
+        &p->has_cpr_exec_command, &p->has_xbzrle, &p->has_rdma_pin_all,
+        &p->has_auto_converge, &p->has_zero_blocks, &p->has_events,
+        &p->has_postcopy_ram, &p->has_x_colo, &p->has_release_ram,
+        &p->has_return_path, &p->has_pause_before_switchover, &p->has_multifd,
+        &p->has_dirty_bitmaps, &p->has_postcopy_blocktime,
+        &p->has_late_block_activate, &p->has_x_ignore_shared,
+        &p->has_validate_uuid, &p->has_background_snapshot,
+        &p->has_zero_copy_send, &p->has_postcopy_preempt,
+        &p->has_switchover_ack, &p->has_dirty_limit, &p->has_mapped_ram,
     };
 
     len = ARRAY_SIZE(has_fields);
@@ -1320,6 +1435,19 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
     tls_opt_to_str(params->tls_hostname);
     tls_opt_to_str(params->tls_authz);
 
+    /*
+     * FIXME: Temporarily while migrate_caps_check is not
+     * converted to look at s->parameters. Will be gone the end of
+     * the series.
+     */
+    bool new_caps[MIGRATION_CAPABILITY__MAX] = { 0 };
+    for (int i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+        new_caps[i] = migrate_capability_get_compat(&s->parameters, i);
+    }
+    if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
+        return;
+    }
+
     migrate_params_merge(tmp, params);
 
     /*
diff --git a/migration/options.h b/migration/options.h
index 25fb316420..794cf23870 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -93,4 +93,9 @@ ZeroPageDetection migrate_zero_page_detection(void);
 bool migrate_params_check(MigrationParameters *params, Error **errp);
 void migrate_params_init(MigrationParameters *params);
 void migrate_tls_opts_free(MigrationParameters *params);
+bool migrate_capability_get_compat(MigrationParameters *params, int i);
+void migrate_capability_set_compat(MigrationParameters *params, int i,
+                                   bool val);
+void migrate_capabilities_set_compat(MigrationParameters *params,
+                                     MigrationCapabilityStatusList *caps);
 #endif
diff --git a/qapi/migration.json b/qapi/migration.json
index 201dedd982..fcbb699a47 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -832,15 +832,22 @@
            'multifd-channels',
            'xbzrle-cache-size', 'max-postcopy-bandwidth',
            'max-cpu-throttle', 'multifd-compression',
-           'multifd-zlib-level', 'multifd-zstd-level',
-           'multifd-qatzip-level',
+           'multifd-zlib-level', 'multifd-qatzip-level', 'multifd-zstd-level',
            'block-bitmap-mapping',
            { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] },
            'vcpu-dirty-limit',
            'mode',
            'zero-page-detection',
            'direct-io',
-           'cpr-exec-command'] }
+           'cpr-exec-command',
+           'xbzrle', 'rdma-pin-all', 'auto-converge',
+           'zero-blocks', 'events', 'postcopy-ram', 'x-colo',
+           'release-ram', 'return-path', 'pause-before-switchover',
+           'multifd', 'dirty-bitmaps', 'postcopy-blocktime',
+           'late-block-activate', 'x-ignore-shared',
+           'validate-uuid', 'background-snapshot',
+           'zero-copy-send', 'postcopy-preempt',
+           'switchover-ack', 'dirty-limit', 'mapped-ram' ] }
 
 ##
 # @migrate-set-parameters:
@@ -1016,10 +1023,109 @@
 #     is @cpr-exec.  The first list element is the program's filename,
 #     the remainder its arguments.  (Since 10.2)
 #
+# @xbzrle: Migration supports xbzrle (Xor Based Zero Run Length
+#     Encoding).  This feature allows us to minimize migration traffic
+#     for certain work loads, by sending compressed difference of the
+#     pages
+#
+# @rdma-pin-all: Controls whether or not the entire VM memory
+#     footprint is mlock()'d on demand or all at once.  Refer to
+#     docs/rdma.txt for usage.  Disabled by default.  (since 2.0)
+#
+# @zero-blocks: During storage migration encode blocks of zeroes
+#     efficiently.  This essentially saves 1MB of zeroes per block on
+#     the wire.  Enabling requires source and target VM to support
+#     this feature.  To enable it is sufficient to enable the
+#     capability on the source VM.  The feature is disabled by
+#     default.  (since 1.6)
+#
+# @events: Generate events for each migration state change.
+#     (since 2.4)
+#
+# @auto-converge: If enabled, QEMU will automatically throttle down
+#     the guest to speed up convergence of RAM migration.  (since 1.6)
+#
+# @postcopy-ram: Start executing on the migration target before all of
+#     RAM has been migrated, pulling the remaining pages along as
+#     needed.  The capacity must have the same setting on both source
+#     and target or migration will not even start.  **Note:** If the
+#     migration fails during postcopy the VM will fail.  (since 2.6)
+#
+# @x-colo: If enabled, migration will never end, and the state of the
+#     VM on the primary side will be migrated continuously to the VM
+#     on secondary side, this process is called COarse-Grain LOck
+#     Stepping (COLO) for Non-stop Service.  (since 2.8)
+#
+# @release-ram: If enabled, QEMU will free the migrated ram pages on
+#     the source during postcopy-ram migration.  (since 2.9)
+#
+# @return-path: If enabled, migration will use the return path even
+#     for precopy.  (since 2.10)
+#
+# @pause-before-switchover: Pause outgoing migration before
+#     serialising device state and before disabling block IO.
+#     (since 2.11)
+#
+# @multifd: Use more than one fd for migration.  (since 4.0)
+#
+# @dirty-bitmaps: If enabled, QEMU will migrate named dirty bitmaps.
+#     (since 2.12)
+#
+# @postcopy-blocktime: Calculate downtime for postcopy live migration.
+#     (since 3.0)
+#
+# @late-block-activate: If enabled, the destination will not activate
+#     block devices (and thus take locks) immediately at the end of
+#     migration.  (since 3.0)
+#
+# @x-ignore-shared: If enabled, QEMU will not migrate shared memory
+#     that is accessible on the destination machine.  (since 4.0)
+#
+# @validate-uuid: Send the UUID of the source to allow the destination
+#     to ensure it is the same.  (since 4.2)
+#
+# @background-snapshot: If enabled, the migration stream will be a
+#     snapshot of the VM exactly at the point when the migration
+#     procedure starts.  The VM RAM is saved with running VM.
+#     (since 6.0)
+#
+# @zero-copy-send: Controls behavior on sending memory pages on
+#     migration.  When true, enables a zero-copy mechanism for sending
+#     memory pages, if host supports it.  Requires that QEMU be
+#     permitted to use locked memory for guest RAM pages.  (since 7.1)
+#
+# @postcopy-preempt: If enabled, the migration process will allow
+#     postcopy requests to preempt precopy stream, so postcopy
+#     requests will be handled faster.  This is a performance feature
+#     and should not affect the correctness of postcopy migration.
+#     (since 7.1)
+#
+# @switchover-ack: If enabled, migration will not stop the source VM
+#     and complete the migration until an ACK is received from the
+#     destination that it's OK to do so.  Exactly when this ACK is
+#     sent depends on the migrated devices that use this feature.  For
+#     example, a device can use it to make sure some of its data is
+#     sent and loaded in the destination before doing switchover.
+#     This can reduce downtime if devices that support this capability
+#     are present.  'return-path' capability must be enabled to use
+#     it.  (since 8.1)
+#
+# @dirty-limit: If enabled, migration will throttle vCPUs as needed to
+#     keep their dirty page rate within @vcpu-dirty-limit.  This can
+#     improve responsiveness of large guests during live migration,
+#     and can result in more stable read performance.  Requires KVM
+#     with accelerator property "dirty-ring-size" set.  (Since 8.1)
+#
+# @mapped-ram: Migrate using fixed offsets in the migration file for
+#     each RAM page.  Requires a migration URI that supports seeking,
+#     such as a file.  (since 9.0)
+#
 # Features:
 #
-# @unstable: Members @x-checkpoint-delay and
-#     @x-vcpu-dirty-limit-period are experimental.
+# @unstable: Members @x-checkpoint-delay, @x-vcpu-dirty-limit-period,
+#     @x-colo and @x-ignore-shared are experimental.
+# @deprecated: Member @zero-blocks is deprecated as being part of
+#     block migration which was already removed.
 #
 # Since: 2.4
 ##
@@ -1055,7 +1161,29 @@
             '*mode': 'MigMode',
             '*zero-page-detection': 'ZeroPageDetection',
             '*direct-io': 'bool',
-            '*cpr-exec-command': [ 'str' ]} }
+            '*cpr-exec-command': [ 'str' ],
+            '*xbzrle': 'bool',
+            '*rdma-pin-all': 'bool',
+            '*auto-converge': 'bool',
+            '*zero-blocks': { 'type': 'bool', 'features': [ 'deprecated' ] },
+            '*events': 'bool',
+            '*postcopy-ram': 'bool',
+            '*x-colo': { 'type': 'bool', 'features': [ 'unstable' ] },
+            '*release-ram': 'bool',
+            '*return-path': 'bool',
+            '*pause-before-switchover': 'bool',
+            '*multifd': 'bool',
+            '*dirty-bitmaps': 'bool',
+            '*postcopy-blocktime': 'bool',
+            '*late-block-activate': 'bool',
+            '*x-ignore-shared': { 'type': 'bool', 'features': [ 'unstable' ] },
+            '*validate-uuid': 'bool',
+            '*background-snapshot': 'bool',
+            '*zero-copy-send': 'bool',
+            '*postcopy-preempt': 'bool',
+            '*switchover-ack': 'bool',
+            '*dirty-limit': 'bool',
+            '*mapped-ram': 'bool' } }
 
 ##
 # @query-migrate-parameters:
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 20/51] migration: Remove s->capabilities
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (18 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 19/51] migration: Add capabilities into MigrationParameters Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 21/51] qapi/migration: Deprecate capabilities commands Fabiano Rosas
                   ` (31 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

Last patch added capabilities to s->parameters. Now we can replace all
instances of s->capabilities with s->parameters:

- The -global properties now get set directly in s->parameters.

- Accessors from options.c now read from s->parameters.

- migrate_caps_check() now takes a MigrationParameters object. The
  function is still kept around because migrate-set-capabilities will
  still use it.

- The machinery for background-snapshot compatibility check goes
  away. We can check each capability by name (if s->parameters.cap ...)

- savevm uses the helper functions introduced in the last patch to do
  validation of capabilities found on the migration stream.

Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration.c |  22 +--
 migration/migration.h |   1 -
 migration/options.c   | 310 +++++++++++++++++-------------------------
 migration/options.h   |  19 +--
 migration/savevm.c    |   8 +-
 5 files changed, 140 insertions(+), 220 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index f0e74cbf4b..182dccd579 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -262,9 +262,10 @@ static bool
 migration_capabilities_and_transport_compatible(MigrationAddress *addr,
                                                 Error **errp)
 {
+    MigrationState *s = migrate_get_current();
+
     if (addr->transport == MIGRATION_ADDRESS_TYPE_RDMA) {
-        return migrate_rdma_caps_check(migrate_get_current()->capabilities,
-                                       errp);
+        return migrate_rdma_caps_check(&s->parameters, errp);
     }
 
     return true;
@@ -4189,22 +4190,7 @@ static void migration_instance_init(Object *obj)
  */
 static bool migration_object_check(MigrationState *ms, Error **errp)
 {
-    /* Assuming all off */
-    bool old_caps[MIGRATION_CAPABILITY__MAX] = { 0 };
-
-    if (!migrate_params_check(&ms->parameters, errp)) {
-        return false;
-    }
-
-    /*
-     * FIXME: Temporarily while -global capabilties are still using
-     * s->capabilities. Will be gone by the end of the series.
-     */
-    for (int i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
-        migrate_capability_set_compat(&ms->parameters, i, ms->capabilities[i]);
-    }
-
-    return migrate_caps_check(old_caps, ms->capabilities, errp);
+    return migrate_params_check(&ms->parameters, errp);
 }
 
 static const TypeInfo migration_type = {
diff --git a/migration/migration.h b/migration/migration.h
index 20802596fb..5fe5f8a23e 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -359,7 +359,6 @@ struct MigrationState {
     int64_t downtime_start;
     int64_t downtime;
     int64_t expected_downtime;
-    bool capabilities[MIGRATION_CAPABILITY__MAX];
     int64_t setup_time;
 
     /*
diff --git a/migration/options.c b/migration/options.c
index b23dcc15f9..d3bb65513b 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -82,9 +82,6 @@
 #define DEFAULT_MIGRATE_ANNOUNCE_ROUNDS    5
 #define DEFAULT_MIGRATE_ANNOUNCE_STEP    100
 
-#define DEFINE_PROP_MIG_CAP(name, x)             \
-    DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)
-
 const PropertyInfo qdev_prop_StrOrNull;
 #define DEFINE_PROP_STR_OR_NULL(_name, _state, _field)                  \
     DEFINE_PROP(_name, _state, _field, qdev_prop_StrOrNull, StrOrNull *, \
@@ -185,32 +182,42 @@ const Property migration_properties[] = {
     DEFINE_PROP_ZERO_PAGE_DETECTION("zero-page-detection", MigrationState,
                        parameters.zero_page_detection,
                        ZERO_PAGE_DETECTION_MULTIFD),
-
-    /* Migration capabilities */
-    DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
-    DEFINE_PROP_MIG_CAP("x-rdma-pin-all", MIGRATION_CAPABILITY_RDMA_PIN_ALL),
-    DEFINE_PROP_MIG_CAP("x-auto-converge", MIGRATION_CAPABILITY_AUTO_CONVERGE),
-    DEFINE_PROP_MIG_CAP("x-zero-blocks", MIGRATION_CAPABILITY_ZERO_BLOCKS),
-    DEFINE_PROP_MIG_CAP("x-events", MIGRATION_CAPABILITY_EVENTS),
-    DEFINE_PROP_MIG_CAP("x-postcopy-ram", MIGRATION_CAPABILITY_POSTCOPY_RAM),
-    DEFINE_PROP_MIG_CAP("x-postcopy-preempt",
-                        MIGRATION_CAPABILITY_POSTCOPY_PREEMPT),
-    DEFINE_PROP_MIG_CAP("postcopy-blocktime",
-                        MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME),
-    DEFINE_PROP_MIG_CAP("x-colo", MIGRATION_CAPABILITY_X_COLO),
-    DEFINE_PROP_MIG_CAP("x-release-ram", MIGRATION_CAPABILITY_RELEASE_RAM),
-    DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
-    DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD),
-    DEFINE_PROP_MIG_CAP("x-background-snapshot",
-            MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT),
+    DEFINE_PROP_BOOL("x-xbzrle",
+                     MigrationState, parameters.xbzrle, false),
+    DEFINE_PROP_BOOL("x-rdma-pin-all",
+                     MigrationState, parameters.rdma_pin_all, false),
+    DEFINE_PROP_BOOL("x-auto-converge",
+                     MigrationState, parameters.auto_converge, false),
+    DEFINE_PROP_BOOL("x-zero-blocks",
+                     MigrationState, parameters.zero_blocks, false),
+    DEFINE_PROP_BOOL("x-events",
+                     MigrationState, parameters.events, false),
+    DEFINE_PROP_BOOL("x-postcopy-ram",
+                     MigrationState, parameters.postcopy_ram, false),
+    DEFINE_PROP_BOOL("x-postcopy-preempt",
+                     MigrationState, parameters.postcopy_preempt, false),
+    DEFINE_PROP_BOOL("postcopy-blocktime",
+                     MigrationState, parameters.postcopy_blocktime, false),
+    DEFINE_PROP_BOOL("x-colo",
+                     MigrationState, parameters.x_colo, false),
+    DEFINE_PROP_BOOL("x-release-ram",
+                     MigrationState, parameters.release_ram, false),
+    DEFINE_PROP_BOOL("x-return-path",
+                     MigrationState, parameters.return_path, false),
+    DEFINE_PROP_BOOL("x-multifd",
+                     MigrationState, parameters.multifd, false),
+    DEFINE_PROP_BOOL("x-background-snapshot",
+                     MigrationState, parameters.background_snapshot, false),
 #ifdef CONFIG_LINUX
-    DEFINE_PROP_MIG_CAP("x-zero-copy-send",
-            MIGRATION_CAPABILITY_ZERO_COPY_SEND),
+    DEFINE_PROP_BOOL("x-zero-copy-send",
+                     MigrationState, parameters.zero_copy_send, false),
 #endif
-    DEFINE_PROP_MIG_CAP("x-switchover-ack",
-                        MIGRATION_CAPABILITY_SWITCHOVER_ACK),
-    DEFINE_PROP_MIG_CAP("x-dirty-limit", MIGRATION_CAPABILITY_DIRTY_LIMIT),
-    DEFINE_PROP_MIG_CAP("mapped-ram", MIGRATION_CAPABILITY_MAPPED_RAM),
+    DEFINE_PROP_BOOL("x-switchover-ack",
+                     MigrationState, parameters.switchover_ack, false),
+    DEFINE_PROP_BOOL("x-dirty-limit",
+                     MigrationState, parameters.dirty_limit, false),
+    DEFINE_PROP_BOOL("mapped-ram",
+                     MigrationState, parameters.mapped_ram, false),
 };
 const size_t migration_properties_count = ARRAY_SIZE(migration_properties);
 
@@ -285,7 +292,7 @@ bool migrate_auto_converge(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_AUTO_CONVERGE];
+    return s->parameters.auto_converge;
 }
 
 bool migrate_send_switchover_start(void)
@@ -299,144 +306,142 @@ bool migrate_background_snapshot(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT];
+    return s->parameters.background_snapshot;
 }
 
 bool migrate_colo(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_X_COLO];
+    return s->parameters.x_colo;
 }
 
 bool migrate_dirty_bitmaps(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS];
+    return s->parameters.dirty_bitmaps;
 }
 
 bool migrate_dirty_limit(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_DIRTY_LIMIT];
+    return s->parameters.dirty_limit;
 }
 
 bool migrate_events(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_EVENTS];
+    return s->parameters.events;
 }
 
 bool migrate_mapped_ram(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_MAPPED_RAM];
+    return s->parameters.mapped_ram;
 }
 
 bool migrate_ignore_shared(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_X_IGNORE_SHARED];
+    return s->parameters.x_ignore_shared;
 }
 
 bool migrate_late_block_activate(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE];
+    return s->parameters.late_block_activate;
 }
 
 bool migrate_multifd(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_MULTIFD];
+    return s->parameters.multifd;
 }
 
 bool migrate_pause_before_switchover(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER];
+    return s->parameters.pause_before_switchover;
 }
 
 bool migrate_postcopy_blocktime(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME];
+    return s->parameters.postcopy_blocktime;
 }
 
 bool migrate_postcopy_preempt(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT];
+    return s->parameters.postcopy_preempt;
 }
 
 bool migrate_postcopy_ram(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM];
+    return s->parameters.postcopy_ram;
 }
 
 bool migrate_rdma_pin_all(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL];
+    return s->parameters.rdma_pin_all;
 }
 
 bool migrate_release_ram(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_RELEASE_RAM];
+    return s->parameters.release_ram;
 }
 
 bool migrate_return_path(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_RETURN_PATH];
+    return s->parameters.return_path;
 }
 
 bool migrate_switchover_ack(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_SWITCHOVER_ACK];
+    return s->parameters.switchover_ack;
 }
 
 bool migrate_validate_uuid(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_VALIDATE_UUID];
+    return s->parameters.validate_uuid;
 }
 
 bool migrate_xbzrle(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_XBZRLE];
+    return s->parameters.xbzrle;
 }
 
 bool migrate_zero_copy_send(void)
 {
     MigrationState *s = migrate_get_current();
 
-    return s->capabilities[MIGRATION_CAPABILITY_ZERO_COPY_SEND];
+    return s->parameters.zero_copy_send;
 }
 
-/* pseudo capabilities */
-
 bool migrate_multifd_flush_after_each_section(void)
 {
     MigrationState *s = migrate_get_current();
@@ -481,44 +486,6 @@ WriteTrackingSupport migrate_query_write_tracking(void)
     return WT_SUPPORT_COMPATIBLE;
 }
 
-/* Migration capabilities set */
-struct MigrateCapsSet {
-    int size;                       /* Capability set size */
-    MigrationCapability caps[];     /* Variadic array of capabilities */
-};
-typedef struct MigrateCapsSet MigrateCapsSet;
-
-/* Define and initialize MigrateCapsSet */
-#define INITIALIZE_MIGRATE_CAPS_SET(_name, ...)   \
-    MigrateCapsSet _name = {    \
-        .size = sizeof((int []) { __VA_ARGS__ }) / sizeof(int), \
-        .caps = { __VA_ARGS__ } \
-    }
-
-/* Background-snapshot compatibility check list */
-static const
-INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot,
-    MIGRATION_CAPABILITY_POSTCOPY_RAM,
-    MIGRATION_CAPABILITY_DIRTY_BITMAPS,
-    MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME,
-    MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE,
-    MIGRATION_CAPABILITY_RETURN_PATH,
-    MIGRATION_CAPABILITY_MULTIFD,
-    MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER,
-    MIGRATION_CAPABILITY_AUTO_CONVERGE,
-    MIGRATION_CAPABILITY_RELEASE_RAM,
-    MIGRATION_CAPABILITY_RDMA_PIN_ALL,
-    MIGRATION_CAPABILITY_XBZRLE,
-    MIGRATION_CAPABILITY_X_COLO,
-    MIGRATION_CAPABILITY_VALIDATE_UUID,
-    MIGRATION_CAPABILITY_ZERO_COPY_SEND);
-
-/* Snapshot compatibility check list */
-static const
-INITIALIZE_MIGRATE_CAPS_SET(check_caps_savevm,
-                            MIGRATION_CAPABILITY_MULTIFD,
-);
-
 static bool migrate_incoming_started(void)
 {
     return !!migration_incoming_get_current()->transport_data;
@@ -527,34 +494,28 @@ static bool migrate_incoming_started(void)
 bool migrate_can_snapshot(Error **errp)
 {
     MigrationState *s = migrate_get_current();
-    int i;
 
-    for (i = 0; i < check_caps_savevm.size; i++) {
-        int incomp_cap = check_caps_savevm.caps[i];
-
-        if (s->capabilities[incomp_cap]) {
-            error_setg(errp,
-                       "Snapshots are not compatible with %s",
-                       MigrationCapability_str(incomp_cap));
-            return false;
-        }
+    if (migrate_capability_get_compat(
+            &s->parameters, MIGRATION_CAPABILITY_MULTIFD)) {
+        error_setg(errp,
+                   "Snapshots are not compatible with multifd");
+        return false;
     }
 
     return true;
 }
 
-
-bool migrate_rdma_caps_check(bool *caps, Error **errp)
+bool migrate_rdma_caps_check(MigrationParameters *params, Error **errp)
 {
-    if (caps[MIGRATION_CAPABILITY_XBZRLE]) {
+    if (params->xbzrle) {
         error_setg(errp, "RDMA and XBZRLE can't be used together");
         return false;
     }
-    if (caps[MIGRATION_CAPABILITY_MULTIFD]) {
+    if (params->multifd) {
         error_setg(errp, "RDMA and multifd can't be used together");
         return false;
     }
-    if (caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+    if (params->postcopy_ram) {
         error_setg(errp, "RDMA and postcopy-ram can't be used together");
         return false;
     }
@@ -562,26 +523,19 @@ bool migrate_rdma_caps_check(bool *caps, Error **errp)
     return true;
 }
 
-/**
- * @migration_caps_check - check capability compatibility
- *
- * @old_caps: old capability list
- * @new_caps: new capability list
- * @errp: set *errp if the check failed, with reason
- *
- * Returns true if check passed, otherwise false.
- */
-bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
+bool migrate_caps_check(MigrationParameters *new, Error **errp)
 {
-    ERRP_GUARD();
+    MigrationState *s = migrate_get_current();
     MigrationIncomingState *mis = migration_incoming_get_current();
+    bool postcopy_already_on = s->parameters.postcopy_ram;
+    ERRP_GUARD();
 
-    if (new_caps[MIGRATION_CAPABILITY_ZERO_BLOCKS]) {
+    if (new->zero_blocks) {
         warn_report("zero-blocks capability is deprecated");
     }
 
 #ifndef CONFIG_REPLICATION
-    if (new_caps[MIGRATION_CAPABILITY_X_COLO]) {
+    if (new->x_colo) {
         error_setg(errp, "QEMU compiled without replication module"
                    " can't enable COLO");
         error_append_hint(errp, "Please enable replication before COLO.\n");
@@ -589,27 +543,27 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
     }
 #endif
 
-    if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+    if (new->postcopy_ram) {
         /* This check is reasonably expensive, so only when it's being
          * set the first time, also it's only the destination that needs
          * special support.
          */
-        if (!old_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] &&
+        if (!postcopy_already_on &&
             runstate_check(RUN_STATE_INMIGRATE) &&
             !postcopy_ram_supported_by_host(mis, errp)) {
             error_prepend(errp, "Postcopy is not supported: ");
             return false;
         }
 
-        if (new_caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED]) {
+        if (new->x_ignore_shared) {
             error_setg(errp, "Postcopy is not compatible with ignore-shared");
             return false;
         }
     }
 
-    if (new_caps[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) {
+    if (new->background_snapshot) {
         WriteTrackingSupport wt_support;
-        int idx;
+
         /*
          * Check if 'background-snapshot' capability is supported by
          * host kernel and compatible with guest memory configuration.
@@ -625,41 +579,45 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
             return false;
         }
 
-        /*
-         * Check if there are any migration capabilities
-         * incompatible with 'background-snapshot'.
-         */
-        for (idx = 0; idx < check_caps_background_snapshot.size; idx++) {
-            int incomp_cap = check_caps_background_snapshot.caps[idx];
-            if (new_caps[incomp_cap]) {
-                error_setg(errp,
-                        "Background-snapshot is not compatible with %s",
-                        MigrationCapability_str(incomp_cap));
-                return false;
-            }
+        if (new->postcopy_ram ||
+            new->dirty_bitmaps ||
+            new->postcopy_blocktime ||
+            new->late_block_activate ||
+            new->return_path ||
+            new->multifd ||
+            new->pause_before_switchover ||
+            new->auto_converge ||
+            new->release_ram ||
+            new->rdma_pin_all ||
+            new->xbzrle ||
+            new->x_colo ||
+            new->validate_uuid ||
+            new->zero_copy_send) {
+            error_setg(errp,
+                       "Background-snapshot is not compatible with "
+                       "currently set capabilities");
+            return false;
         }
     }
 
 #ifdef CONFIG_LINUX
-    if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND] &&
-        (!new_caps[MIGRATION_CAPABILITY_MULTIFD] ||
-         new_caps[MIGRATION_CAPABILITY_XBZRLE] ||
-         migrate_multifd_compression() ||
-         migrate_tls())) {
+    if (new->zero_copy_send &&
+        (!new->multifd || new->xbzrle ||
+         migrate_multifd_compression() || migrate_tls())) {
         error_setg(errp,
                    "Zero copy only available for non-compressed non-TLS multifd migration");
         return false;
     }
 #else
-    if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND]) {
+    if (new->zero_copy_send) {
         error_setg(errp,
                    "Zero copy currently only available on Linux");
         return false;
     }
 #endif
 
-    if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) {
-        if (!new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+    if (new->postcopy_preempt) {
+        if (!new->postcopy_ram) {
             error_setg(errp, "Postcopy preempt requires postcopy-ram");
             return false;
         }
@@ -671,22 +629,22 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
         }
     }
 
-    if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
+    if (new->multifd) {
         if (!migrate_multifd() && migrate_incoming_started()) {
             error_setg(errp, "Multifd must be set before incoming starts");
             return false;
         }
     }
 
-    if (new_caps[MIGRATION_CAPABILITY_SWITCHOVER_ACK]) {
-        if (!new_caps[MIGRATION_CAPABILITY_RETURN_PATH]) {
+    if (new->switchover_ack) {
+        if (!new->return_path) {
             error_setg(errp, "Capability 'switchover-ack' requires capability "
                              "'return-path'");
             return false;
         }
     }
-    if (new_caps[MIGRATION_CAPABILITY_DIRTY_LIMIT]) {
-        if (new_caps[MIGRATION_CAPABILITY_AUTO_CONVERGE]) {
+    if (new->dirty_limit) {
+        if (new->auto_converge) {
             error_setg(errp, "dirty-limit conflicts with auto-converge"
                        " either of then available currently");
             return false;
@@ -699,21 +657,21 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
         }
     }
 
-    if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
-        if (new_caps[MIGRATION_CAPABILITY_XBZRLE]) {
+    if (new->multifd) {
+        if (new->xbzrle) {
             error_setg(errp, "Multifd is not compatible with xbzrle");
             return false;
         }
     }
 
-    if (new_caps[MIGRATION_CAPABILITY_MAPPED_RAM]) {
-        if (new_caps[MIGRATION_CAPABILITY_XBZRLE]) {
+    if (new->mapped_ram) {
+        if (new->xbzrle) {
             error_setg(errp,
                        "Mapped-ram migration is incompatible with xbzrle");
             return false;
         }
 
-        if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+        if (new->postcopy_ram) {
             error_setg(errp,
                        "Mapped-ram migration is incompatible with postcopy");
             return false;
@@ -724,7 +682,7 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
      * On destination side, check the cases that capability is being set
      * after incoming thread has started.
      */
-    if (migrate_rdma() && !migrate_rdma_caps_check(new_caps, errp)) {
+    if (migrate_rdma() && !migrate_rdma_caps_check(new, errp)) {
         return false;
     }
     return true;
@@ -845,39 +803,37 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
     for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
         caps = g_malloc0(sizeof(*caps));
         caps->capability = i;
-        caps->state = s->capabilities[i];
+        caps->state = migrate_capability_get_compat(&s->parameters, i);
         QAPI_LIST_APPEND(tail, caps);
     }
 
     return head;
 }
 
-void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
+void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *capabilities,
                                   Error **errp)
 {
     MigrationState *s = migrate_get_current();
-    MigrationCapabilityStatusList *cap;
-    bool new_caps[MIGRATION_CAPABILITY__MAX];
+    g_autoptr(MigrationParameters) params = NULL;
 
     if (migration_is_running() || migration_in_colo_state()) {
         error_setg(errp, "There's a migration process in progress");
         return;
     }
 
-    memcpy(new_caps, s->capabilities, sizeof(new_caps));
-    for (cap = params; cap; cap = cap->next) {
-        new_caps[cap->value->capability] = cap->value->state;
-    }
+    /*
+     * Capabilities validation needs to first copy from s->parameters
+     * in case the incoming capabilities have a capability that
+     * conflicts with another that's already set.
+     */
+    params = QAPI_CLONE(MigrationParameters, &s->parameters);
+    migrate_capabilities_set_compat(params, capabilities);
 
-    if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
+    if (!migrate_caps_check(params, errp)) {
         return;
     }
 
-    for (cap = params; cap; cap = cap->next) {
-        s->capabilities[cap->value->capability] = cap->value->state;
-    }
-
-    migrate_capabilities_set_compat(&s->parameters, params);
+    migrate_capabilities_set_compat(&s->parameters, capabilities);
 }
 
 /* parameters */
@@ -938,9 +894,8 @@ bool migrate_direct_io(void)
      * isolated to the main migration thread while multifd channels
      * process the aligned data with O_DIRECT enabled.
      */
-    return s->parameters.direct_io &&
-        s->capabilities[MIGRATION_CAPABILITY_MAPPED_RAM] &&
-        s->capabilities[MIGRATION_CAPABILITY_MULTIFD];
+    return s->parameters.direct_io && s->parameters.mapped_ram &&
+        s->parameters.multifd;
 }
 
 uint64_t migrate_downtime_limit(void)
@@ -1373,6 +1328,10 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
         return false;
     }
 
+    if (!migrate_caps_check(params, errp)) {
+        return false;
+    }
+
     return true;
 }
 
@@ -1435,19 +1394,6 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
     tls_opt_to_str(params->tls_hostname);
     tls_opt_to_str(params->tls_authz);
 
-    /*
-     * FIXME: Temporarily while migrate_caps_check is not
-     * converted to look at s->parameters. Will be gone the end of
-     * the series.
-     */
-    bool new_caps[MIGRATION_CAPABILITY__MAX] = { 0 };
-    for (int i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
-        new_caps[i] = migrate_capability_get_compat(&s->parameters, i);
-    }
-    if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
-        return;
-    }
-
     migrate_params_merge(tmp, params);
 
     /*
diff --git a/migration/options.h b/migration/options.h
index 794cf23870..ceb12b0ff0 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -1,5 +1,5 @@
 /*
- * QEMU migration capabilities
+ * QEMU migration options
  *
  * Copyright (c) 2012-2023 Red Hat Inc
  *
@@ -23,8 +23,6 @@
 extern const Property migration_properties[];
 extern const size_t migration_properties_count;
 
-/* capabilities */
-
 bool migrate_auto_converge(void);
 bool migrate_colo(void);
 bool migrate_dirty_bitmaps(void);
@@ -43,22 +41,12 @@ bool migrate_validate_uuid(void);
 bool migrate_xbzrle(void);
 bool migrate_zero_copy_send(void);
 
-/*
- * pseudo capabilities
- *
- * These are functions that are used in a similar way to capabilities
- * check, but they are not a capability.
- */
-
 bool migrate_multifd_flush_after_each_section(void);
 bool migrate_postcopy(void);
 bool migrate_rdma(void);
 bool migrate_tls(void);
 
-/* capabilities helpers */
-
-bool migrate_rdma_caps_check(bool *caps, Error **errp);
-bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp);
+bool migrate_rdma_caps_check(MigrationParameters *config, Error **errp);
 bool migrate_can_snapshot(Error **errp);
 
 /* parameters */
@@ -88,8 +76,6 @@ const char *migrate_tls_hostname(void);
 uint64_t migrate_xbzrle_cache_size(void);
 ZeroPageDetection migrate_zero_page_detection(void);
 
-/* parameters helpers */
-
 bool migrate_params_check(MigrationParameters *params, Error **errp);
 void migrate_params_init(MigrationParameters *params);
 void migrate_tls_opts_free(MigrationParameters *params);
@@ -98,4 +84,5 @@ void migrate_capability_set_compat(MigrationParameters *params, int i,
                                    bool val);
 void migrate_capabilities_set_compat(MigrationParameters *params,
                                      MigrationCapabilityStatusList *caps);
+bool migrate_caps_check(MigrationParameters *new, Error **errp);
 #endif
diff --git a/migration/savevm.c b/migration/savevm.c
index 62cc2ce25c..d61d266902 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -291,7 +291,8 @@ static uint32_t get_validatable_capabilities_count(void)
     uint32_t result = 0;
     int i;
     for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
-        if (should_validate_capability(i) && s->capabilities[i]) {
+        if (should_validate_capability(i) &&
+            migrate_capability_get_compat(&s->parameters, i)) {
             result++;
         }
     }
@@ -313,7 +314,8 @@ static int configuration_pre_save(void *opaque)
     state->capabilities = g_renew(MigrationCapability, state->capabilities,
                                   state->caps_count);
     for (i = j = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
-        if (should_validate_capability(i) && s->capabilities[i]) {
+        if (should_validate_capability(i) &&
+            migrate_capability_get_compat(&s->parameters, i)) {
             state->capabilities[j++] = i;
         }
     }
@@ -363,7 +365,7 @@ static bool configuration_validate_capabilities(SaveState *state)
             continue;
         }
         source_state = test_bit(i, source_caps_bm);
-        target_state = s->capabilities[i];
+        target_state = migrate_capability_get_compat(&s->parameters, i);
         if (source_state != target_state) {
             error_report("Capability %s is %s, but received capability is %s",
                          MigrationCapability_str(i),
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 21/51] qapi/migration: Deprecate capabilities commands
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (19 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 20/51] migration: Remove s->capabilities Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 22/51] migration: Store the initial values used for s->parameters Fabiano Rosas
                   ` (30 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, devel, Eric Blake

The concept of capabilities is being merged into the concept of
parameters. From now on, the commands that handle capabilities are
deprecated in favor of the commands that handle parameters.

Affected commands:

- migrate-set-capabilities
- query-migrate-capabilities

Reviewed-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 docs/about/deprecated.rst      | 10 ++++++++++
 migration/migration-hmp-cmds.c |  6 ++++++
 qapi/migration.json            | 16 ++++++++++++++--
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index ac31a2bce4..1949508efa 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -588,3 +588,13 @@ command documentation for details on the ``fdset`` usage.
 
 The ``zero-blocks`` capability was part of the block migration which
 doesn't exist anymore since it was removed in QEMU v9.1.
+
+``migrate-set-capabilities`` command (since 10.2)
+'''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use ``migrate-set-parameters`` instead.
+
+``query-migrate-capabilities`` command (since 10.2)
+'''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use ``query-migrate-parameters`` instead.
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 28b48c34bf..7e5ac57da5 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -298,6 +298,9 @@ void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
 {
     MigrationCapabilityStatusList *caps, *cap;
 
+    warn_report("info migrate_capabilities is deprecated;"
+                " use info migrate_parameters instead");
+
     caps = qmp_query_migrate_capabilities(NULL);
 
     if (caps) {
@@ -705,6 +708,9 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
     MigrationCapabilityStatus *value;
     int val;
 
+    warn_report("migrate_set_capability is deprecated;"
+                " use migrate_set_parameter instead");
+
     val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
     if (val < 0) {
         goto end;
diff --git a/qapi/migration.json b/qapi/migration.json
index fcbb699a47..76a1e03f2f 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -570,6 +570,11 @@
 #
 # @capabilities: json array of capability modifications to make
 #
+# Features:
+#
+# @deprecated: This command is deprecated.  Use migrate-set-parameters
+# instead.
+#
 # Since: 1.2
 #
 # .. qmp-example::
@@ -579,13 +584,19 @@
 #     <- { "return": {} }
 ##
 { 'command': 'migrate-set-capabilities',
-  'data': { 'capabilities': ['MigrationCapabilityStatus'] } }
+  'data': { 'capabilities': ['MigrationCapabilityStatus'] },
+  'features': ['deprecated'] }
 
 ##
 # @query-migrate-capabilities:
 #
 # Return information about the current migration capabilities status
 #
+# Features:
+#
+# @deprecated: This command is deprecated.  Use
+# query-migrate-parameters instead.
+#
 # Since: 1.2
 #
 # .. qmp-example::
@@ -601,7 +612,8 @@
 #           {"state": false, "capability": "x-colo"}
 #        ]}
 ##
-{ 'command': 'query-migrate-capabilities', 'returns':   ['MigrationCapabilityStatus']}
+{ 'command': 'query-migrate-capabilities', 'returns':   ['MigrationCapabilityStatus'],
+  'features': ['deprecated'] }
 
 ##
 # @MultiFDCompression:
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 22/51] migration: Store the initial values used for s->parameters
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (20 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 21/51] qapi/migration: Deprecate capabilities commands Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 23/51] migration: Allow migrate commands to provide the migration config Fabiano Rosas
                   ` (29 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu

Each migration parameter has a default value, store them for later
use in resetting s->parameters. Values overridden via the command line
with the debugging option -global migration.<param> will be included.

Make the structure const and change the appropriate signatures to make
sure its values are not changed by accident. Some functions take two
MigrationParameters pointers and it's easy to confuse them.

Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration.c |  3 +++
 migration/migration.h |  6 ++++++
 migration/options.c   | 21 +++++++++++++++++----
 migration/options.h   |  7 ++++---
 4 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 182dccd579..90b381b1fe 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -331,6 +331,7 @@ void migration_object_init(void)
     current_incoming->exit_on_error = INMIGRATE_DEFAULT_EXIT_ON_ERROR;
 
     migration_object_check(current_migration, &error_fatal);
+    migrate_params_store_defaults(current_migration);
 
     ram_mig_init();
     dirty_bitmap_mig_init();
@@ -4149,6 +4150,8 @@ static void migration_instance_finalize(Object *obj)
 
     qapi_free_BitmapMigrationNodeAliasList(ms->parameters.block_bitmap_mapping);
     qapi_free_strList(ms->parameters.cpr_exec_command);
+    /* drop const */
+    qapi_free_MigrationParameters((MigrationParameters *)ms->initial_params);
     qemu_mutex_destroy(&ms->error_mutex);
     qemu_mutex_destroy(&ms->qemu_file_lock);
     qemu_sem_destroy(&ms->wait_unplug_sem);
diff --git a/migration/migration.h b/migration/migration.h
index 5fe5f8a23e..a4b5dbb09b 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -320,6 +320,12 @@ struct MigrationState {
 
     /* params from 'migrate-set-parameters' */
     MigrationParameters parameters;
+    /*
+     * This holds the values initially set in the 'parameters' struct
+     * above. Any values overriden by -global migration.<parameter>
+     * will be reflected here as well.
+     */
+    const MigrationParameters *initial_params;
 
     MigrationStatus state;
 
diff --git a/migration/options.c b/migration/options.c
index d3bb65513b..d1d8e5c181 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -505,7 +505,7 @@ bool migrate_can_snapshot(Error **errp)
     return true;
 }
 
-bool migrate_rdma_caps_check(MigrationParameters *params, Error **errp)
+bool migrate_rdma_caps_check(const MigrationParameters *params, Error **errp)
 {
     if (params->xbzrle) {
         error_setg(errp, "RDMA and XBZRLE can't be used together");
@@ -523,7 +523,7 @@ bool migrate_rdma_caps_check(MigrationParameters *params, Error **errp)
     return true;
 }
 
-bool migrate_caps_check(MigrationParameters *new, Error **errp)
+bool migrate_caps_check(const MigrationParameters *new, Error **errp)
 {
     MigrationState *s = migrate_get_current();
     MigrationIncomingState *mis = migration_incoming_get_current();
@@ -1182,7 +1182,7 @@ static void migrate_post_update_params(MigrationParameters *new, Error **errp)
  * Check whether the parameters are valid. Error will be put into errp
  * (if provided). Return true if valid, otherwise false.
  */
-bool migrate_params_check(MigrationParameters *params, Error **errp)
+bool migrate_params_check(const MigrationParameters *params, Error **errp)
 {
     ERRP_GUARD();
 
@@ -1363,7 +1363,7 @@ static void migrate_params_merge(MigrationParameters *dst,
  * Caller must ensure all has_* fields of @params are true to ensure
  * all fields get copied and the pointer members don't dangle.
  */
-static void migrate_params_apply(MigrationParameters *params)
+static void migrate_params_apply(const MigrationParameters *params)
 {
     MigrationState *s = migrate_get_current();
     MigrationParameters *cur = &s->parameters;
@@ -1376,6 +1376,19 @@ static void migrate_params_apply(MigrationParameters *params)
     QAPI_CLONE_MEMBERS(MigrationParameters, cur, params);
 }
 
+void migrate_params_store_defaults(MigrationState *s)
+{
+    assert(!s->initial_params);
+
+    /*
+     * The defaults set for each qdev property in migration_properties
+     * will be stored as the default values for each migration
+     * parameter. For debugging, using -global can override the
+     * defaults.
+     */
+    s->initial_params = QAPI_CLONE(MigrationParameters, &s->parameters);
+}
+
 void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
 {
     MigrationState *s = migrate_get_current();
diff --git a/migration/options.h b/migration/options.h
index ceb12b0ff0..47f84bf180 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -46,7 +46,7 @@ bool migrate_postcopy(void);
 bool migrate_rdma(void);
 bool migrate_tls(void);
 
-bool migrate_rdma_caps_check(MigrationParameters *config, Error **errp);
+bool migrate_rdma_caps_check(const MigrationParameters *config, Error **errp);
 bool migrate_can_snapshot(Error **errp);
 
 /* parameters */
@@ -76,7 +76,7 @@ const char *migrate_tls_hostname(void);
 uint64_t migrate_xbzrle_cache_size(void);
 ZeroPageDetection migrate_zero_page_detection(void);
 
-bool migrate_params_check(MigrationParameters *params, Error **errp);
+bool migrate_params_check(const MigrationParameters *params, Error **errp);
 void migrate_params_init(MigrationParameters *params);
 void migrate_tls_opts_free(MigrationParameters *params);
 bool migrate_capability_get_compat(MigrationParameters *params, int i);
@@ -84,5 +84,6 @@ void migrate_capability_set_compat(MigrationParameters *params, int i,
                                    bool val);
 void migrate_capabilities_set_compat(MigrationParameters *params,
                                      MigrationCapabilityStatusList *caps);
-bool migrate_caps_check(MigrationParameters *new, Error **errp);
+bool migrate_caps_check(const MigrationParameters *const new, Error **errp);
+void migrate_params_store_defaults(MigrationState *s);
 #endif
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 23/51] migration: Allow migrate commands to provide the migration config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (21 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 22/51] migration: Store the initial values used for s->parameters Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 24/51] migration: Allow incoming cmdline to take config Fabiano Rosas
                   ` (28 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Eric Blake, Paolo Bonzini

Allow the migrate and migrate_incoming commands to pass the migration
configuration options all at once, dispensing the use of
migrate-set-parameters and migrate-set-capabilities.

The motivation of this is to simplify the interface with the
management layer and avoid the usage of several command invocations to
configure a migration. It also avoids stale parameters from a previous
migration to influence the current migration.

The options that are changed during the migration can still be set
with the existing commands.

The order of precedence is:

'config' argument > migrate-set-parameters > -global migration cmdline
> defaults (migration_properties)

I.e. the config takes precedence over all, values not present in the
config assume the default values. The -global migration command line
option allows the defaults to be overridden for debug.

Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/migration-hmp-cmds.c |  5 +++--
 migration/migration.c          | 28 +++++++++++++++++++++++++---
 migration/options.c            | 19 +++++++++++++++++++
 migration/options.h            |  4 +++-
 qapi/migration.json            | 10 ++++++++++
 system/vl.c                    |  3 ++-
 6 files changed, 62 insertions(+), 7 deletions(-)

diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 7e5ac57da5..e9c3541352 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -672,7 +672,7 @@ void hmp_migrate_incoming(Monitor *mon, const QDict *qdict)
     }
     QAPI_LIST_PREPEND(caps, g_steal_pointer(&channel));
 
-    qmp_migrate_incoming(NULL, true, caps, true, false, &err);
+    qmp_migrate_incoming(NULL, true, caps, NULL, true, false, &err);
     qapi_free_MigrationChannelList(caps);
 
 end:
@@ -1070,7 +1070,8 @@ void hmp_migrate(Monitor *mon, const QDict *qdict)
     }
     QAPI_LIST_PREPEND(caps, g_steal_pointer(&channel));
 
-    qmp_migrate(NULL, true, caps, false, false, true, resume, &err);
+    qmp_migrate(NULL, true, caps, NULL, false, false, true, resume,
+                &err);
     if (hmp_handle_error(mon, err)) {
         return;
     }
diff --git a/migration/migration.c b/migration/migration.c
index 90b381b1fe..d23ab2905a 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1930,13 +1930,24 @@ void migrate_del_blocker(Error **reasonp)
 
 void qmp_migrate_incoming(const char *uri, bool has_channels,
                           MigrationChannelList *channels,
-                          bool has_exit_on_error, bool exit_on_error,
-                          Error **errp)
+                          MigrationParameters *config, bool has_exit_on_error,
+                          bool exit_on_error, Error **errp)
 {
     Error *local_err = NULL;
     static bool once = true;
+    MigrationState *s = migrate_get_current();
     MigrationIncomingState *mis = migration_incoming_get_current();
 
+    if (config) {
+        /*
+         * If a config was provided, all options set previously by
+         * migrate-set-parameters get ignored.
+         */
+        if (!migrate_params_override(s, config, errp)) {
+            return;
+        }
+    }
+
     if (!once) {
         error_setg(errp, "The incoming migration has already been started");
         return;
@@ -2208,7 +2219,8 @@ static gboolean qmp_migrate_finish_cb(QIOChannel *channel,
 }
 
 void qmp_migrate(const char *uri, bool has_channels,
-                 MigrationChannelList *channels, bool has_detach, bool detach,
+                 MigrationChannelList *channels,
+                 bool has_detach, bool detach, MigrationParameters *config,
                  bool has_resume, bool resume, Error **errp)
 {
     bool resume_requested;
@@ -2219,6 +2231,16 @@ void qmp_migrate(const char *uri, bool has_channels,
     MigrationChannel *channelv[MIGRATION_CHANNEL_TYPE__MAX] = { NULL };
     MigrationChannel *cpr_channel = NULL;
 
+    if (config) {
+        /*
+         * If a config was provided, all options set previously by
+         * migrate-set-parameters get ignored.
+         */
+        if (!migrate_params_override(s, config, errp)) {
+            return;
+        }
+    }
+
     /*
      * Having preliminary checks for uri and channel
      */
diff --git a/migration/options.c b/migration/options.c
index d1d8e5c181..ccc25ad008 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -1389,6 +1389,25 @@ void migrate_params_store_defaults(MigrationState *s)
     s->initial_params = QAPI_CLONE(MigrationParameters, &s->parameters);
 }
 
+bool migrate_params_override(MigrationState *s, MigrationParameters *new,
+                             Error **errp)
+{
+    ERRP_GUARD();
+
+    assert(bql_locked());
+
+    /* reset to initial parameters */
+    migrate_params_apply(s->initial_params);
+
+    /* apply the new ones on top */
+    qmp_migrate_set_parameters(new, errp);
+    if (*errp) {
+        return false;
+    }
+
+    return true;
+}
+
 void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
 {
     MigrationState *s = migrate_get_current();
diff --git a/migration/options.h b/migration/options.h
index 47f84bf180..29dee6f444 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -84,6 +84,8 @@ void migrate_capability_set_compat(MigrationParameters *params, int i,
                                    bool val);
 void migrate_capabilities_set_compat(MigrationParameters *params,
                                      MigrationCapabilityStatusList *caps);
-bool migrate_caps_check(const MigrationParameters *const new, Error **errp);
+bool migrate_caps_check(const MigrationParameters *new, Error **errp);
 void migrate_params_store_defaults(MigrationState *s);
+bool migrate_params_override(MigrationState *s, MigrationParameters *new,
+                             Error **errp);
 #endif
diff --git a/qapi/migration.json b/qapi/migration.json
index 76a1e03f2f..bd799d67e4 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1546,6 +1546,10 @@
 #     will fail unless migration is in "postcopy-paused" state.
 #     (default: false, since 3.0)
 #
+# @config: migration configuration options.  When present, any
+#     migration configuration previously set with
+#     @migrate-set-parameters is ignored.  (since 11.0)
+#
 # Features:
 #
 # @deprecated: Argument @detach is deprecated.
@@ -1610,6 +1614,7 @@
   'data': {'*uri': 'str',
            '*channels': [ 'MigrationChannel' ],
            '*detach': { 'type': 'bool', 'features': [ 'deprecated' ] },
+           '*config': 'MigrationParameters',
            '*resume': 'bool' } }
 
 ##
@@ -1629,6 +1634,10 @@
 #     :qapi:event:`MIGRATION` event, and error details could be
 #     retrieved with `query-migrate`.  (since 9.1)
 #
+# @config: migration configuration options.  When present, any
+#     migration configuration previously set with
+#     @migrate-set-parameters is ignored.  (since 11.0)
+#
 # Since: 2.3
 #
 # .. admonition:: Notes
@@ -1682,6 +1691,7 @@
 { 'command': 'migrate-incoming',
              'data': {'*uri': 'str',
                       '*channels': [ 'MigrationChannel' ],
+                      '*config': 'MigrationParameters',
                       '*exit-on-error': 'bool' } }
 
 ##
diff --git a/system/vl.c b/system/vl.c
index 5091fe52d9..d09dc9a61c 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -2829,7 +2829,8 @@ void qmp_x_exit_preconfig(Error **errp)
                 g_new0(MigrationChannelList, 1);
 
             channels->value = incoming_channels[MIGRATION_CHANNEL_TYPE_MAIN];
-            qmp_migrate_incoming(NULL, true, channels, true, true, &local_err);
+            qmp_migrate_incoming(NULL, true, channels, NULL, true, true,
+                                 &local_err);
             if (local_err) {
                 error_reportf_err(local_err, "-incoming %s: ", incoming);
                 exit(1);
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 24/51] migration: Allow incoming cmdline to take config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (22 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 23/51] migration: Allow migrate commands to provide the migration config Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-17 15:34   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 25/51] tests/qtest/migration: Pass MigrateCommon into test functions Fabiano Rosas
                   ` (27 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Paolo Bonzini

When -incoming "defer" is not used, the incoming migration is invoked
directly by the command line parsing code in vl.c. Allow the migration
config to be passed via the -incoming command line option so that
invocation of qmp_migrate_incoming() can receive it.

E.g.
-incoming '{"tls-creds": "tlscredsx509server0", "tls-hostname": "qemu.org"}'

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
This is useful for the tests. If we want to declare that
config-passing only works with -incoming defer, that's fine with me.
---
 system/vl.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 100 insertions(+), 12 deletions(-)

diff --git a/system/vl.c b/system/vl.c
index d09dc9a61c..ac44933a11 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -169,6 +169,9 @@ static const char *mem_path;
 static const char *incoming;
 static const char *incoming_str[MIGRATION_CHANNEL_TYPE__MAX];
 static MigrationChannel *incoming_channels[MIGRATION_CHANNEL_TYPE__MAX];
+static MigrationParameters *migration_config;
+static Error *migration_channel_err;
+static Error *migration_config_err;
 static const char *loadvm;
 static const char *accelerators;
 static bool have_custom_ram_size;
@@ -1825,28 +1828,102 @@ static void object_option_add_visitor(Visitor *v)
     QTAILQ_INSERT_TAIL(&object_opts, opt, next);
 }
 
-static void incoming_option_parse(const char *str)
+/*
+ * Either "defer" or a proper uri, whether plain string or a json
+ * representation of MigrationChannel.
+ */
+static bool incoming_option_parse_channels(const char *str, Error **errp)
 {
     MigrationChannelType type = MIGRATION_CHANNEL_TYPE_MAIN;
-    MigrationChannel *channel;
+    MigrationChannel *channel = NULL;
     Visitor *v;
 
-    if (!strcmp(str, "defer")) {
-        channel = NULL;
-    } else if (migrate_is_uri(str)) {
+    if (g_str_equal(str, "defer")) {
+        incoming_str[type] = str;
+        return true;
+    }
+
+    if (migrate_is_uri(str)) {
         migrate_uri_parse(str, &channel, &error_fatal);
     } else {
         v = qobject_input_visitor_new_str(str, "channel-type", &error_fatal);
-        visit_type_MigrationChannel(v, NULL, &channel, &error_fatal);
+        if (v && !visit_type_MigrationChannel(v, NULL, &channel, errp)) {
+            visit_free(v);
+            return false;
+        }
         visit_free(v);
+    }
+
+    if (channel) {
         type = channel->channel_type;
+        /* New incoming spec replaces the previous */
+        qapi_free_MigrationChannel(incoming_channels[type]);
+        incoming_channels[type] = channel;
+        incoming_str[type] = str;
     }
 
-    /* New incoming spec replaces the previous */
-    qapi_free_MigrationChannel(incoming_channels[type]);
-    incoming_channels[type] = channel;
-    incoming_str[type] = str;
     incoming = incoming_str[MIGRATION_CHANNEL_TYPE_MAIN];
+    return true;
+}
+
+/*
+ * The migration configuration object in JSON form.
+ */
+static bool incoming_option_parse_config(const char *str, Error **errp)
+{
+    MigrationParameters *config = NULL;
+    Visitor *v;
+
+    v = qobject_input_visitor_new_str(str, "config", &error_fatal);
+    if (v && !visit_type_MigrationParameters(v, NULL, &config, errp)) {
+        visit_free(v);
+        return false;
+    }
+
+    if (config) {
+        /* later incoming configs replace the previous ones */
+        migration_config = config;
+    }
+
+    visit_free(v);
+    return true;
+}
+
+static void incoming_option_parse(const char *str)
+{
+    /*
+     * Independent Error objects because we don't know whether the
+     * input is meant to be the channels or the config. The parsing
+     * may fail for one and succeed for the other.
+     */
+    g_autoptr(Error) channel_err = NULL;
+    g_autoptr(Error) config_err = NULL;
+
+    /*
+     * Skip if there's already an error for a previous -incoming
+     * instance.
+     */
+    if (migration_channel_err || migration_config_err) {
+        return;
+    }
+
+    if (!migration_channel_err &&
+        incoming_option_parse_channels(str, &channel_err)) {
+        return;
+    }
+
+    if (!migration_config_err &&
+        incoming_option_parse_config(str, &config_err)) {
+        return;
+    }
+
+    if (channel_err) {
+        migration_channel_err = error_copy(channel_err);
+        error_prepend(&migration_channel_err, "-incoming %s: ", str);
+    } else if (config_err) {
+        migration_config_err = error_copy(config_err);
+        error_prepend(&migration_config_err, "-incoming %s: ", str);
+    }
 }
 
 static void object_option_parse(const char *str)
@@ -2537,6 +2614,16 @@ static void qemu_validate_options(const QDict *machine_opts)
         exit(EXIT_FAILURE);
     }
 
+    if (migration_channel_err && !incoming) {
+        error_report_err(migration_config_err);
+        exit(EXIT_FAILURE);
+    }
+
+    if (migration_config_err && !migration_config) {
+        error_report_err(migration_config_err);
+        exit(EXIT_FAILURE);
+    }
+
 #ifdef CONFIG_CURSES
     if (is_daemonized() && dpy.type == DISPLAY_TYPE_CURSES) {
         error_report("curses display cannot be used with -daemonize");
@@ -2824,13 +2911,14 @@ void qmp_x_exit_preconfig(Error **errp)
 
     if (incoming) {
         Error *local_err = NULL;
+
         if (strcmp(incoming, "defer") != 0) {
             g_autofree MigrationChannelList *channels =
                 g_new0(MigrationChannelList, 1);
 
             channels->value = incoming_channels[MIGRATION_CHANNEL_TYPE_MAIN];
-            qmp_migrate_incoming(NULL, true, channels, NULL, true, true,
-                                 &local_err);
+            qmp_migrate_incoming(NULL, true, channels, migration_config, true,
+                                 true, &local_err);
             if (local_err) {
                 error_reportf_err(local_err, "-incoming %s: ", incoming);
                 exit(1);
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 25/51] tests/qtest/migration: Pass MigrateCommon into test functions
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (23 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 24/51] migration: Allow incoming cmdline to take config Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-16 21:57   ` Peter Xu
  2025-12-17 18:35   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 26/51] tests/qtest/migration: Pass MigrateStart into cancel tests Fabiano Rosas
                   ` (26 subsequent siblings)
  51 siblings, 2 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

With the upcoming addition of the config QDict, the tests will need a
better way of managing the memory of the test data than putting the
test arguments on the stack of the test functions. The config QDict
will need to be merged into the arguments of migrate_qmp* functions,
which causes a refcount increment, so the test functions would need to
allocate and deref the config QDict themselves.

A better approach is to already pass the arguments into the test
functions and do the memory management in the existing wrapper. There
is already migration_test_destroy(), which is called for every test.

Do the following:

- merge the two existing wrappers, migration_test_wrapper() and
  migration_test_wrapper_full(). The latter was pioneer in passing
  data into the tests, but now all tests will receive data, so we
  don't need it anymore.

  The usage of migration_test_wrapper_full() was in passing a slightly
  different test name string into the cancel tests, so still keep the
  migration_test_add_suffix() function.

- add (char *name, MigrateCommon *args) to the signature of all test
  functions.

- alter any code to stop allocating args on the stack and instead use
  the object that came as parameter.

- pass args around as needed.

- while here, order args (MigrateCommon) before args->start
  (MigrateStart) and put a blank like in between.

No functional change.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/compression-tests.c | 127 +++---
 tests/qtest/migration/cpr-tests.c         |  71 ++--
 tests/qtest/migration/file-tests.c        | 184 ++++----
 tests/qtest/migration/migration-util.c    |  26 +-
 tests/qtest/migration/migration-util.h    |   8 +-
 tests/qtest/migration/misc-tests.c        | 108 ++---
 tests/qtest/migration/postcopy-tests.c    |  80 ++--
 tests/qtest/migration/precopy-tests.c     | 354 +++++++---------
 tests/qtest/migration/tls-tests.c         | 485 ++++++++++------------
 9 files changed, 642 insertions(+), 801 deletions(-)

diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
index b827665b8e..845e622cd5 100644
--- a/tests/qtest/migration/compression-tests.c
+++ b/tests/qtest/migration/compression-tests.c
@@ -31,30 +31,25 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
     return migrate_hook_start_precopy_tcp_multifd_common(from, to, "zstd");
 }
 
-static void test_multifd_tcp_zstd(void)
+static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        .start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
-static void test_multifd_postcopy_tcp_zstd(void)
+static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-            .caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true,
-        },
-        .start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
-    };
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
 
-    test_precopy_common(&args);
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
+
+    test_precopy_common(args);
 }
 #endif /* CONFIG_ZSTD */
 
@@ -69,16 +64,14 @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
     return migrate_hook_start_precopy_tcp_multifd_common(from, to, "qatzip");
 }
 
-static void test_multifd_tcp_qatzip(void)
+static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        .start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 #endif
 
@@ -90,16 +83,14 @@ migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
     return migrate_hook_start_precopy_tcp_multifd_common(from, to, "qpl");
 }
 
-static void test_multifd_tcp_qpl(void)
+static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        .start_hook = migrate_hook_start_precopy_tcp_multifd_qpl,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 #endif /* CONFIG_QPL */
 
@@ -111,16 +102,14 @@ migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
     return migrate_hook_start_precopy_tcp_multifd_common(from, to, "uadk");
 }
 
-static void test_multifd_tcp_uadk(void)
+static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        .start_hook = migrate_hook_start_precopy_tcp_multifd_uadk,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 #endif /* CONFIG_UADK */
 
@@ -132,25 +121,23 @@ migrate_hook_start_xbzrle(QTestState *from,
     return NULL;
 }
 
-static void test_precopy_unix_xbzrle(void)
+static void test_precopy_unix_xbzrle(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = uri,
-        .start_hook = migrate_hook_start_xbzrle,
-        .iterations = 2,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_XBZRLE] = true,
-        },
-        /*
-         * XBZRLE needs pages to be modified when doing the 2nd+ round
-         * iteration to have real data pushed to the stream.
-         */
-        .live = true,
-    };
 
-    test_precopy_common(&args);
+    args->connect_uri = uri;
+    args->listen_uri = uri;
+    args->start_hook = migrate_hook_start_xbzrle;
+    args->iterations = 2;
+    /*
+     * XBZRLE needs pages to be modified when doing the 2nd+ round
+     * iteration to have real data pushed to the stream.
+     */
+    args->live = true;
+
+    args->start.caps[MIGRATION_CAPABILITY_XBZRLE] = true;
+
+    test_precopy_common(args);
 }
 
 static void *
@@ -167,16 +154,14 @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
     return migrate_hook_start_precopy_tcp_multifd_common(from, to, "zlib");
 }
 
-static void test_multifd_tcp_zlib(void)
+static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        .start_hook = migrate_hook_start_precopy_tcp_multifd_zlib,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
 static void migration_test_add_compression_smoke(MigrationTestEnv *env)
diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
index 2a186c6f35..0d97b5b89f 100644
--- a/tests/qtest/migration/cpr-tests.c
+++ b/tests/qtest/migration/cpr-tests.c
@@ -27,21 +27,19 @@ static void *migrate_hook_start_mode_reboot(QTestState *from, QTestState *to)
     return NULL;
 }
 
-static void test_mode_reboot(void)
+static void test_mode_reboot(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
-    MigrateCommon args = {
-        .start.mem_type = MEM_TYPE_SHMEM,
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_mode_reboot,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true,
-        },
-    };
 
-    test_file_common(&args, true);
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_mode_reboot;
+
+    args->start.mem_type = MEM_TYPE_SHMEM;
+    args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
+
+    test_file_common(args, true);
 }
 
 static void *test_mode_transfer_start(QTestState *from, QTestState *to)
@@ -55,7 +53,7 @@ static void *test_mode_transfer_start(QTestState *from, QTestState *to)
  * migration, and cannot connect synchronously to the monitor, so defer
  * the target connection.
  */
-static void test_mode_transfer_common(bool incoming_defer)
+static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer)
 {
     g_autofree char *cpr_path = g_strdup_printf("%s/cpr.sock", tmpfs);
     g_autofree char *mig_path = g_strdup_printf("%s/migsocket", tmpfs);
@@ -85,31 +83,31 @@ static void test_mode_transfer_common(bool incoming_defer)
     opts_target = g_strdup_printf("-incoming cpr,addr.transport=socket,"
                                   "addr.type=fd,addr.str=%d %s",
                                   cpr_sockfd, opts);
-    MigrateCommon args = {
-        .start.opts_source = opts,
-        .start.opts_target = opts_target,
-        .start.defer_target_connect = true,
-        .start.mem_type = MEM_TYPE_MEMFD,
-        .listen_uri = incoming_defer ? "defer" : uri,
-        .connect_channels = connect_channels,
-        .cpr_channel = cpr_channel,
-        .start_hook = test_mode_transfer_start,
-    };
 
-    if (test_precopy_common(&args) < 0) {
+    args->listen_uri = incoming_defer ? "defer" : uri;
+    args->connect_channels = connect_channels;
+    args->cpr_channel = cpr_channel;
+    args->start_hook = test_mode_transfer_start;
+
+    args->start.opts_source = opts;
+    args->start.opts_target = opts_target;
+    args->start.defer_target_connect = true;
+    args->start.mem_type = MEM_TYPE_MEMFD;
+
+    if (test_precopy_common(args) < 0) {
         close(cpr_sockfd);
         unlink(cpr_path);
     }
 }
 
-static void test_mode_transfer(void)
+static void test_mode_transfer(char *name, MigrateCommon *args)
 {
-    test_mode_transfer_common(NULL);
+    test_mode_transfer_common(args, false);
 }
 
-static void test_mode_transfer_defer(void)
+static void test_mode_transfer_defer(char *name, MigrateCommon *args)
 {
-    test_mode_transfer_common(true);
+    test_mode_transfer_common(args, true);
 }
 
 static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
@@ -225,22 +223,21 @@ static void *test_mode_exec_start(QTestState *from, QTestState *to)
     return NULL;
 }
 
-static void test_mode_exec(void)
+static void test_mode_exec(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
     g_autofree char *listen_uri = g_strdup_printf("defer");
 
-    MigrateCommon args = {
-        .start.only_source = true,
-        .start.opts_source = "-machine aux-ram-share=on -nodefaults",
-        .start.mem_type = MEM_TYPE_MEMFD,
-        .connect_uri = uri,
-        .listen_uri = listen_uri,
-        .start_hook = test_mode_exec_start,
-    };
+    args->connect_uri = uri;
+    args->listen_uri = listen_uri;
+    args->start_hook = test_mode_exec_start;
 
-    test_cpr_exec(&args);
+    args->start.only_source = true;
+    args->start.opts_source = "-machine aux-ram-share=on -nodefaults";
+    args->start.mem_type = MEM_TYPE_MEMFD;
+
+    test_cpr_exec(args);
 }
 
 void migration_test_add_cpr(MigrationTestEnv *env)
diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
index 4d78ce0855..5f1159076c 100644
--- a/tests/qtest/migration/file-tests.c
+++ b/tests/qtest/migration/file-tests.c
@@ -20,16 +20,14 @@
 
 static char *tmpfs;
 
-static void test_precopy_file(void)
+static void test_precopy_file(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-    };
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
 
-    test_file_common(&args, true);
+    test_file_common(args, true);
 }
 
 #ifndef _WIN32
@@ -66,107 +64,94 @@ static void *migrate_hook_start_file_offset_fdset(QTestState *from,
     return NULL;
 }
 
-static void test_precopy_file_offset_fdset(void)
+static void test_precopy_file_offset_fdset(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
                                            FILE_TEST_OFFSET);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_file_offset_fdset,
-    };
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_file_offset_fdset;
 
-    test_file_common(&args, false);
+    test_file_common(args, false);
 }
 #endif
 
-static void test_precopy_file_offset(void)
+static void test_precopy_file_offset(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs,
                                            FILE_TEST_FILENAME,
                                            FILE_TEST_OFFSET);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-    };
 
-    test_file_common(&args, false);
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+
+    test_file_common(args, false);
 }
 
-static void test_precopy_file_offset_bad(void)
+static void test_precopy_file_offset_bad(char *name, MigrateCommon *args)
 {
     /* using a value not supported by qemu_strtosz() */
     g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M",
                                            tmpfs, FILE_TEST_FILENAME);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .result = MIG_TEST_QMP_ERROR,
-    };
 
-    test_file_common(&args, false);
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+    args->result = MIG_TEST_QMP_ERROR;
+
+    test_file_common(args, false);
 }
 
-static void test_precopy_file_mapped_ram_live(void)
+static void test_precopy_file_mapped_ram_live(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
-        },
-    };
-
-    test_file_common(&args, false);
+
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+
+    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
+
+    test_file_common(args, false);
 }
 
-static void test_precopy_file_mapped_ram(void)
+static void test_precopy_file_mapped_ram(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
-        },
-    };
-
-    test_file_common(&args, true);
+
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+
+    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
+
+    test_file_common(args, true);
 }
 
-static void test_multifd_file_mapped_ram_live(void)
+static void test_multifd_file_mapped_ram_live(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-            .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
-        },
-    };
-
-    test_file_common(&args, false);
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
+
+    test_file_common(args, false);
 }
 
-static void test_multifd_file_mapped_ram(void)
+static void test_multifd_file_mapped_ram(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-            .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
-        },
-    };
-
-    test_file_common(&args, true);
+
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
+
+    test_file_common(args, true);
 }
 
 static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
@@ -178,26 +163,23 @@ static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
     return NULL;
 }
 
-static void test_multifd_file_mapped_ram_dio(void)
+static void test_multifd_file_mapped_ram_dio(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_mapped_ram_dio,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-    };
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_mapped_ram_dio;
+
+    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     if (!probe_o_direct_support(tmpfs)) {
         g_test_skip("Filesystem does not support O_DIRECT");
         return;
     }
 
-    test_file_common(&args, true);
+    test_file_common(args, true);
 }
 
 #ifndef _WIN32
@@ -252,45 +234,41 @@ static void *migrate_hook_start_multifd_mapped_ram_fdset(QTestState *from,
     return NULL;
 }
 
-static void test_multifd_file_mapped_ram_fdset(void)
+static void test_multifd_file_mapped_ram_fdset(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
                                            FILE_TEST_OFFSET);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_mapped_ram_fdset,
-        .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-    };
 
-    test_file_common(&args, true);
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset;
+    args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
+
+    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_file_common(args, true);
 }
 
-static void test_multifd_file_mapped_ram_fdset_dio(void)
+static void test_multifd_file_mapped_ram_fdset_dio(char *name,
+                                                   MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
                                            FILE_TEST_OFFSET);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio,
-        .end_hook = migrate_hook_end_multifd_mapped_ram_fdset,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-    };
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio;
+    args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
+
+    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     if (!probe_o_direct_support(tmpfs)) {
         g_test_skip("Filesystem does not support O_DIRECT");
         return;
     }
 
-    test_file_common(&args, true);
+    test_file_common(args, true);
 }
 #endif /* !_WIN32 */
 
diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
index 642cf50c8d..c2462306a1 100644
--- a/tests/qtest/migration/migration-util.c
+++ b/tests/qtest/migration/migration-util.c
@@ -235,14 +235,15 @@ char *resolve_machine_version(const char *alias, const char *var1,
 
 typedef struct {
     char *name;
-    void (*func)(void);
-    void (*func_full)(void *);
+    MigrateCommon *data;
+    void (*func)(char *name, MigrateCommon *args);
 } MigrationTest;
 
 static void migration_test_destroy(gpointer data)
 {
     MigrationTest *test = (MigrationTest *)data;
 
+    g_free(test->data);
     g_free(test->name);
     g_free(test);
 }
@@ -251,11 +252,14 @@ static void migration_test_wrapper(const void *data)
 {
     MigrationTest *test = (MigrationTest *)data;
 
+    test->data = g_new0(MigrateCommon, 1);
+
     g_test_message("Running /%s%s", qtest_get_arch(), test->name);
-    test->func();
+    test->func(test->name, test->data);
 }
 
-void migration_test_add(const char *path, void (*fn)(void))
+void migration_test_add(const char *path,
+                        void (*fn)(char *name, MigrateCommon *args))
 {
     MigrationTest *test = g_new0(MigrationTest, 1);
 
@@ -266,26 +270,18 @@ void migration_test_add(const char *path, void (*fn)(void))
                              migration_test_destroy);
 }
 
-static void migration_test_wrapper_full(const void *data)
-{
-    MigrationTest *test = (MigrationTest *)data;
-
-    g_test_message("Running /%s%s", qtest_get_arch(), test->name);
-    test->func_full(test->name);
-}
-
 void migration_test_add_suffix(const char *path, const char *suffix,
-                               void (*fn)(void *))
+                               void (*fn)(char *name, MigrateCommon *args))
 {
     MigrationTest *test = g_new0(MigrationTest, 1);
 
     g_assert(g_str_has_suffix(path, "/"));
     g_assert(!g_str_has_prefix(suffix, "/"));
 
-    test->func_full = fn;
+    test->func = fn;
     test->name = g_strconcat(path, suffix, NULL);
 
-    qtest_add_data_func_full(test->name, test, migration_test_wrapper_full,
+    qtest_add_data_func_full(test->name, test, migration_test_wrapper,
                              migration_test_destroy);
 }
 
diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
index 44815e9c42..e73d69bab0 100644
--- a/tests/qtest/migration/migration-util.h
+++ b/tests/qtest/migration/migration-util.h
@@ -15,6 +15,8 @@
 
 #include "libqtest.h"
 
+#include "migration/framework.h"
+
 typedef struct QTestMigrationState {
     bool stop_seen;
     bool resume_seen;
@@ -50,9 +52,11 @@ static inline bool probe_o_direct_support(const char *tmpfs)
 
 bool ufd_version_check(bool *uffd_feature_thread_id);
 bool kvm_dirty_ring_supported(void);
-void migration_test_add(const char *path, void (*fn)(void));
+
+void migration_test_add(const char *path,
+                        void (*fn)(char *name, MigrateCommon *args));
 void migration_test_add_suffix(const char *path, const char *suffix,
-                               void (*fn)(void *));
+                               void (*fn)(char *name, MigrateCommon *args));
 char *migrate_get_connect_uri(QTestState *who);
 void migrate_set_ports(QTestState *to, QList *channel_list);
 
diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
index 20edaa51f5..810e9e6549 100644
--- a/tests/qtest/migration/misc-tests.c
+++ b/tests/qtest/migration/misc-tests.c
@@ -22,14 +22,13 @@
 
 static char *tmpfs;
 
-static void test_baddest(void)
+static void test_baddest(char *name, MigrateCommon *args)
 {
-    MigrateStart args = {
-        .hide_stderr = true
-    };
     QTestState *from, *to;
 
-    if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
+    args->start.hide_stderr = true;
+
+    if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) {
         return;
     }
     migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, "{}");
@@ -38,24 +37,23 @@ static void test_baddest(void)
 }
 
 #ifndef _WIN32
-static void test_analyze_script(void)
+static void test_analyze_script(char *name, MigrateCommon *args)
 {
-    MigrateStart args = {
-        .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
-    };
     QTestState *from, *to;
     g_autofree char *uri = NULL;
     g_autofree char *file = NULL;
     int pid, wstatus;
     const char *python = g_getenv("PYTHON");
 
+    args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
+
     if (!python) {
         g_test_skip("PYTHON variable not set");
         return;
     }
 
     /* dummy url */
-    if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
+    if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) {
         return;
     }
 
@@ -92,16 +90,15 @@ static void test_analyze_script(void)
 }
 #endif
 
-static void test_ignore_shared(void)
+static void test_ignore_shared(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
     QTestState *from, *to;
-    MigrateStart args = {
-        .mem_type = MEM_TYPE_SHMEM,
-        .caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true,
-    };
 
-    if (migrate_start(&from, &to, uri, &args)) {
+    args->start.mem_type = MEM_TYPE_SHMEM;
+    args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
+
+    if (migrate_start(&from, &to, uri, &args->start)) {
         return;
     }
 
@@ -161,45 +158,37 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
     migrate_end(from, to, false);
 }
 
-static void test_validate_uuid(void)
+static void test_validate_uuid(char *name, MigrateCommon *args)
 {
-    MigrateStart args = {
-        .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
-        .opts_target = "-uuid 11111111-1111-1111-1111-111111111111",
-    };
+    args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
+    args->start.opts_target = "-uuid 11111111-1111-1111-1111-111111111111";
 
-    do_test_validate_uuid(&args, false);
+    do_test_validate_uuid(&args->start, false);
 }
 
-static void test_validate_uuid_error(void)
+static void test_validate_uuid_error(char *name, MigrateCommon *args)
 {
-    MigrateStart args = {
-        .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
-        .opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
-        .hide_stderr = true,
-    };
+    args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
+    args->start.opts_target = "-uuid 22222222-2222-2222-2222-222222222222";
+    args->start.hide_stderr = true;
 
-    do_test_validate_uuid(&args, true);
+    do_test_validate_uuid(&args->start, true);
 }
 
-static void test_validate_uuid_src_not_set(void)
+static void test_validate_uuid_src_not_set(char *name, MigrateCommon *args)
 {
-    MigrateStart args = {
-        .opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
-        .hide_stderr = true,
-    };
+    args->start.opts_target = "-uuid 22222222-2222-2222-2222-222222222222";
+    args->start.hide_stderr = true;
 
-    do_test_validate_uuid(&args, false);
+    do_test_validate_uuid(&args->start, false);
 }
 
-static void test_validate_uuid_dst_not_set(void)
+static void test_validate_uuid_dst_not_set(char *name, MigrateCommon *args)
 {
-    MigrateStart args = {
-        .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
-        .hide_stderr = true,
-    };
+    args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
+    args->start.hide_stderr = true;
 
-    do_test_validate_uuid(&args, false);
+    do_test_validate_uuid(&args->start, false);
 }
 
 static void do_test_validate_uri_channel(MigrateCommon *args)
@@ -226,34 +215,27 @@ static void do_test_validate_uri_channel(MigrateCommon *args)
     migrate_end(from, to, false);
 }
 
-static void test_validate_uri_channels_both_set(void)
+static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-        },
-        .listen_uri = "defer",
-        .connect_uri = "tcp:127.0.0.1:0",
-        .connect_channels = ("[ { ""'channel-type': 'main',"
-                             "    'addr': { 'transport': 'socket',"
-                             "              'type': 'inet',"
-                             "              'host': '127.0.0.1',"
-                             "              'port': '0' } } ]"),
-    };
+    args->listen_uri = "defer",
+    args->connect_uri = "tcp:127.0.0.1:0",
+    args->connect_channels = ("[ { ""'channel-type': 'main',"
+                              "    'addr': { 'transport': 'socket',"
+                              "              'type': 'inet',"
+                              "              'host': '127.0.0.1',"
+                              "              'port': '0' } } ]"),
 
-    do_test_validate_uri_channel(&args);
+    args->start.hide_stderr = true;
+
+    do_test_validate_uri_channel(args);
 }
 
-static void test_validate_uri_channels_none_set(void)
+static void test_validate_uri_channels_none_set(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-        },
-        .listen_uri = "defer",
-    };
+    args->listen_uri = "defer";
+    args->start.hide_stderr = true;
 
-    do_test_validate_uri_channel(&args);
+    do_test_validate_uri_channel(args);
 }
 
 static void migration_test_add_misc_smoke(MigrationTestEnv *env)
diff --git a/tests/qtest/migration/postcopy-tests.c b/tests/qtest/migration/postcopy-tests.c
index 3773525843..7ae4d765d7 100644
--- a/tests/qtest/migration/postcopy-tests.c
+++ b/tests/qtest/migration/postcopy-tests.c
@@ -20,67 +20,51 @@
 #include "qemu/range.h"
 #include "qemu/sockets.h"
 
-static void test_postcopy(void)
+static void test_postcopy(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = { };
-
-    test_postcopy_common(&args);
+    test_postcopy_common(args);
 }
 
-static void test_postcopy_suspend(void)
+static void test_postcopy_suspend(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start.suspend_me = true,
-    };
+    args->start.suspend_me = true;
 
-    test_postcopy_common(&args);
+    test_postcopy_common(args);
 }
 
-static void test_postcopy_preempt(void)
+static void test_postcopy_preempt(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
-        },
-    };
+    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
 
-    test_postcopy_common(&args);
+    test_postcopy_common(args);
 }
 
-static void test_postcopy_recovery(void)
+static void test_postcopy_recovery(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = { };
-
-    test_postcopy_recovery_common(&args);
+    test_postcopy_recovery_common(args);
 }
 
-static void test_postcopy_recovery_fail_handshake(void)
+static void test_postcopy_recovery_fail_handshake(char *name,
+                                                  MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .postcopy_recovery_fail_stage = POSTCOPY_FAIL_RECOVERY,
-    };
+    args->postcopy_recovery_fail_stage = POSTCOPY_FAIL_RECOVERY;
 
-    test_postcopy_recovery_common(&args);
+    test_postcopy_recovery_common(args);
 }
 
-static void test_postcopy_recovery_fail_reconnect(void)
+static void test_postcopy_recovery_fail_reconnect(char *name,
+                                                  MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .postcopy_recovery_fail_stage = POSTCOPY_FAIL_CHANNEL_ESTABLISH,
-    };
+    args->postcopy_recovery_fail_stage = POSTCOPY_FAIL_CHANNEL_ESTABLISH;
 
-    test_postcopy_recovery_common(&args);
+    test_postcopy_recovery_common(args);
 }
 
-static void test_postcopy_preempt_recovery(void)
+static void test_postcopy_preempt_recovery(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
-        },
-    };
+    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
 
-    test_postcopy_recovery_common(&args);
+    test_postcopy_recovery_common(args);
 }
 
 static void migration_test_add_postcopy_smoke(MigrationTestEnv *env)
@@ -94,27 +78,19 @@ static void migration_test_add_postcopy_smoke(MigrationTestEnv *env)
     }
 }
 
-static void test_multifd_postcopy(void)
+static void test_multifd_postcopy(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-    };
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_postcopy_common(&args);
+    test_postcopy_common(args);
 }
 
-static void test_multifd_postcopy_preempt(void)
+static void test_multifd_postcopy_preempt(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-            .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
-        },
-    };
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
 
-    test_postcopy_common(&args);
+    test_postcopy_common(args);
 }
 
 void migration_test_add_postcopy(MigrationTestEnv *env)
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index 57ca623de5..086d06a31c 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -35,68 +35,64 @@
 
 static char *tmpfs;
 
-static void test_precopy_unix_plain(void)
+static void test_precopy_unix_plain(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateCommon args = {
-        .listen_uri = uri,
-        .connect_uri = uri,
-        /*
-         * The simplest use case of precopy, covering smoke tests of
-         * get-dirty-log dirty tracking.
-         */
-        .live = true,
-    };
-
-    test_precopy_common(&args);
+
+    args->listen_uri = uri;
+    args->connect_uri = uri;
+    /*
+     * The simplest use case of precopy, covering smoke tests of
+     * get-dirty-log dirty tracking.
+     */
+    args->live = true;
+
+    test_precopy_common(args);
 }
 
-static void test_precopy_unix_suspend_live(void)
+static void test_precopy_unix_suspend_live(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateCommon args = {
-        .listen_uri = uri,
-        .connect_uri = uri,
-        /*
-         * despite being live, the test is fast because the src
-         * suspends immediately.
-         */
-        .live = true,
-        .start.suspend_me = true,
-    };
-
-    test_precopy_common(&args);
+
+    args->listen_uri = uri;
+    args->connect_uri = uri;
+    /*
+     * despite being live, the test is fast because the src
+     * suspends immediately.
+     */
+    args->live = true;
+
+    args->start.suspend_me = true;
+
+    test_precopy_common(args);
 }
 
-static void test_precopy_unix_suspend_notlive(void)
+static void test_precopy_unix_suspend_notlive(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateCommon args = {
-        .listen_uri = uri,
-        .connect_uri = uri,
-        .start.suspend_me = true,
-    };
 
-    test_precopy_common(&args);
+    args->listen_uri = uri;
+    args->connect_uri = uri;
+    args->start.suspend_me = true;
+
+    test_precopy_common(args);
 }
 
-static void test_precopy_unix_dirty_ring(void)
+static void test_precopy_unix_dirty_ring(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateCommon args = {
-        .start = {
-            .use_dirty_ring = true,
-        },
-        .listen_uri = uri,
-        .connect_uri = uri,
-        /*
-         * Besides the precopy/unix basic test, cover dirty ring interface
-         * rather than get-dirty-log.
-         */
-        .live = true,
-    };
-
-    test_precopy_common(&args);
+
+    args->listen_uri = uri;
+    args->connect_uri = uri;
+    /*
+     * Besides the precopy/unix basic test, cover dirty ring interface
+     * rather than get-dirty-log.
+     */
+    args->live = true;
+
+    args->start.use_dirty_ring = true;
+
+    test_precopy_common(args);
 }
 
 #ifdef CONFIG_RDMA
@@ -162,7 +158,7 @@ static int new_rdma_link(char *buffer, bool ipv6)
     return -1;
 }
 
-static void __test_precopy_rdma_plain(bool ipv6)
+static void __test_precopy_rdma_plain(MigrateCommon *args, bool ipv6)
 {
     char buffer[128] = {};
 
@@ -187,50 +183,43 @@ static void __test_precopy_rdma_plain(bool ipv6)
      **/
     g_autofree char *uri = g_strdup_printf("rdma:%s:29200", buffer);
 
-    MigrateCommon args = {
-        .listen_uri = uri,
-        .connect_uri = uri,
-    };
+    args->listen_uri = uri;
+    args->connect_uri = uri;
 
-    test_precopy_common(&args);
+    test_precopy_common(args);
 }
 
-static void test_precopy_rdma_plain(void)
+static void test_precopy_rdma_plain(char *name, MigrateCommon *args)
 {
-    __test_precopy_rdma_plain(false);
+    __test_precopy_rdma_plain(args, false);
 }
 
-static void test_precopy_rdma_plain_ipv6(void)
+static void test_precopy_rdma_plain_ipv6(char *name, MigrateCommon *args)
 {
-    __test_precopy_rdma_plain(true);
+    __test_precopy_rdma_plain(args, true);
 }
 #endif
 
-static void test_precopy_tcp_plain(void)
+static void test_precopy_tcp_plain(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "tcp:127.0.0.1:0",
-    };
+    args->listen_uri = "tcp:127.0.0.1:0";
 
-    test_precopy_common(&args);
+    test_precopy_common(args);
 }
 
-static void test_precopy_tcp_switchover_ack(void)
+static void test_precopy_tcp_switchover_ack(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_RETURN_PATH] = true,
-            .caps[MIGRATION_CAPABILITY_SWITCHOVER_ACK] = true,
-        },
-        /*
-         * Source VM must be running in order to consider the switchover ACK
-         * when deciding to do switchover or not.
-         */
-        .live = true,
-    };
+    args->listen_uri = "tcp:127.0.0.1:0";
+    /*
+     * Source VM must be running in order to consider the switchover ACK
+     * when deciding to do switchover or not.
+     */
+    args->live = true;
 
-    test_precopy_common(&args);
+    args->start.caps[MIGRATION_CAPABILITY_RETURN_PATH] = true;
+    args->start.caps[MIGRATION_CAPABILITY_SWITCHOVER_ACK] = true;
+
+    test_precopy_common(args);
 }
 
 #ifndef _WIN32
@@ -291,15 +280,14 @@ static void migrate_hook_end_fd(QTestState *from,
     qobject_unref(rsp);
 }
 
-static void test_precopy_fd_socket(void)
+static void test_precopy_fd_socket(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .connect_uri = "fd:fd-mig",
-        .start_hook = migrate_hook_start_fd,
-        .end_hook = migrate_hook_end_fd,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->connect_uri = "fd:fd-mig";
+    args->start_hook = migrate_hook_start_fd;
+    args->end_hook = migrate_hook_end_fd;
+
+    test_precopy_common(args);
 }
 
 static void *migrate_hook_start_precopy_fd_file(QTestState *from,
@@ -331,15 +319,14 @@ static void *migrate_hook_start_precopy_fd_file(QTestState *from,
     return NULL;
 }
 
-static void test_precopy_fd_file(void)
+static void test_precopy_fd_file(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .connect_uri = "fd:fd-mig",
-        .start_hook = migrate_hook_start_precopy_fd_file,
-        .end_hook = migrate_hook_end_fd,
-    };
-    test_file_common(&args, true);
+    args->listen_uri = "defer";
+    args->connect_uri = "fd:fd-mig";
+    args->start_hook = migrate_hook_start_precopy_fd_file;
+    args->end_hook = migrate_hook_end_fd;
+
+    test_file_common(args, true);
 }
 #endif /* _WIN32 */
 
@@ -358,10 +345,9 @@ static void test_precopy_fd_file(void)
  * To make things even worse, we need to run the initial stage at
  * 3MB/s so we enter autoconverge even when host is (over)loaded.
  */
-static void test_auto_converge(void)
+static void test_auto_converge(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateStart args = {};
     QTestState *from, *to;
     int64_t percentage;
 
@@ -374,7 +360,7 @@ static void test_auto_converge(void)
     uint64_t prev_dirty_sync_cnt, dirty_sync_cnt;
     int max_try_count, hit = 0;
 
-    if (migrate_start(&from, &to, uri, &args)) {
+    if (migrate_start(&from, &to, uri, &args->start)) {
         return;
     }
 
@@ -486,76 +472,68 @@ migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from,
     return NULL;
 }
 
-static void test_multifd_tcp_uri_none(void)
+static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_precopy_tcp_multifd,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        /*
-         * Multifd is more complicated than most of the features, it
-         * directly takes guest page buffers when sending, make sure
-         * everything will work alright even if guest page is changing.
-         */
-        .live = true,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_precopy_tcp_multifd;
+    /*
+     * Multifd is more complicated than most of the features, it
+     * directly takes guest page buffers when sending, make sure
+     * everything will work alright even if guest page is changing.
+     */
+    args->live = true;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
-static void test_multifd_tcp_zero_page_legacy(void)
+static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        /*
-         * Multifd is more complicated than most of the features, it
-         * directly takes guest page buffers when sending, make sure
-         * everything will work alright even if guest page is changing.
-         */
-        .live = true,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy;
+    /*
+     * Multifd is more complicated than most of the features, it
+     * directly takes guest page buffers when sending, make sure
+     * everything will work alright even if guest page is changing.
+     */
+    args->live = true;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
-static void test_multifd_tcp_no_zero_page(void)
+static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        /*
-         * Multifd is more complicated than most of the features, it
-         * directly takes guest page buffers when sending, make sure
-         * everything will work alright even if guest page is changing.
-         */
-        .live = true,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page;
+    /*
+     * Multifd is more complicated than most of the features, it
+     * directly takes guest page buffers when sending, make sure
+     * everything will work alright even if guest page is changing.
+     */
+    args->live = true;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
-static void test_multifd_tcp_channels_none(void)
+static void test_multifd_tcp_channels_none(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_precopy_tcp_multifd,
-        .live = true,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        .connect_channels = ("[ { 'channel-type': 'main',"
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_precopy_tcp_multifd;
+    args->live = true;
+    args->connect_channels = ("[ { 'channel-type': 'main',"
                              "    'addr': { 'transport': 'socket',"
                              "              'type': 'inet',"
                              "              'host': '127.0.0.1',"
-                             "              'port': '0' } } ]"),
-    };
-    test_precopy_common(&args);
+                              "              'port': '0' } } ]");
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
 /*
@@ -569,14 +547,13 @@ static void test_multifd_tcp_channels_none(void)
  *
  *  And see that it works
  */
-static void test_multifd_tcp_cancel(bool postcopy_ram)
+static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
 {
-    MigrateStart args = {
-        .hide_stderr = true,
-    };
     QTestState *from, *to, *to2;
 
-    if (migrate_start(&from, &to, "defer", &args)) {
+    args->start.hide_stderr = true;
+
+    if (migrate_start(&from, &to, "defer", &args->start)) {
         return;
     }
 
@@ -621,11 +598,9 @@ static void test_multifd_tcp_cancel(bool postcopy_ram)
      */
     wait_for_migration_status(from, "cancelled", NULL);
 
-    args = (MigrateStart){
-        .only_target = true,
-    };
+    args->start.only_target = true;
 
-    if (migrate_start(&from, &to2, "defer", &args)) {
+    if (migrate_start(&from, &to2, "defer", &args->start)) {
         return;
     }
 
@@ -656,14 +631,14 @@ static void test_multifd_tcp_cancel(bool postcopy_ram)
     migrate_end(from, to2, true);
 }
 
-static void test_multifd_precopy_tcp_cancel(void)
+static void test_multifd_precopy_tcp_cancel(char *name, MigrateCommon *args)
 {
-    test_multifd_tcp_cancel(false);
+    test_multifd_tcp_cancel(args, false);
 }
 
-static void test_multifd_postcopy_tcp_cancel(void)
+static void test_multifd_postcopy_tcp_cancel(char *name, MigrateCommon *args)
 {
-    test_multifd_tcp_cancel(true);
+    test_multifd_tcp_cancel(args, true);
 }
 
 static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
@@ -786,17 +761,15 @@ static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
                               (const char * []) { "completed", NULL });
 }
 
-static void test_cancel_src_after_status(void *opaque)
+static void test_cancel_src_after_status(char *test_path, MigrateCommon *args)
 {
-    const char *test_path = opaque;
     g_autofree char *phase = g_path_get_basename(test_path);
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
     QTestState *from, *to;
-    MigrateStart args = {
-        .hide_stderr = true,
-    };
 
-    if (migrate_start(&from, &to, "defer", &args)) {
+    args->start.hide_stderr = true;
+
+    if (migrate_start(&from, &to, "defer", &args->start)) {
         return;
     }
 
@@ -980,7 +953,7 @@ static void dirtylimit_stop_vm(QTestState *vm)
     unlink(path);
 }
 
-static void test_vcpu_dirty_limit(void)
+static void test_vcpu_dirty_limit(char *name, MigrateCommon *args)
 {
     QTestState *vm;
     int64_t origin_rate;
@@ -1107,7 +1080,7 @@ static void migrate_dirty_limit_wait_showup(QTestState *from,
  * And see if dirty limit migration works correctly.
  * This test case involves many passes, so it runs in slow mode only.
  */
-static void test_dirty_limit(void)
+static void test_dirty_limit(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
     QTestState *from, *to;
@@ -1128,17 +1101,15 @@ static void test_dirty_limit(void)
      */
     const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000;
     int max_try_count = 10;
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-            .use_dirty_ring = true,
-        },
-        .listen_uri = uri,
-        .connect_uri = uri,
-    };
+
+    args->start.hide_stderr = true;
+    args->start.use_dirty_ring = true;
+
+    args->listen_uri = uri;
+    args->connect_uri = uri;
 
     /* Start src, dst vm */
-    if (migrate_start(&from, &to, args.listen_uri, &args.start)) {
+    if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
         return;
     }
 
@@ -1146,7 +1117,7 @@ static void test_dirty_limit(void)
     migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
 
     /* Start migrate */
-    migrate_qmp(from, to, args.connect_uri, NULL, "{}");
+    migrate_qmp(from, to, args->connect_uri, NULL, "{}");
 
     /* Wait for dirty limit throttle begin */
     throttle_us_per_full = 0;
@@ -1179,22 +1150,19 @@ static void test_dirty_limit(void)
     /* Assert dirty limit is not in service */
     g_assert_cmpint(throttle_us_per_full, ==, 0);
 
-    args = (MigrateCommon) {
-        .start = {
-            .only_target = true,
-            .use_dirty_ring = true,
-        },
-        .listen_uri = uri,
-        .connect_uri = uri,
-    };
+    args->listen_uri = uri;
+    args->connect_uri = uri;
+
+    args->start.only_target = true;
+    args->start.use_dirty_ring = true;
 
     /* Restart dst vm, src vm already show up so we needn't wait anymore */
-    if (migrate_start(&from, &to, args.listen_uri, &args.start)) {
+    if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
         return;
     }
 
     /* Start migrate */
-    migrate_qmp(from, to, args.connect_uri, NULL, "{}");
+    migrate_qmp(from, to, args->connect_uri, NULL, "{}");
 
     /* Wait for dirty limit throttle begin */
     throttle_us_per_full = 0;
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index e0e8a7335c..6a20c65104 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -362,149 +362,128 @@ migrate_hook_end_tls_x509(QTestState *from,
 }
 #endif /* CONFIG_TASN1 */
 
-static void test_postcopy_tls_psk(void)
+static void test_postcopy_tls_psk(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start_hook = migrate_hook_start_tls_psk_match,
-        .end_hook = migrate_hook_end_tls_psk,
-    };
+    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->end_hook = migrate_hook_end_tls_psk;
 
-    test_postcopy_common(&args);
+    test_postcopy_common(args);
 }
 
-static void test_postcopy_preempt_tls_psk(void)
+static void test_postcopy_preempt_tls_psk(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start_hook = migrate_hook_start_tls_psk_match,
-        .end_hook = migrate_hook_end_tls_psk,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
-        },
-    };
-
-    test_postcopy_common(&args);
+    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->end_hook = migrate_hook_end_tls_psk;
+
+    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
+
+    test_postcopy_common(args);
 }
 
-static void test_postcopy_recovery_tls_psk(void)
+static void test_postcopy_recovery_tls_psk(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start_hook = migrate_hook_start_tls_psk_match,
-        .end_hook = migrate_hook_end_tls_psk,
-    };
+    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->end_hook = migrate_hook_end_tls_psk;
 
-    test_postcopy_recovery_common(&args);
+    test_postcopy_recovery_common(args);
 }
 
-static void test_multifd_postcopy_recovery_tls_psk(void)
+static void test_multifd_postcopy_recovery_tls_psk(char *name,
+                                                   MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start_hook = migrate_hook_start_tls_psk_match,
-        .end_hook = migrate_hook_end_tls_psk,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-    };
-
-    test_postcopy_recovery_common(&args);
+    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->end_hook = migrate_hook_end_tls_psk;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_postcopy_recovery_common(args);
 }
 
 /* This contains preempt+recovery+tls test altogether */
-static void test_postcopy_preempt_all(void)
+static void test_postcopy_preempt_all(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start_hook = migrate_hook_start_tls_psk_match,
-        .end_hook = migrate_hook_end_tls_psk,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
-        },
-    };
+    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->end_hook = migrate_hook_end_tls_psk;
 
-    test_postcopy_recovery_common(&args);
+    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
+
+    test_postcopy_recovery_common(args);
 }
 
-static void test_multifd_postcopy_preempt_recovery_tls_psk(void)
+static void test_multifd_postcopy_preempt_recovery_tls_psk(char *name,
+                                                           MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start_hook = migrate_hook_start_tls_psk_match,
-        .end_hook = migrate_hook_end_tls_psk,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-            .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true,
-        },
-    };
+    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->end_hook = migrate_hook_end_tls_psk;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
 
-    test_postcopy_recovery_common(&args);
+    test_postcopy_recovery_common(args);
 }
 
-static void test_precopy_unix_tls_psk(void)
+static void test_precopy_unix_tls_psk(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = uri,
-        .start_hook = migrate_hook_start_tls_psk_match,
-        .end_hook = migrate_hook_end_tls_psk,
-    };
 
-    test_precopy_common(&args);
+    args->connect_uri = uri;
+    args->listen_uri = uri;
+    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->end_hook = migrate_hook_end_tls_psk;
+
+    test_precopy_common(args);
 }
 
 #ifdef CONFIG_TASN1
-static void test_precopy_unix_tls_x509_default_host(void)
+static void test_precopy_unix_tls_x509_default_host(char *name,
+                                                    MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-        },
-        .connect_uri = uri,
-        .listen_uri = uri,
-        .start_hook = migrate_hook_start_tls_x509_default_host,
-        .end_hook = migrate_hook_end_tls_x509,
-        .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
-    };
 
-    test_precopy_common(&args);
+    args->connect_uri = uri;
+    args->listen_uri = uri;
+    args->start_hook = migrate_hook_start_tls_x509_default_host;
+    args->end_hook = migrate_hook_end_tls_x509;
+    args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
+
+    args->start.hide_stderr = true;
+
+    test_precopy_common(args);
 }
 
-static void test_precopy_unix_tls_x509_override_host(void)
+static void test_precopy_unix_tls_x509_override_host(char *name,
+                                                     MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = uri,
-        .start_hook = migrate_hook_start_tls_x509_override_host,
-        .end_hook = migrate_hook_end_tls_x509,
-    };
 
-    test_precopy_common(&args);
+    args->connect_uri = uri;
+    args->listen_uri = uri;
+    args->start_hook = migrate_hook_start_tls_x509_override_host;
+    args->end_hook = migrate_hook_end_tls_x509;
+
+    test_precopy_common(args);
 }
 #endif /* CONFIG_TASN1 */
 
-static void test_precopy_tcp_tls_psk_match(void)
+static void test_precopy_tcp_tls_psk_match(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_tls_psk_match,
-        .end_hook = migrate_hook_end_tls_psk,
-    };
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->end_hook = migrate_hook_end_tls_psk;
 
-    test_precopy_common(&args);
+    test_precopy_common(args);
 }
 
-static void test_precopy_tcp_tls_psk_mismatch(void)
+static void test_precopy_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-        },
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_tls_psk_mismatch,
-        .end_hook = migrate_hook_end_tls_psk,
-        .result = MIG_TEST_FAIL,
-    };
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_tls_psk_mismatch;
+    args->end_hook = migrate_hook_end_tls_psk;
+    args->result = MIG_TEST_FAIL;
 
-    test_precopy_common(&args);
+    args->start.hide_stderr = true;
+
+    test_precopy_common(args);
 }
 
 static void *migrate_hook_start_no_tls(QTestState *from, QTestState *to)
@@ -518,15 +497,13 @@ static void *migrate_hook_start_no_tls(QTestState *from, QTestState *to)
     return data;
 }
 
-static void test_precopy_tcp_no_tls(void)
+static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_no_tls,
-        .end_hook = migrate_hook_end_tls_psk,
-    };
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_no_tls;
+    args->end_hook = migrate_hook_end_tls_psk;
 
-    test_precopy_common(&args);
+    test_precopy_common(args);
 }
 
 static void *
@@ -545,107 +522,96 @@ migrate_hook_start_tls_x509_no_host(QTestState *from, QTestState *to)
     return data;
 }
 
-static void test_precopy_tcp_tls_no_hostname(void)
+static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_tls_x509_no_host,
-        .end_hook = migrate_hook_end_tls_x509,
-        .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
-        .start.hide_stderr = true,
-    };
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_tls_x509_no_host;
+    args->end_hook = migrate_hook_end_tls_x509;
+    args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
 
-    test_precopy_common(&args);
+    args->start.hide_stderr = true;
+
+    test_precopy_common(args);
 }
 
 #ifdef CONFIG_TASN1
-static void test_precopy_tcp_tls_x509_default_host(void)
+static void test_precopy_tcp_tls_x509_default_host(char *name,
+                                                   MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_tls_x509_default_host,
-        .end_hook = migrate_hook_end_tls_x509,
-    };
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_tls_x509_default_host;
+    args->end_hook = migrate_hook_end_tls_x509;
 
-    test_precopy_common(&args);
+    test_precopy_common(args);
 }
 
-static void test_precopy_tcp_tls_x509_override_host(void)
+static void test_precopy_tcp_tls_x509_override_host(char *name,
+                                                    MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_tls_x509_override_host,
-        .end_hook = migrate_hook_end_tls_x509,
-    };
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_tls_x509_override_host;
+    args->end_hook = migrate_hook_end_tls_x509;
 
-    test_precopy_common(&args);
+    test_precopy_common(args);
 }
 
-static void test_precopy_tcp_tls_x509_mismatch_host(void)
+static void test_precopy_tcp_tls_x509_mismatch_host(char *name,
+                                                    MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-        },
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_tls_x509_mismatch_host,
-        .end_hook = migrate_hook_end_tls_x509,
-        .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
-    };
-
-    test_precopy_common(&args);
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_tls_x509_mismatch_host;
+    args->end_hook = migrate_hook_end_tls_x509;
+    args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
+
+    args->start.hide_stderr = true;
+
+    test_precopy_common(args);
 }
 
-static void test_precopy_tcp_tls_x509_friendly_client(void)
+static void test_precopy_tcp_tls_x509_friendly_client(char *name,
+                                                      MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_tls_x509_friendly_client,
-        .end_hook = migrate_hook_end_tls_x509,
-    };
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_tls_x509_friendly_client;
+    args->end_hook = migrate_hook_end_tls_x509;
 
-    test_precopy_common(&args);
+    test_precopy_common(args);
 }
 
-static void test_precopy_tcp_tls_x509_hostile_client(void)
+static void test_precopy_tcp_tls_x509_hostile_client(char *name,
+                                                     MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-        },
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_tls_x509_hostile_client,
-        .end_hook = migrate_hook_end_tls_x509,
-        .result = MIG_TEST_FAIL,
-    };
-
-    test_precopy_common(&args);
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_tls_x509_hostile_client;
+    args->end_hook = migrate_hook_end_tls_x509;
+    args->result = MIG_TEST_FAIL;
+
+    args->start.hide_stderr = true;
+
+    test_precopy_common(args);
 }
 
-static void test_precopy_tcp_tls_x509_allow_anon_client(void)
+static void test_precopy_tcp_tls_x509_allow_anon_client(char *name,
+                                                        MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_tls_x509_allow_anon_client,
-        .end_hook = migrate_hook_end_tls_x509,
-    };
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_tls_x509_allow_anon_client;
+    args->end_hook = migrate_hook_end_tls_x509;
 
-    test_precopy_common(&args);
+    test_precopy_common(args);
 }
 
-static void test_precopy_tcp_tls_x509_reject_anon_client(void)
+static void test_precopy_tcp_tls_x509_reject_anon_client(char *name,
+                                                         MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-        },
-        .listen_uri = "tcp:127.0.0.1:0",
-        .start_hook = migrate_hook_start_tls_x509_reject_anon_client,
-        .end_hook = migrate_hook_end_tls_x509,
-        .result = MIG_TEST_FAIL,
-    };
-
-    test_precopy_common(&args);
+    args->listen_uri = "tcp:127.0.0.1:0";
+    args->start_hook = migrate_hook_start_tls_x509_reject_anon_client;
+    args->end_hook = migrate_hook_end_tls_x509;
+    args->result = MIG_TEST_FAIL;
+
+    args->start.hide_stderr = true;
+
+    test_precopy_common(args);
 }
 #endif /* CONFIG_TASN1 */
 
@@ -707,77 +673,70 @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
 }
 #endif /* CONFIG_TASN1 */
 
-static void test_multifd_tcp_tls_psk_match(void)
+static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_tcp_tls_psk_match,
-        .end_hook = migrate_hook_end_tls_psk,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
+    args->end_hook = migrate_hook_end_tls_psk;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
-static void test_multifd_tcp_tls_psk_mismatch(void)
+static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch,
-        .end_hook = migrate_hook_end_tls_psk,
-        .result = MIG_TEST_FAIL,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
+    args->end_hook = migrate_hook_end_tls_psk;
+    args->result = MIG_TEST_FAIL;
+
+    args->start.hide_stderr = true;
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
-static void test_multifd_postcopy_tcp_tls_psk_match(void)
+static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
+                                                    MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-            .caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true,
-        },
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_tcp_tls_psk_match,
-        .end_hook = migrate_hook_end_tls_psk,
-    };
-
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
+    args->end_hook = migrate_hook_end_tls_psk;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
+
+    test_precopy_common(args);
 }
 
 #ifdef CONFIG_TASN1
-static void test_multifd_tcp_tls_x509_default_host(void)
+static void test_multifd_tcp_tls_x509_default_host(char *name,
+                                                   MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_tls_x509_default_host,
-        .end_hook = migrate_hook_end_tls_x509,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
+    args->end_hook = migrate_hook_end_tls_x509;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
-static void test_multifd_tcp_tls_x509_override_host(void)
+static void test_multifd_tcp_tls_x509_override_host(char *name,
+                                                    MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_tls_x509_override_host,
-        .end_hook = migrate_hook_end_tls_x509,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
+    args->end_hook = migrate_hook_end_tls_x509;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
-static void test_multifd_tcp_tls_x509_mismatch_host(void)
+static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
+                                                    MigrateCommon *args)
 {
     /*
      * This has different behaviour to the non-multifd case.
@@ -792,45 +751,41 @@ static void test_multifd_tcp_tls_x509_mismatch_host(void)
      * to load migration state, and thus just aborts the migration
      * without exiting.
      */
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host,
-        .end_hook = migrate_hook_end_tls_x509,
-        .result = MIG_TEST_FAIL,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
+    args->end_hook = migrate_hook_end_tls_x509;
+    args->result = MIG_TEST_FAIL;
+
+    args->start.hide_stderr = true;
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
-static void test_multifd_tcp_tls_x509_allow_anon_client(void)
+static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
+                                                        MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client,
-        .end_hook = migrate_hook_end_tls_x509,
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
+    args->end_hook = migrate_hook_end_tls_x509;
+
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 
-static void test_multifd_tcp_tls_x509_reject_anon_client(void)
+static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
+                                                         MigrateCommon *args)
 {
-    MigrateCommon args = {
-        .start = {
-            .hide_stderr = true,
-            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
-        },
-        .listen_uri = "defer",
-        .start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client,
-        .end_hook = migrate_hook_end_tls_x509,
-        .result = MIG_TEST_FAIL,
-    };
-    test_precopy_common(&args);
+    args->listen_uri = "defer";
+    args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
+    args->end_hook = migrate_hook_end_tls_x509;
+    args->result = MIG_TEST_FAIL;
+
+    args->start.hide_stderr = true;
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    test_precopy_common(args);
 }
 #endif /* CONFIG_TASN1 */
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 26/51] tests/qtest/migration: Pass MigrateStart into cancel tests
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (24 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 25/51] tests/qtest/migration: Pass MigrateCommon into test functions Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-16 21:57   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 27/51] tests/qtest/migration: Fix misuse of listen_uri Fabiano Rosas
                   ` (25 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Pass the "args" parameter to the cancel tests so they can access the
config object which will be part of this struct.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/precopy-tests.c | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index 086d06a31c..aca7ed51ef 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -642,7 +642,8 @@ static void test_multifd_postcopy_tcp_cancel(char *name, MigrateCommon *args)
 }
 
 static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
-                                         const char *uri, const char *phase)
+                                         const char *uri, const char *phase,
+                                         MigrateStart *args)
 {
     /*
      * No migrate_incoming_qmp() at the start to force source into
@@ -669,7 +670,8 @@ static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
 }
 
 static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
-                                            const char *uri, const char *phase)
+                                            const char *uri, const char *phase,
+                                            MigrateStart *args)
 {
     migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
 
@@ -693,7 +695,8 @@ static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
 }
 
 static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
-                                           const char *uri, const char *phase)
+                                           const char *uri, const char *phase,
+                                           MigrateStart *args)
 {
     migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
 
@@ -714,7 +717,8 @@ static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
 }
 
 static void test_cancel_src_after_none(QTestState *from, QTestState *to,
-                                       const char *uri, const char *phase)
+                                       const char *uri, const char *phase,
+                                       MigrateStart *args)
 {
     /*
      * Test that cancelling without a migration happening does not
@@ -735,7 +739,8 @@ static void test_cancel_src_after_none(QTestState *from, QTestState *to,
 }
 
 static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
-                                           const char *uri, const char *phase)
+                                           const char *uri, const char *phase,
+                                           MigrateStart *args)
 {
     migrate_set_capability(from, "pause-before-switchover", true);
     migrate_set_capability(to, "pause-before-switchover", true);
@@ -775,20 +780,20 @@ static void test_cancel_src_after_status(char *test_path, MigrateCommon *args)
 
     if (g_str_equal(phase, "cancelling") ||
         g_str_equal(phase, "cancelled")) {
-        test_cancel_src_after_cancelled(from, to, uri, phase);
+        test_cancel_src_after_cancelled(from, to, uri, phase, &args->start);
 
     } else if (g_str_equal(phase, "completed")) {
-        test_cancel_src_after_complete(from, to, uri, phase);
+        test_cancel_src_after_complete(from, to, uri, phase, &args->start);
 
     } else if (g_str_equal(phase, "failed")) {
-        test_cancel_src_after_failed(from, to, uri, phase);
+        test_cancel_src_after_failed(from, to, uri, phase, &args->start);
 
     } else if (g_str_equal(phase, "none")) {
-        test_cancel_src_after_none(from, to, uri, phase);
+        test_cancel_src_after_none(from, to, uri, phase, &args->start);
 
     } else {
         /* any state that comes before pre-switchover */
-        test_cancel_src_pre_switchover(from, to, uri, phase);
+        test_cancel_src_pre_switchover(from, to, uri, phase, &args->start);
     }
 
     migrate_end(from, to, false);
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 27/51] tests/qtest/migration: Fix misuse of listen_uri
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (25 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 26/51] tests/qtest/migration: Pass MigrateStart into cancel tests Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-17 15:30   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 28/51] tests/qtest/migration: Stop invoking migrate_incoming from hooks Fabiano Rosas
                   ` (24 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

The listen_uri parameter is supposed to be used for the incoming
migration while connect_uri for the outgoing migration. This is well
documented in the header file.

However, due to -incoming "defer", some tests set listen-uri =
"defer", which is fine. But then, being without another parameter to
define the uri to be use in migrate_incoming, some tests have been
misusing connect_uri.

Add a separate flag to denote "defer" and spare the tests from passing
the string. Change the usage of listen_uri to it's original purpose.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/compression-tests.c | 12 +++----
 tests/qtest/migration/cpr-tests.c         | 17 +++++++---
 tests/qtest/migration/file-tests.c        | 38 ++++++++++++++++-------
 tests/qtest/migration/framework.c         | 12 +++----
 tests/qtest/migration/framework.h         |  7 +++++
 tests/qtest/migration/misc-tests.c        |  4 +--
 tests/qtest/migration/precopy-tests.c     | 26 ++++++++++------
 tests/qtest/migration/tls-tests.c         | 16 +++++-----
 8 files changed, 85 insertions(+), 47 deletions(-)

diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
index 845e622cd5..eb0b7d6b4b 100644
--- a/tests/qtest/migration/compression-tests.c
+++ b/tests/qtest/migration/compression-tests.c
@@ -33,9 +33,9 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
 
 static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -43,9 +43,9 @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
 
 static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
     args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
 
@@ -66,9 +66,9 @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
 
 static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -85,9 +85,9 @@ migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
 
 static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -104,9 +104,9 @@ migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
 
 static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -156,9 +156,9 @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
 
 static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
index 0d97b5b89f..7456337370 100644
--- a/tests/qtest/migration/cpr-tests.c
+++ b/tests/qtest/migration/cpr-tests.c
@@ -32,10 +32,11 @@ static void test_mode_reboot(char *name, MigrateCommon *args)
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
 
+    args->listen_uri = uri;
     args->connect_uri = uri;
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_mode_reboot;
 
+    args->start.incoming_defer = true;
     args->start.mem_type = MEM_TYPE_SHMEM;
     args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
 
@@ -53,7 +54,7 @@ static void *test_mode_transfer_start(QTestState *from, QTestState *to)
  * migration, and cannot connect synchronously to the monitor, so defer
  * the target connection.
  */
-static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer)
+static void test_mode_transfer_common(MigrateCommon *args)
 {
     g_autofree char *cpr_path = g_strdup_printf("%s/cpr.sock", tmpfs);
     g_autofree char *mig_path = g_strdup_printf("%s/migsocket", tmpfs);
@@ -84,7 +85,11 @@ static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer)
                                   "addr.type=fd,addr.str=%d %s",
                                   cpr_sockfd, opts);
 
-    args->listen_uri = incoming_defer ? "defer" : uri;
+    /*
+     * The URI is used only for the deferred target connection when
+     * !incoming_defer.
+     */
+    args->listen_uri = uri;
     args->connect_channels = connect_channels;
     args->cpr_channel = cpr_channel;
     args->start_hook = test_mode_transfer_start;
@@ -102,12 +107,14 @@ static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer)
 
 static void test_mode_transfer(char *name, MigrateCommon *args)
 {
-    test_mode_transfer_common(args, false);
+    args->start.incoming_defer = false;
+    test_mode_transfer_common(args);
 }
 
 static void test_mode_transfer_defer(char *name, MigrateCommon *args)
 {
-    test_mode_transfer_common(args, true);
+    args->start.incoming_defer = true;
+    test_mode_transfer_common(args);
 }
 
 static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
index 5f1159076c..57117b2496 100644
--- a/tests/qtest/migration/file-tests.c
+++ b/tests/qtest/migration/file-tests.c
@@ -25,7 +25,9 @@ static void test_precopy_file(char *name, MigrateCommon *args)
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
+
+    args->start.incoming_defer = true;
 
     test_file_common(args, true);
 }
@@ -69,9 +71,11 @@ static void test_precopy_file_offset_fdset(char *name, MigrateCommon *args)
     g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
                                            FILE_TEST_OFFSET);
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
     args->start_hook = migrate_hook_start_file_offset_fdset;
 
+    args->start.incoming_defer = true;
+
     test_file_common(args, false);
 }
 #endif
@@ -83,7 +87,9 @@ static void test_precopy_file_offset(char *name, MigrateCommon *args)
                                            FILE_TEST_OFFSET);
 
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
+
+    args->start.incoming_defer = true;
 
     test_file_common(args, false);
 }
@@ -95,9 +101,11 @@ static void test_precopy_file_offset_bad(char *name, MigrateCommon *args)
                                            tmpfs, FILE_TEST_FILENAME);
 
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
     args->result = MIG_TEST_QMP_ERROR;
 
+    args->start.incoming_defer = true;
+
     test_file_common(args, false);
 }
 
@@ -107,8 +115,9 @@ static void test_precopy_file_mapped_ram_live(char *name, MigrateCommon *args)
                                            FILE_TEST_FILENAME);
 
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
 
     test_file_common(args, false);
@@ -120,8 +129,9 @@ static void test_precopy_file_mapped_ram(char *name, MigrateCommon *args)
                                            FILE_TEST_FILENAME);
 
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
 
     test_file_common(args, true);
@@ -132,8 +142,9 @@ static void test_multifd_file_mapped_ram_live(char *name, MigrateCommon *args)
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
     args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
 
@@ -146,8 +157,9 @@ static void test_multifd_file_mapped_ram(char *name, MigrateCommon *args)
                                            FILE_TEST_FILENAME);
 
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
     args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
 
@@ -168,9 +180,10 @@ static void test_multifd_file_mapped_ram_dio(char *name, MigrateCommon *args)
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
     args->start_hook = migrate_hook_start_multifd_mapped_ram_dio;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
@@ -240,10 +253,11 @@ static void test_multifd_file_mapped_ram_fdset(char *name, MigrateCommon *args)
                                            FILE_TEST_OFFSET);
 
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
     args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset;
     args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
@@ -255,11 +269,13 @@ static void test_multifd_file_mapped_ram_fdset_dio(char *name,
 {
     g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
                                            FILE_TEST_OFFSET);
+
     args->connect_uri = uri;
-    args->listen_uri = "defer";
+    args->listen_uri = uri;
     args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio;
     args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index e35839c95f..e811945122 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -414,7 +414,8 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
                                  "%s %s %s %s",
                                  kvm_opts ? kvm_opts : "",
                                  machine, machine_opts,
-                                 memory_backend, tmpfs, uri,
+                                 memory_backend, tmpfs,
+                                 args->incoming_defer ? "defer" : uri,
                                  events,
                                  arch_opts ? arch_opts : "",
                                  args->opts_target ? args->opts_target : "",
@@ -856,8 +857,7 @@ int test_precopy_common(MigrateCommon *args)
      * migrate-incoming channels.
      */
     if (args->connect_channels) {
-        if (args->start.defer_target_connect &&
-            !strcmp(args->listen_uri, "defer")) {
+        if (args->start.defer_target_connect && args->start.incoming_defer) {
             in_channels = qobject_from_json(args->connect_channels,
                                             &error_abort);
         }
@@ -881,8 +881,8 @@ int test_precopy_common(MigrateCommon *args)
     if (args->start.defer_target_connect) {
         qtest_connect(to);
         qtest_qmp_handshake(to, NULL);
-        if (!strcmp(args->listen_uri, "defer")) {
-            migrate_incoming_qmp(to, args->connect_uri, in_channels, "{}");
+        if (args->start.incoming_defer) {
+            migrate_incoming_qmp(to, NULL, in_channels, "{}");
         }
     }
 
@@ -1031,7 +1031,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
      * We need to wait for the source to finish before starting the
      * destination.
      */
-    migrate_incoming_qmp(to, args->connect_uri, NULL, "{}");
+    migrate_incoming_qmp(to, args->listen_uri, NULL, "{}");
     wait_for_migration_complete(to);
 
     if (stop_src) {
diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
index ed85ed502d..bf3492a59e 100644
--- a/tests/qtest/migration/framework.h
+++ b/tests/qtest/migration/framework.h
@@ -144,6 +144,13 @@ typedef struct {
      * migration_set_capabilities().
      */
     bool caps[MIGRATION_CAPABILITY__MAX];
+
+    /*
+     * Whether to use "defer" as the uri for the -incoming command
+     * line option. If set to true, MigrateCommon.listen_uri will be
+     * used for the deferred migrate_incoming call.
+     */
+    bool incoming_defer;
 } MigrateStart;
 
 typedef enum PostcopyRecoveryFailStage {
diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
index 810e9e6549..61bdfda857 100644
--- a/tests/qtest/migration/misc-tests.c
+++ b/tests/qtest/migration/misc-tests.c
@@ -217,7 +217,6 @@ static void do_test_validate_uri_channel(MigrateCommon *args)
 
 static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer",
     args->connect_uri = "tcp:127.0.0.1:0",
     args->connect_channels = ("[ { ""'channel-type': 'main',"
                               "    'addr': { 'transport': 'socket',"
@@ -225,6 +224,7 @@ static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
                               "              'host': '127.0.0.1',"
                               "              'port': '0' } } ]"),
 
+    args->start.incoming_defer = true;
     args->start.hide_stderr = true;
 
     do_test_validate_uri_channel(args);
@@ -232,8 +232,8 @@ static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
 
 static void test_validate_uri_channels_none_set(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start.hide_stderr = true;
+    args->start.incoming_defer = true;
 
     do_test_validate_uri_channel(args);
 }
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index aca7ed51ef..d9c463dd0f 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -282,11 +282,12 @@ static void migrate_hook_end_fd(QTestState *from,
 
 static void test_precopy_fd_socket(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->connect_uri = "fd:fd-mig";
     args->start_hook = migrate_hook_start_fd;
     args->end_hook = migrate_hook_end_fd;
 
+    args->start.incoming_defer = true;
+
     test_precopy_common(args);
 }
 
@@ -321,11 +322,13 @@ static void *migrate_hook_start_precopy_fd_file(QTestState *from,
 
 static void test_precopy_fd_file(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
+    args->listen_uri = "fd:fd-mig";
     args->connect_uri = "fd:fd-mig";
     args->start_hook = migrate_hook_start_precopy_fd_file;
     args->end_hook = migrate_hook_end_fd;
 
+    args->start.incoming_defer = true;
+
     test_file_common(args, true);
 }
 #endif /* _WIN32 */
@@ -474,7 +477,6 @@ migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from,
 
 static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd;
     /*
      * Multifd is more complicated than most of the features, it
@@ -483,6 +485,7 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
      */
     args->live = true;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -490,7 +493,6 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
 
 static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy;
     /*
      * Multifd is more complicated than most of the features, it
@@ -499,6 +501,7 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
      */
     args->live = true;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -506,7 +509,6 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
 
 static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page;
     /*
      * Multifd is more complicated than most of the features, it
@@ -515,6 +517,7 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
      */
     args->live = true;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -522,15 +525,15 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
 
 static void test_multifd_tcp_channels_none(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd;
     args->live = true;
     args->connect_channels = ("[ { 'channel-type': 'main',"
-                             "    'addr': { 'transport': 'socket',"
-                             "              'type': 'inet',"
-                             "              'host': '127.0.0.1',"
+                              "    'addr': { 'transport': 'socket',"
+                              "              'type': 'inet',"
+                              "              'host': '127.0.0.1',"
                               "              'port': '0' } } ]");
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -552,6 +555,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
     QTestState *from, *to, *to2;
 
     args->start.hide_stderr = true;
+    args->start.incoming_defer = true;
 
     if (migrate_start(&from, &to, "defer", &args->start)) {
         return;
@@ -599,6 +603,9 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
     wait_for_migration_status(from, "cancelled", NULL);
 
     args->start.only_target = true;
+    args->start.incoming_defer = true;
+
+    /* reusing the same config for to2 */
 
     if (migrate_start(&from, &to2, "defer", &args->start)) {
         return;
@@ -773,6 +780,7 @@ static void test_cancel_src_after_status(char *test_path, MigrateCommon *args)
     QTestState *from, *to;
 
     args->start.hide_stderr = true;
+    args->start.incoming_defer = true;
 
     if (migrate_start(&from, &to, "defer", &args->start)) {
         return;
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 6a20c65104..166f27f478 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -675,10 +675,10 @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
 
 static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -686,12 +686,12 @@ static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
 
 static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
     args->end_hook = migrate_hook_end_tls_psk;
     args->result = MIG_TEST_FAIL;
 
     args->start.hide_stderr = true;
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -700,10 +700,10 @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
 static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
                                                     MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
     args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
 
@@ -714,10 +714,10 @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
 static void test_multifd_tcp_tls_x509_default_host(char *name,
                                                    MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
     args->end_hook = migrate_hook_end_tls_x509;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -726,10 +726,10 @@ static void test_multifd_tcp_tls_x509_default_host(char *name,
 static void test_multifd_tcp_tls_x509_override_host(char *name,
                                                     MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
     args->end_hook = migrate_hook_end_tls_x509;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -751,11 +751,11 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
      * to load migration state, and thus just aborts the migration
      * without exiting.
      */
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
     args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL;
 
+    args->start.incoming_defer = true;
     args->start.hide_stderr = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
@@ -765,10 +765,10 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
 static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
                                                         MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
     args->end_hook = migrate_hook_end_tls_x509;
 
+    args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     test_precopy_common(args);
@@ -777,11 +777,11 @@ static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
 static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
                                                          MigrateCommon *args)
 {
-    args->listen_uri = "defer";
     args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
     args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL;
 
+    args->start.incoming_defer = true;
     args->start.hide_stderr = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 28/51] tests/qtest/migration: Stop invoking migrate_incoming from hooks
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (26 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 27/51] tests/qtest/migration: Fix misuse of listen_uri Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-17 20:26   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 29/51] tests/qtest/migration: Add config QDict Fabiano Rosas
                   ` (23 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Now that the listen_uri is being properly used, tests can stop calling
migrate_incoming from their hooks. The _common functions and
migrate_start should take care of that.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/compression-tests.c |  6 ++++++
 tests/qtest/migration/framework.c         | 14 +++++++++++---
 tests/qtest/migration/precopy-tests.c     |  7 ++++---
 tests/qtest/migration/tls-tests.c         |  8 ++++++++
 4 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
index eb0b7d6b4b..bed39dece0 100644
--- a/tests/qtest/migration/compression-tests.c
+++ b/tests/qtest/migration/compression-tests.c
@@ -33,6 +33,7 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
 
 static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
 {
+    args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
 
     args->start.incoming_defer = true;
@@ -43,6 +44,7 @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
 
 static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
 {
+    args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
 
     args->start.incoming_defer = true;
@@ -66,6 +68,7 @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
 
 static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
 {
+    args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip;
 
     args->start.incoming_defer = true;
@@ -85,6 +88,7 @@ migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
 
 static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
 {
+    args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl;
 
     args->start.incoming_defer = true;
@@ -104,6 +108,7 @@ migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
 
 static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
 {
+    args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk;
 
     args->start.incoming_defer = true;
@@ -156,6 +161,7 @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
 
 static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
 {
+    args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib;
 
     args->start.incoming_defer = true;
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index e811945122..199e439263 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -820,6 +820,9 @@ int test_precopy_common(MigrateCommon *args)
     QObject *out_channels = NULL;
 
     g_assert(!args->cpr_channel || args->connect_channels);
+    if (args->start.incoming_defer) {
+        g_assert(args->listen_uri || args->connect_channels);
+    }
 
     if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
         return -1;
@@ -829,6 +832,14 @@ int test_precopy_common(MigrateCommon *args)
         data_hook = args->start_hook(from, to);
     }
 
+    if (args->start.incoming_defer && !args->start.defer_target_connect) {
+        if (args->connect_channels) {
+            in_channels = qobject_from_json(args->connect_channels,
+                                            &error_abort);
+        }
+        migrate_incoming_qmp(to, args->listen_uri, in_channels, "{}");
+    }
+
     /* Wait for the first serial output from the source */
     if (args->result == MIG_TEST_SUCCEED) {
         wait_for_serial("src_serial");
@@ -1060,9 +1071,6 @@ void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from,
     migrate_set_parameter_str(from, "multifd-compression", method);
     migrate_set_parameter_str(to, "multifd-compression", method);
 
-    /* Start incoming migration from the 1st socket */
-    migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
-
     return NULL;
 }
 
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index d9c463dd0f..ab5789717f 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -239,9 +239,6 @@ static void *migrate_hook_start_fd(QTestState *from,
                                  "  'arguments': { 'fdname': 'fd-mig' }}");
     close(pair[0]);
 
-    /* Start incoming migration from the 1st socket */
-    migrate_incoming_qmp(to, "fd:fd-mig", NULL, "{}");
-
     /* Send the 2nd socket to the target */
     qtest_qmp_fds_assert_success(from, &pair[1], 1,
                                  "{ 'execute': 'getfd',"
@@ -283,6 +280,7 @@ static void migrate_hook_end_fd(QTestState *from,
 static void test_precopy_fd_socket(char *name, MigrateCommon *args)
 {
     args->connect_uri = "fd:fd-mig";
+    args->listen_uri = "fd:fd-mig";
     args->start_hook = migrate_hook_start_fd;
     args->end_hook = migrate_hook_end_fd;
 
@@ -484,6 +482,7 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
      * everything will work alright even if guest page is changing.
      */
     args->live = true;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -500,6 +499,7 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
      * everything will work alright even if guest page is changing.
      */
     args->live = true;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -516,6 +516,7 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
      * everything will work alright even if guest page is changing.
      */
     args->live = true;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 166f27f478..f63f37132a 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -677,6 +677,7 @@ static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
 {
     args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -689,6 +690,7 @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
     args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
     args->end_hook = migrate_hook_end_tls_psk;
     args->result = MIG_TEST_FAIL;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.hide_stderr = true;
     args->start.incoming_defer = true;
@@ -702,6 +704,7 @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
 {
     args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -716,6 +719,7 @@ static void test_multifd_tcp_tls_x509_default_host(char *name,
 {
     args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
     args->end_hook = migrate_hook_end_tls_x509;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -728,6 +732,7 @@ static void test_multifd_tcp_tls_x509_override_host(char *name,
 {
     args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
     args->end_hook = migrate_hook_end_tls_x509;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -754,6 +759,7 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
     args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
     args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.hide_stderr = true;
@@ -767,6 +773,7 @@ static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
 {
     args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
     args->end_hook = migrate_hook_end_tls_x509;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -780,6 +787,7 @@ static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
     args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
     args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL;
+    args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.hide_stderr = true;
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 29/51] tests/qtest/migration: Add config QDict
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (27 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 28/51] tests/qtest/migration: Stop invoking migrate_incoming from hooks Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-17 20:27   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 30/51] tests/qtest/migration: Add temporary code to toggle usage of config Fabiano Rosas
                   ` (22 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Add the config object to the MigrateCommon structure and allocate/free
it in the wrappers that are used when dispatched every migration test.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/framework.h      | 2 ++
 tests/qtest/migration/migration-util.c | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
index bf3492a59e..65c656e0d3 100644
--- a/tests/qtest/migration/framework.h
+++ b/tests/qtest/migration/framework.h
@@ -151,6 +151,8 @@ typedef struct {
      * used for the deferred migrate_incoming call.
      */
     bool incoming_defer;
+
+    QDict *config;
 } MigrateStart;
 
 typedef enum PostcopyRecoveryFailStage {
diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
index c2462306a1..416dd10ef8 100644
--- a/tests/qtest/migration/migration-util.c
+++ b/tests/qtest/migration/migration-util.c
@@ -243,6 +243,7 @@ static void migration_test_destroy(gpointer data)
 {
     MigrationTest *test = (MigrationTest *)data;
 
+    qdict_unref(test->data->start.config);
     g_free(test->data);
     g_free(test->name);
     g_free(test);
@@ -253,6 +254,7 @@ static void migration_test_wrapper(const void *data)
     MigrationTest *test = (MigrationTest *)data;
 
     test->data = g_new0(MigrateCommon, 1);
+    test->data->start.config = qdict_new();
 
     g_test_message("Running /%s%s", qtest_get_arch(), test->name);
     test->func(test->name, test->data);
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 30/51] tests/qtest/migration: Add temporary code to toggle usage of config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (28 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 29/51] tests/qtest/migration: Add config QDict Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-18 17:34   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 31/51] tests/qtest/migration: Add a function for default capabilities Fabiano Rosas
                   ` (21 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

The tests are being refactored to pass migration options to QEMU using
the new API of passing a JSON object as argument the migration
commands instead of using several calls to the
migrate_set_capabilities|parameters commands.

Since multiple tests share common infrastructure (framework.c,
migration-utils.c, migration-qmp.c), it's cumbersome to convert tests
in small chunks, which would require changes to every common function
to accept both the new and old ways.

After some tinkering, an easier way to do this transition is to allow
the tests to set a key in the config dict itself telling whether the
config is supported. With this, the common functions can be fully
altered to support the config object, as long as they check this
temporary key and do the right thing.

QEMU doesn't know about this hack, so some code is needed to hide it
when issuing QMP commands with the config object.

This will all be removed once tests are fully converted.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/migration-qmp.h  |  1 -
 tests/qtest/migration/migration-util.c |  1 +
 tests/qtest/migration/migration-util.h | 34 ++++++++++++++++++++++++++
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
index 940ffd5950..9a36a677ba 100644
--- a/tests/qtest/migration/migration-qmp.h
+++ b/tests/qtest/migration/migration-qmp.h
@@ -47,5 +47,4 @@ void migrate_recover(QTestState *who, const char *uri);
 void migrate_cancel(QTestState *who);
 void migrate_postcopy_start(QTestState *from, QTestState *to,
                             QTestMigrationState *src_state);
-
 #endif /* MIGRATION_QMP_H */
diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
index 416dd10ef8..e702f00896 100644
--- a/tests/qtest/migration/migration-util.c
+++ b/tests/qtest/migration/migration-util.c
@@ -255,6 +255,7 @@ static void migration_test_wrapper(const void *data)
 
     test->data = g_new0(MigrateCommon, 1);
     test->data->start.config = qdict_new();
+    qdict_put_bool(test->data->start.config, "use-config", false);
 
     g_test_message("Running /%s%s", qtest_get_arch(), test->name);
     test->func(test->name, test->data);
diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
index e73d69bab0..3c3b5a8777 100644
--- a/tests/qtest/migration/migration-util.h
+++ b/tests/qtest/migration/migration-util.h
@@ -60,4 +60,38 @@ void migration_test_add_suffix(const char *path, const char *suffix,
 char *migrate_get_connect_uri(QTestState *who);
 void migrate_set_ports(QTestState *to, QList *channel_list);
 
+/*
+ * Scaffolding to allow the framework _common functions and _qmp
+ * functions to use the config object while some tests are still using
+ * migrate_set_*. Tests that have been converted will set use-config =
+ * true on the config dict.
+ */
+static bool has_key;
+static bool use_config;
+static inline QDict *config_load(QDict *config)
+{
+    if (!config) {
+        return NULL;
+    }
+
+    has_key = qdict_haskey(config, "use-config");
+    if (has_key) {
+        use_config = qdict_get_try_bool(config, "use-config", false);
+        qdict_del(config, "use-config");
+    }
+
+    if (use_config) {
+        return config;
+    }
+
+    return NULL;
+}
+
+static inline void config_put(QDict *config)
+{
+    if (config && has_key) {
+        qdict_put_bool(config, "use-config", use_config);
+    }
+}
+
 #endif /* MIGRATION_UTIL_H */
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 31/51] tests/qtest/migration: Add a function for default capabilities
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (29 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 30/51] tests/qtest/migration: Add temporary code to toggle usage of config Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 32/51] tests/qtest/migration: Adapt convergence routines to config Fabiano Rosas
                   ` (20 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Add a helper to set the config object with default capabilities such
as 'events' which are needed by the tests.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/framework.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 199e439263..fd15bd832e 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -208,6 +208,29 @@ static QList *migrate_start_get_qmp_capabilities(const MigrateStart *args)
     return capabilities;
 }
 
+static void migrate_start_set_default_options(MigrateStart *args)
+{
+    if (args->config && qdict_get_bool(args->config, "use-config")) {
+        /*
+         * Always enable migration events. Libvirt always uses it,
+         * let's mimic that.
+         */
+        qdict_put_bool(args->config, "events", true);
+
+        /*
+         * Default number of channels should be fine for most
+         * tests. Individual tests can override by calling
+         * migrate_set_parameter() directly.
+         */
+        if (qdict_get_try_bool(args->config, "multifd", false)) {
+            qdict_put_int(args->config, "multifd-channels",
+                          MULTIFD_TEST_CHANNELS);
+        }
+
+        return;
+    }
+}
+
 static void migrate_start_set_capabilities(QTestState *from, QTestState *to,
                                            MigrateStart *args)
 {
@@ -469,6 +492,8 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
     g_autofree gchar *cmd_target = NULL;
     g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
 
+    migrate_start_set_default_options(args);
+
     if (!migrate_mem_type_prepare(args->mem_type)) {
         return -1;
     }
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 32/51] tests/qtest/migration: Adapt convergence routines to config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (30 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 31/51] tests/qtest/migration: Add a function for default capabilities Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-18 17:25   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 33/51] tests/qtest/migration: Adapt the incoming cmdline for config passing Fabiano Rosas
                   ` (19 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Adapt the convergence routines migrate_ensure_[non_]converge to set
the convergence parameters in the config dict it instead of using
migrate-set-parameters.

Some tests need to change the convergence parameters during the
migration. The config object method is specific to configuration prior
to starting a migration, so by design it's not suitable to effect
migration-runtime changes. The existing routines will be kept for this
purpose (renamed with 'ongoing' for clarity).

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/framework.c     | 10 ++++-----
 tests/qtest/migration/migration-qmp.c | 32 +++++++++++++++++++++++++--
 tests/qtest/migration/migration-qmp.h |  6 +++--
 tests/qtest/migration/misc-tests.c    |  4 ++--
 tests/qtest/migration/precopy-tests.c | 26 +++++++++-------------
 5 files changed, 52 insertions(+), 26 deletions(-)

diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index fd15bd832e..df42a8a2c6 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -583,7 +583,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
         args->postcopy_data = args->start_hook(from, to);
     }
 
-    migrate_ensure_non_converge(from);
+    migrate_ensure_non_converge(from, args->start.config);
     migrate_prepare_for_dirty_mem(from);
     qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
                              "  'arguments': { "
@@ -872,7 +872,7 @@ int test_precopy_common(MigrateCommon *args)
     }
 
     if (args->live) {
-        migrate_ensure_non_converge(from);
+        migrate_ensure_non_converge(from, args->start.config);
         migrate_prepare_for_dirty_mem(from);
     } else {
         /*
@@ -884,7 +884,7 @@ int test_precopy_common(MigrateCommon *args)
         if (args->result == MIG_TEST_SUCCEED) {
             qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
             wait_for_stop(from, &src_state);
-            migrate_ensure_converge(from);
+            migrate_ongoing_ensure_converge(from);
         }
     }
 
@@ -942,7 +942,7 @@ int test_precopy_common(MigrateCommon *args)
             }
             migrate_wait_for_dirty_mem(from, to);
 
-            migrate_ensure_converge(from);
+            migrate_ongoing_ensure_converge(from);
 
             /*
              * We do this first, as it has a timeout to stop us
@@ -1047,7 +1047,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
         data_hook = args->start_hook(from, to);
     }
 
-    migrate_ensure_converge(from);
+    migrate_ensure_converge(from, args->start.config);
     wait_for_serial("src_serial");
 
     if (stop_src) {
diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
index 5c46ceb3e6..7fe47a5793 100644
--- a/tests/qtest/migration/migration-qmp.c
+++ b/tests/qtest/migration/migration-qmp.c
@@ -499,20 +499,48 @@ void migrate_set_parameter_bool(QTestState *who, const char *parameter,
     migrate_check_parameter_bool(who, parameter, value);
 }
 
-void migrate_ensure_non_converge(QTestState *who)
+void migrate_ongoing_ensure_non_converge(QTestState *who)
 {
     /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
     migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
     migrate_set_parameter_int(who, "downtime-limit", 1);
 }
 
-void migrate_ensure_converge(QTestState *who)
+void migrate_ongoing_ensure_converge(QTestState *who)
 {
     /* Should converge with 30s downtime + 1 gbs bandwidth limit */
     migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
     migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
 }
 
+void migrate_ensure_non_converge(QTestState *who, QDict *config)
+{
+    config = config_load(config);
+    if (config) {
+        /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
+        qdict_put_int(config, "max-bandwidth", 3 * 1000 * 1000);
+        qdict_put_int(config, "downtime-limit", 1);
+    } else {
+        assert(who);
+        migrate_ongoing_ensure_non_converge(who);
+    }
+    config_put(config);
+}
+
+void migrate_ensure_converge(QTestState *who, QDict *config)
+{
+    config = config_load(config);
+    /* Should converge with 30s downtime + 1 gbs bandwidth limit */
+    if (config) {
+        qdict_put_int(config, "max-bandwidth", 1 * 1000 * 1000 * 1000);
+        qdict_put_int(config, "downtime-limit", 30 * 1000);
+    } else {
+        assert(who);
+        migrate_ongoing_ensure_converge(who);
+    }
+    config_put(config);
+}
+
 void migrate_pause(QTestState *who)
 {
     qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
index 9a36a677ba..e465c69094 100644
--- a/tests/qtest/migration/migration-qmp.h
+++ b/tests/qtest/migration/migration-qmp.h
@@ -39,8 +39,10 @@ void migrate_set_parameter_strv(QTestState *who, const char *parameter,
 void migrate_set_parameter_null(QTestState *who, const char *parameter);
 void migrate_set_parameter_bool(QTestState *who, const char *parameter,
                                 int value);
-void migrate_ensure_non_converge(QTestState *who);
-void migrate_ensure_converge(QTestState *who);
+void migrate_ongoing_ensure_non_converge(QTestState *who);
+void migrate_ongoing_ensure_converge(QTestState *who);
+void migrate_ensure_non_converge(QTestState *who, QDict *config);
+void migrate_ensure_converge(QTestState *who, QDict *config);
 void migrate_pause(QTestState *who);
 void migrate_continue(QTestState *who, const char *state);
 void migrate_recover(QTestState *who, const char *uri);
diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
index 61bdfda857..0a737cb54f 100644
--- a/tests/qtest/migration/misc-tests.c
+++ b/tests/qtest/migration/misc-tests.c
@@ -68,7 +68,7 @@ static void test_analyze_script(char *name, MigrateCommon *args)
     file = g_strdup_printf("%s/migfile", tmpfs);
     uri = g_strdup_printf("exec:cat > %s", file);
 
-    migrate_ensure_converge(from);
+    migrate_ensure_converge(from, args->start.config);
     migrate_qmp(from, to, uri, NULL, "{}");
     wait_for_migration_complete(from);
 
@@ -102,7 +102,7 @@ static void test_ignore_shared(char *name, MigrateCommon *args)
         return;
     }
 
-    migrate_ensure_non_converge(from);
+    migrate_ensure_non_converge(from, args->start.config);
     migrate_prepare_for_dirty_mem(from);
 
     /* Wait for the first serial output from the source */
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index ab5789717f..eabbbf39c3 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -374,7 +374,7 @@ static void test_auto_converge(char *name, MigrateCommon *args)
      * Set the initial parameters so that the migration could not converge
      * without throttling.
      */
-    migrate_ensure_non_converge(from);
+    migrate_ensure_non_converge(from, args->start.config);
 
     /* To check remaining size after precopy */
     migrate_set_capability(from, "pause-before-switchover", true);
@@ -427,7 +427,7 @@ static void test_auto_converge(char *name, MigrateCommon *args)
     g_assert_cmpint(hit, ==, 1);
 
     /* Now, when we tested that throttling works, let it converge */
-    migrate_ensure_converge(from);
+    migrate_ongoing_ensure_converge(from);
 
     /*
      * Wait for pre-switchover status to check last throttle percentage
@@ -562,7 +562,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
         return;
     }
 
-    migrate_ensure_non_converge(from);
+    migrate_ensure_non_converge(from, args->start.config);
     migrate_prepare_for_dirty_mem(from);
 
     if (postcopy_ram) {
@@ -623,14 +623,12 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
     /* Start incoming migration from the 1st socket */
     migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, "{}");
 
-    migrate_ensure_non_converge(from);
+    migrate_ensure_non_converge(from, args->start.config);
 
     migrate_qmp(from, to2, NULL, NULL, "{}");
 
     migrate_wait_for_dirty_mem(from, to2);
-
-    migrate_ensure_converge(from);
-
+    migrate_ongoing_ensure_converge(from);
     wait_for_stop(from, get_src());
     qtest_qmp_eventwait(to2, "RESUME");
 
@@ -659,7 +657,7 @@ static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
      */
 
     wait_for_serial("src_serial");
-    migrate_ensure_converge(from);
+    migrate_ensure_converge(from, args->config);
 
     migrate_qmp(from, to, uri, NULL, "{}");
 
@@ -684,7 +682,7 @@ static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
     migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
 
     wait_for_serial("src_serial");
-    migrate_ensure_converge(from);
+    migrate_ensure_converge(from, args->config);
 
     migrate_qmp(from, to, uri, NULL, "{}");
 
@@ -709,7 +707,7 @@ static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
     migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
 
     wait_for_serial("src_serial");
-    migrate_ensure_converge(from);
+    migrate_ensure_converge(from, args->config);
 
     migrate_qmp(from, to, uri, NULL, "{}");
 
@@ -739,7 +737,7 @@ static void test_cancel_src_after_none(QTestState *from, QTestState *to,
 
     migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
 
-    migrate_ensure_converge(from);
+    migrate_ensure_converge(from, args->config);
     migrate_qmp(from, to, uri, NULL, "{}");
 
     wait_for_migration_complete(from);
@@ -759,7 +757,7 @@ static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
     migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
 
     wait_for_serial("src_serial");
-    migrate_ensure_converge(from);
+    migrate_ensure_converge(from, args->config);
 
     migrate_qmp(from, to, uri, NULL, "{}");
 
@@ -1066,9 +1064,6 @@ static void migrate_dirty_limit_wait_showup(QTestState *from,
     migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
     migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
 
-    /* Make sure migrate can't converge */
-    migrate_ensure_non_converge(from);
-
     /* To check limit rate after precopy */
     migrate_set_capability(from, "pause-before-switchover", true);
 
@@ -1128,6 +1123,7 @@ static void test_dirty_limit(char *name, MigrateCommon *args)
     }
 
     /* Prepare for dirty limit migration and wait src vm show up */
+    migrate_ensure_non_converge(from, args->start.config);
     migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
 
     /* Start migrate */
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 33/51] tests/qtest/migration: Adapt the incoming cmdline for config passing
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (31 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 32/51] tests/qtest/migration: Adapt convergence routines to config Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 34/51] tests/qtest/migration: Use migrate_incoming_qmp where possible Fabiano Rosas
                   ` (18 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Allow the -incoming command line option to pass the config object in
json format. Regardless of whether config passing via -incoming will
be a supported interface, we need for some tests to work with the
config.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/framework.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index df42a8a2c6..ebd41d3c9f 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -324,6 +324,7 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
     g_autofree gchar *arch_opts = NULL;
     gchar *cmd_source = NULL;
     gchar *cmd_target = NULL;
+    g_autofree gchar *config_opts = NULL;
     const gchar *ignore_stderr;
     g_autofree char *mem_object = NULL;
     const char *kvm_opts = NULL;
@@ -428,17 +429,23 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
      */
     events = args->defer_target_connect ? "-global migration.x-events=on" : "";
 
+    if (args->config) {
+        GString *json = qobject_to_json(QOBJECT(args->config));
+        config_opts = g_strdup_printf("-incoming '%s'", json->str);
+    }
+
     cmd_target = g_strdup_printf("-accel kvm%s -accel tcg "
                                  "-machine %s,%s "
                                  "-name target,debug-threads=on "
                                  "%s "
                                  "-serial file:%s/dest_serial "
                                  "-incoming %s "
-                                 "%s %s %s %s",
+                                 "%s %s %s %s %s",
                                  kvm_opts ? kvm_opts : "",
                                  machine, machine_opts,
                                  memory_backend, tmpfs,
                                  args->incoming_defer ? "defer" : uri,
+                                 config_opts ? config_opts : "",
                                  events,
                                  arch_opts ? arch_opts : "",
                                  args->opts_target ? args->opts_target : "",
@@ -503,9 +510,11 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
     bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me);
     src_state.suspend_me = args->suspend_me;
 
+    args->config = config_load(args->config);
     if (migrate_args(&cmd_source, &cmd_target, uri, args)) {
         return -1;
     }
+    config_put(args->config);
 
     if (!args->only_target) {
         *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 34/51] tests/qtest/migration: Use migrate_incoming_qmp where possible
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (32 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 33/51] tests/qtest/migration: Adapt the incoming cmdline for config passing Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-18 18:47   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 35/51] tests/qtest/migration: Add a config parameter to migrate_qmp functions Fabiano Rosas
                   ` (17 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Always use the proper function for starting the incoming migration,
there's no need to call QMP directly from the tests.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/cpr-tests.c | 19 ++++++++++++-------
 tests/qtest/migration/framework.c | 16 +++++++++-------
 2 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
index 7456337370..280e671e4b 100644
--- a/tests/qtest/migration/cpr-tests.c
+++ b/tests/qtest/migration/cpr-tests.c
@@ -15,6 +15,8 @@
 #include "migration/framework.h"
 #include "migration/migration-qmp.h"
 #include "migration/migration-util.h"
+#include "qapi/error.h"
+#include "qobject/qjson.h"
 
 
 static char *tmpfs;
@@ -183,6 +185,7 @@ static void test_cpr_exec(MigrateCommon *args)
     g_autofree char *connect_uri = g_strdup(args->connect_uri);
     g_autofree char *filename = g_strdup_printf("%s/%s", tmpfs,
                                                 FILE_TEST_FILENAME);
+    g_autofree char *channels = NULL;
 
     if (migrate_start(&from, NULL, args->listen_uri, &args->start)) {
         return;
@@ -203,13 +206,15 @@ static void test_cpr_exec(MigrateCommon *args)
 
     to = qtest_init_after_exec(from);
 
-    qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
-                             "  'arguments': { "
-                             "      'channels': [ { 'channel-type': 'main',"
-                             "      'addr': { 'transport': 'file',"
-                             "                'filename': %s,"
-                             "                'offset': 0  } } ] } }",
-                             filename);
+    channels = g_strdup_printf("[ { 'channel-type': 'main',"
+                               "    'addr': { 'transport': 'file',"
+                               "              'filename': '%s',"
+                               "              'offset': 0  } } ]",
+                               filename);
+
+    migrate_incoming_qmp(to, NULL,
+                         qobject_from_json(channels, &error_abort),
+                         "{}");
     wait_for_migration_complete(to);
 
     wait_for_resume(to, get_dst());
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index ebd41d3c9f..227bc39303 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -579,6 +579,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
                                     MigrateCommon *args)
 {
     QTestState *from, *to;
+    QObject *channels;
 
     /* set postcopy capabilities */
     args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME] = true;
@@ -594,13 +595,14 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
 
     migrate_ensure_non_converge(from, args->start.config);
     migrate_prepare_for_dirty_mem(from);
-    qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
-                             "  'arguments': { "
-                             "      'channels': [ { 'channel-type': 'main',"
-                             "      'addr': { 'transport': 'socket',"
-                             "                'type': 'inet',"
-                             "                'host': '127.0.0.1',"
-                             "                'port': '0' } } ] } }");
+
+    channels = qobject_from_json("[ { 'channel-type': 'main',"
+                                 "    'addr': { 'transport': 'socket',"
+                                 "              'type': 'inet',"
+                                 "              'host': '127.0.0.1',"
+                                 "              'port': '0' } } ]",
+                                 &error_abort);
+    migrate_incoming_qmp(to, NULL, channels, "{}");
 
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 35/51] tests/qtest/migration: Add a config parameter to migrate_qmp functions
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (33 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 34/51] tests/qtest/migration: Use migrate_incoming_qmp where possible Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 36/51] tests/qtest/migration: Move tls hook data out of specific hooks Fabiano Rosas
                   ` (16 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Add a config parameter to all migrate_qmp functions. All tests will be
converted in the next patches to use the config instead of calling
migrate_set_*.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/cpr-tests.c     |  3 ++-
 tests/qtest/migration/framework.c     | 33 ++++++++++++++----------
 tests/qtest/migration/migration-qmp.c | 27 ++++++++++++++++---
 tests/qtest/migration/migration-qmp.h | 13 +++++-----
 tests/qtest/migration/misc-tests.c    | 11 ++++----
 tests/qtest/migration/precopy-tests.c | 37 +++++++++++++++------------
 tests/qtest/virtio-net-failover.c     | 24 +++++++++++------
 7 files changed, 96 insertions(+), 52 deletions(-)

diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
index 280e671e4b..9883616cb5 100644
--- a/tests/qtest/migration/cpr-tests.c
+++ b/tests/qtest/migration/cpr-tests.c
@@ -201,7 +201,7 @@ static void test_cpr_exec(MigrateCommon *args)
     wait_for_serial("src_serial");
     set_cpr_exec_args(from, args);
     migrate_set_capability(from, "events", true);
-    migrate_qmp(from, NULL, connect_uri, NULL, "{}");
+    migrate_qmp(from, NULL, connect_uri, NULL, args->start.config, "{}");
     wait_for_migration_event(from, "completed");
 
     to = qtest_init_after_exec(from);
@@ -214,6 +214,7 @@ static void test_cpr_exec(MigrateCommon *args)
 
     migrate_incoming_qmp(to, NULL,
                          qobject_from_json(channels, &error_abort),
+                         args->start.config,
                          "{}");
     wait_for_migration_complete(to);
 
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 227bc39303..f740228cf2 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -602,13 +602,13 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
                                  "              'host': '127.0.0.1',"
                                  "              'port': '0' } } ]",
                                  &error_abort);
-    migrate_incoming_qmp(to, NULL, channels, "{}");
+    migrate_incoming_qmp(to, NULL, channels, args->start.config, "{}");
 
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
     wait_for_suspend(from, &src_state);
 
-    migrate_qmp(from, to, NULL, NULL, "{}");
+    migrate_qmp(from, to, NULL, NULL, args->start.config, "{}");
 
     migrate_wait_for_dirty_mem(from, to);
 
@@ -666,9 +666,10 @@ static void wait_for_postcopy_status(QTestState *one, const char *status)
 }
 
 static void postcopy_recover_fail(QTestState *from, QTestState *to,
-                                  PostcopyRecoveryFailStage stage)
+                                  MigrateCommon *args)
 {
 #ifndef _WIN32
+    PostcopyRecoveryFailStage stage = args->postcopy_recovery_fail_stage;
     bool fail_early = (stage == POSTCOPY_FAIL_CHANNEL_ESTABLISH);
     int ret, pair1[2], pair2[2];
     char c;
@@ -717,7 +718,8 @@ static void postcopy_recover_fail(QTestState *from, QTestState *to,
     }
 
     migrate_recover(to, "fd:fd-mig");
-    migrate_qmp(from, to, "fd:fd-mig", NULL, "{'resume': true}");
+    migrate_qmp(from, to, "fd:fd-mig", NULL, args->start.config,
+                "{'resume': true}");
 
     /*
      * Source QEMU has an extra RECOVER_SETUP phase, dest doesn't have it.
@@ -824,7 +826,7 @@ void test_postcopy_recovery_common(MigrateCommon *args)
          * Test when a wrong socket specified for recover, and then the
          * ability to kick it out, and continue with a correct socket.
          */
-        postcopy_recover_fail(from, to, args->postcopy_recovery_fail_stage);
+        postcopy_recover_fail(from, to, args);
         /* continue with a good recovery */
     }
 
@@ -840,7 +842,7 @@ void test_postcopy_recovery_common(MigrateCommon *args)
      * Try to rebuild the migration channel using the resume flag and
      * the newly created channel
      */
-    migrate_qmp(from, to, uri, NULL, "{'resume': true}");
+    migrate_qmp(from, to, uri, NULL, args->start.config, "{'resume': true}");
 
     /* Restore the postcopy bandwidth to unlimited */
     migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0);
@@ -873,7 +875,8 @@ int test_precopy_common(MigrateCommon *args)
             in_channels = qobject_from_json(args->connect_channels,
                                             &error_abort);
         }
-        migrate_incoming_qmp(to, args->listen_uri, in_channels, "{}");
+        migrate_incoming_qmp(to, args->listen_uri, in_channels,
+                             args->start.config, "{}");
     }
 
     /* Wait for the first serial output from the source */
@@ -919,17 +922,20 @@ int test_precopy_common(MigrateCommon *args)
     }
 
     if (args->result == MIG_TEST_QMP_ERROR) {
-        migrate_qmp_fail(from, args->connect_uri, out_channels, "{}");
+        migrate_qmp_fail(from, args->connect_uri, out_channels,
+                         args->start.config, "{}");
         goto finish;
     }
 
-    migrate_qmp(from, to, args->connect_uri, out_channels, "{}");
+    migrate_qmp(from, to, args->connect_uri, out_channels,
+                args->start.config, "{}");
 
     if (args->start.defer_target_connect) {
         qtest_connect(to);
         qtest_qmp_handshake(to, NULL);
         if (args->start.incoming_defer) {
-            migrate_incoming_qmp(to, NULL, in_channels, "{}");
+            migrate_incoming_qmp(to, args->connect_uri, in_channels,
+                                 args->start.config, "{}");
         }
     }
 
@@ -1067,18 +1073,19 @@ void test_file_common(MigrateCommon *args, bool stop_src)
     }
 
     if (args->result == MIG_TEST_QMP_ERROR) {
-        migrate_qmp_fail(from, args->connect_uri, NULL, "{}");
+        migrate_qmp_fail(from, args->connect_uri, NULL,
+                         args->start.config, "{}");
         goto finish;
     }
 
-    migrate_qmp(from, to, args->connect_uri, NULL, "{}");
+    migrate_qmp(from, to, args->connect_uri, NULL, args->start.config, "{}");
     wait_for_migration_complete(from);
 
     /*
      * We need to wait for the source to finish before starting the
      * destination.
      */
-    migrate_incoming_qmp(to, args->listen_uri, NULL, "{}");
+    migrate_incoming_qmp(to, args->listen_uri, NULL, args->start.config, "{}");
     wait_for_migration_complete(to);
 
     if (stop_src) {
diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
index 7fe47a5793..a4dde029ee 100644
--- a/tests/qtest/migration/migration-qmp.c
+++ b/tests/qtest/migration/migration-qmp.c
@@ -77,7 +77,7 @@ QObject *migrate_str_to_channel(const char *str)
 }
 
 void migrate_qmp_fail(QTestState *who, const char *uri,
-                      QObject *channels, const char *fmt, ...)
+                      QObject *channels, QDict *config, const char *fmt, ...)
 {
     va_list ap;
     QDict *args, *err;
@@ -96,12 +96,19 @@ void migrate_qmp_fail(QTestState *who, const char *uri,
         qdict_put_obj(args, "channels", channels);
     }
 
+    config = config_load(config);
+    if (config) {
+        qdict_put_obj(args, "config", QOBJECT(config));
+        qobject_ref(config);
+    }
+
     err = qtest_qmp_assert_failure_ref(
         who, "{ 'execute': 'migrate', 'arguments': %p}", args);
 
     g_assert(qdict_haskey(err, "desc"));
 
     qobject_unref(err);
+    config_put(config);
 }
 
 /*
@@ -110,7 +117,7 @@ void migrate_qmp_fail(QTestState *who, const char *uri,
  * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
  */
 void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
-                 QObject *channels, const char *fmt, ...)
+                 QObject *channels, QDict *config, const char *fmt, ...)
 {
     va_list ap;
     QDict *args;
@@ -135,8 +142,15 @@ void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
         qdict_put_obj(args, "channels", channels);
     }
 
+    config = config_load(config);
+    if (config) {
+        qdict_put_obj(args, "config", QOBJECT(config));
+        qobject_ref(config);
+    }
+
     qtest_qmp_assert_success(who,
                              "{ 'execute': 'migrate', 'arguments': %p}", args);
+    config_put(config);
 }
 
 void migrate_set_capability(QTestState *who, const char *capability,
@@ -151,7 +165,7 @@ void migrate_set_capability(QTestState *who, const char *capability,
 }
 
 void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
-                          const char *fmt, ...)
+                          QDict *config, const char *fmt, ...)
 {
     va_list ap;
     QDict *args, *rsp;
@@ -173,6 +187,12 @@ void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
     /* This function relies on the event to work, make sure it's enabled */
     migrate_set_capability(to, "events", true);
 
+    config = config_load(config);
+    if (config) {
+        qdict_put_obj(args, "config", QOBJECT(config));
+        qobject_ref(config);
+    }
+
     rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
                     args);
 
@@ -185,6 +205,7 @@ void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
     qobject_unref(rsp);
 
     migration_event_wait(to, "setup");
+    config_put(config);
 }
 
 static bool check_migration_status(QTestState *who, const char *goal,
diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
index e465c69094..7daeb913fa 100644
--- a/tests/qtest/migration/migration-qmp.h
+++ b/tests/qtest/migration/migration-qmp.h
@@ -6,17 +6,18 @@
 
 QObject *migrate_str_to_channel(const char *str);
 
-G_GNUC_PRINTF(4, 5)
+G_GNUC_PRINTF(5, 6)
 void migrate_qmp_fail(QTestState *who, const char *uri,
-                      QObject *channels, const char *fmt, ...);
+                      QObject *channels, QDict *config, const char *fmt, ...);
 
-G_GNUC_PRINTF(5, 6)
+G_GNUC_PRINTF(6, 7)
 void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
-                 QObject *channels, const char *fmt, ...);
+                 QObject *channels, QDict *config, const char *fmt, ...);
 
-G_GNUC_PRINTF(4, 5)
+G_GNUC_PRINTF(5, 6)
 void migrate_incoming_qmp(QTestState *who, const char *uri,
-                          QObject *channels, const char *fmt, ...);
+                          QObject *channels, QDict *config,
+                          const char *fmt, ...);
 
 void migration_event_wait(QTestState *s, const char *target);
 void migrate_set_capability(QTestState *who, const char *capability,
diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
index 0a737cb54f..c62fd1e3f9 100644
--- a/tests/qtest/migration/misc-tests.c
+++ b/tests/qtest/migration/misc-tests.c
@@ -31,7 +31,7 @@ static void test_baddest(char *name, MigrateCommon *args)
     if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) {
         return;
     }
-    migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, "{}");
+    migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, args->start.config, "{}");
     wait_for_migration_fail(from, false);
     migrate_end(from, to, false);
 }
@@ -69,7 +69,7 @@ static void test_analyze_script(char *name, MigrateCommon *args)
     uri = g_strdup_printf("exec:cat > %s", file);
 
     migrate_ensure_converge(from, args->start.config);
-    migrate_qmp(from, to, uri, NULL, "{}");
+    migrate_qmp(from, to, uri, NULL, args->start.config, "{}");
     wait_for_migration_complete(from);
 
     pid = fork();
@@ -108,7 +108,7 @@ static void test_ignore_shared(char *name, MigrateCommon *args)
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
 
-    migrate_qmp(from, to, uri, NULL, "{}");
+    migrate_qmp(from, to, uri, NULL, args->start.config, "{}");
 
     migrate_wait_for_dirty_mem(from, to);
 
@@ -146,7 +146,7 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
 
-    migrate_qmp(from, to, uri, NULL, "{}");
+    migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
     if (should_fail) {
         qtest_set_expected_status(to, EXIT_FAILURE);
@@ -210,7 +210,8 @@ static void do_test_validate_uri_channel(MigrateCommon *args)
     channels = args->connect_channels ?
                qobject_from_json(args->connect_channels, &error_abort) :
                NULL;
-    migrate_qmp_fail(from, args->connect_uri, channels, "{}");
+    migrate_qmp_fail(from, args->connect_uri, channels,
+                     args->start.config, "{}");
 
     migrate_end(from, to, false);
 }
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index eabbbf39c3..0b0f04bf19 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -382,7 +382,7 @@ static void test_auto_converge(char *name, MigrateCommon *args)
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
 
-    migrate_qmp(from, to, uri, NULL, "{}");
+    migrate_qmp(from, to, uri, NULL, args->start.config, "{}");
 
     /* Wait for throttling begins */
     percentage = 0;
@@ -577,12 +577,12 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
     migrate_set_capability(to, "multifd", true);
 
     /* Start incoming migration from the 1st socket */
-    migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
+    migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, args->start.config, "{}");
 
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
 
-    migrate_qmp(from, to, NULL, NULL, "{}");
+    migrate_qmp(from, to, NULL, NULL, args->start.config, "{}");
 
     migrate_wait_for_dirty_mem(from, to);
 
@@ -621,11 +621,12 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
     migrate_set_capability(to2, "multifd", true);
 
     /* Start incoming migration from the 1st socket */
-    migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, "{}");
+    migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, args->start.config,
+                         "{}");
 
     migrate_ensure_non_converge(from, args->start.config);
 
-    migrate_qmp(from, to2, NULL, NULL, "{}");
+    migrate_qmp(from, to2, NULL, NULL, args->start.config, "{}");
 
     migrate_wait_for_dirty_mem(from, to2);
     migrate_ongoing_ensure_converge(from);
@@ -659,7 +660,7 @@ static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
     wait_for_serial("src_serial");
     migrate_ensure_converge(from, args->config);
 
-    migrate_qmp(from, to, uri, NULL, "{}");
+    migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
     migration_event_wait(from, phase);
     migrate_cancel(from);
@@ -679,12 +680,13 @@ static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
                                             const char *uri, const char *phase,
                                             MigrateStart *args)
 {
-    migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
+    migrate_incoming_qmp(to, uri, NULL, args->config,
+                         "{ 'exit-on-error': false }");
 
     wait_for_serial("src_serial");
     migrate_ensure_converge(from, args->config);
 
-    migrate_qmp(from, to, uri, NULL, "{}");
+    migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
     /* To move to cancelled/cancelling */
     migrate_cancel(from);
@@ -704,12 +706,13 @@ static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
                                            const char *uri, const char *phase,
                                            MigrateStart *args)
 {
-    migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
+    migrate_incoming_qmp(to, uri, NULL, args->config,
+                         "{ 'exit-on-error': false }");
 
     wait_for_serial("src_serial");
     migrate_ensure_converge(from, args->config);
 
-    migrate_qmp(from, to, uri, NULL, "{}");
+    migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
     migration_event_wait(from, phase);
     migrate_cancel(from);
@@ -735,10 +738,11 @@ static void test_cancel_src_after_none(QTestState *from, QTestState *to,
     wait_for_serial("src_serial");
     migrate_cancel(from);
 
-    migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
+    migrate_incoming_qmp(to, uri, NULL, args->config,
+                         "{ 'exit-on-error': false }");
 
     migrate_ensure_converge(from, args->config);
-    migrate_qmp(from, to, uri, NULL, "{}");
+    migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
     wait_for_migration_complete(from);
     wait_for_migration_complete(to);
@@ -754,12 +758,13 @@ static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
     migrate_set_capability(from, "multifd", true);
     migrate_set_capability(to, "multifd", true);
 
-    migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
+    migrate_incoming_qmp(to, uri, NULL, args->config,
+                         "{ 'exit-on-error': false }");
 
     wait_for_serial("src_serial");
     migrate_ensure_converge(from, args->config);
 
-    migrate_qmp(from, to, uri, NULL, "{}");
+    migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
     migration_event_wait(from, phase);
     migrate_cancel(from);
@@ -1127,7 +1132,7 @@ static void test_dirty_limit(char *name, MigrateCommon *args)
     migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
 
     /* Start migrate */
-    migrate_qmp(from, to, args->connect_uri, NULL, "{}");
+    migrate_qmp(from, to, args->connect_uri, NULL, args->start.config, "{}");
 
     /* Wait for dirty limit throttle begin */
     throttle_us_per_full = 0;
@@ -1172,7 +1177,7 @@ static void test_dirty_limit(char *name, MigrateCommon *args)
     }
 
     /* Start migrate */
-    migrate_qmp(from, to, args->connect_uri, NULL, "{}");
+    migrate_qmp(from, to, args->connect_uri, NULL, args->start.config, "{}");
 
     /* Wait for dirty limit throttle begin */
     throttle_us_per_full = 0;
diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c
index 5baf81c3e6..e3edcfc9b7 100644
--- a/tests/qtest/virtio-net-failover.c
+++ b/tests/qtest/virtio-net-failover.c
@@ -741,7 +741,7 @@ static void test_migrate_out(gconstpointer opaque)
 static void test_migrate_in(gconstpointer opaque)
 {
     QTestState *qts;
-    QDict *resp, *ret;
+    QDict *resp, *ret, *config;
     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
 
     qts = machine_start(BASE_MACHINE
@@ -773,7 +773,9 @@ static void test_migrate_in(gconstpointer opaque)
     check_one_card(qts, true, "standby0", MAC_STANDBY0);
     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 
-    migrate_incoming_qmp(qts, uri, NULL, "{}");
+    config = qdict_new();
+    migrate_incoming_qmp(qts, uri, NULL, config, "{}");
+    qdict_unref(config);
 
     resp = get_failover_negociated_event(qts);
     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
@@ -863,7 +865,7 @@ static void test_off_migrate_out(gconstpointer opaque)
 static void test_off_migrate_in(gconstpointer opaque)
 {
     QTestState *qts;
-    QDict *ret;
+    QDict *ret, *config;
     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
 
     qts = machine_start(BASE_MACHINE
@@ -895,7 +897,9 @@ static void test_off_migrate_in(gconstpointer opaque)
     check_one_card(qts, true, "standby0", MAC_STANDBY0);
     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
 
-    migrate_incoming_qmp(qts, uri, NULL, "{}");
+    config = qdict_new();
+    migrate_incoming_qmp(qts, uri, NULL, config, "{}");
+    qdict_unref(config);
 
     check_one_card(qts, true, "standby0", MAC_STANDBY0);
     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
@@ -990,7 +994,7 @@ static void test_guest_off_migrate_out(gconstpointer opaque)
 static void test_guest_off_migrate_in(gconstpointer opaque)
 {
     QTestState *qts;
-    QDict *ret;
+    QDict *ret, *config;
     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
 
     qts = machine_start(BASE_MACHINE
@@ -1022,7 +1026,9 @@ static void test_guest_off_migrate_in(gconstpointer opaque)
     check_one_card(qts, true, "standby0", MAC_STANDBY0);
     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 
-    migrate_incoming_qmp(qts, uri, NULL, "{}");
+    config = qdict_new();
+    migrate_incoming_qmp(qts, uri, NULL, config, "{}");
+    qdict_unref(config);
 
     check_one_card(qts, true, "standby0", MAC_STANDBY0);
     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
@@ -1681,7 +1687,7 @@ static void test_multi_out(gconstpointer opaque)
 static void test_multi_in(gconstpointer opaque)
 {
     QTestState *qts;
-    QDict *resp, *ret;
+    QDict *resp, *ret, *config;
     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
 
     qts = machine_start(BASE_MACHINE
@@ -1747,7 +1753,9 @@ static void test_multi_in(gconstpointer opaque)
     check_one_card(qts, true, "standby1", MAC_STANDBY1);
     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
 
-    migrate_incoming_qmp(qts, uri, NULL, "{}");
+    config = qdict_new();
+    migrate_incoming_qmp(qts, uri, NULL, config, "{}");
+    qdict_unref(config);
 
     resp = get_failover_negociated_event(qts);
     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 36/51] tests/qtest/migration: Move tls hook data out of specific hooks
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (34 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 35/51] tests/qtest/migration: Add a config parameter to migrate_qmp functions Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 37/51] tests/qtest/migration: Add new hook with data Fabiano Rosas
                   ` (15 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

The nesting of hooks in tls-tests.c is out of hand. It's quite
unreadable and makes it a pain to solve git conflicts in that code.

We're at this point moving away from setting migration parameters and
capabilities with migrate_set_* in favor of the new config struct,
which goes along with the migrate commmand. This means hooks will have
to be reworked to allow some data to be accessed earlier than
->start_hook.

Start cleaning up the tls-tests hooks to allow future patches to
address both issues. This patch only deals with x509 code, while a
later patch will appply the same changes to PSK.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/tls-tests.c | 155 ++++++++++++++++--------------
 1 file changed, 84 insertions(+), 71 deletions(-)

diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index f63f37132a..d50832573f 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -134,6 +134,76 @@ typedef struct {
     const char *certipaddr;
 } TestMigrateTLSX509;
 
+/*
+ * The normal case: match server's cert hostname against
+ * whatever host we were telling QEMU to connect to (if any)
+ */
+static TestMigrateTLSX509 tls_x509_default_host = {
+    .verifyclient = true,
+    .clientcert = true,
+    .certipaddr = "127.0.0.1"
+};
+
+/*
+ * The unusual case: the server's cert is different from
+ * the address we're telling QEMU to connect to (if any),
+ * so we must give QEMU an explicit hostname to validate
+ */
+static TestMigrateTLSX509 tls_x509_override_host = {
+    .verifyclient = true,
+    .clientcert = true,
+    .certhostname = "qemu.org",
+};
+
+/*
+ * The unusual case: the server's cert is different from
+ * the address we're telling QEMU to connect to, and so we
+ * expect the client to reject the server
+ */
+static TestMigrateTLSX509 tls_x509_mismatch_host = {
+    .verifyclient = true,
+    .clientcert = true,
+    .certipaddr = "10.0.0.1",
+};
+
+static TestMigrateTLSX509 x509_friendly_client = {
+    .verifyclient = true,
+    .clientcert = true,
+    .authzclient = true,
+    .certipaddr = "127.0.0.1",
+};
+
+static TestMigrateTLSX509 tls_x509_hostile_client = {
+    .verifyclient = true,
+    .clientcert = true,
+    .hostileclient = true,
+    .authzclient = true,
+    .certipaddr = "127.0.0.1",
+};
+
+/*
+ * The case with no client certificate presented,
+ * and no server verification
+ */
+static TestMigrateTLSX509 tls_x509_allow_anon_client = {
+    .certipaddr = "127.0.0.1",
+};
+
+/*
+ * The case with no client certificate presented,
+ * and server verification rejecting
+ */
+static TestMigrateTLSX509 tls_x509_reject_anon_client = {
+    .verifyclient = true,
+    .certipaddr = "127.0.0.1",
+};
+
+static TestMigrateTLSX509 tls_x509_no_host = {
+    .verifyclient = true,
+    .clientcert = true,
+    .authzclient = true,
+};
+
 static void *
 migrate_hook_start_tls_x509_common(QTestState *from,
                                    QTestState *to,
@@ -223,110 +293,58 @@ migrate_hook_start_tls_x509_common(QTestState *from,
     return data;
 }
 
-/*
- * The normal case: match server's cert hostname against
- * whatever host we were telling QEMU to connect to (if any)
- */
 static void *
 migrate_hook_start_tls_x509_default_host(QTestState *from,
                                          QTestState *to)
 {
-    TestMigrateTLSX509 args = {
-        .verifyclient = true,
-        .clientcert = true,
-        .certipaddr = "127.0.0.1"
-    };
-    return migrate_hook_start_tls_x509_common(from, to, &args);
+    return migrate_hook_start_tls_x509_common(from, to, &tls_x509_default_host);
 }
 
-/*
- * The unusual case: the server's cert is different from
- * the address we're telling QEMU to connect to (if any),
- * so we must give QEMU an explicit hostname to validate
- */
 static void *
 migrate_hook_start_tls_x509_override_host(QTestState *from,
                                           QTestState *to)
 {
-    TestMigrateTLSX509 args = {
-        .verifyclient = true,
-        .clientcert = true,
-        .certhostname = "qemu.org",
-    };
-    return migrate_hook_start_tls_x509_common(from, to, &args);
+    return migrate_hook_start_tls_x509_common(from, to,
+                                              &tls_x509_override_host);
 }
 
-/*
- * The unusual case: the server's cert is different from
- * the address we're telling QEMU to connect to, and so we
- * expect the client to reject the server
- */
 static void *
 migrate_hook_start_tls_x509_mismatch_host(QTestState *from,
                                           QTestState *to)
 {
-    TestMigrateTLSX509 args = {
-        .verifyclient = true,
-        .clientcert = true,
-        .certipaddr = "10.0.0.1",
-    };
-    return migrate_hook_start_tls_x509_common(from, to, &args);
+    return migrate_hook_start_tls_x509_common(from, to,
+                                              &tls_x509_mismatch_host);
 }
 
 static void *
 migrate_hook_start_tls_x509_friendly_client(QTestState *from,
                                             QTestState *to)
 {
-    TestMigrateTLSX509 args = {
-        .verifyclient = true,
-        .clientcert = true,
-        .authzclient = true,
-        .certipaddr = "127.0.0.1",
-    };
-    return migrate_hook_start_tls_x509_common(from, to, &args);
+    return migrate_hook_start_tls_x509_common(from, to, &x509_friendly_client);
 }
 
 static void *
 migrate_hook_start_tls_x509_hostile_client(QTestState *from,
                                            QTestState *to)
 {
-    TestMigrateTLSX509 args = {
-        .verifyclient = true,
-        .clientcert = true,
-        .hostileclient = true,
-        .authzclient = true,
-        .certipaddr = "127.0.0.1",
-    };
-    return migrate_hook_start_tls_x509_common(from, to, &args);
+    return migrate_hook_start_tls_x509_common(from, to,
+                                              &tls_x509_hostile_client);
 }
 
-/*
- * The case with no client certificate presented,
- * and no server verification
- */
 static void *
 migrate_hook_start_tls_x509_allow_anon_client(QTestState *from,
                                               QTestState *to)
 {
-    TestMigrateTLSX509 args = {
-        .certipaddr = "127.0.0.1",
-    };
-    return migrate_hook_start_tls_x509_common(from, to, &args);
+    return migrate_hook_start_tls_x509_common(from, to,
+                                              &tls_x509_allow_anon_client);
 }
 
-/*
- * The case with no client certificate presented,
- * and server verification rejecting
- */
 static void *
 migrate_hook_start_tls_x509_reject_anon_client(QTestState *from,
                                                QTestState *to)
 {
-    TestMigrateTLSX509 args = {
-        .verifyclient = true,
-        .certipaddr = "127.0.0.1",
-    };
-    return migrate_hook_start_tls_x509_common(from, to, &args);
+    return migrate_hook_start_tls_x509_common(from, to,
+                                              &tls_x509_reject_anon_client);
 }
 
 static void
@@ -509,13 +527,8 @@ static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args)
 static void *
 migrate_hook_start_tls_x509_no_host(QTestState *from, QTestState *to)
 {
-    TestMigrateTLSX509 args = {
-        .verifyclient = true,
-        .clientcert = true,
-        .authzclient = true,
-    };
-    TestMigrateTLSX509Data *data = migrate_hook_start_tls_x509_common(from, to,
-                                                                      &args);
+    TestMigrateTLSX509Data *data = migrate_hook_start_tls_x509_common(
+        from, to, &tls_x509_no_host);
     migrate_set_parameter_null(from, "tls-hostname");
     migrate_set_parameter_null(to, "tls-hostname");
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 37/51] tests/qtest/migration: Add new hook with data
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (35 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 36/51] tests/qtest/migration: Move tls hook data out of specific hooks Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-18 19:05   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 38/51] tests/qtest/migration: TLS x509: Refactor to use full hook Fabiano Rosas
                   ` (14 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Add a new start hook that takes an opaque pointer so the tests can
stop having to nest hook calls.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/framework.c |  8 ++++++++
 tests/qtest/migration/framework.h | 16 ++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index f740228cf2..b9bbdca6a9 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -591,6 +591,9 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
 
     if (args->start_hook) {
         args->postcopy_data = args->start_hook(from, to);
+    } else if (args->start_hook_full) {
+        args->postcopy_data = args->start_hook_full(from, to,
+                                                    args->start_hook_data);
     }
 
     migrate_ensure_non_converge(from, args->start.config);
@@ -868,6 +871,9 @@ int test_precopy_common(MigrateCommon *args)
 
     if (args->start_hook) {
         data_hook = args->start_hook(from, to);
+    } else if (args->start_hook_full) {
+        data_hook = args->start_hook_full(from, to,
+                                          args->start_hook_data);
     }
 
     if (args->start.incoming_defer && !args->start.defer_target_connect) {
@@ -1062,6 +1068,8 @@ void test_file_common(MigrateCommon *args, bool stop_src)
 
     if (args->start_hook) {
         data_hook = args->start_hook(from, to);
+    } else if (args->start_hook_full) {
+        data_hook = args->start_hook_full(from, to, args->start_hook_data);
     }
 
     migrate_ensure_converge(from, args->start.config);
diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
index 65c656e0d3..2584599f14 100644
--- a/tests/qtest/migration/framework.h
+++ b/tests/qtest/migration/framework.h
@@ -65,6 +65,19 @@ int migration_env_clean(MigrationTestEnv *env);
 typedef void * (*TestMigrateStartHook)(QTestState *from,
                                        QTestState *to);
 
+
+/*
+ * A hook that runs after the src and dst QEMUs have been created, but
+ * before the migration is started. This can be used to run routines
+ * that require the QTestState object.
+ *
+ * Returns: NULL, or a pointer to opaque state to be
+ *          later passed to the TestMigrateEndHook
+ */
+typedef void * (*TestMigrateStartHookFull)(QTestState *from,
+                                           QTestState *to,
+                                           void *opaque);
+
 /*
  * A hook that runs after the migration has finished,
  * regardless of whether it succeeded or failed, but
@@ -196,6 +209,9 @@ typedef struct {
     /* Optional: callback to run at finish to cleanup */
     TestMigrateEndHook end_hook;
 
+    TestMigrateStartHookFull start_hook_full;
+    void *start_hook_data;
+
     /*
      * Optional: normally we expect the migration process to complete.
      *
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 38/51] tests/qtest/migration: TLS x509: Refactor to use full hook
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (36 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 37/51] tests/qtest/migration: Add new hook with data Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-18 19:15   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 39/51] tests/qtest/migration: TLS x509: Add init/cleanup routines Fabiano Rosas
                   ` (13 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Refactor the TLS x509 hooks to use the _full variant which passes the
hook data into the _common functions via MigrateCommon *args.

This reduces the number of hooks and will allow further simplification
of the TLS tests by setting a common hook at a centralized place in
the next patches.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/tls-tests.c | 98 +++++++++----------------------
 1 file changed, 29 insertions(+), 69 deletions(-)

diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index d50832573f..8da95dc92a 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -207,8 +207,9 @@ static TestMigrateTLSX509 tls_x509_no_host = {
 static void *
 migrate_hook_start_tls_x509_common(QTestState *from,
                                    QTestState *to,
-                                   TestMigrateTLSX509 *args)
+                                   void *opaque)
 {
+    TestMigrateTLSX509 *args = opaque;
     TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
 
     data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs);
@@ -293,60 +294,6 @@ migrate_hook_start_tls_x509_common(QTestState *from,
     return data;
 }
 
-static void *
-migrate_hook_start_tls_x509_default_host(QTestState *from,
-                                         QTestState *to)
-{
-    return migrate_hook_start_tls_x509_common(from, to, &tls_x509_default_host);
-}
-
-static void *
-migrate_hook_start_tls_x509_override_host(QTestState *from,
-                                          QTestState *to)
-{
-    return migrate_hook_start_tls_x509_common(from, to,
-                                              &tls_x509_override_host);
-}
-
-static void *
-migrate_hook_start_tls_x509_mismatch_host(QTestState *from,
-                                          QTestState *to)
-{
-    return migrate_hook_start_tls_x509_common(from, to,
-                                              &tls_x509_mismatch_host);
-}
-
-static void *
-migrate_hook_start_tls_x509_friendly_client(QTestState *from,
-                                            QTestState *to)
-{
-    return migrate_hook_start_tls_x509_common(from, to, &x509_friendly_client);
-}
-
-static void *
-migrate_hook_start_tls_x509_hostile_client(QTestState *from,
-                                           QTestState *to)
-{
-    return migrate_hook_start_tls_x509_common(from, to,
-                                              &tls_x509_hostile_client);
-}
-
-static void *
-migrate_hook_start_tls_x509_allow_anon_client(QTestState *from,
-                                              QTestState *to)
-{
-    return migrate_hook_start_tls_x509_common(from, to,
-                                              &tls_x509_allow_anon_client);
-}
-
-static void *
-migrate_hook_start_tls_x509_reject_anon_client(QTestState *from,
-                                               QTestState *to)
-{
-    return migrate_hook_start_tls_x509_common(from, to,
-                                              &tls_x509_reject_anon_client);
-}
-
 static void
 migrate_hook_end_tls_x509(QTestState *from,
                           QTestState *to,
@@ -460,7 +407,8 @@ static void test_precopy_unix_tls_x509_default_host(char *name,
 
     args->connect_uri = uri;
     args->listen_uri = uri;
-    args->start_hook = migrate_hook_start_tls_x509_default_host;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &tls_x509_default_host;
     args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
 
@@ -476,7 +424,8 @@ static void test_precopy_unix_tls_x509_override_host(char *name,
 
     args->connect_uri = uri;
     args->listen_uri = uri;
-    args->start_hook = migrate_hook_start_tls_x509_override_host;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &tls_x509_override_host;
     args->end_hook = migrate_hook_end_tls_x509;
 
     test_precopy_common(args);
@@ -552,7 +501,8 @@ static void test_precopy_tcp_tls_x509_default_host(char *name,
                                                    MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_tls_x509_default_host;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &tls_x509_default_host;
     args->end_hook = migrate_hook_end_tls_x509;
 
     test_precopy_common(args);
@@ -562,7 +512,8 @@ static void test_precopy_tcp_tls_x509_override_host(char *name,
                                                     MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_tls_x509_override_host;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &tls_x509_override_host;
     args->end_hook = migrate_hook_end_tls_x509;
 
     test_precopy_common(args);
@@ -572,7 +523,8 @@ static void test_precopy_tcp_tls_x509_mismatch_host(char *name,
                                                     MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_tls_x509_mismatch_host;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &tls_x509_mismatch_host;
     args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
 
@@ -585,7 +537,8 @@ static void test_precopy_tcp_tls_x509_friendly_client(char *name,
                                                       MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_tls_x509_friendly_client;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &x509_friendly_client;
     args->end_hook = migrate_hook_end_tls_x509;
 
     test_precopy_common(args);
@@ -595,7 +548,8 @@ static void test_precopy_tcp_tls_x509_hostile_client(char *name,
                                                      MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_tls_x509_hostile_client;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &tls_x509_hostile_client;
     args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL;
 
@@ -608,7 +562,8 @@ static void test_precopy_tcp_tls_x509_allow_anon_client(char *name,
                                                         MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_tls_x509_allow_anon_client;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &tls_x509_allow_anon_client;
     args->end_hook = migrate_hook_end_tls_x509;
 
     test_precopy_common(args);
@@ -618,7 +573,8 @@ static void test_precopy_tcp_tls_x509_reject_anon_client(char *name,
                                                          MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_tls_x509_reject_anon_client;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &tls_x509_reject_anon_client;
     args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL;
 
@@ -650,7 +606,7 @@ migrate_hook_start_multifd_tls_x509_default_host(QTestState *from,
                                                  QTestState *to)
 {
     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
-    return migrate_hook_start_tls_x509_default_host(from, to);
+    return migrate_hook_start_tls_x509_common(from, to, &tls_x509_default_host);
 }
 
 static void *
@@ -658,7 +614,8 @@ migrate_hook_start_multifd_tls_x509_override_host(QTestState *from,
                                                   QTestState *to)
 {
     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
-    return migrate_hook_start_tls_x509_override_host(from, to);
+    return migrate_hook_start_tls_x509_common(from, to,
+                                              &tls_x509_override_host);
 }
 
 static void *
@@ -666,7 +623,8 @@ migrate_hook_start_multifd_tls_x509_mismatch_host(QTestState *from,
                                                   QTestState *to)
 {
     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
-    return migrate_hook_start_tls_x509_mismatch_host(from, to);
+    return migrate_hook_start_tls_x509_common(from, to,
+                                              &tls_x509_mismatch_host);
 }
 
 static void *
@@ -674,7 +632,8 @@ migrate_hook_start_multifd_tls_x509_allow_anon_client(QTestState *from,
                                                       QTestState *to)
 {
     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
-    return migrate_hook_start_tls_x509_allow_anon_client(from, to);
+    return migrate_hook_start_tls_x509_common(from, to,
+                                              &tls_x509_allow_anon_client);
 }
 
 static void *
@@ -682,7 +641,8 @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
                                                        QTestState *to)
 {
     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
-    return migrate_hook_start_tls_x509_reject_anon_client(from, to);
+    return migrate_hook_start_tls_x509_common(from, to,
+                                              &tls_x509_reject_anon_client);
 }
 #endif /* CONFIG_TASN1 */
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 39/51] tests/qtest/migration: TLS x509: Add init/cleanup routines
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (37 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 38/51] tests/qtest/migration: TLS x509: Refactor to use full hook Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-18 21:31   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 40/51] tests/qtest/migration: TLS PSK: Refactor to use full hook Fabiano Rosas
                   ` (12 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Split the TLS x509 hooks by moving out of them any code that doesn't
need to access the QTestState.

Aside from making the code harder to follow for no practical reason,
having extra code in the hooks will soon get in the way of converting
the tests to use a new API that, unlike
migrate_set_parameters|capabilities, doesn't require the QEMU instance
to be already live.

Move the QTestState-independent code into a normal function and leave
the hooks only for operations that need the guest machine.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/tls-tests.c | 155 +++++++++++++++---------------
 1 file changed, 75 insertions(+), 80 deletions(-)

diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 8da95dc92a..6a858b766f 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -210,15 +210,57 @@ migrate_hook_start_tls_x509_common(QTestState *from,
                                    void *opaque)
 {
     TestMigrateTLSX509 *args = opaque;
-    TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
+    const char *workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs);
 
+    qtest_qmp_assert_success(from,
+                             "{ 'execute': 'object-add',"
+                             "  'arguments': { 'qom-type': 'tls-creds-x509',"
+                             "                 'id': 'tlscredsx509client0',"
+                             "                 'endpoint': 'client',"
+                             "                 'dir': %s,"
+                             "                 'sanity-check': true,"
+                             "                 'verify-peer': true} }",
+                             workdir);
+    migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0");
+    if (args->certhostname) {
+        migrate_set_parameter_str(from, "tls-hostname", args->certhostname);
+    }
+
+    qtest_qmp_assert_success(to,
+                             "{ 'execute': 'object-add',"
+                             "  'arguments': { 'qom-type': 'tls-creds-x509',"
+                             "                 'id': 'tlscredsx509server0',"
+                             "                 'endpoint': 'server',"
+                             "                 'dir': %s,"
+                             "                 'sanity-check': true,"
+                             "                 'verify-peer': %i} }",
+                             workdir, args->verifyclient);
+    migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0");
+
+    if (args->authzclient) {
+        qtest_qmp_assert_success(to,
+                                 "{ 'execute': 'object-add',"
+                                 "  'arguments': { 'qom-type': 'authz-simple',"
+                                 "                 'id': 'tlsauthz0',"
+                                 "                 'identity': %s} }",
+                                 "CN=" QCRYPTO_TLS_TEST_CLIENT_NAME);
+        migrate_set_parameter_str(to, "tls-authz", "tlsauthz0");
+    }
+
+    return NULL;
+}
+
+static void migrate_tls_x509_init(MigrateCommon *args,
+                                  TestMigrateTLSX509 *test_args,
+                                  TestMigrateTLSX509Data *data)
+{
     data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs);
     data->keyfile = g_strdup_printf("%s/key.pem", data->workdir);
 
     data->cacert = g_strdup_printf("%s/ca-cert.pem", data->workdir);
     data->serverkey = g_strdup_printf("%s/server-key.pem", data->workdir);
     data->servercert = g_strdup_printf("%s/server-cert.pem", data->workdir);
-    if (args->clientcert) {
+    if (test_args->clientcert) {
         data->clientkey = g_strdup_printf("%s/client-key.pem", data->workdir);
         data->clientcert = g_strdup_printf("%s/client-cert.pem", data->workdir);
     }
@@ -231,7 +273,7 @@ migrate_hook_start_tls_x509_common(QTestState *from,
 #else
     g_assert(CreateHardLink(data->serverkey, data->keyfile, NULL) != 0);
 #endif
-    if (args->clientcert) {
+    if (test_args->clientcert) {
 #ifndef _WIN32
         g_assert(link(data->keyfile, data->clientkey) == 0);
 #else
@@ -240,9 +282,9 @@ migrate_hook_start_tls_x509_common(QTestState *from,
     }
 
     TLS_ROOT_REQ_SIMPLE(cacertreq, data->cacert);
-    if (args->clientcert) {
+    if (test_args->clientcert) {
         TLS_CERT_REQ_SIMPLE_CLIENT(servercertreq, cacertreq,
-                                   args->hostileclient ?
+                                   test_args->hostileclient ?
                                    QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME :
                                    QCRYPTO_TLS_TEST_CLIENT_NAME,
                                    data->clientcert);
@@ -251,56 +293,14 @@ migrate_hook_start_tls_x509_common(QTestState *from,
 
     TLS_CERT_REQ_SIMPLE_SERVER(clientcertreq, cacertreq,
                                data->servercert,
-                               args->certhostname,
-                               args->certipaddr);
+                               test_args->certhostname,
+                               test_args->certipaddr);
     test_tls_deinit_cert(&clientcertreq);
     test_tls_deinit_cert(&cacertreq);
-
-    qtest_qmp_assert_success(from,
-                             "{ 'execute': 'object-add',"
-                             "  'arguments': { 'qom-type': 'tls-creds-x509',"
-                             "                 'id': 'tlscredsx509client0',"
-                             "                 'endpoint': 'client',"
-                             "                 'dir': %s,"
-                             "                 'sanity-check': true,"
-                             "                 'verify-peer': true} }",
-                             data->workdir);
-    migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0");
-    if (args->certhostname) {
-        migrate_set_parameter_str(from, "tls-hostname", args->certhostname);
-    }
-
-    qtest_qmp_assert_success(to,
-                             "{ 'execute': 'object-add',"
-                             "  'arguments': { 'qom-type': 'tls-creds-x509',"
-                             "                 'id': 'tlscredsx509server0',"
-                             "                 'endpoint': 'server',"
-                             "                 'dir': %s,"
-                             "                 'sanity-check': true,"
-                             "                 'verify-peer': %i} }",
-                             data->workdir, args->verifyclient);
-    migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0");
-
-    if (args->authzclient) {
-        qtest_qmp_assert_success(to,
-                                 "{ 'execute': 'object-add',"
-                                 "  'arguments': { 'qom-type': 'authz-simple',"
-                                 "                 'id': 'tlsauthz0',"
-                                 "                 'identity': %s} }",
-                                 "CN=" QCRYPTO_TLS_TEST_CLIENT_NAME);
-        migrate_set_parameter_str(to, "tls-authz", "tlsauthz0");
-    }
-
-    return data;
 }
 
-static void
-migrate_hook_end_tls_x509(QTestState *from,
-                          QTestState *to,
-                          void *opaque)
+static void migrate_tls_x509_cleanup(TestMigrateTLSX509Data *data)
 {
-    TestMigrateTLSX509Data *data = opaque;
-
     test_tls_cleanup(data->keyfile);
     g_free(data->keyfile);
 
@@ -325,6 +325,16 @@ migrate_hook_end_tls_x509(QTestState *from,
 
     g_free(data);
 }
+
+static void test_precopy_tls_x509_common(MigrateCommon *args,
+                                         TestMigrateTLSX509 *test_args)
+{
+    TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
+
+    migrate_tls_x509_init(args, test_args, data);
+    test_precopy_common(args);
+    migrate_tls_x509_cleanup(data);
+}
 #endif /* CONFIG_TASN1 */
 
 static void test_postcopy_tls_psk(char *name, MigrateCommon *args)
@@ -409,12 +419,11 @@ static void test_precopy_unix_tls_x509_default_host(char *name,
     args->listen_uri = uri;
     args->start_hook_full = migrate_hook_start_tls_x509_common;
     args->start_hook_data = &tls_x509_default_host;
-    args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
 
     args->start.hide_stderr = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_default_host);
 }
 
 static void test_precopy_unix_tls_x509_override_host(char *name,
@@ -426,9 +435,8 @@ static void test_precopy_unix_tls_x509_override_host(char *name,
     args->listen_uri = uri;
     args->start_hook_full = migrate_hook_start_tls_x509_common;
     args->start_hook_data = &tls_x509_override_host;
-    args->end_hook = migrate_hook_end_tls_x509;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_override_host);
 }
 #endif /* CONFIG_TASN1 */
 
@@ -488,12 +496,11 @@ static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook = migrate_hook_start_tls_x509_no_host;
-    args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
 
     args->start.hide_stderr = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_no_host);
 }
 
 #ifdef CONFIG_TASN1
@@ -503,9 +510,8 @@ static void test_precopy_tcp_tls_x509_default_host(char *name,
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook_full = migrate_hook_start_tls_x509_common;
     args->start_hook_data = &tls_x509_default_host;
-    args->end_hook = migrate_hook_end_tls_x509;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_default_host);
 }
 
 static void test_precopy_tcp_tls_x509_override_host(char *name,
@@ -514,9 +520,8 @@ static void test_precopy_tcp_tls_x509_override_host(char *name,
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook_full = migrate_hook_start_tls_x509_common;
     args->start_hook_data = &tls_x509_override_host;
-    args->end_hook = migrate_hook_end_tls_x509;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_override_host);
 }
 
 static void test_precopy_tcp_tls_x509_mismatch_host(char *name,
@@ -525,12 +530,11 @@ static void test_precopy_tcp_tls_x509_mismatch_host(char *name,
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook_full = migrate_hook_start_tls_x509_common;
     args->start_hook_data = &tls_x509_mismatch_host;
-    args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
 
     args->start.hide_stderr = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_mismatch_host);
 }
 
 static void test_precopy_tcp_tls_x509_friendly_client(char *name,
@@ -539,9 +543,8 @@ static void test_precopy_tcp_tls_x509_friendly_client(char *name,
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook_full = migrate_hook_start_tls_x509_common;
     args->start_hook_data = &x509_friendly_client;
-    args->end_hook = migrate_hook_end_tls_x509;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &x509_friendly_client);
 }
 
 static void test_precopy_tcp_tls_x509_hostile_client(char *name,
@@ -550,12 +553,11 @@ static void test_precopy_tcp_tls_x509_hostile_client(char *name,
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook_full = migrate_hook_start_tls_x509_common;
     args->start_hook_data = &tls_x509_hostile_client;
-    args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL;
 
     args->start.hide_stderr = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_hostile_client);
 }
 
 static void test_precopy_tcp_tls_x509_allow_anon_client(char *name,
@@ -564,9 +566,8 @@ static void test_precopy_tcp_tls_x509_allow_anon_client(char *name,
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook_full = migrate_hook_start_tls_x509_common;
     args->start_hook_data = &tls_x509_allow_anon_client;
-    args->end_hook = migrate_hook_end_tls_x509;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_allow_anon_client);
 }
 
 static void test_precopy_tcp_tls_x509_reject_anon_client(char *name,
@@ -575,12 +576,11 @@ static void test_precopy_tcp_tls_x509_reject_anon_client(char *name,
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook_full = migrate_hook_start_tls_x509_common;
     args->start_hook_data = &tls_x509_reject_anon_client;
-    args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL;
 
     args->start.hide_stderr = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_reject_anon_client);
 }
 #endif /* CONFIG_TASN1 */
 
@@ -691,26 +691,24 @@ static void test_multifd_tcp_tls_x509_default_host(char *name,
                                                    MigrateCommon *args)
 {
     args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
-    args->end_hook = migrate_hook_end_tls_x509;
     args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_default_host);
 }
 
 static void test_multifd_tcp_tls_x509_override_host(char *name,
                                                     MigrateCommon *args)
 {
     args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
-    args->end_hook = migrate_hook_end_tls_x509;
     args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_override_host);
 }
 
 static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
@@ -730,7 +728,6 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
      * without exiting.
      */
     args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
-    args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL;
     args->listen_uri = "tcp:127.0.0.1:0";
 
@@ -738,27 +735,25 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
     args->start.hide_stderr = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_mismatch_host);
 }
 
 static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
                                                         MigrateCommon *args)
 {
     args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
-    args->end_hook = migrate_hook_end_tls_x509;
     args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_allow_anon_client);
 }
 
 static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
                                                          MigrateCommon *args)
 {
     args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
-    args->end_hook = migrate_hook_end_tls_x509;
     args->result = MIG_TEST_FAIL;
     args->listen_uri = "tcp:127.0.0.1:0";
 
@@ -766,7 +761,7 @@ static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
     args->start.hide_stderr = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_x509_common(args, &tls_x509_reject_anon_client);
 }
 #endif /* CONFIG_TASN1 */
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 40/51] tests/qtest/migration: TLS PSK: Refactor to use full hook
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (38 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 39/51] tests/qtest/migration: TLS x509: Add init/cleanup routines Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-18 21:33   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 41/51] tests/qtest/migration: TLS PSK: Add init/cleanup routines Fabiano Rosas
                   ` (11 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Similar to what's been done with the TLS x509 tests, pass an object in
to the TLS PSK common hook so a couple of extra hooks can be removed,
making the code easier to follow.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/tls-tests.c | 64 +++++++++++++++++--------------
 1 file changed, 36 insertions(+), 28 deletions(-)

diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 6a858b766f..2eeed1fc5b 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -30,13 +30,26 @@ struct TestMigrateTLSPSKData {
     char *pskfilealt;
 };
 
+typedef struct {
+    bool mismatch;
+} TestMigrateTLSPSK;
+
+static TestMigrateTLSPSK tls_psk_match = {
+    .mismatch = false,
+};
+
+static TestMigrateTLSPSK tls_psk_mismatch = {
+    .mismatch = true,
+};
+
 static char *tmpfs;
 
 static void *
 migrate_hook_start_tls_psk_common(QTestState *from,
                                   QTestState *to,
-                                  bool mismatch)
+                                  void *opaque)
 {
+    TestMigrateTLSPSK *args = opaque;
     struct TestMigrateTLSPSKData *data =
         g_new0(struct TestMigrateTLSPSKData, 1);
 
@@ -46,7 +59,7 @@ migrate_hook_start_tls_psk_common(QTestState *from,
     g_mkdir_with_parents(data->workdir, 0700);
     test_tls_psk_init(data->pskfile);
 
-    if (mismatch) {
+    if (args->mismatch) {
         data->workdiralt = g_strdup_printf("%s/tlscredspskalt0", tmpfs);
         data->pskfilealt = g_strdup_printf("%s/%s", data->workdiralt,
                                            QCRYPTO_TLS_CREDS_PSKFILE);
@@ -69,7 +82,7 @@ migrate_hook_start_tls_psk_common(QTestState *from,
                              "                 'id': 'tlscredspsk0',"
                              "                 'endpoint': 'server',"
                              "                 'dir': %s } }",
-                             mismatch ? data->workdiralt : data->workdir);
+                             args->mismatch ? data->workdiralt : data->workdir);
 
     migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
     migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
@@ -77,20 +90,6 @@ migrate_hook_start_tls_psk_common(QTestState *from,
     return data;
 }
 
-static void *
-migrate_hook_start_tls_psk_match(QTestState *from,
-                                 QTestState *to)
-{
-    return migrate_hook_start_tls_psk_common(from, to, false);
-}
-
-static void *
-migrate_hook_start_tls_psk_mismatch(QTestState *from,
-                                    QTestState *to)
-{
-    return migrate_hook_start_tls_psk_common(from, to, true);
-}
-
 static void
 migrate_hook_end_tls_psk(QTestState *from,
                          QTestState *to,
@@ -339,7 +338,8 @@ static void test_precopy_tls_x509_common(MigrateCommon *args,
 
 static void test_postcopy_tls_psk(char *name, MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->start_hook_full = migrate_hook_start_tls_psk_common;
+    args->start_hook_data = &tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
 
     test_postcopy_common(args);
@@ -347,7 +347,8 @@ static void test_postcopy_tls_psk(char *name, MigrateCommon *args)
 
 static void test_postcopy_preempt_tls_psk(char *name, MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->start_hook_full = migrate_hook_start_tls_psk_common;
+    args->start_hook_data = &tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
 
     args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
@@ -357,7 +358,8 @@ static void test_postcopy_preempt_tls_psk(char *name, MigrateCommon *args)
 
 static void test_postcopy_recovery_tls_psk(char *name, MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->start_hook_full = migrate_hook_start_tls_psk_common;
+    args->start_hook_data = &tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
 
     test_postcopy_recovery_common(args);
@@ -366,7 +368,8 @@ static void test_postcopy_recovery_tls_psk(char *name, MigrateCommon *args)
 static void test_multifd_postcopy_recovery_tls_psk(char *name,
                                                    MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->start_hook_full = migrate_hook_start_tls_psk_common;
+    args->start_hook_data = &tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
 
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -377,7 +380,8 @@ static void test_multifd_postcopy_recovery_tls_psk(char *name,
 /* This contains preempt+recovery+tls test altogether */
 static void test_postcopy_preempt_all(char *name, MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->start_hook_full = migrate_hook_start_tls_psk_common;
+    args->start_hook_data = &tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
 
     args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
@@ -388,7 +392,8 @@ static void test_postcopy_preempt_all(char *name, MigrateCommon *args)
 static void test_multifd_postcopy_preempt_recovery_tls_psk(char *name,
                                                            MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->start_hook_full = migrate_hook_start_tls_psk_common;
+    args->start_hook_data = &tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
 
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
@@ -403,7 +408,8 @@ static void test_precopy_unix_tls_psk(char *name, MigrateCommon *args)
 
     args->connect_uri = uri;
     args->listen_uri = uri;
-    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->start_hook_full = migrate_hook_start_tls_psk_common;
+    args->start_hook_data = &tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
 
     test_precopy_common(args);
@@ -443,7 +449,8 @@ static void test_precopy_unix_tls_x509_override_host(char *name,
 static void test_precopy_tcp_tls_psk_match(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_tls_psk_match;
+    args->start_hook_full = migrate_hook_start_tls_psk_common;
+    args->start_hook_data = &tls_psk_match;
     args->end_hook = migrate_hook_end_tls_psk;
 
     test_precopy_common(args);
@@ -452,7 +459,8 @@ static void test_precopy_tcp_tls_psk_match(char *name, MigrateCommon *args)
 static void test_precopy_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_tls_psk_mismatch;
+    args->start_hook_full = migrate_hook_start_tls_psk_common;
+    args->start_hook_data = &tls_psk_mismatch;
     args->end_hook = migrate_hook_end_tls_psk;
     args->result = MIG_TEST_FAIL;
 
@@ -589,7 +597,7 @@ migrate_hook_start_multifd_tcp_tls_psk_match(QTestState *from,
                                              QTestState *to)
 {
     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
-    return migrate_hook_start_tls_psk_match(from, to);
+    return migrate_hook_start_tls_psk_common(from, to, &tls_psk_match);
 }
 
 static void *
@@ -597,7 +605,7 @@ migrate_hook_start_multifd_tcp_tls_psk_mismatch(QTestState *from,
                                                 QTestState *to)
 {
     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
-    return migrate_hook_start_tls_psk_mismatch(from, to);
+    return migrate_hook_start_tls_psk_common(from, to, &tls_psk_mismatch);
 }
 
 #ifdef CONFIG_TASN1
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 41/51] tests/qtest/migration: TLS PSK: Add init/cleanup routines
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (39 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 40/51] tests/qtest/migration: TLS PSK: Refactor to use full hook Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-18 21:48   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 42/51] tests/qtest/migration: Remove multifd compression hook Fabiano Rosas
                   ` (10 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Move TLS PSK setup and cleanup into a common function instead of using
hooks. Hooks are for when the test needs to access the QTestState.

This primarily moves setup of TLS PSK tests from ->start_hook time
earlier into test function call time, which brings the migrate_set_*
calls within earlier, where they can be replaced in subsequent patches
with the new config setup.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/tls-tests.c | 149 +++++++++++++++++-------------
 1 file changed, 83 insertions(+), 66 deletions(-)

diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 2eeed1fc5b..aade57f7de 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -23,12 +23,12 @@
 #endif /* CONFIG_TASN1 */
 
 
-struct TestMigrateTLSPSKData {
+typedef struct {
     char *workdir;
     char *workdiralt;
     char *pskfile;
     char *pskfilealt;
-};
+} TestMigrateTLSPSKData;
 
 typedef struct {
     bool mismatch;
@@ -44,59 +44,62 @@ static TestMigrateTLSPSK tls_psk_mismatch = {
 
 static char *tmpfs;
 
-static void *
-migrate_hook_start_tls_psk_common(QTestState *from,
-                                  QTestState *to,
-                                  void *opaque)
+static void *migrate_hook_start_tls_psk_common(QTestState *from,
+                                               QTestState *to,
+                                               void *opaque)
 {
     TestMigrateTLSPSK *args = opaque;
-    struct TestMigrateTLSPSKData *data =
-        g_new0(struct TestMigrateTLSPSKData, 1);
+    g_autofree char *workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs);
+    g_autofree char *workdiralt = NULL;
 
+    if (args->mismatch) {
+        workdiralt = g_strdup_printf("%s/tlscredspskalt0", tmpfs);
+    }
+
+    qtest_qmp_assert_success(from,
+                             "{ 'execute': 'object-add',"
+                             "  'arguments': { 'qom-type': 'tls-creds-psk',"
+                             "                 'id': 'tlscredspsk0',"
+                             "                 'endpoint': 'client',"
+                             "                 'dir': %s,"
+                             "                 'username': 'qemu'} }",
+                             workdir);
+
+    qtest_qmp_assert_success(to,
+                             "{ 'execute': 'object-add',"
+                             "  'arguments': { 'qom-type': 'tls-creds-psk',"
+                             "                 'id': 'tlscredspsk0',"
+                             "                 'endpoint': 'server',"
+                             "                 'dir': %s } }",
+                             args->mismatch ? workdiralt : workdir);
+
+    migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
+    migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
+
+    return NULL;
+}
+
+static void migrate_tls_psk_init(MigrateCommon *args,
+                                 TestMigrateTLSPSK *test_args,
+                                 TestMigrateTLSPSKData *data)
+{
     data->workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs);
     data->pskfile = g_strdup_printf("%s/%s", data->workdir,
                                     QCRYPTO_TLS_CREDS_PSKFILE);
     g_mkdir_with_parents(data->workdir, 0700);
     test_tls_psk_init(data->pskfile);
 
-    if (args->mismatch) {
+    if (test_args->mismatch) {
         data->workdiralt = g_strdup_printf("%s/tlscredspskalt0", tmpfs);
         data->pskfilealt = g_strdup_printf("%s/%s", data->workdiralt,
                                            QCRYPTO_TLS_CREDS_PSKFILE);
         g_mkdir_with_parents(data->workdiralt, 0700);
         test_tls_psk_init_alt(data->pskfilealt);
     }
-
-    qtest_qmp_assert_success(from,
-                             "{ 'execute': 'object-add',"
-                             "  'arguments': { 'qom-type': 'tls-creds-psk',"
-                             "                 'id': 'tlscredspsk0',"
-                             "                 'endpoint': 'client',"
-                             "                 'dir': %s,"
-                             "                 'username': 'qemu'} }",
-                             data->workdir);
-
-    qtest_qmp_assert_success(to,
-                             "{ 'execute': 'object-add',"
-                             "  'arguments': { 'qom-type': 'tls-creds-psk',"
-                             "                 'id': 'tlscredspsk0',"
-                             "                 'endpoint': 'server',"
-                             "                 'dir': %s } }",
-                             args->mismatch ? data->workdiralt : data->workdir);
-
-    migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
-    migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
-
-    return data;
 }
 
-static void
-migrate_hook_end_tls_psk(QTestState *from,
-                         QTestState *to,
-                         void *opaque)
+static void migrate_tls_psk_cleanup(TestMigrateTLSPSKData *data)
 {
-    struct TestMigrateTLSPSKData *data = opaque;
-
     test_tls_psk_cleanup(data->pskfile);
     if (data->pskfilealt) {
         test_tls_psk_cleanup(data->pskfilealt);
@@ -113,6 +116,36 @@ migrate_hook_end_tls_psk(QTestState *from,
     g_free(data);
 }
 
+static void test_precopy_tls_psk_common(MigrateCommon *args,
+                                        TestMigrateTLSPSK *test_args)
+{
+    TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
+
+    migrate_tls_psk_init(args, test_args, data);
+    test_precopy_common(args);
+    migrate_tls_psk_cleanup(data);
+}
+
+static void test_postcopy_tls_psk_common(MigrateCommon *args,
+                                        TestMigrateTLSPSK *test_args)
+{
+    TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
+
+    migrate_tls_psk_init(args, test_args, data);
+    test_postcopy_common(args);
+    migrate_tls_psk_cleanup(data);
+}
+
+static void test_postcopy_recovery_tls_psk_common(MigrateCommon *args,
+                                                  TestMigrateTLSPSK *test_args)
+{
+    TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
+
+    migrate_tls_psk_init(args, test_args, data);
+    test_postcopy_recovery_common(args);
+    migrate_tls_psk_cleanup(data);
+}
+
 #ifdef CONFIG_TASN1
 typedef struct {
     char *workdir;
@@ -340,29 +373,26 @@ static void test_postcopy_tls_psk(char *name, MigrateCommon *args)
 {
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
-    args->end_hook = migrate_hook_end_tls_psk;
 
-    test_postcopy_common(args);
+    test_postcopy_tls_psk_common(args, &tls_psk_match);
 }
 
 static void test_postcopy_preempt_tls_psk(char *name, MigrateCommon *args)
 {
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
-    args->end_hook = migrate_hook_end_tls_psk;
 
     args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
 
-    test_postcopy_common(args);
+    test_postcopy_tls_psk_common(args, &tls_psk_match);
 }
 
 static void test_postcopy_recovery_tls_psk(char *name, MigrateCommon *args)
 {
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
-    args->end_hook = migrate_hook_end_tls_psk;
 
-    test_postcopy_recovery_common(args);
+    test_postcopy_recovery_tls_psk_common(args, &tls_psk_match);
 }
 
 static void test_multifd_postcopy_recovery_tls_psk(char *name,
@@ -370,11 +400,10 @@ static void test_multifd_postcopy_recovery_tls_psk(char *name,
 {
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
-    args->end_hook = migrate_hook_end_tls_psk;
 
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_postcopy_recovery_common(args);
+    test_postcopy_recovery_tls_psk_common(args, &tls_psk_match);
 }
 
 /* This contains preempt+recovery+tls test altogether */
@@ -382,11 +411,10 @@ static void test_postcopy_preempt_all(char *name, MigrateCommon *args)
 {
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
-    args->end_hook = migrate_hook_end_tls_psk;
 
     args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
 
-    test_postcopy_recovery_common(args);
+    test_postcopy_recovery_tls_psk_common(args, &tls_psk_match);
 }
 
 static void test_multifd_postcopy_preempt_recovery_tls_psk(char *name,
@@ -394,12 +422,11 @@ static void test_multifd_postcopy_preempt_recovery_tls_psk(char *name,
 {
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
-    args->end_hook = migrate_hook_end_tls_psk;
 
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
     args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
 
-    test_postcopy_recovery_common(args);
+    test_postcopy_recovery_tls_psk_common(args, &tls_psk_match);
 }
 
 static void test_precopy_unix_tls_psk(char *name, MigrateCommon *args)
@@ -410,9 +437,8 @@ static void test_precopy_unix_tls_psk(char *name, MigrateCommon *args)
     args->listen_uri = uri;
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
-    args->end_hook = migrate_hook_end_tls_psk;
 
-    test_precopy_common(args);
+    test_precopy_tls_psk_common(args, &tls_psk_match);
 }
 
 #ifdef CONFIG_TASN1
@@ -451,9 +477,8 @@ static void test_precopy_tcp_tls_psk_match(char *name, MigrateCommon *args)
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
-    args->end_hook = migrate_hook_end_tls_psk;
 
-    test_precopy_common(args);
+    test_precopy_tls_psk_common(args, &tls_psk_match);
 }
 
 static void test_precopy_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
@@ -461,30 +486,25 @@ static void test_precopy_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_mismatch;
-    args->end_hook = migrate_hook_end_tls_psk;
     args->result = MIG_TEST_FAIL;
 
     args->start.hide_stderr = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_psk_common(args, &tls_psk_mismatch);
 }
 
 static void *migrate_hook_start_no_tls(QTestState *from, QTestState *to)
 {
-    struct TestMigrateTLSPSKData *data =
-        g_new0(struct TestMigrateTLSPSKData, 1);
-
     migrate_set_parameter_null(from, "tls-creds");
     migrate_set_parameter_null(to, "tls-creds");
 
-    return data;
+    return NULL;
 }
 
 static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
     args->start_hook = migrate_hook_start_no_tls;
-    args->end_hook = migrate_hook_end_tls_psk;
 
     test_precopy_common(args);
 }
@@ -657,19 +677,17 @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
 static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
 {
     args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
-    args->end_hook = migrate_hook_end_tls_psk;
     args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_psk_common(args, &tls_psk_match);
 }
 
 static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
 {
     args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
-    args->end_hook = migrate_hook_end_tls_psk;
     args->result = MIG_TEST_FAIL;
     args->listen_uri = "tcp:127.0.0.1:0";
 
@@ -677,21 +695,20 @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_psk_common(args, &tls_psk_mismatch);
 }
 
 static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
                                                     MigrateCommon *args)
 {
     args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
-    args->end_hook = migrate_hook_end_tls_psk;
     args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
     args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
 
-    test_precopy_common(args);
+    test_precopy_tls_psk_common(args, &tls_psk_match);
 }
 
 #ifdef CONFIG_TASN1
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 42/51] tests/qtest/migration: Remove multifd compression hook
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (40 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 41/51] tests/qtest/migration: TLS PSK: Add init/cleanup routines Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 43/51] tests/qtest/migration: Convert postcopy tests to use config Fabiano Rosas
                   ` (9 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Remove the migrate_hook_start_precopy_tcp_multifd_common hook and open
code its contents in the callers. This will simplify moving the
migrate_set_parameters calls in the following patches.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/compression-tests.c | 25 ++++++++++++++++----
 tests/qtest/migration/framework.c         | 10 --------
 tests/qtest/migration/framework.h         |  4 ----
 tests/qtest/migration/precopy-tests.c     |  9 +++++---
 tests/qtest/migration/tls-tests.c         | 28 +++++++++++++++++------
 5 files changed, 47 insertions(+), 29 deletions(-)

diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
index bed39dece0..be60981f66 100644
--- a/tests/qtest/migration/compression-tests.c
+++ b/tests/qtest/migration/compression-tests.c
@@ -28,7 +28,10 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
     migrate_set_parameter_int(from, "multifd-zstd-level", 2);
     migrate_set_parameter_int(to, "multifd-zstd-level", 2);
 
-    return migrate_hook_start_precopy_tcp_multifd_common(from, to, "zstd");
+    migrate_set_parameter_str(from, "multifd-compression", "zstd");
+    migrate_set_parameter_str(to, "multifd-compression", "zstd");
+
+    return NULL;
 }
 
 static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
@@ -63,7 +66,10 @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
     migrate_set_parameter_int(from, "multifd-qatzip-level", 2);
     migrate_set_parameter_int(to, "multifd-qatzip-level", 2);
 
-    return migrate_hook_start_precopy_tcp_multifd_common(from, to, "qatzip");
+    migrate_set_parameter_str(from, "multifd-compression", "qatzip");
+    migrate_set_parameter_str(to, "multifd-compression", "qatzip");
+
+    return NULL;
 }
 
 static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
@@ -83,7 +89,10 @@ static void *
 migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
                                            QTestState *to)
 {
-    return migrate_hook_start_precopy_tcp_multifd_common(from, to, "qpl");
+    migrate_set_parameter_str(from, "multifd-compression", "qpl");
+    migrate_set_parameter_str(to, "multifd-compression", "qpl");
+
+    return NULL;
 }
 
 static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
@@ -103,7 +112,10 @@ static void *
 migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
                                             QTestState *to)
 {
-    return migrate_hook_start_precopy_tcp_multifd_common(from, to, "uadk");
+    migrate_set_parameter_str(from, "multifd-compression", "uadk");
+    migrate_set_parameter_str(to, "multifd-compression", "uadk");
+
+    return NULL;
 }
 
 static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
@@ -156,7 +168,10 @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
     migrate_set_parameter_int(from, "multifd-zlib-level", 2);
     migrate_set_parameter_int(to, "multifd-zlib-level", 2);
 
-    return migrate_hook_start_precopy_tcp_multifd_common(from, to, "zlib");
+    migrate_set_parameter_str(from, "multifd-compression", "zlib");
+    migrate_set_parameter_str(to, "multifd-compression", "zlib");
+
+    return NULL;
 }
 
 static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index b9bbdca6a9..ecfeee570e 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -1115,16 +1115,6 @@ finish:
     migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
 }
 
-void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from,
-                                                    QTestState *to,
-                                                    const char *method)
-{
-    migrate_set_parameter_str(from, "multifd-compression", method);
-    migrate_set_parameter_str(to, "multifd-compression", method);
-
-    return NULL;
-}
-
 QTestMigrationState *get_src(void)
 {
     return &src_state;
diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
index 2584599f14..239fc54f82 100644
--- a/tests/qtest/migration/framework.h
+++ b/tests/qtest/migration/framework.h
@@ -272,10 +272,6 @@ void test_postcopy_common(MigrateCommon *args);
 void test_postcopy_recovery_common(MigrateCommon *args);
 int test_precopy_common(MigrateCommon *args);
 void test_file_common(MigrateCommon *args, bool stop_src);
-void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from,
-                                                    QTestState *to,
-                                                    const char *method);
-
 typedef struct QTestMigrationState QTestMigrationState;
 QTestMigrationState *get_src(void);
 QTestMigrationState *get_dst(void);
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index 0b0f04bf19..01151301ce 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -452,14 +452,17 @@ static void *
 migrate_hook_start_precopy_tcp_multifd(QTestState *from,
                                        QTestState *to)
 {
-    return migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+    migrate_set_parameter_str(from, "multifd-compression", "none");
+    migrate_set_parameter_str(to, "multifd-compression", "none");
+
+    return NULL;
 }
 
 static void *
 migrate_hook_start_precopy_tcp_multifd_zero_page_legacy(QTestState *from,
                                                         QTestState *to)
 {
-    migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+    migrate_hook_start_precopy_tcp_multifd(from, to);
     migrate_set_parameter_str(from, "zero-page-detection", "legacy");
     return NULL;
 }
@@ -468,7 +471,7 @@ static void *
 migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from,
                                                     QTestState *to)
 {
-    migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+    migrate_hook_start_precopy_tcp_multifd(from, to);
     migrate_set_parameter_str(from, "zero-page-detection", "none");
     return NULL;
 }
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index aade57f7de..5f561bc602 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -616,7 +616,9 @@ static void *
 migrate_hook_start_multifd_tcp_tls_psk_match(QTestState *from,
                                              QTestState *to)
 {
-    migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+    migrate_set_parameter_str(from, "multifd-compression", "none");
+    migrate_set_parameter_str(to, "multifd-compression", "none");
+
     return migrate_hook_start_tls_psk_common(from, to, &tls_psk_match);
 }
 
@@ -624,7 +626,9 @@ static void *
 migrate_hook_start_multifd_tcp_tls_psk_mismatch(QTestState *from,
                                                 QTestState *to)
 {
-    migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+    migrate_set_parameter_str(from, "multifd-compression", "none");
+    migrate_set_parameter_str(to, "multifd-compression", "none");
+
     return migrate_hook_start_tls_psk_common(from, to, &tls_psk_mismatch);
 }
 
@@ -633,7 +637,9 @@ static void *
 migrate_hook_start_multifd_tls_x509_default_host(QTestState *from,
                                                  QTestState *to)
 {
-    migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+    migrate_set_parameter_str(from, "multifd-compression", "none");
+    migrate_set_parameter_str(to, "multifd-compression", "none");
+
     return migrate_hook_start_tls_x509_common(from, to, &tls_x509_default_host);
 }
 
@@ -641,7 +647,9 @@ static void *
 migrate_hook_start_multifd_tls_x509_override_host(QTestState *from,
                                                   QTestState *to)
 {
-    migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+    migrate_set_parameter_str(from, "multifd-compression", "none");
+    migrate_set_parameter_str(to, "multifd-compression", "none");
+
     return migrate_hook_start_tls_x509_common(from, to,
                                               &tls_x509_override_host);
 }
@@ -650,7 +658,9 @@ static void *
 migrate_hook_start_multifd_tls_x509_mismatch_host(QTestState *from,
                                                   QTestState *to)
 {
-    migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+    migrate_set_parameter_str(from, "multifd-compression", "none");
+    migrate_set_parameter_str(to, "multifd-compression", "none");
+
     return migrate_hook_start_tls_x509_common(from, to,
                                               &tls_x509_mismatch_host);
 }
@@ -659,7 +669,9 @@ static void *
 migrate_hook_start_multifd_tls_x509_allow_anon_client(QTestState *from,
                                                       QTestState *to)
 {
-    migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+    migrate_set_parameter_str(from, "multifd-compression", "none");
+    migrate_set_parameter_str(to, "multifd-compression", "none");
+
     return migrate_hook_start_tls_x509_common(from, to,
                                               &tls_x509_allow_anon_client);
 }
@@ -668,7 +680,9 @@ static void *
 migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
                                                        QTestState *to)
 {
-    migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
+    migrate_set_parameter_str(from, "multifd-compression", "none");
+    migrate_set_parameter_str(to, "multifd-compression", "none");
+
     return migrate_hook_start_tls_x509_common(from, to,
                                               &tls_x509_reject_anon_client);
 }
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 43/51] tests/qtest/migration: Convert postcopy tests to use config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (41 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 42/51] tests/qtest/migration: Remove multifd compression hook Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-18 22:03   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 44/51] tests/qtest/migration: Convert TLS PSK " Fabiano Rosas
                   ` (8 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Make the postcopy tests (including TLS) pass a config argument to
migration QMP commands.

Temporarily, set the use-config key to enable the new method.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/framework.c      | 10 ++++++++--
 tests/qtest/migration/postcopy-tests.c | 10 +++++-----
 tests/qtest/migration/tls-tests.c      | 14 +++++++++-----
 3 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index ecfeee570e..8f179ea2fa 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -582,8 +582,8 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
     QObject *channels;
 
     /* set postcopy capabilities */
-    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME] = true;
-    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
+    qdict_put_bool(args->start.config, "postcopy-blocktime", true);
+    qdict_put_bool(args->start.config, "postcopy-ram", true);
 
     if (migrate_start(&from, &to, "defer", &args->start)) {
         return -1;
@@ -652,6 +652,9 @@ void test_postcopy_common(MigrateCommon *args)
 {
     QTestState *from, *to;
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     if (migrate_postcopy_prepare(&from, &to, args)) {
         return;
     }
@@ -785,6 +788,9 @@ void test_postcopy_recovery_common(MigrateCommon *args)
     QTestState *from, *to;
     g_autofree char *uri = NULL;
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     /*
      * Always enable OOB QMP capability for recovery tests, migrate-recover is
      * executed out-of-band
diff --git a/tests/qtest/migration/postcopy-tests.c b/tests/qtest/migration/postcopy-tests.c
index 7ae4d765d7..5136a26abd 100644
--- a/tests/qtest/migration/postcopy-tests.c
+++ b/tests/qtest/migration/postcopy-tests.c
@@ -34,7 +34,7 @@ static void test_postcopy_suspend(char *name, MigrateCommon *args)
 
 static void test_postcopy_preempt(char *name, MigrateCommon *args)
 {
-    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
+    qdict_put_bool(args->start.config, "postcopy-preempt", true);
 
     test_postcopy_common(args);
 }
@@ -62,7 +62,7 @@ static void test_postcopy_recovery_fail_reconnect(char *name,
 
 static void test_postcopy_preempt_recovery(char *name, MigrateCommon *args)
 {
-    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
+    qdict_put_bool(args->start.config, "postcopy-preempt", true);
 
     test_postcopy_recovery_common(args);
 }
@@ -80,15 +80,15 @@ static void migration_test_add_postcopy_smoke(MigrationTestEnv *env)
 
 static void test_multifd_postcopy(char *name, MigrateCommon *args)
 {
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+    qdict_put_bool(args->start.config, "multifd", true);
 
     test_postcopy_common(args);
 }
 
 static void test_multifd_postcopy_preempt(char *name, MigrateCommon *args)
 {
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
-    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_bool(args->start.config, "postcopy-preempt", true);
 
     test_postcopy_common(args);
 }
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 5f561bc602..abd6bf9281 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -131,6 +131,8 @@ static void test_postcopy_tls_psk_common(MigrateCommon *args,
 {
     TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
 
+    qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
+
     migrate_tls_psk_init(args, test_args, data);
     test_postcopy_common(args);
     migrate_tls_psk_cleanup(data);
@@ -141,6 +143,8 @@ static void test_postcopy_recovery_tls_psk_common(MigrateCommon *args,
 {
     TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
 
+    qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
+
     migrate_tls_psk_init(args, test_args, data);
     test_postcopy_recovery_common(args);
     migrate_tls_psk_cleanup(data);
@@ -382,7 +386,7 @@ static void test_postcopy_preempt_tls_psk(char *name, MigrateCommon *args)
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
 
-    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
+    qdict_put_bool(args->start.config, "postcopy-preempt", true);
 
     test_postcopy_tls_psk_common(args, &tls_psk_match);
 }
@@ -401,7 +405,7 @@ static void test_multifd_postcopy_recovery_tls_psk(char *name,
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
 
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+    qdict_put_bool(args->start.config, "multifd", true);
 
     test_postcopy_recovery_tls_psk_common(args, &tls_psk_match);
 }
@@ -412,7 +416,7 @@ static void test_postcopy_preempt_all(char *name, MigrateCommon *args)
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
 
-    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
+    qdict_put_bool(args->start.config, "postcopy-preempt", true);
 
     test_postcopy_recovery_tls_psk_common(args, &tls_psk_match);
 }
@@ -423,8 +427,8 @@ static void test_multifd_postcopy_preempt_recovery_tls_psk(char *name,
     args->start_hook_full = migrate_hook_start_tls_psk_common;
     args->start_hook_data = &tls_psk_match;
 
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
-    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true;
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_bool(args->start.config, "postcopy-preempt", true);
 
     test_postcopy_recovery_tls_psk_common(args, &tls_psk_match);
 }
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 44/51] tests/qtest/migration: Convert TLS PSK tests to use config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (42 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 43/51] tests/qtest/migration: Convert postcopy tests to use config Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-18 22:14   ` Peter Xu
  2025-12-15 22:00 ` [PATCH v3 45/51] tests/qtest/migration: Convert TLS x509 " Fabiano Rosas
                   ` (7 subsequent siblings)
  51 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Replace calls to migrate_set_parameters and the usage of args.caps
with the new config object API.

The multifd tests are now the same as the "precopy" tests, only
setting some multifd options, so reuse the precopy code.

Temporarily, set the use-config key to enable the new method.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/tls-tests.c | 72 +++++++++----------------------
 1 file changed, 20 insertions(+), 52 deletions(-)

diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index abd6bf9281..68304a7af3 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -73,9 +73,6 @@ static void *migrate_hook_start_tls_psk_common(QTestState *from,
                              "                 'dir': %s } }",
                              args->mismatch ? workdiralt : workdir);
 
-    migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
-    migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
-
     return NULL;
 }
 
@@ -121,6 +118,11 @@ static void test_precopy_tls_psk_common(MigrateCommon *args,
 {
     TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
+    qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
+
     migrate_tls_psk_init(args, test_args, data);
     test_precopy_common(args);
     migrate_tls_psk_cleanup(data);
@@ -497,18 +499,11 @@ static void test_precopy_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
     test_precopy_tls_psk_common(args, &tls_psk_mismatch);
 }
 
-static void *migrate_hook_start_no_tls(QTestState *from, QTestState *to)
-{
-    migrate_set_parameter_null(from, "tls-creds");
-    migrate_set_parameter_null(to, "tls-creds");
-
-    return NULL;
-}
-
 static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_no_tls;
+
+    qdict_put_null(args->start.config, "tls-creds");
 
     test_precopy_common(args);
 }
@@ -614,29 +609,7 @@ static void test_precopy_tcp_tls_x509_reject_anon_client(char *name,
 
     test_precopy_tls_x509_common(args, &tls_x509_reject_anon_client);
 }
-#endif /* CONFIG_TASN1 */
 
-static void *
-migrate_hook_start_multifd_tcp_tls_psk_match(QTestState *from,
-                                             QTestState *to)
-{
-    migrate_set_parameter_str(from, "multifd-compression", "none");
-    migrate_set_parameter_str(to, "multifd-compression", "none");
-
-    return migrate_hook_start_tls_psk_common(from, to, &tls_psk_match);
-}
-
-static void *
-migrate_hook_start_multifd_tcp_tls_psk_mismatch(QTestState *from,
-                                                QTestState *to)
-{
-    migrate_set_parameter_str(from, "multifd-compression", "none");
-    migrate_set_parameter_str(to, "multifd-compression", "none");
-
-    return migrate_hook_start_tls_psk_common(from, to, &tls_psk_mismatch);
-}
-
-#ifdef CONFIG_TASN1
 static void *
 migrate_hook_start_multifd_tls_x509_default_host(QTestState *from,
                                                  QTestState *to)
@@ -694,39 +667,34 @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
 
 static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
-    args->listen_uri = "tcp:127.0.0.1:0";
-
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_precopy_tls_psk_common(args, &tls_psk_match);
+    qdict_put_str(args->start.config, "multifd-compression", "none");
+    qdict_put_bool(args->start.config, "multifd", true);
+
+    test_precopy_tcp_tls_psk_match(name, args);
 }
 
 static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
-    args->result = MIG_TEST_FAIL;
-    args->listen_uri = "tcp:127.0.0.1:0";
-
-    args->start.hide_stderr = true;
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
-    test_precopy_tls_psk_common(args, &tls_psk_mismatch);
+    qdict_put_str(args->start.config, "multifd-compression", "none");
+    qdict_put_bool(args->start.config, "multifd", true);
+
+    test_precopy_tcp_tls_psk_mismatch(name, args);
 }
 
 static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
                                                     MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
-    args->listen_uri = "tcp:127.0.0.1:0";
-
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
-    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
 
-    test_precopy_tls_psk_common(args, &tls_psk_match);
+    qdict_put_str(args->start.config, "multifd-compression", "none");
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_bool(args->start.config, "postcopy-ram", true);
+
+    test_precopy_tcp_tls_psk_match(name, args);
 }
 
 #ifdef CONFIG_TASN1
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 45/51] tests/qtest/migration: Convert TLS x509 tests to use config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (43 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 44/51] tests/qtest/migration: Convert TLS PSK " Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 46/51] tests/qtest/migration: Convert compression " Fabiano Rosas
                   ` (6 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Convert the TLS x509 tests to start passing the config object to the
migration commands. Replace the usage of migrate_set_parameters and
args->caps with the config QDict.

Note that the TLS credentials id is different among the two migration
machines so it cannot follow the standard practice of setting the same
value for both QTestState instances (i.e. from/to). This is a issue
specific to the test code because it uses the same config object for
both QEMU instances. Since this is a one-off, add a workaround
specific for that situation.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/framework.c      |  11 +-
 tests/qtest/migration/migration-util.c |  44 ++++++++
 tests/qtest/migration/migration-util.h |   1 +
 tests/qtest/migration/tls-tests.c      | 139 +++++++------------------
 4 files changed, 92 insertions(+), 103 deletions(-)

diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 8f179ea2fa..44ef80cf0c 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -429,8 +429,10 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
      */
     events = args->defer_target_connect ? "-global migration.x-events=on" : "";
 
-    if (args->config) {
-        GString *json = qobject_to_json(QOBJECT(args->config));
+    if (!args->incoming_defer && args->config) {
+        QDict *conf = fixup_tls_creds(args->config);
+        GString *json = qobject_to_json(QOBJECT(conf));
+
         config_opts = g_strdup_printf("-incoming '%s'", json->str);
     }
 
@@ -883,12 +885,15 @@ int test_precopy_common(MigrateCommon *args)
     }
 
     if (args->start.incoming_defer && !args->start.defer_target_connect) {
+        QDict *incoming_conf = fixup_tls_creds(args->start.config);
+
         if (args->connect_channels) {
             in_channels = qobject_from_json(args->connect_channels,
                                             &error_abort);
         }
+
         migrate_incoming_qmp(to, args->listen_uri, in_channels,
-                             args->start.config, "{}");
+                             incoming_conf, "{}");
     }
 
     /* Wait for the first serial output from the source */
diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
index e702f00896..efe1ae25de 100644
--- a/tests/qtest/migration/migration-util.c
+++ b/tests/qtest/migration/migration-util.c
@@ -395,3 +395,47 @@ bool kvm_dirty_ring_supported(void)
     return false;
 #endif
 }
+
+QDict *fixup_tls_creds(QDict *config)
+{
+    QDict *new;
+
+    if (!config) {
+        return NULL;
+    }
+
+    /*
+     * The tests expect the tls-creds to have different values for
+     * client and server, but there's only one config object. The
+     * tls-tests have passed the values in the two temporary keys
+     * below.
+     */
+    const char *server = qdict_get_try_str(config, "tmp-tls-server");
+    const char *client = qdict_get_try_str(config, "tmp-tls-client");
+
+    if (server && client) {
+        new = qdict_clone_shallow(config);
+
+        /*
+         * Set the proper value for the incoming side and discard the
+         * temporaries. Note that removing the temporaries cannot
+         * happen before cloning because the qdict code frees the
+         * strings.
+         */
+        qdict_put_str(new, "tls-creds", server);
+        qdict_del(new, "tmp-tls-client");
+        qdict_del(new, "tmp-tls-server");
+
+        /*
+         * Set the value for the outgoing side for further usage
+         * outside this function.
+         */
+        qdict_put_str(config, "tls-creds", client);
+        qdict_del(config, "tmp-tls-client");
+        qdict_del(config, "tmp-tls-server");
+
+        return new;
+    }
+
+    return config;
+}
diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
index 3c3b5a8777..ec58868197 100644
--- a/tests/qtest/migration/migration-util.h
+++ b/tests/qtest/migration/migration-util.h
@@ -59,6 +59,7 @@ void migration_test_add_suffix(const char *path, const char *suffix,
                                void (*fn)(char *name, MigrateCommon *args));
 char *migrate_get_connect_uri(QTestState *who);
 void migrate_set_ports(QTestState *to, QList *channel_list);
+QDict *fixup_tls_creds(QDict *config);
 
 /*
  * Scaffolding to allow the framework _common functions and _qmp
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index 68304a7af3..b6d436389a 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -259,10 +259,6 @@ migrate_hook_start_tls_x509_common(QTestState *from,
                              "                 'sanity-check': true,"
                              "                 'verify-peer': true} }",
                              workdir);
-    migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0");
-    if (args->certhostname) {
-        migrate_set_parameter_str(from, "tls-hostname", args->certhostname);
-    }
 
     qtest_qmp_assert_success(to,
                              "{ 'execute': 'object-add',"
@@ -273,7 +269,6 @@ migrate_hook_start_tls_x509_common(QTestState *from,
                              "                 'sanity-check': true,"
                              "                 'verify-peer': %i} }",
                              workdir, args->verifyclient);
-    migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0");
 
     if (args->authzclient) {
         qtest_qmp_assert_success(to,
@@ -282,7 +277,6 @@ migrate_hook_start_tls_x509_common(QTestState *from,
                                  "                 'id': 'tlsauthz0',"
                                  "                 'identity': %s} }",
                                  "CN=" QCRYPTO_TLS_TEST_CLIENT_NAME);
-        migrate_set_parameter_str(to, "tls-authz", "tlsauthz0");
     }
 
     return NULL;
@@ -335,6 +329,28 @@ static void migrate_tls_x509_init(MigrateCommon *args,
                                test_args->certipaddr);
     test_tls_deinit_cert(&clientcertreq);
     test_tls_deinit_cert(&cacertreq);
+
+    /*
+     * These keys are not actual parameters, we need them for the test
+     * code because it uses the same config object for both QEMUs.
+     */
+    qdict_put_str(args->start.config, "tmp-tls-client", "tlscredsx509client0");
+    qdict_put_str(args->start.config, "tmp-tls-server", "tlscredsx509server0");
+
+    if (test_args->certhostname) {
+        qdict_put_str(args->start.config, "tls-hostname",
+                      test_args->certhostname);
+    } else {
+        qdict_put_null(args->start.config, "tls-hostname");
+    }
+
+    if (test_args->authzclient) {
+        qdict_put_str(args->start.config, "tls-authz", "tlsauthz0");
+    }
+
+    if (qdict_get_try_bool(args->start.config, "multifd", false)) {
+        qdict_put_str(args->start.config, "multifd-compression", "none");
+    }
 }
 
 static void migrate_tls_x509_cleanup(TestMigrateTLSX509Data *data)
@@ -369,6 +385,9 @@ static void test_precopy_tls_x509_common(MigrateCommon *args,
 {
     TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     migrate_tls_x509_init(args, test_args, data);
     test_precopy_common(args);
     migrate_tls_x509_cleanup(data);
@@ -508,21 +527,11 @@ static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args)
     test_precopy_common(args);
 }
 
-static void *
-migrate_hook_start_tls_x509_no_host(QTestState *from, QTestState *to)
-{
-    TestMigrateTLSX509Data *data = migrate_hook_start_tls_x509_common(
-        from, to, &tls_x509_no_host);
-    migrate_set_parameter_null(from, "tls-hostname");
-    migrate_set_parameter_null(to, "tls-hostname");
-
-    return data;
-}
-
 static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_tls_x509_no_host;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &tls_x509_no_host;
     args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
 
     args->start.hide_stderr = true;
@@ -609,60 +618,6 @@ static void test_precopy_tcp_tls_x509_reject_anon_client(char *name,
 
     test_precopy_tls_x509_common(args, &tls_x509_reject_anon_client);
 }
-
-static void *
-migrate_hook_start_multifd_tls_x509_default_host(QTestState *from,
-                                                 QTestState *to)
-{
-    migrate_set_parameter_str(from, "multifd-compression", "none");
-    migrate_set_parameter_str(to, "multifd-compression", "none");
-
-    return migrate_hook_start_tls_x509_common(from, to, &tls_x509_default_host);
-}
-
-static void *
-migrate_hook_start_multifd_tls_x509_override_host(QTestState *from,
-                                                  QTestState *to)
-{
-    migrate_set_parameter_str(from, "multifd-compression", "none");
-    migrate_set_parameter_str(to, "multifd-compression", "none");
-
-    return migrate_hook_start_tls_x509_common(from, to,
-                                              &tls_x509_override_host);
-}
-
-static void *
-migrate_hook_start_multifd_tls_x509_mismatch_host(QTestState *from,
-                                                  QTestState *to)
-{
-    migrate_set_parameter_str(from, "multifd-compression", "none");
-    migrate_set_parameter_str(to, "multifd-compression", "none");
-
-    return migrate_hook_start_tls_x509_common(from, to,
-                                              &tls_x509_mismatch_host);
-}
-
-static void *
-migrate_hook_start_multifd_tls_x509_allow_anon_client(QTestState *from,
-                                                      QTestState *to)
-{
-    migrate_set_parameter_str(from, "multifd-compression", "none");
-    migrate_set_parameter_str(to, "multifd-compression", "none");
-
-    return migrate_hook_start_tls_x509_common(from, to,
-                                              &tls_x509_allow_anon_client);
-}
-
-static void *
-migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
-                                                       QTestState *to)
-{
-    migrate_set_parameter_str(from, "multifd-compression", "none");
-    migrate_set_parameter_str(to, "multifd-compression", "none");
-
-    return migrate_hook_start_tls_x509_common(from, to,
-                                              &tls_x509_reject_anon_client);
-}
 #endif /* CONFIG_TASN1 */
 
 static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
@@ -701,25 +656,17 @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
 static void test_multifd_tcp_tls_x509_default_host(char *name,
                                                    MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
-    args->listen_uri = "tcp:127.0.0.1:0";
-
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
-
-    test_precopy_tls_x509_common(args, &tls_x509_default_host);
+    qdict_put_bool(args->start.config, "multifd", true);
+    test_precopy_tcp_tls_x509_default_host(name, args);
 }
 
 static void test_multifd_tcp_tls_x509_override_host(char *name,
                                                     MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
-    args->listen_uri = "tcp:127.0.0.1:0";
-
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
-
-    test_precopy_tls_x509_common(args, &tls_x509_override_host);
+    qdict_put_bool(args->start.config, "multifd", true);
+    test_precopy_tcp_tls_x509_override_host(name, args);
 }
 
 static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
@@ -738,13 +685,15 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
      * to load migration state, and thus just aborts the migration
      * without exiting.
      */
-    args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = &tls_x509_mismatch_host;
     args->result = MIG_TEST_FAIL;
     args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
     args->start.hide_stderr = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    qdict_put_bool(args->start.config, "multifd", true);
 
     test_precopy_tls_x509_common(args, &tls_x509_mismatch_host);
 }
@@ -752,27 +701,17 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
 static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
                                                         MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
-    args->listen_uri = "tcp:127.0.0.1:0";
-
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
-
-    test_precopy_tls_x509_common(args, &tls_x509_allow_anon_client);
+    qdict_put_bool(args->start.config, "multifd", true);
+    test_precopy_tcp_tls_x509_allow_anon_client(name, args);
 }
 
 static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
                                                          MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
-    args->result = MIG_TEST_FAIL;
-    args->listen_uri = "tcp:127.0.0.1:0";
-
     args->start.incoming_defer = true;
-    args->start.hide_stderr = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
-
-    test_precopy_tls_x509_common(args, &tls_x509_reject_anon_client);
+    qdict_put_bool(args->start.config, "multifd", true);
+    test_precopy_tcp_tls_x509_reject_anon_client(name, args);
 }
 #endif /* CONFIG_TASN1 */
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 46/51] tests/qtest/migration: Convert compression tests to use config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (44 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 45/51] tests/qtest/migration: Convert TLS x509 " Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 47/51] tests/qtest/migration: Convert file " Fabiano Rosas
                   ` (5 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Make the compression tests pass a config argument to migration QMP
commands.

Temporarily, set the use-config key to enable the new method.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/compression-tests.c | 132 ++++++++--------------
 1 file changed, 47 insertions(+), 85 deletions(-)

diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
index be60981f66..ff3386f586 100644
--- a/tests/qtest/migration/compression-tests.c
+++ b/tests/qtest/migration/compression-tests.c
@@ -21,26 +21,16 @@
 static char *tmpfs;
 
 #ifdef CONFIG_ZSTD
-static void *
-migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
-                                            QTestState *to)
-{
-    migrate_set_parameter_int(from, "multifd-zstd-level", 2);
-    migrate_set_parameter_int(to, "multifd-zstd-level", 2);
-
-    migrate_set_parameter_str(from, "multifd-compression", "zstd");
-    migrate_set_parameter_str(to, "multifd-compression", "zstd");
-
-    return NULL;
-}
-
 static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    qdict_put_bool(args->start.config, "multifd", true);
+
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
 
     test_precopy_common(args);
 }
@@ -48,103 +38,79 @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
 static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
-    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
+
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_bool(args->start.config, "postcopy-ram", true);
+    qdict_put_int(args->start.config, "multifd-zstd-level", 2);
+    qdict_put_str(args->start.config, "multifd-compression", "zstd");
+
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
 
     test_precopy_common(args);
 }
 #endif /* CONFIG_ZSTD */
 
 #ifdef CONFIG_QATZIP
-static void *
-migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
-                                              QTestState *to)
-{
-    migrate_set_parameter_int(from, "multifd-qatzip-level", 2);
-    migrate_set_parameter_int(to, "multifd-qatzip-level", 2);
-
-    migrate_set_parameter_str(from, "multifd-compression", "qatzip");
-    migrate_set_parameter_str(to, "multifd-compression", "qatzip");
-
-    return NULL;
-}
-
 static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_int(args->start.config, "multifd-qatzip-level", 2);
+    qdict_put_str(args->start.config, "multifd-compression", "qatzip");
+
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
 
     test_precopy_common(args);
 }
 #endif
 
 #ifdef CONFIG_QPL
-static void *
-migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
-                                           QTestState *to)
-{
-    migrate_set_parameter_str(from, "multifd-compression", "qpl");
-    migrate_set_parameter_str(to, "multifd-compression", "qpl");
-
-    return NULL;
-}
-
 static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_str(args->start.config, "multifd-compression", "qpl");
+
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
 
     test_precopy_common(args);
 }
 #endif /* CONFIG_QPL */
 
 #ifdef CONFIG_UADK
-static void *
-migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
-                                            QTestState *to)
-{
-    migrate_set_parameter_str(from, "multifd-compression", "uadk");
-    migrate_set_parameter_str(to, "multifd-compression", "uadk");
-
-    return NULL;
-}
-
 static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_str(args->start.config, "multifd-compression", "uadk");
+
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
 
     test_precopy_common(args);
 }
 #endif /* CONFIG_UADK */
 
-static void *
-migrate_hook_start_xbzrle(QTestState *from,
-                          QTestState *to)
-{
-    migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432);
-    return NULL;
-}
-
 static void test_precopy_unix_xbzrle(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
 
     args->connect_uri = uri;
     args->listen_uri = uri;
-    args->start_hook = migrate_hook_start_xbzrle;
     args->iterations = 2;
     /*
      * XBZRLE needs pages to be modified when doing the 2nd+ round
@@ -152,35 +118,31 @@ static void test_precopy_unix_xbzrle(char *name, MigrateCommon *args)
      */
     args->live = true;
 
-    args->start.caps[MIGRATION_CAPABILITY_XBZRLE] = true;
+    qdict_put_bool(args->start.config, "xbzrle", true);
+    qdict_put_int(args->start.config, "xbzrle-cache-size", 33554432);
+
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
 
     test_precopy_common(args);
 }
 
-static void *
-migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
-                                            QTestState *to)
+static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
 {
+    args->listen_uri = "tcp:127.0.0.1:0";
+
+    args->start.incoming_defer = true;
+    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
     /*
      * Overloading this test to also check that set_parameter does not error.
      * This is also done in the tests for the other compression methods.
      */
-    migrate_set_parameter_int(from, "multifd-zlib-level", 2);
-    migrate_set_parameter_int(to, "multifd-zlib-level", 2);
+    qdict_put_int(args->start.config, "multifd-zlib-level", 2);
+    qdict_put_str(args->start.config, "multifd-compression", "zlib");
 
-    migrate_set_parameter_str(from, "multifd-compression", "zlib");
-    migrate_set_parameter_str(to, "multifd-compression", "zlib");
-
-    return NULL;
-}
-
-static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
-{
-    args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib;
-
-    args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
 
     test_precopy_common(args);
 }
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 47/51] tests/qtest/migration: Convert file tests to use config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (45 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 46/51] tests/qtest/migration: Convert compression " Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 48/51] tests/qtest/migration: Convert misc-tests " Fabiano Rosas
                   ` (4 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Convert the file tests (including CPR) to use the config object.

The 'events' line can be removed because the capability is always set
in the config QDict in common code.

Temporarily, set the use-config key to enable the new method.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/cpr-tests.c  | 51 ++++++++++++++----------------
 tests/qtest/migration/file-tests.c | 39 ++++++++---------------
 tests/qtest/migration/framework.c  |  3 ++
 3 files changed, 41 insertions(+), 52 deletions(-)

diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
index 9883616cb5..a1b5a39f9f 100644
--- a/tests/qtest/migration/cpr-tests.c
+++ b/tests/qtest/migration/cpr-tests.c
@@ -21,14 +21,6 @@
 
 static char *tmpfs;
 
-static void *migrate_hook_start_mode_reboot(QTestState *from, QTestState *to)
-{
-    migrate_set_parameter_str(from, "mode", "cpr-reboot");
-    migrate_set_parameter_str(to, "mode", "cpr-reboot");
-
-    return NULL;
-}
-
 static void test_mode_reboot(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
@@ -36,21 +28,15 @@ static void test_mode_reboot(char *name, MigrateCommon *args)
 
     args->listen_uri = uri;
     args->connect_uri = uri;
-    args->start_hook = migrate_hook_start_mode_reboot;
 
     args->start.incoming_defer = true;
     args->start.mem_type = MEM_TYPE_SHMEM;
-    args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
 
+    qdict_put_bool(args->start.config, "x-ignore-shared", true);
+    qdict_put_str(args->start.config, "mode", "cpr-reboot");
     test_file_common(args, true);
 }
 
-static void *test_mode_transfer_start(QTestState *from, QTestState *to)
-{
-    migrate_set_parameter_str(from, "mode", "cpr-transfer");
-    return NULL;
-}
-
 /*
  * cpr-transfer mode cannot use the target monitor prior to starting the
  * migration, and cannot connect synchronously to the monitor, so defer
@@ -94,13 +80,17 @@ static void test_mode_transfer_common(MigrateCommon *args)
     args->listen_uri = uri;
     args->connect_channels = connect_channels;
     args->cpr_channel = cpr_channel;
-    args->start_hook = test_mode_transfer_start;
 
     args->start.opts_source = opts;
     args->start.opts_target = opts_target;
     args->start.defer_target_connect = true;
     args->start.mem_type = MEM_TYPE_MEMFD;
 
+    qdict_put_str(args->start.config, "mode", "cpr-transfer");
+
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     if (test_precopy_common(args) < 0) {
         close(cpr_sockfd);
         unlink(cpr_path);
@@ -119,6 +109,18 @@ static void test_mode_transfer_defer(char *name, MigrateCommon *args)
     test_mode_transfer_common(args);
 }
 
+static void set_cpr_exec_command(QDict *config, char **strv)
+{
+    QList *list = qlist_new();
+
+    while (*strv) {
+        qlist_append_str(list, *strv);
+        strv++;
+    }
+
+    qdict_put_obj(config, "cpr-exec-command", (QObject *)list);
+}
+
 static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
 {
     g_autofree char *qtest_from_args = NULL;
@@ -157,7 +159,7 @@ static void set_cpr_exec_args(QTestState *who, MigrateCommon *args)
     exec_args = g_strconcat(qtest_qemu_binary(migration_get_env()->qemu_dst),
                             " -incoming defer ", from_str, NULL);
     argv = g_strsplit(exec_args, " ", -1);
-    migrate_set_parameter_strv(who, "cpr-exec-command", argv);
+    set_cpr_exec_command(args->start.config, argv);
 }
 
 static void wait_for_migration_event(QTestState *who, const char *waitfor)
@@ -187,6 +189,9 @@ static void test_cpr_exec(MigrateCommon *args)
                                                 FILE_TEST_FILENAME);
     g_autofree char *channels = NULL;
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     if (migrate_start(&from, NULL, args->listen_uri, &args->start)) {
         return;
     }
@@ -200,7 +205,6 @@ static void test_cpr_exec(MigrateCommon *args)
 
     wait_for_serial("src_serial");
     set_cpr_exec_args(from, args);
-    migrate_set_capability(from, "events", true);
     migrate_qmp(from, NULL, connect_uri, NULL, args->start.config, "{}");
     wait_for_migration_event(from, "completed");
 
@@ -229,13 +233,6 @@ static void test_cpr_exec(MigrateCommon *args)
     migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
 }
 
-static void *test_mode_exec_start(QTestState *from, QTestState *to)
-{
-    assert(!to);
-    migrate_set_parameter_str(from, "mode", "cpr-exec");
-    return NULL;
-}
-
 static void test_mode_exec(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
@@ -244,12 +241,12 @@ static void test_mode_exec(char *name, MigrateCommon *args)
 
     args->connect_uri = uri;
     args->listen_uri = listen_uri;
-    args->start_hook = test_mode_exec_start;
 
     args->start.only_source = true;
     args->start.opts_source = "-machine aux-ram-share=on -nodefaults";
     args->start.mem_type = MEM_TYPE_MEMFD;
 
+    qdict_put_str(args->start.config, "mode", "cpr-exec");
     test_cpr_exec(args);
 }
 
diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
index 57117b2496..c7a4eb145b 100644
--- a/tests/qtest/migration/file-tests.c
+++ b/tests/qtest/migration/file-tests.c
@@ -118,8 +118,8 @@ static void test_precopy_file_mapped_ram_live(char *name, MigrateCommon *args)
     args->listen_uri = uri;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
 
+    qdict_put_bool(args->start.config, "mapped-ram", true);
     test_file_common(args, false);
 }
 
@@ -132,8 +132,8 @@ static void test_precopy_file_mapped_ram(char *name, MigrateCommon *args)
     args->listen_uri = uri;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
 
+    qdict_put_bool(args->start.config, "mapped-ram", true);
     test_file_common(args, true);
 }
 
@@ -145,9 +145,9 @@ static void test_multifd_file_mapped_ram_live(char *name, MigrateCommon *args)
     args->listen_uri = uri;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
-    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
 
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_bool(args->start.config, "mapped-ram", true);
     test_file_common(args, false);
 }
 
@@ -160,38 +160,29 @@ static void test_multifd_file_mapped_ram(char *name, MigrateCommon *args)
     args->listen_uri = uri;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
-    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
 
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_bool(args->start.config, "mapped-ram", true);
     test_file_common(args, true);
 }
 
-static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from,
-                                                       QTestState *to)
-{
-    migrate_set_parameter_bool(from, "direct-io", true);
-    migrate_set_parameter_bool(to, "direct-io", true);
-
-    return NULL;
-}
-
 static void test_multifd_file_mapped_ram_dio(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
     args->connect_uri = uri;
     args->listen_uri = uri;
-    args->start_hook = migrate_hook_start_multifd_mapped_ram_dio;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     if (!probe_o_direct_support(tmpfs)) {
         g_test_skip("Filesystem does not support O_DIRECT");
         return;
     }
 
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_bool(args->start.config, "mapped-ram", true);
+    qdict_put_bool(args->start.config, "direct-io", true);
     test_file_common(args, true);
 }
 
@@ -230,9 +221,6 @@ static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from,
     fdset_add_fds(from, file, O_WRONLY, 2, true);
     fdset_add_fds(to, file, O_RDONLY, 2, true);
 
-    migrate_set_parameter_bool(from, "direct-io", true);
-    migrate_set_parameter_bool(to, "direct-io", true);
-
     return NULL;
 }
 
@@ -258,9 +246,9 @@ static void test_multifd_file_mapped_ram_fdset(char *name, MigrateCommon *args)
     args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_bool(args->start.config, "mapped-ram", true);
     test_file_common(args, true);
 }
 
@@ -276,14 +264,15 @@ static void test_multifd_file_mapped_ram_fdset_dio(char *name,
     args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset;
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
 
     if (!probe_o_direct_support(tmpfs)) {
         g_test_skip("Filesystem does not support O_DIRECT");
         return;
     }
 
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_bool(args->start.config, "mapped-ram", true);
+    qdict_put_bool(args->start.config, "direct-io", true);
     test_file_common(args, true);
 }
 #endif /* !_WIN32 */
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 44ef80cf0c..6cf2bbf9cc 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -1056,6 +1056,9 @@ void test_file_common(MigrateCommon *args, bool stop_src)
     void *data_hook = NULL;
     bool check_offset = false;
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
         return;
     }
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 48/51] tests/qtest/migration: Convert misc-tests to use config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (46 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 47/51] tests/qtest/migration: Convert file " Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 49/51] tests/qtest/migration: Convert precopy tests " Fabiano Rosas
                   ` (3 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Make the misc tests pass a config argument to migration QMP commands.

Temporarily, set the use-config key to enable the new method.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/misc-tests.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
index c62fd1e3f9..7e38d26ab2 100644
--- a/tests/qtest/migration/misc-tests.c
+++ b/tests/qtest/migration/misc-tests.c
@@ -28,6 +28,9 @@ static void test_baddest(char *name, MigrateCommon *args)
 
     args->start.hide_stderr = true;
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) {
         return;
     }
@@ -52,6 +55,9 @@ static void test_analyze_script(char *name, MigrateCommon *args)
         return;
     }
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     /* dummy url */
     if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) {
         return;
@@ -62,8 +68,8 @@ static void test_analyze_script(char *name, MigrateCommon *args)
      * vmstate to include subsections for them. The script needs to
      * parse those subsections properly.
      */
-    migrate_set_capability(from, "validate-uuid", true);
-    migrate_set_capability(from, "x-ignore-shared", true);
+    qdict_put_bool(args->start.config, "validate-uuid", true);
+    qdict_put_bool(args->start.config, "x-ignore-shared", true);
 
     file = g_strdup_printf("%s/migfile", tmpfs);
     uri = g_strdup_printf("exec:cat > %s", file);
@@ -96,7 +102,11 @@ static void test_ignore_shared(char *name, MigrateCommon *args)
     QTestState *from, *to;
 
     args->start.mem_type = MEM_TYPE_SHMEM;
-    args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
+
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
+    qdict_put_bool(args->start.config, "x-ignore-shared", true);
 
     if (migrate_start(&from, &to, uri, &args->start)) {
         return;
@@ -131,6 +141,9 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
     QTestState *from, *to;
 
+    /* temporary */
+    qdict_put_bool(args->config, "use-config", true);
+
     if (migrate_start(&from, &to, uri, args)) {
         return;
     }
@@ -140,8 +153,8 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
      * migration is not interesting for us here. Thus, set huge downtime for
      * very fast migration.
      */
-    migrate_set_parameter_int(from, "downtime-limit", 1000000);
-    migrate_set_capability(from, "validate-uuid", true);
+    qdict_put_int(args->config, "downtime-limit", 1000000);
+    qdict_put_bool(args->config, "validate-uuid", true);
 
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 49/51] tests/qtest/migration: Convert precopy tests to use config
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (47 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 48/51] tests/qtest/migration: Convert misc-tests " Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 50/51] tests/qtest/migration: Remove migrate_set_capabilities and code around it Fabiano Rosas
                   ` (2 subsequent siblings)
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Make the precopy tests pass a config argument to migration QMP
commands.

Temporarily, set the use-config key to enable the new method.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/compression-tests.c |  21 ----
 tests/qtest/migration/cpr-tests.c         |   3 -
 tests/qtest/migration/framework.c         |   5 +-
 tests/qtest/migration/precopy-tests.c     | 111 ++++++++--------------
 tests/qtest/migration/tls-tests.c         |   6 --
 5 files changed, 46 insertions(+), 100 deletions(-)

diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
index ff3386f586..7ecb10d9a8 100644
--- a/tests/qtest/migration/compression-tests.c
+++ b/tests/qtest/migration/compression-tests.c
@@ -29,9 +29,6 @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
 
     qdict_put_bool(args->start.config, "multifd", true);
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     test_precopy_common(args);
 }
 
@@ -46,9 +43,6 @@ static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
     qdict_put_int(args->start.config, "multifd-zstd-level", 2);
     qdict_put_str(args->start.config, "multifd-compression", "zstd");
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     test_precopy_common(args);
 }
 #endif /* CONFIG_ZSTD */
@@ -64,9 +58,6 @@ static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
     qdict_put_int(args->start.config, "multifd-qatzip-level", 2);
     qdict_put_str(args->start.config, "multifd-compression", "qatzip");
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     test_precopy_common(args);
 }
 #endif
@@ -81,9 +72,6 @@ static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
     qdict_put_bool(args->start.config, "multifd", true);
     qdict_put_str(args->start.config, "multifd-compression", "qpl");
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     test_precopy_common(args);
 }
 #endif /* CONFIG_QPL */
@@ -98,9 +86,6 @@ static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
     qdict_put_bool(args->start.config, "multifd", true);
     qdict_put_str(args->start.config, "multifd-compression", "uadk");
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     test_precopy_common(args);
 }
 #endif /* CONFIG_UADK */
@@ -121,9 +106,6 @@ static void test_precopy_unix_xbzrle(char *name, MigrateCommon *args)
     qdict_put_bool(args->start.config, "xbzrle", true);
     qdict_put_int(args->start.config, "xbzrle-cache-size", 33554432);
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     test_precopy_common(args);
 }
 
@@ -141,9 +123,6 @@ static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
     qdict_put_int(args->start.config, "multifd-zlib-level", 2);
     qdict_put_str(args->start.config, "multifd-compression", "zlib");
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     test_precopy_common(args);
 }
 
diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
index a1b5a39f9f..57199ed3b8 100644
--- a/tests/qtest/migration/cpr-tests.c
+++ b/tests/qtest/migration/cpr-tests.c
@@ -88,9 +88,6 @@ static void test_mode_transfer_common(MigrateCommon *args)
 
     qdict_put_str(args->start.config, "mode", "cpr-transfer");
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     if (test_precopy_common(args) < 0) {
         close(cpr_sockfd);
         unlink(cpr_path);
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index 6cf2bbf9cc..f596f1c171 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -868,6 +868,9 @@ int test_precopy_common(MigrateCommon *args)
     QObject *in_channels = NULL;
     QObject *out_channels = NULL;
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     g_assert(!args->cpr_channel || args->connect_channels);
     if (args->start.incoming_defer) {
         g_assert(args->listen_uri || args->connect_channels);
@@ -951,7 +954,7 @@ int test_precopy_common(MigrateCommon *args)
         qtest_connect(to);
         qtest_qmp_handshake(to, NULL);
         if (args->start.incoming_defer) {
-            migrate_incoming_qmp(to, args->connect_uri, in_channels,
+            migrate_incoming_qmp(to, NULL, in_channels,
                                  args->start.config, "{}");
         }
     }
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index 01151301ce..f8f46322bc 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -216,8 +216,8 @@ static void test_precopy_tcp_switchover_ack(char *name, MigrateCommon *args)
      */
     args->live = true;
 
-    args->start.caps[MIGRATION_CAPABILITY_RETURN_PATH] = true;
-    args->start.caps[MIGRATION_CAPABILITY_SWITCHOVER_ACK] = true;
+    qdict_put_bool(args->start.config, "return-path", true);
+    qdict_put_bool(args->start.config, "switchover-ack", true);
 
     test_precopy_common(args);
 }
@@ -365,10 +365,10 @@ static void test_auto_converge(char *name, MigrateCommon *args)
         return;
     }
 
-    migrate_set_capability(from, "auto-converge", true);
-    migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct);
-    migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct);
-    migrate_set_parameter_int(from, "max-cpu-throttle", max_pct);
+    qdict_put_bool(args->start.config, "auto-converge", true);
+    qdict_put_int(args->start.config, "cpu-throttle-initial", init_pct);
+    qdict_put_int(args->start.config, "cpu-throttle-increment", inc_pct);
+    qdict_put_int(args->start.config, "max-cpu-throttle", max_pct);
 
     /*
      * Set the initial parameters so that the migration could not converge
@@ -377,7 +377,7 @@ static void test_auto_converge(char *name, MigrateCommon *args)
     migrate_ensure_non_converge(from, args->start.config);
 
     /* To check remaining size after precopy */
-    migrate_set_capability(from, "pause-before-switchover", true);
+    qdict_put_bool(args->start.config, "pause-before-switchover", true);
 
     /* Wait for the first serial output from the source */
     wait_for_serial("src_serial");
@@ -448,37 +448,8 @@ static void test_auto_converge(char *name, MigrateCommon *args)
     migrate_end(from, to, true);
 }
 
-static void *
-migrate_hook_start_precopy_tcp_multifd(QTestState *from,
-                                       QTestState *to)
-{
-    migrate_set_parameter_str(from, "multifd-compression", "none");
-    migrate_set_parameter_str(to, "multifd-compression", "none");
-
-    return NULL;
-}
-
-static void *
-migrate_hook_start_precopy_tcp_multifd_zero_page_legacy(QTestState *from,
-                                                        QTestState *to)
-{
-    migrate_hook_start_precopy_tcp_multifd(from, to);
-    migrate_set_parameter_str(from, "zero-page-detection", "legacy");
-    return NULL;
-}
-
-static void *
-migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from,
-                                                    QTestState *to)
-{
-    migrate_hook_start_precopy_tcp_multifd(from, to);
-    migrate_set_parameter_str(from, "zero-page-detection", "none");
-    return NULL;
-}
-
 static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_precopy_tcp_multifd;
     /*
      * Multifd is more complicated than most of the features, it
      * directly takes guest page buffers when sending, make sure
@@ -488,14 +459,15 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
     args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_str(args->start.config, "multifd-compression", "none");
 
     test_precopy_common(args);
 }
 
 static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy;
     /*
      * Multifd is more complicated than most of the features, it
      * directly takes guest page buffers when sending, make sure
@@ -505,14 +477,16 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
     args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_str(args->start.config, "multifd-compression", "none");
+    qdict_put_str(args->start.config, "zero-page-detection", "legacy");
 
     test_precopy_common(args);
 }
 
 static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page;
     /*
      * Multifd is more complicated than most of the features, it
      * directly takes guest page buffers when sending, make sure
@@ -522,14 +496,16 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
     args->listen_uri = "tcp:127.0.0.1:0";
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_str(args->start.config, "multifd-compression", "none");
+    qdict_put_str(args->start.config, "zero-page-detection", "none");
 
     test_precopy_common(args);
 }
 
 static void test_multifd_tcp_channels_none(char *name, MigrateCommon *args)
 {
-    args->start_hook = migrate_hook_start_precopy_tcp_multifd;
     args->live = true;
     args->connect_channels = ("[ { 'channel-type': 'main',"
                               "    'addr': { 'transport': 'socket',"
@@ -538,7 +514,9 @@ static void test_multifd_tcp_channels_none(char *name, MigrateCommon *args)
                               "              'port': '0' } } ]");
 
     args->start.incoming_defer = true;
-    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
+
+    qdict_put_bool(args->start.config, "multifd", true);
+    qdict_put_str(args->start.config, "multifd-compression", "none");
 
     test_precopy_common(args);
 }
@@ -558,6 +536,9 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
 {
     QTestState *from, *to, *to2;
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     args->start.hide_stderr = true;
     args->start.incoming_defer = true;
 
@@ -569,15 +550,11 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
     migrate_prepare_for_dirty_mem(from);
 
     if (postcopy_ram) {
-        migrate_set_capability(from, "postcopy-ram", true);
-        migrate_set_capability(to, "postcopy-ram", true);
+        qdict_put_bool(args->start.config, "postcopy-ram", true);
     }
 
-    migrate_set_parameter_int(from, "multifd-channels", 16);
-    migrate_set_parameter_int(to, "multifd-channels", 16);
-
-    migrate_set_capability(from, "multifd", true);
-    migrate_set_capability(to, "multifd", true);
+    qdict_put_int(args->start.config, "multifd-channels", 16);
+    qdict_put_bool(args->start.config, "multifd", true);
 
     /* Start incoming migration from the 1st socket */
     migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, args->start.config, "{}");
@@ -615,13 +592,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
         return;
     }
 
-    if (postcopy_ram) {
-        migrate_set_capability(to2, "postcopy-ram", true);
-    }
-
-    migrate_set_parameter_int(to2, "multifd-channels", 16);
-
-    migrate_set_capability(to2, "multifd", true);
+    /* reusing the same config for to2 */
 
     /* Start incoming migration from the 1st socket */
     migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, args->start.config,
@@ -755,12 +726,6 @@ static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
                                            const char *uri, const char *phase,
                                            MigrateStart *args)
 {
-    migrate_set_capability(from, "pause-before-switchover", true);
-    migrate_set_capability(to, "pause-before-switchover", true);
-
-    migrate_set_capability(from, "multifd", true);
-    migrate_set_capability(to, "multifd", true);
-
     migrate_incoming_qmp(to, uri, NULL, args->config,
                          "{ 'exit-on-error': false }");
 
@@ -786,6 +751,9 @@ static void test_cancel_src_after_status(char *test_path, MigrateCommon *args)
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
     QTestState *from, *to;
 
+    /* temporary */
+    qdict_put_bool(args->start.config, "use-config", true);
+
     args->start.hide_stderr = true;
     args->start.incoming_defer = true;
 
@@ -808,6 +776,10 @@ static void test_cancel_src_after_status(char *test_path, MigrateCommon *args)
 
     } else {
         /* any state that comes before pre-switchover */
+
+        qdict_put_bool(args->start.config, "pause-before-switchover", true);
+        qdict_put_bool(args->start.config, "multifd", true);
+
         test_cancel_src_pre_switchover(from, to, uri, phase, &args->start);
     }
 
@@ -1061,19 +1033,19 @@ static void test_vcpu_dirty_limit(char *name, MigrateCommon *args)
     dirtylimit_stop_vm(vm);
 }
 
-static void migrate_dirty_limit_wait_showup(QTestState *from,
+static void migrate_dirty_limit_wait_showup(QDict *config,
                                             const int64_t period,
                                             const int64_t value)
 {
     /* Enable dirty limit capability */
-    migrate_set_capability(from, "dirty-limit", true);
+    qdict_put_bool(config, "dirty-limit", true);
 
     /* Set dirty limit parameters */
-    migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
-    migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
+    qdict_put_int(config, "x-vcpu-dirty-limit-period", period);
+    qdict_put_int(config, "vcpu-dirty-limit", value);
 
     /* To check limit rate after precopy */
-    migrate_set_capability(from, "pause-before-switchover", true);
+    qdict_put_bool(config, "pause-before-switchover", true);
 
     /* Wait for the serial output from the source */
     wait_for_serial("src_serial");
@@ -1132,7 +1104,8 @@ static void test_dirty_limit(char *name, MigrateCommon *args)
 
     /* Prepare for dirty limit migration and wait src vm show up */
     migrate_ensure_non_converge(from, args->start.config);
-    migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
+    migrate_dirty_limit_wait_showup(args->start.config, dirtylimit_period,
+                                    dirtylimit_value);
 
     /* Start migrate */
     migrate_qmp(from, to, args->connect_uri, NULL, args->start.config, "{}");
diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index b6d436389a..aa5482b823 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -118,9 +118,6 @@ static void test_precopy_tls_psk_common(MigrateCommon *args,
 {
     TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
 
     migrate_tls_psk_init(args, test_args, data);
@@ -385,9 +382,6 @@ static void test_precopy_tls_x509_common(MigrateCommon *args,
 {
     TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     migrate_tls_x509_init(args, test_args, data);
     test_precopy_common(args);
     migrate_tls_x509_cleanup(data);
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 50/51] tests/qtest/migration: Remove migrate_set_capabilities and code around it
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (48 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 49/51] tests/qtest/migration: Convert precopy tests " Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-15 22:00 ` [PATCH v3 51/51] tests/qtest/migration: Further simplify TLS tests Fabiano Rosas
  2025-12-17 16:58 ` [PATCH v3 00/51] migration: Unify capabilities and parameters Peter Xu
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Remove all of the code that sets capabilities via
migrate_set_capabilities. All the users have already been converted to
use the new API.

Also remove all usage of the use-config key. This is not needed
anymore, tests should always pass the config object, even if empty.

The ensure_non_converge and ensure_converge functions don't need the
QTestState parameter anymore because there will be no fallback, the
config will always be used.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/cpr-tests.c      |  3 -
 tests/qtest/migration/framework.c      | 86 +++-----------------------
 tests/qtest/migration/migration-qmp.c  | 82 +++++-------------------
 tests/qtest/migration/migration-qmp.h  |  4 +-
 tests/qtest/migration/migration-util.c |  1 -
 tests/qtest/migration/migration-util.h | 34 ----------
 tests/qtest/migration/misc-tests.c     | 16 +----
 tests/qtest/migration/precopy-tests.c  | 24 +++----
 8 files changed, 37 insertions(+), 213 deletions(-)

diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c
index 57199ed3b8..f8c20b9038 100644
--- a/tests/qtest/migration/cpr-tests.c
+++ b/tests/qtest/migration/cpr-tests.c
@@ -186,9 +186,6 @@ static void test_cpr_exec(MigrateCommon *args)
                                                 FILE_TEST_FILENAME);
     g_autofree char *channels = NULL;
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     if (migrate_start(&from, NULL, args->listen_uri, &args->start)) {
         return;
     }
diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
index f596f1c171..363604031e 100644
--- a/tests/qtest/migration/framework.c
+++ b/tests/qtest/migration/framework.c
@@ -209,70 +209,21 @@ static QList *migrate_start_get_qmp_capabilities(const MigrateStart *args)
 }
 
 static void migrate_start_set_default_options(MigrateStart *args)
-{
-    if (args->config && qdict_get_bool(args->config, "use-config")) {
-        /*
-         * Always enable migration events. Libvirt always uses it,
-         * let's mimic that.
-         */
-        qdict_put_bool(args->config, "events", true);
-
-        /*
-         * Default number of channels should be fine for most
-         * tests. Individual tests can override by calling
-         * migrate_set_parameter() directly.
-         */
-        if (qdict_get_try_bool(args->config, "multifd", false)) {
-            qdict_put_int(args->config, "multifd-channels",
-                          MULTIFD_TEST_CHANNELS);
-        }
-
-        return;
-    }
-}
-
-static void migrate_start_set_capabilities(QTestState *from, QTestState *to,
-                                           MigrateStart *args)
 {
     /*
-     * MigrationCapability_lookup and MIGRATION_CAPABILITY_ constants
-     * are from qapi-types-migration.h.
+     * Always enable migration events. Libvirt always uses it,
+     * let's mimic that.
      */
-    for (uint8_t i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
-        if (!args->caps[i]) {
-            continue;
-        }
-        if (from) {
-            migrate_set_capability(from,
-                            MigrationCapability_lookup.array[i], true);
-        }
-        if (to) {
-            migrate_set_capability(to,
-                            MigrationCapability_lookup.array[i], true);
-        }
-    }
-
-    /*
-     * Always enable migration events.  Libvirt always uses it, let's try
-     * to mimic as closer as that.
-     */
-    migrate_set_capability(from, "events", true);
-    if (!args->defer_target_connect && to) {
-        migrate_set_capability(to, "events", true);
-    }
+    qdict_put_bool(args->config, "events", true);
 
     /*
      * Default number of channels should be fine for most
      * tests. Individual tests can override by calling
      * migrate_set_parameter() directly.
      */
-    if (args->caps[MIGRATION_CAPABILITY_MULTIFD]) {
-        migrate_set_parameter_int(from, "multifd-channels",
-                                  MULTIFD_TEST_CHANNELS);
-        if (to) {
-            migrate_set_parameter_int(to, "multifd-channels",
-                                      MULTIFD_TEST_CHANNELS);
-        }
+    if (qdict_get_try_bool(args->config, "multifd", false)) {
+        qdict_put_int(args->config, "multifd-channels",
+                      MULTIFD_TEST_CHANNELS);
     }
 
     return;
@@ -429,7 +380,7 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
      */
     events = args->defer_target_connect ? "-global migration.x-events=on" : "";
 
-    if (!args->incoming_defer && args->config) {
+    if (!args->incoming_defer) {
         QDict *conf = fixup_tls_creds(args->config);
         GString *json = qobject_to_json(QOBJECT(conf));
 
@@ -512,11 +463,9 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
     bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me);
     src_state.suspend_me = args->suspend_me;
 
-    args->config = config_load(args->config);
     if (migrate_args(&cmd_source, &cmd_target, uri, args)) {
         return -1;
     }
-    config_put(args->config);
 
     if (!args->only_target) {
         *from = qtest_init_ext(QEMU_ENV_SRC, cmd_source, capabilities, true);
@@ -534,9 +483,6 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
     }
 
     migrate_mem_type_cleanup(args->mem_type);
-    migrate_start_set_capabilities(*from,
-                                   args->only_source ? NULL : *to,
-                                   args);
 
     return 0;
 }
@@ -598,7 +544,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
                                                     args->start_hook_data);
     }
 
-    migrate_ensure_non_converge(from, args->start.config);
+    migrate_ensure_non_converge(args->start.config);
     migrate_prepare_for_dirty_mem(from);
 
     channels = qobject_from_json("[ { 'channel-type': 'main',"
@@ -654,9 +600,6 @@ void test_postcopy_common(MigrateCommon *args)
 {
     QTestState *from, *to;
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     if (migrate_postcopy_prepare(&from, &to, args)) {
         return;
     }
@@ -790,9 +733,6 @@ void test_postcopy_recovery_common(MigrateCommon *args)
     QTestState *from, *to;
     g_autofree char *uri = NULL;
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     /*
      * Always enable OOB QMP capability for recovery tests, migrate-recover is
      * executed out-of-band
@@ -868,9 +808,6 @@ int test_precopy_common(MigrateCommon *args)
     QObject *in_channels = NULL;
     QObject *out_channels = NULL;
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     g_assert(!args->cpr_channel || args->connect_channels);
     if (args->start.incoming_defer) {
         g_assert(args->listen_uri || args->connect_channels);
@@ -906,7 +843,7 @@ int test_precopy_common(MigrateCommon *args)
     }
 
     if (args->live) {
-        migrate_ensure_non_converge(from, args->start.config);
+        migrate_ensure_non_converge(args->start.config);
         migrate_prepare_for_dirty_mem(from);
     } else {
         /*
@@ -1059,9 +996,6 @@ void test_file_common(MigrateCommon *args, bool stop_src)
     void *data_hook = NULL;
     bool check_offset = false;
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
         return;
     }
@@ -1089,7 +1023,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
         data_hook = args->start_hook_full(from, to, args->start_hook_data);
     }
 
-    migrate_ensure_converge(from, args->start.config);
+    migrate_ensure_converge(args->start.config);
     wait_for_serial("src_serial");
 
     if (stop_src) {
diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
index a4dde029ee..a9edc793cd 100644
--- a/tests/qtest/migration/migration-qmp.c
+++ b/tests/qtest/migration/migration-qmp.c
@@ -96,11 +96,8 @@ void migrate_qmp_fail(QTestState *who, const char *uri,
         qdict_put_obj(args, "channels", channels);
     }
 
-    config = config_load(config);
-    if (config) {
-        qdict_put_obj(args, "config", QOBJECT(config));
-        qobject_ref(config);
-    }
+    qdict_put_obj(args, "config", QOBJECT(config));
+    qobject_ref(config);
 
     err = qtest_qmp_assert_failure_ref(
         who, "{ 'execute': 'migrate', 'arguments': %p}", args);
@@ -108,7 +105,6 @@ void migrate_qmp_fail(QTestState *who, const char *uri,
     g_assert(qdict_haskey(err, "desc"));
 
     qobject_unref(err);
-    config_put(config);
 }
 
 /*
@@ -142,26 +138,11 @@ void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
         qdict_put_obj(args, "channels", channels);
     }
 
-    config = config_load(config);
-    if (config) {
-        qdict_put_obj(args, "config", QOBJECT(config));
-        qobject_ref(config);
-    }
+    qdict_put_obj(args, "config", QOBJECT(config));
+    qobject_ref(config);
 
     qtest_qmp_assert_success(who,
                              "{ 'execute': 'migrate', 'arguments': %p}", args);
-    config_put(config);
-}
-
-void migrate_set_capability(QTestState *who, const char *capability,
-                            bool value)
-{
-    qtest_qmp_assert_success(who,
-                             "{ 'execute': 'migrate-set-capabilities',"
-                             "'arguments': { "
-                             "'capabilities': [ { "
-                             "'capability': %s, 'state': %i } ] } }",
-                             capability, value);
 }
 
 void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
@@ -185,13 +166,10 @@ void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
     }
 
     /* This function relies on the event to work, make sure it's enabled */
-    migrate_set_capability(to, "events", true);
+    qdict_put_bool(config, "events", true);
 
-    config = config_load(config);
-    if (config) {
-        qdict_put_obj(args, "config", QOBJECT(config));
-        qobject_ref(config);
-    }
+    qdict_put_obj(args, "config", QOBJECT(config));
+    qobject_ref(config);
 
     rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
                     args);
@@ -205,7 +183,6 @@ void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
     qobject_unref(rsp);
 
     migration_event_wait(to, "setup");
-    config_put(config);
 }
 
 static bool check_migration_status(QTestState *who, const char *goal,
@@ -463,22 +440,6 @@ void migrate_set_parameter_str(QTestState *who, const char *parameter,
     migrate_check_parameter_str(who, parameter, value);
 }
 
-void migrate_set_parameter_strv(QTestState *who, const char *parameter,
-                                char **strv)
-{
-    g_autofree char *args = g_strjoinv("\",\"", strv);
-    g_autoptr(GString) value = g_string_new("");
-    g_autofree char *command = NULL;
-
-    g_string_printf(value, "\"%s\"", args);
-
-    command = g_strdup_printf("{ 'execute': 'migrate-set-parameters',"
-                              "'arguments': { %%s: [ %s ]}}",
-                              value->str);
-
-    qtest_qmp_assert_success(who, command, parameter);
-}
-
 void migrate_set_parameter_null(QTestState *who, const char *parameter)
 {
     qtest_qmp_assert_success(who,
@@ -534,32 +495,17 @@ void migrate_ongoing_ensure_converge(QTestState *who)
     migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
 }
 
-void migrate_ensure_non_converge(QTestState *who, QDict *config)
+void migrate_ensure_non_converge(QDict *config)
 {
-    config = config_load(config);
-    if (config) {
-        /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
-        qdict_put_int(config, "max-bandwidth", 3 * 1000 * 1000);
-        qdict_put_int(config, "downtime-limit", 1);
-    } else {
-        assert(who);
-        migrate_ongoing_ensure_non_converge(who);
-    }
-    config_put(config);
+    /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
+    qdict_put_int(config, "max-bandwidth", 3 * 1000 * 1000);
+    qdict_put_int(config, "downtime-limit", 1);
 }
 
-void migrate_ensure_converge(QTestState *who, QDict *config)
+void migrate_ensure_converge(QDict *config)
 {
-    config = config_load(config);
-    /* Should converge with 30s downtime + 1 gbs bandwidth limit */
-    if (config) {
-        qdict_put_int(config, "max-bandwidth", 1 * 1000 * 1000 * 1000);
-        qdict_put_int(config, "downtime-limit", 30 * 1000);
-    } else {
-        assert(who);
-        migrate_ongoing_ensure_converge(who);
-    }
-    config_put(config);
+    qdict_put_int(config, "max-bandwidth", 1 * 1000 * 1000 * 1000);
+    qdict_put_int(config, "downtime-limit", 30 * 1000);
 }
 
 void migrate_pause(QTestState *who)
diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
index 7daeb913fa..da0d99af59 100644
--- a/tests/qtest/migration/migration-qmp.h
+++ b/tests/qtest/migration/migration-qmp.h
@@ -42,8 +42,8 @@ void migrate_set_parameter_bool(QTestState *who, const char *parameter,
                                 int value);
 void migrate_ongoing_ensure_non_converge(QTestState *who);
 void migrate_ongoing_ensure_converge(QTestState *who);
-void migrate_ensure_non_converge(QTestState *who, QDict *config);
-void migrate_ensure_converge(QTestState *who, QDict *config);
+void migrate_ensure_non_converge(QDict *config);
+void migrate_ensure_converge(QDict *config);
 void migrate_pause(QTestState *who);
 void migrate_continue(QTestState *who, const char *state);
 void migrate_recover(QTestState *who, const char *uri);
diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
index efe1ae25de..c6f5ae3cb1 100644
--- a/tests/qtest/migration/migration-util.c
+++ b/tests/qtest/migration/migration-util.c
@@ -255,7 +255,6 @@ static void migration_test_wrapper(const void *data)
 
     test->data = g_new0(MigrateCommon, 1);
     test->data->start.config = qdict_new();
-    qdict_put_bool(test->data->start.config, "use-config", false);
 
     g_test_message("Running /%s%s", qtest_get_arch(), test->name);
     test->func(test->name, test->data);
diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
index ec58868197..da523fb2f7 100644
--- a/tests/qtest/migration/migration-util.h
+++ b/tests/qtest/migration/migration-util.h
@@ -61,38 +61,4 @@ char *migrate_get_connect_uri(QTestState *who);
 void migrate_set_ports(QTestState *to, QList *channel_list);
 QDict *fixup_tls_creds(QDict *config);
 
-/*
- * Scaffolding to allow the framework _common functions and _qmp
- * functions to use the config object while some tests are still using
- * migrate_set_*. Tests that have been converted will set use-config =
- * true on the config dict.
- */
-static bool has_key;
-static bool use_config;
-static inline QDict *config_load(QDict *config)
-{
-    if (!config) {
-        return NULL;
-    }
-
-    has_key = qdict_haskey(config, "use-config");
-    if (has_key) {
-        use_config = qdict_get_try_bool(config, "use-config", false);
-        qdict_del(config, "use-config");
-    }
-
-    if (use_config) {
-        return config;
-    }
-
-    return NULL;
-}
-
-static inline void config_put(QDict *config)
-{
-    if (config && has_key) {
-        qdict_put_bool(config, "use-config", use_config);
-    }
-}
-
 #endif /* MIGRATION_UTIL_H */
diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
index 7e38d26ab2..4bac7fff41 100644
--- a/tests/qtest/migration/misc-tests.c
+++ b/tests/qtest/migration/misc-tests.c
@@ -28,9 +28,6 @@ static void test_baddest(char *name, MigrateCommon *args)
 
     args->start.hide_stderr = true;
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) {
         return;
     }
@@ -55,9 +52,6 @@ static void test_analyze_script(char *name, MigrateCommon *args)
         return;
     }
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     /* dummy url */
     if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) {
         return;
@@ -74,7 +68,7 @@ static void test_analyze_script(char *name, MigrateCommon *args)
     file = g_strdup_printf("%s/migfile", tmpfs);
     uri = g_strdup_printf("exec:cat > %s", file);
 
-    migrate_ensure_converge(from, args->start.config);
+    migrate_ensure_converge(args->start.config);
     migrate_qmp(from, to, uri, NULL, args->start.config, "{}");
     wait_for_migration_complete(from);
 
@@ -103,16 +97,13 @@ static void test_ignore_shared(char *name, MigrateCommon *args)
 
     args->start.mem_type = MEM_TYPE_SHMEM;
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     qdict_put_bool(args->start.config, "x-ignore-shared", true);
 
     if (migrate_start(&from, &to, uri, &args->start)) {
         return;
     }
 
-    migrate_ensure_non_converge(from, args->start.config);
+    migrate_ensure_non_converge(args->start.config);
     migrate_prepare_for_dirty_mem(from);
 
     /* Wait for the first serial output from the source */
@@ -141,9 +132,6 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
     QTestState *from, *to;
 
-    /* temporary */
-    qdict_put_bool(args->config, "use-config", true);
-
     if (migrate_start(&from, &to, uri, args)) {
         return;
     }
diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
index f8f46322bc..bb96cbb56f 100644
--- a/tests/qtest/migration/precopy-tests.c
+++ b/tests/qtest/migration/precopy-tests.c
@@ -374,7 +374,7 @@ static void test_auto_converge(char *name, MigrateCommon *args)
      * Set the initial parameters so that the migration could not converge
      * without throttling.
      */
-    migrate_ensure_non_converge(from, args->start.config);
+    migrate_ensure_non_converge(args->start.config);
 
     /* To check remaining size after precopy */
     qdict_put_bool(args->start.config, "pause-before-switchover", true);
@@ -536,9 +536,6 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
 {
     QTestState *from, *to, *to2;
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     args->start.hide_stderr = true;
     args->start.incoming_defer = true;
 
@@ -546,7 +543,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
         return;
     }
 
-    migrate_ensure_non_converge(from, args->start.config);
+    migrate_ensure_non_converge(args->start.config);
     migrate_prepare_for_dirty_mem(from);
 
     if (postcopy_ram) {
@@ -598,7 +595,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
     migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, args->start.config,
                          "{}");
 
-    migrate_ensure_non_converge(from, args->start.config);
+    migrate_ensure_non_converge(args->start.config);
 
     migrate_qmp(from, to2, NULL, NULL, args->start.config, "{}");
 
@@ -632,7 +629,7 @@ static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
      */
 
     wait_for_serial("src_serial");
-    migrate_ensure_converge(from, args->config);
+    migrate_ensure_converge(args->config);
 
     migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
@@ -658,7 +655,7 @@ static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
                          "{ 'exit-on-error': false }");
 
     wait_for_serial("src_serial");
-    migrate_ensure_converge(from, args->config);
+    migrate_ensure_converge(args->config);
 
     migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
@@ -684,7 +681,7 @@ static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
                          "{ 'exit-on-error': false }");
 
     wait_for_serial("src_serial");
-    migrate_ensure_converge(from, args->config);
+    migrate_ensure_converge(args->config);
 
     migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
@@ -715,7 +712,7 @@ static void test_cancel_src_after_none(QTestState *from, QTestState *to,
     migrate_incoming_qmp(to, uri, NULL, args->config,
                          "{ 'exit-on-error': false }");
 
-    migrate_ensure_converge(from, args->config);
+    migrate_ensure_converge(args->config);
     migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
     wait_for_migration_complete(from);
@@ -730,7 +727,7 @@ static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
                          "{ 'exit-on-error': false }");
 
     wait_for_serial("src_serial");
-    migrate_ensure_converge(from, args->config);
+    migrate_ensure_converge(args->config);
 
     migrate_qmp(from, to, uri, NULL, args->config, "{}");
 
@@ -751,9 +748,6 @@ static void test_cancel_src_after_status(char *test_path, MigrateCommon *args)
     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
     QTestState *from, *to;
 
-    /* temporary */
-    qdict_put_bool(args->start.config, "use-config", true);
-
     args->start.hide_stderr = true;
     args->start.incoming_defer = true;
 
@@ -1103,7 +1097,7 @@ static void test_dirty_limit(char *name, MigrateCommon *args)
     }
 
     /* Prepare for dirty limit migration and wait src vm show up */
-    migrate_ensure_non_converge(from, args->start.config);
+    migrate_ensure_non_converge(args->start.config);
     migrate_dirty_limit_wait_showup(args->start.config, dirtylimit_period,
                                     dirtylimit_value);
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 51/51] tests/qtest/migration: Further simplify TLS tests
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (49 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 50/51] tests/qtest/migration: Remove migrate_set_capabilities and code around it Fabiano Rosas
@ 2025-12-15 22:00 ` Fabiano Rosas
  2025-12-17 16:58 ` [PATCH v3 00/51] migration: Unify capabilities and parameters Peter Xu
  51 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-15 22:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: berrange, armbru, Peter Xu, Laurent Vivier, Paolo Bonzini

Now that the TLS hooks were simplified, many test functions are using
the same hook, but passing a different data pointer. Since the data
pointer is already an argument for the _common function, stop setting
the hook & data in the test function and do it instead in the init
routine.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/qtest/migration/tls-tests.c | 60 +++++--------------------------
 1 file changed, 8 insertions(+), 52 deletions(-)

diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
index aa5482b823..da8b3e42fe 100644
--- a/tests/qtest/migration/tls-tests.c
+++ b/tests/qtest/migration/tls-tests.c
@@ -80,6 +80,11 @@ static void migrate_tls_psk_init(MigrateCommon *args,
                                  TestMigrateTLSPSK *test_args,
                                  TestMigrateTLSPSKData *data)
 {
+    qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
+
+    args->start_hook_full = migrate_hook_start_tls_psk_common;
+    args->start_hook_data = test_args;
+
     data->workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs);
     data->pskfile = g_strdup_printf("%s/%s", data->workdir,
                                     QCRYPTO_TLS_CREDS_PSKFILE);
@@ -118,8 +123,6 @@ static void test_precopy_tls_psk_common(MigrateCommon *args,
 {
     TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
 
-    qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
-
     migrate_tls_psk_init(args, test_args, data);
     test_precopy_common(args);
     migrate_tls_psk_cleanup(data);
@@ -130,8 +133,6 @@ static void test_postcopy_tls_psk_common(MigrateCommon *args,
 {
     TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
 
-    qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
-
     migrate_tls_psk_init(args, test_args, data);
     test_postcopy_common(args);
     migrate_tls_psk_cleanup(data);
@@ -142,8 +143,6 @@ static void test_postcopy_recovery_tls_psk_common(MigrateCommon *args,
 {
     TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
 
-    qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
-
     migrate_tls_psk_init(args, test_args, data);
     test_postcopy_recovery_common(args);
     migrate_tls_psk_cleanup(data);
@@ -283,6 +282,9 @@ static void migrate_tls_x509_init(MigrateCommon *args,
                                   TestMigrateTLSX509 *test_args,
                                   TestMigrateTLSX509Data *data)
 {
+    args->start_hook_full = migrate_hook_start_tls_x509_common;
+    args->start_hook_data = test_args;
+
     data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs);
     data->keyfile = g_strdup_printf("%s/key.pem", data->workdir);
 
@@ -390,17 +392,11 @@ static void test_precopy_tls_x509_common(MigrateCommon *args,
 
 static void test_postcopy_tls_psk(char *name, MigrateCommon *args)
 {
-    args->start_hook_full = migrate_hook_start_tls_psk_common;
-    args->start_hook_data = &tls_psk_match;
-
     test_postcopy_tls_psk_common(args, &tls_psk_match);
 }
 
 static void test_postcopy_preempt_tls_psk(char *name, MigrateCommon *args)
 {
-    args->start_hook_full = migrate_hook_start_tls_psk_common;
-    args->start_hook_data = &tls_psk_match;
-
     qdict_put_bool(args->start.config, "postcopy-preempt", true);
 
     test_postcopy_tls_psk_common(args, &tls_psk_match);
@@ -408,18 +404,12 @@ static void test_postcopy_preempt_tls_psk(char *name, MigrateCommon *args)
 
 static void test_postcopy_recovery_tls_psk(char *name, MigrateCommon *args)
 {
-    args->start_hook_full = migrate_hook_start_tls_psk_common;
-    args->start_hook_data = &tls_psk_match;
-
     test_postcopy_recovery_tls_psk_common(args, &tls_psk_match);
 }
 
 static void test_multifd_postcopy_recovery_tls_psk(char *name,
                                                    MigrateCommon *args)
 {
-    args->start_hook_full = migrate_hook_start_tls_psk_common;
-    args->start_hook_data = &tls_psk_match;
-
     qdict_put_bool(args->start.config, "multifd", true);
 
     test_postcopy_recovery_tls_psk_common(args, &tls_psk_match);
@@ -428,9 +418,6 @@ static void test_multifd_postcopy_recovery_tls_psk(char *name,
 /* This contains preempt+recovery+tls test altogether */
 static void test_postcopy_preempt_all(char *name, MigrateCommon *args)
 {
-    args->start_hook_full = migrate_hook_start_tls_psk_common;
-    args->start_hook_data = &tls_psk_match;
-
     qdict_put_bool(args->start.config, "postcopy-preempt", true);
 
     test_postcopy_recovery_tls_psk_common(args, &tls_psk_match);
@@ -439,9 +426,6 @@ static void test_postcopy_preempt_all(char *name, MigrateCommon *args)
 static void test_multifd_postcopy_preempt_recovery_tls_psk(char *name,
                                                            MigrateCommon *args)
 {
-    args->start_hook_full = migrate_hook_start_tls_psk_common;
-    args->start_hook_data = &tls_psk_match;
-
     qdict_put_bool(args->start.config, "multifd", true);
     qdict_put_bool(args->start.config, "postcopy-preempt", true);
 
@@ -454,8 +438,6 @@ static void test_precopy_unix_tls_psk(char *name, MigrateCommon *args)
 
     args->connect_uri = uri;
     args->listen_uri = uri;
-    args->start_hook_full = migrate_hook_start_tls_psk_common;
-    args->start_hook_data = &tls_psk_match;
 
     test_precopy_tls_psk_common(args, &tls_psk_match);
 }
@@ -468,8 +450,6 @@ static void test_precopy_unix_tls_x509_default_host(char *name,
 
     args->connect_uri = uri;
     args->listen_uri = uri;
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &tls_x509_default_host;
     args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
 
     args->start.hide_stderr = true;
@@ -484,8 +464,6 @@ static void test_precopy_unix_tls_x509_override_host(char *name,
 
     args->connect_uri = uri;
     args->listen_uri = uri;
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &tls_x509_override_host;
 
     test_precopy_tls_x509_common(args, &tls_x509_override_host);
 }
@@ -494,8 +472,6 @@ static void test_precopy_unix_tls_x509_override_host(char *name,
 static void test_precopy_tcp_tls_psk_match(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook_full = migrate_hook_start_tls_psk_common;
-    args->start_hook_data = &tls_psk_match;
 
     test_precopy_tls_psk_common(args, &tls_psk_match);
 }
@@ -503,8 +479,6 @@ static void test_precopy_tcp_tls_psk_match(char *name, MigrateCommon *args)
 static void test_precopy_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook_full = migrate_hook_start_tls_psk_common;
-    args->start_hook_data = &tls_psk_mismatch;
     args->result = MIG_TEST_FAIL;
 
     args->start.hide_stderr = true;
@@ -524,8 +498,6 @@ static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args)
 static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &tls_x509_no_host;
     args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
 
     args->start.hide_stderr = true;
@@ -538,8 +510,6 @@ static void test_precopy_tcp_tls_x509_default_host(char *name,
                                                    MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &tls_x509_default_host;
 
     test_precopy_tls_x509_common(args, &tls_x509_default_host);
 }
@@ -548,8 +518,6 @@ static void test_precopy_tcp_tls_x509_override_host(char *name,
                                                     MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &tls_x509_override_host;
 
     test_precopy_tls_x509_common(args, &tls_x509_override_host);
 }
@@ -558,8 +526,6 @@ static void test_precopy_tcp_tls_x509_mismatch_host(char *name,
                                                     MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &tls_x509_mismatch_host;
     args->result = MIG_TEST_FAIL_DEST_QUIT_ERR;
 
     args->start.hide_stderr = true;
@@ -571,8 +537,6 @@ static void test_precopy_tcp_tls_x509_friendly_client(char *name,
                                                       MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &x509_friendly_client;
 
     test_precopy_tls_x509_common(args, &x509_friendly_client);
 }
@@ -581,8 +545,6 @@ static void test_precopy_tcp_tls_x509_hostile_client(char *name,
                                                      MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &tls_x509_hostile_client;
     args->result = MIG_TEST_FAIL;
 
     args->start.hide_stderr = true;
@@ -594,8 +556,6 @@ static void test_precopy_tcp_tls_x509_allow_anon_client(char *name,
                                                         MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &tls_x509_allow_anon_client;
 
     test_precopy_tls_x509_common(args, &tls_x509_allow_anon_client);
 }
@@ -604,8 +564,6 @@ static void test_precopy_tcp_tls_x509_reject_anon_client(char *name,
                                                          MigrateCommon *args)
 {
     args->listen_uri = "tcp:127.0.0.1:0";
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &tls_x509_reject_anon_client;
     args->result = MIG_TEST_FAIL;
 
     args->start.hide_stderr = true;
@@ -679,8 +637,6 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
      * to load migration state, and thus just aborts the migration
      * without exiting.
      */
-    args->start_hook_full = migrate_hook_start_tls_x509_common;
-    args->start_hook_data = &tls_x509_mismatch_host;
     args->result = MIG_TEST_FAIL;
     args->listen_uri = "tcp:127.0.0.1:0";
 
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 02/51] migration: Fix leak of cpr_exec_command
  2025-12-15 21:59 ` [PATCH v3 02/51] migration: Fix leak of cpr_exec_command Fabiano Rosas
@ 2025-12-16 16:48   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 16:48 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru

On Mon, Dec 15, 2025 at 06:59:48PM -0300, Fabiano Rosas wrote:
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 03/51] migration: Add a qdev property for StrOrNull
  2025-12-15 21:59 ` [PATCH v3 03/51] migration: Add a qdev property for StrOrNull Fabiano Rosas
@ 2025-12-16 16:57   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 16:57 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru

On Mon, Dec 15, 2025 at 06:59:49PM -0300, Fabiano Rosas wrote:
> The MigrationState is a QOM object with TYPE_DEVICE as a parent. This
> was done about eight years ago so the migration code could make use of
> qdev properties to define the defaults for the migration parameters
> and to be able to expose migration knobs for debugging via the
> '-global migration' command line option.
> 
> Due to unrelated historical reasons, three of the migration parameters
> (TLS options) received different types when used via the
> query-migrate-parameters QMP command than with the
> migrate-set-parameters command. This has created a lot of duplication
> in the migration code and in the QAPI documentation because the whole
> of MigrationParameters had to be duplicated as well.
> 
> The migration code is now being fixed to remove the duplication and
> for that to happen the offending fields need to be reconciled into a
> single type. The StrOrNull type is going to be used.
> 
> To keep the command line compatibility, the parameters need to
> continue being exposed via qdev properties accessible from the command
> line. Introduce a qdev property StrOrNull just for that.
> 
> Note that this code is being kept in migration/options.c as this
> version of StrOrNull doesn't need to handle QNULL because it was never
> a valid option in the previous command line, which took a string.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Acked-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 04/51] tests/qtest/migration: Add a NULL parameters test for TLS
  2025-12-15 21:59 ` [PATCH v3 04/51] tests/qtest/migration: Add a NULL parameters test for TLS Fabiano Rosas
@ 2025-12-16 17:03   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 17:03 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 06:59:50PM -0300, Fabiano Rosas wrote:
> Make sure the TLS options handling is working correctly with a NULL
> parameter. This is relevant due to the usage of StrOrNull for the
> tls-creds, tls-authz and tls-hostname options.
> 
> With this, all manners of passing TLS options are somehow covered by
> the tests, we should not need to do manual testing when touching TLS
> options code.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 05/51] migration: Normalize tls arguments
  2025-12-15 21:59 ` [PATCH v3 05/51] migration: Normalize tls arguments Fabiano Rosas
@ 2025-12-16 17:24   ` Peter Xu
  2025-12-17 16:40     ` Fabiano Rosas
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Xu @ 2025-12-16 17:24 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Eric Blake

On Mon, Dec 15, 2025 at 06:59:51PM -0300, Fabiano Rosas wrote:
> The migration parameters tls_creds, tls_authz and tls_hostname
> currently have a non-uniform handling. When used as arguments to
> migrate-set-parameters, their type is StrOrNull and when used as
> return value from query-migrate-parameters their type is a plain
> string.
> 
> Not only having to convert between the types is cumbersome, but it
> also creates the issue of requiring two different QAPI types to be
> used, one for each command. MigrateSetParameters is used for
> migrate-set-parameters with the TLS arguments as StrOrNull while
> MigrationParameters is used for query-migrate-parameters with the TLS
> arguments as str.
> 
> Since StrOrNull could be considered a superset of str, change the type
> of the TLS arguments in MigrationParameters to StrOrNull. Also ensure
> that QTYPE_QNULL is never used.
> 
> 1) migrate-set-parameters will always write QTYPE_QSTRING to
>   s->parameters, either an empty or non-empty string.
> 
> 2) query-migrate-parameters will always return a QTYPE_QSTRING, either
>   empty or non-empty.
> 
> 3) the migrate_tls_* helpers will always return a non-empty string or
>   NULL, for the internal migration code's consumption.
> 
> Points (1) and (2) above help simplify the parameters validation and
> the query command handling because s->parameters is already kept in
> the format that query-migrate-parameters (and info migrate_paramters)
> expect. Point (3) is so people don't need to care about StrOrNull in
> migration code.
> 
> This will allow the type duplication to be removed in the next
> patches.
> 
> Note that the type of @tls_creds, @tls-hostname, @tls-authz changes
> from str to StrOrNull in introspection of the query-migrate-parameters
> command. We accept this imprecision to enable de-duplication.
> 
> There's no need to free the TLS options in
> migration_instance_finalize() because they're freed by the qdev
> properties .release method.
> 
> Temporary in this patch:
> migrate_params_test_apply() copies s->parameters into a temporary
> structure, so it's necessary to drop the references to the TLS options
> if they were not set by the user to avoid double-free. This is fixed
> in the next patches.
> 
> Acked-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

[...]

> @@ -403,6 +403,9 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
>          monitor_printf(mon, "%s: %" PRIu64 " bytes\n",
>              MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE),
>              params->xbzrle_cache_size);
> +        monitor_printf(mon, "%s: %" PRIu64 "\n",
> +            MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH),
> +            params->max_postcopy_bandwidth);
>  
>          if (params->has_block_bitmap_mapping) {
>              const BitmapMigrationNodeAliasList *bmnal;

This chunk seems to be introduced by accident and removed in patch 18..

After removal, feel free to take:

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 10/51] migration: Remove checks for s->parameters has_* fields
  2025-12-15 21:59 ` [PATCH v3 10/51] migration: Remove checks for s->parameters has_* fields Fabiano Rosas
@ 2025-12-16 18:50   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 18:50 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru

On Mon, Dec 15, 2025 at 06:59:56PM -0300, Fabiano Rosas wrote:
> The migration parameters validation produces a temporary structure
> which is the merge of the current parameter values (s->parameters,
> MigrationParameters) with the new parameters set by the user
> (former MigrateSetParameters).
> 
> When copying the values from s->parameters into the temporary
> structure, the has_* fields are copied along, but when merging the
> user-input values they are not.
> 
> During migrate_params_check(), only the parameters that have the
> corresponding has_* field will be checked, so only the parameters that
> were initialized in migrate_params_init() will be validated.
> 
> This causes (almost) all of the migration parameters to be validated
> every time a parameter is set, regardless of which fields the user
> touched, but it also skips validation of any values that are not set
> in migrate_params_init().
> 
> It's not clear what was the intention of the original code, whether to
> validate all fields always, or only validate what the user input
> changed. Since the current situation is closer to the former option,
> make the choice of validating all parameters by removing the checks
> for the has_* fields when validating.
> 
> Note that bringing the user input into the temporary structure for
> validation still needs to look at the has_* fields, otherwise any
> parameters not set by the user (i.e. 0) would override the
> corresponding value in s->parameters.
> 
> The empty migrate_params_init() will be kept because subsequent
> patches will add code to it.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 12/51] migration: Extract code to mark all parameters as present
  2025-12-15 21:59 ` [PATCH v3 12/51] migration: Extract code to mark all parameters as present Fabiano Rosas
@ 2025-12-16 18:56   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 18:56 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Kevin Wolf

On Mon, Dec 15, 2025 at 06:59:58PM -0300, Fabiano Rosas wrote:
> MigrationParameters needs to have all of its has_* fields marked as
> true when used as the return of query_migrate_parameters because the
> corresponding QMP command has all of its members non-optional by
> design, despite them being marked as optional in migration.json.
> 
> Extract this code into a function and make it assert if any field is
> missing. With this we ensure future changes will not inadvertently
> leave any parameters missing.
> 
> Note that the block-bitmap-mapping is a special case because the empty
> list is considered a valid value, so it has historically not been
> present in the command's output if it has never been set.
> 
> CC: Kevin Wolf <kwolf@redhat.com>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 14/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply
  2025-12-15 22:00 ` [PATCH v3 14/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply Fabiano Rosas
@ 2025-12-16 19:31   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 19:31 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru

On Mon, Dec 15, 2025 at 07:00:00PM -0300, Fabiano Rosas wrote:
> Use QAPI_CLONE_MEMBERS instead of making an assignment. The QAPI
> method makes the handling of the TLS strings more intuitive because it
> clones them as well.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
>  migration/options.c | 25 +++++++++++++------------
>  1 file changed, 13 insertions(+), 12 deletions(-)
> 
> diff --git a/migration/options.c b/migration/options.c
> index 6b60003a32..2901b37228 100644
> --- a/migration/options.c
> +++ b/migration/options.c
> @@ -1262,9 +1262,9 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
>  static void migrate_params_test_apply(MigrationParameters *params,
>                                        MigrationParameters *dest)
>  {
> -    *dest = migrate_get_current()->parameters;
> +    MigrationState *s = migrate_get_current();
>  
> -    /* TODO use QAPI_CLONE() instead of duplicating it inline */
> +    QAPI_CLONE_MEMBERS(MigrationParameters, dest, &s->parameters);
>  
>      if (params->has_throttle_trigger_threshold) {
>          dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
> @@ -1283,24 +1283,18 @@ static void migrate_params_test_apply(MigrationParameters *params,
>      }
>  
>      if (params->tls_creds) {
> +        qapi_free_StrOrNull(dest->tls_creds);
>          dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
> -    } else {
> -        /* clear the reference, it's owned by s->parameters */
> -        dest->tls_creds = NULL;
>      }
>  
>      if (params->tls_hostname) {
> +        qapi_free_StrOrNull(dest->tls_hostname);
>          dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
> -    } else {
> -        /* clear the reference, it's owned by s->parameters */
> -        dest->tls_hostname = NULL;
>      }
>  
>      if (params->tls_authz) {
> +        qapi_free_StrOrNull(dest->tls_authz);
>          dest->tls_authz = QAPI_CLONE(StrOrNull, params->tls_authz);
> -    } else {
> -        /* clear the reference, it's owned by s->parameters */
> -        dest->tls_authz = NULL;
>      }
>  
>      if (params->has_max_bandwidth) {
> @@ -1357,7 +1351,6 @@ static void migrate_params_test_apply(MigrationParameters *params,
>      }
>  
>      if (params->has_block_bitmap_mapping) {
> -        dest->has_block_bitmap_mapping = true;
>          dest->block_bitmap_mapping = params->block_bitmap_mapping;

Now "dest" came from a QAPI_CLONE, does it also need explicit free and
QAPI_CLONE() from params->block_bitmap_mapping?

I think this part looks fine when the whole set is applied, so it's only a
question of intermediate stage of this patch.

>      }
>  
> @@ -1532,6 +1525,14 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
>  
>      migrate_params_test_apply(params, &tmp);
>  
> +    /*
> +     * Mark block_bitmap_mapping as present now while we have the
> +     * params structure with the user input around.
> +     */
> +    if (params->has_block_bitmap_mapping) {
> +        migrate_get_current()->has_block_bitmap_mapping = true;
> +    }

Should this be put into the if block below?  Aka, when we decide to apply
the parameters?

> +
>      if (migrate_params_check(&tmp, errp)) {
>          migrate_params_apply(params);
>          migrate_post_update_params(params, errp);
> -- 
> 2.51.0
> 

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 15/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply
  2025-12-15 22:00 ` [PATCH v3 15/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply Fabiano Rosas
@ 2025-12-16 20:26   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 20:26 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru

On Mon, Dec 15, 2025 at 07:00:01PM -0300, Fabiano Rosas wrote:
> Instead of setting parameters one by one, use the temporary object,
> which already contains the current migration parameters plus the new
> ones and was just validated by migration_params_check(). Use cloning
> to overwrite it.
> 
> This avoids the need to alter this function every time a new parameter
> is added.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 16/51] qapi: Add QAPI_MERGE
  2025-12-15 22:00 ` [PATCH v3 16/51] qapi: Add QAPI_MERGE Fabiano Rosas
@ 2025-12-16 20:30   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 20:30 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Michael Roth

On Mon, Dec 15, 2025 at 07:00:02PM -0300, Fabiano Rosas wrote:
> The migration subsystem currently has code to merge two objects of the
> same type. It does so by checking which fields are present in a source
> object and overwriting the corresponding fields on the destination
> object. This leads to a lot of open-coded lines such as:
> 
>     if (src->has_foobar) {
>         dst->foobar = src->foobar;
>     }
> 
> This pattern could be replaced by a copy using visitors. Implement a
> macro that extracts elements from a source object using an output
> visitor and merges it with a destination object using an input
> visitor.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Let's see how QAPI maintainers think..  Looks good here:

Acked-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 17/51] migration: Use QAPI_MERGE in migrate_params_test_apply
  2025-12-15 22:00 ` [PATCH v3 17/51] migration: Use QAPI_MERGE in migrate_params_test_apply Fabiano Rosas
@ 2025-12-16 20:47   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 20:47 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru

On Mon, Dec 15, 2025 at 07:00:03PM -0300, Fabiano Rosas wrote:
> @@ -1260,124 +1261,28 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
>      return true;
>  }
>  
> -static void migrate_params_test_apply(MigrationParameters *params,
> -                                      MigrationParameters *dest)
> +static void migrate_params_merge(MigrationParameters *dst,
> +                                 MigrationParameters *src)
>  {
> -    MigrationState *s = migrate_get_current();
> -
> -    QAPI_CLONE_MEMBERS(MigrationParameters, dest, &s->parameters);
> -
> -    if (params->has_throttle_trigger_threshold) {
> -        dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
> -    }
> -
> -    if (params->has_cpu_throttle_initial) {
> -        dest->cpu_throttle_initial = params->cpu_throttle_initial;
> -    }
> -
> -    if (params->has_cpu_throttle_increment) {
> -        dest->cpu_throttle_increment = params->cpu_throttle_increment;
> +    /* free memory from pointers that are about to be assigned */
> +    if (src->has_block_bitmap_mapping) {
> +        g_clear_pointer(&dst->block_bitmap_mapping,
> +                        qapi_free_BitmapMigrationNodeAliasList);
>      }
>  
> -    if (params->has_cpu_throttle_tailslow) {
> -        dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow;
> +    if (src->tls_creds) {
> +        g_clear_pointer(&dst->tls_creds, qapi_free_StrOrNull);
>      }
>  
> -    if (params->tls_creds) {
> -        qapi_free_StrOrNull(dest->tls_creds);
> -        dest->tls_creds = QAPI_CLONE(StrOrNull, params->tls_creds);
> +    if (src->tls_hostname) {
> +        g_clear_pointer(&dst->tls_hostname, qapi_free_StrOrNull);
>      }
>  
> -    if (params->tls_hostname) {
> -        qapi_free_StrOrNull(dest->tls_hostname);
> -        dest->tls_hostname = QAPI_CLONE(StrOrNull, params->tls_hostname);
> +    if (src->tls_authz) {
> +        g_clear_pointer(&dst->tls_authz, qapi_free_StrOrNull);
>      }

These will still be error prone when introducing new parameters that needs
explicit frees.  It'll be nice if QAPI_MERGE() can free the elements when
present in dest and when to be replaced.

But this is good enough, let's land this series first..

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 25/51] tests/qtest/migration: Pass MigrateCommon into test functions
  2025-12-15 22:00 ` [PATCH v3 25/51] tests/qtest/migration: Pass MigrateCommon into test functions Fabiano Rosas
@ 2025-12-16 21:57   ` Peter Xu
  2025-12-17 18:35   ` Peter Xu
  1 sibling, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 21:57 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:11PM -0300, Fabiano Rosas wrote:
> With the upcoming addition of the config QDict, the tests will need a
> better way of managing the memory of the test data than putting the
> test arguments on the stack of the test functions. The config QDict
> will need to be merged into the arguments of migrate_qmp* functions,
> which causes a refcount increment, so the test functions would need to
> allocate and deref the config QDict themselves.
> 
> A better approach is to already pass the arguments into the test
> functions and do the memory management in the existing wrapper. There
> is already migration_test_destroy(), which is called for every test.
> 
> Do the following:
> 
> - merge the two existing wrappers, migration_test_wrapper() and
>   migration_test_wrapper_full(). The latter was pioneer in passing
>   data into the tests, but now all tests will receive data, so we
>   don't need it anymore.
> 
>   The usage of migration_test_wrapper_full() was in passing a slightly
>   different test name string into the cancel tests, so still keep the
>   migration_test_add_suffix() function.
> 
> - add (char *name, MigrateCommon *args) to the signature of all test
>   functions.
> 
> - alter any code to stop allocating args on the stack and instead use
>   the object that came as parameter.
> 
> - pass args around as needed.
> 
> - while here, order args (MigrateCommon) before args->start
>   (MigrateStart) and put a blank like in between.
> 
> No functional change.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

This looks fine,

Reviewed-by: Peter Xu <peterx@redhat.com>

I'm just curious, is it required to touch all these lines?  E.g.,

> ---
>  tests/qtest/migration/compression-tests.c | 127 +++---
>  tests/qtest/migration/cpr-tests.c         |  71 ++--
>  tests/qtest/migration/file-tests.c        | 184 ++++----
>  tests/qtest/migration/migration-util.c    |  26 +-
>  tests/qtest/migration/migration-util.h    |   8 +-
>  tests/qtest/migration/misc-tests.c        | 108 ++---
>  tests/qtest/migration/postcopy-tests.c    |  80 ++--
>  tests/qtest/migration/precopy-tests.c     | 354 +++++++---------
>  tests/qtest/migration/tls-tests.c         | 485 ++++++++++------------
>  9 files changed, 642 insertions(+), 801 deletions(-)
> 
> diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
> index b827665b8e..845e622cd5 100644
> --- a/tests/qtest/migration/compression-tests.c
> +++ b/tests/qtest/migration/compression-tests.c
> @@ -31,30 +31,25 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
>      return migrate_hook_start_precopy_tcp_multifd_common(from, to, "zstd");
>  }
>  
> -static void test_multifd_tcp_zstd(void)
> +static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
>  {
> -    MigrateCommon args = {

Can this be changed to:

       *args = (struct MigrateCommon) {

So as to avoid touching most of below across whole tree?

> -        .listen_uri = "defer",
> -        .start = {
> -            .caps[MIGRATION_CAPABILITY_MULTIFD] = true,
> -        },
> -        .start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
> -    };
> -    test_precopy_common(&args);
> +    args->listen_uri = "defer";
> +    args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
> +
> +    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> +
> +    test_precopy_common(args);
>  }

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 26/51] tests/qtest/migration: Pass MigrateStart into cancel tests
  2025-12-15 22:00 ` [PATCH v3 26/51] tests/qtest/migration: Pass MigrateStart into cancel tests Fabiano Rosas
@ 2025-12-16 21:57   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-16 21:57 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:12PM -0300, Fabiano Rosas wrote:
> Pass the "args" parameter to the cancel tests so they can access the
> config object which will be part of this struct.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 27/51] tests/qtest/migration: Fix misuse of listen_uri
  2025-12-15 22:00 ` [PATCH v3 27/51] tests/qtest/migration: Fix misuse of listen_uri Fabiano Rosas
@ 2025-12-17 15:30   ` Peter Xu
  2025-12-17 16:59     ` Fabiano Rosas
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Xu @ 2025-12-17 15:30 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:13PM -0300, Fabiano Rosas wrote:
> The listen_uri parameter is supposed to be used for the incoming
> migration while connect_uri for the outgoing migration. This is well
> documented in the header file.
> 
> However, due to -incoming "defer", some tests set listen-uri =
> "defer", which is fine. But then, being without another parameter to
> define the uri to be use in migrate_incoming, some tests have been
> misusing connect_uri.
> 
> Add a separate flag to denote "defer" and spare the tests from passing
> the string. Change the usage of listen_uri to it's original purpose.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
>  tests/qtest/migration/compression-tests.c | 12 +++----
>  tests/qtest/migration/cpr-tests.c         | 17 +++++++---
>  tests/qtest/migration/file-tests.c        | 38 ++++++++++++++++-------
>  tests/qtest/migration/framework.c         | 12 +++----
>  tests/qtest/migration/framework.h         |  7 +++++
>  tests/qtest/migration/misc-tests.c        |  4 +--
>  tests/qtest/migration/precopy-tests.c     | 26 ++++++++++------
>  tests/qtest/migration/tls-tests.c         | 16 +++++-----
>  8 files changed, 85 insertions(+), 47 deletions(-)

Makes sense.

But there's one missing?  I'm staring at a tree where wholeset applied, I
can still see:

static void test_mode_exec(char *name, MigrateCommon *args)
{
    g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                           FILE_TEST_FILENAME);
    g_autofree char *listen_uri = g_strdup_printf("defer"); <-------------

    args->connect_uri = uri;
    args->listen_uri = listen_uri;
    ...
}

The other question is, after this patch, can we assume connect_uri and
listen_uri should always be the same?  Can we merge the two already into
"uri"?

For the latter - not a request to do it in this series, I suggest we land
this series without keep growing, or you'll have endless pain rebasing..
However no hurt to discuss the next step so you can send them afterwards if
you see fit.

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 24/51] migration: Allow incoming cmdline to take config
  2025-12-15 22:00 ` [PATCH v3 24/51] migration: Allow incoming cmdline to take config Fabiano Rosas
@ 2025-12-17 15:34   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-17 15:34 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:10PM -0300, Fabiano Rosas wrote:
> When -incoming "defer" is not used, the incoming migration is invoked
> directly by the command line parsing code in vl.c. Allow the migration
> config to be passed via the -incoming command line option so that
> invocation of qmp_migrate_incoming() can receive it.
> 
> E.g.
> -incoming '{"tls-creds": "tlscredsx509server0", "tls-hostname": "qemu.org"}'
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
> This is useful for the tests. If we want to declare that
> config-passing only works with -incoming defer, that's fine with me.

This can also be done with -global migration.xxx, right?  Except that
-global can also work for either src or dest, I thought that was a bonus as
more flexible.

Maybe I overlooked some reasons from testing side?..

> ---
>  system/vl.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 100 insertions(+), 12 deletions(-)
> 
> diff --git a/system/vl.c b/system/vl.c
> index d09dc9a61c..ac44933a11 100644
> --- a/system/vl.c
> +++ b/system/vl.c
> @@ -169,6 +169,9 @@ static const char *mem_path;
>  static const char *incoming;
>  static const char *incoming_str[MIGRATION_CHANNEL_TYPE__MAX];
>  static MigrationChannel *incoming_channels[MIGRATION_CHANNEL_TYPE__MAX];
> +static MigrationParameters *migration_config;
> +static Error *migration_channel_err;
> +static Error *migration_config_err;
>  static const char *loadvm;
>  static const char *accelerators;
>  static bool have_custom_ram_size;
> @@ -1825,28 +1828,102 @@ static void object_option_add_visitor(Visitor *v)
>      QTAILQ_INSERT_TAIL(&object_opts, opt, next);
>  }
>  
> -static void incoming_option_parse(const char *str)
> +/*
> + * Either "defer" or a proper uri, whether plain string or a json
> + * representation of MigrationChannel.
> + */
> +static bool incoming_option_parse_channels(const char *str, Error **errp)
>  {
>      MigrationChannelType type = MIGRATION_CHANNEL_TYPE_MAIN;
> -    MigrationChannel *channel;
> +    MigrationChannel *channel = NULL;
>      Visitor *v;
>  
> -    if (!strcmp(str, "defer")) {
> -        channel = NULL;
> -    } else if (migrate_is_uri(str)) {
> +    if (g_str_equal(str, "defer")) {
> +        incoming_str[type] = str;
> +        return true;
> +    }
> +
> +    if (migrate_is_uri(str)) {
>          migrate_uri_parse(str, &channel, &error_fatal);
>      } else {
>          v = qobject_input_visitor_new_str(str, "channel-type", &error_fatal);
> -        visit_type_MigrationChannel(v, NULL, &channel, &error_fatal);
> +        if (v && !visit_type_MigrationChannel(v, NULL, &channel, errp)) {
> +            visit_free(v);
> +            return false;
> +        }
>          visit_free(v);
> +    }
> +
> +    if (channel) {
>          type = channel->channel_type;
> +        /* New incoming spec replaces the previous */
> +        qapi_free_MigrationChannel(incoming_channels[type]);
> +        incoming_channels[type] = channel;
> +        incoming_str[type] = str;
>      }
>  
> -    /* New incoming spec replaces the previous */
> -    qapi_free_MigrationChannel(incoming_channels[type]);
> -    incoming_channels[type] = channel;
> -    incoming_str[type] = str;
>      incoming = incoming_str[MIGRATION_CHANNEL_TYPE_MAIN];
> +    return true;
> +}
> +
> +/*
> + * The migration configuration object in JSON form.
> + */
> +static bool incoming_option_parse_config(const char *str, Error **errp)
> +{
> +    MigrationParameters *config = NULL;
> +    Visitor *v;
> +
> +    v = qobject_input_visitor_new_str(str, "config", &error_fatal);
> +    if (v && !visit_type_MigrationParameters(v, NULL, &config, errp)) {
> +        visit_free(v);
> +        return false;
> +    }
> +
> +    if (config) {
> +        /* later incoming configs replace the previous ones */
> +        migration_config = config;
> +    }
> +
> +    visit_free(v);
> +    return true;
> +}
> +
> +static void incoming_option_parse(const char *str)
> +{
> +    /*
> +     * Independent Error objects because we don't know whether the
> +     * input is meant to be the channels or the config. The parsing
> +     * may fail for one and succeed for the other.
> +     */
> +    g_autoptr(Error) channel_err = NULL;
> +    g_autoptr(Error) config_err = NULL;
> +
> +    /*
> +     * Skip if there's already an error for a previous -incoming
> +     * instance.
> +     */
> +    if (migration_channel_err || migration_config_err) {
> +        return;
> +    }
> +
> +    if (!migration_channel_err &&
> +        incoming_option_parse_channels(str, &channel_err)) {
> +        return;
> +    }
> +
> +    if (!migration_config_err &&
> +        incoming_option_parse_config(str, &config_err)) {
> +        return;
> +    }
> +
> +    if (channel_err) {
> +        migration_channel_err = error_copy(channel_err);
> +        error_prepend(&migration_channel_err, "-incoming %s: ", str);
> +    } else if (config_err) {
> +        migration_config_err = error_copy(config_err);
> +        error_prepend(&migration_config_err, "-incoming %s: ", str);
> +    }
>  }
>  
>  static void object_option_parse(const char *str)
> @@ -2537,6 +2614,16 @@ static void qemu_validate_options(const QDict *machine_opts)
>          exit(EXIT_FAILURE);
>      }
>  
> +    if (migration_channel_err && !incoming) {
> +        error_report_err(migration_config_err);
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    if (migration_config_err && !migration_config) {
> +        error_report_err(migration_config_err);
> +        exit(EXIT_FAILURE);
> +    }
> +
>  #ifdef CONFIG_CURSES
>      if (is_daemonized() && dpy.type == DISPLAY_TYPE_CURSES) {
>          error_report("curses display cannot be used with -daemonize");
> @@ -2824,13 +2911,14 @@ void qmp_x_exit_preconfig(Error **errp)
>  
>      if (incoming) {
>          Error *local_err = NULL;
> +
>          if (strcmp(incoming, "defer") != 0) {
>              g_autofree MigrationChannelList *channels =
>                  g_new0(MigrationChannelList, 1);
>  
>              channels->value = incoming_channels[MIGRATION_CHANNEL_TYPE_MAIN];
> -            qmp_migrate_incoming(NULL, true, channels, NULL, true, true,
> -                                 &local_err);
> +            qmp_migrate_incoming(NULL, true, channels, migration_config, true,
> +                                 true, &local_err);
>              if (local_err) {
>                  error_reportf_err(local_err, "-incoming %s: ", incoming);
>                  exit(1);
> -- 
> 2.51.0
> 

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 05/51] migration: Normalize tls arguments
  2025-12-16 17:24   ` Peter Xu
@ 2025-12-17 16:40     ` Fabiano Rosas
  0 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-17 16:40 UTC (permalink / raw)
  To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Eric Blake

Peter Xu <peterx@redhat.com> writes:

> On Mon, Dec 15, 2025 at 06:59:51PM -0300, Fabiano Rosas wrote:
>> The migration parameters tls_creds, tls_authz and tls_hostname
>> currently have a non-uniform handling. When used as arguments to
>> migrate-set-parameters, their type is StrOrNull and when used as
>> return value from query-migrate-parameters their type is a plain
>> string.
>> 
>> Not only having to convert between the types is cumbersome, but it
>> also creates the issue of requiring two different QAPI types to be
>> used, one for each command. MigrateSetParameters is used for
>> migrate-set-parameters with the TLS arguments as StrOrNull while
>> MigrationParameters is used for query-migrate-parameters with the TLS
>> arguments as str.
>> 
>> Since StrOrNull could be considered a superset of str, change the type
>> of the TLS arguments in MigrationParameters to StrOrNull. Also ensure
>> that QTYPE_QNULL is never used.
>> 
>> 1) migrate-set-parameters will always write QTYPE_QSTRING to
>>   s->parameters, either an empty or non-empty string.
>> 
>> 2) query-migrate-parameters will always return a QTYPE_QSTRING, either
>>   empty or non-empty.
>> 
>> 3) the migrate_tls_* helpers will always return a non-empty string or
>>   NULL, for the internal migration code's consumption.
>> 
>> Points (1) and (2) above help simplify the parameters validation and
>> the query command handling because s->parameters is already kept in
>> the format that query-migrate-parameters (and info migrate_paramters)
>> expect. Point (3) is so people don't need to care about StrOrNull in
>> migration code.
>> 
>> This will allow the type duplication to be removed in the next
>> patches.
>> 
>> Note that the type of @tls_creds, @tls-hostname, @tls-authz changes
>> from str to StrOrNull in introspection of the query-migrate-parameters
>> command. We accept this imprecision to enable de-duplication.
>> 
>> There's no need to free the TLS options in
>> migration_instance_finalize() because they're freed by the qdev
>> properties .release method.
>> 
>> Temporary in this patch:
>> migrate_params_test_apply() copies s->parameters into a temporary
>> structure, so it's necessary to drop the references to the TLS options
>> if they were not set by the user to avoid double-free. This is fixed
>> in the next patches.
>> 
>> Acked-by: Markus Armbruster <armbru@redhat.com>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>
> [...]
>
>> @@ -403,6 +403,9 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
>>          monitor_printf(mon, "%s: %" PRIu64 " bytes\n",
>>              MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE),
>>              params->xbzrle_cache_size);
>> +        monitor_printf(mon, "%s: %" PRIu64 "\n",
>> +            MigrationParameter_str(MIGRATION_PARAMETER_MAX_POSTCOPY_BANDWIDTH),
>> +            params->max_postcopy_bandwidth);
>>  
>>          if (params->has_block_bitmap_mapping) {
>>              const BitmapMigrationNodeAliasList *bmnal;
>
> This chunk seems to be introduced by accident and removed in patch 18..
>

Yes, rebase mistake. Thanks.


^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 00/51] migration: Unify capabilities and parameters
  2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
                   ` (50 preceding siblings ...)
  2025-12-15 22:00 ` [PATCH v3 51/51] tests/qtest/migration: Further simplify TLS tests Fabiano Rosas
@ 2025-12-17 16:58 ` Peter Xu
  51 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-17 16:58 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru

On Mon, Dec 15, 2025 at 06:59:46PM -0300, Fabiano Rosas wrote:
> Hi, the scope of this series is the same as the previous versions, but
> to be explicit, these are various parts of which it's comprised:
> 
> 1) Remove duplication of migration parameters documentation in
>    migration.json.
> 
> 2) Merge migration capabilities and parameters in MigrationState (as
>    visible internally in migration code).
> 
> 3) Deprecate migration capabilities QMP commands. Functionality
>    previously provided by "capabilities" commands are now provided by
>    "parameters" commands.
> 
> 4) Introduce new 'config' argument to migration commands taking the
>    entire set of options to use for a migration. Obsoletes the usage
>    of migrate-set-parameters, except for "runtime" options, which are
>    as of yet uncovered by this proposal.
> 
> 5) Adapt all migration-test(s) to use the new config API exclusively.
> 
> Notable changes in this v3:
> 
> - Added the setter for the new StrOrNull qdev property
> - Move the visitor code into a new QAPI_MERGE macro
> - Converted all tests to use config
>   - Unfortunate side-quest: rework the TLS test hooks to support
>     setting options before migrate_start.
> 
> CI run: https://gitlab.com/farosas/qemu/-/pipelines/2216127826
> 
> v2:
> https://lore.kernel.org/r/20250630195913.28033-1-farosas@suse.de
> 
> v1:
> https://lore.kernel.org/r/20250603013810.4772-1-farosas@suse.de
> 
> RFC:
> https://lore.kernel.org/r/20250411191443.22565-1-farosas@suse.de
> 
> Fabiano Rosas (51):
>   migration: Fix leak of block_bitmap_mapping
>   migration: Fix leak of cpr_exec_command
>   migration: Add a qdev property for StrOrNull
>   tests/qtest/migration: Add a NULL parameters test for TLS
>   migration: Normalize tls arguments
>   migration: Remove MigrateSetParameters
>   qapi/migration: Don't document MigrationParameter
>   migration: Run a post update routine after setting parameters
>   migration: Add a flag to track block-bitmap-mapping input
>   migration: Remove checks for s->parameters has_* fields
>   migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE
>   migration: Extract code to mark all parameters as present
>   migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters
>   migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply
>   migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply
>   qapi: Add QAPI_MERGE
>   migration: Use QAPI_MERGE in migrate_params_test_apply
>   migration: Cleanup hmp_info_migrate_parameters
>   migration: Add capabilities into MigrationParameters
>   migration: Remove s->capabilities
>   qapi/migration: Deprecate capabilities commands
>   migration: Store the initial values used for s->parameters
>   migration: Allow migrate commands to provide the migration config
>   migration: Allow incoming cmdline to take config
>   tests/qtest/migration: Pass MigrateCommon into test functions
>   tests/qtest/migration: Pass MigrateStart into cancel tests
>   tests/qtest/migration: Fix misuse of listen_uri
>   tests/qtest/migration: Stop invoking migrate_incoming from hooks
>   tests/qtest/migration: Add config QDict
>   tests/qtest/migration: Add temporary code to toggle usage of config
>   tests/qtest/migration: Add a function for default capabilities
>   tests/qtest/migration: Adapt convergence routines to config
>   tests/qtest/migration: Adapt the incoming cmdline for config passing
>   tests/qtest/migration: Use migrate_incoming_qmp where possible
>   tests/qtest/migration: Add a config parameter to migrate_qmp functions
>   tests/qtest/migration: Move tls hook data out of specific hooks
>   tests/qtest/migration: Add new hook with data
>   tests/qtest/migration: TLS x509: Refactor to use full hook
>   tests/qtest/migration: TLS x509: Add init/cleanup routines
>   tests/qtest/migration: TLS PSK: Refactor to use full hook
>   tests/qtest/migration: TLS PSK: Add init/cleanup routines
>   tests/qtest/migration: Remove multifd compression hook
>   tests/qtest/migration: Convert postcopy tests to use config
>   tests/qtest/migration: Convert TLS PSK tests to use config
>   tests/qtest/migration: Convert TLS x509 tests to use config
>   tests/qtest/migration: Convert compression tests to use config
>   tests/qtest/migration: Convert file tests to use config
>   tests/qtest/migration: Convert misc-tests to use config
>   tests/qtest/migration: Convert precopy tests to use config
>   tests/qtest/migration: Remove migrate_set_capabilities and code around
>     it
>   tests/qtest/migration: Further simplify TLS tests

I'll keep reviewing the rest test changes.. while I've queued patches
1-13,25,26 for the upcoming pull for qemu 11.0.  Please shoot if there's
any concerns.

Thanks,

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 27/51] tests/qtest/migration: Fix misuse of listen_uri
  2025-12-17 15:30   ` Peter Xu
@ 2025-12-17 16:59     ` Fabiano Rosas
  0 siblings, 0 replies; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-17 16:59 UTC (permalink / raw)
  To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

Peter Xu <peterx@redhat.com> writes:

> On Mon, Dec 15, 2025 at 07:00:13PM -0300, Fabiano Rosas wrote:
>> The listen_uri parameter is supposed to be used for the incoming
>> migration while connect_uri for the outgoing migration. This is well
>> documented in the header file.
>> 
>> However, due to -incoming "defer", some tests set listen-uri =
>> "defer", which is fine. But then, being without another parameter to
>> define the uri to be use in migrate_incoming, some tests have been
>> misusing connect_uri.
>> 
>> Add a separate flag to denote "defer" and spare the tests from passing
>> the string. Change the usage of listen_uri to it's original purpose.
>> 
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>>  tests/qtest/migration/compression-tests.c | 12 +++----
>>  tests/qtest/migration/cpr-tests.c         | 17 +++++++---
>>  tests/qtest/migration/file-tests.c        | 38 ++++++++++++++++-------
>>  tests/qtest/migration/framework.c         | 12 +++----
>>  tests/qtest/migration/framework.h         |  7 +++++
>>  tests/qtest/migration/misc-tests.c        |  4 +--
>>  tests/qtest/migration/precopy-tests.c     | 26 ++++++++++------
>>  tests/qtest/migration/tls-tests.c         | 16 +++++-----
>>  8 files changed, 85 insertions(+), 47 deletions(-)
>
> Makes sense.
>
> But there's one missing?  I'm staring at a tree where wholeset applied, I
> can still see:
>
> static void test_mode_exec(char *name, MigrateCommon *args)
> {
>     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
>                                            FILE_TEST_FILENAME);
>     g_autofree char *listen_uri = g_strdup_printf("defer"); <-------------
>

Missed that one.

>     args->connect_uri = uri;
>     args->listen_uri = listen_uri;
>     ...
> }
>
> The other question is, after this patch, can we assume connect_uri and
> listen_uri should always be the same?  Can we merge the two already into
> "uri"?
>

Yes, because the tests run on the same machine, so the endpoint is
always the same. I don't think we do any tricks of making them mismatch
just to see it burn. It could be useful for testing maybe, or not. I'll
check and if they're indeed always the same I can merge them, it would
clarify the code a lot.

> For the latter - not a request to do it in this series, I suggest we land
> this series without keep growing, or you'll have endless pain rebasing..
> However no hurt to discuss the next step so you can send them afterwards if
> you see fit.



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 25/51] tests/qtest/migration: Pass MigrateCommon into test functions
  2025-12-15 22:00 ` [PATCH v3 25/51] tests/qtest/migration: Pass MigrateCommon into test functions Fabiano Rosas
  2025-12-16 21:57   ` Peter Xu
@ 2025-12-17 18:35   ` Peter Xu
  1 sibling, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-17 18:35 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:11PM -0300, Fabiano Rosas wrote:
> With the upcoming addition of the config QDict, the tests will need a
> better way of managing the memory of the test data than putting the
> test arguments on the stack of the test functions. The config QDict
> will need to be merged into the arguments of migrate_qmp* functions,
> which causes a refcount increment, so the test functions would need to
> allocate and deref the config QDict themselves.
> 
> A better approach is to already pass the arguments into the test
> functions and do the memory management in the existing wrapper. There
> is already migration_test_destroy(), which is called for every test.

This patch has a conflict with the other mapped-ram fix patch queued for
11.0 already:

https://lore.kernel.org/all/20251126121233.542473-1-pzmarzly0@gmail.com/

I'll squash this fixup into this patch when sending the pull:

From 5a772b9f992d87055151ab3a026e08b8dc87409e Mon Sep 17 00:00:00 2001
From: Peter Xu <peterx@redhat.com>
Date: Wed, 17 Dec 2025 13:31:08 -0500
Subject: [PATCH] fixup! tests/qtest/migration: Pass MigrateCommon into test
 functions

Signed-off-by: Peter Xu <peterx@redhat.com>
---
 tests/qtest/migration/file-tests.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c
index c4c3016f0a..5d1b861cf6 100644
--- a/tests/qtest/migration/file-tests.c
+++ b/tests/qtest/migration/file-tests.c
@@ -281,20 +281,18 @@ static void migration_test_add_file_smoke(MigrationTestEnv *env)
                        test_multifd_file_mapped_ram_dio);
 }
 
-static void test_precopy_file_mapped_ram_ignore_shared(void)
+static void
+test_precopy_file_mapped_ram_ignore_shared(char *name, MigrateCommon *args)
 {
     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
                                            FILE_TEST_FILENAME);
-    MigrateCommon args = {
-        .connect_uri = uri,
-        .listen_uri = "defer",
-        .start = {
-            .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true,
-            .caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true,
-        },
-    };
-
-    test_file_common(&args, true);
+    args->connect_uri = uri;
+    args->listen_uri = "defer";
+
+    args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true;
+    args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
+
+    test_file_common(args, true);
 }
 
 void migration_test_add_file(MigrationTestEnv *env)
-- 
2.50.1


-- 
Peter Xu



^ permalink raw reply related	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 28/51] tests/qtest/migration: Stop invoking migrate_incoming from hooks
  2025-12-15 22:00 ` [PATCH v3 28/51] tests/qtest/migration: Stop invoking migrate_incoming from hooks Fabiano Rosas
@ 2025-12-17 20:26   ` Peter Xu
  2025-12-17 21:05     ` Fabiano Rosas
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Xu @ 2025-12-17 20:26 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:14PM -0300, Fabiano Rosas wrote:
> Now that the listen_uri is being properly used, tests can stop calling
> migrate_incoming from their hooks. The _common functions and
> migrate_start should take care of that.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

IMHO this patch is almost fine,

Reviewed-by: Peter Xu <peterx@redhat.com>

still, some thoughts inline.

> ---
>  tests/qtest/migration/compression-tests.c |  6 ++++++
>  tests/qtest/migration/framework.c         | 14 +++++++++++---
>  tests/qtest/migration/precopy-tests.c     |  7 ++++---
>  tests/qtest/migration/tls-tests.c         |  8 ++++++++
>  4 files changed, 29 insertions(+), 6 deletions(-)
> 
> diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
> index eb0b7d6b4b..bed39dece0 100644
> --- a/tests/qtest/migration/compression-tests.c
> +++ b/tests/qtest/migration/compression-tests.c
> @@ -33,6 +33,7 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
>  
>  static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
>  {
> +    args->listen_uri = "tcp:127.0.0.1:0";

Definitely a step forward to unify migrate_incoming into the precopy
framework, however lots duplication of this "tcp:*" string..

Shall we provide some migrate_common_set_listen_uri_default()?

>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
>  
>      args->start.incoming_defer = true;
> @@ -43,6 +44,7 @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
>  
>  static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
>  {
> +    args->listen_uri = "tcp:127.0.0.1:0";
>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
>  
>      args->start.incoming_defer = true;
> @@ -66,6 +68,7 @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
>  
>  static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
>  {
> +    args->listen_uri = "tcp:127.0.0.1:0";
>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip;
>  
>      args->start.incoming_defer = true;
> @@ -85,6 +88,7 @@ migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
>  
>  static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
>  {
> +    args->listen_uri = "tcp:127.0.0.1:0";
>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl;
>  
>      args->start.incoming_defer = true;
> @@ -104,6 +108,7 @@ migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
>  
>  static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
>  {
> +    args->listen_uri = "tcp:127.0.0.1:0";
>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk;
>  
>      args->start.incoming_defer = true;
> @@ -156,6 +161,7 @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
>  
>  static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
>  {
> +    args->listen_uri = "tcp:127.0.0.1:0";
>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib;
>  
>      args->start.incoming_defer = true;
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index e811945122..199e439263 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -820,6 +820,9 @@ int test_precopy_common(MigrateCommon *args)
>      QObject *out_channels = NULL;
>  
>      g_assert(!args->cpr_channel || args->connect_channels);
> +    if (args->start.incoming_defer) {
> +        g_assert(args->listen_uri || args->connect_channels);
> +    }
>  
>      if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
>          return -1;
> @@ -829,6 +832,14 @@ int test_precopy_common(MigrateCommon *args)
>          data_hook = args->start_hook(from, to);
>      }
>  
> +    if (args->start.incoming_defer && !args->start.defer_target_connect) {
> +        if (args->connect_channels) {
> +            in_channels = qobject_from_json(args->connect_channels,
> +                                            &error_abort);
> +        }
> +        migrate_incoming_qmp(to, args->listen_uri, in_channels, "{}");
> +    }

The changes here in the framework code looks all correct, even though I
don't think "connect_channels" is used here in this patch.

Said that, IMHO the channel management is chaos right now in our qtest..
At least it took me some time staring at this path when reviewing.

IMHO a major reason is due to the cpr complexities.

E.g. test_mode_transfer_common() used different things to specify incoming
channels (cpr_channel, opts_target, connect_channels).  We should clean
them up at some point..

> +
>      /* Wait for the first serial output from the source */
>      if (args->result == MIG_TEST_SUCCEED) {
>          wait_for_serial("src_serial");
> @@ -1060,9 +1071,6 @@ void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from,
>      migrate_set_parameter_str(from, "multifd-compression", method);
>      migrate_set_parameter_str(to, "multifd-compression", method);
>  
> -    /* Start incoming migration from the 1st socket */
> -    migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
> -
>      return NULL;
>  }
>  
> diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
> index d9c463dd0f..ab5789717f 100644
> --- a/tests/qtest/migration/precopy-tests.c
> +++ b/tests/qtest/migration/precopy-tests.c
> @@ -239,9 +239,6 @@ static void *migrate_hook_start_fd(QTestState *from,
>                                   "  'arguments': { 'fdname': 'fd-mig' }}");
>      close(pair[0]);
>  
> -    /* Start incoming migration from the 1st socket */
> -    migrate_incoming_qmp(to, "fd:fd-mig", NULL, "{}");
> -
>      /* Send the 2nd socket to the target */
>      qtest_qmp_fds_assert_success(from, &pair[1], 1,
>                                   "{ 'execute': 'getfd',"
> @@ -283,6 +280,7 @@ static void migrate_hook_end_fd(QTestState *from,
>  static void test_precopy_fd_socket(char *name, MigrateCommon *args)
>  {
>      args->connect_uri = "fd:fd-mig";
> +    args->listen_uri = "fd:fd-mig";
>      args->start_hook = migrate_hook_start_fd;
>      args->end_hook = migrate_hook_end_fd;
>  
> @@ -484,6 +482,7 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
>       * everything will work alright even if guest page is changing.
>       */
>      args->live = true;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.incoming_defer = true;
>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -500,6 +499,7 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
>       * everything will work alright even if guest page is changing.
>       */
>      args->live = true;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.incoming_defer = true;
>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -516,6 +516,7 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
>       * everything will work alright even if guest page is changing.
>       */
>      args->live = true;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.incoming_defer = true;
>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
> index 166f27f478..f63f37132a 100644
> --- a/tests/qtest/migration/tls-tests.c
> +++ b/tests/qtest/migration/tls-tests.c
> @@ -677,6 +677,7 @@ static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
>  {
>      args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
>      args->end_hook = migrate_hook_end_tls_psk;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.incoming_defer = true;
>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -689,6 +690,7 @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
>      args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
>      args->end_hook = migrate_hook_end_tls_psk;
>      args->result = MIG_TEST_FAIL;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.hide_stderr = true;
>      args->start.incoming_defer = true;
> @@ -702,6 +704,7 @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
>  {
>      args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
>      args->end_hook = migrate_hook_end_tls_psk;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.incoming_defer = true;
>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -716,6 +719,7 @@ static void test_multifd_tcp_tls_x509_default_host(char *name,
>  {
>      args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
>      args->end_hook = migrate_hook_end_tls_x509;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.incoming_defer = true;
>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -728,6 +732,7 @@ static void test_multifd_tcp_tls_x509_override_host(char *name,
>  {
>      args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
>      args->end_hook = migrate_hook_end_tls_x509;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.incoming_defer = true;
>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -754,6 +759,7 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
>      args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
>      args->end_hook = migrate_hook_end_tls_x509;
>      args->result = MIG_TEST_FAIL;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.incoming_defer = true;
>      args->start.hide_stderr = true;
> @@ -767,6 +773,7 @@ static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
>  {
>      args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
>      args->end_hook = migrate_hook_end_tls_x509;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.incoming_defer = true;
>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> @@ -780,6 +787,7 @@ static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
>      args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
>      args->end_hook = migrate_hook_end_tls_x509;
>      args->result = MIG_TEST_FAIL;
> +    args->listen_uri = "tcp:127.0.0.1:0";
>  
>      args->start.incoming_defer = true;
>      args->start.hide_stderr = true;
> -- 
> 2.51.0
> 

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 29/51] tests/qtest/migration: Add config QDict
  2025-12-15 22:00 ` [PATCH v3 29/51] tests/qtest/migration: Add config QDict Fabiano Rosas
@ 2025-12-17 20:27   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-17 20:27 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:15PM -0300, Fabiano Rosas wrote:
> Add the config object to the MigrateCommon structure and allocate/free
> it in the wrappers that are used when dispatched every migration test.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 28/51] tests/qtest/migration: Stop invoking migrate_incoming from hooks
  2025-12-17 20:26   ` Peter Xu
@ 2025-12-17 21:05     ` Fabiano Rosas
  2025-12-17 21:24       ` Peter Xu
  0 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-17 21:05 UTC (permalink / raw)
  To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

Peter Xu <peterx@redhat.com> writes:

> On Mon, Dec 15, 2025 at 07:00:14PM -0300, Fabiano Rosas wrote:
>> Now that the listen_uri is being properly used, tests can stop calling
>> migrate_incoming from their hooks. The _common functions and
>> migrate_start should take care of that.
>> 
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>
> IMHO this patch is almost fine,
>
> Reviewed-by: Peter Xu <peterx@redhat.com>
>
> still, some thoughts inline.
>
>> ---
>>  tests/qtest/migration/compression-tests.c |  6 ++++++
>>  tests/qtest/migration/framework.c         | 14 +++++++++++---
>>  tests/qtest/migration/precopy-tests.c     |  7 ++++---
>>  tests/qtest/migration/tls-tests.c         |  8 ++++++++
>>  4 files changed, 29 insertions(+), 6 deletions(-)
>> 
>> diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c
>> index eb0b7d6b4b..bed39dece0 100644
>> --- a/tests/qtest/migration/compression-tests.c
>> +++ b/tests/qtest/migration/compression-tests.c
>> @@ -33,6 +33,7 @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from,
>>  
>>  static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
>>  {
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>
> Definitely a step forward to unify migrate_incoming into the precopy
> framework, however lots duplication of this "tcp:*" string..
>
> Shall we provide some migrate_common_set_listen_uri_default()?
>

Yeah, this one was bothering me. Maybe we should default to that string
and let the tests override? But then there are other duplications with
unix sockets and the like. This one is definitely the major offender
though.

>>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd;
>>  
>>      args->start.incoming_defer = true;
>> @@ -43,6 +44,7 @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args)
>>  
>>  static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args)
>>  {
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd,
>>  
>>      args->start.incoming_defer = true;
>> @@ -66,6 +68,7 @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from,
>>  
>>  static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args)
>>  {
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip;
>>  
>>      args->start.incoming_defer = true;
>> @@ -85,6 +88,7 @@ migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from,
>>  
>>  static void test_multifd_tcp_qpl(char *name, MigrateCommon *args)
>>  {
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl;
>>  
>>      args->start.incoming_defer = true;
>> @@ -104,6 +108,7 @@ migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from,
>>  
>>  static void test_multifd_tcp_uadk(char *name, MigrateCommon *args)
>>  {
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk;
>>  
>>      args->start.incoming_defer = true;
>> @@ -156,6 +161,7 @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from,
>>  
>>  static void test_multifd_tcp_zlib(char *name, MigrateCommon *args)
>>  {
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>      args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib;
>>  
>>      args->start.incoming_defer = true;
>> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
>> index e811945122..199e439263 100644
>> --- a/tests/qtest/migration/framework.c
>> +++ b/tests/qtest/migration/framework.c
>> @@ -820,6 +820,9 @@ int test_precopy_common(MigrateCommon *args)
>>      QObject *out_channels = NULL;
>>  
>>      g_assert(!args->cpr_channel || args->connect_channels);
>> +    if (args->start.incoming_defer) {
>> +        g_assert(args->listen_uri || args->connect_channels);
>> +    }
>>  
>>      if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
>>          return -1;
>> @@ -829,6 +832,14 @@ int test_precopy_common(MigrateCommon *args)
>>          data_hook = args->start_hook(from, to);
>>      }
>>  
>> +    if (args->start.incoming_defer && !args->start.defer_target_connect) {
>> +        if (args->connect_channels) {
>> +            in_channels = qobject_from_json(args->connect_channels,
>> +                                            &error_abort);
>> +        }
>> +        migrate_incoming_qmp(to, args->listen_uri, in_channels, "{}");
>> +    }
>
> The changes here in the framework code looks all correct, even though I
> don't think "connect_channels" is used here in this patch.
>
> Said that, IMHO the channel management is chaos right now in our qtest..
> At least it took me some time staring at this path when reviewing.
>

I had bugs around here when working on this series, so I agree. The
semantics of defer_target_connect are a bit confusing I think. Maybe
that logic could be moved into some CPR specific routine. I need to
check.

> IMHO a major reason is due to the cpr complexities.
>
> E.g. test_mode_transfer_common() used different things to specify incoming
> channels (cpr_channel, opts_target, connect_channels).  We should clean
> them up at some point..
>

Yes, although it's a good test that the various ways of passing channels
are working

>> +
>>      /* Wait for the first serial output from the source */
>>      if (args->result == MIG_TEST_SUCCEED) {
>>          wait_for_serial("src_serial");
>> @@ -1060,9 +1071,6 @@ void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from,
>>      migrate_set_parameter_str(from, "multifd-compression", method);
>>      migrate_set_parameter_str(to, "multifd-compression", method);
>>  
>> -    /* Start incoming migration from the 1st socket */
>> -    migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
>> -
>>      return NULL;
>>  }
>>  
>> diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
>> index d9c463dd0f..ab5789717f 100644
>> --- a/tests/qtest/migration/precopy-tests.c
>> +++ b/tests/qtest/migration/precopy-tests.c
>> @@ -239,9 +239,6 @@ static void *migrate_hook_start_fd(QTestState *from,
>>                                   "  'arguments': { 'fdname': 'fd-mig' }}");
>>      close(pair[0]);
>>  
>> -    /* Start incoming migration from the 1st socket */
>> -    migrate_incoming_qmp(to, "fd:fd-mig", NULL, "{}");
>> -
>>      /* Send the 2nd socket to the target */
>>      qtest_qmp_fds_assert_success(from, &pair[1], 1,
>>                                   "{ 'execute': 'getfd',"
>> @@ -283,6 +280,7 @@ static void migrate_hook_end_fd(QTestState *from,
>>  static void test_precopy_fd_socket(char *name, MigrateCommon *args)
>>  {
>>      args->connect_uri = "fd:fd-mig";
>> +    args->listen_uri = "fd:fd-mig";
>>      args->start_hook = migrate_hook_start_fd;
>>      args->end_hook = migrate_hook_end_fd;
>>  
>> @@ -484,6 +482,7 @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args)
>>       * everything will work alright even if guest page is changing.
>>       */
>>      args->live = true;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.incoming_defer = true;
>>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>> @@ -500,6 +499,7 @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args)
>>       * everything will work alright even if guest page is changing.
>>       */
>>      args->live = true;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.incoming_defer = true;
>>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>> @@ -516,6 +516,7 @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args)
>>       * everything will work alright even if guest page is changing.
>>       */
>>      args->live = true;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.incoming_defer = true;
>>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
>> index 166f27f478..f63f37132a 100644
>> --- a/tests/qtest/migration/tls-tests.c
>> +++ b/tests/qtest/migration/tls-tests.c
>> @@ -677,6 +677,7 @@ static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
>>  {
>>      args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
>>      args->end_hook = migrate_hook_end_tls_psk;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.incoming_defer = true;
>>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>> @@ -689,6 +690,7 @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
>>      args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
>>      args->end_hook = migrate_hook_end_tls_psk;
>>      args->result = MIG_TEST_FAIL;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.hide_stderr = true;
>>      args->start.incoming_defer = true;
>> @@ -702,6 +704,7 @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
>>  {
>>      args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
>>      args->end_hook = migrate_hook_end_tls_psk;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.incoming_defer = true;
>>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>> @@ -716,6 +719,7 @@ static void test_multifd_tcp_tls_x509_default_host(char *name,
>>  {
>>      args->start_hook = migrate_hook_start_multifd_tls_x509_default_host;
>>      args->end_hook = migrate_hook_end_tls_x509;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.incoming_defer = true;
>>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>> @@ -728,6 +732,7 @@ static void test_multifd_tcp_tls_x509_override_host(char *name,
>>  {
>>      args->start_hook = migrate_hook_start_multifd_tls_x509_override_host;
>>      args->end_hook = migrate_hook_end_tls_x509;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.incoming_defer = true;
>>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>> @@ -754,6 +759,7 @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name,
>>      args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host;
>>      args->end_hook = migrate_hook_end_tls_x509;
>>      args->result = MIG_TEST_FAIL;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.incoming_defer = true;
>>      args->start.hide_stderr = true;
>> @@ -767,6 +773,7 @@ static void test_multifd_tcp_tls_x509_allow_anon_client(char *name,
>>  {
>>      args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client;
>>      args->end_hook = migrate_hook_end_tls_x509;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.incoming_defer = true;
>>      args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>> @@ -780,6 +787,7 @@ static void test_multifd_tcp_tls_x509_reject_anon_client(char *name,
>>      args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client;
>>      args->end_hook = migrate_hook_end_tls_x509;
>>      args->result = MIG_TEST_FAIL;
>> +    args->listen_uri = "tcp:127.0.0.1:0";
>>  
>>      args->start.incoming_defer = true;
>>      args->start.hide_stderr = true;
>> -- 
>> 2.51.0
>> 


^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 28/51] tests/qtest/migration: Stop invoking migrate_incoming from hooks
  2025-12-17 21:05     ` Fabiano Rosas
@ 2025-12-17 21:24       ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-17 21:24 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Wed, Dec 17, 2025 at 06:05:11PM -0300, Fabiano Rosas wrote:
> > E.g. test_mode_transfer_common() used different things to specify incoming
> > channels (cpr_channel, opts_target, connect_channels).  We should clean
> > them up at some point..
> 
> Yes, although it's a good test that the various ways of passing channels
> are working

Yes.  Said that, ideally IMHO we should only specify the channels, e.g. in
MigrationAddress format (for both main and cpr), then test code should be
able to convert it into either JSON (in form of "channels") or URIs.  I
recall we have had some discussion before on that.  We can leave that for
later.

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 32/51] tests/qtest/migration: Adapt convergence routines to config
  2025-12-15 22:00 ` [PATCH v3 32/51] tests/qtest/migration: Adapt convergence routines to config Fabiano Rosas
@ 2025-12-18 17:25   ` Peter Xu
  2025-12-18 19:47     ` Fabiano Rosas
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Xu @ 2025-12-18 17:25 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:18PM -0300, Fabiano Rosas wrote:
> Adapt the convergence routines migrate_ensure_[non_]converge to set
> the convergence parameters in the config dict it instead of using
> migrate-set-parameters.
> 
> Some tests need to change the convergence parameters during the
> migration. The config object method is specific to configuration prior
> to starting a migration, so by design it's not suitable to effect
> migration-runtime changes. The existing routines will be kept for this
> purpose (renamed with 'ongoing' for clarity).
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
>  tests/qtest/migration/framework.c     | 10 ++++-----
>  tests/qtest/migration/migration-qmp.c | 32 +++++++++++++++++++++++++--
>  tests/qtest/migration/migration-qmp.h |  6 +++--
>  tests/qtest/migration/misc-tests.c    |  4 ++--
>  tests/qtest/migration/precopy-tests.c | 26 +++++++++-------------
>  5 files changed, 52 insertions(+), 26 deletions(-)
> 
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index fd15bd832e..df42a8a2c6 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -583,7 +583,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
>          args->postcopy_data = args->start_hook(from, to);
>      }
>  
> -    migrate_ensure_non_converge(from);
> +    migrate_ensure_non_converge(from, args->start.config);
>      migrate_prepare_for_dirty_mem(from);
>      qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
>                               "  'arguments': { "
> @@ -872,7 +872,7 @@ int test_precopy_common(MigrateCommon *args)
>      }
>  
>      if (args->live) {
> -        migrate_ensure_non_converge(from);
> +        migrate_ensure_non_converge(from, args->start.config);
>          migrate_prepare_for_dirty_mem(from);
>      } else {
>          /*
> @@ -884,7 +884,7 @@ int test_precopy_common(MigrateCommon *args)
>          if (args->result == MIG_TEST_SUCCEED) {
>              qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
>              wait_for_stop(from, &src_state);
> -            migrate_ensure_converge(from);
> +            migrate_ongoing_ensure_converge(from);
>          }
>      }
>  
> @@ -942,7 +942,7 @@ int test_precopy_common(MigrateCommon *args)
>              }
>              migrate_wait_for_dirty_mem(from, to);
>  
> -            migrate_ensure_converge(from);
> +            migrate_ongoing_ensure_converge(from);
>  
>              /*
>               * We do this first, as it has a timeout to stop us
> @@ -1047,7 +1047,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
>          data_hook = args->start_hook(from, to);
>      }
>  
> -    migrate_ensure_converge(from);
> +    migrate_ensure_converge(from, args->start.config);
>      wait_for_serial("src_serial");
>  
>      if (stop_src) {
> diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
> index 5c46ceb3e6..7fe47a5793 100644
> --- a/tests/qtest/migration/migration-qmp.c
> +++ b/tests/qtest/migration/migration-qmp.c
> @@ -499,20 +499,48 @@ void migrate_set_parameter_bool(QTestState *who, const char *parameter,
>      migrate_check_parameter_bool(who, parameter, value);
>  }
>  
> -void migrate_ensure_non_converge(QTestState *who)
> +void migrate_ongoing_ensure_non_converge(QTestState *who)
>  {
>      /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
>      migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
>      migrate_set_parameter_int(who, "downtime-limit", 1);
>  }
>  
> -void migrate_ensure_converge(QTestState *who)
> +void migrate_ongoing_ensure_converge(QTestState *who)
>  {
>      /* Should converge with 30s downtime + 1 gbs bandwidth limit */
>      migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
>      migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
>  }
>  
> +void migrate_ensure_non_converge(QTestState *who, QDict *config)
> +{
> +    config = config_load(config);
> +    if (config) {
> +        /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
> +        qdict_put_int(config, "max-bandwidth", 3 * 1000 * 1000);
> +        qdict_put_int(config, "downtime-limit", 1);
> +    } else {
> +        assert(who);
> +        migrate_ongoing_ensure_non_converge(who);
> +    }
> +    config_put(config);
> +}
> +
> +void migrate_ensure_converge(QTestState *who, QDict *config)
> +{
> +    config = config_load(config);
> +    /* Should converge with 30s downtime + 1 gbs bandwidth limit */
> +    if (config) {
> +        qdict_put_int(config, "max-bandwidth", 1 * 1000 * 1000 * 1000);
> +        qdict_put_int(config, "downtime-limit", 30 * 1000);
> +    } else {
> +        assert(who);
> +        migrate_ongoing_ensure_converge(who);
> +    }
> +    config_put(config);
> +}

It's slightly an overkill to me to have these converge helpers to provide
two versions.  Also a bit confusing on when should we use which.

After all, parameters touched on convergence must be able to be dynamically
set..

Can we always stick with the QMP set-parameters for all these?

> +
>  void migrate_pause(QTestState *who)
>  {
>      qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
> diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
> index 9a36a677ba..e465c69094 100644
> --- a/tests/qtest/migration/migration-qmp.h
> +++ b/tests/qtest/migration/migration-qmp.h
> @@ -39,8 +39,10 @@ void migrate_set_parameter_strv(QTestState *who, const char *parameter,
>  void migrate_set_parameter_null(QTestState *who, const char *parameter);
>  void migrate_set_parameter_bool(QTestState *who, const char *parameter,
>                                  int value);
> -void migrate_ensure_non_converge(QTestState *who);
> -void migrate_ensure_converge(QTestState *who);
> +void migrate_ongoing_ensure_non_converge(QTestState *who);
> +void migrate_ongoing_ensure_converge(QTestState *who);
> +void migrate_ensure_non_converge(QTestState *who, QDict *config);
> +void migrate_ensure_converge(QTestState *who, QDict *config);
>  void migrate_pause(QTestState *who);
>  void migrate_continue(QTestState *who, const char *state);
>  void migrate_recover(QTestState *who, const char *uri);
> diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
> index 61bdfda857..0a737cb54f 100644
> --- a/tests/qtest/migration/misc-tests.c
> +++ b/tests/qtest/migration/misc-tests.c
> @@ -68,7 +68,7 @@ static void test_analyze_script(char *name, MigrateCommon *args)
>      file = g_strdup_printf("%s/migfile", tmpfs);
>      uri = g_strdup_printf("exec:cat > %s", file);
>  
> -    migrate_ensure_converge(from);
> +    migrate_ensure_converge(from, args->start.config);
>      migrate_qmp(from, to, uri, NULL, "{}");
>      wait_for_migration_complete(from);
>  
> @@ -102,7 +102,7 @@ static void test_ignore_shared(char *name, MigrateCommon *args)
>          return;
>      }
>  
> -    migrate_ensure_non_converge(from);
> +    migrate_ensure_non_converge(from, args->start.config);
>      migrate_prepare_for_dirty_mem(from);
>  
>      /* Wait for the first serial output from the source */
> diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
> index ab5789717f..eabbbf39c3 100644
> --- a/tests/qtest/migration/precopy-tests.c
> +++ b/tests/qtest/migration/precopy-tests.c
> @@ -374,7 +374,7 @@ static void test_auto_converge(char *name, MigrateCommon *args)
>       * Set the initial parameters so that the migration could not converge
>       * without throttling.
>       */
> -    migrate_ensure_non_converge(from);
> +    migrate_ensure_non_converge(from, args->start.config);
>  
>      /* To check remaining size after precopy */
>      migrate_set_capability(from, "pause-before-switchover", true);
> @@ -427,7 +427,7 @@ static void test_auto_converge(char *name, MigrateCommon *args)
>      g_assert_cmpint(hit, ==, 1);
>  
>      /* Now, when we tested that throttling works, let it converge */
> -    migrate_ensure_converge(from);
> +    migrate_ongoing_ensure_converge(from);
>  
>      /*
>       * Wait for pre-switchover status to check last throttle percentage
> @@ -562,7 +562,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
>          return;
>      }
>  
> -    migrate_ensure_non_converge(from);
> +    migrate_ensure_non_converge(from, args->start.config);
>      migrate_prepare_for_dirty_mem(from);
>  
>      if (postcopy_ram) {
> @@ -623,14 +623,12 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
>      /* Start incoming migration from the 1st socket */
>      migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, "{}");
>  
> -    migrate_ensure_non_converge(from);
> +    migrate_ensure_non_converge(from, args->start.config);
>  
>      migrate_qmp(from, to2, NULL, NULL, "{}");
>  
>      migrate_wait_for_dirty_mem(from, to2);
> -
> -    migrate_ensure_converge(from);
> -
> +    migrate_ongoing_ensure_converge(from);
>      wait_for_stop(from, get_src());
>      qtest_qmp_eventwait(to2, "RESUME");
>  
> @@ -659,7 +657,7 @@ static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
>       */
>  
>      wait_for_serial("src_serial");
> -    migrate_ensure_converge(from);
> +    migrate_ensure_converge(from, args->config);
>  
>      migrate_qmp(from, to, uri, NULL, "{}");
>  
> @@ -684,7 +682,7 @@ static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
>      migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
>  
>      wait_for_serial("src_serial");
> -    migrate_ensure_converge(from);
> +    migrate_ensure_converge(from, args->config);
>  
>      migrate_qmp(from, to, uri, NULL, "{}");
>  
> @@ -709,7 +707,7 @@ static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
>      migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
>  
>      wait_for_serial("src_serial");
> -    migrate_ensure_converge(from);
> +    migrate_ensure_converge(from, args->config);
>  
>      migrate_qmp(from, to, uri, NULL, "{}");
>  
> @@ -739,7 +737,7 @@ static void test_cancel_src_after_none(QTestState *from, QTestState *to,
>  
>      migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
>  
> -    migrate_ensure_converge(from);
> +    migrate_ensure_converge(from, args->config);
>      migrate_qmp(from, to, uri, NULL, "{}");
>  
>      wait_for_migration_complete(from);
> @@ -759,7 +757,7 @@ static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
>      migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
>  
>      wait_for_serial("src_serial");
> -    migrate_ensure_converge(from);
> +    migrate_ensure_converge(from, args->config);
>  
>      migrate_qmp(from, to, uri, NULL, "{}");
>  
> @@ -1066,9 +1064,6 @@ static void migrate_dirty_limit_wait_showup(QTestState *from,
>      migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
>      migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
>  
> -    /* Make sure migrate can't converge */
> -    migrate_ensure_non_converge(from);
> -
>      /* To check limit rate after precopy */
>      migrate_set_capability(from, "pause-before-switchover", true);
>  
> @@ -1128,6 +1123,7 @@ static void test_dirty_limit(char *name, MigrateCommon *args)
>      }
>  
>      /* Prepare for dirty limit migration and wait src vm show up */
> +    migrate_ensure_non_converge(from, args->start.config);
>      migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
>  
>      /* Start migrate */
> -- 
> 2.51.0
> 

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 30/51] tests/qtest/migration: Add temporary code to toggle usage of config
  2025-12-15 22:00 ` [PATCH v3 30/51] tests/qtest/migration: Add temporary code to toggle usage of config Fabiano Rosas
@ 2025-12-18 17:34   ` Peter Xu
  2025-12-18 19:41     ` Fabiano Rosas
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Xu @ 2025-12-18 17:34 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:16PM -0300, Fabiano Rosas wrote:
> The tests are being refactored to pass migration options to QEMU using
> the new API of passing a JSON object as argument the migration
> commands instead of using several calls to the
> migrate_set_capabilities|parameters commands.
> 
> Since multiple tests share common infrastructure (framework.c,
> migration-utils.c, migration-qmp.c), it's cumbersome to convert tests
> in small chunks, which would require changes to every common function
> to accept both the new and old ways.
> 
> After some tinkering, an easier way to do this transition is to allow
> the tests to set a key in the config dict itself telling whether the
> config is supported. With this, the common functions can be fully
> altered to support the config object, as long as they check this
> temporary key and do the right thing.
> 
> QEMU doesn't know about this hack, so some code is needed to hide it
> when issuing QMP commands with the config object.
> 
> This will all be removed once tests are fully converted.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
>  tests/qtest/migration/migration-qmp.h  |  1 -
>  tests/qtest/migration/migration-util.c |  1 +
>  tests/qtest/migration/migration-util.h | 34 ++++++++++++++++++++++++++
>  3 files changed, 35 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
> index 940ffd5950..9a36a677ba 100644
> --- a/tests/qtest/migration/migration-qmp.h
> +++ b/tests/qtest/migration/migration-qmp.h
> @@ -47,5 +47,4 @@ void migrate_recover(QTestState *who, const char *uri);
>  void migrate_cancel(QTestState *who);
>  void migrate_postcopy_start(QTestState *from, QTestState *to,
>                              QTestMigrationState *src_state);
> -
>  #endif /* MIGRATION_QMP_H */
> diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
> index 416dd10ef8..e702f00896 100644
> --- a/tests/qtest/migration/migration-util.c
> +++ b/tests/qtest/migration/migration-util.c
> @@ -255,6 +255,7 @@ static void migration_test_wrapper(const void *data)
>  
>      test->data = g_new0(MigrateCommon, 1);
>      test->data->start.config = qdict_new();
> +    qdict_put_bool(test->data->start.config, "use-config", false);
>  
>      g_test_message("Running /%s%s", qtest_get_arch(), test->name);
>      test->func(test->name, test->data);
> diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
> index e73d69bab0..3c3b5a8777 100644
> --- a/tests/qtest/migration/migration-util.h
> +++ b/tests/qtest/migration/migration-util.h
> @@ -60,4 +60,38 @@ void migration_test_add_suffix(const char *path, const char *suffix,
>  char *migrate_get_connect_uri(QTestState *who);
>  void migrate_set_ports(QTestState *to, QList *channel_list);
>  
> +/*
> + * Scaffolding to allow the framework _common functions and _qmp
> + * functions to use the config object while some tests are still using
> + * migrate_set_*. Tests that have been converted will set use-config =
> + * true on the config dict.
> + */
> +static bool has_key;
> +static bool use_config;

Looks like this is temp measure, so no strong opinions.. said that, it
looks tricky to have the two globals shared between all the tests, and
having magic keys in the qdict.

Can we pass in MigrateStart* for config_load() and config_put()?  Then at
least we can change globals into per-test flags of MigrateStart.

Btw, AFAIU the two helpers should always used in a pair but load() and
put() do not look like a pair..

If we can have args->use_config as a bool, having tests opt-in config
setups by setting it, then I wonder if we can do that like:

  if (args->use_config) {
      // do whatever with args->config...
  } else {
      // covered by other migrate-set-parameters QMP commands..
  }

Do we really need config_put()? I'll keep reading, but please evaluate..

> +static inline QDict *config_load(QDict *config)
> +{
> +    if (!config) {
> +        return NULL;
> +    }
> +
> +    has_key = qdict_haskey(config, "use-config");
> +    if (has_key) {
> +        use_config = qdict_get_try_bool(config, "use-config", false);
> +        qdict_del(config, "use-config");
> +    }
> +
> +    if (use_config) {
> +        return config;
> +    }
> +
> +    return NULL;
> +}
> +
> +static inline void config_put(QDict *config)
> +{
> +    if (config && has_key) {
> +        qdict_put_bool(config, "use-config", use_config);
> +    }
> +}
> +
>  #endif /* MIGRATION_UTIL_H */
> -- 
> 2.51.0
> 

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 34/51] tests/qtest/migration: Use migrate_incoming_qmp where possible
  2025-12-15 22:00 ` [PATCH v3 34/51] tests/qtest/migration: Use migrate_incoming_qmp where possible Fabiano Rosas
@ 2025-12-18 18:47   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-18 18:47 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:20PM -0300, Fabiano Rosas wrote:
> Always use the proper function for starting the incoming migration,
> there's no need to call QMP directly from the tests.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 37/51] tests/qtest/migration: Add new hook with data
  2025-12-15 22:00 ` [PATCH v3 37/51] tests/qtest/migration: Add new hook with data Fabiano Rosas
@ 2025-12-18 19:05   ` Peter Xu
  2025-12-18 21:43     ` Peter Xu
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Xu @ 2025-12-18 19:05 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:23PM -0300, Fabiano Rosas wrote:
> Add a new start hook that takes an opaque pointer so the tests can
> stop having to nest hook calls.

I saw that this hook is also removed after the whole series applied.. maybe
it should be mentioned here.

> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

> ---
>  tests/qtest/migration/framework.c |  8 ++++++++
>  tests/qtest/migration/framework.h | 16 ++++++++++++++++
>  2 files changed, 24 insertions(+)
> 
> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> index f740228cf2..b9bbdca6a9 100644
> --- a/tests/qtest/migration/framework.c
> +++ b/tests/qtest/migration/framework.c
> @@ -591,6 +591,9 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
>  
>      if (args->start_hook) {
>          args->postcopy_data = args->start_hook(from, to);
> +    } else if (args->start_hook_full) {
> +        args->postcopy_data = args->start_hook_full(from, to,
> +                                                    args->start_hook_data);
>      }
>  
>      migrate_ensure_non_converge(from, args->start.config);
> @@ -868,6 +871,9 @@ int test_precopy_common(MigrateCommon *args)
>  
>      if (args->start_hook) {
>          data_hook = args->start_hook(from, to);
> +    } else if (args->start_hook_full) {
> +        data_hook = args->start_hook_full(from, to,
> +                                          args->start_hook_data);
>      }
>  
>      if (args->start.incoming_defer && !args->start.defer_target_connect) {
> @@ -1062,6 +1068,8 @@ void test_file_common(MigrateCommon *args, bool stop_src)
>  
>      if (args->start_hook) {
>          data_hook = args->start_hook(from, to);
> +    } else if (args->start_hook_full) {
> +        data_hook = args->start_hook_full(from, to, args->start_hook_data);
>      }
>  
>      migrate_ensure_converge(from, args->start.config);
> diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h
> index 65c656e0d3..2584599f14 100644
> --- a/tests/qtest/migration/framework.h
> +++ b/tests/qtest/migration/framework.h
> @@ -65,6 +65,19 @@ int migration_env_clean(MigrationTestEnv *env);
>  typedef void * (*TestMigrateStartHook)(QTestState *from,
>                                         QTestState *to);
>  
> +
> +/*
> + * A hook that runs after the src and dst QEMUs have been created, but
> + * before the migration is started. This can be used to run routines
> + * that require the QTestState object.
> + *
> + * Returns: NULL, or a pointer to opaque state to be
> + *          later passed to the TestMigrateEndHook
> + */
> +typedef void * (*TestMigrateStartHookFull)(QTestState *from,
> +                                           QTestState *to,
> +                                           void *opaque);
> +
>  /*
>   * A hook that runs after the migration has finished,
>   * regardless of whether it succeeded or failed, but
> @@ -196,6 +209,9 @@ typedef struct {
>      /* Optional: callback to run at finish to cleanup */
>      TestMigrateEndHook end_hook;
>  
> +    TestMigrateStartHookFull start_hook_full;
> +    void *start_hook_data;
> +
>      /*
>       * Optional: normally we expect the migration process to complete.
>       *
> -- 
> 2.51.0
> 

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 38/51] tests/qtest/migration: TLS x509: Refactor to use full hook
  2025-12-15 22:00 ` [PATCH v3 38/51] tests/qtest/migration: TLS x509: Refactor to use full hook Fabiano Rosas
@ 2025-12-18 19:15   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-18 19:15 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:24PM -0300, Fabiano Rosas wrote:
> Refactor the TLS x509 hooks to use the _full variant which passes the
> hook data into the _common functions via MigrateCommon *args.
> 
> This reduces the number of hooks and will allow further simplification
> of the TLS tests by setting a common hook at a centralized place in
> the next patches.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 30/51] tests/qtest/migration: Add temporary code to toggle usage of config
  2025-12-18 17:34   ` Peter Xu
@ 2025-12-18 19:41     ` Fabiano Rosas
  2025-12-18 20:58       ` Peter Xu
  0 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-18 19:41 UTC (permalink / raw)
  To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

Peter Xu <peterx@redhat.com> writes:

> On Mon, Dec 15, 2025 at 07:00:16PM -0300, Fabiano Rosas wrote:
>> The tests are being refactored to pass migration options to QEMU using
>> the new API of passing a JSON object as argument the migration
>> commands instead of using several calls to the
>> migrate_set_capabilities|parameters commands.
>> 
>> Since multiple tests share common infrastructure (framework.c,
>> migration-utils.c, migration-qmp.c), it's cumbersome to convert tests
>> in small chunks, which would require changes to every common function
>> to accept both the new and old ways.
>> 
>> After some tinkering, an easier way to do this transition is to allow
>> the tests to set a key in the config dict itself telling whether the
>> config is supported. With this, the common functions can be fully
>> altered to support the config object, as long as they check this
>> temporary key and do the right thing.
>> 
>> QEMU doesn't know about this hack, so some code is needed to hide it
>> when issuing QMP commands with the config object.
>> 
>> This will all be removed once tests are fully converted.
>> 
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>>  tests/qtest/migration/migration-qmp.h  |  1 -
>>  tests/qtest/migration/migration-util.c |  1 +
>>  tests/qtest/migration/migration-util.h | 34 ++++++++++++++++++++++++++
>>  3 files changed, 35 insertions(+), 1 deletion(-)
>> 
>> diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
>> index 940ffd5950..9a36a677ba 100644
>> --- a/tests/qtest/migration/migration-qmp.h
>> +++ b/tests/qtest/migration/migration-qmp.h
>> @@ -47,5 +47,4 @@ void migrate_recover(QTestState *who, const char *uri);
>>  void migrate_cancel(QTestState *who);
>>  void migrate_postcopy_start(QTestState *from, QTestState *to,
>>                              QTestMigrationState *src_state);
>> -
>>  #endif /* MIGRATION_QMP_H */
>> diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
>> index 416dd10ef8..e702f00896 100644
>> --- a/tests/qtest/migration/migration-util.c
>> +++ b/tests/qtest/migration/migration-util.c
>> @@ -255,6 +255,7 @@ static void migration_test_wrapper(const void *data)
>>  
>>      test->data = g_new0(MigrateCommon, 1);
>>      test->data->start.config = qdict_new();
>> +    qdict_put_bool(test->data->start.config, "use-config", false);
>>  
>>      g_test_message("Running /%s%s", qtest_get_arch(), test->name);
>>      test->func(test->name, test->data);
>> diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
>> index e73d69bab0..3c3b5a8777 100644
>> --- a/tests/qtest/migration/migration-util.h
>> +++ b/tests/qtest/migration/migration-util.h
>> @@ -60,4 +60,38 @@ void migration_test_add_suffix(const char *path, const char *suffix,
>>  char *migrate_get_connect_uri(QTestState *who);
>>  void migrate_set_ports(QTestState *to, QList *channel_list);
>>  
>> +/*
>> + * Scaffolding to allow the framework _common functions and _qmp
>> + * functions to use the config object while some tests are still using
>> + * migrate_set_*. Tests that have been converted will set use-config =
>> + * true on the config dict.
>> + */
>> +static bool has_key;
>> +static bool use_config;
>
> Looks like this is temp measure, so no strong opinions.. said that, it
> looks tricky to have the two globals shared between all the tests, and
> having magic keys in the qdict.
>

It is tricky, but it works. The other options all require "passing
something" in, which ends up touching good code and causing a mess with
rebases and the overall clarity of the patches. But let me read about
your suggestions below...

> Can we pass in MigrateStart* for config_load() and config_put()?  Then at
> least we can change globals into per-test flags of MigrateStart.
>
> Btw, AFAIU the two helpers should always used in a pair but load() and
> put() do not look like a pair..
>

My mind went to vcpu_load/vcpu_put from kvm code. =D

> If we can have args->use_config as a bool, having tests opt-in config
> setups by setting it, then I wonder if we can do that like:
>

The migrate_qmp commands don't take args. So I'd have to alter their
signature just for this temporary state. That's why I put the flag in
the dict itself.

>   if (args->use_config) {
>       // do whatever with args->config...
>   } else {
>       // covered by other migrate-set-parameters QMP commands..
>   }
>
> Do we really need config_put()? I'll keep reading, but please evaluate..
>

Because of the migrate_incoming_qmp and -incoming calls, we need to take
the key out of the dict to hide it. Then put it back so the rest of the
code, e.g. migrate_qmp can use it.

>> +static inline QDict *config_load(QDict *config)
>> +{
>> +    if (!config) {
>> +        return NULL;
>> +    }
>> +
>> +    has_key = qdict_haskey(config, "use-config");
>> +    if (has_key) {
>> +        use_config = qdict_get_try_bool(config, "use-config", false);
>> +        qdict_del(config, "use-config");
>> +    }
>> +
>> +    if (use_config) {
>> +        return config;
>> +    }
>> +
>> +    return NULL;
>> +}
>> +
>> +static inline void config_put(QDict *config)
>> +{
>> +    if (config && has_key) {
>> +        qdict_put_bool(config, "use-config", use_config);
>> +    }
>> +}
>> +
>>  #endif /* MIGRATION_UTIL_H */
>> -- 
>> 2.51.0
>> 


^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 32/51] tests/qtest/migration: Adapt convergence routines to config
  2025-12-18 17:25   ` Peter Xu
@ 2025-12-18 19:47     ` Fabiano Rosas
  2025-12-18 21:08       ` Peter Xu
  0 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-18 19:47 UTC (permalink / raw)
  To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

Peter Xu <peterx@redhat.com> writes:

> On Mon, Dec 15, 2025 at 07:00:18PM -0300, Fabiano Rosas wrote:
>> Adapt the convergence routines migrate_ensure_[non_]converge to set
>> the convergence parameters in the config dict it instead of using
>> migrate-set-parameters.
>> 
>> Some tests need to change the convergence parameters during the
>> migration. The config object method is specific to configuration prior
>> to starting a migration, so by design it's not suitable to effect
>> migration-runtime changes. The existing routines will be kept for this
>> purpose (renamed with 'ongoing' for clarity).
>> 
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>>  tests/qtest/migration/framework.c     | 10 ++++-----
>>  tests/qtest/migration/migration-qmp.c | 32 +++++++++++++++++++++++++--
>>  tests/qtest/migration/migration-qmp.h |  6 +++--
>>  tests/qtest/migration/misc-tests.c    |  4 ++--
>>  tests/qtest/migration/precopy-tests.c | 26 +++++++++-------------
>>  5 files changed, 52 insertions(+), 26 deletions(-)
>> 
>> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
>> index fd15bd832e..df42a8a2c6 100644
>> --- a/tests/qtest/migration/framework.c
>> +++ b/tests/qtest/migration/framework.c
>> @@ -583,7 +583,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
>>          args->postcopy_data = args->start_hook(from, to);
>>      }
>>  
>> -    migrate_ensure_non_converge(from);
>> +    migrate_ensure_non_converge(from, args->start.config);
>>      migrate_prepare_for_dirty_mem(from);
>>      qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
>>                               "  'arguments': { "
>> @@ -872,7 +872,7 @@ int test_precopy_common(MigrateCommon *args)
>>      }
>>  
>>      if (args->live) {
>> -        migrate_ensure_non_converge(from);
>> +        migrate_ensure_non_converge(from, args->start.config);
>>          migrate_prepare_for_dirty_mem(from);
>>      } else {
>>          /*
>> @@ -884,7 +884,7 @@ int test_precopy_common(MigrateCommon *args)
>>          if (args->result == MIG_TEST_SUCCEED) {
>>              qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
>>              wait_for_stop(from, &src_state);
>> -            migrate_ensure_converge(from);
>> +            migrate_ongoing_ensure_converge(from);
>>          }
>>      }
>>  
>> @@ -942,7 +942,7 @@ int test_precopy_common(MigrateCommon *args)
>>              }
>>              migrate_wait_for_dirty_mem(from, to);
>>  
>> -            migrate_ensure_converge(from);
>> +            migrate_ongoing_ensure_converge(from);
>>  
>>              /*
>>               * We do this first, as it has a timeout to stop us
>> @@ -1047,7 +1047,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
>>          data_hook = args->start_hook(from, to);
>>      }
>>  
>> -    migrate_ensure_converge(from);
>> +    migrate_ensure_converge(from, args->start.config);
>>      wait_for_serial("src_serial");
>>  
>>      if (stop_src) {
>> diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
>> index 5c46ceb3e6..7fe47a5793 100644
>> --- a/tests/qtest/migration/migration-qmp.c
>> +++ b/tests/qtest/migration/migration-qmp.c
>> @@ -499,20 +499,48 @@ void migrate_set_parameter_bool(QTestState *who, const char *parameter,
>>      migrate_check_parameter_bool(who, parameter, value);
>>  }
>>  
>> -void migrate_ensure_non_converge(QTestState *who)
>> +void migrate_ongoing_ensure_non_converge(QTestState *who)
>>  {
>>      /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
>>      migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
>>      migrate_set_parameter_int(who, "downtime-limit", 1);
>>  }
>>  
>> -void migrate_ensure_converge(QTestState *who)
>> +void migrate_ongoing_ensure_converge(QTestState *who)
>>  {
>>      /* Should converge with 30s downtime + 1 gbs bandwidth limit */
>>      migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
>>      migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
>>  }
>>  
>> +void migrate_ensure_non_converge(QTestState *who, QDict *config)
>> +{
>> +    config = config_load(config);
>> +    if (config) {
>> +        /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
>> +        qdict_put_int(config, "max-bandwidth", 3 * 1000 * 1000);
>> +        qdict_put_int(config, "downtime-limit", 1);
>> +    } else {
>> +        assert(who);
>> +        migrate_ongoing_ensure_non_converge(who);
>> +    }
>> +    config_put(config);
>> +}
>> +
>> +void migrate_ensure_converge(QTestState *who, QDict *config)
>> +{
>> +    config = config_load(config);
>> +    /* Should converge with 30s downtime + 1 gbs bandwidth limit */
>> +    if (config) {
>> +        qdict_put_int(config, "max-bandwidth", 1 * 1000 * 1000 * 1000);
>> +        qdict_put_int(config, "downtime-limit", 30 * 1000);
>> +    } else {
>> +        assert(who);
>> +        migrate_ongoing_ensure_converge(who);
>> +    }
>> +    config_put(config);
>> +}
>
> It's slightly an overkill to me to have these converge helpers to provide
> two versions.  Also a bit confusing on when should we use which.
>
> After all, parameters touched on convergence must be able to be dynamically
> set..
>
> Can we always stick with the QMP set-parameters for all these?
>

Well, QEMU ignores anything set with migrate-set-parameters once it sees
the config, so we'd need to change that in the code.

Thinking about the design of "config", I think the point was to never
configure a migration via migrate-set-parameters. Always pass the config
to the migration commands.

These options are special in that they make sense both before and after
starting the migration, so it's indeed confusing. I don't know what the
best approach is.

>> +
>>  void migrate_pause(QTestState *who)
>>  {
>>      qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
>> diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
>> index 9a36a677ba..e465c69094 100644
>> --- a/tests/qtest/migration/migration-qmp.h
>> +++ b/tests/qtest/migration/migration-qmp.h
>> @@ -39,8 +39,10 @@ void migrate_set_parameter_strv(QTestState *who, const char *parameter,
>>  void migrate_set_parameter_null(QTestState *who, const char *parameter);
>>  void migrate_set_parameter_bool(QTestState *who, const char *parameter,
>>                                  int value);
>> -void migrate_ensure_non_converge(QTestState *who);
>> -void migrate_ensure_converge(QTestState *who);
>> +void migrate_ongoing_ensure_non_converge(QTestState *who);
>> +void migrate_ongoing_ensure_converge(QTestState *who);
>> +void migrate_ensure_non_converge(QTestState *who, QDict *config);
>> +void migrate_ensure_converge(QTestState *who, QDict *config);
>>  void migrate_pause(QTestState *who);
>>  void migrate_continue(QTestState *who, const char *state);
>>  void migrate_recover(QTestState *who, const char *uri);
>> diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c
>> index 61bdfda857..0a737cb54f 100644
>> --- a/tests/qtest/migration/misc-tests.c
>> +++ b/tests/qtest/migration/misc-tests.c
>> @@ -68,7 +68,7 @@ static void test_analyze_script(char *name, MigrateCommon *args)
>>      file = g_strdup_printf("%s/migfile", tmpfs);
>>      uri = g_strdup_printf("exec:cat > %s", file);
>>  
>> -    migrate_ensure_converge(from);
>> +    migrate_ensure_converge(from, args->start.config);
>>      migrate_qmp(from, to, uri, NULL, "{}");
>>      wait_for_migration_complete(from);
>>  
>> @@ -102,7 +102,7 @@ static void test_ignore_shared(char *name, MigrateCommon *args)
>>          return;
>>      }
>>  
>> -    migrate_ensure_non_converge(from);
>> +    migrate_ensure_non_converge(from, args->start.config);
>>      migrate_prepare_for_dirty_mem(from);
>>  
>>      /* Wait for the first serial output from the source */
>> diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c
>> index ab5789717f..eabbbf39c3 100644
>> --- a/tests/qtest/migration/precopy-tests.c
>> +++ b/tests/qtest/migration/precopy-tests.c
>> @@ -374,7 +374,7 @@ static void test_auto_converge(char *name, MigrateCommon *args)
>>       * Set the initial parameters so that the migration could not converge
>>       * without throttling.
>>       */
>> -    migrate_ensure_non_converge(from);
>> +    migrate_ensure_non_converge(from, args->start.config);
>>  
>>      /* To check remaining size after precopy */
>>      migrate_set_capability(from, "pause-before-switchover", true);
>> @@ -427,7 +427,7 @@ static void test_auto_converge(char *name, MigrateCommon *args)
>>      g_assert_cmpint(hit, ==, 1);
>>  
>>      /* Now, when we tested that throttling works, let it converge */
>> -    migrate_ensure_converge(from);
>> +    migrate_ongoing_ensure_converge(from);
>>  
>>      /*
>>       * Wait for pre-switchover status to check last throttle percentage
>> @@ -562,7 +562,7 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
>>          return;
>>      }
>>  
>> -    migrate_ensure_non_converge(from);
>> +    migrate_ensure_non_converge(from, args->start.config);
>>      migrate_prepare_for_dirty_mem(from);
>>  
>>      if (postcopy_ram) {
>> @@ -623,14 +623,12 @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram)
>>      /* Start incoming migration from the 1st socket */
>>      migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, "{}");
>>  
>> -    migrate_ensure_non_converge(from);
>> +    migrate_ensure_non_converge(from, args->start.config);
>>  
>>      migrate_qmp(from, to2, NULL, NULL, "{}");
>>  
>>      migrate_wait_for_dirty_mem(from, to2);
>> -
>> -    migrate_ensure_converge(from);
>> -
>> +    migrate_ongoing_ensure_converge(from);
>>      wait_for_stop(from, get_src());
>>      qtest_qmp_eventwait(to2, "RESUME");
>>  
>> @@ -659,7 +657,7 @@ static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
>>       */
>>  
>>      wait_for_serial("src_serial");
>> -    migrate_ensure_converge(from);
>> +    migrate_ensure_converge(from, args->config);
>>  
>>      migrate_qmp(from, to, uri, NULL, "{}");
>>  
>> @@ -684,7 +682,7 @@ static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
>>      migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
>>  
>>      wait_for_serial("src_serial");
>> -    migrate_ensure_converge(from);
>> +    migrate_ensure_converge(from, args->config);
>>  
>>      migrate_qmp(from, to, uri, NULL, "{}");
>>  
>> @@ -709,7 +707,7 @@ static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
>>      migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
>>  
>>      wait_for_serial("src_serial");
>> -    migrate_ensure_converge(from);
>> +    migrate_ensure_converge(from, args->config);
>>  
>>      migrate_qmp(from, to, uri, NULL, "{}");
>>  
>> @@ -739,7 +737,7 @@ static void test_cancel_src_after_none(QTestState *from, QTestState *to,
>>  
>>      migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
>>  
>> -    migrate_ensure_converge(from);
>> +    migrate_ensure_converge(from, args->config);
>>      migrate_qmp(from, to, uri, NULL, "{}");
>>  
>>      wait_for_migration_complete(from);
>> @@ -759,7 +757,7 @@ static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
>>      migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
>>  
>>      wait_for_serial("src_serial");
>> -    migrate_ensure_converge(from);
>> +    migrate_ensure_converge(from, args->config);
>>  
>>      migrate_qmp(from, to, uri, NULL, "{}");
>>  
>> @@ -1066,9 +1064,6 @@ static void migrate_dirty_limit_wait_showup(QTestState *from,
>>      migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
>>      migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
>>  
>> -    /* Make sure migrate can't converge */
>> -    migrate_ensure_non_converge(from);
>> -
>>      /* To check limit rate after precopy */
>>      migrate_set_capability(from, "pause-before-switchover", true);
>>  
>> @@ -1128,6 +1123,7 @@ static void test_dirty_limit(char *name, MigrateCommon *args)
>>      }
>>  
>>      /* Prepare for dirty limit migration and wait src vm show up */
>> +    migrate_ensure_non_converge(from, args->start.config);
>>      migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
>>  
>>      /* Start migrate */
>> -- 
>> 2.51.0
>> 


^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 30/51] tests/qtest/migration: Add temporary code to toggle usage of config
  2025-12-18 19:41     ` Fabiano Rosas
@ 2025-12-18 20:58       ` Peter Xu
  2025-12-18 23:41         ` Fabiano Rosas
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Xu @ 2025-12-18 20:58 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Thu, Dec 18, 2025 at 04:41:46PM -0300, Fabiano Rosas wrote:
> Peter Xu <peterx@redhat.com> writes:
> 
> > On Mon, Dec 15, 2025 at 07:00:16PM -0300, Fabiano Rosas wrote:
> >> The tests are being refactored to pass migration options to QEMU using
> >> the new API of passing a JSON object as argument the migration
> >> commands instead of using several calls to the
> >> migrate_set_capabilities|parameters commands.
> >> 
> >> Since multiple tests share common infrastructure (framework.c,
> >> migration-utils.c, migration-qmp.c), it's cumbersome to convert tests
> >> in small chunks, which would require changes to every common function
> >> to accept both the new and old ways.
> >> 
> >> After some tinkering, an easier way to do this transition is to allow
> >> the tests to set a key in the config dict itself telling whether the
> >> config is supported. With this, the common functions can be fully
> >> altered to support the config object, as long as they check this
> >> temporary key and do the right thing.
> >> 
> >> QEMU doesn't know about this hack, so some code is needed to hide it
> >> when issuing QMP commands with the config object.
> >> 
> >> This will all be removed once tests are fully converted.
> >> 
> >> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> >> ---
> >>  tests/qtest/migration/migration-qmp.h  |  1 -
> >>  tests/qtest/migration/migration-util.c |  1 +
> >>  tests/qtest/migration/migration-util.h | 34 ++++++++++++++++++++++++++
> >>  3 files changed, 35 insertions(+), 1 deletion(-)
> >> 
> >> diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
> >> index 940ffd5950..9a36a677ba 100644
> >> --- a/tests/qtest/migration/migration-qmp.h
> >> +++ b/tests/qtest/migration/migration-qmp.h
> >> @@ -47,5 +47,4 @@ void migrate_recover(QTestState *who, const char *uri);
> >>  void migrate_cancel(QTestState *who);
> >>  void migrate_postcopy_start(QTestState *from, QTestState *to,
> >>                              QTestMigrationState *src_state);
> >> -
> >>  #endif /* MIGRATION_QMP_H */
> >> diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
> >> index 416dd10ef8..e702f00896 100644
> >> --- a/tests/qtest/migration/migration-util.c
> >> +++ b/tests/qtest/migration/migration-util.c
> >> @@ -255,6 +255,7 @@ static void migration_test_wrapper(const void *data)
> >>  
> >>      test->data = g_new0(MigrateCommon, 1);
> >>      test->data->start.config = qdict_new();
> >> +    qdict_put_bool(test->data->start.config, "use-config", false);
> >>  
> >>      g_test_message("Running /%s%s", qtest_get_arch(), test->name);
> >>      test->func(test->name, test->data);
> >> diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
> >> index e73d69bab0..3c3b5a8777 100644
> >> --- a/tests/qtest/migration/migration-util.h
> >> +++ b/tests/qtest/migration/migration-util.h
> >> @@ -60,4 +60,38 @@ void migration_test_add_suffix(const char *path, const char *suffix,
> >>  char *migrate_get_connect_uri(QTestState *who);
> >>  void migrate_set_ports(QTestState *to, QList *channel_list);
> >>  
> >> +/*
> >> + * Scaffolding to allow the framework _common functions and _qmp
> >> + * functions to use the config object while some tests are still using
> >> + * migrate_set_*. Tests that have been converted will set use-config =
> >> + * true on the config dict.
> >> + */
> >> +static bool has_key;
> >> +static bool use_config;
> >
> > Looks like this is temp measure, so no strong opinions.. said that, it
> > looks tricky to have the two globals shared between all the tests, and
> > having magic keys in the qdict.
> >
> 
> It is tricky, but it works. The other options all require "passing
> something" in, which ends up touching good code and causing a mess with
> rebases and the overall clarity of the patches. But let me read about
> your suggestions below...
> 
> > Can we pass in MigrateStart* for config_load() and config_put()?  Then at
> > least we can change globals into per-test flags of MigrateStart.
> >
> > Btw, AFAIU the two helpers should always used in a pair but load() and
> > put() do not look like a pair..
> >
> 
> My mind went to vcpu_load/vcpu_put from kvm code. =D

Fair enough. :) Personally I'd use load/unload in new codes.

> 
> > If we can have args->use_config as a bool, having tests opt-in config
> > setups by setting it, then I wonder if we can do that like:
> >
> 
> The migrate_qmp commands don't take args. So I'd have to alter their
> signature just for this temporary state. That's why I put the flag in
> the dict itself.
> 
> >   if (args->use_config) {
> >       // do whatever with args->config...
> >   } else {
> >       // covered by other migrate-set-parameters QMP commands..
> >   }
> >
> > Do we really need config_put()? I'll keep reading, but please evaluate..
> >
> 
> Because of the migrate_incoming_qmp and -incoming calls, we need to take
> the key out of the dict to hide it. Then put it back so the rest of the
> code, e.g. migrate_qmp can use it.

Can we introduce migrate_qmp_args() wrapper which takes the *args, then
only pass in config if args->use_config for migrate_qmp()?

I still want to know if we can have better way to do this, so that the
qdict should only and always be the real configs to be applied.  That can
remove a major confusion I had when reading this series.

Another example is, I see that you also reused the qdict keys for storing
different tls-creds for client/server, which needs tweak as well before
applying.  I wonder if those can be done with config, config_src,
config_dst, hence whatever passed into migrate_qmp should be
"config+config_src", whilist "config+config_dst" for migrate_incoming_qmp.

IMHO if no way to work it out, one last request is for all special keys we
should have somewhere document them explicitly (maybe above the "config"
var?). We could also make all special keys to be prefixed with "__" (or
something else) so as to be very clear they are special.  We can even
assert in a config_load() making sure no special keys after loaded.

So in general, if there's way to not introduce special keys I'll consider
voting for them first..  Said that, please go choose whatever way you
finally decide. It can take into account of how easy it is to impl the idea
based on your current version, to not make this series drag you too much.
Not a big deal, IMHO we can work on top especially with tests.

> 
> >> +static inline QDict *config_load(QDict *config)
> >> +{
> >> +    if (!config) {
> >> +        return NULL;
> >> +    }
> >> +
> >> +    has_key = qdict_haskey(config, "use-config");
> >> +    if (has_key) {
> >> +        use_config = qdict_get_try_bool(config, "use-config", false);
> >> +        qdict_del(config, "use-config");
> >> +    }
> >> +
> >> +    if (use_config) {
> >> +        return config;
> >> +    }
> >> +
> >> +    return NULL;
> >> +}
> >> +
> >> +static inline void config_put(QDict *config)
> >> +{
> >> +    if (config && has_key) {
> >> +        qdict_put_bool(config, "use-config", use_config);
> >> +    }
> >> +}
> >> +
> >>  #endif /* MIGRATION_UTIL_H */
> >> -- 
> >> 2.51.0
> >> 
> 

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 32/51] tests/qtest/migration: Adapt convergence routines to config
  2025-12-18 19:47     ` Fabiano Rosas
@ 2025-12-18 21:08       ` Peter Xu
  2025-12-18 23:28         ` Fabiano Rosas
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Xu @ 2025-12-18 21:08 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Thu, Dec 18, 2025 at 04:47:47PM -0300, Fabiano Rosas wrote:
> Peter Xu <peterx@redhat.com> writes:
> 
> > On Mon, Dec 15, 2025 at 07:00:18PM -0300, Fabiano Rosas wrote:
> >> Adapt the convergence routines migrate_ensure_[non_]converge to set
> >> the convergence parameters in the config dict it instead of using
> >> migrate-set-parameters.
> >> 
> >> Some tests need to change the convergence parameters during the
> >> migration. The config object method is specific to configuration prior
> >> to starting a migration, so by design it's not suitable to effect
> >> migration-runtime changes. The existing routines will be kept for this
> >> purpose (renamed with 'ongoing' for clarity).
> >> 
> >> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> >> ---
> >>  tests/qtest/migration/framework.c     | 10 ++++-----
> >>  tests/qtest/migration/migration-qmp.c | 32 +++++++++++++++++++++++++--
> >>  tests/qtest/migration/migration-qmp.h |  6 +++--
> >>  tests/qtest/migration/misc-tests.c    |  4 ++--
> >>  tests/qtest/migration/precopy-tests.c | 26 +++++++++-------------
> >>  5 files changed, 52 insertions(+), 26 deletions(-)
> >> 
> >> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> >> index fd15bd832e..df42a8a2c6 100644
> >> --- a/tests/qtest/migration/framework.c
> >> +++ b/tests/qtest/migration/framework.c
> >> @@ -583,7 +583,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
> >>          args->postcopy_data = args->start_hook(from, to);
> >>      }
> >>  
> >> -    migrate_ensure_non_converge(from);
> >> +    migrate_ensure_non_converge(from, args->start.config);
> >>      migrate_prepare_for_dirty_mem(from);
> >>      qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
> >>                               "  'arguments': { "
> >> @@ -872,7 +872,7 @@ int test_precopy_common(MigrateCommon *args)
> >>      }
> >>  
> >>      if (args->live) {
> >> -        migrate_ensure_non_converge(from);
> >> +        migrate_ensure_non_converge(from, args->start.config);
> >>          migrate_prepare_for_dirty_mem(from);
> >>      } else {
> >>          /*
> >> @@ -884,7 +884,7 @@ int test_precopy_common(MigrateCommon *args)
> >>          if (args->result == MIG_TEST_SUCCEED) {
> >>              qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
> >>              wait_for_stop(from, &src_state);
> >> -            migrate_ensure_converge(from);
> >> +            migrate_ongoing_ensure_converge(from);
> >>          }
> >>      }
> >>  
> >> @@ -942,7 +942,7 @@ int test_precopy_common(MigrateCommon *args)
> >>              }
> >>              migrate_wait_for_dirty_mem(from, to);
> >>  
> >> -            migrate_ensure_converge(from);
> >> +            migrate_ongoing_ensure_converge(from);
> >>  
> >>              /*
> >>               * We do this first, as it has a timeout to stop us
> >> @@ -1047,7 +1047,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
> >>          data_hook = args->start_hook(from, to);
> >>      }
> >>  
> >> -    migrate_ensure_converge(from);
> >> +    migrate_ensure_converge(from, args->start.config);
> >>      wait_for_serial("src_serial");
> >>  
> >>      if (stop_src) {
> >> diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
> >> index 5c46ceb3e6..7fe47a5793 100644
> >> --- a/tests/qtest/migration/migration-qmp.c
> >> +++ b/tests/qtest/migration/migration-qmp.c
> >> @@ -499,20 +499,48 @@ void migrate_set_parameter_bool(QTestState *who, const char *parameter,
> >>      migrate_check_parameter_bool(who, parameter, value);
> >>  }
> >>  
> >> -void migrate_ensure_non_converge(QTestState *who)
> >> +void migrate_ongoing_ensure_non_converge(QTestState *who)
> >>  {
> >>      /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
> >>      migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
> >>      migrate_set_parameter_int(who, "downtime-limit", 1);
> >>  }
> >>  
> >> -void migrate_ensure_converge(QTestState *who)
> >> +void migrate_ongoing_ensure_converge(QTestState *who)
> >>  {
> >>      /* Should converge with 30s downtime + 1 gbs bandwidth limit */
> >>      migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
> >>      migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
> >>  }
> >>  
> >> +void migrate_ensure_non_converge(QTestState *who, QDict *config)
> >> +{
> >> +    config = config_load(config);
> >> +    if (config) {
> >> +        /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
> >> +        qdict_put_int(config, "max-bandwidth", 3 * 1000 * 1000);
> >> +        qdict_put_int(config, "downtime-limit", 1);
> >> +    } else {
> >> +        assert(who);
> >> +        migrate_ongoing_ensure_non_converge(who);
> >> +    }
> >> +    config_put(config);
> >> +}
> >> +
> >> +void migrate_ensure_converge(QTestState *who, QDict *config)
> >> +{
> >> +    config = config_load(config);
> >> +    /* Should converge with 30s downtime + 1 gbs bandwidth limit */
> >> +    if (config) {
> >> +        qdict_put_int(config, "max-bandwidth", 1 * 1000 * 1000 * 1000);
> >> +        qdict_put_int(config, "downtime-limit", 30 * 1000);
> >> +    } else {
> >> +        assert(who);
> >> +        migrate_ongoing_ensure_converge(who);
> >> +    }
> >> +    config_put(config);
> >> +}
> >
> > It's slightly an overkill to me to have these converge helpers to provide
> > two versions.  Also a bit confusing on when should we use which.
> >
> > After all, parameters touched on convergence must be able to be dynamically
> > set..
> >
> > Can we always stick with the QMP set-parameters for all these?
> >
> 
> Well, QEMU ignores anything set with migrate-set-parameters once it sees
> the config, so we'd need to change that in the code.
> 
> Thinking about the design of "config", I think the point was to never
> configure a migration via migrate-set-parameters. Always pass the config
> to the migration commands.
> 
> These options are special in that they make sense both before and after
> starting the migration, so it's indeed confusing. I don't know what the
> best approach is.

Hmm, now I start to question whether this is a good idea.  That's about
this patch of the series:

    migration: Allow migrate commands to provide the migration config
    
    Allow the migrate and migrate_incoming commands to pass the migration
    configuration options all at once, dispensing the use of
    migrate-set-parameters and migrate-set-capabilities.
    
    The motivation of this is to simplify the interface with the
    management layer and avoid the usage of several command invocations to
    configure a migration. It also avoids stale parameters from a previous
    migration to influence the current migration.

Logically speaking, if mgmt worries about a stale parameter leftover, the
mgmt should always overwrite it in the config of this QMP migrate command..
Now I don't see a real benefit that we need to ignore global setups.

A mgmt should simply query all parameters when QEMU just started up, then
keep it, then whatever user changes should be applied on top,  Then when
any QMP migrate happens, it should always set all parameters.. no matter
what is the global.

The problem is exactly here, that when some parameters can be dynamically
changed like max-bw, if it was set and throttled 10Gbps dynamically,
migration failed, someone re-started the migration expecting the 10Gbps was
still applied when QMP migrate didn't set max-bw this time, but it didn't
work like that.

Do you think we should make "config" of migrate / migrate_incoming taking
global setting as base, rather than initial_params?  I hope we don't
introduce something for nobody at last, but only to make our lives slightly
harder. :(

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 39/51] tests/qtest/migration: TLS x509: Add init/cleanup routines
  2025-12-15 22:00 ` [PATCH v3 39/51] tests/qtest/migration: TLS x509: Add init/cleanup routines Fabiano Rosas
@ 2025-12-18 21:31   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-18 21:31 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:25PM -0300, Fabiano Rosas wrote:
> Split the TLS x509 hooks by moving out of them any code that doesn't
> need to access the QTestState.
> 
> Aside from making the code harder to follow for no practical reason,
> having extra code in the hooks will soon get in the way of converting
> the tests to use a new API that, unlike
> migrate_set_parameters|capabilities, doesn't require the QEMU instance
> to be already live.
> 
> Move the QTestState-independent code into a normal function and leave
> the hooks only for operations that need the guest machine.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

I think I see what you want to do, this looks ok,

Reviewed-by: Peter Xu <peterx@redhat.com>

One trivial thing to mention below,

> ---
>  tests/qtest/migration/tls-tests.c | 155 +++++++++++++++---------------
>  1 file changed, 75 insertions(+), 80 deletions(-)
> 
> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
> index 8da95dc92a..6a858b766f 100644
> --- a/tests/qtest/migration/tls-tests.c
> +++ b/tests/qtest/migration/tls-tests.c
> @@ -210,15 +210,57 @@ migrate_hook_start_tls_x509_common(QTestState *from,
>                                     void *opaque)
>  {
>      TestMigrateTLSX509 *args = opaque;
> -    TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
> +    const char *workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs);

This introduces a string duplicate with the init() function.

Quick change is we can at least make it a macro so use it in both places
just to be clear that they must match.

Logically we can also make the opaque to be TestMigrateTLSX509Data*
instead, which can add a pointer pointing to TestMigrateTLSX509 (the "Data"
struct is per-test, "non-Data" is a setup, which can be shared).

Either way (the latter will need separate patch), or keep it as-is, you can
keep my R-b.

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 40/51] tests/qtest/migration: TLS PSK: Refactor to use full hook
  2025-12-15 22:00 ` [PATCH v3 40/51] tests/qtest/migration: TLS PSK: Refactor to use full hook Fabiano Rosas
@ 2025-12-18 21:33   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-18 21:33 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:26PM -0300, Fabiano Rosas wrote:
> Similar to what's been done with the TLS x509 tests, pass an object in
> to the TLS PSK common hook so a couple of extra hooks can be removed,
> making the code easier to follow.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 37/51] tests/qtest/migration: Add new hook with data
  2025-12-18 19:05   ` Peter Xu
@ 2025-12-18 21:43     ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-18 21:43 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Thu, Dec 18, 2025 at 02:05:38PM -0500, Peter Xu wrote:
> On Mon, Dec 15, 2025 at 07:00:23PM -0300, Fabiano Rosas wrote:
> > Add a new start hook that takes an opaque pointer so the tests can
> > stop having to nest hook calls.
> 
> I saw that this hook is also removed after the whole series applied.. maybe
> it should be mentioned here.

I guess I read the wrong tree just now... both hooks will be present.

Then IMHO we could have one patch merge them, because start_hook() ones can
ignore the opaque..  Then we can rename start_hook_full() back to
start_hook() (or... just add the opaque since the start into start_hook?).

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 41/51] tests/qtest/migration: TLS PSK: Add init/cleanup routines
  2025-12-15 22:00 ` [PATCH v3 41/51] tests/qtest/migration: TLS PSK: Add init/cleanup routines Fabiano Rosas
@ 2025-12-18 21:48   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-18 21:48 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:27PM -0300, Fabiano Rosas wrote:
> Move TLS PSK setup and cleanup into a common function instead of using
> hooks. Hooks are for when the test needs to access the QTestState.
> 
> This primarily moves setup of TLS PSK tests from ->start_hook time
> earlier into test function call time, which brings the migrate_set_*
> calls within earlier, where they can be replaced in subsequent patches
> with the new config setup.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
>  tests/qtest/migration/tls-tests.c | 149 +++++++++++++++++-------------
>  1 file changed, 83 insertions(+), 66 deletions(-)
> 
> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
> index 2eeed1fc5b..aade57f7de 100644
> --- a/tests/qtest/migration/tls-tests.c
> +++ b/tests/qtest/migration/tls-tests.c
> @@ -23,12 +23,12 @@
>  #endif /* CONFIG_TASN1 */
>  
>  
> -struct TestMigrateTLSPSKData {
> +typedef struct {
>      char *workdir;
>      char *workdiralt;
>      char *pskfile;
>      char *pskfilealt;
> -};
> +} TestMigrateTLSPSKData;
>  
>  typedef struct {
>      bool mismatch;
> @@ -44,59 +44,62 @@ static TestMigrateTLSPSK tls_psk_mismatch = {
>  
>  static char *tmpfs;
>  
> -static void *
> -migrate_hook_start_tls_psk_common(QTestState *from,
> -                                  QTestState *to,
> -                                  void *opaque)
> +static void *migrate_hook_start_tls_psk_common(QTestState *from,
> +                                               QTestState *to,
> +                                               void *opaque)
>  {
>      TestMigrateTLSPSK *args = opaque;
> -    struct TestMigrateTLSPSKData *data =
> -        g_new0(struct TestMigrateTLSPSKData, 1);
> +    g_autofree char *workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs);
> +    g_autofree char *workdiralt = NULL;
>  
> +    if (args->mismatch) {
> +        workdiralt = g_strdup_printf("%s/tlscredspskalt0", tmpfs);
> +    }

Nit: similar string duplications here, now two (workdir, workdiralt).
I guess OK for now,

Reviewed-by: Peter Xu <peterx@redhat.com>

dedup somehow would be better.

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 43/51] tests/qtest/migration: Convert postcopy tests to use config
  2025-12-15 22:00 ` [PATCH v3 43/51] tests/qtest/migration: Convert postcopy tests to use config Fabiano Rosas
@ 2025-12-18 22:03   ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-18 22:03 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:29PM -0300, Fabiano Rosas wrote:
> Make the postcopy tests (including TLS) pass a config argument to
> migration QMP commands.
> 
> Temporarily, set the use-config key to enable the new method.

Maybe worth mention in the commit message that the two set-parameters in
migrate_hook_start_tls_psk_common() will still be kept for now for
non-postcopy tls tests.

> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 44/51] tests/qtest/migration: Convert TLS PSK tests to use config
  2025-12-15 22:00 ` [PATCH v3 44/51] tests/qtest/migration: Convert TLS PSK " Fabiano Rosas
@ 2025-12-18 22:14   ` Peter Xu
  2025-12-18 22:42     ` Fabiano Rosas
  0 siblings, 1 reply; 95+ messages in thread
From: Peter Xu @ 2025-12-18 22:14 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Mon, Dec 15, 2025 at 07:00:30PM -0300, Fabiano Rosas wrote:
> Replace calls to migrate_set_parameters and the usage of args.caps
> with the new config object API.
> 
> The multifd tests are now the same as the "precopy" tests, only
> setting some multifd options, so reuse the precopy code.
> 
> Temporarily, set the use-config key to enable the new method.
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
>  tests/qtest/migration/tls-tests.c | 72 +++++++++----------------------
>  1 file changed, 20 insertions(+), 52 deletions(-)
> 
> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
> index abd6bf9281..68304a7af3 100644
> --- a/tests/qtest/migration/tls-tests.c
> +++ b/tests/qtest/migration/tls-tests.c
> @@ -73,9 +73,6 @@ static void *migrate_hook_start_tls_psk_common(QTestState *from,
>                               "                 'dir': %s } }",
>                               args->mismatch ? workdiralt : workdir);
>  
> -    migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
> -    migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
> -
>      return NULL;
>  }
>  
> @@ -121,6 +118,11 @@ static void test_precopy_tls_psk_common(MigrateCommon *args,
>  {
>      TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
>  
> +    /* temporary */
> +    qdict_put_bool(args->start.config, "use-config", true);
> +
> +    qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
> +
>      migrate_tls_psk_init(args, test_args, data);
>      test_precopy_common(args);
>      migrate_tls_psk_cleanup(data);
> @@ -497,18 +499,11 @@ static void test_precopy_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
>      test_precopy_tls_psk_common(args, &tls_psk_mismatch);
>  }
>  
> -static void *migrate_hook_start_no_tls(QTestState *from, QTestState *to)
> -{
> -    migrate_set_parameter_null(from, "tls-creds");
> -    migrate_set_parameter_null(to, "tls-creds");
> -
> -    return NULL;
> -}
> -
>  static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args)
>  {
>      args->listen_uri = "tcp:127.0.0.1:0";
> -    args->start_hook = migrate_hook_start_no_tls;
> +
> +    qdict_put_null(args->start.config, "tls-creds");
>  
>      test_precopy_common(args);
>  }
> @@ -614,29 +609,7 @@ static void test_precopy_tcp_tls_x509_reject_anon_client(char *name,
>  
>      test_precopy_tls_x509_common(args, &tls_x509_reject_anon_client);
>  }
> -#endif /* CONFIG_TASN1 */
>  
> -static void *
> -migrate_hook_start_multifd_tcp_tls_psk_match(QTestState *from,
> -                                             QTestState *to)
> -{
> -    migrate_set_parameter_str(from, "multifd-compression", "none");
> -    migrate_set_parameter_str(to, "multifd-compression", "none");
> -
> -    return migrate_hook_start_tls_psk_common(from, to, &tls_psk_match);
> -}
> -
> -static void *
> -migrate_hook_start_multifd_tcp_tls_psk_mismatch(QTestState *from,
> -                                                QTestState *to)
> -{
> -    migrate_set_parameter_str(from, "multifd-compression", "none");
> -    migrate_set_parameter_str(to, "multifd-compression", "none");
> -
> -    return migrate_hook_start_tls_psk_common(from, to, &tls_psk_mismatch);
> -}
> -
> -#ifdef CONFIG_TASN1
>  static void *
>  migrate_hook_start_multifd_tls_x509_default_host(QTestState *from,
>                                                   QTestState *to)
> @@ -694,39 +667,34 @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
>  
>  static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
>  {
> -    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
> -    args->listen_uri = "tcp:127.0.0.1:0";
> -
>      args->start.incoming_defer = true;
> -    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>  
> -    test_precopy_tls_psk_common(args, &tls_psk_match);
> +    qdict_put_str(args->start.config, "multifd-compression", "none");
> +    qdict_put_bool(args->start.config, "multifd", true);
> +
> +    test_precopy_tcp_tls_psk_match(name, args);
>  }
>  
>  static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
>  {
> -    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
> -    args->result = MIG_TEST_FAIL;
> -    args->listen_uri = "tcp:127.0.0.1:0";
> -
> -    args->start.hide_stderr = true;
>      args->start.incoming_defer = true;
> -    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>  
> -    test_precopy_tls_psk_common(args, &tls_psk_mismatch);
> +    qdict_put_str(args->start.config, "multifd-compression", "none");

Why do we need to start set multifd-compression=none all the time
(including all below tests)?  Isn't that the default anyway?

> +    qdict_put_bool(args->start.config, "multifd", true);
> +
> +    test_precopy_tcp_tls_psk_mismatch(name, args);
>  }
>  
>  static void test_multifd_postcopy_tcp_tls_psk_match(char *name,
>                                                      MigrateCommon *args)
>  {
> -    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
> -    args->listen_uri = "tcp:127.0.0.1:0";
> -
>      args->start.incoming_defer = true;
> -    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> -    args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true;
>  
> -    test_precopy_tls_psk_common(args, &tls_psk_match);
> +    qdict_put_str(args->start.config, "multifd-compression", "none");
> +    qdict_put_bool(args->start.config, "multifd", true);
> +    qdict_put_bool(args->start.config, "postcopy-ram", true);
> +
> +    test_precopy_tcp_tls_psk_match(name, args);
>  }
>  
>  #ifdef CONFIG_TASN1
> -- 
> 2.51.0
> 

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 44/51] tests/qtest/migration: Convert TLS PSK tests to use config
  2025-12-18 22:14   ` Peter Xu
@ 2025-12-18 22:42     ` Fabiano Rosas
  2025-12-19 15:59       ` Peter Xu
  0 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-18 22:42 UTC (permalink / raw)
  To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

Peter Xu <peterx@redhat.com> writes:

> On Mon, Dec 15, 2025 at 07:00:30PM -0300, Fabiano Rosas wrote:
>> Replace calls to migrate_set_parameters and the usage of args.caps
>> with the new config object API.
>> 
>> The multifd tests are now the same as the "precopy" tests, only
>> setting some multifd options, so reuse the precopy code.
>> 
>> Temporarily, set the use-config key to enable the new method.
>> 
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>>  tests/qtest/migration/tls-tests.c | 72 +++++++++----------------------
>>  1 file changed, 20 insertions(+), 52 deletions(-)
>> 
>> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
>> index abd6bf9281..68304a7af3 100644
>> --- a/tests/qtest/migration/tls-tests.c
>> +++ b/tests/qtest/migration/tls-tests.c
>> @@ -73,9 +73,6 @@ static void *migrate_hook_start_tls_psk_common(QTestState *from,
>>                               "                 'dir': %s } }",
>>                               args->mismatch ? workdiralt : workdir);
>>  
>> -    migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
>> -    migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
>> -
>>      return NULL;
>>  }
>>  
>> @@ -121,6 +118,11 @@ static void test_precopy_tls_psk_common(MigrateCommon *args,
>>  {
>>      TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
>>  
>> +    /* temporary */
>> +    qdict_put_bool(args->start.config, "use-config", true);
>> +
>> +    qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
>> +
>>      migrate_tls_psk_init(args, test_args, data);
>>      test_precopy_common(args);
>>      migrate_tls_psk_cleanup(data);
>> @@ -497,18 +499,11 @@ static void test_precopy_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
>>      test_precopy_tls_psk_common(args, &tls_psk_mismatch);
>>  }
>>  
>> -static void *migrate_hook_start_no_tls(QTestState *from, QTestState *to)
>> -{
>> -    migrate_set_parameter_null(from, "tls-creds");
>> -    migrate_set_parameter_null(to, "tls-creds");
>> -
>> -    return NULL;
>> -}
>> -
>>  static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args)
>>  {
>>      args->listen_uri = "tcp:127.0.0.1:0";
>> -    args->start_hook = migrate_hook_start_no_tls;
>> +
>> +    qdict_put_null(args->start.config, "tls-creds");
>>  
>>      test_precopy_common(args);
>>  }
>> @@ -614,29 +609,7 @@ static void test_precopy_tcp_tls_x509_reject_anon_client(char *name,
>>  
>>      test_precopy_tls_x509_common(args, &tls_x509_reject_anon_client);
>>  }
>> -#endif /* CONFIG_TASN1 */
>>  
>> -static void *
>> -migrate_hook_start_multifd_tcp_tls_psk_match(QTestState *from,
>> -                                             QTestState *to)
>> -{
>> -    migrate_set_parameter_str(from, "multifd-compression", "none");
>> -    migrate_set_parameter_str(to, "multifd-compression", "none");
>> -
>> -    return migrate_hook_start_tls_psk_common(from, to, &tls_psk_match);
>> -}
>> -
>> -static void *
>> -migrate_hook_start_multifd_tcp_tls_psk_mismatch(QTestState *from,
>> -                                                QTestState *to)
>> -{
>> -    migrate_set_parameter_str(from, "multifd-compression", "none");
>> -    migrate_set_parameter_str(to, "multifd-compression", "none");
>> -
>> -    return migrate_hook_start_tls_psk_common(from, to, &tls_psk_mismatch);
>> -}
>> -
>> -#ifdef CONFIG_TASN1
>>  static void *
>>  migrate_hook_start_multifd_tls_x509_default_host(QTestState *from,
>>                                                   QTestState *to)
>> @@ -694,39 +667,34 @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
>>  
>>  static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
>>  {
>> -    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
>> -    args->listen_uri = "tcp:127.0.0.1:0";
>> -
>>      args->start.incoming_defer = true;
>> -    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>>  
>> -    test_precopy_tls_psk_common(args, &tls_psk_match);
>> +    qdict_put_str(args->start.config, "multifd-compression", "none");
>> +    qdict_put_bool(args->start.config, "multifd", true);
>> +
>> +    test_precopy_tcp_tls_psk_match(name, args);
>>  }
>>  
>>  static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
>>  {
>> -    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
>> -    args->result = MIG_TEST_FAIL;
>> -    args->listen_uri = "tcp:127.0.0.1:0";
>> -
>> -    args->start.hide_stderr = true;
>>      args->start.incoming_defer = true;
>> -    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
>>  
>> -    test_precopy_tls_psk_common(args, &tls_psk_mismatch);
>> +    qdict_put_str(args->start.config, "multifd-compression", "none");
>
> Why do we need to start set multifd-compression=none all the time
> (including all below tests)?  Isn't that the default anyway?
>

Because patch 43 removed the hook.

I haven't thought about it being default, I guess I can just remove it
then.



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 32/51] tests/qtest/migration: Adapt convergence routines to config
  2025-12-18 21:08       ` Peter Xu
@ 2025-12-18 23:28         ` Fabiano Rosas
  2025-12-19 15:39           ` Peter Xu
  0 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-18 23:28 UTC (permalink / raw)
  To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

Peter Xu <peterx@redhat.com> writes:

> On Thu, Dec 18, 2025 at 04:47:47PM -0300, Fabiano Rosas wrote:
>> Peter Xu <peterx@redhat.com> writes:
>> 
>> > On Mon, Dec 15, 2025 at 07:00:18PM -0300, Fabiano Rosas wrote:
>> >> Adapt the convergence routines migrate_ensure_[non_]converge to set
>> >> the convergence parameters in the config dict it instead of using
>> >> migrate-set-parameters.
>> >> 
>> >> Some tests need to change the convergence parameters during the
>> >> migration. The config object method is specific to configuration prior
>> >> to starting a migration, so by design it's not suitable to effect
>> >> migration-runtime changes. The existing routines will be kept for this
>> >> purpose (renamed with 'ongoing' for clarity).
>> >> 
>> >> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> >> ---
>> >>  tests/qtest/migration/framework.c     | 10 ++++-----
>> >>  tests/qtest/migration/migration-qmp.c | 32 +++++++++++++++++++++++++--
>> >>  tests/qtest/migration/migration-qmp.h |  6 +++--
>> >>  tests/qtest/migration/misc-tests.c    |  4 ++--
>> >>  tests/qtest/migration/precopy-tests.c | 26 +++++++++-------------
>> >>  5 files changed, 52 insertions(+), 26 deletions(-)
>> >> 
>> >> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
>> >> index fd15bd832e..df42a8a2c6 100644
>> >> --- a/tests/qtest/migration/framework.c
>> >> +++ b/tests/qtest/migration/framework.c
>> >> @@ -583,7 +583,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
>> >>          args->postcopy_data = args->start_hook(from, to);
>> >>      }
>> >>  
>> >> -    migrate_ensure_non_converge(from);
>> >> +    migrate_ensure_non_converge(from, args->start.config);
>> >>      migrate_prepare_for_dirty_mem(from);
>> >>      qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
>> >>                               "  'arguments': { "
>> >> @@ -872,7 +872,7 @@ int test_precopy_common(MigrateCommon *args)
>> >>      }
>> >>  
>> >>      if (args->live) {
>> >> -        migrate_ensure_non_converge(from);
>> >> +        migrate_ensure_non_converge(from, args->start.config);
>> >>          migrate_prepare_for_dirty_mem(from);
>> >>      } else {
>> >>          /*
>> >> @@ -884,7 +884,7 @@ int test_precopy_common(MigrateCommon *args)
>> >>          if (args->result == MIG_TEST_SUCCEED) {
>> >>              qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
>> >>              wait_for_stop(from, &src_state);
>> >> -            migrate_ensure_converge(from);
>> >> +            migrate_ongoing_ensure_converge(from);
>> >>          }
>> >>      }
>> >>  
>> >> @@ -942,7 +942,7 @@ int test_precopy_common(MigrateCommon *args)
>> >>              }
>> >>              migrate_wait_for_dirty_mem(from, to);
>> >>  
>> >> -            migrate_ensure_converge(from);
>> >> +            migrate_ongoing_ensure_converge(from);
>> >>  
>> >>              /*
>> >>               * We do this first, as it has a timeout to stop us
>> >> @@ -1047,7 +1047,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
>> >>          data_hook = args->start_hook(from, to);
>> >>      }
>> >>  
>> >> -    migrate_ensure_converge(from);
>> >> +    migrate_ensure_converge(from, args->start.config);
>> >>      wait_for_serial("src_serial");
>> >>  
>> >>      if (stop_src) {
>> >> diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
>> >> index 5c46ceb3e6..7fe47a5793 100644
>> >> --- a/tests/qtest/migration/migration-qmp.c
>> >> +++ b/tests/qtest/migration/migration-qmp.c
>> >> @@ -499,20 +499,48 @@ void migrate_set_parameter_bool(QTestState *who, const char *parameter,
>> >>      migrate_check_parameter_bool(who, parameter, value);
>> >>  }
>> >>  
>> >> -void migrate_ensure_non_converge(QTestState *who)
>> >> +void migrate_ongoing_ensure_non_converge(QTestState *who)
>> >>  {
>> >>      /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
>> >>      migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
>> >>      migrate_set_parameter_int(who, "downtime-limit", 1);
>> >>  }
>> >>  
>> >> -void migrate_ensure_converge(QTestState *who)
>> >> +void migrate_ongoing_ensure_converge(QTestState *who)
>> >>  {
>> >>      /* Should converge with 30s downtime + 1 gbs bandwidth limit */
>> >>      migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
>> >>      migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
>> >>  }
>> >>  
>> >> +void migrate_ensure_non_converge(QTestState *who, QDict *config)
>> >> +{
>> >> +    config = config_load(config);
>> >> +    if (config) {
>> >> +        /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
>> >> +        qdict_put_int(config, "max-bandwidth", 3 * 1000 * 1000);
>> >> +        qdict_put_int(config, "downtime-limit", 1);
>> >> +    } else {
>> >> +        assert(who);
>> >> +        migrate_ongoing_ensure_non_converge(who);
>> >> +    }
>> >> +    config_put(config);
>> >> +}
>> >> +
>> >> +void migrate_ensure_converge(QTestState *who, QDict *config)
>> >> +{
>> >> +    config = config_load(config);
>> >> +    /* Should converge with 30s downtime + 1 gbs bandwidth limit */
>> >> +    if (config) {
>> >> +        qdict_put_int(config, "max-bandwidth", 1 * 1000 * 1000 * 1000);
>> >> +        qdict_put_int(config, "downtime-limit", 30 * 1000);
>> >> +    } else {
>> >> +        assert(who);
>> >> +        migrate_ongoing_ensure_converge(who);
>> >> +    }
>> >> +    config_put(config);
>> >> +}
>> >
>> > It's slightly an overkill to me to have these converge helpers to provide
>> > two versions.  Also a bit confusing on when should we use which.
>> >
>> > After all, parameters touched on convergence must be able to be dynamically
>> > set..
>> >
>> > Can we always stick with the QMP set-parameters for all these?
>> >
>> 
>> Well, QEMU ignores anything set with migrate-set-parameters once it sees
>> the config, so we'd need to change that in the code.
>> 
>> Thinking about the design of "config", I think the point was to never
>> configure a migration via migrate-set-parameters. Always pass the config
>> to the migration commands.
>> 
>> These options are special in that they make sense both before and after
>> starting the migration, so it's indeed confusing. I don't know what the
>> best approach is.
>
> Hmm, now I start to question whether this is a good idea.  That's about
> this patch of the series:
>
>     migration: Allow migrate commands to provide the migration config
>     
>     Allow the migrate and migrate_incoming commands to pass the migration
>     configuration options all at once, dispensing the use of
>     migrate-set-parameters and migrate-set-capabilities.
>     
>     The motivation of this is to simplify the interface with the
>     management layer and avoid the usage of several command invocations to
>     configure a migration. It also avoids stale parameters from a previous
>     migration to influence the current migration.
>
> Logically speaking, if mgmt worries about a stale parameter leftover, the
> mgmt should always overwrite it in the config of this QMP migrate command..
> Now I don't see a real benefit that we need to ignore global setups.
>
> A mgmt should simply query all parameters when QEMU just started up, then
> keep it, then whatever user changes should be applied on top,  Then when
> any QMP migrate happens, it should always set all parameters.. no matter
> what is the global.
>

We can decide that QEMU will not force the mgmt app to do that work and
will provide an API that doesn't require setting all parameters. I don't
see an argument here.

> The problem is exactly here, that when some parameters can be dynamically
> changed like max-bw, if it was set and throttled 10Gbps dynamically,
> migration failed, someone re-started the migration expecting the 10Gbps was
> still applied when QMP migrate didn't set max-bw this time, but it didn't
> work like that.
>

We need to think about what the QMP API exposes.

If we expose an API that says: QMP_MIGRATE might use a value that was
set using MIGRATE-SET-PARAMETERS 6 months ago because QEMU uses global
state, that's an API usability issue.

If we expose an API that says: QMP_MIGRATE runs the migration with
whatever arguments were passed to it via CONFIG, that sounds like
something sensible.

I don't think the API consumers would be surprised if we allow
MIGRATE-SET-PARAMETERS to change runtime values for a migration and on
the next migration that value is no longer the same.

> Do you think we should make "config" of migrate / migrate_incoming taking
> global setting as base, rather than initial_params?  I hope we don't
> introduce something for nobody at last, but only to make our lives slightly
> harder. :(

One calls a function and it uses the arguments passed to it, that's
it. New migration, new arguments. As you said, mgmt could just hold the
dynamic parameter that their user changed and pass that along with the
config for the new migration.

But I don't think we fleshed out the usage regarding the dynamic
parameters yet. There might be other issues that I'm overlooking. Maybe
we'd need a whole new command with slightly different semantics from
migrate-set-parameters that adjusts the dynamic options while migration
is running, I'm not sure.

---
side note:

If you think the whole endevour of passing a config to qmp_migrate
is a bad idea, please speak up. If mgmt code will require the amount of
churn I had to do for our test suite, maybe it's not worth the effort
after all.

My opinion is that, in general, the "config" changes are going in a good
direction. I worry slightly about what the cost would be for the users
to adhere to it. Migration has been quirky for a looong time, you make
it less quirky people will find it strange =)


^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 30/51] tests/qtest/migration: Add temporary code to toggle usage of config
  2025-12-18 20:58       ` Peter Xu
@ 2025-12-18 23:41         ` Fabiano Rosas
  2025-12-19 15:09           ` Peter Xu
  0 siblings, 1 reply; 95+ messages in thread
From: Fabiano Rosas @ 2025-12-18 23:41 UTC (permalink / raw)
  To: Peter Xu; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

Peter Xu <peterx@redhat.com> writes:

> On Thu, Dec 18, 2025 at 04:41:46PM -0300, Fabiano Rosas wrote:
>> Peter Xu <peterx@redhat.com> writes:
>> 
>> > On Mon, Dec 15, 2025 at 07:00:16PM -0300, Fabiano Rosas wrote:
>> >> The tests are being refactored to pass migration options to QEMU using
>> >> the new API of passing a JSON object as argument the migration
>> >> commands instead of using several calls to the
>> >> migrate_set_capabilities|parameters commands.
>> >> 
>> >> Since multiple tests share common infrastructure (framework.c,
>> >> migration-utils.c, migration-qmp.c), it's cumbersome to convert tests
>> >> in small chunks, which would require changes to every common function
>> >> to accept both the new and old ways.
>> >> 
>> >> After some tinkering, an easier way to do this transition is to allow
>> >> the tests to set a key in the config dict itself telling whether the
>> >> config is supported. With this, the common functions can be fully
>> >> altered to support the config object, as long as they check this
>> >> temporary key and do the right thing.
>> >> 
>> >> QEMU doesn't know about this hack, so some code is needed to hide it
>> >> when issuing QMP commands with the config object.
>> >> 
>> >> This will all be removed once tests are fully converted.
>> >> 
>> >> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> >> ---
>> >>  tests/qtest/migration/migration-qmp.h  |  1 -
>> >>  tests/qtest/migration/migration-util.c |  1 +
>> >>  tests/qtest/migration/migration-util.h | 34 ++++++++++++++++++++++++++
>> >>  3 files changed, 35 insertions(+), 1 deletion(-)
>> >> 
>> >> diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
>> >> index 940ffd5950..9a36a677ba 100644
>> >> --- a/tests/qtest/migration/migration-qmp.h
>> >> +++ b/tests/qtest/migration/migration-qmp.h
>> >> @@ -47,5 +47,4 @@ void migrate_recover(QTestState *who, const char *uri);
>> >>  void migrate_cancel(QTestState *who);
>> >>  void migrate_postcopy_start(QTestState *from, QTestState *to,
>> >>                              QTestMigrationState *src_state);
>> >> -
>> >>  #endif /* MIGRATION_QMP_H */
>> >> diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
>> >> index 416dd10ef8..e702f00896 100644
>> >> --- a/tests/qtest/migration/migration-util.c
>> >> +++ b/tests/qtest/migration/migration-util.c
>> >> @@ -255,6 +255,7 @@ static void migration_test_wrapper(const void *data)
>> >>  
>> >>      test->data = g_new0(MigrateCommon, 1);
>> >>      test->data->start.config = qdict_new();
>> >> +    qdict_put_bool(test->data->start.config, "use-config", false);
>> >>  
>> >>      g_test_message("Running /%s%s", qtest_get_arch(), test->name);
>> >>      test->func(test->name, test->data);
>> >> diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
>> >> index e73d69bab0..3c3b5a8777 100644
>> >> --- a/tests/qtest/migration/migration-util.h
>> >> +++ b/tests/qtest/migration/migration-util.h
>> >> @@ -60,4 +60,38 @@ void migration_test_add_suffix(const char *path, const char *suffix,
>> >>  char *migrate_get_connect_uri(QTestState *who);
>> >>  void migrate_set_ports(QTestState *to, QList *channel_list);
>> >>  
>> >> +/*
>> >> + * Scaffolding to allow the framework _common functions and _qmp
>> >> + * functions to use the config object while some tests are still using
>> >> + * migrate_set_*. Tests that have been converted will set use-config =
>> >> + * true on the config dict.
>> >> + */
>> >> +static bool has_key;
>> >> +static bool use_config;
>> >
>> > Looks like this is temp measure, so no strong opinions.. said that, it
>> > looks tricky to have the two globals shared between all the tests, and
>> > having magic keys in the qdict.
>> >
>> 
>> It is tricky, but it works. The other options all require "passing
>> something" in, which ends up touching good code and causing a mess with
>> rebases and the overall clarity of the patches. But let me read about
>> your suggestions below...
>> 
>> > Can we pass in MigrateStart* for config_load() and config_put()?  Then at
>> > least we can change globals into per-test flags of MigrateStart.
>> >
>> > Btw, AFAIU the two helpers should always used in a pair but load() and
>> > put() do not look like a pair..
>> >
>> 
>> My mind went to vcpu_load/vcpu_put from kvm code. =D
>
> Fair enough. :) Personally I'd use load/unload in new codes.
>
>> 
>> > If we can have args->use_config as a bool, having tests opt-in config
>> > setups by setting it, then I wonder if we can do that like:
>> >
>> 
>> The migrate_qmp commands don't take args. So I'd have to alter their
>> signature just for this temporary state. That's why I put the flag in
>> the dict itself.
>> 
>> >   if (args->use_config) {
>> >       // do whatever with args->config...
>> >   } else {
>> >       // covered by other migrate-set-parameters QMP commands..
>> >   }
>> >
>> > Do we really need config_put()? I'll keep reading, but please evaluate..
>> >
>> 
>> Because of the migrate_incoming_qmp and -incoming calls, we need to take
>> the key out of the dict to hide it. Then put it back so the rest of the
>> code, e.g. migrate_qmp can use it.
>
> Can we introduce migrate_qmp_args() wrapper which takes the *args, then
> only pass in config if args->use_config for migrate_qmp()?
>
> I still want to know if we can have better way to do this, so that the
> qdict should only and always be the real configs to be applied.  That can
> remove a major confusion I had when reading this series.
>

Ok, I can try harder.

> Another example is, I see that you also reused the qdict keys for storing
> different tls-creds for client/server, which needs tweak as well before
> applying.  I wonder if those can be done with config, config_src,
> config_dst, hence whatever passed into migrate_qmp should be
> "config+config_src", whilist "config+config_dst" for migrate_incoming_qmp.
>

Hm, but then we'd have these args->config_src and args->config_dst for
people to misuse. The config reaches migrate_qmp via the _common
functions:

test_foobar(args)
{
    args->config.multifd = true;
    args->config.tls_creds = "abc";
    test_foobar_common(args);
}

test_foobar_common(args)
{
    migrate_start(args);
    ...
    migrate_qmp_incoming(args->config);
    ...
    migrate_qmp(args->config);
}

It would be weird:

test_foobar(args)
{
    args->config.multifd = true;
    args->config_src.tls_creds = "abc";
    args->config_dst.tls_creds = "def";
    test_foobar_common(args);
}

test_foobar_common(args)
{
    migrate_start(args);
    ...
    migrate_qmp_incoming(args->config, args->config_dst);
    ...
    migrate_qmp(args->config, args->config_src);
}

If there's code that needs to check the config for an option, how does
it know which of the three to look at?

> IMHO if no way to work it out, one last request is for all special keys we
> should have somewhere document them explicitly (maybe above the "config"
> var?). We could also make all special keys to be prefixed with "__" (or
> something else) so as to be very clear they are special.  We can even
> assert in a config_load() making sure no special keys after loaded.
>
> So in general, if there's way to not introduce special keys I'll consider
> voting for them first..  Said that, please go choose whatever way you
> finally decide. It can take into account of how easy it is to impl the idea
> based on your current version, to not make this series drag you too much.
> Not a big deal, IMHO we can work on top especially with tests.
>
>> 
>> >> +static inline QDict *config_load(QDict *config)
>> >> +{
>> >> +    if (!config) {
>> >> +        return NULL;
>> >> +    }
>> >> +
>> >> +    has_key = qdict_haskey(config, "use-config");
>> >> +    if (has_key) {
>> >> +        use_config = qdict_get_try_bool(config, "use-config", false);
>> >> +        qdict_del(config, "use-config");
>> >> +    }
>> >> +
>> >> +    if (use_config) {
>> >> +        return config;
>> >> +    }
>> >> +
>> >> +    return NULL;
>> >> +}
>> >> +
>> >> +static inline void config_put(QDict *config)
>> >> +{
>> >> +    if (config && has_key) {
>> >> +        qdict_put_bool(config, "use-config", use_config);
>> >> +    }
>> >> +}
>> >> +
>> >>  #endif /* MIGRATION_UTIL_H */
>> >> -- 
>> >> 2.51.0
>> >> 
>> 


^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 30/51] tests/qtest/migration: Add temporary code to toggle usage of config
  2025-12-18 23:41         ` Fabiano Rosas
@ 2025-12-19 15:09           ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-19 15:09 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Thu, Dec 18, 2025 at 08:41:20PM -0300, Fabiano Rosas wrote:
> Peter Xu <peterx@redhat.com> writes:
> 
> > On Thu, Dec 18, 2025 at 04:41:46PM -0300, Fabiano Rosas wrote:
> >> Peter Xu <peterx@redhat.com> writes:
> >> 
> >> > On Mon, Dec 15, 2025 at 07:00:16PM -0300, Fabiano Rosas wrote:
> >> >> The tests are being refactored to pass migration options to QEMU using
> >> >> the new API of passing a JSON object as argument the migration
> >> >> commands instead of using several calls to the
> >> >> migrate_set_capabilities|parameters commands.
> >> >> 
> >> >> Since multiple tests share common infrastructure (framework.c,
> >> >> migration-utils.c, migration-qmp.c), it's cumbersome to convert tests
> >> >> in small chunks, which would require changes to every common function
> >> >> to accept both the new and old ways.
> >> >> 
> >> >> After some tinkering, an easier way to do this transition is to allow
> >> >> the tests to set a key in the config dict itself telling whether the
> >> >> config is supported. With this, the common functions can be fully
> >> >> altered to support the config object, as long as they check this
> >> >> temporary key and do the right thing.
> >> >> 
> >> >> QEMU doesn't know about this hack, so some code is needed to hide it
> >> >> when issuing QMP commands with the config object.
> >> >> 
> >> >> This will all be removed once tests are fully converted.
> >> >> 
> >> >> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> >> >> ---
> >> >>  tests/qtest/migration/migration-qmp.h  |  1 -
> >> >>  tests/qtest/migration/migration-util.c |  1 +
> >> >>  tests/qtest/migration/migration-util.h | 34 ++++++++++++++++++++++++++
> >> >>  3 files changed, 35 insertions(+), 1 deletion(-)
> >> >> 
> >> >> diff --git a/tests/qtest/migration/migration-qmp.h b/tests/qtest/migration/migration-qmp.h
> >> >> index 940ffd5950..9a36a677ba 100644
> >> >> --- a/tests/qtest/migration/migration-qmp.h
> >> >> +++ b/tests/qtest/migration/migration-qmp.h
> >> >> @@ -47,5 +47,4 @@ void migrate_recover(QTestState *who, const char *uri);
> >> >>  void migrate_cancel(QTestState *who);
> >> >>  void migrate_postcopy_start(QTestState *from, QTestState *to,
> >> >>                              QTestMigrationState *src_state);
> >> >> -
> >> >>  #endif /* MIGRATION_QMP_H */
> >> >> diff --git a/tests/qtest/migration/migration-util.c b/tests/qtest/migration/migration-util.c
> >> >> index 416dd10ef8..e702f00896 100644
> >> >> --- a/tests/qtest/migration/migration-util.c
> >> >> +++ b/tests/qtest/migration/migration-util.c
> >> >> @@ -255,6 +255,7 @@ static void migration_test_wrapper(const void *data)
> >> >>  
> >> >>      test->data = g_new0(MigrateCommon, 1);
> >> >>      test->data->start.config = qdict_new();
> >> >> +    qdict_put_bool(test->data->start.config, "use-config", false);
> >> >>  
> >> >>      g_test_message("Running /%s%s", qtest_get_arch(), test->name);
> >> >>      test->func(test->name, test->data);
> >> >> diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
> >> >> index e73d69bab0..3c3b5a8777 100644
> >> >> --- a/tests/qtest/migration/migration-util.h
> >> >> +++ b/tests/qtest/migration/migration-util.h
> >> >> @@ -60,4 +60,38 @@ void migration_test_add_suffix(const char *path, const char *suffix,
> >> >>  char *migrate_get_connect_uri(QTestState *who);
> >> >>  void migrate_set_ports(QTestState *to, QList *channel_list);
> >> >>  
> >> >> +/*
> >> >> + * Scaffolding to allow the framework _common functions and _qmp
> >> >> + * functions to use the config object while some tests are still using
> >> >> + * migrate_set_*. Tests that have been converted will set use-config =
> >> >> + * true on the config dict.
> >> >> + */
> >> >> +static bool has_key;
> >> >> +static bool use_config;
> >> >
> >> > Looks like this is temp measure, so no strong opinions.. said that, it
> >> > looks tricky to have the two globals shared between all the tests, and
> >> > having magic keys in the qdict.
> >> >
> >> 
> >> It is tricky, but it works. The other options all require "passing
> >> something" in, which ends up touching good code and causing a mess with
> >> rebases and the overall clarity of the patches. But let me read about
> >> your suggestions below...
> >> 
> >> > Can we pass in MigrateStart* for config_load() and config_put()?  Then at
> >> > least we can change globals into per-test flags of MigrateStart.
> >> >
> >> > Btw, AFAIU the two helpers should always used in a pair but load() and
> >> > put() do not look like a pair..
> >> >
> >> 
> >> My mind went to vcpu_load/vcpu_put from kvm code. =D
> >
> > Fair enough. :) Personally I'd use load/unload in new codes.
> >
> >> 
> >> > If we can have args->use_config as a bool, having tests opt-in config
> >> > setups by setting it, then I wonder if we can do that like:
> >> >
> >> 
> >> The migrate_qmp commands don't take args. So I'd have to alter their
> >> signature just for this temporary state. That's why I put the flag in
> >> the dict itself.
> >> 
> >> >   if (args->use_config) {
> >> >       // do whatever with args->config...
> >> >   } else {
> >> >       // covered by other migrate-set-parameters QMP commands..
> >> >   }
> >> >
> >> > Do we really need config_put()? I'll keep reading, but please evaluate..
> >> >
> >> 
> >> Because of the migrate_incoming_qmp and -incoming calls, we need to take
> >> the key out of the dict to hide it. Then put it back so the rest of the
> >> code, e.g. migrate_qmp can use it.
> >
> > Can we introduce migrate_qmp_args() wrapper which takes the *args, then
> > only pass in config if args->use_config for migrate_qmp()?
> >
> > I still want to know if we can have better way to do this, so that the
> > qdict should only and always be the real configs to be applied.  That can
> > remove a major confusion I had when reading this series.
> >
> 
> Ok, I can try harder.

Thanks.

> 
> > Another example is, I see that you also reused the qdict keys for storing
> > different tls-creds for client/server, which needs tweak as well before
> > applying.  I wonder if those can be done with config, config_src,
> > config_dst, hence whatever passed into migrate_qmp should be
> > "config+config_src", whilist "config+config_dst" for migrate_incoming_qmp.
> >
> 
> Hm, but then we'd have these args->config_src and args->config_dst for
> people to misuse. The config reaches migrate_qmp via the _common
> functions:
> 
> test_foobar(args)
> {
>     args->config.multifd = true;
>     args->config.tls_creds = "abc";
>     test_foobar_common(args);
> }
> 
> test_foobar_common(args)
> {
>     migrate_start(args);
>     ...
>     migrate_qmp_incoming(args->config);
>     ...
>     migrate_qmp(args->config);
> }
> 
> It would be weird:
> 
> test_foobar(args)
> {
>     args->config.multifd = true;
>     args->config_src.tls_creds = "abc";
>     args->config_dst.tls_creds = "def";
>     test_foobar_common(args);
> }
> 
> test_foobar_common(args)
> {
>     migrate_start(args);
>     ...
>     migrate_qmp_incoming(args->config, args->config_dst);
>     ...
>     migrate_qmp(args->config, args->config_src);

Here IMHO we can keep the migrate[_incoming]_qmp() taking only one qdict,
like:

      config = migrate_start_get_config_dst(args);  // merge config+dst
      migrate_incoming_qmp(config);
      qobject_unref(config);
      ...
      config = migrate_start_get_config_src(args);  // merge config+src
      migrate_qmp(config);
      qobject_unref(config);

PS: irrelevant of whether we need config_src/config_dst, maybe it'll always
be good to have a pair of such:

   config = migrate_start_get_config_src/dst()
   ...
   qobject_unref(config);

Over fixup_tls_creds()?

I think fixup_tls_creds() is almost that, however IMHO the name of the
function makes it hard to guess what it really does.

> }
> 
> If there's code that needs to check the config for an option, how does
> it know which of the three to look at?

I doubt if we need such use case in tests; I can't find any so far.

If we'll need it, IMHO it should always check against args->config, because
by default migration configs should really always match on both
sides.. which is the shared portion in args->config.

Looks like tls-creds is the only outlier here? If so, maybe we can also
special case it to have args->start having special variable for tls-creds
for both src/dst, then migrate_start_get_config_src() can apply that on top
of the shared config.  IMHO it'll still be slightly better than reusing
keys directly in the qdict.

But maybe config_src/dst is more future-proof.

You may have a better grasp.  Having temp keys in qdict is still fine to me
when use cases are very limited, but as requested before, I wish we can
document all these special keys then above "MigrateStart.config" explicitly
if so.

Not sure if Dan has any preference.

> 
> > IMHO if no way to work it out, one last request is for all special keys we
> > should have somewhere document them explicitly (maybe above the "config"
> > var?). We could also make all special keys to be prefixed with "__" (or
> > something else) so as to be very clear they are special.  We can even
> > assert in a config_load() making sure no special keys after loaded.
> >
> > So in general, if there's way to not introduce special keys I'll consider
> > voting for them first..  Said that, please go choose whatever way you
> > finally decide. It can take into account of how easy it is to impl the idea
> > based on your current version, to not make this series drag you too much.
> > Not a big deal, IMHO we can work on top especially with tests.
> >
> >> 
> >> >> +static inline QDict *config_load(QDict *config)
> >> >> +{
> >> >> +    if (!config) {
> >> >> +        return NULL;
> >> >> +    }
> >> >> +
> >> >> +    has_key = qdict_haskey(config, "use-config");
> >> >> +    if (has_key) {
> >> >> +        use_config = qdict_get_try_bool(config, "use-config", false);
> >> >> +        qdict_del(config, "use-config");
> >> >> +    }
> >> >> +
> >> >> +    if (use_config) {
> >> >> +        return config;
> >> >> +    }
> >> >> +
> >> >> +    return NULL;
> >> >> +}
> >> >> +
> >> >> +static inline void config_put(QDict *config)
> >> >> +{
> >> >> +    if (config && has_key) {
> >> >> +        qdict_put_bool(config, "use-config", use_config);
> >> >> +    }
> >> >> +}
> >> >> +
> >> >>  #endif /* MIGRATION_UTIL_H */
> >> >> -- 
> >> >> 2.51.0
> >> >> 
> >> 
> 

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 32/51] tests/qtest/migration: Adapt convergence routines to config
  2025-12-18 23:28         ` Fabiano Rosas
@ 2025-12-19 15:39           ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-19 15:39 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Thu, Dec 18, 2025 at 08:28:28PM -0300, Fabiano Rosas wrote:
> Peter Xu <peterx@redhat.com> writes:
> 
> > On Thu, Dec 18, 2025 at 04:47:47PM -0300, Fabiano Rosas wrote:
> >> Peter Xu <peterx@redhat.com> writes:
> >> 
> >> > On Mon, Dec 15, 2025 at 07:00:18PM -0300, Fabiano Rosas wrote:
> >> >> Adapt the convergence routines migrate_ensure_[non_]converge to set
> >> >> the convergence parameters in the config dict it instead of using
> >> >> migrate-set-parameters.
> >> >> 
> >> >> Some tests need to change the convergence parameters during the
> >> >> migration. The config object method is specific to configuration prior
> >> >> to starting a migration, so by design it's not suitable to effect
> >> >> migration-runtime changes. The existing routines will be kept for this
> >> >> purpose (renamed with 'ongoing' for clarity).
> >> >> 
> >> >> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> >> >> ---
> >> >>  tests/qtest/migration/framework.c     | 10 ++++-----
> >> >>  tests/qtest/migration/migration-qmp.c | 32 +++++++++++++++++++++++++--
> >> >>  tests/qtest/migration/migration-qmp.h |  6 +++--
> >> >>  tests/qtest/migration/misc-tests.c    |  4 ++--
> >> >>  tests/qtest/migration/precopy-tests.c | 26 +++++++++-------------
> >> >>  5 files changed, 52 insertions(+), 26 deletions(-)
> >> >> 
> >> >> diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c
> >> >> index fd15bd832e..df42a8a2c6 100644
> >> >> --- a/tests/qtest/migration/framework.c
> >> >> +++ b/tests/qtest/migration/framework.c
> >> >> @@ -583,7 +583,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
> >> >>          args->postcopy_data = args->start_hook(from, to);
> >> >>      }
> >> >>  
> >> >> -    migrate_ensure_non_converge(from);
> >> >> +    migrate_ensure_non_converge(from, args->start.config);
> >> >>      migrate_prepare_for_dirty_mem(from);
> >> >>      qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
> >> >>                               "  'arguments': { "
> >> >> @@ -872,7 +872,7 @@ int test_precopy_common(MigrateCommon *args)
> >> >>      }
> >> >>  
> >> >>      if (args->live) {
> >> >> -        migrate_ensure_non_converge(from);
> >> >> +        migrate_ensure_non_converge(from, args->start.config);
> >> >>          migrate_prepare_for_dirty_mem(from);
> >> >>      } else {
> >> >>          /*
> >> >> @@ -884,7 +884,7 @@ int test_precopy_common(MigrateCommon *args)
> >> >>          if (args->result == MIG_TEST_SUCCEED) {
> >> >>              qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
> >> >>              wait_for_stop(from, &src_state);
> >> >> -            migrate_ensure_converge(from);
> >> >> +            migrate_ongoing_ensure_converge(from);
> >> >>          }
> >> >>      }
> >> >>  
> >> >> @@ -942,7 +942,7 @@ int test_precopy_common(MigrateCommon *args)
> >> >>              }
> >> >>              migrate_wait_for_dirty_mem(from, to);
> >> >>  
> >> >> -            migrate_ensure_converge(from);
> >> >> +            migrate_ongoing_ensure_converge(from);
> >> >>  
> >> >>              /*
> >> >>               * We do this first, as it has a timeout to stop us
> >> >> @@ -1047,7 +1047,7 @@ void test_file_common(MigrateCommon *args, bool stop_src)
> >> >>          data_hook = args->start_hook(from, to);
> >> >>      }
> >> >>  
> >> >> -    migrate_ensure_converge(from);
> >> >> +    migrate_ensure_converge(from, args->start.config);
> >> >>      wait_for_serial("src_serial");
> >> >>  
> >> >>      if (stop_src) {
> >> >> diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
> >> >> index 5c46ceb3e6..7fe47a5793 100644
> >> >> --- a/tests/qtest/migration/migration-qmp.c
> >> >> +++ b/tests/qtest/migration/migration-qmp.c
> >> >> @@ -499,20 +499,48 @@ void migrate_set_parameter_bool(QTestState *who, const char *parameter,
> >> >>      migrate_check_parameter_bool(who, parameter, value);
> >> >>  }
> >> >>  
> >> >> -void migrate_ensure_non_converge(QTestState *who)
> >> >> +void migrate_ongoing_ensure_non_converge(QTestState *who)
> >> >>  {
> >> >>      /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
> >> >>      migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
> >> >>      migrate_set_parameter_int(who, "downtime-limit", 1);
> >> >>  }
> >> >>  
> >> >> -void migrate_ensure_converge(QTestState *who)
> >> >> +void migrate_ongoing_ensure_converge(QTestState *who)
> >> >>  {
> >> >>      /* Should converge with 30s downtime + 1 gbs bandwidth limit */
> >> >>      migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
> >> >>      migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
> >> >>  }
> >> >>  
> >> >> +void migrate_ensure_non_converge(QTestState *who, QDict *config)
> >> >> +{
> >> >> +    config = config_load(config);
> >> >> +    if (config) {
> >> >> +        /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
> >> >> +        qdict_put_int(config, "max-bandwidth", 3 * 1000 * 1000);
> >> >> +        qdict_put_int(config, "downtime-limit", 1);
> >> >> +    } else {
> >> >> +        assert(who);
> >> >> +        migrate_ongoing_ensure_non_converge(who);
> >> >> +    }
> >> >> +    config_put(config);
> >> >> +}
> >> >> +
> >> >> +void migrate_ensure_converge(QTestState *who, QDict *config)
> >> >> +{
> >> >> +    config = config_load(config);
> >> >> +    /* Should converge with 30s downtime + 1 gbs bandwidth limit */
> >> >> +    if (config) {
> >> >> +        qdict_put_int(config, "max-bandwidth", 1 * 1000 * 1000 * 1000);
> >> >> +        qdict_put_int(config, "downtime-limit", 30 * 1000);
> >> >> +    } else {
> >> >> +        assert(who);
> >> >> +        migrate_ongoing_ensure_converge(who);
> >> >> +    }
> >> >> +    config_put(config);
> >> >> +}
> >> >
> >> > It's slightly an overkill to me to have these converge helpers to provide
> >> > two versions.  Also a bit confusing on when should we use which.
> >> >
> >> > After all, parameters touched on convergence must be able to be dynamically
> >> > set..
> >> >
> >> > Can we always stick with the QMP set-parameters for all these?
> >> >
> >> 
> >> Well, QEMU ignores anything set with migrate-set-parameters once it sees
> >> the config, so we'd need to change that in the code.
> >> 
> >> Thinking about the design of "config", I think the point was to never
> >> configure a migration via migrate-set-parameters. Always pass the config
> >> to the migration commands.
> >> 
> >> These options are special in that they make sense both before and after
> >> starting the migration, so it's indeed confusing. I don't know what the
> >> best approach is.
> >
> > Hmm, now I start to question whether this is a good idea.  That's about
> > this patch of the series:
> >
> >     migration: Allow migrate commands to provide the migration config
> >     
> >     Allow the migrate and migrate_incoming commands to pass the migration
> >     configuration options all at once, dispensing the use of
> >     migrate-set-parameters and migrate-set-capabilities.
> >     
> >     The motivation of this is to simplify the interface with the
> >     management layer and avoid the usage of several command invocations to
> >     configure a migration. It also avoids stale parameters from a previous
> >     migration to influence the current migration.
> >
> > Logically speaking, if mgmt worries about a stale parameter leftover, the
> > mgmt should always overwrite it in the config of this QMP migrate command..
> > Now I don't see a real benefit that we need to ignore global setups.
> >
> > A mgmt should simply query all parameters when QEMU just started up, then
> > keep it, then whatever user changes should be applied on top,  Then when
> > any QMP migrate happens, it should always set all parameters.. no matter
> > what is the global.
> >
> 
> We can decide that QEMU will not force the mgmt app to do that work and
> will provide an API that doesn't require setting all parameters. I don't
> see an argument here.
> 
> > The problem is exactly here, that when some parameters can be dynamically
> > changed like max-bw, if it was set and throttled 10Gbps dynamically,
> > migration failed, someone re-started the migration expecting the 10Gbps was
> > still applied when QMP migrate didn't set max-bw this time, but it didn't
> > work like that.
> >
> 
> We need to think about what the QMP API exposes.
> 
> If we expose an API that says: QMP_MIGRATE might use a value that was
> set using MIGRATE-SET-PARAMETERS 6 months ago because QEMU uses global
> state, that's an API usability issue.
> 
> If we expose an API that says: QMP_MIGRATE runs the migration with
> whatever arguments were passed to it via CONFIG, that sounds like
> something sensible.
> 
> I don't think the API consumers would be surprised if we allow
> MIGRATE-SET-PARAMETERS to change runtime values for a migration and on
> the next migration that value is no longer the same.
> 
> > Do you think we should make "config" of migrate / migrate_incoming taking
> > global setting as base, rather than initial_params?  I hope we don't
> > introduce something for nobody at last, but only to make our lives slightly
> > harder. :(
> 
> One calls a function and it uses the arguments passed to it, that's
> it. New migration, new arguments. As you said, mgmt could just hold the
> dynamic parameter that their user changed and pass that along with the
> config for the new migration.

It's never about when mgmt is an app like libvirt, IMHO either way we
define it, libvirt will be fine.  It's only about human beings when using
this API e.g. via HMPs, or who start to write scripts manipulating QEMU
directly assuming the max-bw will persist.

That's almost why I thought remembering the globals should be the best
because it will work well for both a computer and a human being.  But I
might be the only one thinking so if you don't agree on this; it's fine.

> 
> But I don't think we fleshed out the usage regarding the dynamic
> parameters yet. There might be other issues that I'm overlooking. Maybe
> we'd need a whole new command with slightly different semantics from
> migrate-set-parameters that adjusts the dynamic options while migration
> is running, I'm not sure.
> 
> ---
> side note:
> 
> If you think the whole endevour of passing a config to qmp_migrate
> is a bad idea, please speak up. If mgmt code will require the amount of
> churn I had to do for our test suite, maybe it's not worth the effort
> after all.

Frankly, I never thought there was an real problem to solve..  the only
thing I can remember is that "libvirt used to control this qemu, but link
down, some admin set something, libvirt reconnected and migration caused
weird issues".

IMHO when reconnect libvirt can always apply all the parameters once
more.. then if link kept, globals are also kept for this session anyway.
IMHO it's fair here because migration is special and unique for a QEMU
instance.  I don't further worry on other weird setups, like QEMU exposing
two QMP monitors - libvirt started the QEMU instance after all.

I almost always thought having "config" in migrate QMP command is a bonus
and optional, since it's still easy to get.  Hence, there's no harm anyway
we support it.  Your other changes (dedup >1 migration parameters structs,
merging caps into parameters, etc.) are more solid changers to me.

I'd confess initially I didn't expect so - logically we can introduce one
or a few new cases to test "config" setups, because most of the code paths
should really be shared (unless we decide to obsolete set-parameters; I
guess we won't.. forever).  But since we moved this far, The test cases are
now also moving all towards configs after this series. I think it's fine,
and you can decide that.

> 
> My opinion is that, in general, the "config" changes are going in a good
> direction. I worry slightly about what the cost would be for the users
> to adhere to it. Migration has been quirky for a looong time, you make
> it less quirky people will find it strange =)

Yes, actually I won't be surprised that after your series lands maybe the
"config" in QMP_MIGRATE won't be used for a while.  And if it keeps going
like that, nobody will consume it.. but I don't really know.  We'll see!

What I know is, after your series lands, I'll start to play with changing
default values for capabilities. :)

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 44/51] tests/qtest/migration: Convert TLS PSK tests to use config
  2025-12-18 22:42     ` Fabiano Rosas
@ 2025-12-19 15:59       ` Peter Xu
  0 siblings, 0 replies; 95+ messages in thread
From: Peter Xu @ 2025-12-19 15:59 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-devel, berrange, armbru, Laurent Vivier, Paolo Bonzini

On Thu, Dec 18, 2025 at 07:42:36PM -0300, Fabiano Rosas wrote:
> Peter Xu <peterx@redhat.com> writes:
> 
> > On Mon, Dec 15, 2025 at 07:00:30PM -0300, Fabiano Rosas wrote:
> >> Replace calls to migrate_set_parameters and the usage of args.caps
> >> with the new config object API.
> >> 
> >> The multifd tests are now the same as the "precopy" tests, only
> >> setting some multifd options, so reuse the precopy code.
> >> 
> >> Temporarily, set the use-config key to enable the new method.
> >> 
> >> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> >> ---
> >>  tests/qtest/migration/tls-tests.c | 72 +++++++++----------------------
> >>  1 file changed, 20 insertions(+), 52 deletions(-)
> >> 
> >> diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c
> >> index abd6bf9281..68304a7af3 100644
> >> --- a/tests/qtest/migration/tls-tests.c
> >> +++ b/tests/qtest/migration/tls-tests.c
> >> @@ -73,9 +73,6 @@ static void *migrate_hook_start_tls_psk_common(QTestState *from,
> >>                               "                 'dir': %s } }",
> >>                               args->mismatch ? workdiralt : workdir);
> >>  
> >> -    migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
> >> -    migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
> >> -
> >>      return NULL;
> >>  }
> >>  
> >> @@ -121,6 +118,11 @@ static void test_precopy_tls_psk_common(MigrateCommon *args,
> >>  {
> >>      TestMigrateTLSPSKData *data = g_new0(TestMigrateTLSPSKData, 1);
> >>  
> >> +    /* temporary */
> >> +    qdict_put_bool(args->start.config, "use-config", true);
> >> +
> >> +    qdict_put_str(args->start.config, "tls-creds", "tlscredspsk0");
> >> +
> >>      migrate_tls_psk_init(args, test_args, data);
> >>      test_precopy_common(args);
> >>      migrate_tls_psk_cleanup(data);
> >> @@ -497,18 +499,11 @@ static void test_precopy_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
> >>      test_precopy_tls_psk_common(args, &tls_psk_mismatch);
> >>  }
> >>  
> >> -static void *migrate_hook_start_no_tls(QTestState *from, QTestState *to)
> >> -{
> >> -    migrate_set_parameter_null(from, "tls-creds");
> >> -    migrate_set_parameter_null(to, "tls-creds");
> >> -
> >> -    return NULL;
> >> -}
> >> -
> >>  static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args)
> >>  {
> >>      args->listen_uri = "tcp:127.0.0.1:0";
> >> -    args->start_hook = migrate_hook_start_no_tls;
> >> +
> >> +    qdict_put_null(args->start.config, "tls-creds");
> >>  
> >>      test_precopy_common(args);
> >>  }
> >> @@ -614,29 +609,7 @@ static void test_precopy_tcp_tls_x509_reject_anon_client(char *name,
> >>  
> >>      test_precopy_tls_x509_common(args, &tls_x509_reject_anon_client);
> >>  }
> >> -#endif /* CONFIG_TASN1 */
> >>  
> >> -static void *
> >> -migrate_hook_start_multifd_tcp_tls_psk_match(QTestState *from,
> >> -                                             QTestState *to)
> >> -{
> >> -    migrate_set_parameter_str(from, "multifd-compression", "none");
> >> -    migrate_set_parameter_str(to, "multifd-compression", "none");
> >> -
> >> -    return migrate_hook_start_tls_psk_common(from, to, &tls_psk_match);
> >> -}
> >> -
> >> -static void *
> >> -migrate_hook_start_multifd_tcp_tls_psk_mismatch(QTestState *from,
> >> -                                                QTestState *to)
> >> -{
> >> -    migrate_set_parameter_str(from, "multifd-compression", "none");
> >> -    migrate_set_parameter_str(to, "multifd-compression", "none");
> >> -
> >> -    return migrate_hook_start_tls_psk_common(from, to, &tls_psk_mismatch);
> >> -}
> >> -
> >> -#ifdef CONFIG_TASN1
> >>  static void *
> >>  migrate_hook_start_multifd_tls_x509_default_host(QTestState *from,
> >>                                                   QTestState *to)
> >> @@ -694,39 +667,34 @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from,
> >>  
> >>  static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args)
> >>  {
> >> -    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match;
> >> -    args->listen_uri = "tcp:127.0.0.1:0";
> >> -
> >>      args->start.incoming_defer = true;
> >> -    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> >>  
> >> -    test_precopy_tls_psk_common(args, &tls_psk_match);
> >> +    qdict_put_str(args->start.config, "multifd-compression", "none");
> >> +    qdict_put_bool(args->start.config, "multifd", true);
> >> +
> >> +    test_precopy_tcp_tls_psk_match(name, args);
> >>  }
> >>  
> >>  static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args)
> >>  {
> >> -    args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch;
> >> -    args->result = MIG_TEST_FAIL;
> >> -    args->listen_uri = "tcp:127.0.0.1:0";
> >> -
> >> -    args->start.hide_stderr = true;
> >>      args->start.incoming_defer = true;
> >> -    args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
> >>  
> >> -    test_precopy_tls_psk_common(args, &tls_psk_mismatch);
> >> +    qdict_put_str(args->start.config, "multifd-compression", "none");
> >
> > Why do we need to start set multifd-compression=none all the time
> > (including all below tests)?  Isn't that the default anyway?
> >
> 
> Because patch 43 removed the hook.
> 
> I haven't thought about it being default, I guess I can just remove it
> then.

Ah yes, you removed the start_hook which used to do it, I got tricked..  It
looks all fine.

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 95+ messages in thread

end of thread, other threads:[~2025-12-19 16:01 UTC | newest]

Thread overview: 95+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-15 21:59 [PATCH v3 00/51] migration: Unify capabilities and parameters Fabiano Rosas
2025-12-15 21:59 ` [PATCH v3 01/51] migration: Fix leak of block_bitmap_mapping Fabiano Rosas
2025-12-15 21:59 ` [PATCH v3 02/51] migration: Fix leak of cpr_exec_command Fabiano Rosas
2025-12-16 16:48   ` Peter Xu
2025-12-15 21:59 ` [PATCH v3 03/51] migration: Add a qdev property for StrOrNull Fabiano Rosas
2025-12-16 16:57   ` Peter Xu
2025-12-15 21:59 ` [PATCH v3 04/51] tests/qtest/migration: Add a NULL parameters test for TLS Fabiano Rosas
2025-12-16 17:03   ` Peter Xu
2025-12-15 21:59 ` [PATCH v3 05/51] migration: Normalize tls arguments Fabiano Rosas
2025-12-16 17:24   ` Peter Xu
2025-12-17 16:40     ` Fabiano Rosas
2025-12-15 21:59 ` [PATCH v3 06/51] migration: Remove MigrateSetParameters Fabiano Rosas
2025-12-15 21:59 ` [PATCH v3 07/51] qapi/migration: Don't document MigrationParameter Fabiano Rosas
2025-12-15 21:59 ` [PATCH v3 08/51] migration: Run a post update routine after setting parameters Fabiano Rosas
2025-12-15 21:59 ` [PATCH v3 09/51] migration: Add a flag to track block-bitmap-mapping input Fabiano Rosas
2025-12-15 21:59 ` [PATCH v3 10/51] migration: Remove checks for s->parameters has_* fields Fabiano Rosas
2025-12-16 18:50   ` Peter Xu
2025-12-15 21:59 ` [PATCH v3 11/51] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE Fabiano Rosas
2025-12-15 21:59 ` [PATCH v3 12/51] migration: Extract code to mark all parameters as present Fabiano Rosas
2025-12-16 18:56   ` Peter Xu
2025-12-15 21:59 ` [PATCH v3 13/51] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 14/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply Fabiano Rosas
2025-12-16 19:31   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 15/51] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply Fabiano Rosas
2025-12-16 20:26   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 16/51] qapi: Add QAPI_MERGE Fabiano Rosas
2025-12-16 20:30   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 17/51] migration: Use QAPI_MERGE in migrate_params_test_apply Fabiano Rosas
2025-12-16 20:47   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 18/51] migration: Cleanup hmp_info_migrate_parameters Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 19/51] migration: Add capabilities into MigrationParameters Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 20/51] migration: Remove s->capabilities Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 21/51] qapi/migration: Deprecate capabilities commands Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 22/51] migration: Store the initial values used for s->parameters Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 23/51] migration: Allow migrate commands to provide the migration config Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 24/51] migration: Allow incoming cmdline to take config Fabiano Rosas
2025-12-17 15:34   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 25/51] tests/qtest/migration: Pass MigrateCommon into test functions Fabiano Rosas
2025-12-16 21:57   ` Peter Xu
2025-12-17 18:35   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 26/51] tests/qtest/migration: Pass MigrateStart into cancel tests Fabiano Rosas
2025-12-16 21:57   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 27/51] tests/qtest/migration: Fix misuse of listen_uri Fabiano Rosas
2025-12-17 15:30   ` Peter Xu
2025-12-17 16:59     ` Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 28/51] tests/qtest/migration: Stop invoking migrate_incoming from hooks Fabiano Rosas
2025-12-17 20:26   ` Peter Xu
2025-12-17 21:05     ` Fabiano Rosas
2025-12-17 21:24       ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 29/51] tests/qtest/migration: Add config QDict Fabiano Rosas
2025-12-17 20:27   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 30/51] tests/qtest/migration: Add temporary code to toggle usage of config Fabiano Rosas
2025-12-18 17:34   ` Peter Xu
2025-12-18 19:41     ` Fabiano Rosas
2025-12-18 20:58       ` Peter Xu
2025-12-18 23:41         ` Fabiano Rosas
2025-12-19 15:09           ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 31/51] tests/qtest/migration: Add a function for default capabilities Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 32/51] tests/qtest/migration: Adapt convergence routines to config Fabiano Rosas
2025-12-18 17:25   ` Peter Xu
2025-12-18 19:47     ` Fabiano Rosas
2025-12-18 21:08       ` Peter Xu
2025-12-18 23:28         ` Fabiano Rosas
2025-12-19 15:39           ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 33/51] tests/qtest/migration: Adapt the incoming cmdline for config passing Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 34/51] tests/qtest/migration: Use migrate_incoming_qmp where possible Fabiano Rosas
2025-12-18 18:47   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 35/51] tests/qtest/migration: Add a config parameter to migrate_qmp functions Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 36/51] tests/qtest/migration: Move tls hook data out of specific hooks Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 37/51] tests/qtest/migration: Add new hook with data Fabiano Rosas
2025-12-18 19:05   ` Peter Xu
2025-12-18 21:43     ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 38/51] tests/qtest/migration: TLS x509: Refactor to use full hook Fabiano Rosas
2025-12-18 19:15   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 39/51] tests/qtest/migration: TLS x509: Add init/cleanup routines Fabiano Rosas
2025-12-18 21:31   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 40/51] tests/qtest/migration: TLS PSK: Refactor to use full hook Fabiano Rosas
2025-12-18 21:33   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 41/51] tests/qtest/migration: TLS PSK: Add init/cleanup routines Fabiano Rosas
2025-12-18 21:48   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 42/51] tests/qtest/migration: Remove multifd compression hook Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 43/51] tests/qtest/migration: Convert postcopy tests to use config Fabiano Rosas
2025-12-18 22:03   ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 44/51] tests/qtest/migration: Convert TLS PSK " Fabiano Rosas
2025-12-18 22:14   ` Peter Xu
2025-12-18 22:42     ` Fabiano Rosas
2025-12-19 15:59       ` Peter Xu
2025-12-15 22:00 ` [PATCH v3 45/51] tests/qtest/migration: Convert TLS x509 " Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 46/51] tests/qtest/migration: Convert compression " Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 47/51] tests/qtest/migration: Convert file " Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 48/51] tests/qtest/migration: Convert misc-tests " Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 49/51] tests/qtest/migration: Convert precopy tests " Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 50/51] tests/qtest/migration: Remove migrate_set_capabilities and code around it Fabiano Rosas
2025-12-15 22:00 ` [PATCH v3 51/51] tests/qtest/migration: Further simplify TLS tests Fabiano Rosas
2025-12-17 16:58 ` [PATCH v3 00/51] migration: Unify capabilities and parameters Peter Xu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.