Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/amit-migration/tags/migration-2…
Browse files Browse the repository at this point in the history
….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>
  • Loading branch information
pm215 committed May 26, 2016
2 parents 2c56d06 + 12992c1 commit aef11b8
Show file tree
Hide file tree
Showing 32 changed files with 1,281 additions and 1,675 deletions.
4 changes: 2 additions & 2 deletions docs/migration.txt
Expand Up @@ -403,8 +403,8 @@ listen thread: --- page -- page -- page -- page -- page --

On receipt of CMD_PACKAGED (1)
All the data associated with the package - the ( ... ) section in the
diagram - is read into memory (into a QEMUSizedBuffer), and the main thread
recurses into qemu_loadvm_state_main to process the contents of the package (2)
diagram - is read into memory, and the main thread recurses into
qemu_loadvm_state_main to process the contents of the package (2)
which contains commands (3,6) and devices (4...)

On receipt of 'postcopy listen' - 3 -(i.e. the 1st command in the package)
Expand Down
2 changes: 1 addition & 1 deletion hmp-commands.hx
Expand Up @@ -1008,7 +1008,7 @@ ETEXI

{
.name = "migrate_set_parameter",
.args_type = "parameter:s,value:i",
.args_type = "parameter:s,value:s",
.params = "parameter value",
.help = "Set the parameter for migration",
.mhandler.cmd = hmp_migrate_set_parameter,
Expand Down
57 changes: 50 additions & 7 deletions hmp.c
Expand Up @@ -35,6 +35,7 @@
#include "block/qapi.h"
#include "qemu-io.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"

#ifdef CONFIG_SPICE
#include <spice/enums.h>
Expand Down Expand Up @@ -168,8 +169,15 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
}

if (info->has_status) {
monitor_printf(mon, "Migration status: %s\n",
monitor_printf(mon, "Migration status: %s",
MigrationStatus_lookup[info->status]);
if (info->status == MIGRATION_STATUS_FAILED &&
info->has_error_desc) {
monitor_printf(mon, " (%s)\n", info->error_desc);
} else {
monitor_printf(mon, "\n");
}

monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
info->total_time);
if (info->has_expected_downtime) {
Expand Down Expand Up @@ -286,6 +294,12 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
monitor_printf(mon, " %s: %" PRId64,
MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT],
params->cpu_throttle_increment);
monitor_printf(mon, " %s: '%s'",
MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_CREDS],
params->tls_creds ? : "");
monitor_printf(mon, " %s: '%s'",
MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_HOSTNAME],
params->tls_hostname ? : "");
monitor_printf(mon, "\n");
}

Expand Down Expand Up @@ -1235,39 +1249,64 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
{
const char *param = qdict_get_str(qdict, "parameter");
int value = qdict_get_int(qdict, "value");
const char *valuestr = qdict_get_str(qdict, "value");
long valueint = 0;
Error *err = NULL;
bool has_compress_level = false;
bool has_compress_threads = false;
bool has_decompress_threads = false;
bool has_cpu_throttle_initial = false;
bool has_cpu_throttle_increment = false;
bool has_tls_creds = false;
bool has_tls_hostname = false;
bool use_int_value = false;
int i;

for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
if (strcmp(param, MigrationParameter_lookup[i]) == 0) {
switch (i) {
case MIGRATION_PARAMETER_COMPRESS_LEVEL:
has_compress_level = true;
use_int_value = true;
break;
case MIGRATION_PARAMETER_COMPRESS_THREADS:
has_compress_threads = true;
use_int_value = true;
break;
case MIGRATION_PARAMETER_DECOMPRESS_THREADS:
has_decompress_threads = true;
use_int_value = true;
break;
case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL:
has_cpu_throttle_initial = true;
use_int_value = true;
break;
case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT:
has_cpu_throttle_increment = true;
break;
case MIGRATION_PARAMETER_TLS_CREDS:
has_tls_creds = true;
break;
case MIGRATION_PARAMETER_TLS_HOSTNAME:
has_tls_hostname = true;
break;
}
qmp_migrate_set_parameters(has_compress_level, value,
has_compress_threads, value,
has_decompress_threads, value,
has_cpu_throttle_initial, value,
has_cpu_throttle_increment, value,

if (use_int_value) {
if (qemu_strtol(valuestr, NULL, 10, &valueint) < 0) {
error_setg(&err, "Unable to parse '%s' as an int",
valuestr);
goto cleanup;
}
}

qmp_migrate_set_parameters(has_compress_level, valueint,
has_compress_threads, valueint,
has_decompress_threads, valueint,
has_cpu_throttle_initial, valueint,
has_cpu_throttle_increment, valueint,
has_tls_creds, valuestr,
has_tls_hostname, valuestr,
&err);
break;
}
Expand All @@ -1277,6 +1316,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
error_setg(&err, QERR_INVALID_PARAMETER, param);
}

cleanup:
if (err) {
error_report_err(err);
}
Expand Down Expand Up @@ -1533,6 +1573,9 @@ static void hmp_migrate_status_cb(void *opaque)
if (status->is_block_migration) {
monitor_printf(status->mon, "\n");
}
if (info->has_error_desc) {
error_report("%s", info->error_desc);
}
monitor_resume(status->mon);
timer_del(status->timer);
g_free(status);
Expand Down
26 changes: 14 additions & 12 deletions hw/s390x/s390-skeys.c
Expand Up @@ -47,15 +47,11 @@ void s390_skeys_init(void)
qdev_init_nofail(DEVICE(obj));
}

