[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH] Migration via unix sockets.
From: |
Chris Lalancette |
Subject: |
Re: [Qemu-devel] [PATCH] Migration via unix sockets. |
Date: |
Mon, 10 Aug 2009 12:23:59 +0200 |
User-agent: |
Thunderbird 2.0.0.21 (X11/20090320) |
Chris Lalancette wrote:
> Implement migration via unix sockets. While you can fake this using
> exec and netcat, this involves forking another process and is
> generally not very nice. By doing this directly in qemu, we can avoid
> the copy through the external nc command. This is useful for
> implementations (such as libvirt) that want to do "secure" migration;
> we pipe the data on the sending side into the unix socket, libvirt
> picks it up, encrypts it, and transports it, and then on the remote
> side libvirt decrypts it, dumps it to another unix socket, and
> feeds it into qemu.
>
> The implementation is straightforward and looks very similar to
> migration-exec.c and migration-tcp.c
ping?
>
> Signed-off-by: Chris Lalancette <address@hidden>
> ---
> Makefile | 2 +-
> migration-unix.c | 216
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> migration.c | 4 +
> migration.h | 6 ++
> 4 files changed, 227 insertions(+), 1 deletions(-)
> create mode 100644 migration-unix.c
>
> diff --git a/Makefile b/Makefile
> index d3f999e..c5763b7 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -110,7 +110,7 @@ obj-$(CONFIG_BRLAPI) += baum.o
> LIBS+=$(BRLAPI_LIBS)
>
> obj-$(CONFIG_WIN32) += tap-win32.o
> -obj-$(CONFIG_POSIX) += migration-exec.o
> +obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o
>
> ifdef CONFIG_COREAUDIO
> AUDIO_PT = y
> diff --git a/migration-unix.c b/migration-unix.c
> new file mode 100644
> index 0000000..a26587a
> --- /dev/null
> +++ b/migration-unix.c
> @@ -0,0 +1,216 @@
> +/*
> + * QEMU live migration via Unix Domain Sockets
> + *
> + * Copyright Red Hat, Inc. 2009
> + *
> + * Authors:
> + * Chris Lalancette <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "qemu-common.h"
> +#include "qemu_socket.h"
> +#include "migration.h"
> +#include "qemu-char.h"
> +#include "sysemu.h"
> +#include "buffered_file.h"
> +#include "block.h"
> +
> +//#define DEBUG_MIGRATION_UNIX
> +
> +#ifdef DEBUG_MIGRATION_UNIX
> +#define dprintf(fmt, ...) \
> + do { printf("migration-unix: " fmt, ## __VA_ARGS__); } while (0)
> +#else
> +#define dprintf(fmt, ...) \
> + do { } while (0)
> +#endif
> +
> +static int unix_errno(FdMigrationState *s)
> +{
> + return errno;
> +}
> +
> +static int unix_write(FdMigrationState *s, const void * buf, size_t size)
> +{
> + return write(s->fd, buf, size);
> +}
> +
> +static int unix_close(FdMigrationState *s)
> +{
> + dprintf("unix_close\n");
> + if (s->fd != -1) {
> + close(s->fd);
> + s->fd = -1;
> + }
> + return 0;
> +}
> +
> +static void unix_wait_for_connect(void *opaque)
> +{
> + FdMigrationState *s = opaque;
> + int val, ret;
> + socklen_t valsize = sizeof(val);
> +
> + dprintf("connect completed\n");
> + do {
> + ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val,
> &valsize);
> + } while (ret == -1 && (s->get_error(s)) == EINTR);
> +
> + if (ret < 0) {
> + migrate_fd_error(s);
> + return;
> + }
> +
> + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
> +
> + if (val == 0)
> + migrate_fd_connect(s);
> + else {
> + dprintf("error connecting %d\n", val);
> + migrate_fd_error(s);
> + }
> +}
> +
> +MigrationState *unix_start_outgoing_migration(const char *path,
> + int64_t bandwidth_limit,
> + int detach)
> +{
> + FdMigrationState *s;
> + struct sockaddr_un addr;
> + int ret;
> +
> + addr.sun_family = AF_UNIX;
> + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
> +
> + s = qemu_mallocz(sizeof(*s));
> +
> + s->get_error = unix_errno;
> + s->write = unix_write;
> + s->close = unix_close;
> + s->mig_state.cancel = migrate_fd_cancel;
> + s->mig_state.get_status = migrate_fd_get_status;
> + s->mig_state.release = migrate_fd_release;
> +
> + s->state = MIG_STATE_ACTIVE;
> + s->mon_resume = NULL;
> + s->bandwidth_limit = bandwidth_limit;
> + s->fd = socket(PF_UNIX, SOCK_STREAM, 0);
> + if (s->fd < 0) {
> + dprintf("Unable to open socket");
> + goto err_after_alloc;
> + }
> +
> + socket_set_nonblock(s->fd);
> +
> + if (!detach)
> + migrate_fd_monitor_suspend(s);
> +
> + do {
> + ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
> + if (ret == -1)
> + ret = -(s->get_error(s));
> +
> + if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
> + qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s);
> + } while (ret == -EINTR);
> +
> + if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
> + dprintf("connect failed\n");
> + goto err_after_open;
> + } else if (ret >= 0)
> + migrate_fd_connect(s);
> +
> + return &s->mig_state;
> +
> +err_after_open:
> + close(s->fd);
> +
> +err_after_alloc:
> + qemu_free(s);
> + return NULL;
> +}
> +
> +static void unix_accept_incoming_migration(void *opaque)
> +{
> + struct sockaddr_un addr;
> + socklen_t addrlen = sizeof(addr);
> + int s = (unsigned long)opaque;
> + QEMUFile *f;
> + int c, ret;
> +
> + do {
> + c = accept(s, (struct sockaddr *)&addr, &addrlen);
> + } while (c == -1 && socket_error() == EINTR);
> +
> + dprintf("accepted migration\n");
> +
> + if (c == -1) {
> + fprintf(stderr, "could not accept migration connection\n");
> + return;
> + }
> +
> + f = qemu_fopen_socket(c);
> + if (f == NULL) {
> + fprintf(stderr, "could not qemu_fopen socket\n");
> + goto out;
> + }
> +
> + ret = qemu_loadvm_state(f);
> + if (ret < 0) {
> + fprintf(stderr, "load of migration failed\n");
> + goto out_fopen;
> + }
> + qemu_announce_self();
> + dprintf("successfully loaded vm state\n");
> +
> + /* we've successfully migrated, close the server socket */
> + qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
> + close(s);
> +
> +out_fopen:
> + qemu_fclose(f);
> +out:
> + close(c);
> +}
> +
> +int unix_start_incoming_migration(const char *path)
> +{
> + struct sockaddr_un un;
> + int sock;
> +
> + dprintf("Attempting to start an incoming migration\n");
> +
> + sock = socket(PF_UNIX, SOCK_STREAM, 0);
> + if (sock < 0) {
> + fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno));
> + return -EINVAL;
> + }
> +
> + memset(&un, 0, sizeof(un));
> + un.sun_family = AF_UNIX;
> + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
> +
> + unlink(un.sun_path);
> + if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
> + fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
> + goto err;
> + }
> + if (listen(sock, 1) < 0) {
> + fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path,
> strerror(errno));
> + goto err;
> + }
> +
> + qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL,
> + (void *)(unsigned long)sock);
> +
> + return 0;
> +
> +err:
> + close(sock);
> +
> + return -EINVAL;
> +}
> diff --git a/migration.c b/migration.c
> index ee64d41..34e2bc1 100644
> --- a/migration.c
> +++ b/migration.c
> @@ -43,6 +43,8 @@ void qemu_start_incoming_migration(const char *uri)
> #if !defined(WIN32)
> else if (strstart(uri, "exec:", &p))
> exec_start_incoming_migration(p);
> + else if (strstart(uri, "unix:", &p))
> + unix_start_incoming_migration(p);
> #endif
> else
> fprintf(stderr, "unknown migration protocol: %s\n", uri);
> @@ -58,6 +60,8 @@ void do_migrate(Monitor *mon, int detach, const char *uri)
> #if !defined(WIN32)
> else if (strstart(uri, "exec:", &p))
> s = exec_start_outgoing_migration(p, max_throttle, detach);
> + else if (strstart(uri, "unix:", &p))
> + s = unix_start_outgoing_migration(p, max_throttle, detach);
> #endif
> else
> monitor_printf(mon, "unknown migration protocol: %s\n", uri);
> diff --git a/migration.h b/migration.h
> index 37c7f8e..0ed1fcb 100644
> --- a/migration.h
> +++ b/migration.h
> @@ -73,6 +73,12 @@ MigrationState *tcp_start_outgoing_migration(const char
> *host_port,
> int64_t bandwidth_limit,
> int detach);
>
> +int unix_start_incoming_migration(const char *path);
> +
> +MigrationState *unix_start_outgoing_migration(const char *path,
> + int64_t bandwidth_limit,
> + int detach);
> +
> void migrate_fd_monitor_suspend(FdMigrationState *s);
>
> void migrate_fd_error(FdMigrationState *s);
--
Chris Lalancette
- [Qemu-devel] [PATCH] Migration via unix sockets., Chris Lalancette, 2009/08/05
- Re: [Qemu-devel] [PATCH] Migration via unix sockets.,
Chris Lalancette <=
- Re: [Qemu-devel] [PATCH] Migration via unix sockets., Avi Kivity, 2009/08/10
- Re: [Qemu-devel] [PATCH] Migration via unix sockets., Chris Lalancette, 2009/08/11
- Re: [Qemu-devel] [PATCH] Migration via unix sockets., Avi Kivity, 2009/08/11
- [Qemu-devel] Re: [PATCH] Migration via unix sockets., Paolo Bonzini, 2009/08/11
- [Qemu-devel] Re: [PATCH] Migration via unix sockets., Avi Kivity, 2009/08/11
- [Qemu-devel] [PATCH] add file descriptor migration, Paolo Bonzini, 2009/08/12
- [Qemu-devel] [PATCH v2] add file descriptor migration, Paolo Bonzini, 2009/08/18
- [Qemu-devel] Re: [PATCH v2] add file descriptor migration, Chris Lalancette, 2009/08/18
- Re: [Qemu-devel] [PATCH] Migration via unix sockets., Daniel P. Berrange, 2009/08/11