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