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