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#include "qemu/cutils.h"
  19
  20#include "qemu/error-report.h"
  21#include "qapi/error.h"
  22#include "channel.h"
  23#include "socket.h"
  24#include "migration.h"
  25#include "qemu-file.h"
  26#include "io/channel-socket.h"
  27#include "io/net-listener.h"
  28#include "trace.h"
  29
  30
  31struct SocketOutgoingArgs {
  32    SocketAddress *saddr;
  33} outgoing_args;
  34
  35void socket_send_channel_create(QIOTaskFunc f, void *data)
  36{
  37    QIOChannelSocket *sioc = qio_channel_socket_new();
  38    qio_channel_socket_connect_async(sioc, outgoing_args.saddr,
  39                                     f, data, NULL, NULL);
  40}
  41
  42int socket_send_channel_destroy(QIOChannel *send)
  43{
  44    /* Remove channel */
  45    object_unref(OBJECT(send));
  46    if (outgoing_args.saddr) {
  47        qapi_free_SocketAddress(outgoing_args.saddr);
  48        outgoing_args.saddr = NULL;
  49    }
  50    return 0;
  51}
  52
  53struct SocketConnectData {
  54    MigrationState *s;
  55    char *hostname;
  56};
  57
  58static void socket_connect_data_free(void *opaque)
  59{
  60    struct SocketConnectData *data = opaque;
  61    if (!data) {
  62        return;
  63    }
  64    g_free(data->hostname);
  65    g_free(data);
  66}
  67
  68static void socket_outgoing_migration(QIOTask *task,
  69                                      gpointer opaque)
  70{
  71    struct SocketConnectData *data = opaque;
  72    QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task));
  73    Error *err = NULL;
  74
  75    if (qio_task_propagate_error(task, &err)) {
  76        trace_migration_socket_outgoing_error(error_get_pretty(err));
  77    } else {
  78        trace_migration_socket_outgoing_connected(data->hostname);
  79    }
  80    migration_channel_connect(data->s, sioc, data->hostname, err);
  81    object_unref(OBJECT(sioc));
  82}
  83
  84static void
  85socket_start_outgoing_migration_internal(MigrationState *s,
  86                                         SocketAddress *saddr,
  87                                         Error **errp)
  88{
  89    QIOChannelSocket *sioc = qio_channel_socket_new();
  90    struct SocketConnectData *data = g_new0(struct SocketConnectData, 1);
  91
  92    data->s = s;
  93
  94    /* in case previous migration leaked it */
  95    qapi_free_SocketAddress(outgoing_args.saddr);
  96    outgoing_args.saddr = saddr;
  97
  98    if (saddr->type == SOCKET_ADDRESS_TYPE_INET) {
  99        data->hostname = g_strdup(saddr->u.inet.host);
 100    }
 101
 102    qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-outgoing");
 103    qio_channel_socket_connect_async(sioc,
 104                                     saddr,
 105                                     socket_outgoing_migration,
 106                                     data,
 107                                     socket_connect_data_free,
 108                                     NULL);
 109}
 110
 111void socket_start_outgoing_migration(MigrationState *s,
 112                                     const char *str,
 113                                     Error **errp)
 114{
 115    Error *err = NULL;
 116    SocketAddress *saddr = socket_parse(str, &err);
 117    if (!err) {
 118        socket_start_outgoing_migration_internal(s, saddr, &err);
 119    }
 120    error_propagate(errp, err);
 121}
 122
 123static void socket_accept_incoming_migration(QIONetListener *listener,
 124                                             QIOChannelSocket *cioc,
 125                                             gpointer opaque)
 126{
 127    trace_migration_socket_incoming_accepted();
 128
 129    qio_channel_set_name(QIO_CHANNEL(cioc), "migration-socket-incoming");
 130    migration_channel_process_incoming(QIO_CHANNEL(cioc));
 131
 132    if (migration_has_all_channels()) {
 133        /* Close listening socket as its no longer needed */
 134        qio_net_listener_disconnect(listener);
 135        object_unref(OBJECT(listener));
 136    }
 137}
 138
 139
 140static void
 141socket_start_incoming_migration_internal(SocketAddress *saddr,
 142                                         Error **errp)
 143{
 144    QIONetListener *listener = qio_net_listener_new();
 145    size_t i;
 146    int num = 1;
 147
 148    qio_net_listener_set_name(listener, "migration-socket-listener");
 149
 150    if (migrate_use_multifd()) {
 151        num = migrate_multifd_channels();
 152    }
 153
 154    if (qio_net_listener_open_sync(listener, saddr, num, errp) < 0) {
 155        object_unref(OBJECT(listener));
 156        return;
 157    }
 158
 159    qio_net_listener_set_client_func_full(listener,
 160                                          socket_accept_incoming_migration,
 161                                          NULL, NULL,
 162                                          g_main_context_get_thread_default());
 163
 164    for (i = 0; i < listener->nsioc; i++)  {
 165        SocketAddress *address =
 166            qio_channel_socket_get_local_address(listener->sioc[i], errp);
 167        if (!address) {
 168            return;
 169        }
 170        migrate_add_address(address);
 171        qapi_free_SocketAddress(address);
 172    }
 173}
 174
 175void socket_start_incoming_migration(const char *str, Error **errp)
 176{
 177    Error *err = NULL;
 178    SocketAddress *saddr = socket_parse(str, &err);
 179    if (!err) {
 180        socket_start_incoming_migration_internal(saddr, &err);
 181    }
 182    qapi_free_SocketAddress(saddr);
 183    error_propagate(errp, err);
 184}
 185