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