migration: Move channel code to channel.c

Move the code responsible for the various channels connection into
channel.c. This is all executed before the migration_thread and
process_incoming_migration_co are running, so it helps the reasoning
to have them out of migration.c.

migration_ioc_process_incoming becomes migration_channel_identify
which is more in line with what the function does.

Reviewed-by: Peter Xu <peterx@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260123141656.6765-19-farosas@suse.de
Signed-off-by: Fabiano Rosas <farosas@suse.de>
This commit is contained in:
Fabiano Rosas
2026-01-23 11:16:48 -03:00
parent 86a0ceb1ce
commit 7d7bf3e60e
5 changed files with 103 additions and 101 deletions

View File

@@ -14,13 +14,110 @@
#include "channel.h"
#include "tls.h"
#include "migration.h"
#include "multifd.h"
#include "savevm.h"
#include "trace.h"
#include "options.h"
#include "qapi/error.h"
#include "io/channel-tls.h"
#include "io/channel-socket.h"
#include "qemu/yank.h"
#include "yank_functions.h"
bool migration_has_main_and_multifd_channels(void)
{
MigrationIncomingState *mis = migration_incoming_get_current();
if (!mis->from_src_file) {
/* main channel not established */
return false;
}
if (migrate_multifd() && !multifd_recv_all_channels_created()) {
return false;
}
/* main and all multifd channels are established */
return true;
}
/**
* @migration_has_all_channels: We have received all channels that we need
*
* Returns true when we have got connections to all the channels that
* we need for migration.
*/
bool migration_has_all_channels(void)
{
if (!migration_has_main_and_multifd_channels()) {
return false;
}
MigrationIncomingState *mis = migration_incoming_get_current();
if (migrate_postcopy_preempt() && !mis->postcopy_qemufile_dst) {
return false;
}
return true;
}
static MigChannelType migration_channel_identify(MigrationIncomingState *mis,
QIOChannel *ioc, Error **errp)
{
MigChannelType channel = CH_NONE;
uint32_t channel_magic = 0;
int ret = 0;
if (!migration_has_main_and_multifd_channels()) {
if (qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_READ_MSG_PEEK)) {
/*
* With multiple channels, it is possible that we receive channels
* out of order on destination side, causing incorrect mapping of
* source channels on destination side. Check channel MAGIC to
* decide type of channel. Please note this is best effort,
* postcopy preempt channel does not send any magic number so
* avoid it for postcopy live migration. Also tls live migration
* already does tls handshake while initializing main channel so
* with tls this issue is not possible.
*/
ret = migration_channel_read_peek(ioc, (void *)&channel_magic,
sizeof(channel_magic), errp);
if (ret != 0) {
goto out;
}
channel_magic = be32_to_cpu(channel_magic);
if (channel_magic == QEMU_VM_FILE_MAGIC) {
channel = CH_MAIN;
} else if (channel_magic == MULTIFD_MAGIC) {
assert(migrate_multifd());
channel = CH_MULTIFD;
} else if (!mis->from_src_file &&
mis->state == MIGRATION_STATUS_POSTCOPY_PAUSED) {
/* reconnect main channel for postcopy recovery */
channel = CH_MAIN;
} else {
error_setg(errp, "unknown channel magic: %u", channel_magic);
}
} else if (mis->from_src_file && migrate_multifd()) {
/*
* Non-peekable channels like tls/file are processed as
* multifd channels when multifd is enabled.
*/
channel = CH_MULTIFD;
} else if (!mis->from_src_file) {
channel = CH_MAIN;
} else {
error_setg(errp, "non-peekable channel used without multifd");
}
} else {
assert(migrate_postcopy_preempt());
channel = CH_POSTCOPY;
}
out:
return channel;
}
/**
* @migration_channel_process_incoming - Create new incoming migration channel
*
@@ -42,7 +139,7 @@ void migration_channel_process_incoming(QIOChannel *ioc)
migration_tls_channel_process_incoming(ioc, &local_err);
} else {
migration_ioc_register_yank(ioc);
ch = migration_ioc_process_incoming(ioc, &local_err);
ch = migration_channel_identify(mis, ioc, &local_err);
if (!ch) {
goto out;
}

View File

@@ -34,4 +34,8 @@ int migration_channel_read_peek(QIOChannel *ioc,
const char *buf,
const size_t buflen,
Error **errp);
bool migration_has_main_and_multifd_channels(void);
bool migration_has_all_channels(void);
#endif

View File

@@ -926,8 +926,6 @@ out:
migrate_incoming_unref_outgoing_state();
}
static bool migration_has_main_and_multifd_channels(void);
/*
* Returns whether all the necessary channels to proceed with the
* incoming migration have been established without error.
@@ -1021,100 +1019,6 @@ void migration_start_incoming(void)
qemu_coroutine_enter(co);
}
static bool migration_has_main_and_multifd_channels(void)
{
MigrationIncomingState *mis = migration_incoming_get_current();
if (!mis->from_src_file) {
/* main channel not established */
return false;
}
if (migrate_multifd() && !multifd_recv_all_channels_created()) {
return false;
}
/* main and all multifd channels are established */
return true;
}
MigChannelType migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
{
MigrationIncomingState *mis = migration_incoming_get_current();
MigChannelType channel = CH_NONE;
uint32_t channel_magic = 0;
int ret = 0;
if (!migration_has_main_and_multifd_channels()) {
if (qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_READ_MSG_PEEK)) {
/*
* With multiple channels, it is possible that we receive channels
* out of order on destination side, causing incorrect mapping of
* source channels on destination side. Check channel MAGIC to
* decide type of channel. Please note this is best effort,
* postcopy preempt channel does not send any magic number so
* avoid it for postcopy live migration. Also tls live migration
* already does tls handshake while initializing main channel so
* with tls this issue is not possible.
*/
ret = migration_channel_read_peek(ioc, (void *)&channel_magic,
sizeof(channel_magic), errp);
if (ret != 0) {
goto out;
}
channel_magic = be32_to_cpu(channel_magic);
if (channel_magic == QEMU_VM_FILE_MAGIC) {
channel = CH_MAIN;
} else if (channel_magic == MULTIFD_MAGIC) {
assert(migrate_multifd());
channel = CH_MULTIFD;
} else if (!mis->from_src_file &&
mis->state == MIGRATION_STATUS_POSTCOPY_PAUSED) {
/* reconnect main channel for postcopy recovery */
channel = CH_MAIN;
} else {
error_setg(errp, "unknown channel magic: %u", channel_magic);
}
} else if (mis->from_src_file && migrate_multifd()) {
/*
* Non-peekable channels like tls/file are processed as
* multifd channels when multifd is enabled.
*/
channel = CH_MULTIFD;
} else if (!mis->from_src_file) {
channel = CH_MAIN;
} else {
error_setg(errp, "non-peekable channel used without multifd");
}
} else {
assert(migrate_postcopy_preempt());
channel = CH_POSTCOPY;
}
out:
return channel;
}
/**
* @migration_has_all_channels: We have received all channels that we need
*
* Returns true when we have got connections to all the channels that
* we need for migration.
*/
bool migration_has_all_channels(void)
{
if (!migration_has_main_and_multifd_channels()) {
return false;
}
MigrationIncomingState *mis = migration_incoming_get_current();
if (migrate_postcopy_preempt() && !mis->postcopy_qemufile_dst) {
return false;
}
return true;
}
int migrate_send_rp_switchover_ack(MigrationIncomingState *mis)
{
return migrate_send_rp_message(mis, MIG_RP_MSG_SWITCHOVER_ACK, 0, NULL);

View File

@@ -28,7 +28,6 @@
#include "postcopy-ram.h"
#include "system/runstate.h"
#include "migration/misc.h"
#include "channel.h"
#define MIGRATION_THREAD_SNAPSHOT "mig/snapshot"
#define MIGRATION_THREAD_DIRTY_RATE "mig/dirtyrate"
@@ -528,13 +527,10 @@ struct MigrationState {
void migrate_set_state(MigrationStatus *state, MigrationStatus old_state,
MigrationStatus new_state);
MigChannelType migration_ioc_process_incoming(QIOChannel *ioc, Error **errp);
void migration_incoming_process(void);
bool migration_incoming_setup(QIOChannel *ioc, uint8_t channel, Error **errp);
void migration_outgoing_setup(QIOChannel *ioc);
bool migration_has_all_channels(void);
void migration_connect_error_propagate(MigrationState *s, Error *error);
void migrate_error_propagate(MigrationState *s, Error *error);
bool migrate_has_error(MigrationState *s);

View File

@@ -18,6 +18,7 @@
#include "channel.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "channel.h"
#include "exec/target_page.h"
#include "rdma.h"
#include "migration.h"