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