1 /*
2  * QTest testcase for virtio-net failover
3  *
4  * See docs/system/virtio-net-failover.rst
5  *
6  * Copyright (c) 2021 Red Hat, Inc.
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 #include "qemu/osdep.h"
11 #include "libqtest.h"
12 #include "libqos/pci.h"
13 #include "libqos/pci-pc.h"
14 #include "qapi/qmp/qdict.h"
15 #include "qapi/qmp/qlist.h"
16 #include "qapi/qmp/qjson.h"
17 #include "libqos/malloc-pc.h"
18 #include "libqos/virtio-pci.h"
19 #include "hw/pci/pci.h"
20 
21 #define VIRTIO_NET_F_STANDBY    62
22 
23 #define ACPI_PCIHP_ADDR_ICH9    0x0cc0
24 #define PCI_EJ_BASE             0x0008
25 #define PCI_SEL_BASE            0x0010
26 
27 #define BASE_MACHINE "-M q35 -nodefaults " \
28     "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
29     "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "
30 
31 #define MAC_PRIMARY0 "52:54:00:11:11:11"
32 #define MAC_STANDBY0 "52:54:00:22:22:22"
33 #define MAC_PRIMARY1 "52:54:00:33:33:33"
34 #define MAC_STANDBY1 "52:54:00:44:44:44"
35 
36 static QGuestAllocator guest_malloc;
37 static QPCIBus *pcibus;
38 
39 static QTestState *machine_start(const char *args, int numbus)
40 {
41     QTestState *qts;
42     QPCIDevice *dev;
43     int bus;
44 
45     qts = qtest_init(args);
46 
47     pc_alloc_init(&guest_malloc, qts, 0);
48     pcibus = qpci_new_pc(qts, &guest_malloc);
49     g_assert(qpci_secondary_buses_init(pcibus) == numbus);
50 
51     for (bus = 1; bus <= numbus; bus++) {
52         dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0));
53         g_assert_nonnull(dev);
54 
55         qpci_device_enable(dev);
56         qpci_iomap(dev, 4, NULL);
57 
58         g_free(dev);
59     }
60 
61     return qts;
62 }
63 
64 static void machine_stop(QTestState *qts)
65 {
66     qpci_free_pc(pcibus);
67     alloc_destroy(&guest_malloc);
68     qtest_quit(qts);
69 }
70 
71 static void test_error_id(void)
72 {
73     QTestState *qts;
74     QDict *resp;
75     QDict *err;
76 
77     qts = machine_start(BASE_MACHINE
78                         "-device virtio-net,bus=root0,id=standby0,failover=on",
79                         2);
80 
81     resp = qtest_qmp(qts, "{'execute': 'device_add',"
82                           "'arguments': {"
83                           "'driver': 'virtio-net',"
84                           "'bus': 'root1',"
85                           "'failover_pair_id': 'standby0'"
86                           "} }");
87     g_assert(qdict_haskey(resp, "error"));
88 
89     err = qdict_get_qdict(resp, "error");
90     g_assert(qdict_haskey(err, "desc"));
91 
92     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
93                     "Device with failover_pair_id needs to have id");
94 
95     qobject_unref(resp);
96 
97     machine_stop(qts);
98 }
99 
100 static void test_error_pcie(void)
101 {
102     QTestState *qts;
103     QDict *resp;
104     QDict *err;
105 
106     qts = machine_start(BASE_MACHINE
107                         "-device virtio-net,bus=root0,id=standby0,failover=on",
108                         2);
109 
110     resp = qtest_qmp(qts, "{'execute': 'device_add',"
111                           "'arguments': {"
112                           "'driver': 'virtio-net',"
113                           "'id': 'primary0',"
114                           "'bus': 'pcie.0',"
115                           "'failover_pair_id': 'standby0'"
116                           "} }");
117     g_assert(qdict_haskey(resp, "error"));
118 
119     err = qdict_get_qdict(resp, "error");
120     g_assert(qdict_haskey(err, "desc"));
121 
122     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
123                     "Bus 'pcie.0' does not support hotplugging");
124 
125     qobject_unref(resp);
126 
127     machine_stop(qts);
128 }
129 
130 static QDict *find_device(QDict *bus, const char *name)
131 {
132     const QObject *obj;
133     QList *devices;
134     QList *list;
135 
136     devices = qdict_get_qlist(bus, "devices");
137     if (devices == NULL) {
138         return NULL;
139     }
140 
141     list = qlist_copy(devices);
142     while ((obj = qlist_pop(list))) {
143         QDict *device;
144 
145         device = qobject_to(QDict, obj);
146 
147         if (qdict_haskey(device, "pci_bridge")) {
148             QDict *bridge;
149             QDict *bridge_device;
150 
151             bridge = qdict_get_qdict(device, "pci_bridge");
152 
153             if (qdict_haskey(bridge, "devices")) {
154                 bridge_device = find_device(bridge, name);
155                 if (bridge_device) {
156                     qobject_unref(device);
157                     qobject_unref(list);
158                     return bridge_device;
159                 }
160             }
161         }
162 
163         if (!qdict_haskey(device, "qdev_id")) {
164             qobject_unref(device);
165             continue;
166         }
167 
168         if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) {
169             qobject_unref(list);
170             return device;
171         }
172         qobject_unref(device);
173     }
174     qobject_unref(list);
175 
176     return NULL;
177 }
178 
179 static QDict *get_bus(QTestState *qts, int num)
180 {
181     QObject *obj;
182     QDict *resp;
183     QList *ret;
184 
185     resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }");
186     g_assert(qdict_haskey(resp, "return"));
187 
188     ret = qdict_get_qlist(resp, "return");
189     g_assert_nonnull(ret);
190 
191     while ((obj = qlist_pop(ret))) {
192         QDict *bus;
193 
194         bus = qobject_to(QDict, obj);
195         if (!qdict_haskey(bus, "bus")) {
196             qobject_unref(bus);
197             continue;
198         }
199         if (qdict_get_int(bus, "bus") == num) {
200             qobject_unref(resp);
201             return bus;
202         }
203         qobject_ref(bus);
204     }
205     qobject_unref(resp);
206 
207     return NULL;
208 }
209 
210 static char *get_mac(QTestState *qts, const char *name)
211 {
212     QDict *resp;
213     char *mac;
214 
215     resp = qtest_qmp(qts, "{ 'execute': 'qom-get', "
216                      "'arguments': { "
217                      "'path': %s, "
218                      "'property': 'mac' } }", name);
219 
220     g_assert(qdict_haskey(resp, "return"));
221 
222     mac = g_strdup(qdict_get_str(resp, "return"));
223 
224     qobject_unref(resp);
225 
226     return mac;
227 }
228 
229 #define check_one_card(qts, present, id, mac)                   \
230 do {                                                            \
231     QDict *device;                                              \
232     QDict *bus;                                                 \
233     char *addr;                                                 \
234     bus = get_bus(qts, 0);                                      \
235     device = find_device(bus, id);                              \
236     if (present) {                                              \
237         char *path;                                             \
238         g_assert_nonnull(device);                               \
239         qobject_unref(device);                                  \
240         path = g_strdup_printf("/machine/peripheral/%s", id);   \
241         addr = get_mac(qts, path);                              \
242         g_free(path);                                           \
243         g_assert_cmpstr(mac, ==, addr);                         \
244         g_free(addr);                                           \
245     } else {                                                    \
246        g_assert_null(device);                                   \
247     }                                                           \
248     qobject_unref(bus);                                         \
249 } while (0)
250 
251 static QDict *get_failover_negociated_event(QTestState *qts)
252 {
253     QDict *resp;
254     QDict *data;
255 
256     resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED");
257     g_assert(qdict_haskey(resp, "data"));
258 
259     data = qdict_get_qdict(resp, "data");
260     g_assert(qdict_haskey(data, "device-id"));
261     qobject_ref(data);
262     qobject_unref(resp);
263 
264     return data;
265 }
266 
267 static QVirtioPCIDevice *start_virtio_net_internal(QTestState *qts,
268                                                    int bus, int slot,
269                                                    uint64_t *features)
270 {
271     QVirtioPCIDevice *dev;
272     QPCIAddress addr;
273 
274     addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0);
275     dev = virtio_pci_new(pcibus, &addr);
276     g_assert_nonnull(dev);
277     qvirtio_pci_device_enable(dev);
278     qvirtio_start_device(&dev->vdev);
279     *features &= qvirtio_get_features(&dev->vdev);
280     qvirtio_set_features(&dev->vdev, *features);
281     qvirtio_set_driver_ok(&dev->vdev);
282     return dev;
283 }
284 
285 static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
286                                           const char *id, bool failover)
287 {
288     QVirtioPCIDevice *dev;
289     uint64_t features;
290 
291     features = ~(QVIRTIO_F_BAD_FEATURE |
292                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
293                  (1ull << VIRTIO_RING_F_EVENT_IDX));
294 
295     dev = start_virtio_net_internal(qts, bus, slot, &features);
296 
297     g_assert(!!(features & (1ull << VIRTIO_NET_F_STANDBY)) == failover);
298 
299     if (failover) {
300         QDict *resp;
301 
302         resp = get_failover_negociated_event(qts);
303         g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
304         qobject_unref(resp);
305     }
306 
307     return dev;
308 }
309 
310 static void test_on(void)
311 {
312     QTestState *qts;
313 
314     qts = machine_start(BASE_MACHINE
315                         "-netdev user,id=hs0 "
316                         "-device virtio-net,bus=root0,id=standby0,"
317                         "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
318                         "-netdev user,id=hs1 "
319                         "-device virtio-net,bus=root1,id=primary0,"
320                         "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
321                         2);
322 
323     check_one_card(qts, true, "standby0", MAC_STANDBY0);
324     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
325 
326     machine_stop(qts);
327 }
328 
329 static void test_on_mismatch(void)
330 {
331     QTestState *qts;
332     QVirtioPCIDevice *vdev;
333 
334     qts = machine_start(BASE_MACHINE
335                      "-netdev user,id=hs0 "
336                      "-device virtio-net,bus=root0,id=standby0,"
337                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
338                      "-netdev user,id=hs1 "
339                      "-device virtio-net,bus=root1,id=primary0,"
340                      "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0,
341                      2);
342 
343     check_one_card(qts, true, "standby0", MAC_STANDBY0);
344     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
345 
346     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
347 
348     check_one_card(qts, true, "standby0", MAC_STANDBY0);
349     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
350 
351     qos_object_destroy((QOSGraphObject *)vdev);
352     machine_stop(qts);
353 }
354 
355 static void test_off(void)
356 {
357     QTestState *qts;
358     QVirtioPCIDevice *vdev;
359 
360     qts = machine_start(BASE_MACHINE
361                      "-netdev user,id=hs0 "
362                      "-device virtio-net,bus=root0,id=standby0,"
363                      "failover=off,netdev=hs0,mac="MAC_STANDBY0" "
364                      "-netdev user,id=hs1 "
365                      "-device virtio-net,bus=root1,id=primary0,"
366                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
367                      2);
368 
369     check_one_card(qts, true, "standby0", MAC_STANDBY0);
370     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
371 
372     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
373 
374     check_one_card(qts, true, "standby0", MAC_STANDBY0);
375     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
376 
377     qos_object_destroy((QOSGraphObject *)vdev);
378     machine_stop(qts);
379 }
380 
381 static void test_enabled(void)
382 {
383     QTestState *qts;
384     QVirtioPCIDevice *vdev;
385 
386     qts = machine_start(BASE_MACHINE
387                      "-netdev user,id=hs0 "
388                      "-device virtio-net,bus=root0,id=standby0,"
389                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
390                      "-netdev user,id=hs1 "
391                      "-device virtio-net,bus=root1,id=primary0,"
392                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
393                      2);
394 
395     check_one_card(qts, true, "standby0", MAC_STANDBY0);
396     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
397 
398     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
399 
400     check_one_card(qts, true, "standby0", MAC_STANDBY0);
401     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
402 
403     qos_object_destroy((QOSGraphObject *)vdev);
404     machine_stop(qts);
405 }
406 
407 static void test_guest_off(void)
408 {
409     QTestState *qts;
410     QVirtioPCIDevice *vdev;
411     uint64_t features;
412 
413     qts = machine_start(BASE_MACHINE
414                      "-netdev user,id=hs0 "
415                      "-device virtio-net,bus=root0,id=standby0,"
416                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
417                      "-netdev user,id=hs1 "
418                      "-device virtio-net,bus=root1,id=primary0,"
419                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
420                      2);
421 
422     check_one_card(qts, true, "standby0", MAC_STANDBY0);
423     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
424 
425     features = ~(QVIRTIO_F_BAD_FEATURE |
426                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
427                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
428                  (1ull << VIRTIO_NET_F_STANDBY));
429 
430     vdev = start_virtio_net_internal(qts, 1, 0, &features);
431 
432     check_one_card(qts, true, "standby0", MAC_STANDBY0);
433     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
434 
435     qos_object_destroy((QOSGraphObject *)vdev);
436     machine_stop(qts);
437 }
438 
439 static void test_hotplug_1(void)
440 {
441     QTestState *qts;
442     QVirtioPCIDevice *vdev;
443 
444     qts = machine_start(BASE_MACHINE
445                      "-netdev user,id=hs0 "
446                      "-device virtio-net,bus=root0,id=standby0,"
447                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
448                      "-netdev user,id=hs1 ", 2);
449 
450     check_one_card(qts, true, "standby0", MAC_STANDBY0);
451     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
452 
453     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
454 
455     check_one_card(qts, true, "standby0", MAC_STANDBY0);
456     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
457 
458     qtest_qmp_device_add(qts, "virtio-net", "primary0",
459                          "{'bus': 'root1',"
460                          "'failover_pair_id': 'standby0',"
461                          "'netdev': 'hs1',"
462                          "'mac': '"MAC_PRIMARY0"'}");
463 
464     check_one_card(qts, true, "standby0", MAC_STANDBY0);
465     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
466 
467     qos_object_destroy((QOSGraphObject *)vdev);
468     machine_stop(qts);
469 }
470 
471 static void test_hotplug_1_reverse(void)
472 {
473     QTestState *qts;
474     QVirtioPCIDevice *vdev;
475 
476     qts = machine_start(BASE_MACHINE
477                      "-netdev user,id=hs0 "
478                      "-netdev user,id=hs1 "
479                      "-device virtio-net,bus=root1,id=primary0,"
480                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
481                      2);
482 
483     check_one_card(qts, false, "standby0", MAC_STANDBY0);
484     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
485 
486     qtest_qmp_device_add(qts, "virtio-net", "standby0",
487                          "{'bus': 'root0',"
488                          "'failover': 'on',"
489                          "'netdev': 'hs0',"
490                          "'mac': '"MAC_STANDBY0"'}");
491 
492     check_one_card(qts, true, "standby0", MAC_STANDBY0);
493     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
494 
495     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
496 
497     check_one_card(qts, true, "standby0", MAC_STANDBY0);
498     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
499 
500     qos_object_destroy((QOSGraphObject *)vdev);
501     machine_stop(qts);
502 }
503 
504 static void test_hotplug_2(void)
505 {
506     QTestState *qts;
507     QVirtioPCIDevice *vdev;
508 
509     qts = machine_start(BASE_MACHINE
510                      "-netdev user,id=hs0 "
511                      "-netdev user,id=hs1 ",
512                      2);
513 
514     check_one_card(qts, false, "standby0", MAC_STANDBY0);
515     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
516 
517     qtest_qmp_device_add(qts, "virtio-net", "standby0",
518                          "{'bus': 'root0',"
519                          "'failover': 'on',"
520                          "'netdev': 'hs0',"
521                          "'mac': '"MAC_STANDBY0"'}");
522 
523     check_one_card(qts, true, "standby0", MAC_STANDBY0);
524     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
525 
526     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
527 
528     check_one_card(qts, true, "standby0", MAC_STANDBY0);
529     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
530 
531     qtest_qmp_device_add(qts, "virtio-net", "primary0",
532                          "{'bus': 'root1',"
533                          "'failover_pair_id': 'standby0',"
534                          "'netdev': 'hs1',"
535                          "'mac': '"MAC_PRIMARY0"'}");
536 
537     check_one_card(qts, true, "standby0", MAC_STANDBY0);
538     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
539 
540     qos_object_destroy((QOSGraphObject *)vdev);
541     machine_stop(qts);
542 }
543 
544 static void test_hotplug_2_reverse(void)
545 {
546     QTestState *qts;
547     QVirtioPCIDevice *vdev;
548 
549     qts = machine_start(BASE_MACHINE
550                      "-netdev user,id=hs0 "
551                      "-netdev user,id=hs1 ",
552                      2);
553 
554     check_one_card(qts, false, "standby0", MAC_STANDBY0);
555     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
556 
557     qtest_qmp_device_add(qts, "virtio-net", "primary0",
558                          "{'bus': 'root1',"
559                          "'failover_pair_id': 'standby0',"
560                          "'netdev': 'hs1',"
561                          "'mac': '"MAC_PRIMARY0"'}");
562 
563     check_one_card(qts, false, "standby0", MAC_STANDBY0);
564     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
565 
566     qtest_qmp_device_add(qts, "virtio-net", "standby0",
567                          "{'bus': 'root0',"
568                          "'failover': 'on',"
569                          "'netdev': 'hs0',"
570                          "'rombar': 0,"
571                          "'romfile': '',"
572                          "'mac': '"MAC_STANDBY0"'}");
573 
574     /*
575      * XXX: sounds like a bug:
576      * The primary should be hidden until the virtio-net driver
577      * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
578      */
579     check_one_card(qts, true, "standby0", MAC_STANDBY0);
580     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
581 
582     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
583 
584     check_one_card(qts, true, "standby0", MAC_STANDBY0);
585     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
586 
587     qos_object_destroy((QOSGraphObject *)vdev);
588     machine_stop(qts);
589 }
590 
591 #ifndef _WIN32
592 static QDict *migrate_status(QTestState *qts)
593 {
594     QDict *resp, *ret;
595 
596     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
597     g_assert(qdict_haskey(resp, "return"));
598 
599     ret = qdict_get_qdict(resp, "return");
600     g_assert(qdict_haskey(ret, "status"));
601     qobject_ref(ret);
602     qobject_unref(resp);
603 
604     return ret;
605 }
606 
607 static QDict *get_unplug_primary_event(QTestState *qts)
608 {
609     QDict *resp;
610     QDict *data;
611 
612     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
613     g_assert(qdict_haskey(resp, "data"));
614 
615     data = qdict_get_qdict(resp, "data");
616     g_assert(qdict_haskey(data, "device-id"));
617     qobject_ref(data);
618     qobject_unref(resp);
619 
620     return data;
621 }
622 
623 static void test_migrate_out(gconstpointer opaque)
624 {
625     QTestState *qts;
626     QDict *resp, *args, *ret;
627     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
628     const gchar *status;
629     QVirtioPCIDevice *vdev;
630 
631     qts = machine_start(BASE_MACHINE
632                      "-netdev user,id=hs0 "
633                      "-netdev user,id=hs1 ",
634                      2);
635 
636     check_one_card(qts, false, "standby0", MAC_STANDBY0);
637     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
638 
639     qtest_qmp_device_add(qts, "virtio-net", "standby0",
640                          "{'bus': 'root0',"
641                          "'failover': 'on',"
642                          "'netdev': 'hs0',"
643                          "'mac': '"MAC_STANDBY0"'}");
644 
645     check_one_card(qts, true, "standby0", MAC_STANDBY0);
646     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
647 
648     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
649 
650     check_one_card(qts, true, "standby0", MAC_STANDBY0);
651     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
652 
653     qtest_qmp_device_add(qts, "virtio-net", "primary0",
654                          "{'bus': 'root1',"
655                          "'failover_pair_id': 'standby0',"
656                          "'netdev': 'hs1',"
657                          "'rombar': 0,"
658                          "'romfile': '',"
659                          "'mac': '"MAC_PRIMARY0"'}");
660 
661     check_one_card(qts, true, "standby0", MAC_STANDBY0);
662     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
663 
664     args = qdict_from_jsonf_nofail("{}");
665     g_assert_nonnull(args);
666     qdict_put_str(args, "uri", uri);
667 
668     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
669     g_assert(qdict_haskey(resp, "return"));
670     qobject_unref(resp);
671 
672     /* the event is sent when QEMU asks the OS to unplug the card */
673     resp = get_unplug_primary_event(qts);
674     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
675     qobject_unref(resp);
676 
677     /* wait the end of the migration setup phase */
678     while (true) {
679         ret = migrate_status(qts);
680 
681         status = qdict_get_str(ret, "status");
682         if (strcmp(status, "wait-unplug") == 0) {
683             qobject_unref(ret);
684             break;
685         }
686 
687         /* The migration must not start if the card is not ejected */
688         g_assert_cmpstr(status, !=, "active");
689         g_assert_cmpstr(status, !=, "completed");
690         g_assert_cmpstr(status, !=, "failed");
691         g_assert_cmpstr(status, !=, "cancelling");
692         g_assert_cmpstr(status, !=, "cancelled");
693 
694         qobject_unref(ret);
695     }
696 
697     if (g_test_slow()) {
698         /* check we stay in wait-unplug while the card is not ejected */
699         for (int i = 0; i < 5; i++) {
700             sleep(1);
701             ret = migrate_status(qts);
702             status = qdict_get_str(ret, "status");
703             g_assert_cmpstr(status, ==, "wait-unplug");
704             qobject_unref(ret);
705         }
706     }
707 
708     /* OS unplugs the cards, QEMU can move from wait-unplug state */
709     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
710 
711     while (true) {
712         ret = migrate_status(qts);
713 
714         status = qdict_get_str(ret, "status");
715         if (strcmp(status, "completed") == 0) {
716             qobject_unref(ret);
717             break;
718         }
719         g_assert_cmpstr(status, !=, "failed");
720         g_assert_cmpstr(status, !=, "cancelling");
721         g_assert_cmpstr(status, !=, "cancelled");
722         qobject_unref(ret);
723     }
724 
725     qtest_qmp_eventwait(qts, "STOP");
726 
727     /*
728      * in fact, the card is ejected from the point of view of kernel
729      * but not really from QEMU to be able to hotplug it back if
730      * migration fails. So we can't check that:
731      *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
732      *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
733      */
734 
735     qos_object_destroy((QOSGraphObject *)vdev);
736     machine_stop(qts);
737 }
738 
739 static QDict *get_migration_event(QTestState *qts)
740 {
741     QDict *resp;
742     QDict *data;
743 
744     resp = qtest_qmp_eventwait_ref(qts, "MIGRATION");
745     g_assert(qdict_haskey(resp, "data"));
746 
747     data = qdict_get_qdict(resp, "data");
748     g_assert(qdict_haskey(data, "status"));
749     qobject_ref(data);
750     qobject_unref(resp);
751 
752     return data;
753 }
754 
755 static void test_migrate_in(gconstpointer opaque)
756 {
757     QTestState *qts;
758     QDict *resp, *args, *ret;
759     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
760 
761     qts = machine_start(BASE_MACHINE
762                      "-netdev user,id=hs0 "
763                      "-netdev user,id=hs1 "
764                      "-incoming defer ",
765                      2);
766 
767     check_one_card(qts, false, "standby0", MAC_STANDBY0);
768     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
769 
770     qtest_qmp_device_add(qts, "virtio-net", "standby0",
771                          "{'bus': 'root0',"
772                          "'failover': 'on',"
773                          "'netdev': 'hs0',"
774                          "'mac': '"MAC_STANDBY0"'}");
775 
776     check_one_card(qts, true, "standby0", MAC_STANDBY0);
777     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
778 
779     qtest_qmp_device_add(qts, "virtio-net", "primary0",
780                          "{'bus': 'root1',"
781                          "'failover_pair_id': 'standby0',"
782                          "'netdev': 'hs1',"
783                          "'rombar': 0,"
784                          "'romfile': '',"
785                          "'mac': '"MAC_PRIMARY0"'}");
786 
787     check_one_card(qts, true, "standby0", MAC_STANDBY0);
788     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
789 
790     args = qdict_from_jsonf_nofail("{}");
791     g_assert_nonnull(args);
792     qdict_put_str(args, "uri", uri);
793 
794     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
795                      args);
796     g_assert(qdict_haskey(resp, "return"));
797     qobject_unref(resp);
798 
799     resp = get_migration_event(qts);
800     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
801     qobject_unref(resp);
802 
803     resp = get_failover_negociated_event(qts);
804     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
805     qobject_unref(resp);
806 
807     check_one_card(qts, true, "standby0", MAC_STANDBY0);
808     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
809 
810     qtest_qmp_eventwait(qts, "RESUME");
811 
812     ret = migrate_status(qts);
813     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
814     qobject_unref(ret);
815 
816     machine_stop(qts);
817 }
818 
819 static void test_off_migrate_out(gconstpointer opaque)
820 {
821     QTestState *qts;
822     QDict *resp, *args, *ret;
823     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
824     const gchar *status;
825     QVirtioPCIDevice *vdev;
826 
827     qts = machine_start(BASE_MACHINE
828                      "-netdev user,id=hs0 "
829                      "-netdev user,id=hs1 ",
830                      2);
831 
832     check_one_card(qts, false, "standby0", MAC_STANDBY0);
833     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
834 
835     qtest_qmp_device_add(qts, "virtio-net", "standby0",
836                          "{'bus': 'root0',"
837                          "'failover': 'off',"
838                          "'netdev': 'hs0',"
839                          "'mac': '"MAC_STANDBY0"'}");
840 
841     check_one_card(qts, true, "standby0", MAC_STANDBY0);
842     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
843 
844     qtest_qmp_device_add(qts, "virtio-net", "primary0",
845                          "{'bus': 'root1',"
846                          "'failover_pair_id': 'standby0',"
847                          "'netdev': 'hs1',"
848                          "'rombar': 0,"
849                          "'romfile': '',"
850                          "'mac': '"MAC_PRIMARY0"'}");
851 
852     check_one_card(qts, true, "standby0", MAC_STANDBY0);
853     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
854 
855     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
856 
857     check_one_card(qts, true, "standby0", MAC_STANDBY0);
858     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
859 
860     args = qdict_from_jsonf_nofail("{}");
861     g_assert_nonnull(args);
862     qdict_put_str(args, "uri", uri);
863 
864     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
865     g_assert(qdict_haskey(resp, "return"));
866     qobject_unref(resp);
867 
868     while (true) {
869         ret = migrate_status(qts);
870 
871         status = qdict_get_str(ret, "status");
872         if (strcmp(status, "completed") == 0) {
873             qobject_unref(ret);
874             break;
875         }
876         g_assert_cmpstr(status, !=, "failed");
877         g_assert_cmpstr(status, !=, "cancelling");
878         g_assert_cmpstr(status, !=, "cancelled");
879         qobject_unref(ret);
880     }
881 
882     qtest_qmp_eventwait(qts, "STOP");
883 
884     qos_object_destroy((QOSGraphObject *)vdev);
885     machine_stop(qts);
886 }
887 
888 static void test_off_migrate_in(gconstpointer opaque)
889 {
890     QTestState *qts;
891     QDict *resp, *args, *ret;
892     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
893 
894     qts = machine_start(BASE_MACHINE
895                      "-netdev user,id=hs0 "
896                      "-netdev user,id=hs1 "
897                      "-incoming defer ",
898                      2);
899 
900     check_one_card(qts, false, "standby0", MAC_STANDBY0);
901     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
902 
903     qtest_qmp_device_add(qts, "virtio-net", "standby0",
904                          "{'bus': 'root0',"
905                          "'failover': 'off',"
906                          "'netdev': 'hs0',"
907                          "'mac': '"MAC_STANDBY0"'}");
908 
909     check_one_card(qts, true, "standby0", MAC_STANDBY0);
910     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
911 
912     qtest_qmp_device_add(qts, "virtio-net", "primary0",
913                          "{'bus': 'root1',"
914                          "'failover_pair_id': 'standby0',"
915                          "'netdev': 'hs1',"
916                          "'rombar': 0,"
917                          "'romfile': '',"
918                          "'mac': '"MAC_PRIMARY0"'}");
919 
920     check_one_card(qts, true, "standby0", MAC_STANDBY0);
921     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
922 
923     args = qdict_from_jsonf_nofail("{}");
924     g_assert_nonnull(args);
925     qdict_put_str(args, "uri", uri);
926 
927     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
928                      args);
929     g_assert(qdict_haskey(resp, "return"));
930     qobject_unref(resp);
931 
932     resp = get_migration_event(qts);
933     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
934     qobject_unref(resp);
935 
936     check_one_card(qts, true, "standby0", MAC_STANDBY0);
937     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
938 
939     qtest_qmp_eventwait(qts, "RESUME");
940 
941     ret = migrate_status(qts);
942     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
943     qobject_unref(ret);
944 
945     machine_stop(qts);
946 }
947 
948 static void test_guest_off_migrate_out(gconstpointer opaque)
949 {
950     QTestState *qts;
951     QDict *resp, *args, *ret;
952     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
953     const gchar *status;
954     QVirtioPCIDevice *vdev;
955     uint64_t features;
956 
957     qts = machine_start(BASE_MACHINE
958                      "-netdev user,id=hs0 "
959                      "-netdev user,id=hs1 ",
960                      2);
961 
962     check_one_card(qts, false, "standby0", MAC_STANDBY0);
963     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
964 
965     qtest_qmp_device_add(qts, "virtio-net", "standby0",
966                          "{'bus': 'root0',"
967                          "'failover': 'on',"
968                          "'netdev': 'hs0',"
969                          "'mac': '"MAC_STANDBY0"'}");
970 
971     check_one_card(qts, true, "standby0", MAC_STANDBY0);
972     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
973 
974     qtest_qmp_device_add(qts, "virtio-net", "primary0",
975                          "{'bus': 'root1',"
976                          "'failover_pair_id': 'standby0',"
977                          "'netdev': 'hs1',"
978                          "'rombar': 0,"
979                          "'romfile': '',"
980                          "'mac': '"MAC_PRIMARY0"'}");
981 
982     check_one_card(qts, true, "standby0", MAC_STANDBY0);
983     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
984 
985     features = ~(QVIRTIO_F_BAD_FEATURE |
986                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
987                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
988                  (1ull << VIRTIO_NET_F_STANDBY));
989 
990     vdev = start_virtio_net_internal(qts, 1, 0, &features);
991 
992     check_one_card(qts, true, "standby0", MAC_STANDBY0);
993     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
994 
995     args = qdict_from_jsonf_nofail("{}");
996     g_assert_nonnull(args);
997     qdict_put_str(args, "uri", uri);
998 
999     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1000     g_assert(qdict_haskey(resp, "return"));
1001     qobject_unref(resp);
1002 
1003     while (true) {
1004         ret = migrate_status(qts);
1005 
1006         status = qdict_get_str(ret, "status");
1007         if (strcmp(status, "completed") == 0) {
1008             qobject_unref(ret);
1009             break;
1010         }
1011         g_assert_cmpstr(status, !=, "failed");
1012         g_assert_cmpstr(status, !=, "cancelling");
1013         g_assert_cmpstr(status, !=, "cancelled");
1014         qobject_unref(ret);
1015     }
1016 
1017     qtest_qmp_eventwait(qts, "STOP");
1018 
1019     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1020     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1021 
1022     qos_object_destroy((QOSGraphObject *)vdev);
1023     machine_stop(qts);
1024 }
1025 
1026 static void test_guest_off_migrate_in(gconstpointer opaque)
1027 {
1028     QTestState *qts;
1029     QDict *resp, *args, *ret;
1030     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1031 
1032     qts = machine_start(BASE_MACHINE
1033                      "-netdev user,id=hs0 "
1034                      "-netdev user,id=hs1 "
1035                      "-incoming defer ",
1036                      2);
1037 
1038     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1039     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1040 
1041     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1042                          "{'bus': 'root0',"
1043                          "'failover': 'on',"
1044                          "'netdev': 'hs0',"
1045                          "'mac': '"MAC_STANDBY0"'}");
1046 
1047     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1048     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1049 
1050     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1051                          "{'bus': 'root1',"
1052                          "'failover_pair_id': 'standby0',"
1053                          "'netdev': 'hs1',"
1054                          "'rombar': 0,"
1055                          "'romfile': '',"
1056                          "'mac': '"MAC_PRIMARY0"'}");
1057 
1058     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1059     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1060 
1061     args = qdict_from_jsonf_nofail("{}");
1062     g_assert_nonnull(args);
1063     qdict_put_str(args, "uri", uri);
1064 
1065     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1066                      args);
1067     g_assert(qdict_haskey(resp, "return"));
1068     qobject_unref(resp);
1069 
1070     resp = get_migration_event(qts);
1071     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1072     qobject_unref(resp);
1073 
1074     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1075     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1076 
1077     qtest_qmp_eventwait(qts, "RESUME");
1078 
1079     ret = migrate_status(qts);
1080     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1081     qobject_unref(ret);
1082 
1083     machine_stop(qts);
1084 }
1085 
1086 static void test_migrate_guest_off_abort(gconstpointer opaque)
1087 {
1088     QTestState *qts;
1089     QDict *resp, *args, *ret;
1090     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1091     const gchar *status;
1092     QVirtioPCIDevice *vdev;
1093     uint64_t features;
1094 
1095     qts = machine_start(BASE_MACHINE
1096                      "-netdev user,id=hs0 "
1097                      "-netdev user,id=hs1 ",
1098                      2);
1099 
1100     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1101     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1102 
1103     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1104                          "{'bus': 'root0',"
1105                          "'failover': 'on',"
1106                          "'netdev': 'hs0',"
1107                          "'mac': '"MAC_STANDBY0"'}");
1108 
1109     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1110     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1111 
1112     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1113                          "{'bus': 'root1',"
1114                          "'failover_pair_id': 'standby0',"
1115                          "'netdev': 'hs1',"
1116                          "'rombar': 0,"
1117                          "'romfile': '',"
1118                          "'mac': '"MAC_PRIMARY0"'}");
1119 
1120     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1121     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1122 
1123     features = ~(QVIRTIO_F_BAD_FEATURE |
1124                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
1125                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
1126                  (1ull << VIRTIO_NET_F_STANDBY));
1127 
1128     vdev = start_virtio_net_internal(qts, 1, 0, &features);
1129 
1130     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1131     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1132 
1133     args = qdict_from_jsonf_nofail("{}");
1134     g_assert_nonnull(args);
1135     qdict_put_str(args, "uri", uri);
1136 
1137     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1138     g_assert(qdict_haskey(resp, "return"));
1139     qobject_unref(resp);
1140 
1141     while (true) {
1142         ret = migrate_status(qts);
1143 
1144         status = qdict_get_str(ret, "status");
1145         if (strcmp(status, "completed") == 0) {
1146             g_test_skip("Failed to cancel the migration");
1147             qobject_unref(ret);
1148             goto out;
1149         }
1150         if (strcmp(status, "active") == 0) {
1151             qobject_unref(ret);
1152             break;
1153         }
1154         g_assert_cmpstr(status, !=, "failed");
1155         qobject_unref(ret);
1156     }
1157 
1158     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1159     g_assert(qdict_haskey(resp, "return"));
1160     qobject_unref(resp);
1161 
1162     while (true) {
1163         ret = migrate_status(qts);
1164         status = qdict_get_str(ret, "status");
1165         if (strcmp(status, "completed") == 0) {
1166             g_test_skip("Failed to cancel the migration");
1167             qobject_unref(ret);
1168             goto out;
1169         }
1170         if (strcmp(status, "cancelled") == 0) {
1171             qobject_unref(ret);
1172             break;
1173         }
1174         g_assert_cmpstr(status, !=, "failed");
1175         g_assert_cmpstr(status, !=, "active");
1176         qobject_unref(ret);
1177     }
1178 
1179     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1180     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1181 
1182 out:
1183     qos_object_destroy((QOSGraphObject *)vdev);
1184     machine_stop(qts);
1185 }
1186 
1187 static void test_migrate_abort_wait_unplug(gconstpointer opaque)
1188 {
1189     QTestState *qts;
1190     QDict *resp, *args, *ret;
1191     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1192     const gchar *status;
1193     QVirtioPCIDevice *vdev;
1194 
1195     qts = machine_start(BASE_MACHINE
1196                      "-netdev user,id=hs0 "
1197                      "-netdev user,id=hs1 ",
1198                      2);
1199 
1200     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1201     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1202 
1203     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1204                          "{'bus': 'root0',"
1205                          "'failover': 'on',"
1206                          "'netdev': 'hs0',"
1207                          "'mac': '"MAC_STANDBY0"'}");
1208 
1209     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1210     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1211 
1212     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1213 
1214     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1215     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1216 
1217     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1218                          "{'bus': 'root1',"
1219                          "'failover_pair_id': 'standby0',"
1220                          "'netdev': 'hs1',"
1221                          "'rombar': 0,"
1222                          "'romfile': '',"
1223                          "'mac': '"MAC_PRIMARY0"'}");
1224 
1225     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1226     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1227 
1228     args = qdict_from_jsonf_nofail("{}");
1229     g_assert_nonnull(args);
1230     qdict_put_str(args, "uri", uri);
1231 
1232     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1233     g_assert(qdict_haskey(resp, "return"));
1234     qobject_unref(resp);
1235 
1236     /* the event is sent when QEMU asks the OS to unplug the card */
1237     resp = get_unplug_primary_event(qts);
1238     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1239     qobject_unref(resp);
1240 
1241     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1242     g_assert(qdict_haskey(resp, "return"));
1243     qobject_unref(resp);
1244 
1245     /* migration has been cancelled while the unplug was in progress */
1246 
1247     /* while the card is not ejected, we must be in "cancelling" state */
1248     ret = migrate_status(qts);
1249 
1250     status = qdict_get_str(ret, "status");
1251     g_assert_cmpstr(status, ==, "cancelling");
1252     qobject_unref(ret);
1253 
1254     /* OS unplugs the cards, QEMU can move from wait-unplug state */
1255     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1256 
1257     while (true) {
1258         ret = migrate_status(qts);
1259 
1260         status = qdict_get_str(ret, "status");
1261         if (strcmp(status, "cancelled") == 0) {
1262             qobject_unref(ret);
1263             break;
1264         }
1265         g_assert_cmpstr(status, ==, "cancelling");
1266         qobject_unref(ret);
1267     }
1268 
1269     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1270     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1271 
1272     qos_object_destroy((QOSGraphObject *)vdev);
1273     machine_stop(qts);
1274 }
1275 
1276 static void test_migrate_abort_active(gconstpointer opaque)
1277 {
1278     QTestState *qts;
1279     QDict *resp, *args, *ret;
1280     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1281     const gchar *status;
1282     QVirtioPCIDevice *vdev;
1283 
1284     qts = machine_start(BASE_MACHINE
1285                      "-netdev user,id=hs0 "
1286                      "-netdev user,id=hs1 ",
1287                      2);
1288 
1289     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1290     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1291 
1292     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1293                          "{'bus': 'root0',"
1294                          "'failover': 'on',"
1295                          "'netdev': 'hs0',"
1296                          "'mac': '"MAC_STANDBY0"'}");
1297 
1298     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1299     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1300 
1301     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1302 
1303     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1304     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1305 
1306     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1307                          "{'bus': 'root1',"
1308                          "'failover_pair_id': 'standby0',"
1309                          "'netdev': 'hs1',"
1310                          "'rombar': 0,"
1311                          "'romfile': '',"
1312                          "'mac': '"MAC_PRIMARY0"'}");
1313 
1314     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1315     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1316 
1317     args = qdict_from_jsonf_nofail("{}");
1318     g_assert_nonnull(args);
1319     qdict_put_str(args, "uri", uri);
1320 
1321     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1322     g_assert(qdict_haskey(resp, "return"));
1323     qobject_unref(resp);
1324 
1325     /* the event is sent when QEMU asks the OS to unplug the card */
1326     resp = get_unplug_primary_event(qts);
1327     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1328     qobject_unref(resp);
1329 
1330     /* OS unplugs the cards, QEMU can move from wait-unplug state */
1331     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1332 
1333     while (true) {
1334         ret = migrate_status(qts);
1335 
1336         status = qdict_get_str(ret, "status");
1337         g_assert_cmpstr(status, !=, "failed");
1338         if (strcmp(status, "wait-unplug") != 0) {
1339             qobject_unref(ret);
1340             break;
1341         }
1342         qobject_unref(ret);
1343     }
1344 
1345     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1346     g_assert(qdict_haskey(resp, "return"));
1347     qobject_unref(resp);
1348 
1349     while (true) {
1350         ret = migrate_status(qts);
1351 
1352         status = qdict_get_str(ret, "status");
1353         if (strcmp(status, "completed") == 0) {
1354             g_test_skip("Failed to cancel the migration");
1355             qobject_unref(ret);
1356             goto out;
1357         }
1358         if (strcmp(status, "cancelled") == 0) {
1359             qobject_unref(ret);
1360             break;
1361         }
1362         g_assert_cmpstr(status, !=, "failed");
1363         g_assert_cmpstr(status, !=, "active");
1364         qobject_unref(ret);
1365     }
1366 
1367     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1368     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1369 
1370 out:
1371     qos_object_destroy((QOSGraphObject *)vdev);
1372     machine_stop(qts);
1373 }
1374 
1375 static void test_migrate_off_abort(gconstpointer opaque)
1376 {
1377     QTestState *qts;
1378     QDict *resp, *args, *ret;
1379     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1380     const gchar *status;
1381     QVirtioPCIDevice *vdev;
1382 
1383     qts = machine_start(BASE_MACHINE
1384                      "-netdev user,id=hs0 "
1385                      "-netdev user,id=hs1 ",
1386                      2);
1387 
1388     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1389     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1390 
1391     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1392                          "{'bus': 'root0',"
1393                          "'failover': 'off',"
1394                          "'netdev': 'hs0',"
1395                          "'mac': '"MAC_STANDBY0"'}");
1396 
1397     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1398     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1399 
1400     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
1401 
1402     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1403     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1404 
1405     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1406                          "{'bus': 'root1',"
1407                          "'failover_pair_id': 'standby0',"
1408                          "'netdev': 'hs1',"
1409                          "'rombar': 0,"
1410                          "'romfile': '',"
1411                          "'mac': '"MAC_PRIMARY0"'}");
1412 
1413     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1414     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1415 
1416     args = qdict_from_jsonf_nofail("{}");
1417     g_assert_nonnull(args);
1418     qdict_put_str(args, "uri", uri);
1419 
1420     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1421     g_assert(qdict_haskey(resp, "return"));
1422     qobject_unref(resp);
1423 
1424     while (true) {
1425         ret = migrate_status(qts);
1426 
1427         status = qdict_get_str(ret, "status");
1428         if (strcmp(status, "active") == 0) {
1429             qobject_unref(ret);
1430             break;
1431         }
1432         g_assert_cmpstr(status, !=, "failed");
1433         qobject_unref(ret);
1434     }
1435 
1436     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1437     g_assert(qdict_haskey(resp, "return"));
1438     qobject_unref(resp);
1439 
1440     while (true) {
1441         ret = migrate_status(qts);
1442 
1443         status = qdict_get_str(ret, "status");
1444         if (strcmp(status, "completed") == 0) {
1445             g_test_skip("Failed to cancel the migration");
1446             qobject_unref(ret);
1447             goto out;
1448         }
1449         if (strcmp(status, "cancelled") == 0) {
1450             qobject_unref(ret);
1451             break;
1452         }
1453         g_assert_cmpstr(status, !=, "failed");
1454         g_assert_cmpstr(status, !=, "active");
1455         qobject_unref(ret);
1456     }
1457 
1458     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1459     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1460 
1461 out:
1462     qos_object_destroy((QOSGraphObject *)vdev);
1463     machine_stop(qts);
1464 }
1465 
1466 static void test_migrate_abort_timeout(gconstpointer opaque)
1467 {
1468     QTestState *qts;
1469     QDict *resp, *args, *ret;
1470     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1471     const gchar *status;
1472     int total;
1473     QVirtioPCIDevice *vdev;
1474 
1475     qts = machine_start(BASE_MACHINE
1476                      "-netdev user,id=hs0 "
1477                      "-netdev user,id=hs1 ",
1478                      2);
1479 
1480     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1481     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1482 
1483     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1484                          "{'bus': 'root0',"
1485                          "'failover': 'on',"
1486                          "'netdev': 'hs0',"
1487                          "'mac': '"MAC_STANDBY0"'}");
1488 
1489     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1490     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1491 
1492     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1493 
1494     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1495     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1496 
1497     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1498                          "{'bus': 'root1',"
1499                          "'failover_pair_id': 'standby0',"
1500                          "'netdev': 'hs1',"
1501                          "'rombar': 0,"
1502                          "'romfile': '',"
1503                          "'mac': '"MAC_PRIMARY0"'}");
1504 
1505     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1506     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1507 
1508     args = qdict_from_jsonf_nofail("{}");
1509     g_assert_nonnull(args);
1510     qdict_put_str(args, "uri", uri);
1511 
1512     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1513     g_assert(qdict_haskey(resp, "return"));
1514     qobject_unref(resp);
1515 
1516     /* the event is sent when QEMU asks the OS to unplug the card */
1517     resp = get_unplug_primary_event(qts);
1518     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1519     qobject_unref(resp);
1520 
1521     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1522     g_assert(qdict_haskey(resp, "return"));
1523     qobject_unref(resp);
1524 
1525     /* migration has been cancelled while the unplug was in progress */
1526 
1527     /* while the card is not ejected, we must be in "cancelling" state */
1528 
1529     total = 0;
1530     while (true) {
1531         ret = migrate_status(qts);
1532 
1533         status = qdict_get_str(ret, "status");
1534         if (strcmp(status, "cancelled") == 0) {
1535             qobject_unref(ret);
1536             break;
1537         }
1538         g_assert_cmpstr(status, ==, "cancelling");
1539         g_assert(qdict_haskey(ret, "total-time"));
1540         total = qdict_get_int(ret, "total-time");
1541         qobject_unref(ret);
1542     }
1543 
1544     /*
1545      * migration timeout in this case is 30 seconds
1546      * check we exit on the timeout (ms)
1547      */
1548     g_assert_cmpint(total, >, 30000);
1549 
1550     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1551     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1552 
1553     qos_object_destroy((QOSGraphObject *)vdev);
1554     machine_stop(qts);
1555 }
1556 
1557 static void test_multi_out(gconstpointer opaque)
1558 {
1559     QTestState *qts;
1560     QDict *resp, *args, *ret;
1561     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1562     const gchar *status, *expected;
1563     QVirtioPCIDevice *vdev0, *vdev1;
1564 
1565     qts = machine_start(BASE_MACHINE
1566                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1567                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1568                 "-netdev user,id=hs0 "
1569                 "-netdev user,id=hs1 "
1570                 "-netdev user,id=hs2 "
1571                 "-netdev user,id=hs3 ",
1572                 4);
1573 
1574     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1575     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1576     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1577     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1578 
1579     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1580                          "{'bus': 'root0',"
1581                          "'failover': 'on',"
1582                          "'netdev': 'hs0',"
1583                          "'mac': '"MAC_STANDBY0"'}");
1584 
1585     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1586     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1587     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1588     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1589 
1590     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1591                          "{'bus': 'root1',"
1592                          "'failover_pair_id': 'standby0',"
1593                          "'netdev': 'hs1',"
1594                          "'rombar': 0,"
1595                          "'romfile': '',"
1596                          "'mac': '"MAC_PRIMARY0"'}");
1597 
1598     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1599     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1600     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1601     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1602 
1603     vdev0 = start_virtio_net(qts, 1, 0, "standby0", true);
1604 
1605     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1606     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1607     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1608     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1609 
1610     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1611                          "{'bus': 'root2',"
1612                          "'failover': 'on',"
1613                          "'netdev': 'hs2',"
1614                          "'mac': '"MAC_STANDBY1"'}");
1615 
1616     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1617     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1618     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1619     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1620 
1621     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1622                          "{'bus': 'root3',"
1623                          "'failover_pair_id': 'standby1',"
1624                          "'netdev': 'hs3',"
1625                          "'rombar': 0,"
1626                          "'romfile': '',"
1627                          "'mac': '"MAC_PRIMARY1"'}");
1628 
1629     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1630     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1631     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1632     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1633 
1634     vdev1 = start_virtio_net(qts, 3, 0, "standby1", true);
1635 
1636     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1637     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1638     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1639     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1640 
1641     args = qdict_from_jsonf_nofail("{}");
1642     g_assert_nonnull(args);
1643     qdict_put_str(args, "uri", uri);
1644 
1645     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1646     g_assert(qdict_haskey(resp, "return"));
1647     qobject_unref(resp);
1648 
1649     /* the event is sent when QEMU asks the OS to unplug the card */
1650     resp = get_unplug_primary_event(qts);
1651     if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
1652         expected = "primary1";
1653     } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
1654         expected = "primary0";
1655     } else {
1656         g_assert_not_reached();
1657     }
1658     qobject_unref(resp);
1659 
1660     resp = get_unplug_primary_event(qts);
1661     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1662     qobject_unref(resp);
1663 
1664     /* wait the end of the migration setup phase */
1665     while (true) {
1666         ret = migrate_status(qts);
1667 
1668         status = qdict_get_str(ret, "status");
1669         if (strcmp(status, "wait-unplug") == 0) {
1670             qobject_unref(ret);
1671             break;
1672         }
1673 
1674         /* The migration must not start if the card is not ejected */
1675         g_assert_cmpstr(status, !=, "active");
1676         g_assert_cmpstr(status, !=, "completed");
1677         g_assert_cmpstr(status, !=, "failed");
1678         g_assert_cmpstr(status, !=, "cancelling");
1679         g_assert_cmpstr(status, !=, "cancelled");
1680 
1681         qobject_unref(ret);
1682     }
1683 
1684     /* OS unplugs primary1, but we must wait the second */
1685     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1686 
1687     ret = migrate_status(qts);
1688     status = qdict_get_str(ret, "status");
1689     g_assert_cmpstr(status, ==, "wait-unplug");
1690     qobject_unref(ret);
1691 
1692     if (g_test_slow()) {
1693         /* check we stay in wait-unplug while the card is not ejected */
1694         for (int i = 0; i < 5; i++) {
1695             sleep(1);
1696             ret = migrate_status(qts);
1697             status = qdict_get_str(ret, "status");
1698             g_assert_cmpstr(status, ==, "wait-unplug");
1699             qobject_unref(ret);
1700         }
1701     }
1702 
1703     /* OS unplugs primary0, QEMU can move from wait-unplug state */
1704     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
1705     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1706 
1707     while (true) {
1708         ret = migrate_status(qts);
1709 
1710         status = qdict_get_str(ret, "status");
1711         if (strcmp(status, "completed") == 0) {
1712             qobject_unref(ret);
1713             break;
1714         }
1715         g_assert_cmpstr(status, !=, "failed");
1716         g_assert_cmpstr(status, !=, "cancelling");
1717         g_assert_cmpstr(status, !=, "cancelled");
1718         qobject_unref(ret);
1719     }
1720 
1721     qtest_qmp_eventwait(qts, "STOP");
1722 
1723     qos_object_destroy((QOSGraphObject *)vdev0);
1724     qos_object_destroy((QOSGraphObject *)vdev1);
1725     machine_stop(qts);
1726 }
1727 
1728 static void test_multi_in(gconstpointer opaque)
1729 {
1730     QTestState *qts;
1731     QDict *resp, *args, *ret;
1732     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1733 
1734     qts = machine_start(BASE_MACHINE
1735                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1736                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1737                 "-netdev user,id=hs0 "
1738                 "-netdev user,id=hs1 "
1739                 "-netdev user,id=hs2 "
1740                 "-netdev user,id=hs3 "
1741                 "-incoming defer ",
1742                 4);
1743 
1744     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1745     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1746     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1747     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1748 
1749     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1750                          "{'bus': 'root0',"
1751                          "'failover': 'on',"
1752                          "'netdev': 'hs0',"
1753                          "'mac': '"MAC_STANDBY0"'}");
1754 
1755     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1756     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1757     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1758     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1759 
1760     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1761                          "{'bus': 'root1',"
1762                          "'failover_pair_id': 'standby0',"
1763                          "'netdev': 'hs1',"
1764                          "'rombar': 0,"
1765                          "'romfile': '',"
1766                          "'mac': '"MAC_PRIMARY0"'}");
1767 
1768     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1769     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1770     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1771     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1772 
1773     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1774                          "{'bus': 'root2',"
1775                          "'failover': 'on',"
1776                          "'netdev': 'hs2',"
1777                          "'mac': '"MAC_STANDBY1"'}");
1778 
1779     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1780     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1781     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1782     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1783 
1784     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1785                          "{'bus': 'root3',"
1786                          "'failover_pair_id': 'standby1',"
1787                          "'netdev': 'hs3',"
1788                          "'rombar': 0,"
1789                          "'romfile': '',"
1790                          "'mac': '"MAC_PRIMARY1"'}");
1791 
1792     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1793     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1794     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1795     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1796 
1797     args = qdict_from_jsonf_nofail("{}");
1798     g_assert_nonnull(args);
1799     qdict_put_str(args, "uri", uri);
1800 
1801     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1802                      args);
1803     g_assert(qdict_haskey(resp, "return"));
1804     qobject_unref(resp);
1805 
1806     resp = get_migration_event(qts);
1807     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1808     qobject_unref(resp);
1809 
1810     resp = get_failover_negociated_event(qts);
1811     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1812     qobject_unref(resp);
1813 
1814     resp = get_failover_negociated_event(qts);
1815     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1816     qobject_unref(resp);
1817 
1818     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1819     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1820     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1821     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1822 
1823     qtest_qmp_eventwait(qts, "RESUME");
1824 
1825     ret = migrate_status(qts);
1826     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1827     qobject_unref(ret);
1828 
1829     machine_stop(qts);
1830 }
1831 #endif /* _WIN32 */
1832 
1833 int main(int argc, char **argv)
1834 {
1835     gchar *tmpfile;
1836     int ret;
1837 
1838     g_test_init(&argc, &argv, NULL);
1839 
1840     ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
1841     g_assert_true(ret >= 0);
1842     close(ret);
1843 
1844     /* parameters tests */
1845     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1846     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1847     qtest_add_func("failover-virtio-net/params/on", test_on);
1848     qtest_add_func("failover-virtio-net/params/on_mismatch",
1849                    test_on_mismatch);
1850     qtest_add_func("failover-virtio-net/params/off", test_off);
1851     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
1852     qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off);
1853 
1854     /* hotplug tests */
1855     qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1);
1856     qtest_add_func("failover-virtio-net/hotplug/1_reverse",
1857                    test_hotplug_1_reverse);
1858     qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2);
1859     qtest_add_func("failover-virtio-net/hotplug/2_reverse",
1860                    test_hotplug_2_reverse);
1861 
1862 #ifndef _WIN32
1863     /*
1864      * These migration tests cases use the exec migration protocol,
1865      * which is unsupported on Windows.
1866      */
1867     qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile,
1868                         test_migrate_out);
1869     qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile,
1870                         test_migrate_in);
1871     qtest_add_data_func("failover-virtio-net/migrate/off/out", tmpfile,
1872                         test_off_migrate_out);
1873     qtest_add_data_func("failover-virtio-net/migrate/off/in", tmpfile,
1874                         test_off_migrate_in);
1875     qtest_add_data_func("failover-virtio-net/migrate/off/abort", tmpfile,
1876                         test_migrate_off_abort);
1877     qtest_add_data_func("failover-virtio-net/migrate/guest_off/out", tmpfile,
1878                         test_guest_off_migrate_out);
1879     qtest_add_data_func("failover-virtio-net/migrate/guest_off/in", tmpfile,
1880                         test_guest_off_migrate_in);
1881     qtest_add_data_func("failover-virtio-net/migrate/guest_off/abort", tmpfile,
1882                         test_migrate_guest_off_abort);
1883     qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
1884                         tmpfile, test_migrate_abort_wait_unplug);
1885     qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
1886                         test_migrate_abort_active);
1887     if (g_test_slow()) {
1888         qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
1889                             tmpfile, test_migrate_abort_timeout);
1890     }
1891     qtest_add_data_func("failover-virtio-net/migrate/multi/out",
1892                         tmpfile, test_multi_out);
1893     qtest_add_data_func("failover-virtio-net/migrate/multi/in",
1894                    tmpfile, test_multi_in);
1895 #endif /* _WIN32 */
1896 
1897     ret = g_test_run();
1898 
1899     unlink(tmpfile);
1900     g_free(tmpfile);
1901 
1902     return ret;
1903 }
1904