aboutsummaryrefslogtreecommitdiff
path: root/migration/socket.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-05-26 16:09:26 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-05-26 16:09:27 +0100
commitaef11b8d33ff9018b20ae29d87b1d674ed23dab9 (patch)
treedc8839951876a7063facf6cce77c839ff1fc434a /migration/socket.c
parent2c56d06bafd8933d2a9c6e0aeb5d45f7c1fb5616 (diff)
parent12992c16d9afd8a23a94a84ad532a1adedf9e511 (diff)
downloadqemu-aef11b8d33ff9018b20ae29d87b1d674ed23dab9.zip
qemu-aef11b8d33ff9018b20ae29d87b1d674ed23dab9.tar.gz
qemu-aef11b8d33ff9018b20ae29d87b1d674ed23dab9.tar.bz2
Merge remote-tracking branch 'remotes/amit-migration/tags/migration-2.7-2' into staging
migration: add TLS support to the migration data channel This is a big refactoring of the migration backend code - moving away from QEMUFile to the new QIOChannel framework introduced here. This brings a good level of abstraction and reduction of many lines of code. This series also adds the ability for many backends (all except RDMA) to use TLS for encrypting the migration data between the endpoints. # gpg: Signature made Thu 26 May 2016 07:07:08 BST using RSA key ID 657EF670 # gpg: Good signature from "Amit Shah <amit@amitshah.net>" # gpg: aka "Amit Shah <amit@kernel.org>" # gpg: aka "Amit Shah <amitshah@gmx.net>" * remotes/amit-migration/tags/migration-2.7-2: (28 commits) migration: remove qemu_get_fd method from QEMUFile migration: remove support for non-iovec based write handlers migration: add support for encrypting data with TLS migration: define 'tls-creds' and 'tls-hostname' migration parameters migration: don't use an array for storing migrate parameters migration: move definition of struct QEMUFile back into qemu-file.c migration: delete QEMUFile stdio implementation migration: delete QEMUFile sockets implementation migration: delete QEMUSizedBuffer struct migration: delete QEMUFile buffer implementation migration: convert savevm to use QIOChannel for writing to files migration: convert RDMA to use QIOChannel interface migration: convert exec socket protocol to use QIOChannel migration: convert fd socket protocol to use QIOChannel migration: convert tcp socket protocol to use QIOChannel migration: rename unix.c to socket.c migration: convert unix socket protocol to use QIOChannel migration: convert post-copy to use QIOChannelBuffer migration: add reporting of errors for outgoing migration migration: add helpers for creating QEMUFile from a QIOChannel ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'migration/socket.c')
-rw-r--r--migration/socket.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/migration/socket.c b/migration/socket.c
new file mode 100644
index 0000000..977a8d3
--- /dev/null
+++ b/migration/socket.c
@@ -0,0 +1,183 @@
+/*
+ * QEMU live migration via Unix Domain Sockets
+ *
+ * Copyright Red Hat, Inc. 2009-2016
+ *
+ * Authors:
+ * Chris Lalancette <clalance@redhat.com>
+ * Daniel P. Berrange <berrange@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "migration/migration.h"
+#include "migration/qemu-file.h"
+#include "io/channel-socket.h"
+#include "trace.h"
+
+
+static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
+{
+ InetSocketAddress *iaddr = inet_parse(host_port, errp);
+ SocketAddress *saddr;
+
+ if (!iaddr) {
+ return NULL;
+ }
+
+ saddr = g_new0(SocketAddress, 1);
+ saddr->type = SOCKET_ADDRESS_KIND_INET;
+ saddr->u.inet.data = iaddr;
+
+ return saddr;
+}
+
+
+static SocketAddress *unix_build_address(const char *path)
+{
+ SocketAddress *saddr;
+
+ saddr = g_new0(SocketAddress, 1);
+ saddr->type = SOCKET_ADDRESS_KIND_UNIX;
+ saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
+ saddr->u.q_unix.data->path = g_strdup(path);
+
+ return saddr;
+}
+
+
+struct SocketConnectData {
+ MigrationState *s;
+ char *hostname;
+};
+
+static void socket_connect_data_free(void *opaque)
+{
+ struct SocketConnectData *data = opaque;
+ if (!data) {
+ return;
+ }
+ g_free(data->hostname);
+ g_free(data);
+}
+
+static void socket_outgoing_migration(Object *src,
+ Error *err,
+ gpointer opaque)
+{
+ struct SocketConnectData *data = opaque;
+ QIOChannel *sioc = QIO_CHANNEL(src);
+
+ if (err) {
+ trace_migration_socket_outgoing_error(error_get_pretty(err));
+ data->s->to_dst_file = NULL;
+ migrate_fd_error(data->s, err);
+ } else {
+ trace_migration_socket_outgoing_connected(data->hostname);
+ migration_set_outgoing_channel(data->s, sioc, data->hostname);
+ }
+ object_unref(src);
+}
+
+static void socket_start_outgoing_migration(MigrationState *s,
+ SocketAddress *saddr,
+ Error **errp)
+{
+ QIOChannelSocket *sioc = qio_channel_socket_new();
+ struct SocketConnectData *data = g_new0(struct SocketConnectData, 1);
+ data->s = s;
+ if (saddr->type == SOCKET_ADDRESS_KIND_INET) {
+ data->hostname = g_strdup(saddr->u.inet.data->host);
+ }
+ qio_channel_socket_connect_async(sioc,
+ saddr,
+ socket_outgoing_migration,
+ data,
+ socket_connect_data_free);
+ qapi_free_SocketAddress(saddr);
+}
+
+void tcp_start_outgoing_migration(MigrationState *s,
+ const char *host_port,
+ Error **errp)
+{
+ SocketAddress *saddr = tcp_build_address(host_port, errp);
+ socket_start_outgoing_migration(s, saddr, errp);
+}
+
+void unix_start_outgoing_migration(MigrationState *s,
+ const char *path,
+ Error **errp)
+{
+ SocketAddress *saddr = unix_build_address(path);
+ socket_start_outgoing_migration(s, saddr, errp);
+}
+
+
+static gboolean socket_accept_incoming_migration(QIOChannel *ioc,
+ GIOCondition condition,
+ gpointer opaque)
+{
+ QIOChannelSocket *sioc;
+ Error *err = NULL;
+
+ sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
+ &err);
+ if (!sioc) {
+ error_report("could not accept migration connection (%s)",
+ error_get_pretty(err));
+ goto out;
+ }
+
+ trace_migration_socket_incoming_accepted();
+
+ migration_set_incoming_channel(migrate_get_current(),
+ QIO_CHANNEL(sioc));
+ object_unref(OBJECT(sioc));
+
+out:
+ /* Close listening socket as its no longer needed */
+ qio_channel_close(ioc, NULL);
+ return FALSE; /* unregister */
+}
+
+
+static void socket_start_incoming_migration(SocketAddress *saddr,
+ Error **errp)
+{
+ QIOChannelSocket *listen_ioc = qio_channel_socket_new();
+
+ if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
+ object_unref(OBJECT(listen_ioc));
+ qapi_free_SocketAddress(saddr);
+ return;
+ }
+
+ qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
+ G_IO_IN,
+ socket_accept_incoming_migration,
+ listen_ioc,
+ (GDestroyNotify)object_unref);
+ qapi_free_SocketAddress(saddr);
+}
+
+void tcp_start_incoming_migration(const char *host_port, Error **errp)
+{
+ SocketAddress *saddr = tcp_build_address(host_port, errp);
+ socket_start_incoming_migration(saddr, errp);
+}
+
+void unix_start_incoming_migration(const char *path, Error **errp)
+{
+ SocketAddress *saddr = unix_build_address(path);
+ socket_start_incoming_migration(saddr, errp);
+}