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