aboutsummaryrefslogtreecommitdiff
path: root/migration/migration.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/migration.c
parent2c56d06bafd8933d2a9c6e0aeb5d45f7c1fb5616 (diff)
parent12992c16d9afd8a23a94a84ad532a1adedf9e511 (diff)
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/migration.c')
-rw-r--r--migration/migration.c157
1 files changed, 107 insertions, 50 deletions
diff --git a/migration/migration.c b/migration/migration.c
index f5327e8c0a..7ecbadee6f 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -34,6 +34,8 @@
#include "qom/cpu.h"
#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 */
@@ -81,16 +83,13 @@ MigrationState *migrate_get_current(void)
.bandwidth_limit = MAX_THROTTLE,
.xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE,
.mbps = -1,
- .parameters[MIGRATION_PARAMETER_COMPRESS_LEVEL] =
- DEFAULT_MIGRATE_COMPRESS_LEVEL,
- .parameters[MIGRATION_PARAMETER_COMPRESS_THREADS] =
- DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT,
- .parameters[MIGRATION_PARAMETER_DECOMPRESS_THREADS] =
- DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT,
- .parameters[MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL] =
- DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL,
- .parameters[MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT] =
- DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT,
+ .parameters = {
+ .compress_level = DEFAULT_MIGRATE_COMPRESS_LEVEL,
+ .compress_threads = DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT,
+ .decompress_threads = DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT,
+ .cpu_throttle_initial = DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL,
+ .cpu_throttle_increment = DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT,
+ },
};
if (!once) {
@@ -310,14 +309,12 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
} else if (strstart(uri, "rdma:", &p)) {
rdma_start_incoming_migration(p, errp);
#endif
-#if !defined(WIN32)
} else if (strstart(uri, "exec:", &p)) {
exec_start_incoming_migration(p, errp);
} else if (strstart(uri, "unix:", &p)) {
unix_start_incoming_migration(p, errp);
} else if (strstart(uri, "fd:", &p)) {
fd_start_incoming_migration(p, errp);
-#endif
} else {
error_setg(errp, "unknown migration protocol: %s", uri);
}
@@ -422,14 +419,60 @@ static void process_incoming_migration_co(void *opaque)
void process_incoming_migration(QEMUFile *f)
{
Coroutine *co = qemu_coroutine_create(process_incoming_migration_co);
- int fd = qemu_get_fd(f);
- assert(fd != -1);
migrate_decompress_threads_create();
- qemu_set_nonblock(fd);
+ qemu_file_set_blocking(f, false);
qemu_coroutine_enter(co, f);
}
+
+void migration_set_incoming_channel(MigrationState *s,
+ QIOChannel *ioc)
+{
+ trace_migration_set_incoming_channel(
+ ioc, object_get_typename(OBJECT(ioc)));
+
+ 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,
+ const char *hostname)
+{
+ trace_migration_set_outgoing_channel(
+ ioc, object_get_typename(OBJECT(ioc)), hostname);
+
+ 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);
+ }
+}
+
+
/*
* Send a message on the return channel back to the source
* of the migration.
@@ -516,15 +559,13 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
MigrationState *s = migrate_get_current();
params = g_malloc0(sizeof(*params));
- params->compress_level = s->parameters[MIGRATION_PARAMETER_COMPRESS_LEVEL];
- params->compress_threads =
- s->parameters[MIGRATION_PARAMETER_COMPRESS_THREADS];
- params->decompress_threads =
- s->parameters[MIGRATION_PARAMETER_DECOMPRESS_THREADS];
- params->cpu_throttle_initial =
- s->parameters[MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL];
- params->cpu_throttle_increment =
- s->parameters[MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT];
+ params->compress_level = s->parameters.compress_level;
+ params->compress_threads = s->parameters.compress_threads;
+ params->decompress_threads = s->parameters.decompress_threads;
+ params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
+ params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
+ params->tls_creds = g_strdup(s->parameters.tls_creds);
+ params->tls_hostname = g_strdup(s->parameters.tls_hostname);
return params;
}
@@ -672,6 +713,10 @@ MigrationInfo *qmp_query_migrate(Error **errp)
break;
case MIGRATION_STATUS_FAILED:
info->has_status = true;
+ if (s->error) {
+ info->has_error_desc = true;
+ info->error_desc = g_strdup(error_get_pretty(s->error));
+ }
break;
case MIGRATION_STATUS_CANCELLED:
info->has_status = true;
@@ -721,7 +766,12 @@ void qmp_migrate_set_parameters(bool has_compress_level,
bool has_cpu_throttle_initial,
int64_t cpu_throttle_initial,
bool has_cpu_throttle_increment,
- int64_t cpu_throttle_increment, Error **errp)
+ int64_t cpu_throttle_increment,
+ bool has_tls_creds,
+ const char *tls_creds,
+ bool has_tls_hostname,
+ const char *tls_hostname,
+ Error **errp)
{
MigrationState *s = migrate_get_current();
@@ -758,26 +808,31 @@ void qmp_migrate_set_parameters(bool has_compress_level,
}
if (has_compress_level) {
- s->parameters[MIGRATION_PARAMETER_COMPRESS_LEVEL] = compress_level;
+ s->parameters.compress_level = compress_level;
}
if (has_compress_threads) {
- s->parameters[MIGRATION_PARAMETER_COMPRESS_THREADS] = compress_threads;
+ s->parameters.compress_threads = compress_threads;
}
if (has_decompress_threads) {
- s->parameters[MIGRATION_PARAMETER_DECOMPRESS_THREADS] =
- decompress_threads;
+ s->parameters.decompress_threads = decompress_threads;
}
if (has_cpu_throttle_initial) {
- s->parameters[MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL] =
- cpu_throttle_initial;
+ s->parameters.cpu_throttle_initial = cpu_throttle_initial;
}
-
if (has_cpu_throttle_increment) {
- s->parameters[MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT] =
- cpu_throttle_increment;
+ s->parameters.cpu_throttle_increment = cpu_throttle_increment;
+ }
+ if (has_tls_creds) {
+ g_free(s->parameters.tls_creds);
+ s->parameters.tls_creds = g_strdup(tls_creds);
+ }
+ if (has_tls_hostname) {
+ g_free(s->parameters.tls_hostname);
+ s->parameters.tls_hostname = g_strdup(tls_hostname);
}
}
+
void qmp_migrate_start_postcopy(Error **errp)
{
MigrationState *s = migrate_get_current();
@@ -844,12 +899,15 @@ static void migrate_fd_cleanup(void *opaque)
notifier_list_notify(&migration_state_notifiers, s);
}
-void migrate_fd_error(MigrationState *s)
+void migrate_fd_error(MigrationState *s, const Error *error)
{
- trace_migrate_fd_error();
+ trace_migrate_fd_error(error ? error_get_pretty(error) : "");
assert(s->to_dst_file == NULL);
migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_FAILED);
+ if (!s->error) {
+ s->error = error_copy(error);
+ }
notifier_list_notify(&migration_state_notifiers, s);
}
@@ -948,6 +1006,8 @@ MigrationState *migrate_init(const MigrationParams *params)
s->postcopy_after_devices = false;
s->migration_thread_running = false;
s->last_req_rb = NULL;
+ error_free(s->error);
+ s->error = NULL;
migrate_set_state(&s->state, MIGRATION_STATUS_NONE, MIGRATION_STATUS_SETUP);
@@ -1040,14 +1100,12 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
} else if (strstart(uri, "rdma:", &p)) {
rdma_start_outgoing_migration(s, p, &local_err);
#endif
-#if !defined(WIN32)
} else if (strstart(uri, "exec:", &p)) {
exec_start_outgoing_migration(s, p, &local_err);
} else if (strstart(uri, "unix:", &p)) {
unix_start_outgoing_migration(s, p, &local_err);
} else if (strstart(uri, "fd:", &p)) {
fd_start_outgoing_migration(s, p, &local_err);
-#endif
} else {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "uri",
"a valid migration protocol");
@@ -1057,7 +1115,7 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
}
if (local_err) {
- migrate_fd_error(s);
+ migrate_fd_error(s, local_err);
error_propagate(errp, local_err);
return;
}
@@ -1170,7 +1228,7 @@ int migrate_compress_level(void)
s = migrate_get_current();
- return s->parameters[MIGRATION_PARAMETER_COMPRESS_LEVEL];
+ return s->parameters.compress_level;
}
int migrate_compress_threads(void)
@@ -1179,7 +1237,7 @@ int migrate_compress_threads(void)
s = migrate_get_current();
- return s->parameters[MIGRATION_PARAMETER_COMPRESS_THREADS];
+ return s->parameters.compress_threads;
}
int migrate_decompress_threads(void)
@@ -1188,7 +1246,7 @@ int migrate_decompress_threads(void)
s = migrate_get_current();
- return s->parameters[MIGRATION_PARAMETER_DECOMPRESS_THREADS];
+ return s->parameters.decompress_threads;
}
bool migrate_use_events(void)
@@ -1429,7 +1487,8 @@ static int await_return_path_close_on_source(MigrationState *ms)
static int postcopy_start(MigrationState *ms, bool *old_vm_running)
{
int ret;
- const QEMUSizedBuffer *qsb;
+ QIOChannelBuffer *bioc;
+ QEMUFile *fb;
int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
migrate_set_state(&ms->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_POSTCOPY_ACTIVE);
@@ -1488,11 +1547,9 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
* So we wrap the device state up in a package with a length at the start;
* to do this we use a qemu_buf to hold the whole of the device state.
*/
- QEMUFile *fb = qemu_bufopen("w", NULL);
- if (!fb) {
- error_report("Failed to create buffered file");
- goto fail;
- }
+ bioc = qio_channel_buffer_new(4096);
+ fb = qemu_fopen_channel_output(QIO_CHANNEL(bioc));
+ object_unref(OBJECT(bioc));
/*
* Make sure the receiver can get incoming pages before we send the rest
@@ -1506,10 +1563,9 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
qemu_savevm_send_postcopy_run(fb);
/* <><> end of stuff going into the package */
- qsb = qemu_buf_get(fb);
/* Now send that blob */
- if (qemu_savevm_send_packaged(ms->to_dst_file, qsb)) {
+ if (qemu_savevm_send_packaged(ms->to_dst_file, bioc->data, bioc->usage)) {
goto fail_closefb;
}
qemu_fclose(fb);
@@ -1793,6 +1849,7 @@ void migrate_fd_connect(MigrationState *s)
s->expected_downtime = max_downtime/1000000;
s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
+ qemu_file_set_blocking(s->to_dst_file, true);
qemu_file_set_rate_limit(s->to_dst_file,
s->bandwidth_limit / XFER_LIMIT_RATIO);