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 ACPI_PCIHP_ADDR_ICH9    0x0cc0
22 #define PCI_EJ_BASE             0x0008
23 #define PCI_SEL_BASE            0x0010
24 
25 #define BASE_MACHINE "-M q35 -nodefaults " \
26     "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
27     "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "
28 
29 #define MAC_PRIMARY0 "52:54:00:11:11:11"
30 #define MAC_STANDBY0 "52:54:00:22:22:22"
31 #define MAC_PRIMARY1 "52:54:00:33:33:33"
32 #define MAC_STANDBY1 "52:54:00:44:44:44"
33 
34 static QGuestAllocator guest_malloc;
35 static QPCIBus *pcibus;
36 
37 static QTestState *machine_start(const char *args, int numbus)
38 {
39     QTestState *qts;
40     QPCIDevice *dev;
41     int bus;
42 
43     qts = qtest_init(args);
44 
45     pc_alloc_init(&guest_malloc, qts, 0);
46     pcibus = qpci_new_pc(qts, &guest_malloc);
47     g_assert(qpci_secondary_buses_init(pcibus) == numbus);
48 
49     for (bus = 1; bus <= numbus; bus++) {
50         dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0));
51         g_assert_nonnull(dev);
52 
53         qpci_device_enable(dev);
54         qpci_iomap(dev, 4, NULL);
55 
56         g_free(dev);
57     }
58 
59     return qts;
60 }
61 
62 static void machine_stop(QTestState *qts)
63 {
64     qpci_free_pc(pcibus);
65     alloc_destroy(&guest_malloc);
66     qtest_quit(qts);
67 }
68 
69 static void test_error_id(void)
70 {
71     QTestState *qts;
72     QDict *resp;
73     QDict *err;
74 
75     qts = machine_start(BASE_MACHINE
76                         "-device virtio-net,bus=root0,id=standby0,failover=on",
77                         2);
78 
79     resp = qtest_qmp(qts, "{'execute': 'device_add',"
80                           "'arguments': {"
81                           "'driver': 'virtio-net',"
82                           "'bus': 'root1',"
83                           "'failover_pair_id': 'standby0'"
84                           "} }");
85     g_assert(qdict_haskey(resp, "error"));
86 
87     err = qdict_get_qdict(resp, "error");
88     g_assert(qdict_haskey(err, "desc"));
89 
90     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
91                     "Device with failover_pair_id needs to have id");
92 
93     qobject_unref(resp);
94 
95     machine_stop(qts);
96 }
97 
98 static void test_error_pcie(void)
99 {
100     QTestState *qts;
101     QDict *resp;
102     QDict *err;
103 
104     qts = machine_start(BASE_MACHINE
105                         "-device virtio-net,bus=root0,id=standby0,failover=on",
106                         2);
107 
108     resp = qtest_qmp(qts, "{'execute': 'device_add',"
109                           "'arguments': {"
110                           "'driver': 'virtio-net',"
111                           "'id': 'primary0',"
112                           "'bus': 'pcie.0',"
113                           "'failover_pair_id': 'standby0'"
114                           "} }");
115     g_assert(qdict_haskey(resp, "error"));
116 
117     err = qdict_get_qdict(resp, "error");
118     g_assert(qdict_haskey(err, "desc"));
119 
120     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
121                     "Bus 'pcie.0' does not support hotplugging");
122 
123     qobject_unref(resp);
124 
125     machine_stop(qts);
126 }
127 
128 static QDict *find_device(QDict *bus, const char *name)
129 {
130     const QObject *obj;
131     QList *devices;
132     QList *list;
133 
134     devices = qdict_get_qlist(bus, "devices");
135     if (devices == NULL) {
136         return NULL;
137     }
138 
139     list = qlist_copy(devices);
140     while ((obj = qlist_pop(list))) {
141         QDict *device;
142 
143         device = qobject_to(QDict, obj);
144 
145         if (qdict_haskey(device, "pci_bridge")) {
146             QDict *bridge;
147             QDict *bridge_device;
148 
149             bridge = qdict_get_qdict(device, "pci_bridge");
150 
151             if (qdict_haskey(bridge, "devices")) {
152                 bridge_device = find_device(bridge, name);
153                 if (bridge_device) {
154                     qobject_unref(device);
155                     qobject_unref(list);
156                     return bridge_device;
157                 }
158             }
159         }
160 
161         if (!qdict_haskey(device, "qdev_id")) {
162             qobject_unref(device);
163             continue;
164         }
165 
166         if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) {
167             qobject_unref(list);
168             return device;
169         }
170         qobject_unref(device);
171     }
172     qobject_unref(list);
173 
174     return NULL;
175 }
176 
177 static QDict *get_bus(QTestState *qts, int num)
178 {
179     QObject *obj;
180     QDict *resp;
181     QList *ret;
182 
183     resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }");
184     g_assert(qdict_haskey(resp, "return"));
185 
186     ret = qdict_get_qlist(resp, "return");
187     g_assert_nonnull(ret);
188 
189     while ((obj = qlist_pop(ret))) {
190         QDict *bus;
191 
192         bus = qobject_to(QDict, obj);
193         if (!qdict_haskey(bus, "bus")) {
194             qobject_unref(bus);
195             continue;
196         }
197         if (qdict_get_int(bus, "bus") == num) {
198             qobject_unref(resp);
199             return bus;
200         }
201         qobject_ref(bus);
202     }
203     qobject_unref(resp);
204 
205     return NULL;
206 }
207 
208 static char *get_mac(QTestState *qts, const char *name)
209 {
210     QDict *resp;
211     char *mac;
212 
213     resp = qtest_qmp(qts, "{ 'execute': 'qom-get', "
214                      "'arguments': { "
215                      "'path': %s, "
216                      "'property': 'mac' } }", name);
217 
218     g_assert(qdict_haskey(resp, "return"));
219 
220     mac = g_strdup(qdict_get_str(resp, "return"));
221 
222     qobject_unref(resp);
223 
224     return mac;
225 }
226 
227 static void check_one_card(QTestState *qts, bool present,
228                            const char *id, const char *mac)
229 {
230     QDict *device;
231     QDict *bus;
232     char *addr;
233 
234     bus = get_bus(qts, 0);
235     device = find_device(bus, id);
236     if (present) {
237         char *path;
238 
239         g_assert_nonnull(device);
240         qobject_unref(device);
241 
242         path = g_strdup_printf("/machine/peripheral/%s", id);
243         addr = get_mac(qts, path);
244         g_free(path);
245         g_assert_cmpstr(mac, ==, addr);
246         g_free(addr);
247     } else {
248        g_assert_null(device);
249     }
250 
251     qobject_unref(bus);
252 }
253 
254 static void test_on(void)
255 {
256     QTestState *qts;
257 
258     qts = machine_start(BASE_MACHINE
259                         "-netdev user,id=hs0 "
260                         "-device virtio-net,bus=root0,id=standby0,"
261                         "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
262                         "-device virtio-net,bus=root1,id=primary0,"
263                         "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
264                         2);
265 
266     check_one_card(qts, true, "standby0", MAC_STANDBY0);
267     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
268 
269     machine_stop(qts);
270 }
271 
272 static void test_on_mismatch(void)
273 {
274     QTestState *qts;
275 
276     qts = machine_start(BASE_MACHINE
277                      "-netdev user,id=hs0 "
278                      "-device virtio-net,bus=root0,id=standby0,"
279                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
280                      "-netdev user,id=hs1 "
281                      "-device virtio-net,bus=root1,id=primary0,"
282                      "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0,
283                      2);
284 
285     check_one_card(qts, true, "standby0", MAC_STANDBY0);
286     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
287 
288     machine_stop(qts);
289 }
290 
291 static void test_off(void)
292 {
293     QTestState *qts;
294 
295     qts = machine_start(BASE_MACHINE
296                      "-netdev user,id=hs0 "
297                      "-device virtio-net,bus=root0,id=standby0,"
298                      "failover=off,netdev=hs0,mac="MAC_STANDBY0" "
299                      "-netdev user,id=hs1 "
300                      "-device virtio-net,bus=root1,id=primary0,"
301                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
302                      2);
303 
304     check_one_card(qts, true, "standby0", MAC_STANDBY0);
305     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
306 
307     machine_stop(qts);
308 }
309 
310 static QDict *get_failover_negociated_event(QTestState *qts)
311 {
312     QDict *resp;
313     QDict *data;
314 
315     resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED");
316     g_assert(qdict_haskey(resp, "data"));
317 
318     data = qdict_get_qdict(resp, "data");
319     g_assert(qdict_haskey(data, "device-id"));
320     qobject_ref(data);
321     qobject_unref(resp);
322 
323     return data;
324 }
325 
326 static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
327                              const char *id)
328 {
329     QVirtioPCIDevice *dev;
330     uint64_t features;
331     QPCIAddress addr;
332     QDict *resp;
333 
334     addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0);
335     dev = virtio_pci_new(pcibus, &addr);
336     g_assert_nonnull(dev);
337     qvirtio_pci_device_enable(dev);
338     qvirtio_start_device(&dev->vdev);
339     features = qvirtio_get_features(&dev->vdev);
340     features = features & ~(QVIRTIO_F_BAD_FEATURE |
341                             (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
342                             (1ull << VIRTIO_RING_F_EVENT_IDX));
343     qvirtio_set_features(&dev->vdev, features);
344     qvirtio_set_driver_ok(&dev->vdev);
345 
346     resp = get_failover_negociated_event(qts);
347     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
348     qobject_unref(resp);
349 
350     return dev;
351 }
352 
353 static void test_enabled(void)
354 {
355     QTestState *qts;
356     QVirtioPCIDevice *vdev;
357 
358     qts = machine_start(BASE_MACHINE
359                      "-netdev user,id=hs0 "
360                      "-device virtio-net,bus=root0,id=standby0,"
361                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
362                      "-netdev user,id=hs1 "
363                      "-device virtio-net,bus=root1,id=primary0,"
364                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
365                      2);
366 
367     check_one_card(qts, true, "standby0", MAC_STANDBY0);
368     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
369 
370     vdev = start_virtio_net(qts, 1, 0, "standby0");
371 
372     check_one_card(qts, true, "standby0", MAC_STANDBY0);
373     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
374 
375     qos_object_destroy((QOSGraphObject *)vdev);
376     machine_stop(qts);
377 }
378 
379 static void test_hotplug_1(void)
380 {
381     QTestState *qts;
382     QVirtioPCIDevice *vdev;
383 
384     qts = machine_start(BASE_MACHINE
385                      "-netdev user,id=hs0 "
386                      "-device virtio-net,bus=root0,id=standby0,"
387                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
388                      "-netdev user,id=hs1 ", 2);
389 
390     check_one_card(qts, true, "standby0", MAC_STANDBY0);
391     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
392 
393     vdev = start_virtio_net(qts, 1, 0, "standby0");
394 
395     check_one_card(qts, true, "standby0", MAC_STANDBY0);
396     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
397 
398     qtest_qmp_device_add(qts, "virtio-net", "primary0",
399                          "{'bus': 'root1',"
400                          "'failover_pair_id': 'standby0',"
401                          "'netdev': 'hs1',"
402                          "'mac': '"MAC_PRIMARY0"'}");
403 
404     check_one_card(qts, true, "standby0", MAC_STANDBY0);
405     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
406 
407     qos_object_destroy((QOSGraphObject *)vdev);
408     machine_stop(qts);
409 }
410 
411 static void test_hotplug_1_reverse(void)
412 {
413     QTestState *qts;
414     QVirtioPCIDevice *vdev;
415 
416     qts = machine_start(BASE_MACHINE
417                      "-netdev user,id=hs0 "
418                      "-netdev user,id=hs1 "
419                      "-device virtio-net,bus=root1,id=primary0,"
420                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
421                      2);
422 
423     check_one_card(qts, false, "standby0", MAC_STANDBY0);
424     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
425 
426     qtest_qmp_device_add(qts, "virtio-net", "standby0",
427                          "{'bus': 'root0',"
428                          "'failover': 'on',"
429                          "'netdev': 'hs0',"
430                          "'mac': '"MAC_STANDBY0"'}");
431 
432     check_one_card(qts, true, "standby0", MAC_STANDBY0);
433     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
434 
435     vdev = start_virtio_net(qts, 1, 0, "standby0");
436 
437     check_one_card(qts, true, "standby0", MAC_STANDBY0);
438     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
439 
440     qos_object_destroy((QOSGraphObject *)vdev);
441     machine_stop(qts);
442 }
443 
444 static void test_hotplug_2(void)
445 {
446     QTestState *qts;
447     QVirtioPCIDevice *vdev;
448 
449     qts = machine_start(BASE_MACHINE
450                      "-netdev user,id=hs0 "
451                      "-netdev user,id=hs1 ",
452                      2);
453 
454     check_one_card(qts, false, "standby0", MAC_STANDBY0);
455     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
456 
457     qtest_qmp_device_add(qts, "virtio-net", "standby0",
458                          "{'bus': 'root0',"
459                          "'failover': 'on',"
460                          "'netdev': 'hs0',"
461                          "'mac': '"MAC_STANDBY0"'}");
462 
463     check_one_card(qts, true, "standby0", MAC_STANDBY0);
464     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
465 
466     vdev = start_virtio_net(qts, 1, 0, "standby0");
467 
468     check_one_card(qts, true, "standby0", MAC_STANDBY0);
469     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
470 
471     qtest_qmp_device_add(qts, "virtio-net", "primary0",
472                          "{'bus': 'root1',"
473                          "'failover_pair_id': 'standby0',"
474                          "'netdev': 'hs1',"
475                          "'mac': '"MAC_PRIMARY0"'}");
476 
477     check_one_card(qts, true, "standby0", MAC_STANDBY0);
478     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
479 
480     qos_object_destroy((QOSGraphObject *)vdev);
481     machine_stop(qts);
482 }
483 
484 static void test_hotplug_2_reverse(void)
485 {
486     QTestState *qts;
487     QVirtioPCIDevice *vdev;
488 
489     qts = machine_start(BASE_MACHINE
490                      "-netdev user,id=hs0 "
491                      "-netdev user,id=hs1 ",
492                      2);
493 
494     check_one_card(qts, false, "standby0", MAC_STANDBY0);
495     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
496 
497     qtest_qmp_device_add(qts, "virtio-net", "primary0",
498                          "{'bus': 'root1',"
499                          "'failover_pair_id': 'standby0',"
500                          "'netdev': 'hs1',"
501                          "'mac': '"MAC_PRIMARY0"'}");
502 
503     check_one_card(qts, false, "standby0", MAC_STANDBY0);
504     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
505 
506     qtest_qmp_device_add(qts, "virtio-net", "standby0",
507                          "{'bus': 'root0',"
508                          "'failover': 'on',"
509                          "'netdev': 'hs0',"
510                          "'rombar': 0,"
511                          "'romfile': '',"
512                          "'mac': '"MAC_STANDBY0"'}");
513 
514     /*
515      * XXX: sounds like a bug:
516      * The primary should be hidden until the virtio-net driver
517      * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
518      */
519     check_one_card(qts, true, "standby0", MAC_STANDBY0);
520     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
521 
522     vdev = start_virtio_net(qts, 1, 0, "standby0");
523 
524     check_one_card(qts, true, "standby0", MAC_STANDBY0);
525     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
526 
527     qos_object_destroy((QOSGraphObject *)vdev);
528     machine_stop(qts);
529 }
530 
531 static QDict *migrate_status(QTestState *qts)
532 {
533     QDict *resp, *ret;
534 
535     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
536     g_assert(qdict_haskey(resp, "return"));
537 
538     ret = qdict_get_qdict(resp, "return");
539     g_assert(qdict_haskey(ret, "status"));
540     qobject_ref(ret);
541     qobject_unref(resp);
542 
543     return ret;
544 }
545 
546 static QDict *get_unplug_primary_event(QTestState *qts)
547 {
548     QDict *resp;
549     QDict *data;
550 
551     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
552     g_assert(qdict_haskey(resp, "data"));
553 
554     data = qdict_get_qdict(resp, "data");
555     g_assert(qdict_haskey(data, "device-id"));
556     qobject_ref(data);
557     qobject_unref(resp);
558 
559     return data;
560 }
561 
562 static void test_migrate_out(gconstpointer opaque)
563 {
564     QTestState *qts;
565     QDict *resp, *args, *ret;
566     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
567     const gchar *status;
568     QVirtioPCIDevice *vdev;
569 
570     qts = machine_start(BASE_MACHINE
571                      "-netdev user,id=hs0 "
572                      "-netdev user,id=hs1 ",
573                      2);
574 
575     check_one_card(qts, false, "standby0", MAC_STANDBY0);
576     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
577 
578     qtest_qmp_device_add(qts, "virtio-net", "standby0",
579                          "{'bus': 'root0',"
580                          "'failover': 'on',"
581                          "'netdev': 'hs0',"
582                          "'mac': '"MAC_STANDBY0"'}");
583 
584     check_one_card(qts, true, "standby0", MAC_STANDBY0);
585     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
586 
587     vdev = start_virtio_net(qts, 1, 0, "standby0");
588 
589     check_one_card(qts, true, "standby0", MAC_STANDBY0);
590     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
591 
592     qtest_qmp_device_add(qts, "virtio-net", "primary0",
593                          "{'bus': 'root1',"
594                          "'failover_pair_id': 'standby0',"
595                          "'netdev': 'hs1',"
596                          "'rombar': 0,"
597                          "'romfile': '',"
598                          "'mac': '"MAC_PRIMARY0"'}");
599 
600     check_one_card(qts, true, "standby0", MAC_STANDBY0);
601     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
602 
603     args = qdict_from_jsonf_nofail("{}");
604     g_assert_nonnull(args);
605     qdict_put_str(args, "uri", uri);
606 
607     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
608     g_assert(qdict_haskey(resp, "return"));
609     qobject_unref(resp);
610 
611     /* the event is sent when QEMU asks the OS to unplug the card */
612     resp = get_unplug_primary_event(qts);
613     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
614     qobject_unref(resp);
615 
616     /* wait the end of the migration setup phase */
617     while (true) {
618         ret = migrate_status(qts);
619 
620         status = qdict_get_str(ret, "status");
621         if (strcmp(status, "wait-unplug") == 0) {
622             qobject_unref(ret);
623             break;
624         }
625 
626         /* The migration must not start if the card is not ejected */
627         g_assert_cmpstr(status, !=, "active");
628         g_assert_cmpstr(status, !=, "completed");
629         g_assert_cmpstr(status, !=, "failed");
630         g_assert_cmpstr(status, !=, "cancelling");
631         g_assert_cmpstr(status, !=, "cancelled");
632 
633         qobject_unref(ret);
634     }
635 
636     if (g_test_slow()) {
637         /* check we stay in wait-unplug while the card is not ejected */
638         for (int i = 0; i < 5; i++) {
639             sleep(1);
640             ret = migrate_status(qts);
641             status = qdict_get_str(ret, "status");
642             g_assert_cmpstr(status, ==, "wait-unplug");
643             qobject_unref(ret);
644         }
645     }
646 
647     /* OS unplugs the cards, QEMU can move from wait-unplug state */
648     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
649 
650     while (true) {
651         ret = migrate_status(qts);
652 
653         status = qdict_get_str(ret, "status");
654         if (strcmp(status, "completed") == 0) {
655             qobject_unref(ret);
656             break;
657         }
658         g_assert_cmpstr(status, !=, "failed");
659         g_assert_cmpstr(status, !=, "cancelling");
660         g_assert_cmpstr(status, !=, "cancelled");
661         qobject_unref(ret);
662     }
663 
664     qtest_qmp_eventwait(qts, "STOP");
665 
666     /*
667      * in fact, the card is ejected from the point of view of kernel
668      * but not really from QEMU to be able to hotplug it back if
669      * migration fails. So we can't check that:
670      *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
671      *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
672      */
673 
674     qos_object_destroy((QOSGraphObject *)vdev);
675     machine_stop(qts);
676 }
677 
678 static QDict *get_migration_event(QTestState *qts)
679 {
680     QDict *resp;
681     QDict *data;
682 
683     resp = qtest_qmp_eventwait_ref(qts, "MIGRATION");
684     g_assert(qdict_haskey(resp, "data"));
685 
686     data = qdict_get_qdict(resp, "data");
687     g_assert(qdict_haskey(data, "status"));
688     qobject_ref(data);
689     qobject_unref(resp);
690 
691     return data;
692 }
693 
694 static void test_migrate_in(gconstpointer opaque)
695 {
696     QTestState *qts;
697     QDict *resp, *args, *ret;
698     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
699 
700     qts = machine_start(BASE_MACHINE
701                      "-netdev user,id=hs0 "
702                      "-netdev user,id=hs1 "
703                      "-incoming defer ",
704                      2);
705 
706     check_one_card(qts, false, "standby0", MAC_STANDBY0);
707     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
708 
709     qtest_qmp_device_add(qts, "virtio-net", "standby0",
710                          "{'bus': 'root0',"
711                          "'failover': 'on',"
712                          "'netdev': 'hs0',"
713                          "'mac': '"MAC_STANDBY0"'}");
714 
715     check_one_card(qts, true, "standby0", MAC_STANDBY0);
716     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
717 
718     qtest_qmp_device_add(qts, "virtio-net", "primary0",
719                          "{'bus': 'root1',"
720                          "'failover_pair_id': 'standby0',"
721                          "'netdev': 'hs1',"
722                          "'rombar': 0,"
723                          "'romfile': '',"
724                          "'mac': '"MAC_PRIMARY0"'}");
725 
726     check_one_card(qts, true, "standby0", MAC_STANDBY0);
727     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
728 
729     args = qdict_from_jsonf_nofail("{}");
730     g_assert_nonnull(args);
731     qdict_put_str(args, "uri", uri);
732 
733     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
734                      args);
735     g_assert(qdict_haskey(resp, "return"));
736     qobject_unref(resp);
737 
738     resp = get_migration_event(qts);
739     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
740     qobject_unref(resp);
741 
742     resp = get_failover_negociated_event(qts);
743     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
744     qobject_unref(resp);
745 
746     check_one_card(qts, true, "standby0", MAC_STANDBY0);
747     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
748 
749     qtest_qmp_eventwait(qts, "RESUME");
750 
751     ret = migrate_status(qts);
752     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
753     qobject_unref(ret);
754 
755     machine_stop(qts);
756 }
757 
758 static void test_migrate_abort_wait_unplug(gconstpointer opaque)
759 {
760     QTestState *qts;
761     QDict *resp, *args, *ret;
762     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
763     const gchar *status;
764     QVirtioPCIDevice *vdev;
765 
766     qts = machine_start(BASE_MACHINE
767                      "-netdev user,id=hs0 "
768                      "-netdev user,id=hs1 ",
769                      2);
770 
771     check_one_card(qts, false, "standby0", MAC_STANDBY0);
772     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
773 
774     qtest_qmp_device_add(qts, "virtio-net", "standby0",
775                          "{'bus': 'root0',"
776                          "'failover': 'on',"
777                          "'netdev': 'hs0',"
778                          "'mac': '"MAC_STANDBY0"'}");
779 
780     check_one_card(qts, true, "standby0", MAC_STANDBY0);
781     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
782 
783     vdev = start_virtio_net(qts, 1, 0, "standby0");
784 
785     check_one_card(qts, true, "standby0", MAC_STANDBY0);
786     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
787 
788     qtest_qmp_device_add(qts, "virtio-net", "primary0",
789                          "{'bus': 'root1',"
790                          "'failover_pair_id': 'standby0',"
791                          "'netdev': 'hs1',"
792                          "'rombar': 0,"
793                          "'romfile': '',"
794                          "'mac': '"MAC_PRIMARY0"'}");
795 
796     check_one_card(qts, true, "standby0", MAC_STANDBY0);
797     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
798 
799     args = qdict_from_jsonf_nofail("{}");
800     g_assert_nonnull(args);
801     qdict_put_str(args, "uri", uri);
802 
803     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
804     g_assert(qdict_haskey(resp, "return"));
805     qobject_unref(resp);
806 
807     /* the event is sent when QEMU asks the OS to unplug the card */
808     resp = get_unplug_primary_event(qts);
809     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
810     qobject_unref(resp);
811 
812     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
813     g_assert(qdict_haskey(resp, "return"));
814     qobject_unref(resp);
815 
816     /* migration has been cancelled while the unplug was in progress */
817 
818     /* while the card is not ejected, we must be in "cancelling" state */
819     ret = migrate_status(qts);
820 
821     status = qdict_get_str(ret, "status");
822     g_assert_cmpstr(status, ==, "cancelling");
823     qobject_unref(ret);
824 
825     /* OS unplugs the cards, QEMU can move from wait-unplug state */
826     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
827 
828     while (true) {
829         ret = migrate_status(qts);
830 
831         status = qdict_get_str(ret, "status");
832         if (strcmp(status, "cancelled") == 0) {
833             qobject_unref(ret);
834             break;
835         }
836         g_assert_cmpstr(status, !=, "failed");
837         g_assert_cmpstr(status, !=, "active");
838         qobject_unref(ret);
839     }
840 
841     check_one_card(qts, true, "standby0", MAC_STANDBY0);
842     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
843 
844     qos_object_destroy((QOSGraphObject *)vdev);
845     machine_stop(qts);
846 }
847 
848 static void test_migrate_abort_active(gconstpointer opaque)
849 {
850     QTestState *qts;
851     QDict *resp, *args, *ret;
852     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
853     const gchar *status;
854     QVirtioPCIDevice *vdev;
855 
856     qts = machine_start(BASE_MACHINE
857                      "-netdev user,id=hs0 "
858                      "-netdev user,id=hs1 ",
859                      2);
860 
861     check_one_card(qts, false, "standby0", MAC_STANDBY0);
862     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
863 
864     qtest_qmp_device_add(qts, "virtio-net", "standby0",
865                          "{'bus': 'root0',"
866                          "'failover': 'on',"
867                          "'netdev': 'hs0',"
868                          "'mac': '"MAC_STANDBY0"'}");
869 
870     check_one_card(qts, true, "standby0", MAC_STANDBY0);
871     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
872 
873     vdev = start_virtio_net(qts, 1, 0, "standby0");
874 
875     check_one_card(qts, true, "standby0", MAC_STANDBY0);
876     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
877 
878     qtest_qmp_device_add(qts, "virtio-net", "primary0",
879                          "{'bus': 'root1',"
880                          "'failover_pair_id': 'standby0',"
881                          "'netdev': 'hs1',"
882                          "'rombar': 0,"
883                          "'romfile': '',"
884                          "'mac': '"MAC_PRIMARY0"'}");
885 
886     check_one_card(qts, true, "standby0", MAC_STANDBY0);
887     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
888 
889     args = qdict_from_jsonf_nofail("{}");
890     g_assert_nonnull(args);
891     qdict_put_str(args, "uri", uri);
892 
893     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
894     g_assert(qdict_haskey(resp, "return"));
895     qobject_unref(resp);
896 
897     /* the event is sent when QEMU asks the OS to unplug the card */
898     resp = get_unplug_primary_event(qts);
899     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
900     qobject_unref(resp);
901 
902     /* OS unplugs the cards, QEMU can move from wait-unplug state */
903     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
904 
905     while (true) {
906         ret = migrate_status(qts);
907 
908         status = qdict_get_str(ret, "status");
909         if (strcmp(status, "wait-unplug") != 0) {
910             qobject_unref(ret);
911             break;
912         }
913         g_assert_cmpstr(status, !=, "failed");
914         qobject_unref(ret);
915     }
916 
917     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
918     g_assert(qdict_haskey(resp, "return"));
919     qobject_unref(resp);
920 
921     while (true) {
922         ret = migrate_status(qts);
923 
924         status = qdict_get_str(ret, "status");
925         if (strcmp(status, "cancelled") == 0) {
926             qobject_unref(ret);
927             break;
928         }
929         g_assert_cmpstr(status, !=, "failed");
930         g_assert_cmpstr(status, !=, "active");
931         qobject_unref(ret);
932     }
933 
934     check_one_card(qts, true, "standby0", MAC_STANDBY0);
935     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
936 
937     qos_object_destroy((QOSGraphObject *)vdev);
938     machine_stop(qts);
939 }
940 
941 static void test_migrate_abort_timeout(gconstpointer opaque)
942 {
943     QTestState *qts;
944     QDict *resp, *args, *ret;
945     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
946     const gchar *status;
947     int total;
948     QVirtioPCIDevice *vdev;
949 
950     qts = machine_start(BASE_MACHINE
951                      "-netdev user,id=hs0 "
952                      "-netdev user,id=hs1 ",
953                      2);
954 
955     check_one_card(qts, false, "standby0", MAC_STANDBY0);
956     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
957 
958     qtest_qmp_device_add(qts, "virtio-net", "standby0",
959                          "{'bus': 'root0',"
960                          "'failover': 'on',"
961                          "'netdev': 'hs0',"
962                          "'mac': '"MAC_STANDBY0"'}");
963 
964     check_one_card(qts, true, "standby0", MAC_STANDBY0);
965     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
966 
967     vdev = start_virtio_net(qts, 1, 0, "standby0");
968 
969     check_one_card(qts, true, "standby0", MAC_STANDBY0);
970     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
971 
972     qtest_qmp_device_add(qts, "virtio-net", "primary0",
973                          "{'bus': 'root1',"
974                          "'failover_pair_id': 'standby0',"
975                          "'netdev': 'hs1',"
976                          "'rombar': 0,"
977                          "'romfile': '',"
978                          "'mac': '"MAC_PRIMARY0"'}");
979 
980     check_one_card(qts, true, "standby0", MAC_STANDBY0);
981     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
982 
983     args = qdict_from_jsonf_nofail("{}");
984     g_assert_nonnull(args);
985     qdict_put_str(args, "uri", uri);
986 
987     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
988     g_assert(qdict_haskey(resp, "return"));
989     qobject_unref(resp);
990 
991     /* the event is sent when QEMU asks the OS to unplug the card */
992     resp = get_unplug_primary_event(qts);
993     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
994     qobject_unref(resp);
995 
996     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
997     g_assert(qdict_haskey(resp, "return"));
998     qobject_unref(resp);
999 
1000     /* migration has been cancelled while the unplug was in progress */
1001 
1002     /* while the card is not ejected, we must be in "cancelling" state */
1003 
1004     total = 0;
1005     while (true) {
1006         ret = migrate_status(qts);
1007 
1008         status = qdict_get_str(ret, "status");
1009         if (strcmp(status, "cancelled") == 0) {
1010             qobject_unref(ret);
1011             break;
1012         }
1013         g_assert_cmpstr(status, ==, "cancelling");
1014         g_assert(qdict_haskey(ret, "total-time"));
1015         total = qdict_get_int(ret, "total-time");
1016         qobject_unref(ret);
1017     }
1018 
1019     /*
1020      * migration timeout in this case is 30 seconds
1021      * check we exit on the timeout (ms)
1022      */
1023     g_assert_cmpint(total, >, 30000);
1024 
1025     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1026     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1027 
1028     qos_object_destroy((QOSGraphObject *)vdev);
1029     machine_stop(qts);
1030 }
1031 
1032 static void test_multi_out(gconstpointer opaque)
1033 {
1034     QTestState *qts;
1035     QDict *resp, *args, *ret;
1036     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1037     const gchar *status, *expected;
1038     QVirtioPCIDevice *vdev0, *vdev1;
1039 
1040     qts = machine_start(BASE_MACHINE
1041                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1042                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1043                 "-netdev user,id=hs0 "
1044                 "-netdev user,id=hs1 "
1045                 "-netdev user,id=hs2 "
1046                 "-netdev user,id=hs3 ",
1047                 4);
1048 
1049     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1050     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1051     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1052     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1053 
1054     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1055                          "{'bus': 'root0',"
1056                          "'failover': 'on',"
1057                          "'netdev': 'hs0',"
1058                          "'mac': '"MAC_STANDBY0"'}");
1059 
1060     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1061     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1062     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1063     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1064 
1065     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1066                          "{'bus': 'root1',"
1067                          "'failover_pair_id': 'standby0',"
1068                          "'netdev': 'hs1',"
1069                          "'rombar': 0,"
1070                          "'romfile': '',"
1071                          "'mac': '"MAC_PRIMARY0"'}");
1072 
1073     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1074     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1075     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1076     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1077 
1078     vdev0 = start_virtio_net(qts, 1, 0, "standby0");
1079 
1080     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1081     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1082     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1083     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1084 
1085     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1086                          "{'bus': 'root2',"
1087                          "'failover': 'on',"
1088                          "'netdev': 'hs2',"
1089                          "'mac': '"MAC_STANDBY1"'}");
1090 
1091     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1092     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1093     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1094     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1095 
1096     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1097                          "{'bus': 'root3',"
1098                          "'failover_pair_id': 'standby1',"
1099                          "'netdev': 'hs3',"
1100                          "'rombar': 0,"
1101                          "'romfile': '',"
1102                          "'mac': '"MAC_PRIMARY1"'}");
1103 
1104     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1105     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1106     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1107     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1108 
1109     vdev1 = start_virtio_net(qts, 3, 0, "standby1");
1110 
1111     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1112     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1113     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1114     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1115 
1116     args = qdict_from_jsonf_nofail("{}");
1117     g_assert_nonnull(args);
1118     qdict_put_str(args, "uri", uri);
1119 
1120     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1121     g_assert(qdict_haskey(resp, "return"));
1122     qobject_unref(resp);
1123 
1124     /* the event is sent when QEMU asks the OS to unplug the card */
1125     resp = get_unplug_primary_event(qts);
1126     if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
1127         expected = "primary1";
1128     } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
1129         expected = "primary0";
1130     } else {
1131         g_assert_not_reached();
1132     }
1133     qobject_unref(resp);
1134 
1135     resp = get_unplug_primary_event(qts);
1136     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1137     qobject_unref(resp);
1138 
1139     /* wait the end of the migration setup phase */
1140     while (true) {
1141         ret = migrate_status(qts);
1142 
1143         status = qdict_get_str(ret, "status");
1144         if (strcmp(status, "wait-unplug") == 0) {
1145             qobject_unref(ret);
1146             break;
1147         }
1148 
1149         /* The migration must not start if the card is not ejected */
1150         g_assert_cmpstr(status, !=, "active");
1151         g_assert_cmpstr(status, !=, "completed");
1152         g_assert_cmpstr(status, !=, "failed");
1153         g_assert_cmpstr(status, !=, "cancelling");
1154         g_assert_cmpstr(status, !=, "cancelled");
1155 
1156         qobject_unref(ret);
1157     }
1158 
1159     /* OS unplugs primary1, but we must wait the second */
1160     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1161 
1162     ret = migrate_status(qts);
1163     status = qdict_get_str(ret, "status");
1164     g_assert_cmpstr(status, ==, "wait-unplug");
1165     qobject_unref(ret);
1166 
1167     if (g_test_slow()) {
1168         /* check we stay in wait-unplug while the card is not ejected */
1169         for (int i = 0; i < 5; i++) {
1170             sleep(1);
1171             ret = migrate_status(qts);
1172             status = qdict_get_str(ret, "status");
1173             g_assert_cmpstr(status, ==, "wait-unplug");
1174             qobject_unref(ret);
1175         }
1176     }
1177 
1178     /* OS unplugs primary0, QEMU can move from wait-unplug state */
1179     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
1180     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1181 
1182     while (true) {
1183         ret = migrate_status(qts);
1184 
1185         status = qdict_get_str(ret, "status");
1186         if (strcmp(status, "completed") == 0) {
1187             qobject_unref(ret);
1188             break;
1189         }
1190         g_assert_cmpstr(status, !=, "failed");
1191         g_assert_cmpstr(status, !=, "cancelling");
1192         g_assert_cmpstr(status, !=, "cancelled");
1193         qobject_unref(ret);
1194     }
1195 
1196     qtest_qmp_eventwait(qts, "STOP");
1197 
1198     qos_object_destroy((QOSGraphObject *)vdev0);
1199     qos_object_destroy((QOSGraphObject *)vdev1);
1200     machine_stop(qts);
1201 }
1202 
1203 static void test_multi_in(gconstpointer opaque)
1204 {
1205     QTestState *qts;
1206     QDict *resp, *args, *ret;
1207     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1208 
1209     qts = machine_start(BASE_MACHINE
1210                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1211                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1212                 "-netdev user,id=hs0 "
1213                 "-netdev user,id=hs1 "
1214                 "-netdev user,id=hs2 "
1215                 "-netdev user,id=hs3 "
1216                 "-incoming defer ",
1217                 4);
1218 
1219     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1220     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1221     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1222     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1223 
1224     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1225                          "{'bus': 'root0',"
1226                          "'failover': 'on',"
1227                          "'netdev': 'hs0',"
1228                          "'mac': '"MAC_STANDBY0"'}");
1229 
1230     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1231     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1232     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1233     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1234 
1235     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1236                          "{'bus': 'root1',"
1237                          "'failover_pair_id': 'standby0',"
1238                          "'netdev': 'hs1',"
1239                          "'rombar': 0,"
1240                          "'romfile': '',"
1241                          "'mac': '"MAC_PRIMARY0"'}");
1242 
1243     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1244     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1245     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1246     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1247 
1248     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1249                          "{'bus': 'root2',"
1250                          "'failover': 'on',"
1251                          "'netdev': 'hs2',"
1252                          "'mac': '"MAC_STANDBY1"'}");
1253 
1254     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1255     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1256     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1257     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1258 
1259     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1260                          "{'bus': 'root3',"
1261                          "'failover_pair_id': 'standby1',"
1262                          "'netdev': 'hs3',"
1263                          "'rombar': 0,"
1264                          "'romfile': '',"
1265                          "'mac': '"MAC_PRIMARY1"'}");
1266 
1267     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1268     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1269     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1270     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1271 
1272     args = qdict_from_jsonf_nofail("{}");
1273     g_assert_nonnull(args);
1274     qdict_put_str(args, "uri", uri);
1275 
1276     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1277                      args);
1278     g_assert(qdict_haskey(resp, "return"));
1279     qobject_unref(resp);
1280 
1281     resp = get_migration_event(qts);
1282     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1283     qobject_unref(resp);
1284 
1285     resp = get_failover_negociated_event(qts);
1286     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1287     qobject_unref(resp);
1288 
1289     resp = get_failover_negociated_event(qts);
1290     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1291     qobject_unref(resp);
1292 
1293     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1294     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1295     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1296     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1297 
1298     qtest_qmp_eventwait(qts, "RESUME");
1299 
1300     ret = migrate_status(qts);
1301     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1302     qobject_unref(ret);
1303 
1304     machine_stop(qts);
1305 }
1306 
1307 int main(int argc, char **argv)
1308 {
1309     const gchar *tmpdir = g_get_tmp_dir();
1310     gchar *tmpfile = g_strdup_printf("%s/failover_test_migrate-%u-%u",
1311                                      tmpdir, getpid(), g_test_rand_int());
1312     int ret;
1313 
1314     g_test_init(&argc, &argv, NULL);
1315 
1316     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1317     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1318     qtest_add_func("failover-virtio-net/params/on", test_on);
1319     qtest_add_func("failover-virtio-net/params/on_mismatch",
1320                    test_on_mismatch);
1321     qtest_add_func("failover-virtio-net/params/off", test_off);
1322     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
1323     qtest_add_func("failover-virtio-net/hotplug_1", test_hotplug_1);
1324     qtest_add_func("failover-virtio-net/hotplug_1_reverse",
1325                    test_hotplug_1_reverse);
1326     qtest_add_func("failover-virtio-net/hotplug_2", test_hotplug_2);
1327     qtest_add_func("failover-virtio-net/hotplug_2_reverse",
1328                    test_hotplug_2_reverse);
1329     qtest_add_data_func("failover-virtio-net/migrate/out", tmpfile,
1330                         test_migrate_out);
1331     qtest_add_data_func("failover-virtio-net/migrate/in", tmpfile,
1332                         test_migrate_in);
1333     qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
1334                         tmpfile, test_migrate_abort_wait_unplug);
1335     qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
1336                         test_migrate_abort_active);
1337     if (g_test_slow()) {
1338         qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
1339                             tmpfile, test_migrate_abort_timeout);
1340     }
1341     qtest_add_data_func("failover-virtio-net/multi/out",
1342                         tmpfile, test_multi_out);
1343     qtest_add_data_func("failover-virtio-net/multi/in",
1344                    tmpfile, test_multi_in);
1345 
1346     ret = g_test_run();
1347 
1348     unlink(tmpfile);
1349     g_free(tmpfile);
1350 
1351     return ret;
1352 }
1353