1 /*
2  * QTest migration helpers
3  *
4  * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
5  *   based on the vhost-user-test.c that is:
6  *      Copyright (c) 2014 Virtual Open Systems Sarl.
7  *
8  * This work is licensed under the terms of the GNU GPL, version 2 or later.
9  * See the COPYING file in the top-level directory.
10  *
11  */
12 
13 #include "qemu/osdep.h"
14 #include "qemu/ctype.h"
15 #include "qapi/qmp/qjson.h"
16 #include "qapi/qapi-visit-sockets.h"
17 #include "qapi/qobject-input-visitor.h"
18 #include "qapi/error.h"
19 #include "qapi/qmp/qlist.h"
20 #include "qemu/cutils.h"
21 #include "qemu/memalign.h"
22 
23 #include "migration-helpers.h"
24 
25 /*
26  * Number of seconds we wait when looking for migration
27  * status changes, to avoid test suite hanging forever
28  * when things go wrong. Needs to be higher enough to
29  * avoid false positives on loaded hosts.
30  */
31 #define MIGRATION_STATUS_WAIT_TIMEOUT 120
32 
33 static char *SocketAddress_to_str(SocketAddress *addr)
34 {
35     switch (addr->type) {
36     case SOCKET_ADDRESS_TYPE_INET:
37         return g_strdup_printf("tcp:%s:%s",
38                                addr->u.inet.host,
39                                addr->u.inet.port);
40     case SOCKET_ADDRESS_TYPE_UNIX:
41         return g_strdup_printf("unix:%s",
42                                addr->u.q_unix.path);
43     case SOCKET_ADDRESS_TYPE_FD:
44         return g_strdup_printf("fd:%s", addr->u.fd.str);
45     case SOCKET_ADDRESS_TYPE_VSOCK:
46         return g_strdup_printf("vsock:%s:%s",
47                                addr->u.vsock.cid,
48                                addr->u.vsock.port);
49     default:
50         return g_strdup("unknown address type");
51     }
52 }
53 
54 static QDict *SocketAddress_to_qdict(SocketAddress *addr)
55 {
56     QDict *dict = qdict_new();
57 
58     switch (addr->type) {
59     case SOCKET_ADDRESS_TYPE_INET:
60         qdict_put_str(dict, "type", "inet");
61         qdict_put_str(dict, "host", addr->u.inet.host);
62         qdict_put_str(dict, "port", addr->u.inet.port);
63         break;
64     case SOCKET_ADDRESS_TYPE_UNIX:
65         qdict_put_str(dict, "type", "unix");
66         qdict_put_str(dict, "path", addr->u.q_unix.path);
67         break;
68     case SOCKET_ADDRESS_TYPE_FD:
69         qdict_put_str(dict, "type", "fd");
70         qdict_put_str(dict, "str", addr->u.fd.str);
71         break;
72     case SOCKET_ADDRESS_TYPE_VSOCK:
73         qdict_put_str(dict, "type", "vsock");
74         qdict_put_str(dict, "cid", addr->u.vsock.cid);
75         qdict_put_str(dict, "port", addr->u.vsock.port);
76         break;
77     default:
78         g_assert_not_reached();
79     }
80 
81     return dict;
82 }
83 
84 static SocketAddressList *migrate_get_socket_address(QTestState *who)
85 {
86     QDict *rsp;
87     SocketAddressList *addrs;
88     Visitor *iv = NULL;
89     QObject *object;
90 
91     rsp = migrate_query(who);
92     object = qdict_get(rsp, "socket-address");
93 
94     iv = qobject_input_visitor_new(object);
95     visit_type_SocketAddressList(iv, NULL, &addrs, &error_abort);
96     visit_free(iv);
97 
98     qobject_unref(rsp);
99     return addrs;
100 }
101 
102 static char *
103 migrate_get_connect_uri(QTestState *who)
104 {
105     SocketAddressList *addrs;
106     char *connect_uri;
107 
108     addrs = migrate_get_socket_address(who);
109     connect_uri = SocketAddress_to_str(addrs->value);
110 
111     qapi_free_SocketAddressList(addrs);
112     return connect_uri;
113 }
114 
115 static QDict *
116 migrate_get_connect_qdict(QTestState *who)
117 {
118     SocketAddressList *addrs;
119     QDict *connect_qdict;
120 
121     addrs = migrate_get_socket_address(who);
122     connect_qdict = SocketAddress_to_qdict(addrs->value);
123 
124     qapi_free_SocketAddressList(addrs);
125     return connect_qdict;
126 }
127 
128 static void migrate_set_ports(QTestState *to, QList *channel_list)
129 {
130     QDict *addr;
131     QListEntry *entry;
132     const char *addr_port = NULL;
133 
134     addr = migrate_get_connect_qdict(to);
135 
136     QLIST_FOREACH_ENTRY(channel_list, entry) {
137         QDict *channel = qobject_to(QDict, qlist_entry_obj(entry));
138         QDict *addrdict = qdict_get_qdict(channel, "addr");
139 
140         if (qdict_haskey(addrdict, "port") &&
141             qdict_haskey(addr, "port") &&
142             (strcmp(qdict_get_str(addrdict, "port"), "0") == 0)) {
143                 addr_port = qdict_get_str(addr, "port");
144                 qdict_put_str(addrdict, "port", addr_port);
145         }
146     }
147 
148     qobject_unref(addr);
149 }
150 
151 bool migrate_watch_for_events(QTestState *who, const char *name,
152                               QDict *event, void *opaque)
153 {
154     QTestMigrationState *state = opaque;
155 
156     if (g_str_equal(name, "STOP")) {
157         state->stop_seen = true;
158         return true;
159     } else if (g_str_equal(name, "SUSPEND")) {
160         state->suspend_seen = true;
161         return true;
162     } else if (g_str_equal(name, "RESUME")) {
163         state->resume_seen = true;
164         return true;
165     }
166 
167     return false;
168 }
169 
170 void migrate_qmp_fail(QTestState *who, const char *uri,
171                       const char *channels, const char *fmt, ...)
172 {
173     va_list ap;
174     QDict *args, *err;
175 
176     va_start(ap, fmt);
177     args = qdict_from_vjsonf_nofail(fmt, ap);
178     va_end(ap);
179 
180     g_assert(!qdict_haskey(args, "uri"));
181     if (uri) {
182         qdict_put_str(args, "uri", uri);
183     }
184 
185     g_assert(!qdict_haskey(args, "channels"));
186     if (channels) {
187         QObject *channels_obj = qobject_from_json(channels, &error_abort);
188         qdict_put_obj(args, "channels", channels_obj);
189     }
190 
191     err = qtest_qmp_assert_failure_ref(
192         who, "{ 'execute': 'migrate', 'arguments': %p}", args);
193 
194     g_assert(qdict_haskey(err, "desc"));
195 
196     qobject_unref(err);
197 }
198 
199 /*
200  * Send QMP command "migrate".
201  * Arguments are built from @fmt... (formatted like
202  * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
203  */
204 void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
205                  const char *channels, const char *fmt, ...)
206 {
207     va_list ap;
208     QDict *args;
209     g_autofree char *connect_uri = NULL;
210 
211     va_start(ap, fmt);
212     args = qdict_from_vjsonf_nofail(fmt, ap);
213     va_end(ap);
214 
215     g_assert(!qdict_haskey(args, "uri"));
216     if (uri) {
217         qdict_put_str(args, "uri", uri);
218     } else if (!channels) {
219         connect_uri = migrate_get_connect_uri(to);
220         qdict_put_str(args, "uri", connect_uri);
221     }
222 
223     g_assert(!qdict_haskey(args, "channels"));
224     if (channels) {
225         QObject *channels_obj = qobject_from_json(channels, &error_abort);
226         QList *channel_list = qobject_to(QList, channels_obj);
227         migrate_set_ports(to, channel_list);
228         qdict_put_obj(args, "channels", channels_obj);
229     }
230 
231     qtest_qmp_assert_success(who,
232                              "{ 'execute': 'migrate', 'arguments': %p}", args);
233 }
234 
235 void migrate_set_capability(QTestState *who, const char *capability,
236                             bool value)
237 {
238     qtest_qmp_assert_success(who,
239                              "{ 'execute': 'migrate-set-capabilities',"
240                              "'arguments': { "
241                              "'capabilities': [ { "
242                              "'capability': %s, 'state': %i } ] } }",
243                              capability, value);
244 }
245 
246 void migrate_incoming_qmp(QTestState *to, const char *uri, const char *fmt, ...)
247 {
248     va_list ap;
249     QDict *args, *rsp;
250 
251     va_start(ap, fmt);
252     args = qdict_from_vjsonf_nofail(fmt, ap);
253     va_end(ap);
254 
255     g_assert(!qdict_haskey(args, "uri"));
256     qdict_put_str(args, "uri", uri);
257 
258     /* This function relies on the event to work, make sure it's enabled */
259     migrate_set_capability(to, "events", true);
260 
261     rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
262                     args);
263 
264     if (!qdict_haskey(rsp, "return")) {
265         g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true);
266         g_test_message("%s", s->str);
267     }
268 
269     g_assert(qdict_haskey(rsp, "return"));
270     qobject_unref(rsp);
271 
272     migration_event_wait(to, "setup");
273 }
274 
275 /*
276  * Note: caller is responsible to free the returned object via
277  * qobject_unref() after use
278  */
279 QDict *migrate_query(QTestState *who)
280 {
281     return qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-migrate' }");
282 }
283 
284 QDict *migrate_query_not_failed(QTestState *who)
285 {
286     const char *status;
287     QDict *rsp = migrate_query(who);
288     status = qdict_get_str(rsp, "status");
289     if (g_str_equal(status, "failed")) {
290         g_printerr("query-migrate shows failed migration: %s\n",
291                    qdict_get_str(rsp, "error-desc"));
292     }
293     g_assert(!g_str_equal(status, "failed"));
294     return rsp;
295 }
296 
297 /*
298  * Note: caller is responsible to free the returned object via
299  * g_free() after use
300  */
301 static gchar *migrate_query_status(QTestState *who)
302 {
303     QDict *rsp_return = migrate_query(who);
304     gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
305 
306     g_assert(status);
307     qobject_unref(rsp_return);
308 
309     return status;
310 }
311 
312 static bool check_migration_status(QTestState *who, const char *goal,
313                                    const char **ungoals)
314 {
315     bool ready;
316     char *current_status;
317     const char **ungoal;
318 
319     current_status = migrate_query_status(who);
320     ready = strcmp(current_status, goal) == 0;
321     if (!ungoals) {
322         g_assert_cmpstr(current_status, !=, "failed");
323         /*
324          * If looking for a state other than completed,
325          * completion of migration would cause the test to
326          * hang.
327          */
328         if (strcmp(goal, "completed") != 0) {
329             g_assert_cmpstr(current_status, !=, "completed");
330         }
331     } else {
332         for (ungoal = ungoals; *ungoal; ungoal++) {
333             g_assert_cmpstr(current_status, !=,  *ungoal);
334         }
335     }
336     g_free(current_status);
337     return ready;
338 }
339 
340 void wait_for_migration_status(QTestState *who,
341                                const char *goal, const char **ungoals)
342 {
343     g_test_timer_start();
344     while (!check_migration_status(who, goal, ungoals)) {
345         usleep(1000);
346 
347         g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
348     }
349 }
350 
351 void wait_for_migration_complete(QTestState *who)
352 {
353     wait_for_migration_status(who, "completed", NULL);
354 }
355 
356 void wait_for_migration_fail(QTestState *from, bool allow_active)
357 {
358     g_test_timer_start();
359     QDict *rsp_return;
360     char *status;
361     bool failed;
362 
363     do {
364         status = migrate_query_status(from);
365         bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
366             (allow_active && !strcmp(status, "active"));
367         if (!result) {
368             fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
369                     __func__, status, allow_active);
370         }
371         g_assert(result);
372         failed = !strcmp(status, "failed");
373         g_free(status);
374 
375         g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
376     } while (!failed);
377 
378     /* Is the machine currently running? */
379     rsp_return = qtest_qmp_assert_success_ref(from,
380                                               "{ 'execute': 'query-status' }");
381     g_assert(qdict_haskey(rsp_return, "running"));
382     g_assert(qdict_get_bool(rsp_return, "running"));
383     qobject_unref(rsp_return);
384 }
385 
386 char *find_common_machine_version(const char *mtype, const char *var1,
387                                   const char *var2)
388 {
389     g_autofree char *type1 = qtest_resolve_machine_alias(var1, mtype);
390     g_autofree char *type2 = qtest_resolve_machine_alias(var2, mtype);
391 
392     g_assert(type1 && type2);
393 
394     if (g_str_equal(type1, type2)) {
395         /* either can be used */
396         return g_strdup(type1);
397     }
398 
399     if (qtest_has_machine_with_env(var2, type1)) {
400         return g_strdup(type1);
401     }
402 
403     if (qtest_has_machine_with_env(var1, type2)) {
404         return g_strdup(type2);
405     }
406 
407     g_test_message("No common machine version for machine type '%s' between "
408                    "binaries %s and %s", mtype, getenv(var1), getenv(var2));
409     g_assert_not_reached();
410 }
411 
412 char *resolve_machine_version(const char *alias, const char *var1,
413                               const char *var2)
414 {
415     const char *mname = g_getenv("QTEST_QEMU_MACHINE_TYPE");
416     g_autofree char *machine_name = NULL;
417 
418     if (mname) {
419         const char *dash = strrchr(mname, '-');
420         const char *dot = strrchr(mname, '.');
421 
422         machine_name = g_strdup(mname);
423 
424         if (dash && dot) {
425             assert(qtest_has_machine(machine_name));
426             return g_steal_pointer(&machine_name);
427         }
428         /* else: probably an alias, let it be resolved below */
429     } else {
430         /* use the hardcoded alias */
431         machine_name = g_strdup(alias);
432     }
433 
434     return find_common_machine_version(machine_name, var1, var2);
435 }
436 
437 typedef struct {
438     char *name;
439     void (*func)(void);
440 } MigrationTest;
441 
442 static void migration_test_destroy(gpointer data)
443 {
444     MigrationTest *test = (MigrationTest *)data;
445 
446     g_free(test->name);
447     g_free(test);
448 }
449 
450 static void migration_test_wrapper(const void *data)
451 {
452     MigrationTest *test = (MigrationTest *)data;
453 
454     g_test_message("Running /%s%s", qtest_get_arch(), test->name);
455     test->func();
456 }
457 
458 void migration_test_add(const char *path, void (*fn)(void))
459 {
460     MigrationTest *test = g_new0(MigrationTest, 1);
461 
462     test->func = fn;
463     test->name = g_strdup(path);
464 
465     qtest_add_data_func_full(path, test, migration_test_wrapper,
466                              migration_test_destroy);
467 }
468 
469 #ifdef O_DIRECT
470 /*
471  * Probe for O_DIRECT support on the filesystem. Since this is used
472  * for tests, be conservative, if anything fails, assume it's
473  * unsupported.
474  */
475 bool probe_o_direct_support(const char *tmpfs)
476 {
477     g_autofree char *filename = g_strdup_printf("%s/probe-o-direct", tmpfs);
478     int fd, flags = O_CREAT | O_RDWR | O_TRUNC | O_DIRECT;
479     void *buf;
480     ssize_t ret, len;
481     uint64_t offset;
482 
483     fd = open(filename, flags, 0660);
484     if (fd < 0) {
485         unlink(filename);
486         return false;
487     }
488 
489     /*
490      * Using 1MB alignment as conservative choice to satisfy any
491      * plausible architecture default page size, and/or filesystem
492      * alignment restrictions.
493      */
494     len = 0x100000;
495     offset = 0x100000;
496 
497     buf = qemu_try_memalign(len, len);
498     g_assert(buf);
499 
500     ret = pwrite(fd, buf, len, offset);
501     unlink(filename);
502     g_free(buf);
503 
504     if (ret < 0) {
505         return false;
506     }
507 
508     return true;
509 }
510 #endif
511 
512 /*
513  * Wait for a "MIGRATION" event.  This is what Libvirt uses to track
514  * migration status changes.
515  */
516 void migration_event_wait(QTestState *s, const char *target)
517 {
518     QDict *response, *data;
519     const char *status;
520     bool found;
521 
522     do {
523         response = qtest_qmp_eventwait_ref(s, "MIGRATION");
524         data = qdict_get_qdict(response, "data");
525         g_assert(data);
526         status = qdict_get_str(data, "status");
527         found = (strcmp(status, target) == 0);
528         qobject_unref(response);
529     } while (!found);
530 }
531