qemu/migration/socket.c
<<
>>
Prefs
   1/*
   2 * QEMU live migration via socket
   3 *
   4 * Copyright Red Hat, Inc. 2009-2016
   5 *
   6 * Authors:
   7 *  Chris Lalancette <clalance@redhat.com>
   8 *  Daniel P. Berrange <berrange@redhat.com>
   9 *
  10 * This work is licensed under the terms of the GNU GPL, version 2.  See
  11 * the COPYING file in the top-level directory.
  12 *
  13 * Contributions after 2012-01-13 are licensed under the terms of the
  14 * GNU GPL, version 2 or (at your option) any later version.
  15 */
  16
  17#include "qemu/osdep.h"
  18
  19#include "qemu-common.h"
  20#include "qemu/error-report.h"
  21#include "qapi/error.h"
  22#include "migration/migration.h"
  23#include "migration/qemu-file.h"
  24#include "io/channel-socket.h"
  25#include "trace.h"
  26
  27
  28static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
  29{
  30    InetSocketAddress *iaddr = inet_parse(host_port, errp);
  31    SocketAddress *saddr;
  32
  33    if (!iaddr) {
  34        return NULL;
  35    }
  36
  37    saddr = g_new0(SocketAddress, 1);
  38    saddr->type = SOCKET_ADDRESS_KIND_INET;
  39    saddr->u.inet.data = iaddr;
  40
  41    return saddr;
  42}
  43
  44
  45static SocketAddress *unix_build_address(const char *path)
  46{
  47    SocketAddress *saddr;
  48
  49    saddr = g_new0(SocketAddress, 1);
  50    saddr->type = SOCKET_ADDRESS_KIND_UNIX;
  51    saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
  52    saddr->u.q_unix.data->path = g_strdup(path);
  53
  54    return saddr;
  55}
  56
  57
  58struct SocketConnectData {
  59    MigrationState *s;
  60    char *hostname;
  61};
  62
  63static void socket_connect_data_free(void *opaque)
  64{
  65    struct SocketConnectData *data = opaque;
  66    if (!data) {
  67        return;
  68    }
  69    g_free(data->hostname);
  70    g_free(data);
  71}
  72
  73static void socket_outgoing_migration(Object *src,
  74                                      Error *err,
  75                                      gpointer opaque)
  76{
  77    struct SocketConnectData *data = opaque;
  78    QIOChannel *sioc = QIO_CHANNEL(src);
  79
  80    if (err) {
  81        trace_migration_socket_outgoing_error(error_get_pretty(err));
  82        data->s->to_dst_file = NULL;
  83        migrate_fd_error(data->s, err);
  84    } else {
  85        trace_migration_socket_outgoing_connected(data->hostname);
  86        migration_channel_connect(data->s, sioc, data->hostname);
  87    }
  88    object_unref(src);
  89}
  90
  91static void socket_start_outgoing_migration(MigrationState *s,
  92                                            SocketAddress *saddr,
  93                                            Error **errp)
  94{
  95    QIOChannelSocket *sioc = qio_channel_socket_new();
  96    struct SocketConnectData *data = g_new0(struct SocketConnectData, 1);
  97
  98    data->s = s;
  99    if (saddr->type == SOCKET_ADDRESS_KIND_INET) {
 100        data->hostname = g_strdup(saddr->u.inet.data->host);
 101    }
 102
 103    qio_channel_socket_connect_async(sioc,
 104                                     saddr,
 105                                     socket_outgoing_migration,
 106                                     data,
 107                                     socket_connect_data_free);
 108    qapi_free_SocketAddress(saddr);
 109}
 110
 111void tcp_start_outgoing_migration(MigrationState *s,
 112                                  const char *host_port,
 113                                  Error **errp)
 114{
 115    SocketAddress *saddr = tcp_build_address(host_port, errp);
 116    socket_start_outgoing_migration(s, saddr, errp);
 117}
 118
 119void unix_start_outgoing_migration(MigrationState *s,
 120                                   const char *path,
 121                                   Error **errp)
 122{
 123    SocketAddress *saddr = unix_build_address(path);
 124    socket_start_outgoing_migration(s, saddr, errp);
 125}
 126
 127
 128static gboolean socket_accept_incoming_migration(QIOChannel *ioc,
 129                                                 GIOCondition condition,
 130                                                 gpointer opaque)
 131{
 132    QIOChannelSocket *sioc;
 133    Error *err = NULL;
 134
 135    sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
 136                                     &err);
 137    if (!sioc) {
 138        error_report("could not accept migration connection (%s)",
 139                     error_get_pretty(err));
 140        goto out;
 141    }
 142
 143    trace_migration_socket_incoming_accepted();
 144
 145    migration_channel_process_incoming(migrate_get_current(),
 146                                       QIO_CHANNEL(sioc));
 147    object_unref(OBJECT(sioc));
 148
 149out:
 150    /* Close listening socket as its no longer needed */
 151    qio_channel_close(ioc, NULL);
 152    return FALSE; /* unregister */
 153}
 154
 155
 156static void socket_start_incoming_migration(SocketAddress *saddr,
 157                                            Error **errp)
 158{
 159    QIOChannelSocket *listen_ioc = qio_channel_socket_new();
 160
 161    if (qio_channel_socket_listen_sync(listen_ioc, saddr, errp) < 0) {
 162        object_unref(OBJECT(listen_ioc));
 163        qapi_free_SocketAddress(saddr);
 164        return;
 165    }
 166
 167    qio_channel_add_watch(QIO_CHANNEL(listen_ioc),
 168                          G_IO_IN,
 169                          socket_accept_incoming_migration,
 170                          listen_ioc,
 171                          (GDestroyNotify)object_unref);
 172    qapi_free_SocketAddress(saddr);
 173}
 174
 175void tcp_start_incoming_migration(const char *host_port, Error **errp)
 176{
 177    SocketAddress *saddr = tcp_build_address(host_port, errp);
 178    socket_start_incoming_migration(saddr, errp);
 179}
 180
 181void unix_start_incoming_migration(const char *path, Error **errp)
 182{
 183    SocketAddress *saddr = unix_build_address(path);
 184    socket_start_incoming_migration(saddr, errp);
 185}
 186