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 "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"
21 
22 #define VIRTIO_NET_F_STANDBY    62
23 
24 #define ACPI_PCIHP_ADDR_ICH9    0x0cc0
25 #define PCI_EJ_BASE             0x0008
26 #define PCI_SEL_BASE            0x0010
27 
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 "
31 
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"
36 
37 static QGuestAllocator guest_malloc;
38 static QPCIBus *pcibus;
39 
40 static QTestState *machine_start(const char *args, int numbus)
41 {
42     QTestState *qts;
43     QPCIDevice *dev;
44     int bus;
45 
46     qts = qtest_init(args);
47 
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);
51 
52     for (bus = 1; bus <= numbus; bus++) {
53         dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0));
54         g_assert_nonnull(dev);
55 
56         qpci_device_enable(dev);
57         qpci_iomap(dev, 4, NULL);
58 
59         g_free(dev);
60     }
61 
62     return qts;
63 }
64 
65 static void machine_stop(QTestState *qts)
66 {
67     qpci_free_pc(pcibus);
68     alloc_destroy(&guest_malloc);
69     qtest_quit(qts);
70 }
71 
72 static void test_error_id(void)
73 {
74     QTestState *qts;
75     QDict *resp;
76     QDict *err;
77 
78     qts = machine_start(BASE_MACHINE
79                         "-device virtio-net,bus=root0,id=standby0,failover=on",
80                         2);
81 
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"));
89 
90     err = qdict_get_qdict(resp, "error");
91     g_assert(qdict_haskey(err, "desc"));
92 
93     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
94                     "Device with failover_pair_id needs to have id");
95 
96     qobject_unref(resp);
97 
98     machine_stop(qts);
99 }
100 
101 static void test_error_pcie(void)
102 {
103     QTestState *qts;
104     QDict *resp;
105     QDict *err;
106 
107     qts = machine_start(BASE_MACHINE
108                         "-device virtio-net,bus=root0,id=standby0,failover=on",
109                         2);
110 
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"));
119 
120     err = qdict_get_qdict(resp, "error");
121     g_assert(qdict_haskey(err, "desc"));
122 
123     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
124                     "Bus 'pcie.0' does not support hotplugging");
125 
126     qobject_unref(resp);
127 
128     machine_stop(qts);
129 }
130 
131 static QDict *find_device(QDict *bus, const char *name)
132 {
133     const QObject *obj;
134     QList *devices;
135     QList *list;
136 
137     devices = qdict_get_qlist(bus, "devices");
138     if (devices == NULL) {
139         return NULL;
140     }
141 
142     list = qlist_copy(devices);
143     while ((obj = qlist_pop(list))) {
144         QDict *device;
145 
146         device = qobject_to(QDict, obj);
147 
148         if (qdict_haskey(device, "pci_bridge")) {
149             QDict *bridge;
150             QDict *bridge_device;
151 
152             bridge = qdict_get_qdict(device, "pci_bridge");
153 
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;
160                 }
161             }
162         }
163 
164         if (!qdict_haskey(device, "qdev_id")) {
165             qobject_unref(device);
166             continue;
167         }
168 
169         if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) {
170             qobject_unref(list);
171             return device;
172         }
173         qobject_unref(device);
174     }
175     qobject_unref(list);
176 
177     return NULL;
178 }
179 
180 static QDict *get_bus(QTestState *qts, int num)
181 {
182     QObject *obj;
183     QDict *resp;
184     QList *ret;
185 
186     resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }");
187     g_assert(qdict_haskey(resp, "return"));
188 
189     ret = qdict_get_qlist(resp, "return");
190     g_assert_nonnull(ret);
191 
192     while ((obj = qlist_pop(ret))) {
193         QDict *bus;
194 
195         bus = qobject_to(QDict, obj);
196         if (!qdict_haskey(bus, "bus")) {
197             qobject_unref(bus);
198             continue;
199         }
200         if (qdict_get_int(bus, "bus") == num) {
201             qobject_unref(resp);
202             return bus;
203         }
204         qobject_ref(bus);
205     }
206     qobject_unref(resp);
207 
208     return NULL;
209 }
210 
211 static char *get_mac(QTestState *qts, const char *name)
212 {
213     QDict *resp;
214     char *mac;
215 
216     resp = qtest_qmp(qts, "{ 'execute': 'qom-get', "
217                      "'arguments': { "
218                      "'path': %s, "
219                      "'property': 'mac' } }", name);
220 
221     g_assert(qdict_haskey(resp, "return"));
222 
223     mac = g_strdup(qdict_get_str(resp, "return"));
224 
225     qobject_unref(resp);
226 
227     return mac;
228 }
229 
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);                                   \
248     }                                                           \
249     qobject_unref(bus);                                         \
250 } while (0)
251 
252 static QDict *get_failover_negociated_event(QTestState *qts)
253 {
254     QDict *resp;
255     QDict *data;
256 
257     resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED");
258     g_assert(qdict_haskey(resp, "data"));
259 
260     data = qdict_get_qdict(resp, "data");
261     g_assert(qdict_haskey(data, "device-id"));
262     qobject_ref(data);
263     qobject_unref(resp);
264 
265     return data;
266 }
267 
268 static QVirtioPCIDevice *start_virtio_net_internal(QTestState *qts,
269                                                    int bus, int slot,
270                                                    uint64_t *features)
271 {
272     QVirtioPCIDevice *dev;
273     QPCIAddress addr;
274 
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;
284 }
285 
286 static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
287                                           const char *id, bool failover)
288 {
289     QVirtioPCIDevice *dev;
290     uint64_t features;
291 
292     features = ~(QVIRTIO_F_BAD_FEATURE |
293                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
294                  (1ull << VIRTIO_RING_F_EVENT_IDX));
295 
296     dev = start_virtio_net_internal(qts, bus, slot, &features);
297 
298     g_assert(!!(features & (1ull << VIRTIO_NET_F_STANDBY)) == failover);
299 
300     if (failover) {
301         QDict *resp;
302 
303         resp = get_failover_negociated_event(qts);
304         g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
305         qobject_unref(resp);
306     }
307 
308     return dev;
309 }
310 
311 static void test_on(void)
312 {
313     QTestState *qts;
314 
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,
322                         2);
323 
324     check_one_card(qts, true, "standby0", MAC_STANDBY0);
325     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
326 
327     machine_stop(qts);
328 }
329 
330 static void test_on_mismatch(void)
331 {
332     QTestState *qts;
333     QVirtioPCIDevice *vdev;
334 
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,
342                      2);
343 
344     check_one_card(qts, true, "standby0", MAC_STANDBY0);
345     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
346 
347     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
348 
349     check_one_card(qts, true, "standby0", MAC_STANDBY0);
350     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
351 
352     qos_object_destroy((QOSGraphObject *)vdev);
353     machine_stop(qts);
354 }
355 
356 static void test_off(void)
357 {
358     QTestState *qts;
359     QVirtioPCIDevice *vdev;
360 
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,
368                      2);
369 
370     check_one_card(qts, true, "standby0", MAC_STANDBY0);
371     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
372 
373     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
374 
375     check_one_card(qts, true, "standby0", MAC_STANDBY0);
376     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
377 
378     qos_object_destroy((QOSGraphObject *)vdev);
379     machine_stop(qts);
380 }
381 
382 static void test_enabled(void)
383 {
384     QTestState *qts;
385     QVirtioPCIDevice *vdev;
386 
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" ",
394                      2);
395 
396     check_one_card(qts, true, "standby0", MAC_STANDBY0);
397     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
398 
399     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
400 
401     check_one_card(qts, true, "standby0", MAC_STANDBY0);
402     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
403 
404     qos_object_destroy((QOSGraphObject *)vdev);
405     machine_stop(qts);
406 }
407 
408 static void test_guest_off(void)
409 {
410     QTestState *qts;
411     QVirtioPCIDevice *vdev;
412     uint64_t features;
413 
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" ",
421                      2);
422 
423     check_one_card(qts, true, "standby0", MAC_STANDBY0);
424     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
425 
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));
430 
431     vdev = start_virtio_net_internal(qts, 1, 0, &features);
432 
433     check_one_card(qts, true, "standby0", MAC_STANDBY0);
434     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
435 
436     qos_object_destroy((QOSGraphObject *)vdev);
437     machine_stop(qts);
438 }
439 
440 static void test_hotplug_1(void)
441 {
442     QTestState *qts;
443     QVirtioPCIDevice *vdev;
444 
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);
450 
451     check_one_card(qts, true, "standby0", MAC_STANDBY0);
452     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
453 
454     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
455 
456     check_one_card(qts, true, "standby0", MAC_STANDBY0);
457     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
458 
459     qtest_qmp_device_add(qts, "virtio-net", "primary0",
460                          "{'bus': 'root1',"
461                          "'failover_pair_id': 'standby0',"
462                          "'netdev': 'hs1',"
463                          "'mac': '"MAC_PRIMARY0"'}");
464 
465     check_one_card(qts, true, "standby0", MAC_STANDBY0);
466     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
467 
468     qos_object_destroy((QOSGraphObject *)vdev);
469     machine_stop(qts);
470 }
471 
472 static void test_hotplug_1_reverse(void)
473 {
474     QTestState *qts;
475     QVirtioPCIDevice *vdev;
476 
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" ",
482                      2);
483 
484     check_one_card(qts, false, "standby0", MAC_STANDBY0);
485     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
486 
487     qtest_qmp_device_add(qts, "virtio-net", "standby0",
488                          "{'bus': 'root0',"
489                          "'failover': true,"
490                          "'netdev': 'hs0',"
491                          "'mac': '"MAC_STANDBY0"'}");
492 
493     check_one_card(qts, true, "standby0", MAC_STANDBY0);
494     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
495 
496     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
497 
498     check_one_card(qts, true, "standby0", MAC_STANDBY0);
499     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
500 
501     qos_object_destroy((QOSGraphObject *)vdev);
502     machine_stop(qts);
503 }
504 
505 static void test_hotplug_2(void)
506 {
507     QTestState *qts;
508     QVirtioPCIDevice *vdev;
509 
510     qts = machine_start(BASE_MACHINE
511                      "-netdev user,id=hs0 "
512                      "-netdev user,id=hs1 ",
513                      2);
514 
515     check_one_card(qts, false, "standby0", MAC_STANDBY0);
516     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
517 
518     qtest_qmp_device_add(qts, "virtio-net", "standby0",
519                          "{'bus': 'root0',"
520                          "'failover': true,"
521                          "'netdev': 'hs0',"
522                          "'mac': '"MAC_STANDBY0"'}");
523 
524     check_one_card(qts, true, "standby0", MAC_STANDBY0);
525     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
526 
527     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
528 
529     check_one_card(qts, true, "standby0", MAC_STANDBY0);
530     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
531 
532     qtest_qmp_device_add(qts, "virtio-net", "primary0",
533                          "{'bus': 'root1',"
534                          "'failover_pair_id': 'standby0',"
535                          "'netdev': 'hs1',"
536                          "'mac': '"MAC_PRIMARY0"'}");
537 
538     check_one_card(qts, true, "standby0", MAC_STANDBY0);
539     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
540 
541     qos_object_destroy((QOSGraphObject *)vdev);
542     machine_stop(qts);
543 }
544 
545 static void test_hotplug_2_reverse(void)
546 {
547     QTestState *qts;
548     QVirtioPCIDevice *vdev;
549 
550     qts = machine_start(BASE_MACHINE
551                      "-netdev user,id=hs0 "
552                      "-netdev user,id=hs1 ",
553                      2);
554 
555     check_one_card(qts, false, "standby0", MAC_STANDBY0);
556     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
557 
558     qtest_qmp_device_add(qts, "virtio-net", "primary0",
559                          "{'bus': 'root1',"
560                          "'failover_pair_id': 'standby0',"
561                          "'netdev': 'hs1',"
562                          "'mac': '"MAC_PRIMARY0"'}");
563 
564     check_one_card(qts, false, "standby0", MAC_STANDBY0);
565     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
566 
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"'}");
574 
575     /*
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()
579      */
580     check_one_card(qts, true, "standby0", MAC_STANDBY0);
581     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
582 
583     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
584 
585     check_one_card(qts, true, "standby0", MAC_STANDBY0);
586     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
587 
588     qos_object_destroy((QOSGraphObject *)vdev);
589     machine_stop(qts);
590 }
591 
592 #ifndef _WIN32
593 static QDict *migrate_status(QTestState *qts)
594 {
595     QDict *resp, *ret;
596 
597     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
598     g_assert(qdict_haskey(resp, "return"));
599 
600     ret = qdict_get_qdict(resp, "return");
601     g_assert(qdict_haskey(ret, "status"));
602     qobject_ref(ret);
603     qobject_unref(resp);
604 
605     return ret;
606 }
607 
608 static QDict *get_unplug_primary_event(QTestState *qts)
609 {
610     QDict *resp;
611     QDict *data;
612 
613     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
614     g_assert(qdict_haskey(resp, "data"));
615 
616     data = qdict_get_qdict(resp, "data");
617     g_assert(qdict_haskey(data, "device-id"));
618     qobject_ref(data);
619     qobject_unref(resp);
620 
621     return data;
622 }
623 
624 static void test_migrate_out(gconstpointer opaque)
625 {
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;
631 
632     qts = machine_start(BASE_MACHINE
633                      "-netdev user,id=hs0 "
634                      "-netdev user,id=hs1 ",
635                      2);
636 
637     check_one_card(qts, false, "standby0", MAC_STANDBY0);
638     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
639 
640     qtest_qmp_device_add(qts, "virtio-net", "standby0",
641                          "{'bus': 'root0',"
642                          "'failover': true,"
643                          "'netdev': 'hs0',"
644                          "'mac': '"MAC_STANDBY0"'}");
645 
646     check_one_card(qts, true, "standby0", MAC_STANDBY0);
647     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
648 
649     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
650 
651     check_one_card(qts, true, "standby0", MAC_STANDBY0);
652     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
653 
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"'}");
661 
662     check_one_card(qts, true, "standby0", MAC_STANDBY0);
663     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
664 
665     args = qdict_from_jsonf_nofail("{}");
666     g_assert_nonnull(args);
667     qdict_put_str(args, "uri", uri);
668 
669     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
670     g_assert(qdict_haskey(resp, "return"));
671     qobject_unref(resp);
672 
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);
677 
678     /* wait the end of the migration setup phase */
679     while (true) {
680         ret = migrate_status(qts);
681 
682         status = qdict_get_str(ret, "status");
683         if (strcmp(status, "wait-unplug") == 0) {
684             qobject_unref(ret);
685             break;
686         }
687 
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");
694 
695         qobject_unref(ret);
696     }
697 
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);
706         }
707     }
708 
709     /* OS unplugs the cards, QEMU can move from wait-unplug state */
710     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
711 
712     while (true) {
713         ret = migrate_status(qts);
714 
715         status = qdict_get_str(ret, "status");
716         if (strcmp(status, "completed") == 0) {
717             qobject_unref(ret);
718             break;
719         }
720         g_assert_cmpstr(status, !=, "failed");
721         g_assert_cmpstr(status, !=, "cancelling");
722         g_assert_cmpstr(status, !=, "cancelled");
723         qobject_unref(ret);
724     }
725 
726     qtest_qmp_eventwait(qts, "STOP");
727 
728     /*
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);
734      */
735 
736     qos_object_destroy((QOSGraphObject *)vdev);
737     machine_stop(qts);
738 }
739 
740 static void test_migrate_in(gconstpointer opaque)
741 {
742     QTestState *qts;
743     QDict *resp, *ret;
744     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
745 
746     qts = machine_start(BASE_MACHINE
747                      "-netdev user,id=hs0 "
748                      "-netdev user,id=hs1 "
749                      "-incoming defer ",
750                      2);
751 
752     check_one_card(qts, false, "standby0", MAC_STANDBY0);
753     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
754 
755     qtest_qmp_device_add(qts, "virtio-net", "standby0",
756                          "{'bus': 'root0',"
757                          "'failover': true,"
758                          "'netdev': 'hs0',"
759                          "'mac': '"MAC_STANDBY0"'}");
760 
761     check_one_card(qts, true, "standby0", MAC_STANDBY0);
762     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
763 
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"'}");
771 
772     check_one_card(qts, true, "standby0", MAC_STANDBY0);
773     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
774 
775     migrate_incoming_qmp(qts, uri, "{}");
776 
777     resp = get_failover_negociated_event(qts);
778     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
779     qobject_unref(resp);
780 
781     check_one_card(qts, true, "standby0", MAC_STANDBY0);
782     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
783 
784     qtest_qmp_eventwait(qts, "RESUME");
785 
786     ret = migrate_status(qts);
787     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
788     qobject_unref(ret);
789 
790     machine_stop(qts);
791 }
792 
793 static void test_off_migrate_out(gconstpointer opaque)
794 {
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;
800 
801     qts = machine_start(BASE_MACHINE
802                      "-netdev user,id=hs0 "
803                      "-netdev user,id=hs1 ",
804                      2);
805 
806     check_one_card(qts, false, "standby0", MAC_STANDBY0);
807     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
808 
809     qtest_qmp_device_add(qts, "virtio-net", "standby0",
810                          "{'bus': 'root0',"
811                          "'failover': false,"
812                          "'netdev': 'hs0',"
813                          "'mac': '"MAC_STANDBY0"'}");
814 
815     check_one_card(qts, true, "standby0", MAC_STANDBY0);
816     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
817 
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"'}");
825 
826     check_one_card(qts, true, "standby0", MAC_STANDBY0);
827     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
828 
829     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
830 
831     check_one_card(qts, true, "standby0", MAC_STANDBY0);
832     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
833 
834     args = qdict_from_jsonf_nofail("{}");
835     g_assert_nonnull(args);
836     qdict_put_str(args, "uri", uri);
837 
838     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
839     g_assert(qdict_haskey(resp, "return"));
840     qobject_unref(resp);
841 
842     while (true) {
843         ret = migrate_status(qts);
844 
845         status = qdict_get_str(ret, "status");
846         if (strcmp(status, "completed") == 0) {
847             qobject_unref(ret);
848             break;
849         }
850         g_assert_cmpstr(status, !=, "failed");
851         g_assert_cmpstr(status, !=, "cancelling");
852         g_assert_cmpstr(status, !=, "cancelled");
853         qobject_unref(ret);
854     }
855 
856     qtest_qmp_eventwait(qts, "STOP");
857 
858     qos_object_destroy((QOSGraphObject *)vdev);
859     machine_stop(qts);
860 }
861 
862 static void test_off_migrate_in(gconstpointer opaque)
863 {
864     QTestState *qts;
865     QDict *ret;
866     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
867 
868     qts = machine_start(BASE_MACHINE
869                      "-netdev user,id=hs0 "
870                      "-netdev user,id=hs1 "
871                      "-incoming defer ",
872                      2);
873 
874     check_one_card(qts, false, "standby0", MAC_STANDBY0);
875     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
876 
877     qtest_qmp_device_add(qts, "virtio-net", "standby0",
878                          "{'bus': 'root0',"
879                          "'failover': false,"
880                          "'netdev': 'hs0',"
881                          "'mac': '"MAC_STANDBY0"'}");
882 
883     check_one_card(qts, true, "standby0", MAC_STANDBY0);
884     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
885 
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"'}");
893 
894     check_one_card(qts, true, "standby0", MAC_STANDBY0);
895     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
896 
897     migrate_incoming_qmp(qts, uri, "{}");
898 
899     check_one_card(qts, true, "standby0", MAC_STANDBY0);
900     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
901 
902     qtest_qmp_eventwait(qts, "RESUME");
903 
904     ret = migrate_status(qts);
905     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
906     qobject_unref(ret);
907 
908     machine_stop(qts);
909 }
910 
911 static void test_guest_off_migrate_out(gconstpointer opaque)
912 {
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;
919 
920     qts = machine_start(BASE_MACHINE
921                      "-netdev user,id=hs0 "
922                      "-netdev user,id=hs1 ",
923                      2);
924 
925     check_one_card(qts, false, "standby0", MAC_STANDBY0);
926     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
927 
928     qtest_qmp_device_add(qts, "virtio-net", "standby0",
929                          "{'bus': 'root0',"
930                          "'failover': true,"
931                          "'netdev': 'hs0',"
932                          "'mac': '"MAC_STANDBY0"'}");
933 
934     check_one_card(qts, true, "standby0", MAC_STANDBY0);
935     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
936 
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"'}");
944 
945     check_one_card(qts, true, "standby0", MAC_STANDBY0);
946     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
947 
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));
952 
953     vdev = start_virtio_net_internal(qts, 1, 0, &features);
954 
955     check_one_card(qts, true, "standby0", MAC_STANDBY0);
956     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
957 
958     args = qdict_from_jsonf_nofail("{}");
959     g_assert_nonnull(args);
960     qdict_put_str(args, "uri", uri);
961 
962     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
963     g_assert(qdict_haskey(resp, "return"));
964     qobject_unref(resp);
965 
966     while (true) {
967         ret = migrate_status(qts);
968 
969         status = qdict_get_str(ret, "status");
970         if (strcmp(status, "completed") == 0) {
971             qobject_unref(ret);
972             break;
973         }
974         g_assert_cmpstr(status, !=, "failed");
975         g_assert_cmpstr(status, !=, "cancelling");
976         g_assert_cmpstr(status, !=, "cancelled");
977         qobject_unref(ret);
978     }
979 
980     qtest_qmp_eventwait(qts, "STOP");
981 
982     check_one_card(qts, true, "standby0", MAC_STANDBY0);
983     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
984 
985     qos_object_destroy((QOSGraphObject *)vdev);
986     machine_stop(qts);
987 }
988 
989 static void test_guest_off_migrate_in(gconstpointer opaque)
990 {
991     QTestState *qts;
992     QDict *ret;
993     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
994 
995     qts = machine_start(BASE_MACHINE
996                      "-netdev user,id=hs0 "
997                      "-netdev user,id=hs1 "
998                      "-incoming defer ",
999                      2);
1000 
1001     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1002     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1003 
1004     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1005                          "{'bus': 'root0',"
1006                          "'failover': true,"
1007                          "'netdev': 'hs0',"
1008                          "'mac': '"MAC_STANDBY0"'}");
1009 
1010     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1011     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1012 
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"'}");
1020 
1021     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1022     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1023 
1024     migrate_incoming_qmp(qts, uri, "{}");
1025 
1026     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1027     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1028 
1029     qtest_qmp_eventwait(qts, "RESUME");
1030 
1031     ret = migrate_status(qts);
1032     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1033     qobject_unref(ret);
1034 
1035     machine_stop(qts);
1036 }
1037 
1038 static void test_migrate_guest_off_abort(gconstpointer opaque)
1039 {
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;
1046 
1047     qts = machine_start(BASE_MACHINE
1048                      "-netdev user,id=hs0 "
1049                      "-netdev user,id=hs1 ",
1050                      2);
1051 
1052     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1053     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1054 
1055     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1056                          "{'bus': 'root0',"
1057                          "'failover': true,"
1058                          "'netdev': 'hs0',"
1059                          "'mac': '"MAC_STANDBY0"'}");
1060 
1061     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1062     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1063 
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"'}");
1071 
1072     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1073     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1074 
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));
1079 
1080     vdev = start_virtio_net_internal(qts, 1, 0, &features);
1081 
1082     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1083     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1084 
1085     args = qdict_from_jsonf_nofail("{}");
1086     g_assert_nonnull(args);
1087     qdict_put_str(args, "uri", uri);
1088 
1089     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1090     g_assert(qdict_haskey(resp, "return"));
1091     qobject_unref(resp);
1092 
1093     while (true) {
1094         ret = migrate_status(qts);
1095 
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;
1101         }
1102         if (strcmp(status, "active") == 0) {
1103             qobject_unref(ret);
1104             break;
1105         }
1106         g_assert_cmpstr(status, !=, "failed");
1107         qobject_unref(ret);
1108     }
1109 
1110     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1111     g_assert(qdict_haskey(resp, "return"));
1112     qobject_unref(resp);
1113 
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;
1121         }
1122         if (strcmp(status, "cancelled") == 0) {
1123             qobject_unref(ret);
1124             break;
1125         }
1126         g_assert_cmpstr(status, !=, "failed");
1127         g_assert_cmpstr(status, !=, "active");
1128         qobject_unref(ret);
1129     }
1130 
1131     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1132     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1133 
1134 out:
1135     qos_object_destroy((QOSGraphObject *)vdev);
1136     machine_stop(qts);
1137 }
1138 
1139 static void test_migrate_abort_wait_unplug(gconstpointer opaque)
1140 {
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;
1146 
1147     qts = machine_start(BASE_MACHINE
1148                      "-netdev user,id=hs0 "
1149                      "-netdev user,id=hs1 ",
1150                      2);
1151 
1152     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1153     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1154 
1155     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1156                          "{'bus': 'root0',"
1157                          "'failover': true,"
1158                          "'netdev': 'hs0',"
1159                          "'mac': '"MAC_STANDBY0"'}");
1160 
1161     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1162     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1163 
1164     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1165 
1166     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1167     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1168 
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"'}");
1176 
1177     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1178     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1179 
1180     args = qdict_from_jsonf_nofail("{}");
1181     g_assert_nonnull(args);
1182     qdict_put_str(args, "uri", uri);
1183 
1184     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1185     g_assert(qdict_haskey(resp, "return"));
1186     qobject_unref(resp);
1187 
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);
1192 
1193     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1194     g_assert(qdict_haskey(resp, "return"));
1195     qobject_unref(resp);
1196 
1197     /* migration has been cancelled while the unplug was in progress */
1198 
1199     /* while the card is not ejected, we must be in "cancelling" state */
1200     ret = migrate_status(qts);
1201 
1202     status = qdict_get_str(ret, "status");
1203     g_assert_cmpstr(status, ==, "cancelling");
1204     qobject_unref(ret);
1205 
1206     /* OS unplugs the cards, QEMU can move from wait-unplug state */
1207     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1208 
1209     while (true) {
1210         ret = migrate_status(qts);
1211 
1212         status = qdict_get_str(ret, "status");
1213         if (strcmp(status, "cancelled") == 0) {
1214             qobject_unref(ret);
1215             break;
1216         }
1217         g_assert_cmpstr(status, ==, "cancelling");
1218         qobject_unref(ret);
1219     }
1220 
1221     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1222     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1223 
1224     qos_object_destroy((QOSGraphObject *)vdev);
1225     machine_stop(qts);
1226 }
1227 
1228 static void test_migrate_abort_active(gconstpointer opaque)
1229 {
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;
1235 
1236     qts = machine_start(BASE_MACHINE
1237                      "-netdev user,id=hs0 "
1238                      "-netdev user,id=hs1 ",
1239                      2);
1240 
1241     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1242     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1243 
1244     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1245                          "{'bus': 'root0',"
1246                          "'failover': true,"
1247                          "'netdev': 'hs0',"
1248                          "'mac': '"MAC_STANDBY0"'}");
1249 
1250     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1251     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1252 
1253     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1254 
1255     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1256     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1257 
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"'}");
1265 
1266     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1267     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1268 
1269     args = qdict_from_jsonf_nofail("{}");
1270     g_assert_nonnull(args);
1271     qdict_put_str(args, "uri", uri);
1272 
1273     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1274     g_assert(qdict_haskey(resp, "return"));
1275     qobject_unref(resp);
1276 
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);
1281 
1282     /* OS unplugs the cards, QEMU can move from wait-unplug state */
1283     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1284 
1285     while (true) {
1286         ret = migrate_status(qts);
1287 
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;
1293         }
1294         qobject_unref(ret);
1295     }
1296 
1297     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1298     g_assert(qdict_haskey(resp, "return"));
1299     qobject_unref(resp);
1300 
1301     while (true) {
1302         ret = migrate_status(qts);
1303 
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;
1309         }
1310         if (strcmp(status, "cancelled") == 0) {
1311             qobject_unref(ret);
1312             break;
1313         }
1314         g_assert_cmpstr(status, !=, "failed");
1315         g_assert_cmpstr(status, !=, "active");
1316         qobject_unref(ret);
1317     }
1318 
1319     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1320     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1321 
1322 out:
1323     qos_object_destroy((QOSGraphObject *)vdev);
1324     machine_stop(qts);
1325 }
1326 
1327 static void test_migrate_off_abort(gconstpointer opaque)
1328 {
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;
1334 
1335     qts = machine_start(BASE_MACHINE
1336                      "-netdev user,id=hs0 "
1337                      "-netdev user,id=hs1 ",
1338                      2);
1339 
1340     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1341     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1342 
1343     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1344                          "{'bus': 'root0',"
1345                          "'failover': false,"
1346                          "'netdev': 'hs0',"
1347                          "'mac': '"MAC_STANDBY0"'}");
1348 
1349     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1350     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1351 
1352     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
1353 
1354     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1355     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1356 
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"'}");
1364 
1365     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1366     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1367 
1368     args = qdict_from_jsonf_nofail("{}");
1369     g_assert_nonnull(args);
1370     qdict_put_str(args, "uri", uri);
1371 
1372     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1373     g_assert(qdict_haskey(resp, "return"));
1374     qobject_unref(resp);
1375 
1376     while (true) {
1377         ret = migrate_status(qts);
1378 
1379         status = qdict_get_str(ret, "status");
1380         if (strcmp(status, "active") == 0) {
1381             qobject_unref(ret);
1382             break;
1383         }
1384         g_assert_cmpstr(status, !=, "failed");
1385         qobject_unref(ret);
1386     }
1387 
1388     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1389     g_assert(qdict_haskey(resp, "return"));
1390     qobject_unref(resp);
1391 
1392     while (true) {
1393         ret = migrate_status(qts);
1394 
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;
1400         }
1401         if (strcmp(status, "cancelled") == 0) {
1402             qobject_unref(ret);
1403             break;
1404         }
1405         g_assert_cmpstr(status, !=, "failed");
1406         g_assert_cmpstr(status, !=, "active");
1407         qobject_unref(ret);
1408     }
1409 
1410     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1411     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1412 
1413 out:
1414     qos_object_destroy((QOSGraphObject *)vdev);
1415     machine_stop(qts);
1416 }
1417 
1418 static void test_migrate_abort_timeout(gconstpointer opaque)
1419 {
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;
1426 
1427     qts = machine_start(BASE_MACHINE
1428                      "-netdev user,id=hs0 "
1429                      "-netdev user,id=hs1 ",
1430                      2);
1431 
1432     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1433     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1434 
1435     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1436                          "{'bus': 'root0',"
1437                          "'failover': true,"
1438                          "'netdev': 'hs0',"
1439                          "'mac': '"MAC_STANDBY0"'}");
1440 
1441     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1442     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1443 
1444     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1445 
1446     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1447     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1448 
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"'}");
1456 
1457     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1458     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1459 
1460     args = qdict_from_jsonf_nofail("{}");
1461     g_assert_nonnull(args);
1462     qdict_put_str(args, "uri", uri);
1463 
1464     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1465     g_assert(qdict_haskey(resp, "return"));
1466     qobject_unref(resp);
1467 
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);
1472 
1473     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1474     g_assert(qdict_haskey(resp, "return"));
1475     qobject_unref(resp);
1476 
1477     /* migration has been cancelled while the unplug was in progress */
1478 
1479     /* while the card is not ejected, we must be in "cancelling" state */
1480 
1481     total = 0;
1482     while (true) {
1483         ret = migrate_status(qts);
1484 
1485         status = qdict_get_str(ret, "status");
1486         if (strcmp(status, "cancelled") == 0) {
1487             qobject_unref(ret);
1488             break;
1489         }
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);
1494     }
1495 
1496     /*
1497      * migration timeout in this case is 30 seconds
1498      * check we exit on the timeout (ms)
1499      */
1500     g_assert_cmpint(total, >, 30000);
1501 
1502     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1503     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1504 
1505     qos_object_destroy((QOSGraphObject *)vdev);
1506     machine_stop(qts);
1507 }
1508 
1509 static void test_multi_out(gconstpointer opaque)
1510 {
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;
1516 
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 ",
1524                 4);
1525 
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);
1530 
1531     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1532                          "{'bus': 'root0',"
1533                          "'failover': true,"
1534                          "'netdev': 'hs0',"
1535                          "'mac': '"MAC_STANDBY0"'}");
1536 
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);
1541 
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"'}");
1549 
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);
1554 
1555     vdev0 = start_virtio_net(qts, 1, 0, "standby0", true);
1556 
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);
1561 
1562     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1563                          "{'bus': 'root2',"
1564                          "'failover': true,"
1565                          "'netdev': 'hs2',"
1566                          "'mac': '"MAC_STANDBY1"'}");
1567 
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);
1572 
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"'}");
1580 
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);
1585 
1586     vdev1 = start_virtio_net(qts, 3, 0, "standby1", true);
1587 
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);
1592 
1593     args = qdict_from_jsonf_nofail("{}");
1594     g_assert_nonnull(args);
1595     qdict_put_str(args, "uri", uri);
1596 
1597     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1598     g_assert(qdict_haskey(resp, "return"));
1599     qobject_unref(resp);
1600 
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();
1609     }
1610     qobject_unref(resp);
1611 
1612     resp = get_unplug_primary_event(qts);
1613     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1614     qobject_unref(resp);
1615 
1616     /* wait the end of the migration setup phase */
1617     while (true) {
1618         ret = migrate_status(qts);
1619 
1620         status = qdict_get_str(ret, "status");
1621         if (strcmp(status, "wait-unplug") == 0) {
1622             qobject_unref(ret);
1623             break;
1624         }
1625 
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");
1632 
1633         qobject_unref(ret);
1634     }
1635 
1636     /* OS unplugs primary1, but we must wait the second */
1637     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1638 
1639     ret = migrate_status(qts);
1640     status = qdict_get_str(ret, "status");
1641     g_assert_cmpstr(status, ==, "wait-unplug");
1642     qobject_unref(ret);
1643 
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);
1652         }
1653     }
1654 
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);
1658 
1659     while (true) {
1660         ret = migrate_status(qts);
1661 
1662         status = qdict_get_str(ret, "status");
1663         if (strcmp(status, "completed") == 0) {
1664             qobject_unref(ret);
1665             break;
1666         }
1667         g_assert_cmpstr(status, !=, "failed");
1668         g_assert_cmpstr(status, !=, "cancelling");
1669         g_assert_cmpstr(status, !=, "cancelled");
1670         qobject_unref(ret);
1671     }
1672 
1673     qtest_qmp_eventwait(qts, "STOP");
1674 
1675     qos_object_destroy((QOSGraphObject *)vdev0);
1676     qos_object_destroy((QOSGraphObject *)vdev1);
1677     machine_stop(qts);
1678 }
1679 
1680 static void test_multi_in(gconstpointer opaque)
1681 {
1682     QTestState *qts;
1683     QDict *resp, *ret;
1684     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1685 
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 ",
1694                 4);
1695 
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);
1700 
1701     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1702                          "{'bus': 'root0',"
1703                          "'failover': true,"
1704                          "'netdev': 'hs0',"
1705                          "'mac': '"MAC_STANDBY0"'}");
1706 
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);
1711 
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"'}");
1719 
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);
1724 
1725     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1726                          "{'bus': 'root2',"
1727                          "'failover': true,"
1728                          "'netdev': 'hs2',"
1729                          "'mac': '"MAC_STANDBY1"'}");
1730 
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);
1735 
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"'}");
1743 
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);
1748 
1749     migrate_incoming_qmp(qts, uri, "{}");
1750 
1751     resp = get_failover_negociated_event(qts);
1752     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1753     qobject_unref(resp);
1754 
1755     resp = get_failover_negociated_event(qts);
1756     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1757     qobject_unref(resp);
1758 
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);
1763 
1764     qtest_qmp_eventwait(qts, "RESUME");
1765 
1766     ret = migrate_status(qts);
1767     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1768     qobject_unref(ret);
1769 
1770     machine_stop(qts);
1771 }
1772 #endif /* _WIN32 */
1773 
1774 int main(int argc, char **argv)
1775 {
1776     gchar *tmpfile;
1777     int ret;
1778 
1779     g_test_init(&argc, &argv, NULL);
1780 
1781     ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
1782     g_assert_true(ret >= 0);
1783     close(ret);
1784 
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);
1794 
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);
1802 
1803 #ifndef _WIN32
1804     /*
1805      * These migration tests cases use the exec migration protocol,
1806      * which is unsupported on Windows.
1807      */
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);
1831     }
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 */
1837 
1838     ret = g_test_run();
1839 
1840     unlink(tmpfile);
1841     g_free(tmpfile);
1842 
1843     return ret;
1844 }
1845