@@ -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);
@@ -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()) {
@@ -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) ""
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 <avihaih@nvidia.com> --- migration/tls.h | 27 ++++++++++++++++ migration/tls.c | 72 ++++++++++++++++++++++++++++++++++++++++++ migration/trace-events | 3 ++ 3 files changed, 102 insertions(+)