static void write_keys(QEMUFile *f, uint8_t *keys, uint64_t startgfn,
static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn,
uint64_t count, Error **errp)
{
uint64_t curpage = startgfn;
uint64_t maxpage = curpage + count - 1;
const char *fmt = "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d,"
" ch=%d, reserved=%d\n";
char buf[128];
int len;

for (; curpage <= maxpage; curpage++) {
uint8_t acc = (*keys & 0xF0) >> 4;
Expand All @@ -64,10 +60,9 @@ static void write_keys(QEMUFile *f, uint8_t *keys, uint64_t startgfn,
int ch = (*keys & 0x02);
int res = (*keys & 0x01);

len = snprintf(buf, sizeof(buf), fmt, curpage,
*keys, acc, fp, ref, ch, res);
assert(len < sizeof(buf));
qemu_put_buffer(f, (uint8_t *)buf, len);
fprintf(f, "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d,"
" ch=%d, reserved=%d\n",
curpage, *keys, acc, fp, ref, ch, res);
keys++;
}
}
Expand Down Expand Up @@ -116,7 +111,8 @@ void qmp_dump_skeys(const char *filename, Error **errp)
vaddr cur_gfn = 0;
uint8_t *buf;
int ret;
QEMUFile *f;
int fd;
FILE *f;

/* Quick check to see if guest is using storage keys*/
if (!skeyclass->skeys_enabled(ss)) {
Expand All @@ -125,8 +121,14 @@ void qmp_dump_skeys(const char *filename, Error **errp)
return;
}

f = qemu_fopen(filename, "wb");
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) {
error_setg_file_open(errp, errno, filename);
return;
}
f = fdopen(fd, "wb");
if (!f) {
close(fd);
error_setg_file_open(errp, errno, filename);
return;
}
Expand Down Expand Up @@ -162,7 +164,7 @@ void qmp_dump_skeys(const char *filename, Error **errp)
error_propagate(errp, lerr);
g_free(buf);
out:
qemu_fclose(f);
fclose(f);
}

static void qemu_s390_skeys_init(Object *obj)
Expand Down
26 changes: 24 additions & 2 deletions include/migration/migration.h
Expand Up @@ -135,9 +135,12 @@ struct MigrationState
QemuThread thread;
QEMUBH *cleanup_bh;
QEMUFile *to_dst_file;
int parameters[MIGRATION_PARAMETER__MAX];

/* New style params from 'migrate-set-parameters' */
MigrationParameters parameters;

int state;
/* Old style params from 'migrate' command */
MigrationParams params;

/* State related to return path */
Expand Down Expand Up @@ -171,6 +174,9 @@ struct MigrationState
QSIMPLEQ_HEAD(src_page_requests, MigrationSrcPageRequest) src_page_requests;
/* The RAMBlock used in the last src_page_request */
RAMBlock *last_req_rb;

/* The last error that occurred */
Error *error;
};

void migrate_set_state(int *state, int old_state, int new_state);
Expand All @@ -179,6 +185,22 @@ void process_incoming_migration(QEMUFile *f);

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,
const char *hostname);

void migration_tls_set_outgoing_channel(MigrationState *s,
QIOChannel *ioc,
const char *hostname,
Error **errp);

uint64_t migrate_max_downtime(void);

void exec_start_incoming_migration(const char *host_port, Error **errp);
Expand All @@ -201,7 +223,7 @@ void rdma_start_outgoing_migration(void *opaque, const char *host_port, Error **

void rdma_start_incoming_migration(const char *host_port, Error **errp);

void migrate_fd_error(MigrationState *s);
void migrate_fd_error(MigrationState *s, const Error *error);

void migrate_fd_connect(MigrationState *s);

Expand Down
57 changes: 18 additions & 39 deletions include/migration/qemu-file.h
Expand Up @@ -23,16 +23,11 @@
*/
#ifndef QEMU_FILE_H
#define QEMU_FILE_H 1
#include "qemu-common.h"
#include "exec/cpu-common.h"
#include "io/channel.h"


/* This function writes a chunk of data to a file at the given position.
* The pos argument can be ignored if the file is only being used for
* streaming. The handler should try to write all of the data it can.
*/
typedef ssize_t (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
int64_t pos, size_t size);

/* Read a chunk of data from a file at the given position. The pos argument
* can be ignored if the file is only be used for streaming. The number of
* bytes actually read should be returned.
Expand All @@ -53,8 +48,13 @@ typedef int (QEMUFileCloseFunc)(void *opaque);
*/
typedef int (QEMUFileGetFD)(void *opaque);

/* Called to change the blocking mode of the file
*/
typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);

