2 * QTest testcase for virtio-net failover
4 * See docs/system/virtio-net-failover.rst
6 * Copyright (c) 2021 Red Hat, Inc.
8 * SPDX-License-Identifier: GPL-2.0-or-later
10 #include "qemu/osdep.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"
21 #define VIRTIO_NET_F_STANDBY 62
23 #define ACPI_PCIHP_ADDR_ICH9 0x0cc0
24 #define PCI_EJ_BASE 0x0008
25 #define PCI_SEL_BASE 0x0010
27 #define BASE_MACHINE "-M q35 -nodefaults " \
28 "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
29 "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "
31 #define MAC_PRIMARY0 "52:54:00:11:11:11"
32 #define MAC_STANDBY0 "52:54:00:22:22:22"
33 #define MAC_PRIMARY1 "52:54:00:33:33:33"
34 #define MAC_STANDBY1 "52:54:00:44:44:44"
36 static QGuestAllocator guest_malloc
;
37 static QPCIBus
*pcibus
;
39 static QTestState
*machine_start(const char *args
, int numbus
)
45 qts
= qtest_init(args
);
47 pc_alloc_init(&guest_malloc
, qts
, 0);
48 pcibus
= qpci_new_pc(qts
, &guest_malloc
);
49 g_assert(qpci_secondary_buses_init(pcibus
) == numbus
);
51 for (bus
= 1; bus
<= numbus
; bus
++) {
52 dev
= qpci_device_find(pcibus
, QPCI_DEVFN(bus
, 0));
53 g_assert_nonnull(dev
);
55 qpci_device_enable(dev
);
56 qpci_iomap(dev
, 4, NULL
);
64 static void machine_stop(QTestState
*qts
)
67 alloc_destroy(&guest_malloc
);
71 static void test_error_id(void)
77 qts
= machine_start(BASE_MACHINE
78 "-device virtio-net,bus=root0,id=standby0,failover=on",
81 resp
= qtest_qmp(qts
, "{'execute': 'device_add',"
83 "'driver': 'virtio-net',"
85 "'failover_pair_id': 'standby0'"
87 g_assert(qdict_haskey(resp
, "error"));
89 err
= qdict_get_qdict(resp
, "error");
90 g_assert(qdict_haskey(err
, "desc"));
92 g_assert_cmpstr(qdict_get_str(err
, "desc"), ==,
93 "Device with failover_pair_id needs to have id");
100 static void test_error_pcie(void)
106 qts
= machine_start(BASE_MACHINE
107 "-device virtio-net,bus=root0,id=standby0,failover=on",
110 resp
= qtest_qmp(qts
, "{'execute': 'device_add',"
112 "'driver': 'virtio-net',"
115 "'failover_pair_id': 'standby0'"
117 g_assert(qdict_haskey(resp
, "error"));
119 err
= qdict_get_qdict(resp
, "error");
120 g_assert(qdict_haskey(err
, "desc"));
122 g_assert_cmpstr(qdict_get_str(err
, "desc"), ==,
123 "Bus 'pcie.0' does not support hotplugging");
130 static QDict
*find_device(QDict
*bus
, const char *name
)
136 devices
= qdict_get_qlist(bus
, "devices");
137 if (devices
== NULL
) {
141 list
= qlist_copy(devices
);
142 while ((obj
= qlist_pop(list
))) {
145 device
= qobject_to(QDict
, obj
);
147 if (qdict_haskey(device
, "pci_bridge")) {
149 QDict
*bridge_device
;
151 bridge
= qdict_get_qdict(device
, "pci_bridge");
153 if (qdict_haskey(bridge
, "devices")) {
154 bridge_device
= find_device(bridge
, name
);
156 qobject_unref(device
);
158 return bridge_device
;
163 if (!qdict_haskey(device
, "qdev_id")) {
164 qobject_unref(device
);
168 if (strcmp(qdict_get_str(device
, "qdev_id"), name
) == 0) {
172 qobject_unref(device
);
179 static QDict
*get_bus(QTestState
*qts
, int num
)
185 resp
= qtest_qmp(qts
, "{ 'execute': 'query-pci' }");
186 g_assert(qdict_haskey(resp
, "return"));
188 ret
= qdict_get_qlist(resp
, "return");
189 g_assert_nonnull(ret
);
191 while ((obj
= qlist_pop(ret
))) {
194 bus
= qobject_to(QDict
, obj
);
195 if (!qdict_haskey(bus
, "bus")) {
199 if (qdict_get_int(bus
, "bus") == num
) {
210 static char *get_mac(QTestState
*qts
, const char *name
)
215 resp
= qtest_qmp(qts
, "{ 'execute': 'qom-get', "
218 "'property': 'mac' } }", name
);
220 g_assert(qdict_haskey(resp
, "return"));
222 mac
= g_strdup(qdict_get_str(resp
, "return"));
229 #define check_one_card(qts, present, id, mac) \
234 bus = get_bus(qts, 0); \
235 device = find_device(bus, id); \
238 g_assert_nonnull(device); \
239 qobject_unref(device); \
240 path = g_strdup_printf("/machine/peripheral/%s", id); \
241 addr = get_mac(qts, path); \
243 g_assert_cmpstr(mac, ==, addr); \
246 g_assert_null(device); \
248 qobject_unref(bus); \
251 static QDict
*get_failover_negociated_event(QTestState
*qts
)
256 resp
= qtest_qmp_eventwait_ref(qts
, "FAILOVER_NEGOTIATED");
257 g_assert(qdict_haskey(resp
, "data"));
259 data
= qdict_get_qdict(resp
, "data");
260 g_assert(qdict_haskey(data
, "device-id"));
267 static QVirtioPCIDevice
*start_virtio_net_internal(QTestState
*qts
,
271 QVirtioPCIDevice
*dev
;
274 addr
.devfn
= QPCI_DEVFN((bus
<< 5) + slot
, 0);
275 dev
= virtio_pci_new(pcibus
, &addr
);
276 g_assert_nonnull(dev
);
277 qvirtio_pci_device_enable(dev
);
278 qvirtio_start_device(&dev
->vdev
);
279 *features
&= qvirtio_get_features(&dev
->vdev
);
280 qvirtio_set_features(&dev
->vdev
, *features
);
281 qvirtio_set_driver_ok(&dev
->vdev
);
285 static QVirtioPCIDevice
*start_virtio_net(QTestState
*qts
, int bus
, int slot
,
286 const char *id
, bool failover
)
288 QVirtioPCIDevice
*dev
;
291 features
= ~(QVIRTIO_F_BAD_FEATURE
|
292 (1ull << VIRTIO_RING_F_INDIRECT_DESC
) |
293 (1ull << VIRTIO_RING_F_EVENT_IDX
));
295 dev
= start_virtio_net_internal(qts
, bus
, slot
, &features
);
297 g_assert(!!(features
& (1ull << VIRTIO_NET_F_STANDBY
)) == failover
);
302 resp
= get_failover_negociated_event(qts
);
303 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, id
);
310 static void test_on(void)
314 qts
= machine_start(BASE_MACHINE
315 "-netdev user,id=hs0 "
316 "-device virtio-net,bus=root0,id=standby0,"
317 "failover=on,netdev=hs0,mac="MAC_STANDBY0
" "
318 "-netdev user,id=hs1 "
319 "-device virtio-net,bus=root1,id=primary0,"
320 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0
,
323 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
324 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
329 static void test_on_mismatch(void)
332 QVirtioPCIDevice
*vdev
;
334 qts
= machine_start(BASE_MACHINE
335 "-netdev user,id=hs0 "
336 "-device virtio-net,bus=root0,id=standby0,"
337 "failover=on,netdev=hs0,mac="MAC_STANDBY0
" "
338 "-netdev user,id=hs1 "
339 "-device virtio-net,bus=root1,id=primary0,"
340 "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0
,
343 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
344 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
346 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
348 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
349 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
351 qos_object_destroy((QOSGraphObject
*)vdev
);
355 static void test_off(void)
358 QVirtioPCIDevice
*vdev
;
360 qts
= machine_start(BASE_MACHINE
361 "-netdev user,id=hs0 "
362 "-device virtio-net,bus=root0,id=standby0,"
363 "failover=off,netdev=hs0,mac="MAC_STANDBY0
" "
364 "-netdev user,id=hs1 "
365 "-device virtio-net,bus=root1,id=primary0,"
366 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0
,
369 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
370 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
372 vdev
= start_virtio_net(qts
, 1, 0, "standby0", false);
374 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
375 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
377 qos_object_destroy((QOSGraphObject
*)vdev
);
381 static void test_enabled(void)
384 QVirtioPCIDevice
*vdev
;
386 qts
= machine_start(BASE_MACHINE
387 "-netdev user,id=hs0 "
388 "-device virtio-net,bus=root0,id=standby0,"
389 "failover=on,netdev=hs0,mac="MAC_STANDBY0
" "
390 "-netdev user,id=hs1 "
391 "-device virtio-net,bus=root1,id=primary0,"
392 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0
" ",
395 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
396 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
398 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
400 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
401 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
403 qos_object_destroy((QOSGraphObject
*)vdev
);
407 static void test_guest_off(void)
410 QVirtioPCIDevice
*vdev
;
413 qts
= machine_start(BASE_MACHINE
414 "-netdev user,id=hs0 "
415 "-device virtio-net,bus=root0,id=standby0,"
416 "failover=on,netdev=hs0,mac="MAC_STANDBY0
" "
417 "-netdev user,id=hs1 "
418 "-device virtio-net,bus=root1,id=primary0,"
419 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0
" ",
422 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
423 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
425 features
= ~(QVIRTIO_F_BAD_FEATURE
|
426 (1ull << VIRTIO_RING_F_INDIRECT_DESC
) |
427 (1ull << VIRTIO_RING_F_EVENT_IDX
) |
428 (1ull << VIRTIO_NET_F_STANDBY
));
430 vdev
= start_virtio_net_internal(qts
, 1, 0, &features
);
432 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
433 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
435 qos_object_destroy((QOSGraphObject
*)vdev
);
439 static void test_hotplug_1(void)
442 QVirtioPCIDevice
*vdev
;
444 qts
= machine_start(BASE_MACHINE
445 "-netdev user,id=hs0 "
446 "-device virtio-net,bus=root0,id=standby0,"
447 "failover=on,netdev=hs0,mac="MAC_STANDBY0
" "
448 "-netdev user,id=hs1 ", 2);
450 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
451 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
453 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
455 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
456 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
458 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
460 "'failover_pair_id': 'standby0',"
462 "'mac': '"MAC_PRIMARY0
"'}");
464 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
465 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
467 qos_object_destroy((QOSGraphObject
*)vdev
);
471 static void test_hotplug_1_reverse(void)
474 QVirtioPCIDevice
*vdev
;
476 qts
= machine_start(BASE_MACHINE
477 "-netdev user,id=hs0 "
478 "-netdev user,id=hs1 "
479 "-device virtio-net,bus=root1,id=primary0,"
480 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0
" ",
483 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
484 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
486 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
490 "'mac': '"MAC_STANDBY0
"'}");
492 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
493 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
495 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
497 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
498 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
500 qos_object_destroy((QOSGraphObject
*)vdev
);
504 static void test_hotplug_2(void)
507 QVirtioPCIDevice
*vdev
;
509 qts
= machine_start(BASE_MACHINE
510 "-netdev user,id=hs0 "
511 "-netdev user,id=hs1 ",
514 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
515 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
517 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
521 "'mac': '"MAC_STANDBY0
"'}");
523 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
524 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
526 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
528 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
529 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
531 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
533 "'failover_pair_id': 'standby0',"
535 "'mac': '"MAC_PRIMARY0
"'}");
537 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
538 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
540 qos_object_destroy((QOSGraphObject
*)vdev
);
544 static void test_hotplug_2_reverse(void)
547 QVirtioPCIDevice
*vdev
;
549 qts
= machine_start(BASE_MACHINE
550 "-netdev user,id=hs0 "
551 "-netdev user,id=hs1 ",
554 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
555 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
557 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
559 "'failover_pair_id': 'standby0',"
561 "'mac': '"MAC_PRIMARY0
"'}");
563 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
564 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
566 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
572 "'mac': '"MAC_STANDBY0
"'}");
575 * XXX: sounds like a bug:
576 * The primary should be hidden until the virtio-net driver
577 * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
579 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
580 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
582 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
584 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
585 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
587 qos_object_destroy((QOSGraphObject
*)vdev
);
592 static QDict
*migrate_status(QTestState
*qts
)
596 resp
= qtest_qmp(qts
, "{ 'execute': 'query-migrate' }");
597 g_assert(qdict_haskey(resp
, "return"));
599 ret
= qdict_get_qdict(resp
, "return");
600 g_assert(qdict_haskey(ret
, "status"));
607 static QDict
*get_unplug_primary_event(QTestState
*qts
)
612 resp
= qtest_qmp_eventwait_ref(qts
, "UNPLUG_PRIMARY");
613 g_assert(qdict_haskey(resp
, "data"));
615 data
= qdict_get_qdict(resp
, "data");
616 g_assert(qdict_haskey(data
, "device-id"));
623 static void test_migrate_out(gconstpointer opaque
)
626 QDict
*resp
, *args
, *ret
;
627 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
629 QVirtioPCIDevice
*vdev
;
631 qts
= machine_start(BASE_MACHINE
632 "-netdev user,id=hs0 "
633 "-netdev user,id=hs1 ",
636 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
637 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
639 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
643 "'mac': '"MAC_STANDBY0
"'}");
645 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
646 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
648 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
650 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
651 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
653 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
655 "'failover_pair_id': 'standby0',"
659 "'mac': '"MAC_PRIMARY0
"'}");
661 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
662 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
664 args
= qdict_from_jsonf_nofail("{}");
665 g_assert_nonnull(args
);
666 qdict_put_str(args
, "uri", uri
);
668 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
669 g_assert(qdict_haskey(resp
, "return"));
672 /* the event is sent when QEMU asks the OS to unplug the card */
673 resp
= get_unplug_primary_event(qts
);
674 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "primary0");
677 /* wait the end of the migration setup phase */
679 ret
= migrate_status(qts
);
681 status
= qdict_get_str(ret
, "status");
682 if (strcmp(status
, "wait-unplug") == 0) {
687 /* The migration must not start if the card is not ejected */
688 g_assert_cmpstr(status
, !=, "active");
689 g_assert_cmpstr(status
, !=, "completed");
690 g_assert_cmpstr(status
, !=, "failed");
691 g_assert_cmpstr(status
, !=, "cancelling");
692 g_assert_cmpstr(status
, !=, "cancelled");
698 /* check we stay in wait-unplug while the card is not ejected */
699 for (int i
= 0; i
< 5; i
++) {
701 ret
= migrate_status(qts
);
702 status
= qdict_get_str(ret
, "status");
703 g_assert_cmpstr(status
, ==, "wait-unplug");
708 /* OS unplugs the cards, QEMU can move from wait-unplug state */
709 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_EJ_BASE
, 1);
712 ret
= migrate_status(qts
);
714 status
= qdict_get_str(ret
, "status");
715 if (strcmp(status
, "completed") == 0) {
719 g_assert_cmpstr(status
, !=, "failed");
720 g_assert_cmpstr(status
, !=, "cancelling");
721 g_assert_cmpstr(status
, !=, "cancelled");
725 qtest_qmp_eventwait(qts
, "STOP");
728 * in fact, the card is ejected from the point of view of kernel
729 * but not really from QEMU to be able to hotplug it back if
730 * migration fails. So we can't check that:
731 * check_one_card(qts, true, "standby0", MAC_STANDBY0);
732 * check_one_card(qts, false, "primary0", MAC_PRIMARY0);
735 qos_object_destroy((QOSGraphObject
*)vdev
);
739 static QDict
*get_migration_event(QTestState
*qts
)
744 resp
= qtest_qmp_eventwait_ref(qts
, "MIGRATION");
745 g_assert(qdict_haskey(resp
, "data"));
747 data
= qdict_get_qdict(resp
, "data");
748 g_assert(qdict_haskey(data
, "status"));
755 static void test_migrate_in(gconstpointer opaque
)
758 QDict
*resp
, *args
, *ret
;
759 g_autofree gchar
*uri
= g_strdup_printf("exec: cat %s", (gchar
*)opaque
);
761 qts
= machine_start(BASE_MACHINE
762 "-netdev user,id=hs0 "
763 "-netdev user,id=hs1 "
767 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
768 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
770 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
774 "'mac': '"MAC_STANDBY0
"'}");
776 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
777 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
779 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
781 "'failover_pair_id': 'standby0',"
785 "'mac': '"MAC_PRIMARY0
"'}");
787 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
788 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
790 args
= qdict_from_jsonf_nofail("{}");
791 g_assert_nonnull(args
);
792 qdict_put_str(args
, "uri", uri
);
794 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
796 g_assert(qdict_haskey(resp
, "return"));
799 resp
= get_migration_event(qts
);
800 g_assert_cmpstr(qdict_get_str(resp
, "status"), ==, "setup");
803 resp
= get_failover_negociated_event(qts
);
804 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "standby0");
807 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
808 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
810 qtest_qmp_eventwait(qts
, "RESUME");
812 ret
= migrate_status(qts
);
813 g_assert_cmpstr(qdict_get_str(ret
, "status"), ==, "completed");
819 static void test_off_migrate_out(gconstpointer opaque
)
822 QDict
*resp
, *args
, *ret
;
823 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
825 QVirtioPCIDevice
*vdev
;
827 qts
= machine_start(BASE_MACHINE
828 "-netdev user,id=hs0 "
829 "-netdev user,id=hs1 ",
832 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
833 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
835 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
839 "'mac': '"MAC_STANDBY0
"'}");
841 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
842 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
844 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
846 "'failover_pair_id': 'standby0',"
850 "'mac': '"MAC_PRIMARY0
"'}");
852 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
853 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
855 vdev
= start_virtio_net(qts
, 1, 0, "standby0", false);
857 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
858 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
860 args
= qdict_from_jsonf_nofail("{}");
861 g_assert_nonnull(args
);
862 qdict_put_str(args
, "uri", uri
);
864 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
865 g_assert(qdict_haskey(resp
, "return"));
869 ret
= migrate_status(qts
);
871 status
= qdict_get_str(ret
, "status");
872 if (strcmp(status
, "completed") == 0) {
876 g_assert_cmpstr(status
, !=, "failed");
877 g_assert_cmpstr(status
, !=, "cancelling");
878 g_assert_cmpstr(status
, !=, "cancelled");
882 qtest_qmp_eventwait(qts
, "STOP");
884 qos_object_destroy((QOSGraphObject
*)vdev
);
888 static void test_off_migrate_in(gconstpointer opaque
)
891 QDict
*resp
, *args
, *ret
;
892 g_autofree gchar
*uri
= g_strdup_printf("exec: cat %s", (gchar
*)opaque
);
894 qts
= machine_start(BASE_MACHINE
895 "-netdev user,id=hs0 "
896 "-netdev user,id=hs1 "
900 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
901 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
903 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
907 "'mac': '"MAC_STANDBY0
"'}");
909 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
910 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
912 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
914 "'failover_pair_id': 'standby0',"
918 "'mac': '"MAC_PRIMARY0
"'}");
920 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
921 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
923 args
= qdict_from_jsonf_nofail("{}");
924 g_assert_nonnull(args
);
925 qdict_put_str(args
, "uri", uri
);
927 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
929 g_assert(qdict_haskey(resp
, "return"));
932 resp
= get_migration_event(qts
);
933 g_assert_cmpstr(qdict_get_str(resp
, "status"), ==, "setup");
936 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
937 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
939 qtest_qmp_eventwait(qts
, "RESUME");
941 ret
= migrate_status(qts
);
942 g_assert_cmpstr(qdict_get_str(ret
, "status"), ==, "completed");
948 static void test_guest_off_migrate_out(gconstpointer opaque
)
951 QDict
*resp
, *args
, *ret
;
952 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
954 QVirtioPCIDevice
*vdev
;
957 qts
= machine_start(BASE_MACHINE
958 "-netdev user,id=hs0 "
959 "-netdev user,id=hs1 ",
962 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
963 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
965 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
969 "'mac': '"MAC_STANDBY0
"'}");
971 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
972 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
974 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
976 "'failover_pair_id': 'standby0',"
980 "'mac': '"MAC_PRIMARY0
"'}");
982 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
983 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
985 features
= ~(QVIRTIO_F_BAD_FEATURE
|
986 (1ull << VIRTIO_RING_F_INDIRECT_DESC
) |
987 (1ull << VIRTIO_RING_F_EVENT_IDX
) |
988 (1ull << VIRTIO_NET_F_STANDBY
));
990 vdev
= start_virtio_net_internal(qts
, 1, 0, &features
);
992 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
993 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
995 args
= qdict_from_jsonf_nofail("{}");
996 g_assert_nonnull(args
);
997 qdict_put_str(args
, "uri", uri
);
999 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1000 g_assert(qdict_haskey(resp
, "return"));
1001 qobject_unref(resp
);
1004 ret
= migrate_status(qts
);
1006 status
= qdict_get_str(ret
, "status");
1007 if (strcmp(status
, "completed") == 0) {
1011 g_assert_cmpstr(status
, !=, "failed");
1012 g_assert_cmpstr(status
, !=, "cancelling");
1013 g_assert_cmpstr(status
, !=, "cancelled");
1017 qtest_qmp_eventwait(qts
, "STOP");
1019 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1020 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1022 qos_object_destroy((QOSGraphObject
*)vdev
);
1026 static void test_guest_off_migrate_in(gconstpointer opaque
)
1029 QDict
*resp
, *args
, *ret
;
1030 g_autofree gchar
*uri
= g_strdup_printf("exec: cat %s", (gchar
*)opaque
);
1032 qts
= machine_start(BASE_MACHINE
1033 "-netdev user,id=hs0 "
1034 "-netdev user,id=hs1 "
1038 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1039 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1041 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1045 "'mac': '"MAC_STANDBY0
"'}");
1047 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1048 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1050 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1052 "'failover_pair_id': 'standby0',"
1056 "'mac': '"MAC_PRIMARY0
"'}");
1058 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1059 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1061 args
= qdict_from_jsonf_nofail("{}");
1062 g_assert_nonnull(args
);
1063 qdict_put_str(args
, "uri", uri
);
1065 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1067 g_assert(qdict_haskey(resp
, "return"));
1068 qobject_unref(resp
);
1070 resp
= get_migration_event(qts
);
1071 g_assert_cmpstr(qdict_get_str(resp
, "status"), ==, "setup");
1072 qobject_unref(resp
);
1074 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1075 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1077 qtest_qmp_eventwait(qts
, "RESUME");
1079 ret
= migrate_status(qts
);
1080 g_assert_cmpstr(qdict_get_str(ret
, "status"), ==, "completed");
1086 static void test_migrate_guest_off_abort(gconstpointer opaque
)
1089 QDict
*resp
, *args
, *ret
;
1090 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1091 const gchar
*status
;
1092 QVirtioPCIDevice
*vdev
;
1095 qts
= machine_start(BASE_MACHINE
1096 "-netdev user,id=hs0 "
1097 "-netdev user,id=hs1 ",
1100 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1101 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1103 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1107 "'mac': '"MAC_STANDBY0
"'}");
1109 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1110 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1112 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1114 "'failover_pair_id': 'standby0',"
1118 "'mac': '"MAC_PRIMARY0
"'}");
1120 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1121 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1123 features
= ~(QVIRTIO_F_BAD_FEATURE
|
1124 (1ull << VIRTIO_RING_F_INDIRECT_DESC
) |
1125 (1ull << VIRTIO_RING_F_EVENT_IDX
) |
1126 (1ull << VIRTIO_NET_F_STANDBY
));
1128 vdev
= start_virtio_net_internal(qts
, 1, 0, &features
);
1130 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1131 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1133 args
= qdict_from_jsonf_nofail("{}");
1134 g_assert_nonnull(args
);
1135 qdict_put_str(args
, "uri", uri
);
1137 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1138 g_assert(qdict_haskey(resp
, "return"));
1139 qobject_unref(resp
);
1142 ret
= migrate_status(qts
);
1144 status
= qdict_get_str(ret
, "status");
1145 if (strcmp(status
, "completed") == 0) {
1146 g_test_skip("Failed to cancel the migration");
1150 if (strcmp(status
, "active") == 0) {
1154 g_assert_cmpstr(status
, !=, "failed");
1158 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate_cancel' }");
1159 g_assert(qdict_haskey(resp
, "return"));
1160 qobject_unref(resp
);
1163 ret
= migrate_status(qts
);
1164 status
= qdict_get_str(ret
, "status");
1165 if (strcmp(status
, "completed") == 0) {
1166 g_test_skip("Failed to cancel the migration");
1170 if (strcmp(status
, "cancelled") == 0) {
1174 g_assert_cmpstr(status
, !=, "failed");
1175 g_assert_cmpstr(status
, !=, "active");
1179 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1180 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1183 qos_object_destroy((QOSGraphObject
*)vdev
);
1187 static void test_migrate_abort_wait_unplug(gconstpointer opaque
)
1190 QDict
*resp
, *args
, *ret
;
1191 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1192 const gchar
*status
;
1193 QVirtioPCIDevice
*vdev
;
1195 qts
= machine_start(BASE_MACHINE
1196 "-netdev user,id=hs0 "
1197 "-netdev user,id=hs1 ",
1200 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1201 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1203 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1207 "'mac': '"MAC_STANDBY0
"'}");
1209 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1210 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1212 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
1214 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1215 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1217 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1219 "'failover_pair_id': 'standby0',"
1223 "'mac': '"MAC_PRIMARY0
"'}");
1225 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1226 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1228 args
= qdict_from_jsonf_nofail("{}");
1229 g_assert_nonnull(args
);
1230 qdict_put_str(args
, "uri", uri
);
1232 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1233 g_assert(qdict_haskey(resp
, "return"));
1234 qobject_unref(resp
);
1236 /* the event is sent when QEMU asks the OS to unplug the card */
1237 resp
= get_unplug_primary_event(qts
);
1238 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "primary0");
1239 qobject_unref(resp
);
1241 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate_cancel' }");
1242 g_assert(qdict_haskey(resp
, "return"));
1243 qobject_unref(resp
);
1245 /* migration has been cancelled while the unplug was in progress */
1247 /* while the card is not ejected, we must be in "cancelling" state */
1248 ret
= migrate_status(qts
);
1250 status
= qdict_get_str(ret
, "status");
1251 g_assert_cmpstr(status
, ==, "cancelling");
1254 /* OS unplugs the cards, QEMU can move from wait-unplug state */
1255 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_EJ_BASE
, 1);
1258 ret
= migrate_status(qts
);
1260 status
= qdict_get_str(ret
, "status");
1261 if (strcmp(status
, "cancelled") == 0) {
1265 g_assert_cmpstr(status
, ==, "cancelling");
1269 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1270 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1272 qos_object_destroy((QOSGraphObject
*)vdev
);
1276 static void test_migrate_abort_active(gconstpointer opaque
)
1279 QDict
*resp
, *args
, *ret
;
1280 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1281 const gchar
*status
;
1282 QVirtioPCIDevice
*vdev
;
1284 qts
= machine_start(BASE_MACHINE
1285 "-netdev user,id=hs0 "
1286 "-netdev user,id=hs1 ",
1289 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1290 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1292 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1296 "'mac': '"MAC_STANDBY0
"'}");
1298 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1299 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1301 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
1303 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1304 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1306 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1308 "'failover_pair_id': 'standby0',"
1312 "'mac': '"MAC_PRIMARY0
"'}");
1314 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1315 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1317 args
= qdict_from_jsonf_nofail("{}");
1318 g_assert_nonnull(args
);
1319 qdict_put_str(args
, "uri", uri
);
1321 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1322 g_assert(qdict_haskey(resp
, "return"));
1323 qobject_unref(resp
);
1325 /* the event is sent when QEMU asks the OS to unplug the card */
1326 resp
= get_unplug_primary_event(qts
);
1327 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "primary0");
1328 qobject_unref(resp
);
1330 /* OS unplugs the cards, QEMU can move from wait-unplug state */
1331 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_EJ_BASE
, 1);
1334 ret
= migrate_status(qts
);
1336 status
= qdict_get_str(ret
, "status");
1337 g_assert_cmpstr(status
, !=, "failed");
1338 if (strcmp(status
, "wait-unplug") != 0) {
1345 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate_cancel' }");
1346 g_assert(qdict_haskey(resp
, "return"));
1347 qobject_unref(resp
);
1350 ret
= migrate_status(qts
);
1352 status
= qdict_get_str(ret
, "status");
1353 if (strcmp(status
, "completed") == 0) {
1354 g_test_skip("Failed to cancel the migration");
1358 if (strcmp(status
, "cancelled") == 0) {
1362 g_assert_cmpstr(status
, !=, "failed");
1363 g_assert_cmpstr(status
, !=, "active");
1367 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1368 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1371 qos_object_destroy((QOSGraphObject
*)vdev
);
1375 static void test_migrate_off_abort(gconstpointer opaque
)
1378 QDict
*resp
, *args
, *ret
;
1379 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1380 const gchar
*status
;
1381 QVirtioPCIDevice
*vdev
;
1383 qts
= machine_start(BASE_MACHINE
1384 "-netdev user,id=hs0 "
1385 "-netdev user,id=hs1 ",
1388 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1389 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1391 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1393 "'failover': 'off',"
1395 "'mac': '"MAC_STANDBY0
"'}");
1397 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1398 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1400 vdev
= start_virtio_net(qts
, 1, 0, "standby0", false);
1402 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1403 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1405 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1407 "'failover_pair_id': 'standby0',"
1411 "'mac': '"MAC_PRIMARY0
"'}");
1413 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1414 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1416 args
= qdict_from_jsonf_nofail("{}");
1417 g_assert_nonnull(args
);
1418 qdict_put_str(args
, "uri", uri
);
1420 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1421 g_assert(qdict_haskey(resp
, "return"));
1422 qobject_unref(resp
);
1425 ret
= migrate_status(qts
);
1427 status
= qdict_get_str(ret
, "status");
1428 if (strcmp(status
, "active") == 0) {
1432 g_assert_cmpstr(status
, !=, "failed");
1436 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate_cancel' }");
1437 g_assert(qdict_haskey(resp
, "return"));
1438 qobject_unref(resp
);
1441 ret
= migrate_status(qts
);
1443 status
= qdict_get_str(ret
, "status");
1444 if (strcmp(status
, "completed") == 0) {
1445 g_test_skip("Failed to cancel the migration");
1449 if (strcmp(status
, "cancelled") == 0) {
1453 g_assert_cmpstr(status
, !=, "failed");
1454 g_assert_cmpstr(status
, !=, "active");
1458 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1459 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1462 qos_object_destroy((QOSGraphObject
*)vdev
);
1466 static void test_migrate_abort_timeout(gconstpointer opaque
)
1469 QDict
*resp
, *args
, *ret
;
1470 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1471 const gchar
*status
;
1473 QVirtioPCIDevice
*vdev
;
1475 qts
= machine_start(BASE_MACHINE
1476 "-netdev user,id=hs0 "
1477 "-netdev user,id=hs1 ",
1480 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1481 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1483 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1487 "'mac': '"MAC_STANDBY0
"'}");
1489 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1490 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1492 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
1494 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1495 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1497 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1499 "'failover_pair_id': 'standby0',"
1503 "'mac': '"MAC_PRIMARY0
"'}");
1505 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1506 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1508 args
= qdict_from_jsonf_nofail("{}");
1509 g_assert_nonnull(args
);
1510 qdict_put_str(args
, "uri", uri
);
1512 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1513 g_assert(qdict_haskey(resp
, "return"));
1514 qobject_unref(resp
);
1516 /* the event is sent when QEMU asks the OS to unplug the card */
1517 resp
= get_unplug_primary_event(qts
);
1518 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "primary0");
1519 qobject_unref(resp
);
1521 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate_cancel' }");
1522 g_assert(qdict_haskey(resp
, "return"));
1523 qobject_unref(resp
);
1525 /* migration has been cancelled while the unplug was in progress */
1527 /* while the card is not ejected, we must be in "cancelling" state */
1531 ret
= migrate_status(qts
);
1533 status
= qdict_get_str(ret
, "status");
1534 if (strcmp(status
, "cancelled") == 0) {
1538 g_assert_cmpstr(status
, ==, "cancelling");
1539 g_assert(qdict_haskey(ret
, "total-time"));
1540 total
= qdict_get_int(ret
, "total-time");
1545 * migration timeout in this case is 30 seconds
1546 * check we exit on the timeout (ms)
1548 g_assert_cmpint(total
, >, 30000);
1550 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1551 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1553 qos_object_destroy((QOSGraphObject
*)vdev
);
1557 static void test_multi_out(gconstpointer opaque
)
1560 QDict
*resp
, *args
, *ret
;
1561 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1562 const gchar
*status
, *expected
;
1563 QVirtioPCIDevice
*vdev0
, *vdev1
;
1565 qts
= machine_start(BASE_MACHINE
1566 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1567 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1568 "-netdev user,id=hs0 "
1569 "-netdev user,id=hs1 "
1570 "-netdev user,id=hs2 "
1571 "-netdev user,id=hs3 ",
1574 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1575 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1576 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1577 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1579 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1583 "'mac': '"MAC_STANDBY0
"'}");
1585 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1586 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1587 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1588 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1590 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1592 "'failover_pair_id': 'standby0',"
1596 "'mac': '"MAC_PRIMARY0
"'}");
1598 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1599 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1600 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1601 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1603 vdev0
= start_virtio_net(qts
, 1, 0, "standby0", true);
1605 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1606 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1607 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1608 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1610 qtest_qmp_device_add(qts
, "virtio-net", "standby1",
1614 "'mac': '"MAC_STANDBY1
"'}");
1616 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1617 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1618 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1619 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1621 qtest_qmp_device_add(qts
, "virtio-net", "primary1",
1623 "'failover_pair_id': 'standby1',"
1627 "'mac': '"MAC_PRIMARY1
"'}");
1629 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1630 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1631 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1632 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1634 vdev1
= start_virtio_net(qts
, 3, 0, "standby1", true);
1636 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1637 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1638 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1639 check_one_card(qts
, true, "primary1", MAC_PRIMARY1
);
1641 args
= qdict_from_jsonf_nofail("{}");
1642 g_assert_nonnull(args
);
1643 qdict_put_str(args
, "uri", uri
);
1645 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1646 g_assert(qdict_haskey(resp
, "return"));
1647 qobject_unref(resp
);
1649 /* the event is sent when QEMU asks the OS to unplug the card */
1650 resp
= get_unplug_primary_event(qts
);
1651 if (strcmp(qdict_get_str(resp
, "device-id"), "primary0") == 0) {
1652 expected
= "primary1";
1653 } else if (strcmp(qdict_get_str(resp
, "device-id"), "primary1") == 0) {
1654 expected
= "primary0";
1656 g_assert_not_reached();
1658 qobject_unref(resp
);
1660 resp
= get_unplug_primary_event(qts
);
1661 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, expected
);
1662 qobject_unref(resp
);
1664 /* wait the end of the migration setup phase */
1666 ret
= migrate_status(qts
);
1668 status
= qdict_get_str(ret
, "status");
1669 if (strcmp(status
, "wait-unplug") == 0) {
1674 /* The migration must not start if the card is not ejected */
1675 g_assert_cmpstr(status
, !=, "active");
1676 g_assert_cmpstr(status
, !=, "completed");
1677 g_assert_cmpstr(status
, !=, "failed");
1678 g_assert_cmpstr(status
, !=, "cancelling");
1679 g_assert_cmpstr(status
, !=, "cancelled");
1684 /* OS unplugs primary1, but we must wait the second */
1685 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_EJ_BASE
, 1);
1687 ret
= migrate_status(qts
);
1688 status
= qdict_get_str(ret
, "status");
1689 g_assert_cmpstr(status
, ==, "wait-unplug");
1692 if (g_test_slow()) {
1693 /* check we stay in wait-unplug while the card is not ejected */
1694 for (int i
= 0; i
< 5; i
++) {
1696 ret
= migrate_status(qts
);
1697 status
= qdict_get_str(ret
, "status");
1698 g_assert_cmpstr(status
, ==, "wait-unplug");
1703 /* OS unplugs primary0, QEMU can move from wait-unplug state */
1704 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_SEL_BASE
, 2);
1705 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_EJ_BASE
, 1);
1708 ret
= migrate_status(qts
);
1710 status
= qdict_get_str(ret
, "status");
1711 if (strcmp(status
, "completed") == 0) {
1715 g_assert_cmpstr(status
, !=, "failed");
1716 g_assert_cmpstr(status
, !=, "cancelling");
1717 g_assert_cmpstr(status
, !=, "cancelled");
1721 qtest_qmp_eventwait(qts
, "STOP");
1723 qos_object_destroy((QOSGraphObject
*)vdev0
);
1724 qos_object_destroy((QOSGraphObject
*)vdev1
);
1728 static void test_multi_in(gconstpointer opaque
)
1731 QDict
*resp
, *args
, *ret
;
1732 g_autofree gchar
*uri
= g_strdup_printf("exec: cat %s", (gchar
*)opaque
);
1734 qts
= machine_start(BASE_MACHINE
1735 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1736 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1737 "-netdev user,id=hs0 "
1738 "-netdev user,id=hs1 "
1739 "-netdev user,id=hs2 "
1740 "-netdev user,id=hs3 "
1744 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1745 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1746 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1747 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1749 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1753 "'mac': '"MAC_STANDBY0
"'}");
1755 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1756 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1757 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1758 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1760 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1762 "'failover_pair_id': 'standby0',"
1766 "'mac': '"MAC_PRIMARY0
"'}");
1768 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1769 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1770 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1771 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1773 qtest_qmp_device_add(qts
, "virtio-net", "standby1",
1777 "'mac': '"MAC_STANDBY1
"'}");
1779 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1780 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1781 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1782 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1784 qtest_qmp_device_add(qts
, "virtio-net", "primary1",
1786 "'failover_pair_id': 'standby1',"
1790 "'mac': '"MAC_PRIMARY1
"'}");
1792 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1793 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1794 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1795 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1797 args
= qdict_from_jsonf_nofail("{}");
1798 g_assert_nonnull(args
);
1799 qdict_put_str(args
, "uri", uri
);
1801 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1803 g_assert(qdict_haskey(resp
, "return"));
1804 qobject_unref(resp
);
1806 resp
= get_migration_event(qts
);
1807 g_assert_cmpstr(qdict_get_str(resp
, "status"), ==, "setup");
1808 qobject_unref(resp
);
1810 resp
= get_failover_negociated_event(qts
);
1811 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "standby0");
1812 qobject_unref(resp
);
1814 resp
= get_failover_negociated_event(qts
);
1815 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "standby1");
1816 qobject_unref(resp
);
1818 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1819 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1820 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1821 check_one_card(qts
, true, "primary1", MAC_PRIMARY1
);
1823 qtest_qmp_eventwait(qts
, "RESUME");
1825 ret
= migrate_status(qts
);
1826 g_assert_cmpstr(qdict_get_str(ret
, "status"), ==, "completed");
1833 int main(int argc
, char **argv
)
1838 g_test_init(&argc
, &argv
, NULL
);
1840 ret
= g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile
, NULL
);
1841 g_assert_true(ret
>= 0);
1844 /* parameters tests */
1845 qtest_add_func("failover-virtio-net/params/error/id", test_error_id
);
1846 qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie
);
1847 qtest_add_func("failover-virtio-net/params/on", test_on
);
1848 qtest_add_func("failover-virtio-net/params/on_mismatch",
1850 qtest_add_func("failover-virtio-net/params/off", test_off
);
1851 qtest_add_func("failover-virtio-net/params/enabled", test_enabled
);
1852 qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off
);
1855 qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1
);
1856 qtest_add_func("failover-virtio-net/hotplug/1_reverse",
1857 test_hotplug_1_reverse
);
1858 qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2
);
1859 qtest_add_func("failover-virtio-net/hotplug/2_reverse",
1860 test_hotplug_2_reverse
);
1864 * These migration tests cases use the exec migration protocol,
1865 * which is unsupported on Windows.
1867 qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile
,
1869 qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile
,
1871 qtest_add_data_func("failover-virtio-net/migrate/off/out", tmpfile
,
1872 test_off_migrate_out
);
1873 qtest_add_data_func("failover-virtio-net/migrate/off/in", tmpfile
,
1874 test_off_migrate_in
);
1875 qtest_add_data_func("failover-virtio-net/migrate/off/abort", tmpfile
,
1876 test_migrate_off_abort
);
1877 qtest_add_data_func("failover-virtio-net/migrate/guest_off/out", tmpfile
,
1878 test_guest_off_migrate_out
);
1879 qtest_add_data_func("failover-virtio-net/migrate/guest_off/in", tmpfile
,
1880 test_guest_off_migrate_in
);
1881 qtest_add_data_func("failover-virtio-net/migrate/guest_off/abort", tmpfile
,
1882 test_migrate_guest_off_abort
);
1883 qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
1884 tmpfile
, test_migrate_abort_wait_unplug
);
1885 qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile
,
1886 test_migrate_abort_active
);
1887 if (g_test_slow()) {
1888 qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
1889 tmpfile
, test_migrate_abort_timeout
);
1891 qtest_add_data_func("failover-virtio-net/migrate/multi/out",
1892 tmpfile
, test_multi_out
);
1893 qtest_add_data_func("failover-virtio-net/migrate/multi/in",
1894 tmpfile
, test_multi_in
);