chardev/parallel: Don't close stdin on inappropriate device
[qemu/armbru.git] / tests / qtest / virtio-net-failover.c
blob73dfabc2728bc26927c4c8df35e62f85d7907795
1 /*
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
9 */
10 #include "qemu/osdep.h"
11 #include "libqtest.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)
42 QTestState *qts;
43 QPCIDevice *dev;
44 int bus;
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);
59 g_free(dev);
62 return qts;
65 static void machine_stop(QTestState *qts)
67 qpci_free_pc(pcibus);
68 alloc_destroy(&guest_malloc);
69 qtest_quit(qts);
72 static void test_error_id(void)
74 QTestState *qts;
75 QDict *resp;
76 QDict *err;
78 qts = machine_start(BASE_MACHINE
79 "-device virtio-net,bus=root0,id=standby0,failover=on",
80 2);
82 resp = qtest_qmp(qts, "{'execute': 'device_add',"
83 "'arguments': {"
84 "'driver': 'virtio-net',"
85 "'bus': 'root1',"
86 "'failover_pair_id': 'standby0'"
87 "} }");
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");
96 qobject_unref(resp);
98 machine_stop(qts);
101 static void test_error_pcie(void)
103 QTestState *qts;
104 QDict *resp;
105 QDict *err;
107 qts = machine_start(BASE_MACHINE
108 "-device virtio-net,bus=root0,id=standby0,failover=on",
111 resp = qtest_qmp(qts, "{'execute': 'device_add',"
112 "'arguments': {"
113 "'driver': 'virtio-net',"
114 "'id': 'primary0',"
115 "'bus': 'pcie.0',"
116 "'failover_pair_id': 'standby0'"
117 "} }");
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");
126 qobject_unref(resp);
128 machine_stop(qts);
131 static QDict *find_device(QDict *bus, const char *name)
133 const QObject *obj;
134 QList *devices;
135 QList *list;
137 devices = qdict_get_qlist(bus, "devices");
138 if (devices == NULL) {
139 return NULL;
142 list = qlist_copy(devices);
143 while ((obj = qlist_pop(list))) {
144 QDict *device;
146 device = qobject_to(QDict, obj);
148 if (qdict_haskey(device, "pci_bridge")) {
149 QDict *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);
156 if (bridge_device) {
157 qobject_unref(device);
158 qobject_unref(list);
159 return bridge_device;
164 if (!qdict_haskey(device, "qdev_id")) {
165 qobject_unref(device);
166 continue;
169 if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) {
170 qobject_unref(list);
171 return device;
173 qobject_unref(device);
175 qobject_unref(list);
177 return NULL;
180 static QDict *get_bus(QTestState *qts, int num)
182 QObject *obj;
183 QDict *resp;
184 QList *ret;
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))) {
193 QDict *bus;
195 bus = qobject_to(QDict, obj);
196 if (!qdict_haskey(bus, "bus")) {
197 qobject_unref(bus);
198 continue;
200 if (qdict_get_int(bus, "bus") == num) {
201 qobject_unref(resp);
202 return bus;
204 qobject_ref(bus);
206 qobject_unref(resp);
208 return NULL;
211 static char *get_mac(QTestState *qts, const char *name)
213 QDict *resp;
214 char *mac;
216 resp = qtest_qmp(qts, "{ 'execute': 'qom-get', "
217 "'arguments': { "
218 "'path': %s, "
219 "'property': 'mac' } }", name);
221 g_assert(qdict_haskey(resp, "return"));
223 mac = g_strdup(qdict_get_str(resp, "return"));
225 qobject_unref(resp);
227 return mac;
230 #define check_one_card(qts, present, id, mac) \
231 do { \
232 QDict *device; \
233 QDict *bus; \
234 char *addr; \
235 bus = get_bus(qts, 0); \
236 device = find_device(bus, id); \
237 if (present) { \
238 char *path; \
239 g_assert_nonnull(device); \
240 qobject_unref(device); \
241 path = g_strdup_printf("/machine/peripheral/%s", id); \
242 addr = get_mac(qts, path); \
243 g_free(path); \
244 g_assert_cmpstr(mac, ==, addr); \
245 g_free(addr); \
246 } else { \
247 g_assert_null(device); \
249 qobject_unref(bus); \
250 } while (0)
252 static QDict *get_failover_negociated_event(QTestState *qts)
254 QDict *resp;
255 QDict *data;
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"));
262 qobject_ref(data);
263 qobject_unref(resp);
265 return data;
268 static QVirtioPCIDevice *start_virtio_net_internal(QTestState *qts,
269 int bus, int slot,
270 uint64_t *features)
272 QVirtioPCIDevice *dev;
273 QPCIAddress addr;
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);
283 return dev;
286 static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
287 const char *id, bool failover)
289 QVirtioPCIDevice *dev;
290 uint64_t features;
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);
300 if (failover) {
301 QDict *resp;
303 resp = get_failover_negociated_event(qts);
304 g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
305 qobject_unref(resp);
308 return dev;
311 static void test_on(void)
313 QTestState *qts;
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);
327 machine_stop(qts);
330 static void test_on_mismatch(void)
332 QTestState *qts;
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);
353 machine_stop(qts);
356 static void test_off(void)
358 QTestState *qts;
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);
379 machine_stop(qts);
382 static void test_enabled(void)
384 QTestState *qts;
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);
405 machine_stop(qts);
408 static void test_guest_off(void)
410 QTestState *qts;
411 QVirtioPCIDevice *vdev;
412 uint64_t features;
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);
437 machine_stop(qts);
440 static void test_hotplug_1(void)
442 QTestState *qts;
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",
460 "{'bus': 'root1',"
461 "'failover_pair_id': 'standby0',"
462 "'netdev': 'hs1',"
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);
469 machine_stop(qts);
472 static void test_hotplug_1_reverse(void)
474 QTestState *qts;
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",
488 "{'bus': 'root0',"
489 "'failover': true,"
490 "'netdev': 'hs0',"
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);
502 machine_stop(qts);
505 static void test_hotplug_2(void)
507 QTestState *qts;
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",
519 "{'bus': 'root0',"
520 "'failover': true,"
521 "'netdev': 'hs0',"
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",
533 "{'bus': 'root1',"
534 "'failover_pair_id': 'standby0',"
535 "'netdev': 'hs1',"
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);
542 machine_stop(qts);
545 static void test_hotplug_2_reverse(void)
547 QTestState *qts;
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",
559 "{'bus': 'root1',"
560 "'failover_pair_id': 'standby0',"
561 "'netdev': 'hs1',"
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",
568 "{'bus': 'root0',"
569 "'failover': true,"
570 "'netdev': 'hs0',"
571 "'rombar': 0,"
572 "'romfile': '',"
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);
589 machine_stop(qts);
592 #ifndef _WIN32
593 static QDict *migrate_status(QTestState *qts)
595 QDict *resp, *ret;
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"));
602 qobject_ref(ret);
603 qobject_unref(resp);
605 return ret;
608 static QDict *get_unplug_primary_event(QTestState *qts)
610 QDict *resp;
611 QDict *data;
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"));
618 qobject_ref(data);
619 qobject_unref(resp);
621 return data;
624 static void test_migrate_out(gconstpointer opaque)
626 QTestState *qts;
627 QDict *resp, *args, *ret;
628 g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
629 const gchar *status;
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",
641 "{'bus': 'root0',"
642 "'failover': true,"
643 "'netdev': 'hs0',"
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",
655 "{'bus': 'root1',"
656 "'failover_pair_id': 'standby0',"
657 "'netdev': 'hs1',"
658 "'rombar': 0,"
659 "'romfile': '',"
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"));
671 qobject_unref(resp);
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");
676 qobject_unref(resp);
678 /* wait the end of the migration setup phase */
679 while (true) {
680 ret = migrate_status(qts);
682 status = qdict_get_str(ret, "status");
683 if (strcmp(status, "wait-unplug") == 0) {
684 qobject_unref(ret);
685 break;
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");
695 qobject_unref(ret);
698 if (g_test_slow()) {
699 /* check we stay in wait-unplug while the card is not ejected */
700 for (int i = 0; i < 5; i++) {
701 sleep(1);
702 ret = migrate_status(qts);
703 status = qdict_get_str(ret, "status");
704 g_assert_cmpstr(status, ==, "wait-unplug");
705 qobject_unref(ret);
709 /* OS unplugs the cards, QEMU can move from wait-unplug state */
710 qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
712 while (true) {
713 ret = migrate_status(qts);
715 status = qdict_get_str(ret, "status");
716 if (strcmp(status, "completed") == 0) {
717 qobject_unref(ret);
718 break;
720 g_assert_cmpstr(status, !=, "failed");
721 g_assert_cmpstr(status, !=, "cancelling");
722 g_assert_cmpstr(status, !=, "cancelled");
723 qobject_unref(ret);
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);
737 machine_stop(qts);
740 static void test_migrate_in(gconstpointer opaque)
742 QTestState *qts;
743 QDict *resp, *ret;
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 "
749 "-incoming defer ",
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",
756 "{'bus': 'root0',"
757 "'failover': true,"
758 "'netdev': 'hs0',"
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",
765 "{'bus': 'root1',"
766 "'failover_pair_id': 'standby0',"
767 "'netdev': 'hs1',"
768 "'rombar': 0,"
769 "'romfile': '',"
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");
779 qobject_unref(resp);
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");
788 qobject_unref(ret);
790 machine_stop(qts);
793 static void test_off_migrate_out(gconstpointer opaque)
795 QTestState *qts;
796 QDict *resp, *args, *ret;
797 g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
798 const gchar *status;
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",
810 "{'bus': 'root0',"
811 "'failover': false,"
812 "'netdev': 'hs0',"
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",
819 "{'bus': 'root1',"
820 "'failover_pair_id': 'standby0',"
821 "'netdev': 'hs1',"
822 "'rombar': 0,"
823 "'romfile': '',"
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"));
840 qobject_unref(resp);
842 while (true) {
843 ret = migrate_status(qts);
845 status = qdict_get_str(ret, "status");
846 if (strcmp(status, "completed") == 0) {
847 qobject_unref(ret);
848 break;
850 g_assert_cmpstr(status, !=, "failed");
851 g_assert_cmpstr(status, !=, "cancelling");
852 g_assert_cmpstr(status, !=, "cancelled");
853 qobject_unref(ret);
856 qtest_qmp_eventwait(qts, "STOP");
858 qos_object_destroy((QOSGraphObject *)vdev);
859 machine_stop(qts);
862 static void test_off_migrate_in(gconstpointer opaque)
864 QTestState *qts;
865 QDict *ret;
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 "
871 "-incoming defer ",
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",
878 "{'bus': 'root0',"
879 "'failover': false,"
880 "'netdev': 'hs0',"
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",
887 "{'bus': 'root1',"
888 "'failover_pair_id': 'standby0',"
889 "'netdev': 'hs1',"
890 "'rombar': 0,"
891 "'romfile': '',"
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");
906 qobject_unref(ret);
908 machine_stop(qts);
911 static void test_guest_off_migrate_out(gconstpointer opaque)
913 QTestState *qts;
914 QDict *resp, *args, *ret;
915 g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
916 const gchar *status;
917 QVirtioPCIDevice *vdev;
918 uint64_t features;
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",
929 "{'bus': 'root0',"
930 "'failover': true,"
931 "'netdev': 'hs0',"
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",
938 "{'bus': 'root1',"
939 "'failover_pair_id': 'standby0',"
940 "'netdev': 'hs1',"
941 "'rombar': 0,"
942 "'romfile': '',"
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"));
964 qobject_unref(resp);
966 while (true) {
967 ret = migrate_status(qts);
969 status = qdict_get_str(ret, "status");
970 if (strcmp(status, "completed") == 0) {
971 qobject_unref(ret);
972 break;
974 g_assert_cmpstr(status, !=, "failed");
975 g_assert_cmpstr(status, !=, "cancelling");
976 g_assert_cmpstr(status, !=, "cancelled");
977 qobject_unref(ret);
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);
986 machine_stop(qts);
989 static void test_guest_off_migrate_in(gconstpointer opaque)
991 QTestState *qts;
992 QDict *ret;
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 "
998 "-incoming defer ",
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",
1005 "{'bus': 'root0',"
1006 "'failover': true,"
1007 "'netdev': 'hs0',"
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",
1014 "{'bus': 'root1',"
1015 "'failover_pair_id': 'standby0',"
1016 "'netdev': 'hs1',"
1017 "'rombar': 0,"
1018 "'romfile': '',"
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");
1033 qobject_unref(ret);
1035 machine_stop(qts);
1038 static void test_migrate_guest_off_abort(gconstpointer opaque)
1040 QTestState *qts;
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;
1045 uint64_t features;
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",
1056 "{'bus': 'root0',"
1057 "'failover': true,"
1058 "'netdev': 'hs0',"
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",
1065 "{'bus': 'root1',"
1066 "'failover_pair_id': 'standby0',"
1067 "'netdev': 'hs1',"
1068 "'rombar': 0,"
1069 "'romfile': '',"
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);
1093 while (true) {
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");
1099 qobject_unref(ret);
1100 goto out;
1102 if (strcmp(status, "active") == 0) {
1103 qobject_unref(ret);
1104 break;
1106 g_assert_cmpstr(status, !=, "failed");
1107 qobject_unref(ret);
1110 resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1111 g_assert(qdict_haskey(resp, "return"));
1112 qobject_unref(resp);
1114 while (true) {
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");
1119 qobject_unref(ret);
1120 goto out;
1122 if (strcmp(status, "cancelled") == 0) {
1123 qobject_unref(ret);
1124 break;
1126 g_assert_cmpstr(status, !=, "failed");
1127 g_assert_cmpstr(status, !=, "active");
1128 qobject_unref(ret);
1131 check_one_card(qts, true, "standby0", MAC_STANDBY0);
1132 check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1134 out:
1135 qos_object_destroy((QOSGraphObject *)vdev);
1136 machine_stop(qts);
1139 static void test_migrate_abort_wait_unplug(gconstpointer opaque)
1141 QTestState *qts;
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",
1156 "{'bus': 'root0',"
1157 "'failover': true,"
1158 "'netdev': 'hs0',"
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",
1170 "{'bus': 'root1',"
1171 "'failover_pair_id': 'standby0',"
1172 "'netdev': 'hs1',"
1173 "'rombar': 0,"
1174 "'romfile': '',"
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");
1204 qobject_unref(ret);
1206 /* OS unplugs the cards, QEMU can move from wait-unplug state */
1207 qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1209 while (true) {
1210 ret = migrate_status(qts);
1212 status = qdict_get_str(ret, "status");
1213 if (strcmp(status, "cancelled") == 0) {
1214 qobject_unref(ret);
1215 break;
1217 g_assert_cmpstr(status, ==, "cancelling");
1218 qobject_unref(ret);
1221 check_one_card(qts, true, "standby0", MAC_STANDBY0);
1222 check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1224 qos_object_destroy((QOSGraphObject *)vdev);
1225 machine_stop(qts);
1228 static void test_migrate_abort_active(gconstpointer opaque)
1230 QTestState *qts;
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",
1245 "{'bus': 'root0',"
1246 "'failover': true,"
1247 "'netdev': 'hs0',"
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",
1259 "{'bus': 'root1',"
1260 "'failover_pair_id': 'standby0',"
1261 "'netdev': 'hs1',"
1262 "'rombar': 0,"
1263 "'romfile': '',"
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);
1285 while (true) {
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) {
1291 qobject_unref(ret);
1292 break;
1294 qobject_unref(ret);
1297 resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1298 g_assert(qdict_haskey(resp, "return"));
1299 qobject_unref(resp);
1301 while (true) {
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");
1307 qobject_unref(ret);
1308 goto out;
1310 if (strcmp(status, "cancelled") == 0) {
1311 qobject_unref(ret);
1312 break;
1314 g_assert_cmpstr(status, !=, "failed");
1315 g_assert_cmpstr(status, !=, "active");
1316 qobject_unref(ret);
1319 check_one_card(qts, true, "standby0", MAC_STANDBY0);
1320 check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1322 out:
1323 qos_object_destroy((QOSGraphObject *)vdev);
1324 machine_stop(qts);
1327 static void test_migrate_off_abort(gconstpointer opaque)
1329 QTestState *qts;
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",
1344 "{'bus': 'root0',"
1345 "'failover': false,"
1346 "'netdev': 'hs0',"
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",
1358 "{'bus': 'root1',"
1359 "'failover_pair_id': 'standby0',"
1360 "'netdev': 'hs1',"
1361 "'rombar': 0,"
1362 "'romfile': '',"
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);
1376 while (true) {
1377 ret = migrate_status(qts);
1379 status = qdict_get_str(ret, "status");
1380 if (strcmp(status, "active") == 0) {
1381 qobject_unref(ret);
1382 break;
1384 g_assert_cmpstr(status, !=, "failed");
1385 qobject_unref(ret);
1388 resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1389 g_assert(qdict_haskey(resp, "return"));
1390 qobject_unref(resp);
1392 while (true) {
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");
1398 qobject_unref(ret);
1399 goto out;
1401 if (strcmp(status, "cancelled") == 0) {
1402 qobject_unref(ret);
1403 break;
1405 g_assert_cmpstr(status, !=, "failed");
1406 g_assert_cmpstr(status, !=, "active");
1407 qobject_unref(ret);
1410 check_one_card(qts, true, "standby0", MAC_STANDBY0);
1411 check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1413 out:
1414 qos_object_destroy((QOSGraphObject *)vdev);
1415 machine_stop(qts);
1418 static void test_migrate_abort_timeout(gconstpointer opaque)
1420 QTestState *qts;
1421 QDict *resp, *args, *ret;
1422 g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1423 const gchar *status;
1424 int total;
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",
1436 "{'bus': 'root0',"
1437 "'failover': true,"
1438 "'netdev': 'hs0',"
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",
1450 "{'bus': 'root1',"
1451 "'failover_pair_id': 'standby0',"
1452 "'netdev': 'hs1',"
1453 "'rombar': 0,"
1454 "'romfile': '',"
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 */
1481 total = 0;
1482 while (true) {
1483 ret = migrate_status(qts);
1485 status = qdict_get_str(ret, "status");
1486 if (strcmp(status, "cancelled") == 0) {
1487 qobject_unref(ret);
1488 break;
1490 g_assert_cmpstr(status, ==, "cancelling");
1491 g_assert(qdict_haskey(ret, "total-time"));
1492 total = qdict_get_int(ret, "total-time");
1493 qobject_unref(ret);
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);
1506 machine_stop(qts);
1509 static void test_multi_out(gconstpointer opaque)
1511 QTestState *qts;
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",
1532 "{'bus': 'root0',"
1533 "'failover': true,"
1534 "'netdev': 'hs0',"
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",
1543 "{'bus': 'root1',"
1544 "'failover_pair_id': 'standby0',"
1545 "'netdev': 'hs1',"
1546 "'rombar': 0,"
1547 "'romfile': '',"
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",
1563 "{'bus': 'root2',"
1564 "'failover': true,"
1565 "'netdev': 'hs2',"
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",
1574 "{'bus': 'root3',"
1575 "'failover_pair_id': 'standby1',"
1576 "'netdev': 'hs3',"
1577 "'rombar': 0,"
1578 "'romfile': '',"
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";
1607 } else {
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 */
1617 while (true) {
1618 ret = migrate_status(qts);
1620 status = qdict_get_str(ret, "status");
1621 if (strcmp(status, "wait-unplug") == 0) {
1622 qobject_unref(ret);
1623 break;
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");
1633 qobject_unref(ret);
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");
1642 qobject_unref(ret);
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++) {
1647 sleep(1);
1648 ret = migrate_status(qts);
1649 status = qdict_get_str(ret, "status");
1650 g_assert_cmpstr(status, ==, "wait-unplug");
1651 qobject_unref(ret);
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);
1659 while (true) {
1660 ret = migrate_status(qts);
1662 status = qdict_get_str(ret, "status");
1663 if (strcmp(status, "completed") == 0) {
1664 qobject_unref(ret);
1665 break;
1667 g_assert_cmpstr(status, !=, "failed");
1668 g_assert_cmpstr(status, !=, "cancelling");
1669 g_assert_cmpstr(status, !=, "cancelled");
1670 qobject_unref(ret);
1673 qtest_qmp_eventwait(qts, "STOP");
1675 qos_object_destroy((QOSGraphObject *)vdev0);
1676 qos_object_destroy((QOSGraphObject *)vdev1);
1677 machine_stop(qts);
1680 static void test_multi_in(gconstpointer opaque)
1682 QTestState *qts;
1683 QDict *resp, *ret;
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 "
1693 "-incoming defer ",
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",
1702 "{'bus': 'root0',"
1703 "'failover': true,"
1704 "'netdev': 'hs0',"
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",
1713 "{'bus': 'root1',"
1714 "'failover_pair_id': 'standby0',"
1715 "'netdev': 'hs1',"
1716 "'rombar': 0,"
1717 "'romfile': '',"
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",
1726 "{'bus': 'root2',"
1727 "'failover': true,"
1728 "'netdev': 'hs2',"
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",
1737 "{'bus': 'root3',"
1738 "'failover_pair_id': 'standby1',"
1739 "'netdev': 'hs3',"
1740 "'rombar': 0,"
1741 "'romfile': '',"
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");
1768 qobject_unref(ret);
1770 machine_stop(qts);
1772 #endif /* _WIN32 */
1774 int main(int argc, char **argv)
1776 gchar *tmpfile;
1777 int ret;
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);
1783 close(ret);
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",
1790 test_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);
1795 /* hotplug tests */
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);
1803 #ifndef _WIN32
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,
1809 test_migrate_out);
1810 qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile,
1811 test_migrate_in);
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);
1836 #endif /* _WIN32 */
1838 ret = g_test_run();
1840 unlink(tmpfile);
1841 g_free(tmpfile);
1843 return ret;