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 <[email protected]>
> ---
> 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


Reply via email to