16f860ae7SDaniel P. Berrange /*
2474c624dSCao jin * QEMU live migration via socket
36f860ae7SDaniel P. Berrange *
46f860ae7SDaniel P. Berrange * Copyright Red Hat, Inc. 2009-2016
56f860ae7SDaniel P. Berrange *
66f860ae7SDaniel P. Berrange * Authors:
76f860ae7SDaniel P. Berrange * Chris Lalancette <clalance@redhat.com>
86f860ae7SDaniel P. Berrange * Daniel P. Berrange <berrange@redhat.com>
96f860ae7SDaniel P. Berrange *
106f860ae7SDaniel P. Berrange * This work is licensed under the terms of the GNU GPL, version 2. See
116f860ae7SDaniel P. Berrange * the COPYING file in the top-level directory.
126f860ae7SDaniel P. Berrange *
136f860ae7SDaniel P. Berrange * Contributions after 2012-01-13 are licensed under the terms of the
146f860ae7SDaniel P. Berrange * GNU GPL, version 2 or (at your option) any later version.
156f860ae7SDaniel P. Berrange */
166f860ae7SDaniel P. Berrange
176f860ae7SDaniel P. Berrange #include "qemu/osdep.h"
189aca82baSJuan Quintela #include "qemu/cutils.h"
196f860ae7SDaniel P. Berrange
206f860ae7SDaniel P. Berrange #include "qemu/error-report.h"
216f860ae7SDaniel P. Berrange #include "qapi/error.h"
22dd4339c5SJuan Quintela #include "channel.h"
2361e8b148SJuan Quintela #include "socket.h"
246666c96aSJuan Quintela #include "migration.h"
2508a0aee1SJuan Quintela #include "qemu-file.h"
266f860ae7SDaniel P. Berrange #include "io/channel-socket.h"
27bdd847a0SDaniel P. Berrange #include "io/net-listener.h"
286f860ae7SDaniel P. Berrange #include "trace.h"
2936f62f11SPeter Xu #include "postcopy-ram.h"
301f0776f1SJuan Quintela #include "options.h"
3134dfc5e4SHet Gala #include "qapi/clone-visitor.h"
3234dfc5e4SHet Gala #include "qapi/qapi-visit-sockets.h"
336f860ae7SDaniel P. Berrange
343854956aSJuan Quintela struct SocketOutgoingArgs {
353854956aSJuan Quintela SocketAddress *saddr;
363854956aSJuan Quintela } outgoing_args;
373854956aSJuan Quintela
socket_send_channel_create(QIOTaskFunc f,void * data)383854956aSJuan Quintela void socket_send_channel_create(QIOTaskFunc f, void *data)
393854956aSJuan Quintela {
403854956aSJuan Quintela QIOChannelSocket *sioc = qio_channel_socket_new();
413854956aSJuan Quintela qio_channel_socket_connect_async(sioc, outgoing_args.saddr,
423854956aSJuan Quintela f, data, NULL, NULL);
433854956aSJuan Quintela }
443854956aSJuan Quintela
socket_send_channel_create_sync(Error ** errp)4536f62f11SPeter Xu QIOChannel *socket_send_channel_create_sync(Error **errp)
4636f62f11SPeter Xu {
4736f62f11SPeter Xu QIOChannelSocket *sioc = qio_channel_socket_new();
4836f62f11SPeter Xu
4936f62f11SPeter Xu if (!outgoing_args.saddr) {
5036f62f11SPeter Xu object_unref(OBJECT(sioc));
5136f62f11SPeter Xu error_setg(errp, "Initial sock address not set!");
5236f62f11SPeter Xu return NULL;
5336f62f11SPeter Xu }
5436f62f11SPeter Xu
5536f62f11SPeter Xu if (qio_channel_socket_connect_sync(sioc, outgoing_args.saddr, errp) < 0) {
5636f62f11SPeter Xu object_unref(OBJECT(sioc));
5736f62f11SPeter Xu return NULL;
5836f62f11SPeter Xu }
5936f62f11SPeter Xu
6036f62f11SPeter Xu return QIO_CHANNEL(sioc);
6136f62f11SPeter Xu }
6236f62f11SPeter Xu
63e1226365SDaniel P. Berrange struct SocketConnectData {
64e1226365SDaniel P. Berrange MigrationState *s;
65e1226365SDaniel P. Berrange char *hostname;
66e1226365SDaniel P. Berrange };
67e1226365SDaniel P. Berrange
socket_connect_data_free(void * opaque)68e1226365SDaniel P. Berrange static void socket_connect_data_free(void *opaque)
69e1226365SDaniel P. Berrange {
70e1226365SDaniel P. Berrange struct SocketConnectData *data = opaque;
71e1226365SDaniel P. Berrange if (!data) {
72e1226365SDaniel P. Berrange return;
73e1226365SDaniel P. Berrange }
74e1226365SDaniel P. Berrange g_free(data->hostname);
75e1226365SDaniel P. Berrange g_free(data);
76e1226365SDaniel P. Berrange }
77e1226365SDaniel P. Berrange
socket_outgoing_migration(QIOTask * task,gpointer opaque)7860e705c5SDaniel P. Berrange static void socket_outgoing_migration(QIOTask *task,
796f860ae7SDaniel P. Berrange gpointer opaque)
806f860ae7SDaniel P. Berrange {
81e1226365SDaniel P. Berrange struct SocketConnectData *data = opaque;
8260e705c5SDaniel P. Berrange QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task));
8360e705c5SDaniel P. Berrange Error *err = NULL;
846f860ae7SDaniel P. Berrange
8560e705c5SDaniel P. Berrange if (qio_task_propagate_error(task, &err)) {
866f860ae7SDaniel P. Berrange trace_migration_socket_outgoing_error(error_get_pretty(err));
87abb6295bSLeonardo Bras goto out;
886f860ae7SDaniel P. Berrange }
89abb6295bSLeonardo Bras
90abb6295bSLeonardo Bras trace_migration_socket_outgoing_connected(data->hostname);
91abb6295bSLeonardo Bras
92b4bc342cSJuan Quintela if (migrate_zero_copy_send() &&
935b1d9babSLeonardo Bras !qio_channel_has_feature(sioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) {
945b1d9babSLeonardo Bras error_setg(&err, "Zero copy send feature not detected in host kernel");
95abb6295bSLeonardo Bras }
96abb6295bSLeonardo Bras
97abb6295bSLeonardo Bras out:
98688a3dcbSDr. David Alan Gilbert migration_channel_connect(data->s, sioc, data->hostname, err);
9960e705c5SDaniel P. Berrange object_unref(OBJECT(sioc));
1006f860ae7SDaniel P. Berrange }
1016f860ae7SDaniel P. Berrange
socket_start_outgoing_migration(MigrationState * s,SocketAddress * saddr,Error ** errp)10234dfc5e4SHet Gala void socket_start_outgoing_migration(MigrationState *s,
103bd269ebcSMarkus Armbruster SocketAddress *saddr,
1046f860ae7SDaniel P. Berrange Error **errp)
1056f860ae7SDaniel P. Berrange {
1066f860ae7SDaniel P. Berrange QIOChannelSocket *sioc = qio_channel_socket_new();
107e1226365SDaniel P. Berrange struct SocketConnectData *data = g_new0(struct SocketConnectData, 1);
10834dfc5e4SHet Gala SocketAddress *addr = QAPI_CLONE(SocketAddress, saddr);
109474c624dSCao jin
110e1226365SDaniel P. Berrange data->s = s;
1113854956aSJuan Quintela
1123854956aSJuan Quintela /* in case previous migration leaked it */
1133854956aSJuan Quintela qapi_free_SocketAddress(outgoing_args.saddr);
11434dfc5e4SHet Gala outgoing_args.saddr = addr;
1153854956aSJuan Quintela
116bd269ebcSMarkus Armbruster if (saddr->type == SOCKET_ADDRESS_TYPE_INET) {
117bd269ebcSMarkus Armbruster data->hostname = g_strdup(saddr->u.inet.host);
118e1226365SDaniel P. Berrange }
119474c624dSCao jin
1206f01f136SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-outgoing");
1216f860ae7SDaniel P. Berrange qio_channel_socket_connect_async(sioc,
1226f860ae7SDaniel P. Berrange saddr,
1236f860ae7SDaniel P. Berrange socket_outgoing_migration,
124e1226365SDaniel P. Berrange data,
1258005fdd8SPeter Xu socket_connect_data_free,
1268005fdd8SPeter Xu NULL);
1276f860ae7SDaniel P. Berrange }
1286f860ae7SDaniel P. Berrange
socket_cleanup_outgoing_migration(void)129*72b90b96SPeter Xu void socket_cleanup_outgoing_migration(void)
130*72b90b96SPeter Xu {
131*72b90b96SPeter Xu if (outgoing_args.saddr) {
132*72b90b96SPeter Xu qapi_free_SocketAddress(outgoing_args.saddr);
133*72b90b96SPeter Xu outgoing_args.saddr = NULL;
134*72b90b96SPeter Xu }
135*72b90b96SPeter Xu }
136*72b90b96SPeter Xu
socket_accept_incoming_migration(QIONetListener * listener,QIOChannelSocket * cioc,gpointer opaque)137bdd847a0SDaniel P. Berrange static void socket_accept_incoming_migration(QIONetListener *listener,
138bdd847a0SDaniel P. Berrange QIOChannelSocket *cioc,
1396f860ae7SDaniel P. Berrange gpointer opaque)
1406f860ae7SDaniel P. Berrange {
1416f860ae7SDaniel P. Berrange trace_migration_socket_incoming_accepted();
1426f860ae7SDaniel P. Berrange
143a59136f3SDr. David Alan Gilbert if (migration_has_all_channels()) {
144a59136f3SDr. David Alan Gilbert error_report("%s: Extra incoming migration connection; ignoring",
145a59136f3SDr. David Alan Gilbert __func__);
146a59136f3SDr. David Alan Gilbert return;
147a59136f3SDr. David Alan Gilbert }
148a59136f3SDr. David Alan Gilbert
149bdd847a0SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(cioc), "migration-socket-incoming");
150bdd847a0SDaniel P. Berrange migration_channel_process_incoming(QIO_CHANNEL(cioc));
151a59136f3SDr. David Alan Gilbert }
1526f860ae7SDaniel P. Berrange
153a59136f3SDr. David Alan Gilbert static void
socket_incoming_migration_end(void * opaque)154a59136f3SDr. David Alan Gilbert socket_incoming_migration_end(void *opaque)
155a59136f3SDr. David Alan Gilbert {
156a59136f3SDr. David Alan Gilbert QIONetListener *listener = opaque;
157a59136f3SDr. David Alan Gilbert
158bdd847a0SDaniel P. Berrange qio_net_listener_disconnect(listener);
159bdd847a0SDaniel P. Berrange object_unref(OBJECT(listener));
160428d8908SJuan Quintela }
1616f860ae7SDaniel P. Berrange
socket_start_incoming_migration(SocketAddress * saddr,Error ** errp)16234dfc5e4SHet Gala void socket_start_incoming_migration(SocketAddress *saddr,
1636f860ae7SDaniel P. Berrange Error **errp)
1646f860ae7SDaniel P. Berrange {
165bdd847a0SDaniel P. Berrange QIONetListener *listener = qio_net_listener_new();
166a59136f3SDr. David Alan Gilbert MigrationIncomingState *mis = migration_incoming_get_current();
1679aca82baSJuan Quintela size_t i;
1680705e564SJuan Quintela int num = 1;
1696f860ae7SDaniel P. Berrange
170bdd847a0SDaniel P. Berrange qio_net_listener_set_name(listener, "migration-socket-listener");
1716f01f136SDaniel P. Berrange
17251b07548SJuan Quintela if (migrate_multifd()) {
1730705e564SJuan Quintela num = migrate_multifd_channels();
17436f62f11SPeter Xu } else if (migrate_postcopy_preempt()) {
17536f62f11SPeter Xu num = RAM_CHANNEL_MAX;
1760705e564SJuan Quintela }
1770705e564SJuan Quintela
1780705e564SJuan Quintela if (qio_net_listener_open_sync(listener, saddr, num, errp) < 0) {
179bdd847a0SDaniel P. Berrange object_unref(OBJECT(listener));
1806f860ae7SDaniel P. Berrange return;
1816f860ae7SDaniel P. Berrange }
1826f860ae7SDaniel P. Berrange
183a59136f3SDr. David Alan Gilbert mis->transport_data = listener;
184a59136f3SDr. David Alan Gilbert mis->transport_cleanup = socket_incoming_migration_end;
185a59136f3SDr. David Alan Gilbert
186e89f5ff2SPeter Xu qio_net_listener_set_client_func_full(listener,
1876f860ae7SDaniel P. Berrange socket_accept_incoming_migration,
188e89f5ff2SPeter Xu NULL, NULL,
189e89f5ff2SPeter Xu g_main_context_get_thread_default());
1909aca82baSJuan Quintela
1919aca82baSJuan Quintela for (i = 0; i < listener->nsioc; i++) {
1929aca82baSJuan Quintela SocketAddress *address =
1939aca82baSJuan Quintela qio_channel_socket_get_local_address(listener->sioc[i], errp);
1949aca82baSJuan Quintela if (!address) {
1959aca82baSJuan Quintela return;
1969aca82baSJuan Quintela }
1979aca82baSJuan Quintela migrate_add_address(address);
1985e78bc6aSPaolo Bonzini qapi_free_SocketAddress(address);
1999aca82baSJuan Quintela }
2006f860ae7SDaniel P. Berrange }
2016f860ae7SDaniel P. Berrange
202