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 "libqos/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 static QDict *migrate_status(QTestState *qts)
592 {
593     QDict *resp, *ret;
594 
595     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
596     g_assert(qdict_haskey(resp, "return"));
597 
598     ret = qdict_get_qdict(resp, "return");
599     g_assert(qdict_haskey(ret, "status"));
600     qobject_ref(ret);
601     qobject_unref(resp);
602 
603     return ret;
604 }
605 
606 static QDict *get_unplug_primary_event(QTestState *qts)
607 {
608     QDict *resp;
609     QDict *data;
610 
611     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
612     g_assert(qdict_haskey(resp, "data"));
613 
614     data = qdict_get_qdict(resp, "data");
615     g_assert(qdict_haskey(data, "device-id"));
616     qobject_ref(data);
617     qobject_unref(resp);
618 
619     return data;
620 }
621 
622 static void test_migrate_out(gconstpointer opaque)
623 {
624     QTestState *qts;
625     QDict *resp, *args, *ret;
626     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
627     const gchar *status;
628     QVirtioPCIDevice *vdev;
629 
630     qts = machine_start(BASE_MACHINE
631                      "-netdev user,id=hs0 "
632                      "-netdev user,id=hs1 ",
633                      2);
634 
635     check_one_card(qts, false, "standby0", MAC_STANDBY0);
636     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
637 
638     qtest_qmp_device_add(qts, "virtio-net", "standby0",
639                          "{'bus': 'root0',"
640                          "'failover': 'on',"
641                          "'netdev': 'hs0',"
642                          "'mac': '"MAC_STANDBY0"'}");
643 
644     check_one_card(qts, true, "standby0", MAC_STANDBY0);
645     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
646 
647     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
648 
649     check_one_card(qts, true, "standby0", MAC_STANDBY0);
650     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
651 
652     qtest_qmp_device_add(qts, "virtio-net", "primary0",
653                          "{'bus': 'root1',"
654                          "'failover_pair_id': 'standby0',"
655                          "'netdev': 'hs1',"
656                          "'rombar': 0,"
657                          "'romfile': '',"
658                          "'mac': '"MAC_PRIMARY0"'}");
659 
660     check_one_card(qts, true, "standby0", MAC_STANDBY0);
661     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
662 
663     args = qdict_from_jsonf_nofail("{}");
664     g_assert_nonnull(args);
665     qdict_put_str(args, "uri", uri);
666 
667     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
668     g_assert(qdict_haskey(resp, "return"));
669     qobject_unref(resp);
670 
671     /* the event is sent when QEMU asks the OS to unplug the card */
672     resp = get_unplug_primary_event(qts);
673     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
674     qobject_unref(resp);
675 
676     /* wait the end of the migration setup phase */
677     while (true) {
678         ret = migrate_status(qts);
679 
680         status = qdict_get_str(ret, "status");
681         if (strcmp(status, "wait-unplug") == 0) {
682             qobject_unref(ret);
683             break;
684         }
685 
686         /* The migration must not start if the card is not ejected */
687         g_assert_cmpstr(status, !=, "active");
688         g_assert_cmpstr(status, !=, "completed");
689         g_assert_cmpstr(status, !=, "failed");
690         g_assert_cmpstr(status, !=, "cancelling");
691         g_assert_cmpstr(status, !=, "cancelled");
692 
693         qobject_unref(ret);
694     }
695 
696     if (g_test_slow()) {
697         /* check we stay in wait-unplug while the card is not ejected */
698         for (int i = 0; i < 5; i++) {
699             sleep(1);
700             ret = migrate_status(qts);
701             status = qdict_get_str(ret, "status");
702             g_assert_cmpstr(status, ==, "wait-unplug");
703             qobject_unref(ret);
704         }
705     }
706 
707     /* OS unplugs the cards, QEMU can move from wait-unplug state */
708     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
709 
710     while (true) {
711         ret = migrate_status(qts);
712 
713         status = qdict_get_str(ret, "status");
714         if (strcmp(status, "completed") == 0) {
715             qobject_unref(ret);
716             break;
717         }
718         g_assert_cmpstr(status, !=, "failed");
719         g_assert_cmpstr(status, !=, "cancelling");
720         g_assert_cmpstr(status, !=, "cancelled");
721         qobject_unref(ret);
722     }
723 
724     qtest_qmp_eventwait(qts, "STOP");
725 
726     /*
727      * in fact, the card is ejected from the point of view of kernel
728      * but not really from QEMU to be able to hotplug it back if
729      * migration fails. So we can't check that:
730      *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
731      *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
732      */
733 
734     qos_object_destroy((QOSGraphObject *)vdev);
735     machine_stop(qts);
736 }
737 
738 static QDict *get_migration_event(QTestState *qts)
739 {
740     QDict *resp;
741     QDict *data;
742 
743     resp = qtest_qmp_eventwait_ref(qts, "MIGRATION");
744     g_assert(qdict_haskey(resp, "data"));
745 
746     data = qdict_get_qdict(resp, "data");
747     g_assert(qdict_haskey(data, "status"));
748     qobject_ref(data);
749     qobject_unref(resp);
750 
751     return data;
752 }
753 
754 static void test_migrate_in(gconstpointer opaque)
755 {
756     QTestState *qts;
757     QDict *resp, *args, *ret;
758     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
759 
760     qts = machine_start(BASE_MACHINE
761                      "-netdev user,id=hs0 "
762                      "-netdev user,id=hs1 "
763                      "-incoming defer ",
764                      2);
765 
766     check_one_card(qts, false, "standby0", MAC_STANDBY0);
767     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
768 
769     qtest_qmp_device_add(qts, "virtio-net", "standby0",
770                          "{'bus': 'root0',"
771                          "'failover': 'on',"
772                          "'netdev': 'hs0',"
773                          "'mac': '"MAC_STANDBY0"'}");
774 
775     check_one_card(qts, true, "standby0", MAC_STANDBY0);
776     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
777 
778     qtest_qmp_device_add(qts, "virtio-net", "primary0",
779                          "{'bus': 'root1',"
780                          "'failover_pair_id': 'standby0',"
781                          "'netdev': 'hs1',"
782                          "'rombar': 0,"
783                          "'romfile': '',"
784                          "'mac': '"MAC_PRIMARY0"'}");
785 
786     check_one_card(qts, true, "standby0", MAC_STANDBY0);
787     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
788 
789     args = qdict_from_jsonf_nofail("{}");
790     g_assert_nonnull(args);
791     qdict_put_str(args, "uri", uri);
792 
793     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
794                      args);
795     g_assert(qdict_haskey(resp, "return"));
796     qobject_unref(resp);
797 
798     resp = get_migration_event(qts);
799     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
800     qobject_unref(resp);
801 
802     resp = get_failover_negociated_event(qts);
803     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
804     qobject_unref(resp);
805 
806     check_one_card(qts, true, "standby0", MAC_STANDBY0);
807     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
808 
809     qtest_qmp_eventwait(qts, "RESUME");
810 
811     ret = migrate_status(qts);
812     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
813     qobject_unref(ret);
814 
815     machine_stop(qts);
816 }
817 
818 static void test_off_migrate_out(gconstpointer opaque)
819 {
820     QTestState *qts;
821     QDict *resp, *args, *ret;
822     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
823     const gchar *status;
824     QVirtioPCIDevice *vdev;
825 
826     qts = machine_start(BASE_MACHINE
827                      "-netdev user,id=hs0 "
828                      "-netdev user,id=hs1 ",
829                      2);
830 
831     check_one_card(qts, false, "standby0", MAC_STANDBY0);
832     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
833 
834     qtest_qmp_device_add(qts, "virtio-net", "standby0",
835                          "{'bus': 'root0',"
836                          "'failover': 'off',"
837                          "'netdev': 'hs0',"
838                          "'mac': '"MAC_STANDBY0"'}");
839 
840     check_one_card(qts, true, "standby0", MAC_STANDBY0);
841     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
842 
843     qtest_qmp_device_add(qts, "virtio-net", "primary0",
844                          "{'bus': 'root1',"
845                          "'failover_pair_id': 'standby0',"
846                          "'netdev': 'hs1',"
847                          "'rombar': 0,"
848                          "'romfile': '',"
849                          "'mac': '"MAC_PRIMARY0"'}");
850 
851     check_one_card(qts, true, "standby0", MAC_STANDBY0);
852     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
853 
854     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
855 
856     check_one_card(qts, true, "standby0", MAC_STANDBY0);
857     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
858 
859     args = qdict_from_jsonf_nofail("{}");
860     g_assert_nonnull(args);
861     qdict_put_str(args, "uri", uri);
862 
863     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
864     g_assert(qdict_haskey(resp, "return"));
865     qobject_unref(resp);
866 
867     while (true) {
868         ret = migrate_status(qts);
869 
870         status = qdict_get_str(ret, "status");
871         if (strcmp(status, "completed") == 0) {
872             qobject_unref(ret);
873             break;
874         }
875         g_assert_cmpstr(status, !=, "failed");
876         g_assert_cmpstr(status, !=, "cancelling");
877         g_assert_cmpstr(status, !=, "cancelled");
878         qobject_unref(ret);
879     }
880 
881     qtest_qmp_eventwait(qts, "STOP");
882 
883     qos_object_destroy((QOSGraphObject *)vdev);
884     machine_stop(qts);
885 }
886 
887 static void test_off_migrate_in(gconstpointer opaque)
888 {
889     QTestState *qts;
890     QDict *resp, *args, *ret;
891     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
892 
893     qts = machine_start(BASE_MACHINE
894                      "-netdev user,id=hs0 "
895                      "-netdev user,id=hs1 "
896                      "-incoming defer ",
897                      2);
898 
899     check_one_card(qts, false, "standby0", MAC_STANDBY0);
900     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
901 
902     qtest_qmp_device_add(qts, "virtio-net", "standby0",
903                          "{'bus': 'root0',"
904                          "'failover': 'off',"
905                          "'netdev': 'hs0',"
906                          "'mac': '"MAC_STANDBY0"'}");
907 
908     check_one_card(qts, true, "standby0", MAC_STANDBY0);
909     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
910 
911     qtest_qmp_device_add(qts, "virtio-net", "primary0",
912                          "{'bus': 'root1',"
913                          "'failover_pair_id': 'standby0',"
914                          "'netdev': 'hs1',"
915                          "'rombar': 0,"
916                          "'romfile': '',"
917                          "'mac': '"MAC_PRIMARY0"'}");
918 
919     check_one_card(qts, true, "standby0", MAC_STANDBY0);
920     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
921 
922     args = qdict_from_jsonf_nofail("{}");
923     g_assert_nonnull(args);
924     qdict_put_str(args, "uri", uri);
925 
926     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
927                      args);
928     g_assert(qdict_haskey(resp, "return"));
929     qobject_unref(resp);
930 
931     resp = get_migration_event(qts);
932     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
933     qobject_unref(resp);
934 
935     check_one_card(qts, true, "standby0", MAC_STANDBY0);
936     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
937 
938     qtest_qmp_eventwait(qts, "RESUME");
939 
940     ret = migrate_status(qts);
941     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
942     qobject_unref(ret);
943 
944     machine_stop(qts);
945 }
946 
947 static void test_guest_off_migrate_out(gconstpointer opaque)
948 {
949     QTestState *qts;
950     QDict *resp, *args, *ret;
951     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
952     const gchar *status;
953     QVirtioPCIDevice *vdev;
954     uint64_t features;
955 
956     qts = machine_start(BASE_MACHINE
957                      "-netdev user,id=hs0 "
958                      "-netdev user,id=hs1 ",
959                      2);
960 
961     check_one_card(qts, false, "standby0", MAC_STANDBY0);
962     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
963 
964     qtest_qmp_device_add(qts, "virtio-net", "standby0",
965                          "{'bus': 'root0',"
966                          "'failover': 'on',"
967                          "'netdev': 'hs0',"
968                          "'mac': '"MAC_STANDBY0"'}");
969 
970     check_one_card(qts, true, "standby0", MAC_STANDBY0);
971     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
972 
973     qtest_qmp_device_add(qts, "virtio-net", "primary0",
974                          "{'bus': 'root1',"
975                          "'failover_pair_id': 'standby0',"
976                          "'netdev': 'hs1',"
977                          "'rombar': 0,"
978                          "'romfile': '',"
979                          "'mac': '"MAC_PRIMARY0"'}");
980 
981     check_one_card(qts, true, "standby0", MAC_STANDBY0);
982     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
983 
984     features = ~(QVIRTIO_F_BAD_FEATURE |
985                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
986                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
987                  (1ull << VIRTIO_NET_F_STANDBY));
988 
989     vdev = start_virtio_net_internal(qts, 1, 0, &features);
990 
991     check_one_card(qts, true, "standby0", MAC_STANDBY0);
992     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
993 
994     args = qdict_from_jsonf_nofail("{}");
995     g_assert_nonnull(args);
996     qdict_put_str(args, "uri", uri);
997 
998     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
999     g_assert(qdict_haskey(resp, "return"));
1000     qobject_unref(resp);
1001 
1002     while (true) {
1003         ret = migrate_status(qts);
1004 
1005         status = qdict_get_str(ret, "status");
1006         if (strcmp(status, "completed") == 0) {
1007             qobject_unref(ret);
1008             break;
1009         }
1010         g_assert_cmpstr(status, !=, "failed");
1011         g_assert_cmpstr(status, !=, "cancelling");
1012         g_assert_cmpstr(status, !=, "cancelled");
1013         qobject_unref(ret);
1014     }
1015 
1016     qtest_qmp_eventwait(qts, "STOP");
1017 
1018     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1019     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1020 
1021     qos_object_destroy((QOSGraphObject *)vdev);
1022     machine_stop(qts);
1023 }
1024 
1025 static void test_guest_off_migrate_in(gconstpointer opaque)
1026 {
1027     QTestState *qts;
1028     QDict *resp, *args, *ret;
1029     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1030 
1031     qts = machine_start(BASE_MACHINE
1032                      "-netdev user,id=hs0 "
1033                      "-netdev user,id=hs1 "
1034                      "-incoming defer ",
1035                      2);
1036 
1037     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1038     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1039 
1040     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1041                          "{'bus': 'root0',"
1042                          "'failover': 'on',"
1043                          "'netdev': 'hs0',"
1044                          "'mac': '"MAC_STANDBY0"'}");
1045 
1046     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1047     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1048 
1049     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1050                          "{'bus': 'root1',"
1051                          "'failover_pair_id': 'standby0',"
1052                          "'netdev': 'hs1',"
1053                          "'rombar': 0,"
1054                          "'romfile': '',"
1055                          "'mac': '"MAC_PRIMARY0"'}");
1056 
1057     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1058     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1059 
1060     args = qdict_from_jsonf_nofail("{}");
1061     g_assert_nonnull(args);
1062     qdict_put_str(args, "uri", uri);
1063 
1064     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1065                      args);
1066     g_assert(qdict_haskey(resp, "return"));
1067     qobject_unref(resp);
1068 
1069     resp = get_migration_event(qts);
1070     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1071     qobject_unref(resp);
1072 
1073     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1074     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1075 
1076     qtest_qmp_eventwait(qts, "RESUME");
1077 
1078     ret = migrate_status(qts);
1079     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1080     qobject_unref(ret);
1081 
1082     machine_stop(qts);
1083 }
1084 
1085 static void test_migrate_guest_off_abort(gconstpointer opaque)
1086 {
1087     QTestState *qts;
1088     QDict *resp, *args, *ret;
1089     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1090     const gchar *status;
1091     QVirtioPCIDevice *vdev;
1092     uint64_t features;
1093 
1094     qts = machine_start(BASE_MACHINE
1095                      "-netdev user,id=hs0 "
1096                      "-netdev user,id=hs1 ",
1097                      2);
1098 
1099     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1100     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1101 
1102     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1103                          "{'bus': 'root0',"
1104                          "'failover': 'on',"
1105                          "'netdev': 'hs0',"
1106                          "'mac': '"MAC_STANDBY0"'}");
1107 
1108     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1109     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1110 
1111     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1112                          "{'bus': 'root1',"
1113                          "'failover_pair_id': 'standby0',"
1114                          "'netdev': 'hs1',"
1115                          "'rombar': 0,"
1116                          "'romfile': '',"
1117                          "'mac': '"MAC_PRIMARY0"'}");
1118 
1119     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1120     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1121 
1122     features = ~(QVIRTIO_F_BAD_FEATURE |
1123                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
1124                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
1125                  (1ull << VIRTIO_NET_F_STANDBY));
1126 
1127     vdev = start_virtio_net_internal(qts, 1, 0, &features);
1128 
1129     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1130     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1131 
1132     args = qdict_from_jsonf_nofail("{}");
1133     g_assert_nonnull(args);
1134     qdict_put_str(args, "uri", uri);
1135 
1136     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1137     g_assert(qdict_haskey(resp, "return"));
1138     qobject_unref(resp);
1139 
1140     while (true) {
1141         ret = migrate_status(qts);
1142 
1143         status = qdict_get_str(ret, "status");
1144         if (strcmp(status, "completed") == 0) {
1145             g_test_skip("Failed to cancel the migration");
1146             qobject_unref(ret);
1147             goto out;
1148         }
1149         if (strcmp(status, "active") == 0) {
1150             qobject_unref(ret);
1151             break;
1152         }
1153         g_assert_cmpstr(status, !=, "failed");
1154         qobject_unref(ret);
1155     }
1156 
1157     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1158     g_assert(qdict_haskey(resp, "return"));
1159     qobject_unref(resp);
1160 
1161     while (true) {
1162         ret = migrate_status(qts);
1163         status = qdict_get_str(ret, "status");
1164         if (strcmp(status, "completed") == 0) {
1165             g_test_skip("Failed to cancel the migration");
1166             qobject_unref(ret);
1167             goto out;
1168         }
1169         if (strcmp(status, "cancelled") == 0) {
1170             qobject_unref(ret);
1171             break;
1172         }
1173         g_assert_cmpstr(status, !=, "failed");
1174         g_assert_cmpstr(status, !=, "active");
1175         qobject_unref(ret);
1176     }
1177 
1178     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1179     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1180 
1181 out:
1182     qos_object_destroy((QOSGraphObject *)vdev);
1183     machine_stop(qts);
1184 }
1185 
1186 static void test_migrate_abort_wait_unplug(gconstpointer opaque)
1187 {
1188     QTestState *qts;
1189     QDict *resp, *args, *ret;
1190     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1191     const gchar *status;
1192     QVirtioPCIDevice *vdev;
1193 
1194     qts = machine_start(BASE_MACHINE
1195                      "-netdev user,id=hs0 "
1196                      "-netdev user,id=hs1 ",
1197                      2);
1198 
1199     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1200     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1201 
1202     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1203                          "{'bus': 'root0',"
1204                          "'failover': 'on',"
1205                          "'netdev': 'hs0',"
1206                          "'mac': '"MAC_STANDBY0"'}");
1207 
1208     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1209     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1210 
1211     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1212 
1213     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1214     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1215 
1216     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1217                          "{'bus': 'root1',"
1218                          "'failover_pair_id': 'standby0',"
1219                          "'netdev': 'hs1',"
1220                          "'rombar': 0,"
1221                          "'romfile': '',"
1222                          "'mac': '"MAC_PRIMARY0"'}");
1223 
1224     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1225     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1226 
1227     args = qdict_from_jsonf_nofail("{}");
1228     g_assert_nonnull(args);
1229     qdict_put_str(args, "uri", uri);
1230 
1231     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1232     g_assert(qdict_haskey(resp, "return"));
1233     qobject_unref(resp);
1234 
1235     /* the event is sent when QEMU asks the OS to unplug the card */
1236     resp = get_unplug_primary_event(qts);
1237     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1238     qobject_unref(resp);
1239 
1240     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1241     g_assert(qdict_haskey(resp, "return"));
1242     qobject_unref(resp);
1243 
1244     /* migration has been cancelled while the unplug was in progress */
1245 
1246     /* while the card is not ejected, we must be in "cancelling" state */
1247     ret = migrate_status(qts);
1248 
1249     status = qdict_get_str(ret, "status");
1250     g_assert_cmpstr(status, ==, "cancelling");
1251     qobject_unref(ret);
1252 
1253     /* OS unplugs the cards, QEMU can move from wait-unplug state */
1254     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1255 
1256     while (true) {
1257         ret = migrate_status(qts);
1258 
1259         status = qdict_get_str(ret, "status");
1260         if (strcmp(status, "cancelled") == 0) {
1261             qobject_unref(ret);
1262             break;
1263         }
1264         g_assert_cmpstr(status, ==, "cancelling");
1265         qobject_unref(ret);
1266     }
1267 
1268     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1269     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1270 
1271     qos_object_destroy((QOSGraphObject *)vdev);
1272     machine_stop(qts);
1273 }
1274 
1275 static void test_migrate_abort_active(gconstpointer opaque)
1276 {
1277     QTestState *qts;
1278     QDict *resp, *args, *ret;
1279     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1280     const gchar *status;
1281     QVirtioPCIDevice *vdev;
1282 
1283     qts = machine_start(BASE_MACHINE
1284                      "-netdev user,id=hs0 "
1285                      "-netdev user,id=hs1 ",
1286                      2);
1287 
1288     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1289     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1290 
1291     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1292                          "{'bus': 'root0',"
1293                          "'failover': 'on',"
1294                          "'netdev': 'hs0',"
1295                          "'mac': '"MAC_STANDBY0"'}");
1296 
1297     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1298     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1299 
1300     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1301 
1302     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1303     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1304 
1305     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1306                          "{'bus': 'root1',"
1307                          "'failover_pair_id': 'standby0',"
1308                          "'netdev': 'hs1',"
1309                          "'rombar': 0,"
1310                          "'romfile': '',"
1311                          "'mac': '"MAC_PRIMARY0"'}");
1312 
1313     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1314     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1315 
1316     args = qdict_from_jsonf_nofail("{}");
1317     g_assert_nonnull(args);
1318     qdict_put_str(args, "uri", uri);
1319 
1320     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1321     g_assert(qdict_haskey(resp, "return"));
1322     qobject_unref(resp);
1323 
1324     /* the event is sent when QEMU asks the OS to unplug the card */
1325     resp = get_unplug_primary_event(qts);
1326     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1327     qobject_unref(resp);
1328 
1329     /* OS unplugs the cards, QEMU can move from wait-unplug state */
1330     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1331 
1332     while (true) {
1333         ret = migrate_status(qts);
1334 
1335         status = qdict_get_str(ret, "status");
1336         g_assert_cmpstr(status, !=, "failed");
1337         if (strcmp(status, "wait-unplug") != 0) {
1338             qobject_unref(ret);
1339             break;
1340         }
1341         qobject_unref(ret);
1342     }
1343 
1344     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1345     g_assert(qdict_haskey(resp, "return"));
1346     qobject_unref(resp);
1347 
1348     while (true) {
1349         ret = migrate_status(qts);
1350 
1351         status = qdict_get_str(ret, "status");
1352         if (strcmp(status, "completed") == 0) {
1353             g_test_skip("Failed to cancel the migration");
1354             qobject_unref(ret);
1355             goto out;
1356         }
1357         if (strcmp(status, "cancelled") == 0) {
1358             qobject_unref(ret);
1359             break;
1360         }
1361         g_assert_cmpstr(status, !=, "failed");
1362         g_assert_cmpstr(status, !=, "active");
1363         qobject_unref(ret);
1364     }
1365 
1366     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1367     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1368 
1369 out:
1370     qos_object_destroy((QOSGraphObject *)vdev);
1371     machine_stop(qts);
1372 }
1373 
1374 static void test_migrate_off_abort(gconstpointer opaque)
1375 {
1376     QTestState *qts;
1377     QDict *resp, *args, *ret;
1378     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1379     const gchar *status;
1380     QVirtioPCIDevice *vdev;
1381 
1382     qts = machine_start(BASE_MACHINE
1383                      "-netdev user,id=hs0 "
1384                      "-netdev user,id=hs1 ",
1385                      2);
1386 
1387     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1388     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1389 
1390     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1391                          "{'bus': 'root0',"
1392                          "'failover': 'off',"
1393                          "'netdev': 'hs0',"
1394                          "'mac': '"MAC_STANDBY0"'}");
1395 
1396     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1397     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1398 
1399     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
1400 
1401     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1402     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1403 
1404     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1405                          "{'bus': 'root1',"
1406                          "'failover_pair_id': 'standby0',"
1407                          "'netdev': 'hs1',"
1408                          "'rombar': 0,"
1409                          "'romfile': '',"
1410                          "'mac': '"MAC_PRIMARY0"'}");
1411 
1412     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1413     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1414 
1415     args = qdict_from_jsonf_nofail("{}");
1416     g_assert_nonnull(args);
1417     qdict_put_str(args, "uri", uri);
1418 
1419     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1420     g_assert(qdict_haskey(resp, "return"));
1421     qobject_unref(resp);
1422 
1423     while (true) {
1424         ret = migrate_status(qts);
1425 
1426         status = qdict_get_str(ret, "status");
1427         if (strcmp(status, "active") == 0) {
1428             qobject_unref(ret);
1429             break;
1430         }
1431         g_assert_cmpstr(status, !=, "failed");
1432         qobject_unref(ret);
1433     }
1434 
1435     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1436     g_assert(qdict_haskey(resp, "return"));
1437     qobject_unref(resp);
1438 
1439     while (true) {
1440         ret = migrate_status(qts);
1441 
1442         status = qdict_get_str(ret, "status");
1443         if (strcmp(status, "completed") == 0) {
1444             g_test_skip("Failed to cancel the migration");
1445             qobject_unref(ret);
1446             goto out;
1447         }
1448         if (strcmp(status, "cancelled") == 0) {
1449             qobject_unref(ret);
1450             break;
1451         }
1452         g_assert_cmpstr(status, !=, "failed");
1453         g_assert_cmpstr(status, !=, "active");
1454         qobject_unref(ret);
1455     }
1456 
1457     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1458     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1459 
1460 out:
1461     qos_object_destroy((QOSGraphObject *)vdev);
1462     machine_stop(qts);
1463 }
1464 
1465 static void test_migrate_abort_timeout(gconstpointer opaque)
1466 {
1467     QTestState *qts;
1468     QDict *resp, *args, *ret;
1469     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1470     const gchar *status;
1471     int total;
1472     QVirtioPCIDevice *vdev;
1473 
1474     qts = machine_start(BASE_MACHINE
1475                      "-netdev user,id=hs0 "
1476                      "-netdev user,id=hs1 ",
1477                      2);
1478 
1479     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1480     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1481 
1482     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1483                          "{'bus': 'root0',"
1484                          "'failover': 'on',"
1485                          "'netdev': 'hs0',"
1486                          "'mac': '"MAC_STANDBY0"'}");
1487 
1488     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1489     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1490 
1491     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1492 
1493     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1494     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1495 
1496     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1497                          "{'bus': 'root1',"
1498                          "'failover_pair_id': 'standby0',"
1499                          "'netdev': 'hs1',"
1500                          "'rombar': 0,"
1501                          "'romfile': '',"
1502                          "'mac': '"MAC_PRIMARY0"'}");
1503 
1504     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1505     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1506 
1507     args = qdict_from_jsonf_nofail("{}");
1508     g_assert_nonnull(args);
1509     qdict_put_str(args, "uri", uri);
1510 
1511     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1512     g_assert(qdict_haskey(resp, "return"));
1513     qobject_unref(resp);
1514 
1515     /* the event is sent when QEMU asks the OS to unplug the card */
1516     resp = get_unplug_primary_event(qts);
1517     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1518     qobject_unref(resp);
1519 
1520     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1521     g_assert(qdict_haskey(resp, "return"));
1522     qobject_unref(resp);
1523 
1524     /* migration has been cancelled while the unplug was in progress */
1525 
1526     /* while the card is not ejected, we must be in "cancelling" state */
1527 
1528     total = 0;
1529     while (true) {
1530         ret = migrate_status(qts);
1531 
1532         status = qdict_get_str(ret, "status");
1533         if (strcmp(status, "cancelled") == 0) {
1534             qobject_unref(ret);
1535             break;
1536         }
1537         g_assert_cmpstr(status, ==, "cancelling");
1538         g_assert(qdict_haskey(ret, "total-time"));
1539         total = qdict_get_int(ret, "total-time");
1540         qobject_unref(ret);
1541     }
1542 
1543     /*
1544      * migration timeout in this case is 30 seconds
1545      * check we exit on the timeout (ms)
1546      */
1547     g_assert_cmpint(total, >, 30000);
1548 
1549     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1550     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1551 
1552     qos_object_destroy((QOSGraphObject *)vdev);
1553     machine_stop(qts);
1554 }
1555 
1556 static void test_multi_out(gconstpointer opaque)
1557 {
1558     QTestState *qts;
1559     QDict *resp, *args, *ret;
1560     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1561     const gchar *status, *expected;
1562     QVirtioPCIDevice *vdev0, *vdev1;
1563 
1564     qts = machine_start(BASE_MACHINE
1565                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1566                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1567                 "-netdev user,id=hs0 "
1568                 "-netdev user,id=hs1 "
1569                 "-netdev user,id=hs2 "
1570                 "-netdev user,id=hs3 ",
1571                 4);
1572 
1573     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1574     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1575     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1576     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1577 
1578     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1579                          "{'bus': 'root0',"
1580                          "'failover': 'on',"
1581                          "'netdev': 'hs0',"
1582                          "'mac': '"MAC_STANDBY0"'}");
1583 
1584     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1585     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1586     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1587     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1588 
1589     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1590                          "{'bus': 'root1',"
1591                          "'failover_pair_id': 'standby0',"
1592                          "'netdev': 'hs1',"
1593                          "'rombar': 0,"
1594                          "'romfile': '',"
1595                          "'mac': '"MAC_PRIMARY0"'}");
1596 
1597     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1598     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1599     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1600     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1601 
1602     vdev0 = start_virtio_net(qts, 1, 0, "standby0", true);
1603 
1604     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1605     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1606     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1607     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1608 
1609     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1610                          "{'bus': 'root2',"
1611                          "'failover': 'on',"
1612                          "'netdev': 'hs2',"
1613                          "'mac': '"MAC_STANDBY1"'}");
1614 
1615     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1616     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1617     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1618     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1619 
1620     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1621                          "{'bus': 'root3',"
1622                          "'failover_pair_id': 'standby1',"
1623                          "'netdev': 'hs3',"
1624                          "'rombar': 0,"
1625                          "'romfile': '',"
1626                          "'mac': '"MAC_PRIMARY1"'}");
1627 
1628     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1629     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1630     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1631     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1632 
1633     vdev1 = start_virtio_net(qts, 3, 0, "standby1", true);
1634 
1635     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1636     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1637     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1638     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1639 
1640     args = qdict_from_jsonf_nofail("{}");
1641     g_assert_nonnull(args);
1642     qdict_put_str(args, "uri", uri);
1643 
1644     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1645     g_assert(qdict_haskey(resp, "return"));
1646     qobject_unref(resp);
1647 
1648     /* the event is sent when QEMU asks the OS to unplug the card */
1649     resp = get_unplug_primary_event(qts);
1650     if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
1651         expected = "primary1";
1652     } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
1653         expected = "primary0";
1654     } else {
1655         g_assert_not_reached();
1656     }
1657     qobject_unref(resp);
1658 
1659     resp = get_unplug_primary_event(qts);
1660     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1661     qobject_unref(resp);
1662 
1663     /* wait the end of the migration setup phase */
1664     while (true) {
1665         ret = migrate_status(qts);
1666 
1667         status = qdict_get_str(ret, "status");
1668         if (strcmp(status, "wait-unplug") == 0) {
1669             qobject_unref(ret);
1670             break;
1671         }
1672 
1673         /* The migration must not start if the card is not ejected */
1674         g_assert_cmpstr(status, !=, "active");
1675         g_assert_cmpstr(status, !=, "completed");
1676         g_assert_cmpstr(status, !=, "failed");
1677         g_assert_cmpstr(status, !=, "cancelling");
1678         g_assert_cmpstr(status, !=, "cancelled");
1679 
1680         qobject_unref(ret);
1681     }
1682 
1683     /* OS unplugs primary1, but we must wait the second */
1684     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1685 
1686     ret = migrate_status(qts);
1687     status = qdict_get_str(ret, "status");
1688     g_assert_cmpstr(status, ==, "wait-unplug");
1689     qobject_unref(ret);
1690 
1691     if (g_test_slow()) {
1692         /* check we stay in wait-unplug while the card is not ejected */
1693         for (int i = 0; i < 5; i++) {
1694             sleep(1);
1695             ret = migrate_status(qts);
1696             status = qdict_get_str(ret, "status");
1697             g_assert_cmpstr(status, ==, "wait-unplug");
1698             qobject_unref(ret);
1699         }
1700     }
1701 
1702     /* OS unplugs primary0, QEMU can move from wait-unplug state */
1703     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
1704     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1705 
1706     while (true) {
1707         ret = migrate_status(qts);
1708 
1709         status = qdict_get_str(ret, "status");
1710         if (strcmp(status, "completed") == 0) {
1711             qobject_unref(ret);
1712             break;
1713         }
1714         g_assert_cmpstr(status, !=, "failed");
1715         g_assert_cmpstr(status, !=, "cancelling");
1716         g_assert_cmpstr(status, !=, "cancelled");
1717         qobject_unref(ret);
1718     }
1719 
1720     qtest_qmp_eventwait(qts, "STOP");
1721 
1722     qos_object_destroy((QOSGraphObject *)vdev0);
1723     qos_object_destroy((QOSGraphObject *)vdev1);
1724     machine_stop(qts);
1725 }
1726 
1727 static void test_multi_in(gconstpointer opaque)
1728 {
1729     QTestState *qts;
1730     QDict *resp, *args, *ret;
1731     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1732 
1733     qts = machine_start(BASE_MACHINE
1734                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1735                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1736                 "-netdev user,id=hs0 "
1737                 "-netdev user,id=hs1 "
1738                 "-netdev user,id=hs2 "
1739                 "-netdev user,id=hs3 "
1740                 "-incoming defer ",
1741                 4);
1742 
1743     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1744     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1745     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1746     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1747 
1748     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1749                          "{'bus': 'root0',"
1750                          "'failover': 'on',"
1751                          "'netdev': 'hs0',"
1752                          "'mac': '"MAC_STANDBY0"'}");
1753 
1754     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1755     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1756     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1757     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1758 
1759     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1760                          "{'bus': 'root1',"
1761                          "'failover_pair_id': 'standby0',"
1762                          "'netdev': 'hs1',"
1763                          "'rombar': 0,"
1764                          "'romfile': '',"
1765                          "'mac': '"MAC_PRIMARY0"'}");
1766 
1767     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1768     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1769     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1770     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1771 
1772     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1773                          "{'bus': 'root2',"
1774                          "'failover': 'on',"
1775                          "'netdev': 'hs2',"
1776                          "'mac': '"MAC_STANDBY1"'}");
1777 
1778     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1779     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1780     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1781     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1782 
1783     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1784                          "{'bus': 'root3',"
1785                          "'failover_pair_id': 'standby1',"
1786                          "'netdev': 'hs3',"
1787                          "'rombar': 0,"
1788                          "'romfile': '',"
1789                          "'mac': '"MAC_PRIMARY1"'}");
1790 
1791     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1792     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1793     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1794     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1795 
1796     args = qdict_from_jsonf_nofail("{}");
1797     g_assert_nonnull(args);
1798     qdict_put_str(args, "uri", uri);
1799 
1800     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1801                      args);
1802     g_assert(qdict_haskey(resp, "return"));
1803     qobject_unref(resp);
1804 
1805     resp = get_migration_event(qts);
1806     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1807     qobject_unref(resp);
1808 
1809     resp = get_failover_negociated_event(qts);
1810     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1811     qobject_unref(resp);
1812 
1813     resp = get_failover_negociated_event(qts);
1814     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1815     qobject_unref(resp);
1816 
1817     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1818     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1819     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1820     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1821 
1822     qtest_qmp_eventwait(qts, "RESUME");
1823 
1824     ret = migrate_status(qts);
1825     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1826     qobject_unref(ret);
1827 
1828     machine_stop(qts);
1829 }
1830 
1831 int main(int argc, char **argv)
1832 {
1833     gchar *tmpfile;
1834     int ret;
1835 
1836     g_test_init(&argc, &argv, NULL);
1837 
1838     ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
1839     g_assert_true(ret >= 0);
1840     close(ret);
1841 
1842     /* parameters tests */
1843     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1844     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1845     qtest_add_func("failover-virtio-net/params/on", test_on);
1846     qtest_add_func("failover-virtio-net/params/on_mismatch",
1847                    test_on_mismatch);
1848     qtest_add_func("failover-virtio-net/params/off", test_off);
1849     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
1850     qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off);
1851 
1852     /* hotplug tests */
1853     qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1);
1854     qtest_add_func("failover-virtio-net/hotplug/1_reverse",
1855                    test_hotplug_1_reverse);
1856     qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2);
1857     qtest_add_func("failover-virtio-net/hotplug/2_reverse",
1858                    test_hotplug_2_reverse);
1859 
1860     /* migration tests */
1861     qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile,
1862                         test_migrate_out);
1863     qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile,
1864                         test_migrate_in);
1865     qtest_add_data_func("failover-virtio-net/migrate/off/out", tmpfile,
1866                         test_off_migrate_out);
1867     qtest_add_data_func("failover-virtio-net/migrate/off/in", tmpfile,
1868                         test_off_migrate_in);
1869     qtest_add_data_func("failover-virtio-net/migrate/off/abort", tmpfile,
1870                         test_migrate_off_abort);
1871     qtest_add_data_func("failover-virtio-net/migrate/guest_off/out", tmpfile,
1872                         test_guest_off_migrate_out);
1873     qtest_add_data_func("failover-virtio-net/migrate/guest_off/in", tmpfile,
1874                         test_guest_off_migrate_in);
1875     qtest_add_data_func("failover-virtio-net/migrate/guest_off/abort", tmpfile,
1876                         test_migrate_guest_off_abort);
1877     qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
1878                         tmpfile, test_migrate_abort_wait_unplug);
1879     qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
1880                         test_migrate_abort_active);
1881     if (g_test_slow()) {
1882         qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
1883                             tmpfile, test_migrate_abort_timeout);
1884     }
1885     qtest_add_data_func("failover-virtio-net/migrate/multi/out",
1886                         tmpfile, test_multi_out);
1887     qtest_add_data_func("failover-virtio-net/migrate/multi/in",
1888                    tmpfile, test_multi_in);
1889 
1890     ret = g_test_run();
1891 
1892     unlink(tmpfile);
1893     g_free(tmpfile);
1894 
1895     return ret;
1896 }
1897