master
c 179 lines 5.13 KB
Raw
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 #include "postcopy-ram.h"
30 #include "options.h"
31 #include "qapi/clone-visitor.h"
32 #include "qapi/qapi-visit-sockets.h"
33
34 struct SocketOutgoingArgs {
35 SocketAddress *saddr;
36 } outgoing_args;
37
38 void socket_send_channel_create(QIOTaskFunc f, void *data)
39 {
40 QIOChannelSocket *sioc = qio_channel_socket_new();
41 qio_channel_socket_connect_async(sioc, outgoing_args.saddr,
42 f, data, NULL, NULL);
43 }
44
45 struct SocketConnectData {
46 MigrationState *s;
47 };
48
49 static void socket_connect_data_free(void *opaque)
50 {
51 struct SocketConnectData *data = opaque;
52 if (!data) {
53 return;
54 }
55 g_free(data);
56 }
57
58 static void socket_outgoing_migration(QIOTask *task,
59 gpointer opaque)
60 {
61 struct SocketConnectData *data = opaque;
62 g_autoptr(QIOChannel) sioc = QIO_CHANNEL(qio_task_get_source(task));
63 Error *err = NULL;
64
65 if (qio_task_propagate_error(task, &err)) {
66 goto fail;
67 }
68
69 if (migrate_zero_copy_send() &&
70 !qio_channel_has_feature(sioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) {
71 error_setg(&err, "Zero copy send feature not detected in host kernel");
72 goto fail;
73 }
74
75 trace_migration_socket_outgoing_connected();
76 migration_channel_connect_outgoing(data->s, sioc);
77 return;
78 fail:
79 trace_migration_socket_outgoing_error(error_get_pretty(err));
80 migration_connect_error_propagate(data->s, err);
81 }
82
83 void socket_connect_outgoing(MigrationState *s, SocketAddress *saddr,
84 Error **errp)
85 {
86 QIOChannelSocket *sioc = qio_channel_socket_new();
87 struct SocketConnectData *data = g_new0(struct SocketConnectData, 1);
88 SocketAddress *addr = QAPI_CLONE(SocketAddress, saddr);
89
90 data->s = s;
91
92 /* in case previous migration leaked it */
93 qapi_free_SocketAddress(outgoing_args.saddr);
94 outgoing_args.saddr = addr;
95
96 if (saddr->type == SOCKET_ADDRESS_TYPE_INET) {
97 s->hostname = g_strdup(saddr->u.inet.host);
98 }
99
100 qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-outgoing");
101 qio_channel_socket_connect_async(sioc,
102 saddr,
103 socket_outgoing_migration,
104 data,
105 socket_connect_data_free,
106 NULL);
107 }
108
109 void socket_cleanup_outgoing_migration(void)
110 {
111 if (outgoing_args.saddr) {
112 qapi_free_SocketAddress(outgoing_args.saddr);
113 outgoing_args.saddr = NULL;
114 }
115 }
116
117 static void socket_accept_incoming_migration(QIONetListener *listener,
118 QIOChannelSocket *cioc,
119 gpointer opaque)
120 {
121 trace_migration_socket_incoming_accepted();
122
123 if (migration_has_all_channels()) {
124 error_report("%s: Extra incoming migration connection; ignoring",
125 __func__);
126 return;
127 }
128
129 qio_channel_set_name(QIO_CHANNEL(cioc), "migration-socket-incoming");
130 migration_channel_process_incoming(QIO_CHANNEL(cioc));
131 }
132
133 static void
134 socket_incoming_migration_end(void *opaque)
135 {
136 QIONetListener *listener = opaque;
137
138 qio_net_listener_disconnect(listener);
139 object_unref(OBJECT(listener));
140 }
141
142 void socket_connect_incoming(SocketAddress *saddr, Error **errp)
143 {
144 QIONetListener *listener = qio_net_listener_new();
145 MigrationIncomingState *mis = migration_incoming_get_current();
146 size_t i;
147 int num = 1;
148
149 qio_net_listener_set_name(listener, "migration-socket-listener");
150
151 if (migrate_multifd()) {
152 num = migrate_multifd_channels();
153 } else if (migrate_postcopy_preempt()) {
154 num = RAM_CHANNEL_MAX;
155 }
156
157 if (qio_net_listener_open_sync(listener, saddr, num, errp) < 0) {
158 object_unref(OBJECT(listener));
159 return;
160 }
161
162 mis->transport_data = listener;
163 mis->transport_cleanup = socket_incoming_migration_end;
164
165 qio_net_listener_set_client_func_full(listener,
166 socket_accept_incoming_migration,
167 NULL, NULL,
168 g_main_context_get_thread_default());
169
170 for (i = 0; i < qio_net_listener_nsioc(listener); i++) {
171 SocketAddress *address =
172 qio_net_listener_get_local_address(listener, i, errp);
173 if (!address) {
174 return;
175 }
176 migrate_add_address(address);
177 qapi_free_SocketAddress(address);
178 }
179 }