xref: /openbmc/qemu/migration/socket.c (revision b097ba37)
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-common.h"
21 #include "qemu/error-report.h"
22 #include "qapi/error.h"
23 #include "channel.h"
24 #include "socket.h"
25 #include "migration.h"
26 #include "qemu-file.h"
27 #include "io/channel-socket.h"
28 #include "io/net-listener.h"
29 #include "trace.h"
30 
31 
32 struct SocketOutgoingArgs {
33     SocketAddress *saddr;
34 } outgoing_args;
35 
36 void socket_send_channel_create(QIOTaskFunc f, void *data)
37 {
38     QIOChannelSocket *sioc = qio_channel_socket_new();
39     qio_channel_socket_connect_async(sioc, outgoing_args.saddr,
40                                      f, data, NULL, NULL);
41 }
42 
43 int socket_send_channel_destroy(QIOChannel *send)
44 {
45     /* Remove channel */
46     object_unref(OBJECT(send));
47     if (outgoing_args.saddr) {
48         qapi_free_SocketAddress(outgoing_args.saddr);
49         outgoing_args.saddr = NULL;
50     }
51     return 0;
52 }
53 
54 static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
55 {
56     SocketAddress *saddr;
57 
58     saddr = g_new0(SocketAddress, 1);
59     saddr->type = SOCKET_ADDRESS_TYPE_INET;
60 
61     if (inet_parse(&saddr->u.inet, host_port, errp)) {
62         qapi_free_SocketAddress(saddr);
63         return NULL;
64     }
65 
66     return saddr;
67 }
68 
69 
70 static SocketAddress *unix_build_address(const char *path)
71 {
72     SocketAddress *saddr;
73 
74     saddr = g_new0(SocketAddress, 1);
75     saddr->type = SOCKET_ADDRESS_TYPE_UNIX;
76     saddr->u.q_unix.path = g_strdup(path);
77 
78     return saddr;
79 }
80 
81 
82 struct SocketConnectData {
83     MigrationState *s;
84     char *hostname;
85 };
86 
87 static void socket_connect_data_free(void *opaque)
88 {
89     struct SocketConnectData *data = opaque;
90     if (!data) {
91         return;
92     }
93     g_free(data->hostname);
94     g_free(data);
95 }
96 
97 static void socket_outgoing_migration(QIOTask *task,
98                                       gpointer opaque)
99 {
100     struct SocketConnectData *data = opaque;
101     QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task));
102     Error *err = NULL;
103 
104     if (qio_task_propagate_error(task, &err)) {
105         trace_migration_socket_outgoing_error(error_get_pretty(err));
106     } else {
107         trace_migration_socket_outgoing_connected(data->hostname);
108     }
109     migration_channel_connect(data->s, sioc, data->hostname, err);
110     object_unref(OBJECT(sioc));
111 }
112 
113 static void socket_start_outgoing_migration(MigrationState *s,
114                                             SocketAddress *saddr,
115                                             Error **errp)
116 {
117     QIOChannelSocket *sioc = qio_channel_socket_new();
118     struct SocketConnectData *data = g_new0(struct SocketConnectData, 1);
119 
120     data->s = s;
121 
122     /* in case previous migration leaked it */
123     qapi_free_SocketAddress(outgoing_args.saddr);
124     outgoing_args.saddr = saddr;
125 
126     if (saddr->type == SOCKET_ADDRESS_TYPE_INET) {
127         data->hostname = g_strdup(saddr->u.inet.host);
128     }
129 
130     qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-outgoing");
131     qio_channel_socket_connect_async(sioc,
132                                      saddr,
133                                      socket_outgoing_migration,
134                                      data,
135                                      socket_connect_data_free,
136                                      NULL);
137 }
138 
139 void tcp_start_outgoing_migration(MigrationState *s,
140                                   const char *host_port,
141                                   Error **errp)
142 {
143     Error *err = NULL;
144     SocketAddress *saddr = tcp_build_address(host_port, &err);
145     if (!err) {
146         socket_start_outgoing_migration(s, saddr, &err);
147     }
148     error_propagate(errp, err);
149 }
150 
151 void unix_start_outgoing_migration(MigrationState *s,
152                                    const char *path,
153                                    Error **errp)
154 {
155     SocketAddress *saddr = unix_build_address(path);
156     socket_start_outgoing_migration(s, saddr, errp);
157 }
158 
159 
160 static void socket_accept_incoming_migration(QIONetListener *listener,
161                                              QIOChannelSocket *cioc,
162                                              gpointer opaque)
163 {
164     trace_migration_socket_incoming_accepted();
165 
166     qio_channel_set_name(QIO_CHANNEL(cioc), "migration-socket-incoming");
167     migration_channel_process_incoming(QIO_CHANNEL(cioc));
168 
169     if (migration_has_all_channels()) {
170         /* Close listening socket as its no longer needed */
171         qio_net_listener_disconnect(listener);
172         object_unref(OBJECT(listener));
173     }
174 }
175 
176 
177 static void socket_start_incoming_migration(SocketAddress *saddr,
178                                             Error **errp)
179 {
180     QIONetListener *listener = qio_net_listener_new();
181     size_t i;
182 
183     qio_net_listener_set_name(listener, "migration-socket-listener");
184 
185     if (qio_net_listener_open_sync(listener, saddr, errp) < 0) {
186         object_unref(OBJECT(listener));
187         return;
188     }
189 
190     qio_net_listener_set_client_func_full(listener,
191                                           socket_accept_incoming_migration,
192                                           NULL, NULL,
193                                           g_main_context_get_thread_default());
194 
195     for (i = 0; i < listener->nsioc; i++)  {
196         SocketAddress *address =
197             qio_channel_socket_get_local_address(listener->sioc[i], errp);
198         if (!address) {
199             return;
200         }
201         migrate_add_address(address);
202         qapi_free_SocketAddress(address);
203     }
204 }
205 
206 void tcp_start_incoming_migration(const char *host_port, Error **errp)
207 {
208     Error *err = NULL;
209     SocketAddress *saddr = tcp_build_address(host_port, &err);
210     if (!err) {
211         socket_start_incoming_migration(saddr, &err);
212     }
213     qapi_free_SocketAddress(saddr);
214     error_propagate(errp, err);
215 }
216 
217 void unix_start_incoming_migration(const char *path, Error **errp)
218 {
219     SocketAddress *saddr = unix_build_address(path);
220     socket_start_incoming_migration(saddr, errp);
221     qapi_free_SocketAddress(saddr);
222 }
223