From: Fabiano Rosas <farosas@suse.de>
To: Markus Armbruster <armbru@redhat.com>
Cc: qemu-devel@nongnu.org, "Peter Xu" <peterx@redhat.com>,
"Daniel P . Berrangé" <berrange@redhat.com>
Subject: Re: [PATCH 01/21] migration: Normalize tls arguments
Date: Wed, 25 Jun 2025 14:17:19 -0300 [thread overview]
Message-ID: <878qlf7nc0.fsf@suse.de> (raw)
In-Reply-To: <87cyas88gg.fsf@pond.sub.org>
Markus Armbruster <armbru@redhat.com> writes:
> Fabiano Rosas <farosas@suse.de> writes:
>
>> 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 and add a
>> helper to ensure they're never actually used as QTYPE_QNULL.
>
> The type of @tls_creds, @tls-hostname, @tls-authz changes from str to
> StrOrNull in introspection query-migrate-parameters. Loss of precision.
> Introspection is already imprecise: it shows the members optional even
> though they aren't. We accept the loss of precision to enable
> de-duplication.
>
> This should be worked into the commit message.
>
Ack.
>> This will allow the type duplication to be removed in the next
>> patches.
>>
>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>> ---
>> migration/migration-hmp-cmds.c | 8 +-
>> migration/migration.c | 2 +
>> migration/options.c | 149 ++++++++++++++++++++-------------
>> migration/options.h | 1 +
>> migration/tls.c | 2 +-
>> qapi/migration.json | 6 +-
>> 6 files changed, 99 insertions(+), 69 deletions(-)
>>
>> diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
>> index e8a563c7d8..bc8179c582 100644
>> --- a/migration/migration-hmp-cmds.c
>> +++ b/migration/migration-hmp-cmds.c
>> @@ -276,14 +276,12 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
>> 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);
>> - assert(params->tls_hostname);
>> + params->tls_creds ? params->tls_creds->u.s : "");
>> monitor_printf(mon, "%s: '%s'\n",
>> MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME),
>> - params->tls_hostname);
>> + params->tls_hostname ? params->tls_hostname->u.s : "");
>> assert(params->has_max_bandwidth);
>> monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
>> MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH),
>> @@ -319,7 +317,7 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
>> params->max_postcopy_bandwidth);
>> monitor_printf(mon, "%s: '%s'\n",
>> MigrationParameter_str(MIGRATION_PARAMETER_TLS_AUTHZ),
>> - params->tls_authz);
>> + params->tls_authz ? params->tls_authz->u.s : "");
>>
>> if (params->has_block_bitmap_mapping) {
>> const BitmapMigrationNodeAliasList *bmnal;
>
> Before, the code assumes ->tls_creds, ->tls_hostname, and ->tls_authz
> are non-null. It assert its assumption for the first two.
>
> Afterwards, it maps null to "". Why is that necessary? Hmm, see below.
>
Maps NULL to "" because the intermediate type, MigrationParameters, has
been changed from str to StrOrNull. For the purposes of info
migrate_parameters and query-migrate-parameters the only valid values
are a non-empty string or an empty string.
>> diff --git a/migration/migration.c b/migration/migration.c
>> index 4697732bef..f65cb81b6d 100644
>> --- a/migration/migration.c
>> +++ b/migration/migration.c
>> @@ -4053,6 +4053,8 @@ static void migration_instance_finalize(Object *obj)
>> {
>> MigrationState *ms = MIGRATION_OBJ(obj);
>>
>> + migrate_tls_opts_free(&ms->parameters);
>
> Is this a bug fix?
>
My new version is a little different, but I can make it a separate patch
if that happens to be the case.
> As far as I can tell, the object gets destroyed only on QEMU shutdown.
> Freeing resources then is unnecessary, except it may help leak detection
> tools.
>
From a maintenance perspective I consider any leak as a bug because I
don't have control over what kinds of leak detection tools are ran on
the code. To avoid spending time looking at such bug reports I have ASAN
automated in my testing and I fix early any leaks that it founds.
>> +
>> qemu_mutex_destroy(&ms->error_mutex);
>> qemu_mutex_destroy(&ms->qemu_file_lock);
>> qemu_sem_destroy(&ms->wait_unplug_sem);
>> diff --git a/migration/options.c b/migration/options.c
>> index 162c72cda4..45a95dc6da 100644
>> --- a/migration/options.c
>> +++ b/migration/options.c
>> @@ -162,9 +162,11 @@ 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),
>> + /*
>> + * tls-creds, tls-hostname and tls-authz are of type StrOrNull,
>> + * which can't be easily handled (if at all) by qdev. So these
>> + * will not be exposed as global migration options (-global).
>> + */
>
> This is a compatibility break.
>
> The orthodox way to break it is deprecate, let the grace period expire,
> break. Record in docs/about/deprecated.rst at the beginning, move the
> record to docs/about/removed-features.rst at the end.
>
> An argument could be made that the interface in question is
> accidental[*], not actually used by anything, and therefore breaking it
> without a grace period is fine. But even then we should record the
> breakage in docs/about/removed-features.rst.
>
Ok. Alternatively I could try a little harder to keep these
options. I'll see what I can do.
> Aside: the interface in question is a hack (making the migration object
> a device) piled onto a hack (the way compat properties work, and how
> they spill into -global). Past sins catching up with us...
>
Hm, I've been experimenting with adding new objects (still TYPE_DEVICE)
to hold the compatibility options and parameters only. Not the entire
migration state. The MigrationState object would then be converted into
a regular struct.
MigrationState => internal type holding migration state (a better name
could be used)
MigrationOptionsState => -global migration-options.foo=on
MigrationCompatState => -global migration foo=on
But it's getting a little tricky due to s->parameters *also* containing
compat options, namely zero-page-detection.
>> DEFINE_PROP_UINT64("x-vcpu-dirty-limit-period", MigrationState,
>> parameters.x_vcpu_dirty_limit_period,
>> DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD),
>> @@ -379,13 +381,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,
>> @@ -834,21 +829,44 @@ const char *migrate_tls_authz(void)
>> {
>> MigrationState *s = migrate_get_current();
>>
>> - return s->parameters.tls_authz;
>> + if (s->parameters.tls_authz &&
>> + s->parameters.tls_authz->type == QTYPE_QSTRING &&
>> + *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 &&
>> + s->parameters.tls_creds->type == QTYPE_QSTRING &&
>> + *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 &&
>> + s->parameters.tls_hostname->type == QTYPE_QSTRING &&
>> + *s->parameters.tls_hostname->u.s) {
>> + return s->parameters.tls_hostname->u.s;
>> + }
>> +
>> + return NULL;
>> +}
>
> Again, the code changes to cope with null. Why is that necessary?
> Again, see below.
>
This is actually a bit roundabout indeed. In my new version I do:
- migrate-set-parameters: always write either NULL or a non-empty
QTYPE_QSTRING to s->parameters.
- query-migrate-parameters: always return a (possibly empty)
QTYPE_QSTRING.
With this, internal representation is: NULL for not present, non-empty
string for present.
>> +
>> +bool migrate_tls(void)
>> +{
>> + return !!migrate_tls_creds();
>> }
>>
>> uint64_t migrate_vcpu_dirty_limit_period(void)
>> @@ -888,6 +906,36 @@ AnnounceParameters *migrate_announce_params(void)
>> return ≈
>> }
>>
>> +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);
>> +}
>> +
>> +/* needs BQL if dst is part of s->parameters */
>> +static void tls_option_set_str(StrOrNull **dstp, StrOrNull *src)
>> +{
>> + StrOrNull *dst = *dstp;
>> +
>> + assert(!dst);
>> +
>> + dst = *dstp = g_new0(StrOrNull, 1);
>> + dst->type = QTYPE_QSTRING;
>> +
>> + if (!src) {
>> + dst->u.s = g_strdup("");
>> + return;
>> + }
>> +
>> + if (src->type == QTYPE_QSTRING) {
>> + dst->u.s = g_strdup(src->u.s);
>> + } else {
>> + assert(src->type == QTYPE_QNULL);
>> + dst->u.s = g_strdup("");
>> + }
>> +}
>
> Postcondition: dstp points to a StrOrNull containing a str,
> i.e. QTYPE_QSTRING. Makes sense.
>
> I'd prefer something like
>
> StrOrNull *dst = g_new0(StrOrNull, 1);
>
> ... fill in members ...
>
> assert(!*dstp);
> *dstp = dst;
>
This code is also reworked a bit on the next version, I'll see whether
the comment still applies.
>> +
>> MigrationParameters *qmp_query_migrate_parameters(Error **errp)
>> {
>> MigrationParameters *params;
>> @@ -903,10 +951,11 @@ 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 : "");
>> +
>> + tls_option_set_str(¶ms->tls_creds, s->parameters.tls_creds);
>> + tls_option_set_str(¶ms->tls_hostname, s->parameters.tls_hostname);
>> + tls_option_set_str(¶ms->tls_authz, s->parameters.tls_authz);
>> +
>> params->has_max_bandwidth = true;
>> params->max_bandwidth = s->parameters.max_bandwidth;
>> params->has_avail_switchover_bandwidth = true;
>> @@ -963,9 +1012,6 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
>>
>> void migrate_params_init(MigrationParameters *params)
>> {
>> - params->tls_hostname = g_strdup("");
>> - params->tls_creds = g_strdup("");
>> -
>
> Is this the reason why the code now needs to deal with null?
>
> I'm not objecting, just pointing out that the commit message didn't
> prepare me for such a change.
>
I'll document it.
>> /* Set has_* up only for parameter checks */
>> params->has_throttle_trigger_threshold = true;
>> params->has_cpu_throttle_initial = true;
>
> I'm stopping here to ask: how exactly does the patch change quasi-global
> state, namely current_migration->parameters->tls_*?
>
It makes sure the current_migration->parameters->tls_* options are
always QTYPE_QSTRING and either a non-empty or an empty string.
The next version of the patch will instead use non-empty QTYPE_QSTRING
or NULL, which is cleaner from a C perspective.
Both versions ensure the query-* and set-* commands continue to expose
the same values. Query only shows non-empty or empty string and Set
accepts all values of a StrOrNull type.
> [...]
>
>
> [*] We have oh so many accidental external interfaces.
next prev parent reply other threads:[~2025-06-25 17:18 UTC|newest]
Thread overview: 83+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-03 1:37 [PATCH 00/21] migration: Unify capabilities and parameters Fabiano Rosas
2025-06-03 1:37 ` [PATCH 01/21] migration: Normalize tls arguments Fabiano Rosas
2025-06-05 20:51 ` Peter Xu
2025-06-06 13:48 ` Fabiano Rosas
2025-06-25 9:41 ` Markus Armbruster
2025-06-25 17:17 ` Fabiano Rosas [this message]
2025-06-26 9:38 ` Markus Armbruster
2025-06-26 14:51 ` Fabiano Rosas
2025-06-27 7:10 ` Markus Armbruster
2025-06-27 20:28 ` Fabiano Rosas
2025-07-01 7:08 ` Markus Armbruster
2025-07-01 9:05 ` Daniel P. Berrangé
2025-06-03 1:37 ` [PATCH 02/21] migration: Remove MigrateSetParameters Fabiano Rosas
2025-06-05 20:58 ` Peter Xu
2025-06-25 11:31 ` Markus Armbruster
2025-06-25 17:21 ` Fabiano Rosas
2025-06-26 9:40 ` Markus Armbruster
2025-06-03 1:37 ` [PATCH 03/21] qapi/migration: Don't document MigrationParameter Fabiano Rosas
2025-06-05 21:00 ` Peter Xu
2025-06-25 12:04 ` Markus Armbruster
2025-06-25 12:22 ` Markus Armbruster
2025-06-25 17:29 ` Fabiano Rosas
2025-06-03 1:37 ` [PATCH 04/21] migration: Run a post update routine after setting parameters Fabiano Rosas
2025-06-03 1:37 ` [PATCH 05/21] migration: Add a flag to track block-bitmap-mapping input Fabiano Rosas
2025-06-06 15:03 ` Peter Xu
2025-06-06 15:43 ` Fabiano Rosas
2025-06-06 17:44 ` Peter Xu
2025-06-06 18:38 ` Fabiano Rosas
2025-06-03 1:37 ` [PATCH 06/21] migration: Remove checks for s->parameters has_* fields Fabiano Rosas
2025-06-06 15:13 ` Peter Xu
2025-06-03 1:37 ` [PATCH 07/21] migration: Set block_bitmap_mapping unconditionally in query-migrate-parameters Fabiano Rosas
2025-06-03 1:37 ` [PATCH 08/21] migration: Do away with usage of QERR_INVALID_PARAMETER_VALUE Fabiano Rosas
2025-06-06 15:17 ` Peter Xu
2025-06-03 1:37 ` [PATCH 09/21] migration: Extract code to mark all parameters as present Fabiano Rosas
2025-06-06 15:26 ` Peter Xu
2025-06-06 15:51 ` Fabiano Rosas
2025-06-06 17:48 ` Peter Xu
2025-06-03 1:37 ` [PATCH 10/21] migration: Use QAPI_CLONE_MEMBERS in query_migrate_parameters Fabiano Rosas
2025-06-06 15:29 ` Peter Xu
2025-06-06 15:53 ` Fabiano Rosas
2025-06-12 20:58 ` Fabiano Rosas
2025-06-12 21:27 ` Peter Xu
2025-06-13 12:30 ` Fabiano Rosas
2025-06-03 1:38 ` [PATCH 11/21] migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply Fabiano Rosas
2025-06-03 1:38 ` [PATCH 12/21] migration: Use QAPI_CLONE_MEMBERS in migrate_params_apply Fabiano Rosas
2025-06-03 1:38 ` [PATCH 13/21] migration: Use visitors in migrate_params_test_apply Fabiano Rosas
2025-06-03 1:38 ` [PATCH 14/21] migration: Cleanup hmp_info_migrate_parameters Fabiano Rosas
2025-06-06 18:52 ` Peter Xu
2025-06-03 1:38 ` [PATCH 15/21] migration: Add capabilities into MigrationParameters Fabiano Rosas
2025-06-06 19:01 ` Peter Xu
2025-06-03 1:38 ` [PATCH 16/21] qapi/migration: Mark that query/set-migrate-parameters support capabilities Fabiano Rosas
2025-06-03 9:01 ` Daniel P. Berrangé
2025-06-06 13:53 ` Fabiano Rosas
2025-06-03 1:38 ` [PATCH 17/21] migration: Remove s->capabilities Fabiano Rosas
2025-06-06 19:16 ` Peter Xu
2025-06-03 1:38 ` [PATCH 18/21] qapi/migration: Deprecate capabilities commands Fabiano Rosas
2025-06-06 19:16 ` Peter Xu
2025-06-03 1:38 ` [PATCH 19/21] migration: Allow migrate commands to provide the migration config Fabiano Rosas
2025-06-03 9:03 ` Daniel P. Berrangé
2025-06-06 19:28 ` Peter Xu
2025-06-06 20:23 ` Fabiano Rosas
2025-06-06 20:50 ` Peter Xu
2025-06-09 14:37 ` Fabiano Rosas
2025-06-09 15:51 ` Peter Xu
2025-06-09 16:13 ` Daniel P. Berrangé
2025-06-09 16:49 ` Peter Xu
2025-06-09 18:17 ` Fabiano Rosas
2025-06-09 18:02 ` Fabiano Rosas
2025-06-09 19:05 ` Peter Xu
2025-06-09 19:41 ` Fabiano Rosas
2025-06-09 20:35 ` Peter Xu
2025-06-10 20:55 ` Fabiano Rosas
2025-06-10 21:27 ` Peter Xu
2025-06-09 15:03 ` Daniel P. Berrangé
2025-06-09 15:33 ` Peter Xu
2025-06-09 15:43 ` Daniel P. Berrangé
2025-06-09 15:53 ` Peter Xu
2025-06-09 15:58 ` Peter Xu
2025-06-09 16:15 ` Daniel P. Berrangé
2025-06-09 16:41 ` Peter Xu
2025-06-03 1:38 ` [PATCH 20/21] libqtest: Add a function to check whether a QMP command supports a feature Fabiano Rosas
2025-06-03 1:38 ` [PATCH 21/21] tests/qtest/migration: Add a test for config passing Fabiano Rosas
2025-06-12 6:41 ` [PATCH 00/21] migration: Unify capabilities and parameters Mario Casquero
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=878qlf7nc0.fsf@suse.de \
--to=farosas@suse.de \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=peterx@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).