/*
* This function writes an iovec to file.
* This function writes an iovec to file. The handler must write all
* of the data or return a negative errno value.
*/
typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
int iovcnt, int64_t pos);
Expand Down Expand Up @@ -101,32 +101,25 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);

typedef struct QEMUFileOps {
QEMUFilePutBufferFunc *put_buffer;
QEMUFileGetBufferFunc *get_buffer;
QEMUFileCloseFunc *close;
QEMUFileGetFD *get_fd;
QEMUFileSetBlocking *set_blocking;
QEMUFileWritevBufferFunc *writev_buffer;
QEMURamHookFunc *before_ram_iterate;
QEMURamHookFunc *after_ram_iterate;
QEMURamHookFunc *hook_ram_load;
QEMURamSaveFunc *save_page;
QEMURetPathFunc *get_return_path;
QEMUFileShutdownFunc *shut_down;
} QEMUFileOps;

struct QEMUSizedBuffer {
struct iovec *iov;
size_t n_iov;
size_t size; /* total allocated size in all iov's */
size_t used; /* number of used bytes */
};
typedef struct QEMUFileHooks {
QEMURamHookFunc *before_ram_iterate;
QEMURamHookFunc *after_ram_iterate;
QEMURamHookFunc *hook_ram_load;
QEMURamSaveFunc *save_page;
} QEMUFileHooks;

QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
QEMUFile *qemu_fopen(const char *filename, const char *mode);
QEMUFile *qemu_fdopen(int fd, const char *mode);
QEMUFile *qemu_fopen_socket(int fd, const char *mode);
QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input);
QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc);
QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc);
void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks);
int qemu_get_fd(QEMUFile *f);
int qemu_fclose(QEMUFile *f);
int64_t qemu_ftell(QEMUFile *f);
Expand All @@ -141,20 +134,6 @@ void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size);
bool qemu_file_mode_is_not_valid(const char *mode);
bool qemu_file_is_writable(QEMUFile *f);

QEMUSizedBuffer *qsb_create(const uint8_t *buffer, size_t len);
void qsb_free(QEMUSizedBuffer *);
size_t qsb_set_length(QEMUSizedBuffer *qsb, size_t length);
size_t qsb_get_length(const QEMUSizedBuffer *qsb);
ssize_t qsb_get_buffer(const QEMUSizedBuffer *, off_t start, size_t count,
uint8_t *buf);
ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *buf,
off_t pos, size_t count);


/*
* For use on files opened with qemu_bufopen
*/
const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f);

static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
{
Expand Down
2 changes: 1 addition & 1 deletion include/qapi/error.h
Expand Up @@ -134,7 +134,7 @@ typedef enum ErrorClass {
/*
* Get @err's human-readable error message.
*/
const char *error_get_pretty(Error *err);
const char *error_get_pretty(const Error *err);

/*
* Get @err's error class.
Expand Down
1 change: 0 additions & 1 deletion include/qemu/typedefs.h
Expand Up @@ -82,7 +82,6 @@ typedef struct QemuOpt QemuOpt;
typedef struct QemuOpts QemuOpts;
typedef struct QemuOptsList QemuOptsList;
typedef struct QEMUSGList QEMUSGList;
typedef struct QEMUSizedBuffer QEMUSizedBuffer;
typedef struct QEMUTimer QEMUTimer;
typedef struct QEMUTimerListGroup QEMUTimerListGroup;
typedef struct QObject QObject;
Expand Down
2 changes: 1 addition & 1 deletion include/sysemu/sysemu.h
Expand Up @@ -119,7 +119,7 @@ void qemu_savevm_command_send(QEMUFile *f, enum qemu_vm_cmd command,
uint16_t len, uint8_t *data);
void qemu_savevm_send_ping(QEMUFile *f, uint32_t value);
void qemu_savevm_send_open_return_path(QEMUFile *f);
int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb);
int qemu_savevm_send_packaged(QEMUFile *f, const uint8_t *buf, size_t len);
void qemu_savevm_send_postcopy_advise(QEMUFile *f);
void qemu_savevm_send_postcopy_listen(QEMUFile *f);
void qemu_savevm_send_postcopy_run(QEMUFile *f);
Expand Down

0 comments on commit aef11b8

Please sign in to comment.