xref: /qemu/migration/socket.c (revision c9a7e83c)
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