xref: /openbmc/qemu/migration/socket.c (revision 05adb38839ba656c7383a548b460d95c91e2febe)
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 
45e1226365SDaniel P. Berrange struct SocketConnectData {
46e1226365SDaniel P. Berrange     MigrationState *s;
47e1226365SDaniel P. Berrange     char *hostname;
48e1226365SDaniel P. Berrange };
49e1226365SDaniel P. Berrange 
socket_connect_data_free(void * opaque)50e1226365SDaniel P. Berrange static void socket_connect_data_free(void *opaque)
51e1226365SDaniel P. Berrange {
52e1226365SDaniel P. Berrange     struct SocketConnectData *data = opaque;
53e1226365SDaniel P. Berrange     if (!data) {
54e1226365SDaniel P. Berrange         return;
55e1226365SDaniel P. Berrange     }
56e1226365SDaniel P. Berrange     g_free(data->hostname);
57e1226365SDaniel P. Berrange     g_free(data);
58e1226365SDaniel P. Berrange }
59e1226365SDaniel P. Berrange 
socket_outgoing_migration(QIOTask * task,gpointer opaque)6060e705c5SDaniel P. Berrange static void socket_outgoing_migration(QIOTask *task,
616f860ae7SDaniel P. Berrange                                       gpointer opaque)
626f860ae7SDaniel P. Berrange {
63e1226365SDaniel P. Berrange     struct SocketConnectData *data = opaque;
6460e705c5SDaniel P. Berrange     QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task));
6560e705c5SDaniel P. Berrange     Error *err = NULL;
666f860ae7SDaniel P. Berrange 
6760e705c5SDaniel P. Berrange     if (qio_task_propagate_error(task, &err)) {
686f860ae7SDaniel P. Berrange         trace_migration_socket_outgoing_error(error_get_pretty(err));
69abb6295bSLeonardo Bras            goto out;
706f860ae7SDaniel P. Berrange     }
71abb6295bSLeonardo Bras 
72abb6295bSLeonardo Bras     trace_migration_socket_outgoing_connected(data->hostname);
73abb6295bSLeonardo Bras 
74b4bc342cSJuan Quintela     if (migrate_zero_copy_send() &&
755b1d9babSLeonardo Bras         !qio_channel_has_feature(sioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) {
765b1d9babSLeonardo Bras         error_setg(&err, "Zero copy send feature not detected in host kernel");
77abb6295bSLeonardo Bras     }
78abb6295bSLeonardo Bras 
79abb6295bSLeonardo Bras out:
80688a3dcbSDr. David Alan Gilbert     migration_channel_connect(data->s, sioc, data->hostname, err);
8160e705c5SDaniel P. Berrange     object_unref(OBJECT(sioc));
826f860ae7SDaniel P. Berrange }
836f860ae7SDaniel P. Berrange 
socket_start_outgoing_migration(MigrationState * s,SocketAddress * saddr,Error ** errp)8434dfc5e4SHet Gala void socket_start_outgoing_migration(MigrationState *s,
85bd269ebcSMarkus Armbruster                                      SocketAddress *saddr,
866f860ae7SDaniel P. Berrange                                      Error **errp)
876f860ae7SDaniel P. Berrange {
886f860ae7SDaniel P. Berrange     QIOChannelSocket *sioc = qio_channel_socket_new();
89e1226365SDaniel P. Berrange     struct SocketConnectData *data = g_new0(struct SocketConnectData, 1);
9034dfc5e4SHet Gala     SocketAddress *addr = QAPI_CLONE(SocketAddress, saddr);
91474c624dSCao jin 
92e1226365SDaniel P. Berrange     data->s = s;
933854956aSJuan Quintela 
943854956aSJuan Quintela     /* in case previous migration leaked it */
953854956aSJuan Quintela     qapi_free_SocketAddress(outgoing_args.saddr);
9634dfc5e4SHet Gala     outgoing_args.saddr = addr;
973854956aSJuan Quintela 
98bd269ebcSMarkus Armbruster     if (saddr->type == SOCKET_ADDRESS_TYPE_INET) {
99bd269ebcSMarkus Armbruster         data->hostname = g_strdup(saddr->u.inet.host);
100e1226365SDaniel P. Berrange     }
101474c624dSCao jin 
1026f01f136SDaniel P. Berrange     qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-outgoing");
1036f860ae7SDaniel P. Berrange     qio_channel_socket_connect_async(sioc,
1046f860ae7SDaniel P. Berrange                                      saddr,
1056f860ae7SDaniel P. Berrange                                      socket_outgoing_migration,
106e1226365SDaniel P. Berrange                                      data,
1078005fdd8SPeter Xu                                      socket_connect_data_free,
1088005fdd8SPeter Xu                                      NULL);
1096f860ae7SDaniel P. Berrange }
1106f860ae7SDaniel P. Berrange 
socket_cleanup_outgoing_migration(void)111*72b90b96SPeter Xu void socket_cleanup_outgoing_migration(void)
112*72b90b96SPeter Xu {
113*72b90b96SPeter Xu     if (outgoing_args.saddr) {
114*72b90b96SPeter Xu         qapi_free_SocketAddress(outgoing_args.saddr);
115*72b90b96SPeter Xu         outgoing_args.saddr = NULL;
116*72b90b96SPeter Xu     }
117*72b90b96SPeter Xu }
118*72b90b96SPeter Xu 
socket_accept_incoming_migration(QIONetListener * listener,QIOChannelSocket * cioc,gpointer opaque)119bdd847a0SDaniel P. Berrange static void socket_accept_incoming_migration(QIONetListener *listener,
120bdd847a0SDaniel P. Berrange                                              QIOChannelSocket *cioc,
1216f860ae7SDaniel P. Berrange                                              gpointer opaque)
1226f860ae7SDaniel P. Berrange {
1236f860ae7SDaniel P. Berrange     trace_migration_socket_incoming_accepted();
1246f860ae7SDaniel P. Berrange 
125a59136f3SDr. David Alan Gilbert     if (migration_has_all_channels()) {
126a59136f3SDr. David Alan Gilbert         error_report("%s: Extra incoming migration connection; ignoring",
127a59136f3SDr. David Alan Gilbert                      __func__);
128a59136f3SDr. David Alan Gilbert         return;
129a59136f3SDr. David Alan Gilbert     }
130a59136f3SDr. David Alan Gilbert 
131bdd847a0SDaniel P. Berrange     qio_channel_set_name(QIO_CHANNEL(cioc), "migration-socket-incoming");
132bdd847a0SDaniel P. Berrange     migration_channel_process_incoming(QIO_CHANNEL(cioc));
133a59136f3SDr. David Alan Gilbert }
1346f860ae7SDaniel P. Berrange 
135a59136f3SDr. David Alan Gilbert static void
socket_incoming_migration_end(void * opaque)136a59136f3SDr. David Alan Gilbert socket_incoming_migration_end(void *opaque)
137a59136f3SDr. David Alan Gilbert {
138a59136f3SDr. David Alan Gilbert     QIONetListener *listener = opaque;
139a59136f3SDr. David Alan Gilbert 
140bdd847a0SDaniel P. Berrange     qio_net_listener_disconnect(listener);
141bdd847a0SDaniel P. Berrange     object_unref(OBJECT(listener));
142428d8908SJuan Quintela }
1436f860ae7SDaniel P. Berrange 
socket_start_incoming_migration(SocketAddress * saddr,Error ** errp)14434dfc5e4SHet Gala void socket_start_incoming_migration(SocketAddress *saddr,
1456f860ae7SDaniel P. Berrange                                      Error **errp)
1466f860ae7SDaniel P. Berrange {
147bdd847a0SDaniel P. Berrange     QIONetListener *listener = qio_net_listener_new();
148a59136f3SDr. David Alan Gilbert     MigrationIncomingState *mis = migration_incoming_get_current();
1499aca82baSJuan Quintela     size_t i;
1500705e564SJuan Quintela     int num = 1;
1516f860ae7SDaniel P. Berrange 
152bdd847a0SDaniel P. Berrange     qio_net_listener_set_name(listener, "migration-socket-listener");
1536f01f136SDaniel P. Berrange 
15451b07548SJuan Quintela     if (migrate_multifd()) {
1550705e564SJuan Quintela         num = migrate_multifd_channels();
15636f62f11SPeter Xu     } else if (migrate_postcopy_preempt()) {
15736f62f11SPeter Xu         num = RAM_CHANNEL_MAX;
1580705e564SJuan Quintela     }
1590705e564SJuan Quintela 
1600705e564SJuan Quintela     if (qio_net_listener_open_sync(listener, saddr, num, errp) < 0) {
161bdd847a0SDaniel P. Berrange         object_unref(OBJECT(listener));
1626f860ae7SDaniel P. Berrange         return;
1636f860ae7SDaniel P. Berrange     }
1646f860ae7SDaniel P. Berrange 
165a59136f3SDr. David Alan Gilbert     mis->transport_data = listener;
166a59136f3SDr. David Alan Gilbert     mis->transport_cleanup = socket_incoming_migration_end;
167a59136f3SDr. David Alan Gilbert 
168e89f5ff2SPeter Xu     qio_net_listener_set_client_func_full(listener,
1696f860ae7SDaniel P. Berrange                                           socket_accept_incoming_migration,
170e89f5ff2SPeter Xu                                           NULL, NULL,
171e89f5ff2SPeter Xu                                           g_main_context_get_thread_default());
1729aca82baSJuan Quintela 
1739aca82baSJuan Quintela     for (i = 0; i < listener->nsioc; i++)  {
1749aca82baSJuan Quintela         SocketAddress *address =
1759aca82baSJuan Quintela             qio_channel_socket_get_local_address(listener->sioc[i], errp);
1769aca82baSJuan Quintela         if (!address) {
1779aca82baSJuan Quintela             return;
1789aca82baSJuan Quintela         }
1799aca82baSJuan Quintela         migrate_add_address(address);
1805e78bc6aSPaolo Bonzini         qapi_free_SocketAddress(address);
1819aca82baSJuan Quintela     }
1826f860ae7SDaniel P. Berrange }
1836f860ae7SDaniel P. Berrange 
184