1 /* 2 * QTest testcase for virtio-net failover 3 * 4 * See docs/system/virtio-net-failover.rst 5 * 6 * Copyright (c) 2021 Red Hat, Inc. 7 * 8 * SPDX-License-Identifier: GPL-2.0-or-later 9 */ 10 #include "qemu/osdep.h" 11 #include "libqos/libqtest.h" 12 #include "libqos/pci.h" 13 #include "libqos/pci-pc.h" 14 #include "qapi/qmp/qdict.h" 15 #include "qapi/qmp/qlist.h" 16 #include "qapi/qmp/qjson.h" 17 #include "libqos/malloc-pc.h" 18 #include "libqos/virtio-pci.h" 19 #include "hw/pci/pci.h" 20 21 #define ACPI_PCIHP_ADDR_ICH9 0x0cc0 22 #define PCI_EJ_BASE 0x0008 23 #define PCI_SEL_BASE 0x0010 24 25 #define BASE_MACHINE "-M q35 -nodefaults " \ 26 "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \ 27 "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 " 28 29 #define MAC_PRIMARY0 "52:54:00:11:11:11" 30 #define MAC_STANDBY0 "52:54:00:22:22:22" 31 #define MAC_PRIMARY1 "52:54:00:33:33:33" 32 #define MAC_STANDBY1 "52:54:00:44:44:44" 33 34 static QGuestAllocator guest_malloc; 35 static QPCIBus *pcibus; 36 37 static QTestState *machine_start(const char *args, int numbus) 38 { 39 QTestState *qts; 40 QPCIDevice *dev; 41 int bus; 42 43 qts = qtest_init(args); 44 45 pc_alloc_init(&guest_malloc, qts, 0); 46 pcibus = qpci_new_pc(qts, &guest_malloc); 47 g_assert(qpci_secondary_buses_init(pcibus) == numbus); 48 49 for (bus = 1; bus <= numbus; bus++) { 50 dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0)); 51 g_assert_nonnull(dev); 52 53 qpci_device_enable(dev); 54 qpci_iomap(dev, 4, NULL); 55 56 g_free(dev); 57 } 58 59 return qts; 60 } 61 62 static void machine_stop(QTestState *qts) 63 { 64 qpci_free_pc(pcibus); 65 alloc_destroy(&guest_malloc); 66 qtest_quit(qts); 67 } 68 69 static void test_error_id(void) 70 { 71 QTestState *qts; 72 QDict *resp; 73 QDict *err; 74 75 qts = machine_start(BASE_MACHINE 76 "-device virtio-net,bus=root0,id=standby0,failover=on", 77 2); 78 79 resp = qtest_qmp(qts, "{'execute': 'device_add'," 80 "'arguments': {" 81 "'driver': 'virtio-net'," 82 "'bus': 'root1'," 83 "'failover_pair_id': 'standby0'" 84 "} }"); 85 g_assert(qdict_haskey(resp, "error")); 86 87 err = qdict_get_qdict(resp, "error"); 88 g_assert(qdict_haskey(err, "desc")); 89 90 g_assert_cmpstr(qdict_get_str(err, "desc"), ==, 91 "Device with failover_pair_id needs to have id"); 92 93 qobject_unref(resp); 94 95 machine_stop(qts); 96 } 97 98 static void test_error_pcie(void) 99 { 100 QTestState *qts; 101 QDict *resp; 102 QDict *err; 103 104 qts = machine_start(BASE_MACHINE 105 "-device virtio-net,bus=root0,id=standby0,failover=on", 106 2); 107 108 resp = qtest_qmp(qts, "{'execute': 'device_add'," 109 "'arguments': {" 110 "'driver': 'virtio-net'," 111 "'id': 'primary0'," 112 "'bus': 'pcie.0'," 113 "'failover_pair_id': 'standby0'" 114 "} }"); 115 g_assert(qdict_haskey(resp, "error")); 116 117 err = qdict_get_qdict(resp, "error"); 118 g_assert(qdict_haskey(err, "desc")); 119 120 g_assert_cmpstr(qdict_get_str(err, "desc"), ==, 121 "Bus 'pcie.0' does not support hotplugging"); 122 123 qobject_unref(resp); 124 125 machine_stop(qts); 126 } 127 128 static QDict *find_device(QDict *bus, const char *name) 129 { 130 const QObject *obj; 131 QList *devices; 132 QList *list; 133 134 devices = qdict_get_qlist(bus, "devices"); 135 if (devices == NULL) { 136 return NULL; 137 } 138 139 list = qlist_copy(devices); 140 while ((obj = qlist_pop(list))) { 141 QDict *device; 142 143 device = qobject_to(QDict, obj); 144 145 if (qdict_haskey(device, "pci_bridge")) { 146 QDict *bridge; 147 QDict *bridge_device; 148 149 bridge = qdict_get_qdict(device, "pci_bridge"); 150 151 if (qdict_haskey(bridge, "devices")) { 152 bridge_device = find_device(bridge, name); 153 if (bridge_device) { 154 qobject_unref(device); 155 qobject_unref(list); 156 return bridge_device; 157 } 158 } 159 } 160 161 if (!qdict_haskey(device, "qdev_id")) { 162 qobject_unref(device); 163 continue; 164 } 165 166 if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) { 167 qobject_unref(list); 168 return device; 169 } 170 qobject_unref(device); 171 } 172 qobject_unref(list); 173 174 return NULL; 175 } 176 177 static QDict *get_bus(QTestState *qts, int num) 178 { 179 QObject *obj; 180 QDict *resp; 181 QList *ret; 182 183 resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }"); 184 g_assert(qdict_haskey(resp, "return")); 185 186 ret = qdict_get_qlist(resp, "return"); 187 g_assert_nonnull(ret); 188 189 while ((obj = qlist_pop(ret))) { 190 QDict *bus; 191 192 bus = qobject_to(QDict, obj); 193 if (!qdict_haskey(bus, "bus")) { 194 qobject_unref(bus); 195 continue; 196 } 197 if (qdict_get_int(bus, "bus") == num) { 198 qobject_unref(resp); 199 return bus; 200 } 201 qobject_ref(bus); 202 } 203 qobject_unref(resp); 204 205 return NULL; 206 } 207 208 static char *get_mac(QTestState *qts, const char *name) 209 { 210 QDict *resp; 211 char *mac; 212 213 resp = qtest_qmp(qts, "{ 'execute': 'qom-get', " 214 "'arguments': { " 215 "'path': %s, " 216 "'property': 'mac' } }", name); 217 218 g_assert(qdict_haskey(resp, "return")); 219 220 mac = g_strdup(qdict_get_str(resp, "return")); 221 222 qobject_unref(resp); 223 224 return mac; 225 } 226 227 static void check_one_card(QTestState *qts, bool present, 228 const char *id, const char *mac) 229 { 230 QDict *device; 231 QDict *bus; 232 char *addr; 233 234 bus = get_bus(qts, 0); 235 device = find_device(bus, id); 236 if (present) { 237 char *path; 238 239 g_assert_nonnull(device); 240 qobject_unref(device); 241 242 path = g_strdup_printf("/machine/peripheral/%s", id); 243 addr = get_mac(qts, path); 244 g_free(path); 245 g_assert_cmpstr(mac, ==, addr); 246 g_free(addr); 247 } else { 248 g_assert_null(device); 249 } 250 251 qobject_unref(bus); 252 } 253 254 static void test_on(void) 255 { 256 QTestState *qts; 257 258 qts = machine_start(BASE_MACHINE 259 "-netdev user,id=hs0 " 260 "-device virtio-net,bus=root0,id=standby0," 261 "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 262 "-device virtio-net,bus=root1,id=primary0," 263 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0, 264 2); 265 266 check_one_card(qts, true, "standby0", MAC_STANDBY0); 267 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 268 269 machine_stop(qts); 270 } 271 272 static void test_on_mismatch(void) 273 { 274 QTestState *qts; 275 276 qts = machine_start(BASE_MACHINE 277 "-netdev user,id=hs0 " 278 "-device virtio-net,bus=root0,id=standby0," 279 "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 280 "-netdev user,id=hs1 " 281 "-device virtio-net,bus=root1,id=primary0," 282 "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0, 283 2); 284 285 check_one_card(qts, true, "standby0", MAC_STANDBY0); 286 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 287 288 machine_stop(qts); 289 } 290 291 static void test_off(void) 292 { 293 QTestState *qts; 294 295 qts = machine_start(BASE_MACHINE 296 "-netdev user,id=hs0 " 297 "-device virtio-net,bus=root0,id=standby0," 298 "failover=off,netdev=hs0,mac="MAC_STANDBY0" " 299 "-netdev user,id=hs1 " 300 "-device virtio-net,bus=root1,id=primary0," 301 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0, 302 2); 303 304 check_one_card(qts, true, "standby0", MAC_STANDBY0); 305 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 306 307 machine_stop(qts); 308 } 309 310 static QDict *get_failover_negociated_event(QTestState *qts) 311 { 312 QDict *resp; 313 QDict *data; 314 315 resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED"); 316 g_assert(qdict_haskey(resp, "data")); 317 318 data = qdict_get_qdict(resp, "data"); 319 g_assert(qdict_haskey(data, "device-id")); 320 qobject_ref(data); 321 qobject_unref(resp); 322 323 return data; 324 } 325 326 static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot, 327 const char *id) 328 { 329 QVirtioPCIDevice *dev; 330 uint64_t features; 331 QPCIAddress addr; 332 QDict *resp; 333 334 addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0); 335 dev = virtio_pci_new(pcibus, &addr); 336 g_assert_nonnull(dev); 337 qvirtio_pci_device_enable(dev); 338 qvirtio_start_device(&dev->vdev); 339 features = qvirtio_get_features(&dev->vdev); 340 features = features & ~(QVIRTIO_F_BAD_FEATURE | 341 (1ull << VIRTIO_RING_F_INDIRECT_DESC) | 342 (1ull << VIRTIO_RING_F_EVENT_IDX)); 343 qvirtio_set_features(&dev->vdev, features); 344 qvirtio_set_driver_ok(&dev->vdev); 345 346 resp = get_failover_negociated_event(qts); 347 g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id); 348 qobject_unref(resp); 349 350 return dev; 351 } 352 353 static void test_enabled(void) 354 { 355 QTestState *qts; 356 QVirtioPCIDevice *vdev; 357 358 qts = machine_start(BASE_MACHINE 359 "-netdev user,id=hs0 " 360 "-device virtio-net,bus=root0,id=standby0," 361 "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 362 "-netdev user,id=hs1 " 363 "-device virtio-net,bus=root1,id=primary0," 364 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ", 365 2); 366 367 check_one_card(qts, true, "standby0", MAC_STANDBY0); 368 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 369 370 vdev = start_virtio_net(qts, 1, 0, "standby0"); 371 372 check_one_card(qts, true, "standby0", MAC_STANDBY0); 373 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 374 375 qos_object_destroy((QOSGraphObject *)vdev); 376 machine_stop(qts); 377 } 378 379 static void test_hotplug_1(void) 380 { 381 QTestState *qts; 382 QVirtioPCIDevice *vdev; 383 384 qts = machine_start(BASE_MACHINE 385 "-netdev user,id=hs0 " 386 "-device virtio-net,bus=root0,id=standby0," 387 "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 388 "-netdev user,id=hs1 ", 2); 389 390 check_one_card(qts, true, "standby0", MAC_STANDBY0); 391 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 392 393 vdev = start_virtio_net(qts, 1, 0, "standby0"); 394 395 check_one_card(qts, true, "standby0", MAC_STANDBY0); 396 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 397 398 qtest_qmp_device_add(qts, "virtio-net", "primary0", 399 "{'bus': 'root1'," 400 "'failover_pair_id': 'standby0'," 401 "'netdev': 'hs1'," 402 "'mac': '"MAC_PRIMARY0"'}"); 403 404 check_one_card(qts, true, "standby0", MAC_STANDBY0); 405 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 406 407 qos_object_destroy((QOSGraphObject *)vdev); 408 machine_stop(qts); 409 } 410 411 static void test_hotplug_1_reverse(void) 412 { 413 QTestState *qts; 414 QVirtioPCIDevice *vdev; 415 416 qts = machine_start(BASE_MACHINE 417 "-netdev user,id=hs0 " 418 "-netdev user,id=hs1 " 419 "-device virtio-net,bus=root1,id=primary0," 420 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ", 421 2); 422 423 check_one_card(qts, false, "standby0", MAC_STANDBY0); 424 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 425 426 qtest_qmp_device_add(qts, "virtio-net", "standby0", 427 "{'bus': 'root0'," 428 "'failover': 'on'," 429 "'netdev': 'hs0'," 430 "'mac': '"MAC_STANDBY0"'}"); 431 432 check_one_card(qts, true, "standby0", MAC_STANDBY0); 433 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 434 435 vdev = start_virtio_net(qts, 1, 0, "standby0"); 436 437 check_one_card(qts, true, "standby0", MAC_STANDBY0); 438 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 439 440 qos_object_destroy((QOSGraphObject *)vdev); 441 machine_stop(qts); 442 } 443 444 static void test_hotplug_2(void) 445 { 446 QTestState *qts; 447 QVirtioPCIDevice *vdev; 448 449 qts = machine_start(BASE_MACHINE 450 "-netdev user,id=hs0 " 451 "-netdev user,id=hs1 ", 452 2); 453 454 check_one_card(qts, false, "standby0", MAC_STANDBY0); 455 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 456 457 qtest_qmp_device_add(qts, "virtio-net", "standby0", 458 "{'bus': 'root0'," 459 "'failover': 'on'," 460 "'netdev': 'hs0'," 461 "'mac': '"MAC_STANDBY0"'}"); 462 463 check_one_card(qts, true, "standby0", MAC_STANDBY0); 464 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 465 466 vdev = start_virtio_net(qts, 1, 0, "standby0"); 467 468 check_one_card(qts, true, "standby0", MAC_STANDBY0); 469 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 470 471 qtest_qmp_device_add(qts, "virtio-net", "primary0", 472 "{'bus': 'root1'," 473 "'failover_pair_id': 'standby0'," 474 "'netdev': 'hs1'," 475 "'mac': '"MAC_PRIMARY0"'}"); 476 477 check_one_card(qts, true, "standby0", MAC_STANDBY0); 478 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 479 480 qos_object_destroy((QOSGraphObject *)vdev); 481 machine_stop(qts); 482 } 483 484 static void test_hotplug_2_reverse(void) 485 { 486 QTestState *qts; 487 QVirtioPCIDevice *vdev; 488 489 qts = machine_start(BASE_MACHINE 490 "-netdev user,id=hs0 " 491 "-netdev user,id=hs1 ", 492 2); 493 494 check_one_card(qts, false, "standby0", MAC_STANDBY0); 495 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 496 497 qtest_qmp_device_add(qts, "virtio-net", "primary0", 498 "{'bus': 'root1'," 499 "'failover_pair_id': 'standby0'," 500 "'netdev': 'hs1'," 501 "'mac': '"MAC_PRIMARY0"'}"); 502 503 check_one_card(qts, false, "standby0", MAC_STANDBY0); 504 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 505 506 qtest_qmp_device_add(qts, "virtio-net", "standby0", 507 "{'bus': 'root0'," 508 "'failover': 'on'," 509 "'netdev': 'hs0'," 510 "'rombar': 0," 511 "'romfile': ''," 512 "'mac': '"MAC_STANDBY0"'}"); 513 514 /* 515 * XXX: sounds like a bug: 516 * The primary should be hidden until the virtio-net driver 517 * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net() 518 */ 519 check_one_card(qts, true, "standby0", MAC_STANDBY0); 520 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 521 522 vdev = start_virtio_net(qts, 1, 0, "standby0"); 523 524 check_one_card(qts, true, "standby0", MAC_STANDBY0); 525 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 526 527 qos_object_destroy((QOSGraphObject *)vdev); 528 machine_stop(qts); 529 } 530 531 static QDict *migrate_status(QTestState *qts) 532 { 533 QDict *resp, *ret; 534 535 resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }"); 536 g_assert(qdict_haskey(resp, "return")); 537 538 ret = qdict_get_qdict(resp, "return"); 539 g_assert(qdict_haskey(ret, "status")); 540 qobject_ref(ret); 541 qobject_unref(resp); 542 543 return ret; 544 } 545 546 static QDict *get_unplug_primary_event(QTestState *qts) 547 { 548 QDict *resp; 549 QDict *data; 550 551 resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY"); 552 g_assert(qdict_haskey(resp, "data")); 553 554 data = qdict_get_qdict(resp, "data"); 555 g_assert(qdict_haskey(data, "device-id")); 556 qobject_ref(data); 557 qobject_unref(resp); 558 559 return data; 560 } 561 562 static void test_migrate_out(gconstpointer opaque) 563 { 564 QTestState *qts; 565 QDict *resp, *args, *ret; 566 g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 567 const gchar *status; 568 QVirtioPCIDevice *vdev; 569 570 qts = machine_start(BASE_MACHINE 571 "-netdev user,id=hs0 " 572 "-netdev user,id=hs1 ", 573 2); 574 575 check_one_card(qts, false, "standby0", MAC_STANDBY0); 576 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 577 578 qtest_qmp_device_add(qts, "virtio-net", "standby0", 579 "{'bus': 'root0'," 580 "'failover': 'on'," 581 "'netdev': 'hs0'," 582 "'mac': '"MAC_STANDBY0"'}"); 583 584 check_one_card(qts, true, "standby0", MAC_STANDBY0); 585 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 586 587 vdev = start_virtio_net(qts, 1, 0, "standby0"); 588 589 check_one_card(qts, true, "standby0", MAC_STANDBY0); 590 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 591 592 qtest_qmp_device_add(qts, "virtio-net", "primary0", 593 "{'bus': 'root1'," 594 "'failover_pair_id': 'standby0'," 595 "'netdev': 'hs1'," 596 "'rombar': 0," 597 "'romfile': ''," 598 "'mac': '"MAC_PRIMARY0"'}"); 599 600 check_one_card(qts, true, "standby0", MAC_STANDBY0); 601 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 602 603 args = qdict_from_jsonf_nofail("{}"); 604 g_assert_nonnull(args); 605 qdict_put_str(args, "uri", uri); 606 607 resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 608 g_assert(qdict_haskey(resp, "return")); 609 qobject_unref(resp); 610 611 /* the event is sent when QEMU asks the OS to unplug the card */ 612 resp = get_unplug_primary_event(qts); 613 g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 614 qobject_unref(resp); 615 616 /* wait the end of the migration setup phase */ 617 while (true) { 618 ret = migrate_status(qts); 619 620 status = qdict_get_str(ret, "status"); 621 if (strcmp(status, "wait-unplug") == 0) { 622 qobject_unref(ret); 623 break; 624 } 625 626 /* The migration must not start if the card is not ejected */ 627 g_assert_cmpstr(status, !=, "active"); 628 g_assert_cmpstr(status, !=, "completed"); 629 g_assert_cmpstr(status, !=, "failed"); 630 g_assert_cmpstr(status, !=, "cancelling"); 631 g_assert_cmpstr(status, !=, "cancelled"); 632 633 qobject_unref(ret); 634 } 635 636 if (g_test_slow()) { 637 /* check we stay in wait-unplug while the card is not ejected */ 638 for (int i = 0; i < 5; i++) { 639 sleep(1); 640 ret = migrate_status(qts); 641 status = qdict_get_str(ret, "status"); 642 g_assert_cmpstr(status, ==, "wait-unplug"); 643 qobject_unref(ret); 644 } 645 } 646 647 /* OS unplugs the cards, QEMU can move from wait-unplug state */ 648 qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 649 650 while (true) { 651 ret = migrate_status(qts); 652 653 status = qdict_get_str(ret, "status"); 654 if (strcmp(status, "completed") == 0) { 655 qobject_unref(ret); 656 break; 657 } 658 g_assert_cmpstr(status, !=, "failed"); 659 g_assert_cmpstr(status, !=, "cancelling"); 660 g_assert_cmpstr(status, !=, "cancelled"); 661 qobject_unref(ret); 662 } 663 664 qtest_qmp_eventwait(qts, "STOP"); 665 666 /* 667 * in fact, the card is ejected from the point of view of kernel 668 * but not really from QEMU to be able to hotplug it back if 669 * migration fails. So we can't check that: 670 * check_one_card(qts, true, "standby0", MAC_STANDBY0); 671 * check_one_card(qts, false, "primary0", MAC_PRIMARY0); 672 */ 673 674 qos_object_destroy((QOSGraphObject *)vdev); 675 machine_stop(qts); 676 } 677 678 static QDict *get_migration_event(QTestState *qts) 679 { 680 QDict *resp; 681 QDict *data; 682 683 resp = qtest_qmp_eventwait_ref(qts, "MIGRATION"); 684 g_assert(qdict_haskey(resp, "data")); 685 686 data = qdict_get_qdict(resp, "data"); 687 g_assert(qdict_haskey(data, "status")); 688 qobject_ref(data); 689 qobject_unref(resp); 690 691 return data; 692 } 693 694 static void test_migrate_in(gconstpointer opaque) 695 { 696 QTestState *qts; 697 QDict *resp, *args, *ret; 698 g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); 699 700 qts = machine_start(BASE_MACHINE 701 "-netdev user,id=hs0 " 702 "-netdev user,id=hs1 " 703 "-incoming defer ", 704 2); 705 706 check_one_card(qts, false, "standby0", MAC_STANDBY0); 707 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 708 709 qtest_qmp_device_add(qts, "virtio-net", "standby0", 710 "{'bus': 'root0'," 711 "'failover': 'on'," 712 "'netdev': 'hs0'," 713 "'mac': '"MAC_STANDBY0"'}"); 714 715 check_one_card(qts, true, "standby0", MAC_STANDBY0); 716 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 717 718 qtest_qmp_device_add(qts, "virtio-net", "primary0", 719 "{'bus': 'root1'," 720 "'failover_pair_id': 'standby0'," 721 "'netdev': 'hs1'," 722 "'rombar': 0," 723 "'romfile': ''," 724 "'mac': '"MAC_PRIMARY0"'}"); 725 726 check_one_card(qts, true, "standby0", MAC_STANDBY0); 727 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 728 729 args = qdict_from_jsonf_nofail("{}"); 730 g_assert_nonnull(args); 731 qdict_put_str(args, "uri", uri); 732 733 resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", 734 args); 735 g_assert(qdict_haskey(resp, "return")); 736 qobject_unref(resp); 737 738 resp = get_migration_event(qts); 739 g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); 740 qobject_unref(resp); 741 742 resp = get_failover_negociated_event(qts); 743 g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0"); 744 qobject_unref(resp); 745 746 check_one_card(qts, true, "standby0", MAC_STANDBY0); 747 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 748 749 qtest_qmp_eventwait(qts, "RESUME"); 750 751 ret = migrate_status(qts); 752 g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed"); 753 qobject_unref(ret); 754 755 machine_stop(qts); 756 } 757 758 static void test_migrate_abort_wait_unplug(gconstpointer opaque) 759 { 760 QTestState *qts; 761 QDict *resp, *args, *ret; 762 g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 763 const gchar *status; 764 QVirtioPCIDevice *vdev; 765 766 qts = machine_start(BASE_MACHINE 767 "-netdev user,id=hs0 " 768 "-netdev user,id=hs1 ", 769 2); 770 771 check_one_card(qts, false, "standby0", MAC_STANDBY0); 772 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 773 774 qtest_qmp_device_add(qts, "virtio-net", "standby0", 775 "{'bus': 'root0'," 776 "'failover': 'on'," 777 "'netdev': 'hs0'," 778 "'mac': '"MAC_STANDBY0"'}"); 779 780 check_one_card(qts, true, "standby0", MAC_STANDBY0); 781 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 782 783 vdev = start_virtio_net(qts, 1, 0, "standby0"); 784 785 check_one_card(qts, true, "standby0", MAC_STANDBY0); 786 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 787 788 qtest_qmp_device_add(qts, "virtio-net", "primary0", 789 "{'bus': 'root1'," 790 "'failover_pair_id': 'standby0'," 791 "'netdev': 'hs1'," 792 "'rombar': 0," 793 "'romfile': ''," 794 "'mac': '"MAC_PRIMARY0"'}"); 795 796 check_one_card(qts, true, "standby0", MAC_STANDBY0); 797 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 798 799 args = qdict_from_jsonf_nofail("{}"); 800 g_assert_nonnull(args); 801 qdict_put_str(args, "uri", uri); 802 803 resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 804 g_assert(qdict_haskey(resp, "return")); 805 qobject_unref(resp); 806 807 /* the event is sent when QEMU asks the OS to unplug the card */ 808 resp = get_unplug_primary_event(qts); 809 g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 810 qobject_unref(resp); 811 812 resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); 813 g_assert(qdict_haskey(resp, "return")); 814 qobject_unref(resp); 815 816 /* migration has been cancelled while the unplug was in progress */ 817 818 /* while the card is not ejected, we must be in "cancelling" state */ 819 ret = migrate_status(qts); 820 821 status = qdict_get_str(ret, "status"); 822 g_assert_cmpstr(status, ==, "cancelling"); 823 qobject_unref(ret); 824 825 /* OS unplugs the cards, QEMU can move from wait-unplug state */ 826 qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 827 828 while (true) { 829 ret = migrate_status(qts); 830 831 status = qdict_get_str(ret, "status"); 832 if (strcmp(status, "cancelled") == 0) { 833 qobject_unref(ret); 834 break; 835 } 836 g_assert_cmpstr(status, !=, "failed"); 837 g_assert_cmpstr(status, !=, "active"); 838 qobject_unref(ret); 839 } 840 841 check_one_card(qts, true, "standby0", MAC_STANDBY0); 842 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 843 844 qos_object_destroy((QOSGraphObject *)vdev); 845 machine_stop(qts); 846 } 847 848 static void test_migrate_abort_active(gconstpointer opaque) 849 { 850 QTestState *qts; 851 QDict *resp, *args, *ret; 852 g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 853 const gchar *status; 854 QVirtioPCIDevice *vdev; 855 856 qts = machine_start(BASE_MACHINE 857 "-netdev user,id=hs0 " 858 "-netdev user,id=hs1 ", 859 2); 860 861 check_one_card(qts, false, "standby0", MAC_STANDBY0); 862 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 863 864 qtest_qmp_device_add(qts, "virtio-net", "standby0", 865 "{'bus': 'root0'," 866 "'failover': 'on'," 867 "'netdev': 'hs0'," 868 "'mac': '"MAC_STANDBY0"'}"); 869 870 check_one_card(qts, true, "standby0", MAC_STANDBY0); 871 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 872 873 vdev = start_virtio_net(qts, 1, 0, "standby0"); 874 875 check_one_card(qts, true, "standby0", MAC_STANDBY0); 876 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 877 878 qtest_qmp_device_add(qts, "virtio-net", "primary0", 879 "{'bus': 'root1'," 880 "'failover_pair_id': 'standby0'," 881 "'netdev': 'hs1'," 882 "'rombar': 0," 883 "'romfile': ''," 884 "'mac': '"MAC_PRIMARY0"'}"); 885 886 check_one_card(qts, true, "standby0", MAC_STANDBY0); 887 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 888 889 args = qdict_from_jsonf_nofail("{}"); 890 g_assert_nonnull(args); 891 qdict_put_str(args, "uri", uri); 892 893 resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 894 g_assert(qdict_haskey(resp, "return")); 895 qobject_unref(resp); 896 897 /* the event is sent when QEMU asks the OS to unplug the card */ 898 resp = get_unplug_primary_event(qts); 899 g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 900 qobject_unref(resp); 901 902 /* OS unplugs the cards, QEMU can move from wait-unplug state */ 903 qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 904 905 while (true) { 906 ret = migrate_status(qts); 907 908 status = qdict_get_str(ret, "status"); 909 if (strcmp(status, "wait-unplug") != 0) { 910 qobject_unref(ret); 911 break; 912 } 913 g_assert_cmpstr(status, !=, "failed"); 914 qobject_unref(ret); 915 } 916 917 resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); 918 g_assert(qdict_haskey(resp, "return")); 919 qobject_unref(resp); 920 921 while (true) { 922 ret = migrate_status(qts); 923 924 status = qdict_get_str(ret, "status"); 925 if (strcmp(status, "cancelled") == 0) { 926 qobject_unref(ret); 927 break; 928 } 929 g_assert_cmpstr(status, !=, "failed"); 930 g_assert_cmpstr(status, !=, "active"); 931 qobject_unref(ret); 932 } 933 934 check_one_card(qts, true, "standby0", MAC_STANDBY0); 935 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 936 937 qos_object_destroy((QOSGraphObject *)vdev); 938 machine_stop(qts); 939 } 940 941 static void test_migrate_abort_timeout(gconstpointer opaque) 942 { 943 QTestState *qts; 944 QDict *resp, *args, *ret; 945 g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 946 const gchar *status; 947 int total; 948 QVirtioPCIDevice *vdev; 949 950 qts = machine_start(BASE_MACHINE 951 "-netdev user,id=hs0 " 952 "-netdev user,id=hs1 ", 953 2); 954 955 check_one_card(qts, false, "standby0", MAC_STANDBY0); 956 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 957 958 qtest_qmp_device_add(qts, "virtio-net", "standby0", 959 "{'bus': 'root0'," 960 "'failover': 'on'," 961 "'netdev': 'hs0'," 962 "'mac': '"MAC_STANDBY0"'}"); 963 964 check_one_card(qts, true, "standby0", MAC_STANDBY0); 965 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 966 967 vdev = start_virtio_net(qts, 1, 0, "standby0"); 968 969 check_one_card(qts, true, "standby0", MAC_STANDBY0); 970 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 971 972 qtest_qmp_device_add(qts, "virtio-net", "primary0", 973 "{'bus': 'root1'," 974 "'failover_pair_id': 'standby0'," 975 "'netdev': 'hs1'," 976 "'rombar': 0," 977 "'romfile': ''," 978 "'mac': '"MAC_PRIMARY0"'}"); 979 980 check_one_card(qts, true, "standby0", MAC_STANDBY0); 981 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 982 983 args = qdict_from_jsonf_nofail("{}"); 984 g_assert_nonnull(args); 985 qdict_put_str(args, "uri", uri); 986 987 resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 988 g_assert(qdict_haskey(resp, "return")); 989 qobject_unref(resp); 990 991 /* the event is sent when QEMU asks the OS to unplug the card */ 992 resp = get_unplug_primary_event(qts); 993 g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 994 qobject_unref(resp); 995 996 resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); 997 g_assert(qdict_haskey(resp, "return")); 998 qobject_unref(resp); 999 1000 /* migration has been cancelled while the unplug was in progress */ 1001 1002 /* while the card is not ejected, we must be in "cancelling" state */ 1003 1004 total = 0; 1005 while (true) { 1006 ret = migrate_status(qts); 1007 1008 status = qdict_get_str(ret, "status"); 1009 if (strcmp(status, "cancelled") == 0) { 1010 qobject_unref(ret); 1011 break; 1012 } 1013 g_assert_cmpstr(status, ==, "cancelling"); 1014 g_assert(qdict_haskey(ret, "total-time")); 1015 total = qdict_get_int(ret, "total-time"); 1016 qobject_unref(ret); 1017 } 1018 1019 /* 1020 * migration timeout in this case is 30 seconds 1021 * check we exit on the timeout (ms) 1022 */ 1023 g_assert_cmpint(total, >, 30000); 1024 1025 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1026 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1027 1028 qos_object_destroy((QOSGraphObject *)vdev); 1029 machine_stop(qts); 1030 } 1031 1032 static void test_multi_out(gconstpointer opaque) 1033 { 1034 QTestState *qts; 1035 QDict *resp, *args, *ret; 1036 g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 1037 const gchar *status, *expected; 1038 QVirtioPCIDevice *vdev0, *vdev1; 1039 1040 qts = machine_start(BASE_MACHINE 1041 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 " 1042 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 " 1043 "-netdev user,id=hs0 " 1044 "-netdev user,id=hs1 " 1045 "-netdev user,id=hs2 " 1046 "-netdev user,id=hs3 ", 1047 4); 1048 1049 check_one_card(qts, false, "standby0", MAC_STANDBY0); 1050 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1051 check_one_card(qts, false, "standby1", MAC_STANDBY1); 1052 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1053 1054 qtest_qmp_device_add(qts, "virtio-net", "standby0", 1055 "{'bus': 'root0'," 1056 "'failover': 'on'," 1057 "'netdev': 'hs0'," 1058 "'mac': '"MAC_STANDBY0"'}"); 1059 1060 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1061 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1062 check_one_card(qts, false, "standby1", MAC_STANDBY1); 1063 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1064 1065 qtest_qmp_device_add(qts, "virtio-net", "primary0", 1066 "{'bus': 'root1'," 1067 "'failover_pair_id': 'standby0'," 1068 "'netdev': 'hs1'," 1069 "'rombar': 0," 1070 "'romfile': ''," 1071 "'mac': '"MAC_PRIMARY0"'}"); 1072 1073 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1074 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1075 check_one_card(qts, false, "standby1", MAC_STANDBY1); 1076 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1077 1078 vdev0 = start_virtio_net(qts, 1, 0, "standby0"); 1079 1080 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1081 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1082 check_one_card(qts, false, "standby1", MAC_STANDBY1); 1083 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1084 1085 qtest_qmp_device_add(qts, "virtio-net", "standby1", 1086 "{'bus': 'root2'," 1087 "'failover': 'on'," 1088 "'netdev': 'hs2'," 1089 "'mac': '"MAC_STANDBY1"'}"); 1090 1091 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1092 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1093 check_one_card(qts, true, "standby1", MAC_STANDBY1); 1094 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1095 1096 qtest_qmp_device_add(qts, "virtio-net", "primary1", 1097 "{'bus': 'root3'," 1098 "'failover_pair_id': 'standby1'," 1099 "'netdev': 'hs3'," 1100 "'rombar': 0," 1101 "'romfile': ''," 1102 "'mac': '"MAC_PRIMARY1"'}"); 1103 1104 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1105 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1106 check_one_card(qts, true, "standby1", MAC_STANDBY1); 1107 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1108 1109 vdev1 = start_virtio_net(qts, 3, 0, "standby1"); 1110 1111 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1112 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1113 check_one_card(qts, true, "standby1", MAC_STANDBY1); 1114 check_one_card(qts, true, "primary1", MAC_PRIMARY1); 1115 1116 args = qdict_from_jsonf_nofail("{}"); 1117 g_assert_nonnull(args); 1118 qdict_put_str(args, "uri", uri); 1119 1120 resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 1121 g_assert(qdict_haskey(resp, "return")); 1122 qobject_unref(resp); 1123 1124 /* the event is sent when QEMU asks the OS to unplug the card */ 1125 resp = get_unplug_primary_event(qts); 1126 if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) { 1127 expected = "primary1"; 1128 } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) { 1129 expected = "primary0"; 1130 } else { 1131 g_assert_not_reached(); 1132 } 1133 qobject_unref(resp); 1134 1135 resp = get_unplug_primary_event(qts); 1136 g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected); 1137 qobject_unref(resp); 1138 1139 /* wait the end of the migration setup phase */ 1140 while (true) { 1141 ret = migrate_status(qts); 1142 1143 status = qdict_get_str(ret, "status"); 1144 if (strcmp(status, "wait-unplug") == 0) { 1145 qobject_unref(ret); 1146 break; 1147 } 1148 1149 /* The migration must not start if the card is not ejected */ 1150 g_assert_cmpstr(status, !=, "active"); 1151 g_assert_cmpstr(status, !=, "completed"); 1152 g_assert_cmpstr(status, !=, "failed"); 1153 g_assert_cmpstr(status, !=, "cancelling"); 1154 g_assert_cmpstr(status, !=, "cancelled"); 1155 1156 qobject_unref(ret); 1157 } 1158 1159 /* OS unplugs primary1, but we must wait the second */ 1160 qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 1161 1162 ret = migrate_status(qts); 1163 status = qdict_get_str(ret, "status"); 1164 g_assert_cmpstr(status, ==, "wait-unplug"); 1165 qobject_unref(ret); 1166 1167 if (g_test_slow()) { 1168 /* check we stay in wait-unplug while the card is not ejected */ 1169 for (int i = 0; i < 5; i++) { 1170 sleep(1); 1171 ret = migrate_status(qts); 1172 status = qdict_get_str(ret, "status"); 1173 g_assert_cmpstr(status, ==, "wait-unplug"); 1174 qobject_unref(ret); 1175 } 1176 } 1177 1178 /* OS unplugs primary0, QEMU can move from wait-unplug state */ 1179 qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2); 1180 qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 1181 1182 while (true) { 1183 ret = migrate_status(qts); 1184 1185 status = qdict_get_str(ret, "status"); 1186 if (strcmp(status, "completed") == 0) { 1187 qobject_unref(ret); 1188 break; 1189 } 1190 g_assert_cmpstr(status, !=, "failed"); 1191 g_assert_cmpstr(status, !=, "cancelling"); 1192 g_assert_cmpstr(status, !=, "cancelled"); 1193 qobject_unref(ret); 1194 } 1195 1196 qtest_qmp_eventwait(qts, "STOP"); 1197 1198 qos_object_destroy((QOSGraphObject *)vdev0); 1199 qos_object_destroy((QOSGraphObject *)vdev1); 1200 machine_stop(qts); 1201 } 1202 1203 static void test_multi_in(gconstpointer opaque) 1204 { 1205 QTestState *qts; 1206 QDict *resp, *args, *ret; 1207 g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); 1208 1209 qts = machine_start(BASE_MACHINE 1210 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 " 1211 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 " 1212 "-netdev user,id=hs0 " 1213 "-netdev user,id=hs1 " 1214 "-netdev user,id=hs2 " 1215 "-netdev user,id=hs3 " 1216 "-incoming defer ", 1217 4); 1218 1219 check_one_card(qts, false, "standby0", MAC_STANDBY0); 1220 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1221 check_one_card(qts, false, "standby1", MAC_STANDBY1); 1222 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1223 1224 qtest_qmp_device_add(qts, "virtio-net", "standby0", 1225 "{'bus': 'root0'," 1226 "'failover': 'on'," 1227 "'netdev': 'hs0'," 1228 "'mac': '"MAC_STANDBY0"'}"); 1229 1230 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1231 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1232 check_one_card(qts, false, "standby1", MAC_STANDBY1); 1233 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1234 1235 qtest_qmp_device_add(qts, "virtio-net", "primary0", 1236 "{'bus': 'root1'," 1237 "'failover_pair_id': 'standby0'," 1238 "'netdev': 'hs1'," 1239 "'rombar': 0," 1240 "'romfile': ''," 1241 "'mac': '"MAC_PRIMARY0"'}"); 1242 1243 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1244 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1245 check_one_card(qts, false, "standby1", MAC_STANDBY1); 1246 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1247 1248 qtest_qmp_device_add(qts, "virtio-net", "standby1", 1249 "{'bus': 'root2'," 1250 "'failover': 'on'," 1251 "'netdev': 'hs2'," 1252 "'mac': '"MAC_STANDBY1"'}"); 1253 1254 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1255 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1256 check_one_card(qts, true, "standby1", MAC_STANDBY1); 1257 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1258 1259 qtest_qmp_device_add(qts, "virtio-net", "primary1", 1260 "{'bus': 'root3'," 1261 "'failover_pair_id': 'standby1'," 1262 "'netdev': 'hs3'," 1263 "'rombar': 0," 1264 "'romfile': ''," 1265 "'mac': '"MAC_PRIMARY1"'}"); 1266 1267 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1268 check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1269 check_one_card(qts, true, "standby1", MAC_STANDBY1); 1270 check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1271 1272 args = qdict_from_jsonf_nofail("{}"); 1273 g_assert_nonnull(args); 1274 qdict_put_str(args, "uri", uri); 1275 1276 resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", 1277 args); 1278 g_assert(qdict_haskey(resp, "return")); 1279 qobject_unref(resp); 1280 1281 resp = get_migration_event(qts); 1282 g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); 1283 qobject_unref(resp); 1284 1285 resp = get_failover_negociated_event(qts); 1286 g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0"); 1287 qobject_unref(resp); 1288 1289 resp = get_failover_negociated_event(qts); 1290 g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1"); 1291 qobject_unref(resp); 1292 1293 check_one_card(qts, true, "standby0", MAC_STANDBY0); 1294 check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1295 check_one_card(qts, true, "standby1", MAC_STANDBY1); 1296 check_one_card(qts, true, "primary1", MAC_PRIMARY1); 1297 1298 qtest_qmp_eventwait(qts, "RESUME"); 1299 1300 ret = migrate_status(qts); 1301 g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed"); 1302 qobject_unref(ret); 1303 1304 machine_stop(qts); 1305 } 1306 1307 int main(int argc, char **argv) 1308 { 1309 gchar *tmpfile; 1310 int ret; 1311 1312 g_test_init(&argc, &argv, NULL); 1313 1314 ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL); 1315 g_assert_true(ret >= 0); 1316 close(ret); 1317 1318 qtest_add_func("failover-virtio-net/params/error/id", test_error_id); 1319 qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie); 1320 qtest_add_func("failover-virtio-net/params/on", test_on); 1321 qtest_add_func("failover-virtio-net/params/on_mismatch", 1322 test_on_mismatch); 1323 qtest_add_func("failover-virtio-net/params/off", test_off); 1324 qtest_add_func("failover-virtio-net/params/enabled", test_enabled); 1325 qtest_add_func("failover-virtio-net/hotplug_1", test_hotplug_1); 1326 qtest_add_func("failover-virtio-net/hotplug_1_reverse", 1327 test_hotplug_1_reverse); 1328 qtest_add_func("failover-virtio-net/hotplug_2", test_hotplug_2); 1329 qtest_add_func("failover-virtio-net/hotplug_2_reverse", 1330 test_hotplug_2_reverse); 1331 qtest_add_data_func("failover-virtio-net/migrate/out", tmpfile, 1332 test_migrate_out); 1333 qtest_add_data_func("failover-virtio-net/migrate/in", tmpfile, 1334 test_migrate_in); 1335 qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug", 1336 tmpfile, test_migrate_abort_wait_unplug); 1337 qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile, 1338 test_migrate_abort_active); 1339 if (g_test_slow()) { 1340 qtest_add_data_func("failover-virtio-net/migrate/abort/timeout", 1341 tmpfile, test_migrate_abort_timeout); 1342 } 1343 qtest_add_data_func("failover-virtio-net/multi/out", 1344 tmpfile, test_multi_out); 1345 qtest_add_data_func("failover-virtio-net/multi/in", 1346 tmpfile, test_multi_in); 1347 1348 ret = g_test_run(); 1349 1350 unlink(tmpfile); 1351 g_free(tmpfile); 1352 1353 return ret; 1354 } 1355