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, "active") == 0) {
1145             qobject_unref(ret);
1146             break;
1147         }
1148         g_assert_cmpstr(status, !=, "failed");
1149         qobject_unref(ret);
1150     }
1151 
1152     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1153     g_assert(qdict_haskey(resp, "return"));
1154     qobject_unref(resp);
1155 
1156     while (true) {
1157         ret = migrate_status(qts);
1158 
1159         status = qdict_get_str(ret, "status");
1160         if (strcmp(status, "cancelled") == 0) {
1161             qobject_unref(ret);
1162             break;
1163         }
1164         g_assert_cmpstr(status, !=, "failed");
1165         g_assert_cmpstr(status, !=, "active");
1166         qobject_unref(ret);
1167     }
1168 
1169     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1170     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1171 
1172     qos_object_destroy((QOSGraphObject *)vdev);
1173     machine_stop(qts);
1174 }
1175 
1176 static void test_migrate_abort_wait_unplug(gconstpointer opaque)
1177 {
1178     QTestState *qts;
1179     QDict *resp, *args, *ret;
1180     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1181     const gchar *status;
1182     QVirtioPCIDevice *vdev;
1183 
1184     qts = machine_start(BASE_MACHINE
1185                      "-netdev user,id=hs0 "
1186                      "-netdev user,id=hs1 ",
1187                      2);
1188 
1189     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1190     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1191 
1192     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1193                          "{'bus': 'root0',"
1194                          "'failover': 'on',"
1195                          "'netdev': 'hs0',"
1196                          "'mac': '"MAC_STANDBY0"'}");
1197 
1198     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1199     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1200 
1201     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1202 
1203     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1204     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1205 
1206     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1207                          "{'bus': 'root1',"
1208                          "'failover_pair_id': 'standby0',"
1209                          "'netdev': 'hs1',"
1210                          "'rombar': 0,"
1211                          "'romfile': '',"
1212                          "'mac': '"MAC_PRIMARY0"'}");
1213 
1214     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1215     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1216 
1217     args = qdict_from_jsonf_nofail("{}");
1218     g_assert_nonnull(args);
1219     qdict_put_str(args, "uri", uri);
1220 
1221     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1222     g_assert(qdict_haskey(resp, "return"));
1223     qobject_unref(resp);
1224 
1225     /* the event is sent when QEMU asks the OS to unplug the card */
1226     resp = get_unplug_primary_event(qts);
1227     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1228     qobject_unref(resp);
1229 
1230     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1231     g_assert(qdict_haskey(resp, "return"));
1232     qobject_unref(resp);
1233 
1234     /* migration has been cancelled while the unplug was in progress */
1235 
1236     /* while the card is not ejected, we must be in "cancelling" state */
1237     ret = migrate_status(qts);
1238 
1239     status = qdict_get_str(ret, "status");
1240     g_assert_cmpstr(status, ==, "cancelling");
1241     qobject_unref(ret);
1242 
1243     /* OS unplugs the cards, QEMU can move from wait-unplug state */
1244     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1245 
1246     while (true) {
1247         ret = migrate_status(qts);
1248 
1249         status = qdict_get_str(ret, "status");
1250         if (strcmp(status, "cancelled") == 0) {
1251             qobject_unref(ret);
1252             break;
1253         }
1254         g_assert_cmpstr(status, !=, "failed");
1255         g_assert_cmpstr(status, !=, "active");
1256         qobject_unref(ret);
1257     }
1258 
1259     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1260     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1261 
1262     qos_object_destroy((QOSGraphObject *)vdev);
1263     machine_stop(qts);
1264 }
1265 
1266 static void test_migrate_abort_active(gconstpointer opaque)
1267 {
1268     QTestState *qts;
1269     QDict *resp, *args, *ret;
1270     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1271     const gchar *status;
1272     QVirtioPCIDevice *vdev;
1273 
1274     qts = machine_start(BASE_MACHINE
1275                      "-netdev user,id=hs0 "
1276                      "-netdev user,id=hs1 ",
1277                      2);
1278 
1279     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1280     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1281 
1282     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1283                          "{'bus': 'root0',"
1284                          "'failover': 'on',"
1285                          "'netdev': 'hs0',"
1286                          "'mac': '"MAC_STANDBY0"'}");
1287 
1288     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1289     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1290 
1291     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1292 
1293     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1294     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1295 
1296     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1297                          "{'bus': 'root1',"
1298                          "'failover_pair_id': 'standby0',"
1299                          "'netdev': 'hs1',"
1300                          "'rombar': 0,"
1301                          "'romfile': '',"
1302                          "'mac': '"MAC_PRIMARY0"'}");
1303 
1304     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1305     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1306 
1307     args = qdict_from_jsonf_nofail("{}");
1308     g_assert_nonnull(args);
1309     qdict_put_str(args, "uri", uri);
1310 
1311     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1312     g_assert(qdict_haskey(resp, "return"));
1313     qobject_unref(resp);
1314 
1315     /* the event is sent when QEMU asks the OS to unplug the card */
1316     resp = get_unplug_primary_event(qts);
1317     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1318     qobject_unref(resp);
1319 
1320     /* OS unplugs the cards, QEMU can move from wait-unplug state */
1321     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1322 
1323     while (true) {
1324         ret = migrate_status(qts);
1325 
1326         status = qdict_get_str(ret, "status");
1327         if (strcmp(status, "wait-unplug") != 0) {
1328             qobject_unref(ret);
1329             break;
1330         }
1331         g_assert_cmpstr(status, !=, "failed");
1332         qobject_unref(ret);
1333     }
1334 
1335     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1336     g_assert(qdict_haskey(resp, "return"));
1337     qobject_unref(resp);
1338 
1339     while (true) {
1340         ret = migrate_status(qts);
1341 
1342         status = qdict_get_str(ret, "status");
1343         if (strcmp(status, "cancelled") == 0) {
1344             qobject_unref(ret);
1345             break;
1346         }
1347         g_assert_cmpstr(status, !=, "failed");
1348         g_assert_cmpstr(status, !=, "active");
1349         qobject_unref(ret);
1350     }
1351 
1352     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1353     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1354 
1355     qos_object_destroy((QOSGraphObject *)vdev);
1356     machine_stop(qts);
1357 }
1358 
1359 static void test_migrate_off_abort(gconstpointer opaque)
1360 {
1361     QTestState *qts;
1362     QDict *resp, *args, *ret;
1363     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1364     const gchar *status;
1365     QVirtioPCIDevice *vdev;
1366 
1367     qts = machine_start(BASE_MACHINE
1368                      "-netdev user,id=hs0 "
1369                      "-netdev user,id=hs1 ",
1370                      2);
1371 
1372     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1373     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1374 
1375     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1376                          "{'bus': 'root0',"
1377                          "'failover': 'off',"
1378                          "'netdev': 'hs0',"
1379                          "'mac': '"MAC_STANDBY0"'}");
1380 
1381     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1382     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1383 
1384     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
1385 
1386     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1387     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1388 
1389     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1390                          "{'bus': 'root1',"
1391                          "'failover_pair_id': 'standby0',"
1392                          "'netdev': 'hs1',"
1393                          "'rombar': 0,"
1394                          "'romfile': '',"
1395                          "'mac': '"MAC_PRIMARY0"'}");
1396 
1397     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1398     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1399 
1400     args = qdict_from_jsonf_nofail("{}");
1401     g_assert_nonnull(args);
1402     qdict_put_str(args, "uri", uri);
1403 
1404     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1405     g_assert(qdict_haskey(resp, "return"));
1406     qobject_unref(resp);
1407 
1408     while (true) {
1409         ret = migrate_status(qts);
1410 
1411         status = qdict_get_str(ret, "status");
1412         if (strcmp(status, "active") == 0) {
1413             qobject_unref(ret);
1414             break;
1415         }
1416         g_assert_cmpstr(status, !=, "failed");
1417         qobject_unref(ret);
1418     }
1419 
1420     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1421     g_assert(qdict_haskey(resp, "return"));
1422     qobject_unref(resp);
1423 
1424     while (true) {
1425         ret = migrate_status(qts);
1426 
1427         status = qdict_get_str(ret, "status");
1428         if (strcmp(status, "cancelled") == 0) {
1429             qobject_unref(ret);
1430             break;
1431         }
1432         g_assert_cmpstr(status, !=, "failed");
1433         g_assert_cmpstr(status, !=, "active");
1434         qobject_unref(ret);
1435     }
1436 
1437     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1438     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1439 
1440     qos_object_destroy((QOSGraphObject *)vdev);
1441     machine_stop(qts);
1442 }
1443 
1444 static void test_migrate_abort_timeout(gconstpointer opaque)
1445 {
1446     QTestState *qts;
1447     QDict *resp, *args, *ret;
1448     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1449     const gchar *status;
1450     int total;
1451     QVirtioPCIDevice *vdev;
1452 
1453     qts = machine_start(BASE_MACHINE
1454                      "-netdev user,id=hs0 "
1455                      "-netdev user,id=hs1 ",
1456                      2);
1457 
1458     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1459     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1460 
1461     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1462                          "{'bus': 'root0',"
1463                          "'failover': 'on',"
1464                          "'netdev': 'hs0',"
1465                          "'mac': '"MAC_STANDBY0"'}");
1466 
1467     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1468     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1469 
1470     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1471 
1472     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1473     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1474 
1475     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1476                          "{'bus': 'root1',"
1477                          "'failover_pair_id': 'standby0',"
1478                          "'netdev': 'hs1',"
1479                          "'rombar': 0,"
1480                          "'romfile': '',"
1481                          "'mac': '"MAC_PRIMARY0"'}");
1482 
1483     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1484     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1485 
1486     args = qdict_from_jsonf_nofail("{}");
1487     g_assert_nonnull(args);
1488     qdict_put_str(args, "uri", uri);
1489 
1490     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1491     g_assert(qdict_haskey(resp, "return"));
1492     qobject_unref(resp);
1493 
1494     /* the event is sent when QEMU asks the OS to unplug the card */
1495     resp = get_unplug_primary_event(qts);
1496     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1497     qobject_unref(resp);
1498 
1499     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1500     g_assert(qdict_haskey(resp, "return"));
1501     qobject_unref(resp);
1502 
1503     /* migration has been cancelled while the unplug was in progress */
1504 
1505     /* while the card is not ejected, we must be in "cancelling" state */
1506 
1507     total = 0;
1508     while (true) {
1509         ret = migrate_status(qts);
1510 
1511         status = qdict_get_str(ret, "status");
1512         if (strcmp(status, "cancelled") == 0) {
1513             qobject_unref(ret);
1514             break;
1515         }
1516         g_assert_cmpstr(status, ==, "cancelling");
1517         g_assert(qdict_haskey(ret, "total-time"));
1518         total = qdict_get_int(ret, "total-time");
1519         qobject_unref(ret);
1520     }
1521 
1522     /*
1523      * migration timeout in this case is 30 seconds
1524      * check we exit on the timeout (ms)
1525      */
1526     g_assert_cmpint(total, >, 30000);
1527 
1528     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1529     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1530 
1531     qos_object_destroy((QOSGraphObject *)vdev);
1532     machine_stop(qts);
1533 }
1534 
1535 static void test_multi_out(gconstpointer opaque)
1536 {
1537     QTestState *qts;
1538     QDict *resp, *args, *ret;
1539     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1540     const gchar *status, *expected;
1541     QVirtioPCIDevice *vdev0, *vdev1;
1542 
1543     qts = machine_start(BASE_MACHINE
1544                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1545                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1546                 "-netdev user,id=hs0 "
1547                 "-netdev user,id=hs1 "
1548                 "-netdev user,id=hs2 "
1549                 "-netdev user,id=hs3 ",
1550                 4);
1551 
1552     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1553     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1554     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1555     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1556 
1557     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1558                          "{'bus': 'root0',"
1559                          "'failover': 'on',"
1560                          "'netdev': 'hs0',"
1561                          "'mac': '"MAC_STANDBY0"'}");
1562 
1563     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1564     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1565     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1566     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1567 
1568     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1569                          "{'bus': 'root1',"
1570                          "'failover_pair_id': 'standby0',"
1571                          "'netdev': 'hs1',"
1572                          "'rombar': 0,"
1573                          "'romfile': '',"
1574                          "'mac': '"MAC_PRIMARY0"'}");
1575 
1576     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1577     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1578     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1579     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1580 
1581     vdev0 = start_virtio_net(qts, 1, 0, "standby0", true);
1582 
1583     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1584     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1585     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1586     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1587 
1588     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1589                          "{'bus': 'root2',"
1590                          "'failover': 'on',"
1591                          "'netdev': 'hs2',"
1592                          "'mac': '"MAC_STANDBY1"'}");
1593 
1594     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1595     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1596     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1597     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1598 
1599     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1600                          "{'bus': 'root3',"
1601                          "'failover_pair_id': 'standby1',"
1602                          "'netdev': 'hs3',"
1603                          "'rombar': 0,"
1604                          "'romfile': '',"
1605                          "'mac': '"MAC_PRIMARY1"'}");
1606 
1607     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1608     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1609     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1610     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1611 
1612     vdev1 = start_virtio_net(qts, 3, 0, "standby1", true);
1613 
1614     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1615     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1616     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1617     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1618 
1619     args = qdict_from_jsonf_nofail("{}");
1620     g_assert_nonnull(args);
1621     qdict_put_str(args, "uri", uri);
1622 
1623     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1624     g_assert(qdict_haskey(resp, "return"));
1625     qobject_unref(resp);
1626 
1627     /* the event is sent when QEMU asks the OS to unplug the card */
1628     resp = get_unplug_primary_event(qts);
1629     if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
1630         expected = "primary1";
1631     } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
1632         expected = "primary0";
1633     } else {
1634         g_assert_not_reached();
1635     }
1636     qobject_unref(resp);
1637 
1638     resp = get_unplug_primary_event(qts);
1639     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1640     qobject_unref(resp);
1641 
1642     /* wait the end of the migration setup phase */
1643     while (true) {
1644         ret = migrate_status(qts);
1645 
1646         status = qdict_get_str(ret, "status");
1647         if (strcmp(status, "wait-unplug") == 0) {
1648             qobject_unref(ret);
1649             break;
1650         }
1651 
1652         /* The migration must not start if the card is not ejected */
1653         g_assert_cmpstr(status, !=, "active");
1654         g_assert_cmpstr(status, !=, "completed");
1655         g_assert_cmpstr(status, !=, "failed");
1656         g_assert_cmpstr(status, !=, "cancelling");
1657         g_assert_cmpstr(status, !=, "cancelled");
1658 
1659         qobject_unref(ret);
1660     }
1661 
1662     /* OS unplugs primary1, but we must wait the second */
1663     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1664 
1665     ret = migrate_status(qts);
1666     status = qdict_get_str(ret, "status");
1667     g_assert_cmpstr(status, ==, "wait-unplug");
1668     qobject_unref(ret);
1669 
1670     if (g_test_slow()) {
1671         /* check we stay in wait-unplug while the card is not ejected */
1672         for (int i = 0; i < 5; i++) {
1673             sleep(1);
1674             ret = migrate_status(qts);
1675             status = qdict_get_str(ret, "status");
1676             g_assert_cmpstr(status, ==, "wait-unplug");
1677             qobject_unref(ret);
1678         }
1679     }
1680 
1681     /* OS unplugs primary0, QEMU can move from wait-unplug state */
1682     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
1683     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1684 
1685     while (true) {
1686         ret = migrate_status(qts);
1687 
1688         status = qdict_get_str(ret, "status");
1689         if (strcmp(status, "completed") == 0) {
1690             qobject_unref(ret);
1691             break;
1692         }
1693         g_assert_cmpstr(status, !=, "failed");
1694         g_assert_cmpstr(status, !=, "cancelling");
1695         g_assert_cmpstr(status, !=, "cancelled");
1696         qobject_unref(ret);
1697     }
1698 
1699     qtest_qmp_eventwait(qts, "STOP");
1700 
1701     qos_object_destroy((QOSGraphObject *)vdev0);
1702     qos_object_destroy((QOSGraphObject *)vdev1);
1703     machine_stop(qts);
1704 }
1705 
1706 static void test_multi_in(gconstpointer opaque)
1707 {
1708     QTestState *qts;
1709     QDict *resp, *args, *ret;
1710     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1711 
1712     qts = machine_start(BASE_MACHINE
1713                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1714                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1715                 "-netdev user,id=hs0 "
1716                 "-netdev user,id=hs1 "
1717                 "-netdev user,id=hs2 "
1718                 "-netdev user,id=hs3 "
1719                 "-incoming defer ",
1720                 4);
1721 
1722     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1723     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1724     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1725     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1726 
1727     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1728                          "{'bus': 'root0',"
1729                          "'failover': 'on',"
1730                          "'netdev': 'hs0',"
1731                          "'mac': '"MAC_STANDBY0"'}");
1732 
1733     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1734     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1735     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1736     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1737 
1738     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1739                          "{'bus': 'root1',"
1740                          "'failover_pair_id': 'standby0',"
1741                          "'netdev': 'hs1',"
1742                          "'rombar': 0,"
1743                          "'romfile': '',"
1744                          "'mac': '"MAC_PRIMARY0"'}");
1745 
1746     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1747     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1748     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1749     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1750 
1751     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1752                          "{'bus': 'root2',"
1753                          "'failover': 'on',"
1754                          "'netdev': 'hs2',"
1755                          "'mac': '"MAC_STANDBY1"'}");
1756 
1757     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1758     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1759     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1760     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1761 
1762     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1763                          "{'bus': 'root3',"
1764                          "'failover_pair_id': 'standby1',"
1765                          "'netdev': 'hs3',"
1766                          "'rombar': 0,"
1767                          "'romfile': '',"
1768                          "'mac': '"MAC_PRIMARY1"'}");
1769 
1770     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1771     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1772     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1773     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1774 
1775     args = qdict_from_jsonf_nofail("{}");
1776     g_assert_nonnull(args);
1777     qdict_put_str(args, "uri", uri);
1778 
1779     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1780                      args);
1781     g_assert(qdict_haskey(resp, "return"));
1782     qobject_unref(resp);
1783 
1784     resp = get_migration_event(qts);
1785     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1786     qobject_unref(resp);
1787 
1788     resp = get_failover_negociated_event(qts);
1789     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1790     qobject_unref(resp);
1791 
1792     resp = get_failover_negociated_event(qts);
1793     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1794     qobject_unref(resp);
1795 
1796     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1797     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1798     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1799     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1800 
1801     qtest_qmp_eventwait(qts, "RESUME");
1802 
1803     ret = migrate_status(qts);
1804     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1805     qobject_unref(ret);
1806 
1807     machine_stop(qts);
1808 }
1809 
1810 int main(int argc, char **argv)
1811 {
1812     gchar *tmpfile;
1813     int ret;
1814 
1815     g_test_init(&argc, &argv, NULL);
1816 
1817     ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
1818     g_assert_true(ret >= 0);
1819     close(ret);
1820 
1821     /* parameters tests */
1822     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1823     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1824     qtest_add_func("failover-virtio-net/params/on", test_on);
1825     qtest_add_func("failover-virtio-net/params/on_mismatch",
1826                    test_on_mismatch);
1827     qtest_add_func("failover-virtio-net/params/off", test_off);
1828     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
1829     qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off);
1830 
1831     /* hotplug tests */
1832     qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1);
1833     qtest_add_func("failover-virtio-net/hotplug/1_reverse",
1834                    test_hotplug_1_reverse);
1835     qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2);
1836     qtest_add_func("failover-virtio-net/hotplug/2_reverse",
1837                    test_hotplug_2_reverse);
1838 
1839     /* migration tests */
1840     qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile,
1841                         test_migrate_out);
1842     qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile,
1843                         test_migrate_in);
1844     qtest_add_data_func("failover-virtio-net/migrate/off/out", tmpfile,
1845                         test_off_migrate_out);
1846     qtest_add_data_func("failover-virtio-net/migrate/off/in", tmpfile,
1847                         test_off_migrate_in);
1848     qtest_add_data_func("failover-virtio-net/migrate/off/abort", tmpfile,
1849                         test_migrate_off_abort);
1850     qtest_add_data_func("failover-virtio-net/migrate/guest_off/out", tmpfile,
1851                         test_guest_off_migrate_out);
1852     qtest_add_data_func("failover-virtio-net/migrate/guest_off/in", tmpfile,
1853                         test_guest_off_migrate_in);
1854     qtest_add_data_func("failover-virtio-net/migrate/guest_off/abort", tmpfile,
1855                         test_migrate_guest_off_abort);
1856     qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
1857                         tmpfile, test_migrate_abort_wait_unplug);
1858     qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
1859                         test_migrate_abort_active);
1860     if (g_test_slow()) {
1861         qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
1862                             tmpfile, test_migrate_abort_timeout);
1863     }
1864     qtest_add_data_func("failover-virtio-net/migrate/multi/out",
1865                         tmpfile, test_multi_out);
1866     qtest_add_data_func("failover-virtio-net/migrate/multi/in",
1867                    tmpfile, test_multi_in);
1868 
1869     ret = g_test_run();
1870 
1871     unlink(tmpfile);
1872     g_free(tmpfile);
1873 
1874     return ret;
1875 }
1876