migration: incoming channel

Extend the -incoming option to allow an @MigrationChannel to be specified.
This allows channels other than 'main' to be described on the command
line, which will be needed for CPR.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
Acked-by: Peter Xu <peterx@redhat.com>
Link: https://lore.kernel.org/r/1736967650-129648-13-git-send-email-steven.sistare@oracle.com
Signed-off-by: Fabiano Rosas <farosas@suse.de>
This commit is contained in:
Steve Sistare 2025-01-15 11:00:38 -08:00 committed by Fabiano Rosas
parent f2374f0fc3
commit 2862b6b924
3 changed files with 70 additions and 8 deletions

View file

@ -695,7 +695,8 @@ static void qemu_start_incoming_migration(const char *uri, bool has_channels,
if (channels) { if (channels) {
/* To verify that Migrate channel list has only item */ /* To verify that Migrate channel list has only item */
if (channels->next) { if (channels->next) {
error_setg(errp, "Channel list has more than one entries"); error_setg(errp, "Channel list must have only one entry, "
"for type 'main'");
return; return;
} }
addr = channels->value->addr; addr = channels->value->addr;
@ -2054,6 +2055,7 @@ void qmp_migrate(const char *uri, bool has_channels,
MigrationState *s = migrate_get_current(); MigrationState *s = migrate_get_current();
g_autoptr(MigrationChannel) channel = NULL; g_autoptr(MigrationChannel) channel = NULL;
MigrationAddress *addr = NULL; MigrationAddress *addr = NULL;
MigrationChannel *channelv[MIGRATION_CHANNEL_TYPE__MAX] = { NULL };
/* /*
* Having preliminary checks for uri and channel * Having preliminary checks for uri and channel
@ -2064,12 +2066,21 @@ void qmp_migrate(const char *uri, bool has_channels,
} }
if (channels) { if (channels) {
/* To verify that Migrate channel list has only item */ for ( ; channels; channels = channels->next) {
if (channels->next) { MigrationChannelType type = channels->value->channel_type;
error_setg(errp, "Channel list has more than one entries");
if (channelv[type]) {
error_setg(errp, "Channel list has more than one %s entry",
MigrationChannelType_str(type));
return;
}
channelv[type] = channels->value;
}
addr = channelv[MIGRATION_CHANNEL_TYPE_MAIN]->addr;
if (!addr) {
error_setg(errp, "Channel list has no main entry");
return; return;
} }
addr = channels->value->addr;
} }
if (uri) { if (uri) {

View file

@ -4940,10 +4940,18 @@ DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \
"-incoming exec:cmdline\n" \ "-incoming exec:cmdline\n" \
" accept incoming migration on given file descriptor\n" \ " accept incoming migration on given file descriptor\n" \
" or from given external command\n" \ " or from given external command\n" \
"-incoming <channel>\n" \
" accept incoming migration on the migration channel\n" \
"-incoming defer\n" \ "-incoming defer\n" \
" wait for the URI to be specified via migrate_incoming\n", " wait for the URI to be specified via migrate_incoming\n",
QEMU_ARCH_ALL) QEMU_ARCH_ALL)
SRST SRST
The -incoming option specifies the migration channel for an incoming
migration. It may be used multiple times to specify multiple
migration channel types. The channel type is specified in <channel>,
or is 'main' for all other forms of -incoming. If multiple -incoming
options are specified for a channel type, the last one takes precedence.
``-incoming tcp:[host]:port[,to=maxport][,ipv4=on|off][,ipv6=on|off]`` ``-incoming tcp:[host]:port[,to=maxport][,ipv4=on|off][,ipv6=on|off]``
\ \
``-incoming rdma:host:port[,ipv4=on|off][,ipv6=on|off]`` ``-incoming rdma:host:port[,ipv4=on|off][,ipv6=on|off]``
@ -4963,6 +4971,19 @@ SRST
Accept incoming migration as an output from specified external Accept incoming migration as an output from specified external
command. command.
``-incoming <channel>``
Accept incoming migration on the migration channel. For the syntax
of <channel>, see the QAPI documentation of ``MigrationChannel``.
Examples:
::
-incoming '{"channel-type": "main",
"addr": { "transport": "socket",
"type": "unix",
"path": "my.sock" }}'
-incoming main,addr.transport=socket,addr.type=unix,addr.path=my.sock
``-incoming defer`` ``-incoming defer``
Wait for the URI to be specified via migrate\_incoming. The monitor Wait for the URI to be specified via migrate\_incoming. The monitor
can be used to change settings (such as migration parameters) prior can be used to change settings (such as migration parameters) prior

View file

@ -123,6 +123,7 @@
#include "qapi/qapi-visit-block-core.h" #include "qapi/qapi-visit-block-core.h"
#include "qapi/qapi-visit-compat.h" #include "qapi/qapi-visit-compat.h"
#include "qapi/qapi-visit-machine.h" #include "qapi/qapi-visit-machine.h"
#include "qapi/qapi-visit-migration.h"
#include "qapi/qapi-visit-ui.h" #include "qapi/qapi-visit-ui.h"
#include "qapi/qapi-commands-block-core.h" #include "qapi/qapi-commands-block-core.h"
#include "qapi/qapi-commands-migration.h" #include "qapi/qapi-commands-migration.h"
@ -159,6 +160,8 @@ typedef struct DeviceOption {
static const char *cpu_option; static const char *cpu_option;
static const char *mem_path; static const char *mem_path;
static const char *incoming; static const char *incoming;
static const char *incoming_str[MIGRATION_CHANNEL_TYPE__MAX];
static MigrationChannel *incoming_channels[MIGRATION_CHANNEL_TYPE__MAX];
static const char *loadvm; static const char *loadvm;
static const char *accelerators; static const char *accelerators;
static bool have_custom_ram_size; static bool have_custom_ram_size;
@ -1813,6 +1816,30 @@ static void object_option_add_visitor(Visitor *v)
QTAILQ_INSERT_TAIL(&object_opts, opt, next); QTAILQ_INSERT_TAIL(&object_opts, opt, next);
} }
static void incoming_option_parse(const char *str)
{
MigrationChannelType type = MIGRATION_CHANNEL_TYPE_MAIN;
MigrationChannel *channel;
Visitor *v;
if (!strcmp(str, "defer")) {
channel = NULL;
} else 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);
visit_free(v);
type = channel->channel_type;
}
/* 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];
}
static void object_option_parse(const char *str) static void object_option_parse(const char *str)
{ {
QemuOpts *opts; QemuOpts *opts;
@ -2738,8 +2765,11 @@ void qmp_x_exit_preconfig(Error **errp)
if (incoming) { if (incoming) {
Error *local_err = NULL; Error *local_err = NULL;
if (strcmp(incoming, "defer") != 0) { if (strcmp(incoming, "defer") != 0) {
qmp_migrate_incoming(incoming, false, NULL, true, true, g_autofree MigrationChannelList *channels =
&local_err); g_new0(MigrationChannelList, 1);
channels->value = incoming_channels[MIGRATION_CHANNEL_TYPE_MAIN];
qmp_migrate_incoming(NULL, true, channels, true, true, &local_err);
if (local_err) { if (local_err) {
error_reportf_err(local_err, "-incoming %s: ", incoming); error_reportf_err(local_err, "-incoming %s: ", incoming);
exit(1); exit(1);
@ -3458,7 +3488,7 @@ void qemu_init(int argc, char **argv)
if (!incoming) { if (!incoming) {
runstate_set(RUN_STATE_INMIGRATE); runstate_set(RUN_STATE_INMIGRATE);
} }
incoming = optarg; incoming_option_parse(optarg);
break; break;
case QEMU_OPTION_only_migratable: case QEMU_OPTION_only_migratable:
only_migratable = 1; only_migratable = 1;