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 "migration-helpers.h"
15 #include "qapi/qmp/qdict.h"
16 #include "qapi/qmp/qlist.h"
17 #include "qapi/qmp/qjson.h"
18 #include "libqos/malloc-pc.h"
19 #include "libqos/virtio-pci.h"
20 #include "hw/pci/pci.h"
22 #define VIRTIO_NET_F_STANDBY 62
24 #define ACPI_PCIHP_ADDR_ICH9 0x0cc0
25 #define PCI_EJ_BASE 0x0008
26 #define PCI_SEL_BASE 0x0010
28 #define BASE_MACHINE "-M q35 -nodefaults " \
29 "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
30 "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "
32 #define MAC_PRIMARY0 "52:54:00:11:11:11"
33 #define MAC_STANDBY0 "52:54:00:22:22:22"
34 #define MAC_PRIMARY1 "52:54:00:33:33:33"
35 #define MAC_STANDBY1 "52:54:00:44:44:44"
37 static QGuestAllocator guest_malloc
;
38 static QPCIBus
*pcibus
;
40 static QTestState
*machine_start(const char *args
, int numbus
)
46 qts
= qtest_init(args
);
48 pc_alloc_init(&guest_malloc
, qts
, 0);
49 pcibus
= qpci_new_pc(qts
, &guest_malloc
);
50 g_assert(qpci_secondary_buses_init(pcibus
) == numbus
);
52 for (bus
= 1; bus
<= numbus
; bus
++) {
53 dev
= qpci_device_find(pcibus
, QPCI_DEVFN(bus
, 0));
54 g_assert_nonnull(dev
);
56 qpci_device_enable(dev
);
57 qpci_iomap(dev
, 4, NULL
);
65 static void machine_stop(QTestState
*qts
)
68 alloc_destroy(&guest_malloc
);
72 static void test_error_id(void)
78 qts
= machine_start(BASE_MACHINE
79 "-device virtio-net,bus=root0,id=standby0,failover=on",
82 resp
= qtest_qmp(qts
, "{'execute': 'device_add',"
84 "'driver': 'virtio-net',"
86 "'failover_pair_id': 'standby0'"
88 g_assert(qdict_haskey(resp
, "error"));
90 err
= qdict_get_qdict(resp
, "error");
91 g_assert(qdict_haskey(err
, "desc"));
93 g_assert_cmpstr(qdict_get_str(err
, "desc"), ==,
94 "Device with failover_pair_id needs to have id");
101 static void test_error_pcie(void)
107 qts
= machine_start(BASE_MACHINE
108 "-device virtio-net,bus=root0,id=standby0,failover=on",
111 resp
= qtest_qmp(qts
, "{'execute': 'device_add',"
113 "'driver': 'virtio-net',"
116 "'failover_pair_id': 'standby0'"
118 g_assert(qdict_haskey(resp
, "error"));
120 err
= qdict_get_qdict(resp
, "error");
121 g_assert(qdict_haskey(err
, "desc"));
123 g_assert_cmpstr(qdict_get_str(err
, "desc"), ==,
124 "Bus 'pcie.0' does not support hotplugging");
131 static QDict
*find_device(QDict
*bus
, const char *name
)
137 devices
= qdict_get_qlist(bus
, "devices");
138 if (devices
== NULL
) {
142 list
= qlist_copy(devices
);
143 while ((obj
= qlist_pop(list
))) {
146 device
= qobject_to(QDict
, obj
);
148 if (qdict_haskey(device
, "pci_bridge")) {
150 QDict
*bridge_device
;
152 bridge
= qdict_get_qdict(device
, "pci_bridge");
154 if (qdict_haskey(bridge
, "devices")) {
155 bridge_device
= find_device(bridge
, name
);
157 qobject_unref(device
);
159 return bridge_device
;
164 if (!qdict_haskey(device
, "qdev_id")) {
165 qobject_unref(device
);
169 if (strcmp(qdict_get_str(device
, "qdev_id"), name
) == 0) {
173 qobject_unref(device
);
180 static QDict
*get_bus(QTestState
*qts
, int num
)
186 resp
= qtest_qmp(qts
, "{ 'execute': 'query-pci' }");
187 g_assert(qdict_haskey(resp
, "return"));
189 ret
= qdict_get_qlist(resp
, "return");
190 g_assert_nonnull(ret
);
192 while ((obj
= qlist_pop(ret
))) {
195 bus
= qobject_to(QDict
, obj
);
196 if (!qdict_haskey(bus
, "bus")) {
200 if (qdict_get_int(bus
, "bus") == num
) {
211 static char *get_mac(QTestState
*qts
, const char *name
)
216 resp
= qtest_qmp(qts
, "{ 'execute': 'qom-get', "
219 "'property': 'mac' } }", name
);
221 g_assert(qdict_haskey(resp
, "return"));
223 mac
= g_strdup(qdict_get_str(resp
, "return"));
230 #define check_one_card(qts, present, id, mac) \
235 bus = get_bus(qts, 0); \
236 device = find_device(bus, id); \
239 g_assert_nonnull(device); \
240 qobject_unref(device); \
241 path = g_strdup_printf("/machine/peripheral/%s", id); \
242 addr = get_mac(qts, path); \
244 g_assert_cmpstr(mac, ==, addr); \
247 g_assert_null(device); \
249 qobject_unref(bus); \
252 static QDict
*get_failover_negociated_event(QTestState
*qts
)
257 resp
= qtest_qmp_eventwait_ref(qts
, "FAILOVER_NEGOTIATED");
258 g_assert(qdict_haskey(resp
, "data"));
260 data
= qdict_get_qdict(resp
, "data");
261 g_assert(qdict_haskey(data
, "device-id"));
268 static QVirtioPCIDevice
*start_virtio_net_internal(QTestState
*qts
,
272 QVirtioPCIDevice
*dev
;
275 addr
.devfn
= QPCI_DEVFN((bus
<< 5) + slot
, 0);
276 dev
= virtio_pci_new(pcibus
, &addr
);
277 g_assert_nonnull(dev
);
278 qvirtio_pci_device_enable(dev
);
279 qvirtio_start_device(&dev
->vdev
);
280 *features
&= qvirtio_get_features(&dev
->vdev
);
281 qvirtio_set_features(&dev
->vdev
, *features
);
282 qvirtio_set_driver_ok(&dev
->vdev
);
286 static QVirtioPCIDevice
*start_virtio_net(QTestState
*qts
, int bus
, int slot
,
287 const char *id
, bool failover
)
289 QVirtioPCIDevice
*dev
;
292 features
= ~(QVIRTIO_F_BAD_FEATURE
|
293 (1ull << VIRTIO_RING_F_INDIRECT_DESC
) |
294 (1ull << VIRTIO_RING_F_EVENT_IDX
));
296 dev
= start_virtio_net_internal(qts
, bus
, slot
, &features
);
298 g_assert(!!(features
& (1ull << VIRTIO_NET_F_STANDBY
)) == failover
);
303 resp
= get_failover_negociated_event(qts
);
304 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, id
);
311 static void test_on(void)
315 qts
= machine_start(BASE_MACHINE
316 "-netdev user,id=hs0 "
317 "-device virtio-net,bus=root0,id=standby0,"
318 "failover=on,netdev=hs0,mac="MAC_STANDBY0
" "
319 "-netdev user,id=hs1 "
320 "-device virtio-net,bus=root1,id=primary0,"
321 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0
,
324 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
325 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
330 static void test_on_mismatch(void)
333 QVirtioPCIDevice
*vdev
;
335 qts
= machine_start(BASE_MACHINE
336 "-netdev user,id=hs0 "
337 "-device virtio-net,bus=root0,id=standby0,"
338 "failover=on,netdev=hs0,mac="MAC_STANDBY0
" "
339 "-netdev user,id=hs1 "
340 "-device virtio-net,bus=root1,id=primary0,"
341 "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0
,
344 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
345 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
347 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
349 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
350 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
352 qos_object_destroy((QOSGraphObject
*)vdev
);
356 static void test_off(void)
359 QVirtioPCIDevice
*vdev
;
361 qts
= machine_start(BASE_MACHINE
362 "-netdev user,id=hs0 "
363 "-device virtio-net,bus=root0,id=standby0,"
364 "failover=off,netdev=hs0,mac="MAC_STANDBY0
" "
365 "-netdev user,id=hs1 "
366 "-device virtio-net,bus=root1,id=primary0,"
367 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0
,
370 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
371 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
373 vdev
= start_virtio_net(qts
, 1, 0, "standby0", false);
375 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
376 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
378 qos_object_destroy((QOSGraphObject
*)vdev
);
382 static void test_enabled(void)
385 QVirtioPCIDevice
*vdev
;
387 qts
= machine_start(BASE_MACHINE
388 "-netdev user,id=hs0 "
389 "-device virtio-net,bus=root0,id=standby0,"
390 "failover=on,netdev=hs0,mac="MAC_STANDBY0
" "
391 "-netdev user,id=hs1 "
392 "-device virtio-net,bus=root1,id=primary0,"
393 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0
" ",
396 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
397 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
399 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
401 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
402 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
404 qos_object_destroy((QOSGraphObject
*)vdev
);
408 static void test_guest_off(void)
411 QVirtioPCIDevice
*vdev
;
414 qts
= machine_start(BASE_MACHINE
415 "-netdev user,id=hs0 "
416 "-device virtio-net,bus=root0,id=standby0,"
417 "failover=on,netdev=hs0,mac="MAC_STANDBY0
" "
418 "-netdev user,id=hs1 "
419 "-device virtio-net,bus=root1,id=primary0,"
420 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0
" ",
423 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
424 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
426 features
= ~(QVIRTIO_F_BAD_FEATURE
|
427 (1ull << VIRTIO_RING_F_INDIRECT_DESC
) |
428 (1ull << VIRTIO_RING_F_EVENT_IDX
) |
429 (1ull << VIRTIO_NET_F_STANDBY
));
431 vdev
= start_virtio_net_internal(qts
, 1, 0, &features
);
433 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
434 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
436 qos_object_destroy((QOSGraphObject
*)vdev
);
440 static void test_hotplug_1(void)
443 QVirtioPCIDevice
*vdev
;
445 qts
= machine_start(BASE_MACHINE
446 "-netdev user,id=hs0 "
447 "-device virtio-net,bus=root0,id=standby0,"
448 "failover=on,netdev=hs0,mac="MAC_STANDBY0
" "
449 "-netdev user,id=hs1 ", 2);
451 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
452 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
454 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
456 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
457 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
459 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
461 "'failover_pair_id': 'standby0',"
463 "'mac': '"MAC_PRIMARY0
"'}");
465 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
466 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
468 qos_object_destroy((QOSGraphObject
*)vdev
);
472 static void test_hotplug_1_reverse(void)
475 QVirtioPCIDevice
*vdev
;
477 qts
= machine_start(BASE_MACHINE
478 "-netdev user,id=hs0 "
479 "-netdev user,id=hs1 "
480 "-device virtio-net,bus=root1,id=primary0,"
481 "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0
" ",
484 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
485 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
487 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
491 "'mac': '"MAC_STANDBY0
"'}");
493 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
494 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
496 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
498 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
499 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
501 qos_object_destroy((QOSGraphObject
*)vdev
);
505 static void test_hotplug_2(void)
508 QVirtioPCIDevice
*vdev
;
510 qts
= machine_start(BASE_MACHINE
511 "-netdev user,id=hs0 "
512 "-netdev user,id=hs1 ",
515 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
516 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
518 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
522 "'mac': '"MAC_STANDBY0
"'}");
524 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
525 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
527 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
529 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
530 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
532 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
534 "'failover_pair_id': 'standby0',"
536 "'mac': '"MAC_PRIMARY0
"'}");
538 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
539 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
541 qos_object_destroy((QOSGraphObject
*)vdev
);
545 static void test_hotplug_2_reverse(void)
548 QVirtioPCIDevice
*vdev
;
550 qts
= machine_start(BASE_MACHINE
551 "-netdev user,id=hs0 "
552 "-netdev user,id=hs1 ",
555 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
556 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
558 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
560 "'failover_pair_id': 'standby0',"
562 "'mac': '"MAC_PRIMARY0
"'}");
564 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
565 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
567 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
573 "'mac': '"MAC_STANDBY0
"'}");
576 * XXX: sounds like a bug:
577 * The primary should be hidden until the virtio-net driver
578 * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
580 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
581 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
583 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
585 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
586 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
588 qos_object_destroy((QOSGraphObject
*)vdev
);
593 static QDict
*migrate_status(QTestState
*qts
)
597 resp
= qtest_qmp(qts
, "{ 'execute': 'query-migrate' }");
598 g_assert(qdict_haskey(resp
, "return"));
600 ret
= qdict_get_qdict(resp
, "return");
601 g_assert(qdict_haskey(ret
, "status"));
608 static QDict
*get_unplug_primary_event(QTestState
*qts
)
613 resp
= qtest_qmp_eventwait_ref(qts
, "UNPLUG_PRIMARY");
614 g_assert(qdict_haskey(resp
, "data"));
616 data
= qdict_get_qdict(resp
, "data");
617 g_assert(qdict_haskey(data
, "device-id"));
624 static void test_migrate_out(gconstpointer opaque
)
627 QDict
*resp
, *args
, *ret
;
628 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
630 QVirtioPCIDevice
*vdev
;
632 qts
= machine_start(BASE_MACHINE
633 "-netdev user,id=hs0 "
634 "-netdev user,id=hs1 ",
637 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
638 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
640 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
644 "'mac': '"MAC_STANDBY0
"'}");
646 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
647 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
649 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
651 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
652 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
654 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
656 "'failover_pair_id': 'standby0',"
660 "'mac': '"MAC_PRIMARY0
"'}");
662 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
663 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
665 args
= qdict_from_jsonf_nofail("{}");
666 g_assert_nonnull(args
);
667 qdict_put_str(args
, "uri", uri
);
669 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
670 g_assert(qdict_haskey(resp
, "return"));
673 /* the event is sent when QEMU asks the OS to unplug the card */
674 resp
= get_unplug_primary_event(qts
);
675 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "primary0");
678 /* wait the end of the migration setup phase */
680 ret
= migrate_status(qts
);
682 status
= qdict_get_str(ret
, "status");
683 if (strcmp(status
, "wait-unplug") == 0) {
688 /* The migration must not start if the card is not ejected */
689 g_assert_cmpstr(status
, !=, "active");
690 g_assert_cmpstr(status
, !=, "completed");
691 g_assert_cmpstr(status
, !=, "failed");
692 g_assert_cmpstr(status
, !=, "cancelling");
693 g_assert_cmpstr(status
, !=, "cancelled");
699 /* check we stay in wait-unplug while the card is not ejected */
700 for (int i
= 0; i
< 5; i
++) {
702 ret
= migrate_status(qts
);
703 status
= qdict_get_str(ret
, "status");
704 g_assert_cmpstr(status
, ==, "wait-unplug");
709 /* OS unplugs the cards, QEMU can move from wait-unplug state */
710 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_EJ_BASE
, 1);
713 ret
= migrate_status(qts
);
715 status
= qdict_get_str(ret
, "status");
716 if (strcmp(status
, "completed") == 0) {
720 g_assert_cmpstr(status
, !=, "failed");
721 g_assert_cmpstr(status
, !=, "cancelling");
722 g_assert_cmpstr(status
, !=, "cancelled");
726 qtest_qmp_eventwait(qts
, "STOP");
729 * in fact, the card is ejected from the point of view of kernel
730 * but not really from QEMU to be able to hotplug it back if
731 * migration fails. So we can't check that:
732 * check_one_card(qts, true, "standby0", MAC_STANDBY0);
733 * check_one_card(qts, false, "primary0", MAC_PRIMARY0);
736 qos_object_destroy((QOSGraphObject
*)vdev
);
740 static void test_migrate_in(gconstpointer opaque
)
744 g_autofree gchar
*uri
= g_strdup_printf("exec: cat %s", (gchar
*)opaque
);
746 qts
= machine_start(BASE_MACHINE
747 "-netdev user,id=hs0 "
748 "-netdev user,id=hs1 "
752 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
753 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
755 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
759 "'mac': '"MAC_STANDBY0
"'}");
761 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
762 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
764 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
766 "'failover_pair_id': 'standby0',"
770 "'mac': '"MAC_PRIMARY0
"'}");
772 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
773 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
775 migrate_incoming_qmp(qts
, uri
, "{}");
777 resp
= get_failover_negociated_event(qts
);
778 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "standby0");
781 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
782 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
784 qtest_qmp_eventwait(qts
, "RESUME");
786 ret
= migrate_status(qts
);
787 g_assert_cmpstr(qdict_get_str(ret
, "status"), ==, "completed");
793 static void test_off_migrate_out(gconstpointer opaque
)
796 QDict
*resp
, *args
, *ret
;
797 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
799 QVirtioPCIDevice
*vdev
;
801 qts
= machine_start(BASE_MACHINE
802 "-netdev user,id=hs0 "
803 "-netdev user,id=hs1 ",
806 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
807 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
809 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
813 "'mac': '"MAC_STANDBY0
"'}");
815 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
816 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
818 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
820 "'failover_pair_id': 'standby0',"
824 "'mac': '"MAC_PRIMARY0
"'}");
826 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
827 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
829 vdev
= start_virtio_net(qts
, 1, 0, "standby0", false);
831 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
832 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
834 args
= qdict_from_jsonf_nofail("{}");
835 g_assert_nonnull(args
);
836 qdict_put_str(args
, "uri", uri
);
838 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
839 g_assert(qdict_haskey(resp
, "return"));
843 ret
= migrate_status(qts
);
845 status
= qdict_get_str(ret
, "status");
846 if (strcmp(status
, "completed") == 0) {
850 g_assert_cmpstr(status
, !=, "failed");
851 g_assert_cmpstr(status
, !=, "cancelling");
852 g_assert_cmpstr(status
, !=, "cancelled");
856 qtest_qmp_eventwait(qts
, "STOP");
858 qos_object_destroy((QOSGraphObject
*)vdev
);
862 static void test_off_migrate_in(gconstpointer opaque
)
866 g_autofree gchar
*uri
= g_strdup_printf("exec: cat %s", (gchar
*)opaque
);
868 qts
= machine_start(BASE_MACHINE
869 "-netdev user,id=hs0 "
870 "-netdev user,id=hs1 "
874 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
875 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
877 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
881 "'mac': '"MAC_STANDBY0
"'}");
883 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
884 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
886 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
888 "'failover_pair_id': 'standby0',"
892 "'mac': '"MAC_PRIMARY0
"'}");
894 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
895 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
897 migrate_incoming_qmp(qts
, uri
, "{}");
899 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
900 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
902 qtest_qmp_eventwait(qts
, "RESUME");
904 ret
= migrate_status(qts
);
905 g_assert_cmpstr(qdict_get_str(ret
, "status"), ==, "completed");
911 static void test_guest_off_migrate_out(gconstpointer opaque
)
914 QDict
*resp
, *args
, *ret
;
915 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
917 QVirtioPCIDevice
*vdev
;
920 qts
= machine_start(BASE_MACHINE
921 "-netdev user,id=hs0 "
922 "-netdev user,id=hs1 ",
925 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
926 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
928 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
932 "'mac': '"MAC_STANDBY0
"'}");
934 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
935 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
937 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
939 "'failover_pair_id': 'standby0',"
943 "'mac': '"MAC_PRIMARY0
"'}");
945 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
946 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
948 features
= ~(QVIRTIO_F_BAD_FEATURE
|
949 (1ull << VIRTIO_RING_F_INDIRECT_DESC
) |
950 (1ull << VIRTIO_RING_F_EVENT_IDX
) |
951 (1ull << VIRTIO_NET_F_STANDBY
));
953 vdev
= start_virtio_net_internal(qts
, 1, 0, &features
);
955 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
956 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
958 args
= qdict_from_jsonf_nofail("{}");
959 g_assert_nonnull(args
);
960 qdict_put_str(args
, "uri", uri
);
962 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
963 g_assert(qdict_haskey(resp
, "return"));
967 ret
= migrate_status(qts
);
969 status
= qdict_get_str(ret
, "status");
970 if (strcmp(status
, "completed") == 0) {
974 g_assert_cmpstr(status
, !=, "failed");
975 g_assert_cmpstr(status
, !=, "cancelling");
976 g_assert_cmpstr(status
, !=, "cancelled");
980 qtest_qmp_eventwait(qts
, "STOP");
982 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
983 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
985 qos_object_destroy((QOSGraphObject
*)vdev
);
989 static void test_guest_off_migrate_in(gconstpointer opaque
)
993 g_autofree gchar
*uri
= g_strdup_printf("exec: cat %s", (gchar
*)opaque
);
995 qts
= machine_start(BASE_MACHINE
996 "-netdev user,id=hs0 "
997 "-netdev user,id=hs1 "
1001 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1002 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1004 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1008 "'mac': '"MAC_STANDBY0
"'}");
1010 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1011 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1013 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1015 "'failover_pair_id': 'standby0',"
1019 "'mac': '"MAC_PRIMARY0
"'}");
1021 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1022 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1024 migrate_incoming_qmp(qts
, uri
, "{}");
1026 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1027 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1029 qtest_qmp_eventwait(qts
, "RESUME");
1031 ret
= migrate_status(qts
);
1032 g_assert_cmpstr(qdict_get_str(ret
, "status"), ==, "completed");
1038 static void test_migrate_guest_off_abort(gconstpointer opaque
)
1041 QDict
*resp
, *args
, *ret
;
1042 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1043 const gchar
*status
;
1044 QVirtioPCIDevice
*vdev
;
1047 qts
= machine_start(BASE_MACHINE
1048 "-netdev user,id=hs0 "
1049 "-netdev user,id=hs1 ",
1052 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1053 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1055 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1059 "'mac': '"MAC_STANDBY0
"'}");
1061 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1062 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1064 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1066 "'failover_pair_id': 'standby0',"
1070 "'mac': '"MAC_PRIMARY0
"'}");
1072 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1073 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1075 features
= ~(QVIRTIO_F_BAD_FEATURE
|
1076 (1ull << VIRTIO_RING_F_INDIRECT_DESC
) |
1077 (1ull << VIRTIO_RING_F_EVENT_IDX
) |
1078 (1ull << VIRTIO_NET_F_STANDBY
));
1080 vdev
= start_virtio_net_internal(qts
, 1, 0, &features
);
1082 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1083 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1085 args
= qdict_from_jsonf_nofail("{}");
1086 g_assert_nonnull(args
);
1087 qdict_put_str(args
, "uri", uri
);
1089 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1090 g_assert(qdict_haskey(resp
, "return"));
1091 qobject_unref(resp
);
1094 ret
= migrate_status(qts
);
1096 status
= qdict_get_str(ret
, "status");
1097 if (strcmp(status
, "completed") == 0) {
1098 g_test_skip("Failed to cancel the migration");
1102 if (strcmp(status
, "active") == 0) {
1106 g_assert_cmpstr(status
, !=, "failed");
1110 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate_cancel' }");
1111 g_assert(qdict_haskey(resp
, "return"));
1112 qobject_unref(resp
);
1115 ret
= migrate_status(qts
);
1116 status
= qdict_get_str(ret
, "status");
1117 if (strcmp(status
, "completed") == 0) {
1118 g_test_skip("Failed to cancel the migration");
1122 if (strcmp(status
, "cancelled") == 0) {
1126 g_assert_cmpstr(status
, !=, "failed");
1127 g_assert_cmpstr(status
, !=, "active");
1131 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1132 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1135 qos_object_destroy((QOSGraphObject
*)vdev
);
1139 static void test_migrate_abort_wait_unplug(gconstpointer opaque
)
1142 QDict
*resp
, *args
, *ret
;
1143 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1144 const gchar
*status
;
1145 QVirtioPCIDevice
*vdev
;
1147 qts
= machine_start(BASE_MACHINE
1148 "-netdev user,id=hs0 "
1149 "-netdev user,id=hs1 ",
1152 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1153 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1155 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1159 "'mac': '"MAC_STANDBY0
"'}");
1161 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1162 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1164 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
1166 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1167 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1169 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1171 "'failover_pair_id': 'standby0',"
1175 "'mac': '"MAC_PRIMARY0
"'}");
1177 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1178 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1180 args
= qdict_from_jsonf_nofail("{}");
1181 g_assert_nonnull(args
);
1182 qdict_put_str(args
, "uri", uri
);
1184 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1185 g_assert(qdict_haskey(resp
, "return"));
1186 qobject_unref(resp
);
1188 /* the event is sent when QEMU asks the OS to unplug the card */
1189 resp
= get_unplug_primary_event(qts
);
1190 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "primary0");
1191 qobject_unref(resp
);
1193 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate_cancel' }");
1194 g_assert(qdict_haskey(resp
, "return"));
1195 qobject_unref(resp
);
1197 /* migration has been cancelled while the unplug was in progress */
1199 /* while the card is not ejected, we must be in "cancelling" state */
1200 ret
= migrate_status(qts
);
1202 status
= qdict_get_str(ret
, "status");
1203 g_assert_cmpstr(status
, ==, "cancelling");
1206 /* OS unplugs the cards, QEMU can move from wait-unplug state */
1207 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_EJ_BASE
, 1);
1210 ret
= migrate_status(qts
);
1212 status
= qdict_get_str(ret
, "status");
1213 if (strcmp(status
, "cancelled") == 0) {
1217 g_assert_cmpstr(status
, ==, "cancelling");
1221 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1222 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1224 qos_object_destroy((QOSGraphObject
*)vdev
);
1228 static void test_migrate_abort_active(gconstpointer opaque
)
1231 QDict
*resp
, *args
, *ret
;
1232 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1233 const gchar
*status
;
1234 QVirtioPCIDevice
*vdev
;
1236 qts
= machine_start(BASE_MACHINE
1237 "-netdev user,id=hs0 "
1238 "-netdev user,id=hs1 ",
1241 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1242 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1244 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1248 "'mac': '"MAC_STANDBY0
"'}");
1250 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1251 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1253 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
1255 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1256 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1258 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1260 "'failover_pair_id': 'standby0',"
1264 "'mac': '"MAC_PRIMARY0
"'}");
1266 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1267 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1269 args
= qdict_from_jsonf_nofail("{}");
1270 g_assert_nonnull(args
);
1271 qdict_put_str(args
, "uri", uri
);
1273 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1274 g_assert(qdict_haskey(resp
, "return"));
1275 qobject_unref(resp
);
1277 /* the event is sent when QEMU asks the OS to unplug the card */
1278 resp
= get_unplug_primary_event(qts
);
1279 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "primary0");
1280 qobject_unref(resp
);
1282 /* OS unplugs the cards, QEMU can move from wait-unplug state */
1283 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_EJ_BASE
, 1);
1286 ret
= migrate_status(qts
);
1288 status
= qdict_get_str(ret
, "status");
1289 g_assert_cmpstr(status
, !=, "failed");
1290 if (strcmp(status
, "wait-unplug") != 0) {
1297 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate_cancel' }");
1298 g_assert(qdict_haskey(resp
, "return"));
1299 qobject_unref(resp
);
1302 ret
= migrate_status(qts
);
1304 status
= qdict_get_str(ret
, "status");
1305 if (strcmp(status
, "completed") == 0) {
1306 g_test_skip("Failed to cancel the migration");
1310 if (strcmp(status
, "cancelled") == 0) {
1314 g_assert_cmpstr(status
, !=, "failed");
1315 g_assert_cmpstr(status
, !=, "active");
1319 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1320 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1323 qos_object_destroy((QOSGraphObject
*)vdev
);
1327 static void test_migrate_off_abort(gconstpointer opaque
)
1330 QDict
*resp
, *args
, *ret
;
1331 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1332 const gchar
*status
;
1333 QVirtioPCIDevice
*vdev
;
1335 qts
= machine_start(BASE_MACHINE
1336 "-netdev user,id=hs0 "
1337 "-netdev user,id=hs1 ",
1340 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1341 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1343 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1345 "'failover': false,"
1347 "'mac': '"MAC_STANDBY0
"'}");
1349 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1350 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1352 vdev
= start_virtio_net(qts
, 1, 0, "standby0", false);
1354 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1355 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1357 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1359 "'failover_pair_id': 'standby0',"
1363 "'mac': '"MAC_PRIMARY0
"'}");
1365 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1366 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1368 args
= qdict_from_jsonf_nofail("{}");
1369 g_assert_nonnull(args
);
1370 qdict_put_str(args
, "uri", uri
);
1372 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1373 g_assert(qdict_haskey(resp
, "return"));
1374 qobject_unref(resp
);
1377 ret
= migrate_status(qts
);
1379 status
= qdict_get_str(ret
, "status");
1380 if (strcmp(status
, "active") == 0) {
1384 g_assert_cmpstr(status
, !=, "failed");
1388 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate_cancel' }");
1389 g_assert(qdict_haskey(resp
, "return"));
1390 qobject_unref(resp
);
1393 ret
= migrate_status(qts
);
1395 status
= qdict_get_str(ret
, "status");
1396 if (strcmp(status
, "completed") == 0) {
1397 g_test_skip("Failed to cancel the migration");
1401 if (strcmp(status
, "cancelled") == 0) {
1405 g_assert_cmpstr(status
, !=, "failed");
1406 g_assert_cmpstr(status
, !=, "active");
1410 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1411 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1414 qos_object_destroy((QOSGraphObject
*)vdev
);
1418 static void test_migrate_abort_timeout(gconstpointer opaque
)
1421 QDict
*resp
, *args
, *ret
;
1422 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1423 const gchar
*status
;
1425 QVirtioPCIDevice
*vdev
;
1427 qts
= machine_start(BASE_MACHINE
1428 "-netdev user,id=hs0 "
1429 "-netdev user,id=hs1 ",
1432 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1433 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1435 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1439 "'mac': '"MAC_STANDBY0
"'}");
1441 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1442 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1444 vdev
= start_virtio_net(qts
, 1, 0, "standby0", true);
1446 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1447 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1449 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1451 "'failover_pair_id': 'standby0',"
1455 "'mac': '"MAC_PRIMARY0
"'}");
1457 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1458 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1460 args
= qdict_from_jsonf_nofail("{}");
1461 g_assert_nonnull(args
);
1462 qdict_put_str(args
, "uri", uri
);
1464 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1465 g_assert(qdict_haskey(resp
, "return"));
1466 qobject_unref(resp
);
1468 /* the event is sent when QEMU asks the OS to unplug the card */
1469 resp
= get_unplug_primary_event(qts
);
1470 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "primary0");
1471 qobject_unref(resp
);
1473 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate_cancel' }");
1474 g_assert(qdict_haskey(resp
, "return"));
1475 qobject_unref(resp
);
1477 /* migration has been cancelled while the unplug was in progress */
1479 /* while the card is not ejected, we must be in "cancelling" state */
1483 ret
= migrate_status(qts
);
1485 status
= qdict_get_str(ret
, "status");
1486 if (strcmp(status
, "cancelled") == 0) {
1490 g_assert_cmpstr(status
, ==, "cancelling");
1491 g_assert(qdict_haskey(ret
, "total-time"));
1492 total
= qdict_get_int(ret
, "total-time");
1497 * migration timeout in this case is 30 seconds
1498 * check we exit on the timeout (ms)
1500 g_assert_cmpint(total
, >, 30000);
1502 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1503 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1505 qos_object_destroy((QOSGraphObject
*)vdev
);
1509 static void test_multi_out(gconstpointer opaque
)
1512 QDict
*resp
, *args
, *ret
;
1513 g_autofree gchar
*uri
= g_strdup_printf("exec: cat > %s", (gchar
*)opaque
);
1514 const gchar
*status
, *expected
;
1515 QVirtioPCIDevice
*vdev0
, *vdev1
;
1517 qts
= machine_start(BASE_MACHINE
1518 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1519 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1520 "-netdev user,id=hs0 "
1521 "-netdev user,id=hs1 "
1522 "-netdev user,id=hs2 "
1523 "-netdev user,id=hs3 ",
1526 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1527 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1528 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1529 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1531 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1535 "'mac': '"MAC_STANDBY0
"'}");
1537 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1538 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1539 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1540 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1542 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1544 "'failover_pair_id': 'standby0',"
1548 "'mac': '"MAC_PRIMARY0
"'}");
1550 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1551 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1552 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1553 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1555 vdev0
= start_virtio_net(qts
, 1, 0, "standby0", true);
1557 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1558 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1559 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1560 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1562 qtest_qmp_device_add(qts
, "virtio-net", "standby1",
1566 "'mac': '"MAC_STANDBY1
"'}");
1568 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1569 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1570 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1571 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1573 qtest_qmp_device_add(qts
, "virtio-net", "primary1",
1575 "'failover_pair_id': 'standby1',"
1579 "'mac': '"MAC_PRIMARY1
"'}");
1581 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1582 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1583 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1584 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1586 vdev1
= start_virtio_net(qts
, 3, 0, "standby1", true);
1588 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1589 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1590 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1591 check_one_card(qts
, true, "primary1", MAC_PRIMARY1
);
1593 args
= qdict_from_jsonf_nofail("{}");
1594 g_assert_nonnull(args
);
1595 qdict_put_str(args
, "uri", uri
);
1597 resp
= qtest_qmp(qts
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
1598 g_assert(qdict_haskey(resp
, "return"));
1599 qobject_unref(resp
);
1601 /* the event is sent when QEMU asks the OS to unplug the card */
1602 resp
= get_unplug_primary_event(qts
);
1603 if (strcmp(qdict_get_str(resp
, "device-id"), "primary0") == 0) {
1604 expected
= "primary1";
1605 } else if (strcmp(qdict_get_str(resp
, "device-id"), "primary1") == 0) {
1606 expected
= "primary0";
1608 g_assert_not_reached();
1610 qobject_unref(resp
);
1612 resp
= get_unplug_primary_event(qts
);
1613 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, expected
);
1614 qobject_unref(resp
);
1616 /* wait the end of the migration setup phase */
1618 ret
= migrate_status(qts
);
1620 status
= qdict_get_str(ret
, "status");
1621 if (strcmp(status
, "wait-unplug") == 0) {
1626 /* The migration must not start if the card is not ejected */
1627 g_assert_cmpstr(status
, !=, "active");
1628 g_assert_cmpstr(status
, !=, "completed");
1629 g_assert_cmpstr(status
, !=, "failed");
1630 g_assert_cmpstr(status
, !=, "cancelling");
1631 g_assert_cmpstr(status
, !=, "cancelled");
1636 /* OS unplugs primary1, but we must wait the second */
1637 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_EJ_BASE
, 1);
1639 ret
= migrate_status(qts
);
1640 status
= qdict_get_str(ret
, "status");
1641 g_assert_cmpstr(status
, ==, "wait-unplug");
1644 if (g_test_slow()) {
1645 /* check we stay in wait-unplug while the card is not ejected */
1646 for (int i
= 0; i
< 5; i
++) {
1648 ret
= migrate_status(qts
);
1649 status
= qdict_get_str(ret
, "status");
1650 g_assert_cmpstr(status
, ==, "wait-unplug");
1655 /* OS unplugs primary0, QEMU can move from wait-unplug state */
1656 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_SEL_BASE
, 2);
1657 qtest_outl(qts
, ACPI_PCIHP_ADDR_ICH9
+ PCI_EJ_BASE
, 1);
1660 ret
= migrate_status(qts
);
1662 status
= qdict_get_str(ret
, "status");
1663 if (strcmp(status
, "completed") == 0) {
1667 g_assert_cmpstr(status
, !=, "failed");
1668 g_assert_cmpstr(status
, !=, "cancelling");
1669 g_assert_cmpstr(status
, !=, "cancelled");
1673 qtest_qmp_eventwait(qts
, "STOP");
1675 qos_object_destroy((QOSGraphObject
*)vdev0
);
1676 qos_object_destroy((QOSGraphObject
*)vdev1
);
1680 static void test_multi_in(gconstpointer opaque
)
1684 g_autofree gchar
*uri
= g_strdup_printf("exec: cat %s", (gchar
*)opaque
);
1686 qts
= machine_start(BASE_MACHINE
1687 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1688 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1689 "-netdev user,id=hs0 "
1690 "-netdev user,id=hs1 "
1691 "-netdev user,id=hs2 "
1692 "-netdev user,id=hs3 "
1696 check_one_card(qts
, false, "standby0", MAC_STANDBY0
);
1697 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1698 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1699 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1701 qtest_qmp_device_add(qts
, "virtio-net", "standby0",
1705 "'mac': '"MAC_STANDBY0
"'}");
1707 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1708 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1709 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1710 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1712 qtest_qmp_device_add(qts
, "virtio-net", "primary0",
1714 "'failover_pair_id': 'standby0',"
1718 "'mac': '"MAC_PRIMARY0
"'}");
1720 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1721 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1722 check_one_card(qts
, false, "standby1", MAC_STANDBY1
);
1723 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1725 qtest_qmp_device_add(qts
, "virtio-net", "standby1",
1729 "'mac': '"MAC_STANDBY1
"'}");
1731 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1732 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1733 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1734 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1736 qtest_qmp_device_add(qts
, "virtio-net", "primary1",
1738 "'failover_pair_id': 'standby1',"
1742 "'mac': '"MAC_PRIMARY1
"'}");
1744 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1745 check_one_card(qts
, false, "primary0", MAC_PRIMARY0
);
1746 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1747 check_one_card(qts
, false, "primary1", MAC_PRIMARY1
);
1749 migrate_incoming_qmp(qts
, uri
, "{}");
1751 resp
= get_failover_negociated_event(qts
);
1752 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "standby0");
1753 qobject_unref(resp
);
1755 resp
= get_failover_negociated_event(qts
);
1756 g_assert_cmpstr(qdict_get_str(resp
, "device-id"), ==, "standby1");
1757 qobject_unref(resp
);
1759 check_one_card(qts
, true, "standby0", MAC_STANDBY0
);
1760 check_one_card(qts
, true, "primary0", MAC_PRIMARY0
);
1761 check_one_card(qts
, true, "standby1", MAC_STANDBY1
);
1762 check_one_card(qts
, true, "primary1", MAC_PRIMARY1
);
1764 qtest_qmp_eventwait(qts
, "RESUME");
1766 ret
= migrate_status(qts
);
1767 g_assert_cmpstr(qdict_get_str(ret
, "status"), ==, "completed");
1774 int main(int argc
, char **argv
)
1779 g_test_init(&argc
, &argv
, NULL
);
1781 ret
= g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile
, NULL
);
1782 g_assert_true(ret
>= 0);
1785 /* parameters tests */
1786 qtest_add_func("failover-virtio-net/params/error/id", test_error_id
);
1787 qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie
);
1788 qtest_add_func("failover-virtio-net/params/on", test_on
);
1789 qtest_add_func("failover-virtio-net/params/on_mismatch",
1791 qtest_add_func("failover-virtio-net/params/off", test_off
);
1792 qtest_add_func("failover-virtio-net/params/enabled", test_enabled
);
1793 qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off
);
1796 qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1
);
1797 qtest_add_func("failover-virtio-net/hotplug/1_reverse",
1798 test_hotplug_1_reverse
);
1799 qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2
);
1800 qtest_add_func("failover-virtio-net/hotplug/2_reverse",
1801 test_hotplug_2_reverse
);
1805 * These migration tests cases use the exec migration protocol,
1806 * which is unsupported on Windows.
1808 qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile
,
1810 qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile
,
1812 qtest_add_data_func("failover-virtio-net/migrate/off/out", tmpfile
,
1813 test_off_migrate_out
);
1814 qtest_add_data_func("failover-virtio-net/migrate/off/in", tmpfile
,
1815 test_off_migrate_in
);
1816 qtest_add_data_func("failover-virtio-net/migrate/off/abort", tmpfile
,
1817 test_migrate_off_abort
);
1818 qtest_add_data_func("failover-virtio-net/migrate/guest_off/out", tmpfile
,
1819 test_guest_off_migrate_out
);
1820 qtest_add_data_func("failover-virtio-net/migrate/guest_off/in", tmpfile
,
1821 test_guest_off_migrate_in
);
1822 qtest_add_data_func("failover-virtio-net/migrate/guest_off/abort", tmpfile
,
1823 test_migrate_guest_off_abort
);
1824 qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
1825 tmpfile
, test_migrate_abort_wait_unplug
);
1826 qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile
,
1827 test_migrate_abort_active
);
1828 if (g_test_slow()) {
1829 qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
1830 tmpfile
, test_migrate_abort_timeout
);
1832 qtest_add_data_func("failover-virtio-net/migrate/multi/out",
1833 tmpfile
, test_multi_out
);
1834 qtest_add_data_func("failover-virtio-net/migrate/multi/in",
1835 tmpfile
, test_multi_in
);