Main migration channel, multifd channels and postcopy preempt channel use the QIOChannelTLS API to upgrade their channels to TLS when needed.
Each of them has its own code to create a QIOChannelTLS and to perform the TLS handshake. Some of this code is duplicate and can be avoided. Add a new API to TLS upgrade migration channels. This will make the code clearer and avoid duplicate code such as TLS handshake, trace handling and threading. Signed-off-by: Avihai Horon <avih...@nvidia.com> --- migration/tls.h | 27 ++++++++++++++++ migration/tls.c | 72 ++++++++++++++++++++++++++++++++++++++++++ migration/trace-events | 3 ++ 3 files changed, 102 insertions(+) diff --git a/migration/tls.h b/migration/tls.h index 5435dd4867..514529ff38 100644 --- a/migration/tls.h +++ b/migration/tls.h @@ -35,6 +35,33 @@ QIOChannelTLS *migration_tls_client_create(QIOChannel *ioc, void migration_tls_channel_connect_main(MigrationState *s, QIOChannel *ioc, const char *hostname, Error **errp); +typedef void (*MigTLSConCallback)(QIOChannel *ioc, void *opaque, Error *err); + +/** + * migration_tls_channel_connect: + * @ioc: The underlying channel object + * @name: The name of the channel + * @hostname: The user specified server hostname + * @callback: The callback to invoke when completed + * @opaque: Opaque data to pass to @callback + * @run_in_thread: Whether to run TLS handshake in new thread or not + * @errp: Pointer to a NULL-initialized error object pointer + * + * Establishes a TLS connection on top of the provided QIOChannel @ioc. If this + * function succeeds, @callback will be invoked upon completion and + * success/failure will be reported to it via the Error object argument. + * In case multiple channels are TLS upgraded in parallel, @run_in_thread + * should be set to true so the TLS handshake will be performed in a new + * thread, to avoid a potential risk of migration hang. + * + * Returns: True on successful initiation of TLS upgrade process, or false on + * failure. + */ +bool migration_tls_channel_connect(QIOChannel *ioc, const char *name, + const char *hostname, + MigTLSConCallback callback, void *opaque, + bool run_in_thread, Error **errp); + /* Whether the QIO channel requires further TLS handshake? */ bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc); diff --git a/migration/tls.c b/migration/tls.c index 803cb54c8b..e6a0349bd1 100644 --- a/migration/tls.c +++ b/migration/tls.c @@ -152,6 +152,78 @@ void migration_tls_channel_connect_main(MigrationState *s, QIOChannel *ioc, NULL, NULL); } +typedef struct { + QIOChannelTLS *tioc; + MigTLSConCallback callback; + void *opaque; + char *name; + QemuThread thread; +} MigTLSConData; + +static void migration_tls_outgoing_handshake(QIOTask *task, void *opaque) +{ + QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task)); + MigTLSConData *data = opaque; + Error *err = NULL; + + if (qio_task_propagate_error(task, &err)) { + trace_migration_tls_outgoing_handshake_error(data->name, + error_get_pretty(err)); + } else { + trace_migration_tls_outgoing_handshake_complete(data->name); + } + + data->callback(ioc, data->opaque, err); + g_free(data->name); + g_free(data); +} + +static void *migration_tls_channel_connect_thread(void *opaque) +{ + MigTLSConData *data = opaque; + + qio_channel_tls_handshake(data->tioc, migration_tls_outgoing_handshake, + data, NULL, NULL); + return NULL; +} + +bool migration_tls_channel_connect(QIOChannel *ioc, const char *name, + const char *hostname, + MigTLSConCallback callback, void *opaque, + bool run_in_thread, Error **errp) +{ + QIOChannelTLS *tioc; + MigTLSConData *data; + g_autofree char *channel_name = NULL; + g_autofree char *thread_name = NULL; + + tioc = migration_tls_client_create(ioc, hostname, errp); + if (!tioc) { + return false; + } + + data = g_new0(MigTLSConData, 1); + data->tioc = tioc; + data->callback = callback; + data->opaque = opaque; + data->name = g_strdup(name); + + trace_migration_tls_outgoing_handshake_start(hostname, name); + channel_name = g_strdup_printf("migration-tls-outgoing-%s", name); + qio_channel_set_name(QIO_CHANNEL(tioc), channel_name); + if (!run_in_thread) { + qio_channel_tls_handshake(tioc, migration_tls_outgoing_handshake, data, + NULL, NULL); + return true; + } + + thread_name = g_strdup_printf("migration-tls-outgoing-worker-%s", name); + qemu_thread_create(&data->thread, thread_name, + migration_tls_channel_connect_thread, data, + QEMU_THREAD_JOINABLE); + return true; +} + bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc) { if (!migrate_tls()) { diff --git a/migration/trace-events b/migration/trace-events index 9448b5cedf..09dd342d37 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -328,6 +328,9 @@ migration_socket_outgoing_error(const char *err) "error=%s" migration_tls_outgoing_handshake_main_start(const char *hostname) "hostname=%s" migration_tls_outgoing_handshake_main_error(const char *err) "err=%s" migration_tls_outgoing_handshake_main_complete(void) "" +migration_tls_outgoing_handshake_start(const char *hostname, const char *name) "hostname=%s, name=%s" +migration_tls_outgoing_handshake_error(const char *name, const char *err) "name=%s, err=%s" +migration_tls_outgoing_handshake_complete(const char *name) "name=%s" migration_tls_incoming_handshake_start(void) "" migration_tls_incoming_handshake_error(const char *err) "err=%s" migration_tls_incoming_handshake_complete(void) "" -- 2.26.3