[PATCH 07/17] migration/tls: Add new migration channel TLS upgrade API

Avihai Horon posted 17 patches 10 months ago
Maintainers: Peter Xu <peterx@redhat.com>, Fabiano Rosas <farosas@suse.de>
[PATCH 07/17] migration/tls: Add new migration channel TLS upgrade API
Posted by Avihai Horon 10 months ago
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(+)

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