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