diff options
-rw-r--r-- | include/migration/migration.h | 12 | ||||
-rw-r--r-- | migration/Makefile.objs | 1 | ||||
-rw-r--r-- | migration/exec.c | 2 | ||||
-rw-r--r-- | migration/fd.c | 2 | ||||
-rw-r--r-- | migration/migration.c | 40 | ||||
-rw-r--r-- | migration/socket.c | 34 | ||||
-rw-r--r-- | migration/tls.c | 161 | ||||
-rw-r--r-- | trace-events | 12 |
8 files changed, 247 insertions, 17 deletions
diff --git a/include/migration/migration.h b/include/migration/migration.h index 74105a11a1..13b12b7e87 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -188,8 +188,18 @@ void qemu_start_incoming_migration(const char *uri, Error **errp); void migration_set_incoming_channel(MigrationState *s, QIOChannel *ioc); +void migration_tls_set_incoming_channel(MigrationState *s, + QIOChannel *ioc, + Error **errp); + void migration_set_outgoing_channel(MigrationState *s, - QIOChannel *ioc); + QIOChannel *ioc, + const char *hostname); + +void migration_tls_set_outgoing_channel(MigrationState *s, + QIOChannel *ioc, + const char *hostname, + Error **errp); uint64_t migrate_max_downtime(void); diff --git a/migration/Makefile.objs b/migration/Makefile.objs index 7e1bec22f5..30ad945918 100644 --- a/migration/Makefile.objs +++ b/migration/Makefile.objs @@ -1,4 +1,5 @@ common-obj-y += migration.o socket.o fd.o exec.o +common-obj-y += tls.o common-obj-y += vmstate.o common-obj-y += qemu-file.o common-obj-y += qemu-file-channel.o diff --git a/migration/exec.c b/migration/exec.c index c825e273d8..1515cc3319 100644 --- a/migration/exec.c +++ b/migration/exec.c @@ -38,7 +38,7 @@ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error return; } - migration_set_outgoing_channel(s, ioc); + migration_set_outgoing_channel(s, ioc, NULL); object_unref(OBJECT(ioc)); } diff --git a/migration/fd.c b/migration/fd.c index 60a75b81e0..fc5c9eee02 100644 --- a/migration/fd.c +++ b/migration/fd.c @@ -38,7 +38,7 @@ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error ** return; } - migration_set_outgoing_channel(s, ioc); + migration_set_outgoing_channel(s, ioc, NULL); object_unref(OBJECT(ioc)); } diff --git a/migration/migration.c b/migration/migration.c index 9b037ab9f1..7ecbadee6f 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -35,6 +35,7 @@ #include "exec/memory.h" #include "exec/address-spaces.h" #include "io/channel-buffer.h" +#include "io/channel-tls.h" #define MAX_THROTTLE (32 << 20) /* Migration transfer speed throttling */ @@ -428,20 +429,47 @@ void process_incoming_migration(QEMUFile *f) void migration_set_incoming_channel(MigrationState *s, QIOChannel *ioc) { - QEMUFile *f = qemu_fopen_channel_input(ioc); + trace_migration_set_incoming_channel( + ioc, object_get_typename(OBJECT(ioc))); - process_incoming_migration(f); + if (s->parameters.tls_creds && + !object_dynamic_cast(OBJECT(ioc), + TYPE_QIO_CHANNEL_TLS)) { + Error *local_err = NULL; + migration_tls_set_incoming_channel(s, ioc, &local_err); + if (local_err) { + error_report_err(local_err); + } + } else { + QEMUFile *f = qemu_fopen_channel_input(ioc); + process_incoming_migration(f); + } } void migration_set_outgoing_channel(MigrationState *s, - QIOChannel *ioc) + QIOChannel *ioc, + const char *hostname) { - QEMUFile *f = qemu_fopen_channel_output(ioc); + trace_migration_set_outgoing_channel( + ioc, object_get_typename(OBJECT(ioc)), hostname); - s->to_dst_file = f; + if (s->parameters.tls_creds && + !object_dynamic_cast(OBJECT(ioc), + TYPE_QIO_CHANNEL_TLS)) { + Error *local_err = NULL; + migration_tls_set_outgoing_channel(s, ioc, hostname, &local_err); + if (local_err) { + migrate_fd_error(s, local_err); + error_free(local_err); + } + } else { + QEMUFile *f = qemu_fopen_channel_output(ioc); + + s->to_dst_file = f; - migrate_fd_connect(s); + migrate_fd_connect(s); + } } diff --git a/migration/socket.c b/migration/socket.c index 25457eaee9..977a8d3c1d 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -55,20 +55,35 @@ static SocketAddress *unix_build_address(const char *path) } +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) { - MigrationState *s = opaque; + struct SocketConnectData *data = opaque; QIOChannel *sioc = QIO_CHANNEL(src); if (err) { trace_migration_socket_outgoing_error(error_get_pretty(err)); - s->to_dst_file = NULL; - migrate_fd_error(s, err); + data->s->to_dst_file = NULL; + migrate_fd_error(data->s, err); } else { - trace_migration_socket_outgoing_connected(); - migration_set_outgoing_channel(s, sioc); + trace_migration_socket_outgoing_connected(data->hostname); + migration_set_outgoing_channel(data->s, sioc, data->hostname); } object_unref(src); } @@ -78,11 +93,16 @@ static void socket_start_outgoing_migration(MigrationState *s, 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, - s, - NULL); + data, + socket_connect_data_free); qapi_free_SocketAddress(saddr); } diff --git a/migration/tls.c b/migration/tls.c new file mode 100644 index 0000000000..75f959ff9c --- /dev/null +++ b/migration/tls.c @@ -0,0 +1,161 @@ +/* + * QEMU migration TLS support + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "migration/migration.h" +#include "io/channel-tls.h" +#include "crypto/tlscreds.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "trace.h" + +static QCryptoTLSCreds * +migration_tls_get_creds(MigrationState *s, + QCryptoTLSCredsEndpoint endpoint, + Error **errp) +{ + Object *creds; + QCryptoTLSCreds *ret; + + creds = object_resolve_path_component( + object_get_objects_root(), s->parameters.tls_creds); + if (!creds) { + error_setg(errp, "No TLS credentials with id '%s'", + s->parameters.tls_creds); + return NULL; + } + ret = (QCryptoTLSCreds *)object_dynamic_cast( + creds, TYPE_QCRYPTO_TLS_CREDS); + if (!ret) { + error_setg(errp, "Object with id '%s' is not TLS credentials", + s->parameters.tls_creds); + return NULL; + } + if (ret->endpoint != endpoint) { + error_setg(errp, + "Expected TLS credentials for a %s endpoint", + endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT ? + "client" : "server"); + return NULL; + } + + object_ref(OBJECT(ret)); + return ret; +} + + +static void migration_tls_incoming_handshake(Object *src, + Error *err, + gpointer opaque) +{ + QIOChannel *ioc = QIO_CHANNEL(src); + + if (err) { + trace_migration_tls_incoming_handshake_error(error_get_pretty(err)); + error_report("%s", error_get_pretty(err)); + } else { + trace_migration_tls_incoming_handshake_complete(); + migration_set_incoming_channel(migrate_get_current(), ioc); + } + object_unref(OBJECT(ioc)); +} + +void migration_tls_set_incoming_channel(MigrationState *s, + QIOChannel *ioc, + Error **errp) +{ + QCryptoTLSCreds *creds; + QIOChannelTLS *tioc; + + creds = migration_tls_get_creds( + s, QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, errp); + if (!creds) { + return; + } + + tioc = qio_channel_tls_new_server( + ioc, creds, + NULL, /* XXX pass ACL name */ + errp); + if (!tioc) { + return; + } + + trace_migration_tls_incoming_handshake_start(); + qio_channel_tls_handshake(tioc, + migration_tls_incoming_handshake, + NULL, + NULL); +} + + +static void migration_tls_outgoing_handshake(Object *src, + Error *err, + gpointer opaque) +{ + MigrationState *s = opaque; + QIOChannel *ioc = QIO_CHANNEL(src); + + if (err) { + trace_migration_tls_outgoing_handshake_error(error_get_pretty(err)); + s->to_dst_file = NULL; + migrate_fd_error(s, err); + } else { + trace_migration_tls_outgoing_handshake_complete(); + migration_set_outgoing_channel(s, ioc, NULL); + } + object_unref(OBJECT(ioc)); +} + + +void migration_tls_set_outgoing_channel(MigrationState *s, + QIOChannel *ioc, + const char *hostname, + Error **errp) +{ + QCryptoTLSCreds *creds; + QIOChannelTLS *tioc; + + creds = migration_tls_get_creds( + s, QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, errp); + if (!creds) { + return; + } + + if (s->parameters.tls_hostname) { + hostname = s->parameters.tls_hostname; + } + if (!hostname) { + error_setg(errp, "No hostname available for TLS"); + return; + } + + tioc = qio_channel_tls_new_client( + ioc, creds, hostname, errp); + if (!tioc) { + return; + } + + trace_migration_tls_outgoing_handshake_start(hostname); + qio_channel_tls_handshake(tioc, + migration_tls_outgoing_handshake, + s, + NULL); +} diff --git a/trace-events b/trace-events index 1584b0afd1..c276075eb4 100644 --- a/trace-events +++ b/trace-events @@ -1511,6 +1511,8 @@ migrate_state_too_big(void) "" migrate_transferred(uint64_t tranferred, uint64_t time_spent, double bandwidth, uint64_t size) "transferred %" PRIu64 " time_spent %" PRIu64 " bandwidth %g max_size %" PRId64 process_incoming_migration_co_end(int ret, int ps) "ret=%d postcopy-state=%d" process_incoming_migration_co_postcopy_end_main(void) "" +migration_set_incoming_channel(void *ioc, const char *ioctype) "ioc=%p ioctype=%s" +migration_set_outgoing_channel(void *ioc, const char *ioctype, const char *hostname) "ioc=%p ioctype=%s hostname=%s" # migration/rdma.c qemu_rdma_accept_incoming_migration(void) "" @@ -1605,9 +1607,17 @@ migration_fd_incoming(int fd) "fd=%d" # migration/socket.c migration_socket_incoming_accepted(void) "" -migration_socket_outgoing_connected(void) "" +migration_socket_outgoing_connected(const char *hostname) "hostname=%s" migration_socket_outgoing_error(const char *err) "error=%s" +# migration/tls.c +migration_tls_outgoing_handshake_start(const char *hostname) "hostname=%s" +migration_tls_outgoing_handshake_error(const char *err) "err=%s" +migration_tls_outgoing_handshake_complete(void) "" +migration_tls_incoming_handshake_start(void) "" +migration_tls_incoming_handshake_error(const char *err) "err=%s" +migration_tls_incoming_handshake_complete(void) "" + # kvm-all.c kvm_ioctl(int type, void *arg) "type 0x%x, arg %p" kvm_vm_ioctl(int type, void *arg) "type 0x%x, arg %p" |