qemu-devel
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]