xref: /qemu/tests/qtest/virtio-net-failover.c (revision e63ed64c6d10768b3a41c3337226372a9664ef6f)
1e32b96b5SLaurent Vivier /*
2e32b96b5SLaurent Vivier  * QTest testcase for virtio-net failover
3e32b96b5SLaurent Vivier  *
4e32b96b5SLaurent Vivier  * See docs/system/virtio-net-failover.rst
5e32b96b5SLaurent Vivier  *
6e32b96b5SLaurent Vivier  * Copyright (c) 2021 Red Hat, Inc.
7e32b96b5SLaurent Vivier  *
8e32b96b5SLaurent Vivier  * SPDX-License-Identifier: GPL-2.0-or-later
9e32b96b5SLaurent Vivier  */
10e32b96b5SLaurent Vivier #include "qemu/osdep.h"
11e32b96b5SLaurent Vivier #include "libqos/libqtest.h"
12e32b96b5SLaurent Vivier #include "libqos/pci.h"
13e32b96b5SLaurent Vivier #include "libqos/pci-pc.h"
14e32b96b5SLaurent Vivier #include "qapi/qmp/qdict.h"
15e32b96b5SLaurent Vivier #include "qapi/qmp/qlist.h"
16e32b96b5SLaurent Vivier #include "qapi/qmp/qjson.h"
17e32b96b5SLaurent Vivier #include "libqos/malloc-pc.h"
18e32b96b5SLaurent Vivier #include "libqos/virtio-pci.h"
19e32b96b5SLaurent Vivier #include "hw/pci/pci.h"
20e32b96b5SLaurent Vivier 
21e32b96b5SLaurent Vivier #define ACPI_PCIHP_ADDR_ICH9    0x0cc0
22e32b96b5SLaurent Vivier #define PCI_EJ_BASE             0x0008
23e1e3d321SLaurent Vivier #define PCI_SEL_BASE            0x0010
24e32b96b5SLaurent Vivier 
25e32b96b5SLaurent Vivier #define BASE_MACHINE "-M q35 -nodefaults " \
26e32b96b5SLaurent Vivier     "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
27e32b96b5SLaurent Vivier     "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "
28e32b96b5SLaurent Vivier 
29e32b96b5SLaurent Vivier #define MAC_PRIMARY0 "52:54:00:11:11:11"
30e32b96b5SLaurent Vivier #define MAC_STANDBY0 "52:54:00:22:22:22"
31e1e3d321SLaurent Vivier #define MAC_PRIMARY1 "52:54:00:33:33:33"
32e1e3d321SLaurent Vivier #define MAC_STANDBY1 "52:54:00:44:44:44"
33e32b96b5SLaurent Vivier 
34e32b96b5SLaurent Vivier static QGuestAllocator guest_malloc;
35e32b96b5SLaurent Vivier static QPCIBus *pcibus;
36e32b96b5SLaurent Vivier 
37e32b96b5SLaurent Vivier static QTestState *machine_start(const char *args, int numbus)
38e32b96b5SLaurent Vivier {
39e32b96b5SLaurent Vivier     QTestState *qts;
40e32b96b5SLaurent Vivier     QPCIDevice *dev;
41e32b96b5SLaurent Vivier     int bus;
42e32b96b5SLaurent Vivier 
43e32b96b5SLaurent Vivier     qts = qtest_init(args);
44e32b96b5SLaurent Vivier 
45e32b96b5SLaurent Vivier     pc_alloc_init(&guest_malloc, qts, 0);
46e32b96b5SLaurent Vivier     pcibus = qpci_new_pc(qts, &guest_malloc);
47e32b96b5SLaurent Vivier     g_assert(qpci_secondary_buses_init(pcibus) == numbus);
48e32b96b5SLaurent Vivier 
49e32b96b5SLaurent Vivier     for (bus = 1; bus <= numbus; bus++) {
50e32b96b5SLaurent Vivier         dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0));
51e32b96b5SLaurent Vivier         g_assert_nonnull(dev);
52e32b96b5SLaurent Vivier 
53e32b96b5SLaurent Vivier         qpci_device_enable(dev);
54e32b96b5SLaurent Vivier         qpci_iomap(dev, 4, NULL);
55e32b96b5SLaurent Vivier 
56e32b96b5SLaurent Vivier         g_free(dev);
57e32b96b5SLaurent Vivier     }
58e32b96b5SLaurent Vivier 
59e32b96b5SLaurent Vivier     return qts;
60e32b96b5SLaurent Vivier }
61e32b96b5SLaurent Vivier 
62e32b96b5SLaurent Vivier static void machine_stop(QTestState *qts)
63e32b96b5SLaurent Vivier {
64e32b96b5SLaurent Vivier     qpci_free_pc(pcibus);
65e32b96b5SLaurent Vivier     alloc_destroy(&guest_malloc);
66e32b96b5SLaurent Vivier     qtest_quit(qts);
67e32b96b5SLaurent Vivier }
68e32b96b5SLaurent Vivier 
69e32b96b5SLaurent Vivier static void test_error_id(void)
70e32b96b5SLaurent Vivier {
71e32b96b5SLaurent Vivier     QTestState *qts;
72e32b96b5SLaurent Vivier     QDict *resp;
73e32b96b5SLaurent Vivier     QDict *err;
74e32b96b5SLaurent Vivier 
75e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
76e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,failover=on",
77e32b96b5SLaurent Vivier                         2);
78e32b96b5SLaurent Vivier 
79e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{'execute': 'device_add',"
80e32b96b5SLaurent Vivier                           "'arguments': {"
81e32b96b5SLaurent Vivier                           "'driver': 'virtio-net',"
82e32b96b5SLaurent Vivier                           "'bus': 'root1',"
83e32b96b5SLaurent Vivier                           "'failover_pair_id': 'standby0'"
84e32b96b5SLaurent Vivier                           "} }");
85e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "error"));
86e32b96b5SLaurent Vivier 
87e32b96b5SLaurent Vivier     err = qdict_get_qdict(resp, "error");
88e32b96b5SLaurent Vivier     g_assert(qdict_haskey(err, "desc"));
89e32b96b5SLaurent Vivier 
90e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
91e32b96b5SLaurent Vivier                     "Device with failover_pair_id needs to have id");
92e32b96b5SLaurent Vivier 
93e32b96b5SLaurent Vivier     qobject_unref(resp);
94e32b96b5SLaurent Vivier 
95e32b96b5SLaurent Vivier     machine_stop(qts);
96e32b96b5SLaurent Vivier }
97e32b96b5SLaurent Vivier 
98e32b96b5SLaurent Vivier static void test_error_pcie(void)
99e32b96b5SLaurent Vivier {
100e32b96b5SLaurent Vivier     QTestState *qts;
101e32b96b5SLaurent Vivier     QDict *resp;
102e32b96b5SLaurent Vivier     QDict *err;
103e32b96b5SLaurent Vivier 
104e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
105e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,failover=on",
106e32b96b5SLaurent Vivier                         2);
107e32b96b5SLaurent Vivier 
108e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{'execute': 'device_add',"
109e32b96b5SLaurent Vivier                           "'arguments': {"
110e32b96b5SLaurent Vivier                           "'driver': 'virtio-net',"
111e32b96b5SLaurent Vivier                           "'id': 'primary0',"
112e32b96b5SLaurent Vivier                           "'bus': 'pcie.0',"
113e32b96b5SLaurent Vivier                           "'failover_pair_id': 'standby0'"
114e32b96b5SLaurent Vivier                           "} }");
115e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "error"));
116e32b96b5SLaurent Vivier 
117e32b96b5SLaurent Vivier     err = qdict_get_qdict(resp, "error");
118e32b96b5SLaurent Vivier     g_assert(qdict_haskey(err, "desc"));
119e32b96b5SLaurent Vivier 
120e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
121e32b96b5SLaurent Vivier                     "Bus 'pcie.0' does not support hotplugging");
122e32b96b5SLaurent Vivier 
123e32b96b5SLaurent Vivier     qobject_unref(resp);
124e32b96b5SLaurent Vivier 
125e32b96b5SLaurent Vivier     machine_stop(qts);
126e32b96b5SLaurent Vivier }
127e32b96b5SLaurent Vivier 
128e32b96b5SLaurent Vivier static QDict *find_device(QDict *bus, const char *name)
129e32b96b5SLaurent Vivier {
130e32b96b5SLaurent Vivier     const QObject *obj;
131e32b96b5SLaurent Vivier     QList *devices;
132e32b96b5SLaurent Vivier     QList *list;
133e32b96b5SLaurent Vivier 
134e32b96b5SLaurent Vivier     devices = qdict_get_qlist(bus, "devices");
135e32b96b5SLaurent Vivier     if (devices == NULL) {
136e32b96b5SLaurent Vivier         return NULL;
137e32b96b5SLaurent Vivier     }
138e32b96b5SLaurent Vivier 
139e32b96b5SLaurent Vivier     list = qlist_copy(devices);
140e32b96b5SLaurent Vivier     while ((obj = qlist_pop(list))) {
141e32b96b5SLaurent Vivier         QDict *device;
142e32b96b5SLaurent Vivier 
143e32b96b5SLaurent Vivier         device = qobject_to(QDict, obj);
144e32b96b5SLaurent Vivier 
145e32b96b5SLaurent Vivier         if (qdict_haskey(device, "pci_bridge")) {
146e32b96b5SLaurent Vivier             QDict *bridge;
147e32b96b5SLaurent Vivier             QDict *bridge_device;
148e32b96b5SLaurent Vivier 
149e32b96b5SLaurent Vivier             bridge = qdict_get_qdict(device, "pci_bridge");
150e32b96b5SLaurent Vivier 
151e32b96b5SLaurent Vivier             if (qdict_haskey(bridge, "devices")) {
152e32b96b5SLaurent Vivier                 bridge_device = find_device(bridge, name);
153e32b96b5SLaurent Vivier                 if (bridge_device) {
154e32b96b5SLaurent Vivier                     qobject_unref(device);
155e32b96b5SLaurent Vivier                     qobject_unref(list);
156e32b96b5SLaurent Vivier                     return bridge_device;
157e32b96b5SLaurent Vivier                 }
158e32b96b5SLaurent Vivier             }
159e32b96b5SLaurent Vivier         }
160e32b96b5SLaurent Vivier 
161e32b96b5SLaurent Vivier         if (!qdict_haskey(device, "qdev_id")) {
162e32b96b5SLaurent Vivier             qobject_unref(device);
163e32b96b5SLaurent Vivier             continue;
164e32b96b5SLaurent Vivier         }
165e32b96b5SLaurent Vivier 
166e32b96b5SLaurent Vivier         if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) {
167e32b96b5SLaurent Vivier             qobject_unref(list);
168e32b96b5SLaurent Vivier             return device;
169e32b96b5SLaurent Vivier         }
170e32b96b5SLaurent Vivier         qobject_unref(device);
171e32b96b5SLaurent Vivier     }
172e32b96b5SLaurent Vivier     qobject_unref(list);
173e32b96b5SLaurent Vivier 
174e32b96b5SLaurent Vivier     return NULL;
175e32b96b5SLaurent Vivier }
176e32b96b5SLaurent Vivier 
177e32b96b5SLaurent Vivier static QDict *get_bus(QTestState *qts, int num)
178e32b96b5SLaurent Vivier {
179e32b96b5SLaurent Vivier     QObject *obj;
180e32b96b5SLaurent Vivier     QDict *resp;
181e32b96b5SLaurent Vivier     QList *ret;
182e32b96b5SLaurent Vivier 
183e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }");
184e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
185e32b96b5SLaurent Vivier 
186e32b96b5SLaurent Vivier     ret = qdict_get_qlist(resp, "return");
187e32b96b5SLaurent Vivier     g_assert_nonnull(ret);
188e32b96b5SLaurent Vivier 
189e32b96b5SLaurent Vivier     while ((obj = qlist_pop(ret))) {
190e32b96b5SLaurent Vivier         QDict *bus;
191e32b96b5SLaurent Vivier 
192e32b96b5SLaurent Vivier         bus = qobject_to(QDict, obj);
193e32b96b5SLaurent Vivier         if (!qdict_haskey(bus, "bus")) {
194e32b96b5SLaurent Vivier             qobject_unref(bus);
195e32b96b5SLaurent Vivier             continue;
196e32b96b5SLaurent Vivier         }
197e32b96b5SLaurent Vivier         if (qdict_get_int(bus, "bus") == num) {
198e32b96b5SLaurent Vivier             qobject_unref(resp);
199e32b96b5SLaurent Vivier             return bus;
200e32b96b5SLaurent Vivier         }
201e32b96b5SLaurent Vivier         qobject_ref(bus);
202e32b96b5SLaurent Vivier     }
203e32b96b5SLaurent Vivier     qobject_unref(resp);
204e32b96b5SLaurent Vivier 
205e32b96b5SLaurent Vivier     return NULL;
206e32b96b5SLaurent Vivier }
207e32b96b5SLaurent Vivier 
208e32b96b5SLaurent Vivier static char *get_mac(QTestState *qts, const char *name)
209e32b96b5SLaurent Vivier {
210e32b96b5SLaurent Vivier     QDict *resp;
211e32b96b5SLaurent Vivier     char *mac;
212e32b96b5SLaurent Vivier 
213e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'qom-get', "
214e32b96b5SLaurent Vivier                      "'arguments': { "
215e32b96b5SLaurent Vivier                      "'path': %s, "
216e32b96b5SLaurent Vivier                      "'property': 'mac' } }", name);
217e32b96b5SLaurent Vivier 
218e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
219e32b96b5SLaurent Vivier 
220e32b96b5SLaurent Vivier     mac = g_strdup(qdict_get_str(resp, "return"));
221e32b96b5SLaurent Vivier 
222e32b96b5SLaurent Vivier     qobject_unref(resp);
223e32b96b5SLaurent Vivier 
224e32b96b5SLaurent Vivier     return mac;
225e32b96b5SLaurent Vivier }
226e32b96b5SLaurent Vivier 
227e32b96b5SLaurent Vivier static void check_one_card(QTestState *qts, bool present,
228e32b96b5SLaurent Vivier                            const char *id, const char *mac)
229e32b96b5SLaurent Vivier {
230e32b96b5SLaurent Vivier     QDict *device;
231e32b96b5SLaurent Vivier     QDict *bus;
232e32b96b5SLaurent Vivier     char *addr;
233e32b96b5SLaurent Vivier 
234e32b96b5SLaurent Vivier     bus = get_bus(qts, 0);
235e32b96b5SLaurent Vivier     device = find_device(bus, id);
236e32b96b5SLaurent Vivier     if (present) {
237e32b96b5SLaurent Vivier         char *path;
238e32b96b5SLaurent Vivier 
239e32b96b5SLaurent Vivier         g_assert_nonnull(device);
240e32b96b5SLaurent Vivier         qobject_unref(device);
241e32b96b5SLaurent Vivier 
242e32b96b5SLaurent Vivier         path = g_strdup_printf("/machine/peripheral/%s", id);
243e32b96b5SLaurent Vivier         addr = get_mac(qts, path);
244e32b96b5SLaurent Vivier         g_free(path);
245e32b96b5SLaurent Vivier         g_assert_cmpstr(mac, ==, addr);
246e32b96b5SLaurent Vivier         g_free(addr);
247e32b96b5SLaurent Vivier     } else {
248e32b96b5SLaurent Vivier        g_assert_null(device);
249e32b96b5SLaurent Vivier     }
250e32b96b5SLaurent Vivier 
251e32b96b5SLaurent Vivier     qobject_unref(bus);
252e32b96b5SLaurent Vivier }
253e32b96b5SLaurent Vivier 
254e32b96b5SLaurent Vivier static void test_on(void)
255e32b96b5SLaurent Vivier {
256e32b96b5SLaurent Vivier     QTestState *qts;
257e32b96b5SLaurent Vivier 
258e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
259e32b96b5SLaurent Vivier                         "-netdev user,id=hs0 "
260e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,"
261e32b96b5SLaurent Vivier                         "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
262e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root1,id=primary0,"
263e32b96b5SLaurent Vivier                         "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
264e32b96b5SLaurent Vivier                         2);
265e32b96b5SLaurent Vivier 
266e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
267e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
268e32b96b5SLaurent Vivier 
269e32b96b5SLaurent Vivier     machine_stop(qts);
270e32b96b5SLaurent Vivier }
271e32b96b5SLaurent Vivier 
272e32b96b5SLaurent Vivier static void test_on_mismatch(void)
273e32b96b5SLaurent Vivier {
274e32b96b5SLaurent Vivier     QTestState *qts;
275e32b96b5SLaurent Vivier 
276e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
277e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
278e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
279e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
280e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
281e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
282e32b96b5SLaurent Vivier                      "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0,
283e32b96b5SLaurent Vivier                      2);
284e32b96b5SLaurent Vivier 
285e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
286e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
287e32b96b5SLaurent Vivier 
288e32b96b5SLaurent Vivier     machine_stop(qts);
289e32b96b5SLaurent Vivier }
290e32b96b5SLaurent Vivier 
291e32b96b5SLaurent Vivier static void test_off(void)
292e32b96b5SLaurent Vivier {
293e32b96b5SLaurent Vivier     QTestState *qts;
294e32b96b5SLaurent Vivier 
295e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
296e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
297e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
298e32b96b5SLaurent Vivier                      "failover=off,netdev=hs0,mac="MAC_STANDBY0" "
299e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
300e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
301e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
302e32b96b5SLaurent Vivier                      2);
303e32b96b5SLaurent Vivier 
304e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
305e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
306e32b96b5SLaurent Vivier 
307e32b96b5SLaurent Vivier     machine_stop(qts);
308e32b96b5SLaurent Vivier }
309e32b96b5SLaurent Vivier 
310e32b96b5SLaurent Vivier static QDict *get_failover_negociated_event(QTestState *qts)
311e32b96b5SLaurent Vivier {
312e32b96b5SLaurent Vivier     QDict *resp;
313e32b96b5SLaurent Vivier     QDict *data;
314e32b96b5SLaurent Vivier 
315e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED");
316e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
317e32b96b5SLaurent Vivier 
318e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
319e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
320e32b96b5SLaurent Vivier     qobject_ref(data);
321e32b96b5SLaurent Vivier     qobject_unref(resp);
322e32b96b5SLaurent Vivier 
323e32b96b5SLaurent Vivier     return data;
324e32b96b5SLaurent Vivier }
325e32b96b5SLaurent Vivier 
326e32b96b5SLaurent Vivier static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
327e32b96b5SLaurent Vivier                              const char *id)
328e32b96b5SLaurent Vivier {
329e32b96b5SLaurent Vivier     QVirtioPCIDevice *dev;
330e32b96b5SLaurent Vivier     uint64_t features;
331e32b96b5SLaurent Vivier     QPCIAddress addr;
332e32b96b5SLaurent Vivier     QDict *resp;
333e32b96b5SLaurent Vivier 
334e32b96b5SLaurent Vivier     addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0);
335e32b96b5SLaurent Vivier     dev = virtio_pci_new(pcibus, &addr);
336e32b96b5SLaurent Vivier     g_assert_nonnull(dev);
337e32b96b5SLaurent Vivier     qvirtio_pci_device_enable(dev);
338e32b96b5SLaurent Vivier     qvirtio_start_device(&dev->vdev);
339e32b96b5SLaurent Vivier     features = qvirtio_get_features(&dev->vdev);
340e32b96b5SLaurent Vivier     features = features & ~(QVIRTIO_F_BAD_FEATURE |
341e32b96b5SLaurent Vivier                             (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
342e32b96b5SLaurent Vivier                             (1ull << VIRTIO_RING_F_EVENT_IDX));
343e32b96b5SLaurent Vivier     qvirtio_set_features(&dev->vdev, features);
344e32b96b5SLaurent Vivier     qvirtio_set_driver_ok(&dev->vdev);
345e32b96b5SLaurent Vivier 
346e32b96b5SLaurent Vivier     resp = get_failover_negociated_event(qts);
347e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
348e32b96b5SLaurent Vivier     qobject_unref(resp);
349e32b96b5SLaurent Vivier 
350e32b96b5SLaurent Vivier     return dev;
351e32b96b5SLaurent Vivier }
352e32b96b5SLaurent Vivier 
353e32b96b5SLaurent Vivier static void test_enabled(void)
354e32b96b5SLaurent Vivier {
355e32b96b5SLaurent Vivier     QTestState *qts;
356e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
357e32b96b5SLaurent Vivier 
358e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
359e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
360e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
361e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
362e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
363e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
364e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
365e32b96b5SLaurent Vivier                      2);
366e32b96b5SLaurent Vivier 
367e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
368e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
369e32b96b5SLaurent Vivier 
370e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
371e32b96b5SLaurent Vivier 
372e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
373e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
374e32b96b5SLaurent Vivier 
375e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
376e32b96b5SLaurent Vivier     machine_stop(qts);
377e32b96b5SLaurent Vivier }
378e32b96b5SLaurent Vivier 
379e32b96b5SLaurent Vivier static void test_hotplug_1(void)
380e32b96b5SLaurent Vivier {
381e32b96b5SLaurent Vivier     QTestState *qts;
382e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
383e32b96b5SLaurent Vivier 
384e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
385e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
386e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
387e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
388e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ", 2);
389e32b96b5SLaurent Vivier 
390e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
391e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
392e32b96b5SLaurent Vivier 
393e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
394e32b96b5SLaurent Vivier 
395e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
396e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
397e32b96b5SLaurent Vivier 
398e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
399e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
400e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
401e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
402e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
403e32b96b5SLaurent Vivier 
404e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
405e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
406e32b96b5SLaurent Vivier 
407e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
408e32b96b5SLaurent Vivier     machine_stop(qts);
409e32b96b5SLaurent Vivier }
410e32b96b5SLaurent Vivier 
411e32b96b5SLaurent Vivier static void test_hotplug_1_reverse(void)
412e32b96b5SLaurent Vivier {
413e32b96b5SLaurent Vivier     QTestState *qts;
414e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
415e32b96b5SLaurent Vivier 
416e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
417e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
418e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
419e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
420e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
421e32b96b5SLaurent Vivier                      2);
422e32b96b5SLaurent Vivier 
423e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
424e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
425e32b96b5SLaurent Vivier 
426e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
427e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
428e32b96b5SLaurent Vivier                          "'failover': 'on',"
429e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
430e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
431e32b96b5SLaurent Vivier 
432e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
433e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
434e32b96b5SLaurent Vivier 
435e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
436e32b96b5SLaurent Vivier 
437e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
438e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
439e32b96b5SLaurent Vivier 
440e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
441e32b96b5SLaurent Vivier     machine_stop(qts);
442e32b96b5SLaurent Vivier }
443e32b96b5SLaurent Vivier 
444e32b96b5SLaurent Vivier static void test_hotplug_2(void)
445e32b96b5SLaurent Vivier {
446e32b96b5SLaurent Vivier     QTestState *qts;
447e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
448e32b96b5SLaurent Vivier 
449e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
450e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
451e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
452e32b96b5SLaurent Vivier                      2);
453e32b96b5SLaurent Vivier 
454e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
455e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
456e32b96b5SLaurent Vivier 
457e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
458e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
459e32b96b5SLaurent Vivier                          "'failover': 'on',"
460e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
461e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
462e32b96b5SLaurent Vivier 
463e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
464e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
465e32b96b5SLaurent Vivier 
466e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
467e32b96b5SLaurent Vivier 
468e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
469e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
470e32b96b5SLaurent Vivier 
471e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
472e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
473e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
474e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
475e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
476e32b96b5SLaurent Vivier 
477e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
478e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
479e32b96b5SLaurent Vivier 
480e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
481e32b96b5SLaurent Vivier     machine_stop(qts);
482e32b96b5SLaurent Vivier }
483e32b96b5SLaurent Vivier 
484e32b96b5SLaurent Vivier static void test_hotplug_2_reverse(void)
485e32b96b5SLaurent Vivier {
486e32b96b5SLaurent Vivier     QTestState *qts;
487e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
488e32b96b5SLaurent Vivier 
489e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
490e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
491e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
492e32b96b5SLaurent Vivier                      2);
493e32b96b5SLaurent Vivier 
494e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
495e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
496e32b96b5SLaurent Vivier 
497e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
498e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
499e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
500e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
501e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
502e32b96b5SLaurent Vivier 
503e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
504e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
505e32b96b5SLaurent Vivier 
506e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
507e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
508e32b96b5SLaurent Vivier                          "'failover': 'on',"
509e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
510e32b96b5SLaurent Vivier                          "'rombar': 0,"
511e32b96b5SLaurent Vivier                          "'romfile': '',"
512e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
513e32b96b5SLaurent Vivier 
514e32b96b5SLaurent Vivier     /*
515e32b96b5SLaurent Vivier      * XXX: sounds like a bug:
516e32b96b5SLaurent Vivier      * The primary should be hidden until the virtio-net driver
517e32b96b5SLaurent Vivier      * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
518e32b96b5SLaurent Vivier      */
519e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
520e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
521e32b96b5SLaurent Vivier 
522e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
523e32b96b5SLaurent Vivier 
524e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
525e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
526e32b96b5SLaurent Vivier 
527e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
528e32b96b5SLaurent Vivier     machine_stop(qts);
529e32b96b5SLaurent Vivier }
530e32b96b5SLaurent Vivier 
531e32b96b5SLaurent Vivier static QDict *migrate_status(QTestState *qts)
532e32b96b5SLaurent Vivier {
533e32b96b5SLaurent Vivier     QDict *resp, *ret;
534e32b96b5SLaurent Vivier 
535e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
536e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
537e32b96b5SLaurent Vivier 
538e32b96b5SLaurent Vivier     ret = qdict_get_qdict(resp, "return");
539e32b96b5SLaurent Vivier     g_assert(qdict_haskey(ret, "status"));
540e32b96b5SLaurent Vivier     qobject_ref(ret);
541e32b96b5SLaurent Vivier     qobject_unref(resp);
542e32b96b5SLaurent Vivier 
543e32b96b5SLaurent Vivier     return ret;
544e32b96b5SLaurent Vivier }
545e32b96b5SLaurent Vivier 
546e32b96b5SLaurent Vivier static QDict *get_unplug_primary_event(QTestState *qts)
547e32b96b5SLaurent Vivier {
548e32b96b5SLaurent Vivier     QDict *resp;
549e32b96b5SLaurent Vivier     QDict *data;
550e32b96b5SLaurent Vivier 
551e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
552e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
553e32b96b5SLaurent Vivier 
554e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
555e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
556e32b96b5SLaurent Vivier     qobject_ref(data);
557e32b96b5SLaurent Vivier     qobject_unref(resp);
558e32b96b5SLaurent Vivier 
559e32b96b5SLaurent Vivier     return data;
560e32b96b5SLaurent Vivier }
561e32b96b5SLaurent Vivier 
562e32b96b5SLaurent Vivier static void test_migrate_out(gconstpointer opaque)
563e32b96b5SLaurent Vivier {
564e32b96b5SLaurent Vivier     QTestState *qts;
565e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
566e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
567e32b96b5SLaurent Vivier     const gchar *status;
568e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
569e32b96b5SLaurent Vivier 
570e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
571e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
572e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
573e32b96b5SLaurent Vivier                      2);
574e32b96b5SLaurent Vivier 
575e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
576e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
577e32b96b5SLaurent Vivier 
578e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
579e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
580e32b96b5SLaurent Vivier                          "'failover': 'on',"
581e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
582e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
583e32b96b5SLaurent Vivier 
584e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
585e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
586e32b96b5SLaurent Vivier 
587e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
588e32b96b5SLaurent Vivier 
589e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
590e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
591e32b96b5SLaurent Vivier 
592e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
593e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
594e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
595e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
596e32b96b5SLaurent Vivier                          "'rombar': 0,"
597e32b96b5SLaurent Vivier                          "'romfile': '',"
598e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
599e32b96b5SLaurent Vivier 
600e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
601e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
602e32b96b5SLaurent Vivier 
603e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
604e32b96b5SLaurent Vivier     g_assert_nonnull(args);
605e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
606e32b96b5SLaurent Vivier 
607e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
608e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
609e32b96b5SLaurent Vivier     qobject_unref(resp);
610e32b96b5SLaurent Vivier 
611e32b96b5SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
612e32b96b5SLaurent Vivier     resp = get_unplug_primary_event(qts);
613e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
614e32b96b5SLaurent Vivier     qobject_unref(resp);
615e32b96b5SLaurent Vivier 
616e32b96b5SLaurent Vivier     /* wait the end of the migration setup phase */
617e32b96b5SLaurent Vivier     while (true) {
618e32b96b5SLaurent Vivier         ret = migrate_status(qts);
619e32b96b5SLaurent Vivier 
620e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
621e32b96b5SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
622e32b96b5SLaurent Vivier             qobject_unref(ret);
623e32b96b5SLaurent Vivier             break;
624e32b96b5SLaurent Vivier         }
625e32b96b5SLaurent Vivier 
626e32b96b5SLaurent Vivier         /* The migration must not start if the card is not ejected */
627e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
628e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
629e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
630e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
631e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
632e32b96b5SLaurent Vivier 
633e32b96b5SLaurent Vivier         qobject_unref(ret);
634e32b96b5SLaurent Vivier     }
635e32b96b5SLaurent Vivier 
636e32b96b5SLaurent Vivier     if (g_test_slow()) {
637e32b96b5SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
638e32b96b5SLaurent Vivier         for (int i = 0; i < 5; i++) {
639e32b96b5SLaurent Vivier             sleep(1);
640e32b96b5SLaurent Vivier             ret = migrate_status(qts);
641e32b96b5SLaurent Vivier             status = qdict_get_str(ret, "status");
642e32b96b5SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
643e32b96b5SLaurent Vivier             qobject_unref(ret);
644e32b96b5SLaurent Vivier         }
645e32b96b5SLaurent Vivier     }
646e32b96b5SLaurent Vivier 
647e32b96b5SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
648e32b96b5SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
649e32b96b5SLaurent Vivier 
650e32b96b5SLaurent Vivier     while (true) {
651e32b96b5SLaurent Vivier         ret = migrate_status(qts);
652e32b96b5SLaurent Vivier 
653e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
654e32b96b5SLaurent Vivier         if (strcmp(status, "completed") == 0) {
655e32b96b5SLaurent Vivier             qobject_unref(ret);
656e32b96b5SLaurent Vivier             break;
657e32b96b5SLaurent Vivier         }
658e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
659e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
660e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
661e32b96b5SLaurent Vivier         qobject_unref(ret);
662e32b96b5SLaurent Vivier     }
663e32b96b5SLaurent Vivier 
664e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
665e32b96b5SLaurent Vivier 
666e32b96b5SLaurent Vivier     /*
667e32b96b5SLaurent Vivier      * in fact, the card is ejected from the point of view of kernel
668e32b96b5SLaurent Vivier      * but not really from QEMU to be able to hotplug it back if
669e32b96b5SLaurent Vivier      * migration fails. So we can't check that:
670e32b96b5SLaurent Vivier      *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
671e32b96b5SLaurent Vivier      *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
672e32b96b5SLaurent Vivier      */
673e32b96b5SLaurent Vivier 
674e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
675e32b96b5SLaurent Vivier     machine_stop(qts);
676e32b96b5SLaurent Vivier }
677e32b96b5SLaurent Vivier 
678e32b96b5SLaurent Vivier static QDict *get_migration_event(QTestState *qts)
679e32b96b5SLaurent Vivier {
680e32b96b5SLaurent Vivier     QDict *resp;
681e32b96b5SLaurent Vivier     QDict *data;
682e32b96b5SLaurent Vivier 
683e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "MIGRATION");
684e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
685e32b96b5SLaurent Vivier 
686e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
687e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "status"));
688e32b96b5SLaurent Vivier     qobject_ref(data);
689e32b96b5SLaurent Vivier     qobject_unref(resp);
690e32b96b5SLaurent Vivier 
691e32b96b5SLaurent Vivier     return data;
692e32b96b5SLaurent Vivier }
693e32b96b5SLaurent Vivier 
694e32b96b5SLaurent Vivier static void test_migrate_in(gconstpointer opaque)
695e32b96b5SLaurent Vivier {
696e32b96b5SLaurent Vivier     QTestState *qts;
697e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
698e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
699e32b96b5SLaurent Vivier 
700e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
701e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
702e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
703e32b96b5SLaurent Vivier                      "-incoming defer ",
704e32b96b5SLaurent Vivier                      2);
705e32b96b5SLaurent Vivier 
706e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
707e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
708e32b96b5SLaurent Vivier 
709e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
710e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
711e32b96b5SLaurent Vivier                          "'failover': 'on',"
712e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
713e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
714e32b96b5SLaurent Vivier 
715e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
716e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
717e32b96b5SLaurent Vivier 
718e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
719e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
720e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
721e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
722e32b96b5SLaurent Vivier                          "'rombar': 0,"
723e32b96b5SLaurent Vivier                          "'romfile': '',"
724e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
725e32b96b5SLaurent Vivier 
726e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
727e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
728e32b96b5SLaurent Vivier 
729e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
730e32b96b5SLaurent Vivier     g_assert_nonnull(args);
731e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
732e32b96b5SLaurent Vivier 
733e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
734e32b96b5SLaurent Vivier                      args);
735e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
736e32b96b5SLaurent Vivier     qobject_unref(resp);
737e32b96b5SLaurent Vivier 
738e32b96b5SLaurent Vivier     resp = get_migration_event(qts);
739e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
740e32b96b5SLaurent Vivier     qobject_unref(resp);
741e32b96b5SLaurent Vivier 
742e32b96b5SLaurent Vivier     resp = get_failover_negociated_event(qts);
743e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
744e32b96b5SLaurent Vivier     qobject_unref(resp);
745e32b96b5SLaurent Vivier 
746e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
747e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
748e32b96b5SLaurent Vivier 
749e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
750e32b96b5SLaurent Vivier 
751e32b96b5SLaurent Vivier     ret = migrate_status(qts);
752e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
753e32b96b5SLaurent Vivier     qobject_unref(ret);
754e32b96b5SLaurent Vivier 
755e32b96b5SLaurent Vivier     machine_stop(qts);
756e32b96b5SLaurent Vivier }
757e32b96b5SLaurent Vivier 
7581e2077e2SLaurent Vivier static void test_migrate_abort_wait_unplug(gconstpointer opaque)
7591e2077e2SLaurent Vivier {
7601e2077e2SLaurent Vivier     QTestState *qts;
7611e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
7621e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
7631e2077e2SLaurent Vivier     const gchar *status;
7641e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
7651e2077e2SLaurent Vivier 
7661e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
7671e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
7681e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
7691e2077e2SLaurent Vivier                      2);
7701e2077e2SLaurent Vivier 
7711e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
7721e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
7731e2077e2SLaurent Vivier 
7741e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
7751e2077e2SLaurent Vivier                          "{'bus': 'root0',"
7761e2077e2SLaurent Vivier                          "'failover': 'on',"
7771e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
7781e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
7791e2077e2SLaurent Vivier 
7801e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
7811e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
7821e2077e2SLaurent Vivier 
7831e2077e2SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
7841e2077e2SLaurent Vivier 
7851e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
7861e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
7871e2077e2SLaurent Vivier 
7881e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
7891e2077e2SLaurent Vivier                          "{'bus': 'root1',"
7901e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
7911e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
7921e2077e2SLaurent Vivier                          "'rombar': 0,"
7931e2077e2SLaurent Vivier                          "'romfile': '',"
7941e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
7951e2077e2SLaurent Vivier 
7961e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
7971e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
7981e2077e2SLaurent Vivier 
7991e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
8001e2077e2SLaurent Vivier     g_assert_nonnull(args);
8011e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
8021e2077e2SLaurent Vivier 
8031e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
8041e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
8051e2077e2SLaurent Vivier     qobject_unref(resp);
8061e2077e2SLaurent Vivier 
8071e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
8081e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
8091e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
8101e2077e2SLaurent Vivier     qobject_unref(resp);
8111e2077e2SLaurent Vivier 
8121e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
8131e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
8141e2077e2SLaurent Vivier     qobject_unref(resp);
8151e2077e2SLaurent Vivier 
8161e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
8171e2077e2SLaurent Vivier 
8181e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
8191e2077e2SLaurent Vivier     ret = migrate_status(qts);
8201e2077e2SLaurent Vivier 
8211e2077e2SLaurent Vivier     status = qdict_get_str(ret, "status");
8221e2077e2SLaurent Vivier     g_assert_cmpstr(status, ==, "cancelling");
8231e2077e2SLaurent Vivier     qobject_unref(ret);
8241e2077e2SLaurent Vivier 
8251e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
8261e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
8271e2077e2SLaurent Vivier 
8281e2077e2SLaurent Vivier     while (true) {
8291e2077e2SLaurent Vivier         ret = migrate_status(qts);
8301e2077e2SLaurent Vivier 
8311e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
8321e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
8331e2077e2SLaurent Vivier             qobject_unref(ret);
8341e2077e2SLaurent Vivier             break;
8351e2077e2SLaurent Vivier         }
8361e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
8371e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
8381e2077e2SLaurent Vivier         qobject_unref(ret);
8391e2077e2SLaurent Vivier     }
8401e2077e2SLaurent Vivier 
8411e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8421e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
8431e2077e2SLaurent Vivier 
8441e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
8451e2077e2SLaurent Vivier     machine_stop(qts);
8461e2077e2SLaurent Vivier }
8471e2077e2SLaurent Vivier 
8481e2077e2SLaurent Vivier static void test_migrate_abort_active(gconstpointer opaque)
8491e2077e2SLaurent Vivier {
8501e2077e2SLaurent Vivier     QTestState *qts;
8511e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
8521e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
8531e2077e2SLaurent Vivier     const gchar *status;
8541e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
8551e2077e2SLaurent Vivier 
8561e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
8571e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
8581e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
8591e2077e2SLaurent Vivier                      2);
8601e2077e2SLaurent Vivier 
8611e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
8621e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8631e2077e2SLaurent Vivier 
8641e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
8651e2077e2SLaurent Vivier                          "{'bus': 'root0',"
8661e2077e2SLaurent Vivier                          "'failover': 'on',"
8671e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
8681e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
8691e2077e2SLaurent Vivier 
8701e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8711e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8721e2077e2SLaurent Vivier 
8731e2077e2SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
8741e2077e2SLaurent Vivier 
8751e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8761e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8771e2077e2SLaurent Vivier 
8781e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
8791e2077e2SLaurent Vivier                          "{'bus': 'root1',"
8801e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
8811e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
8821e2077e2SLaurent Vivier                          "'rombar': 0,"
8831e2077e2SLaurent Vivier                          "'romfile': '',"
8841e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
8851e2077e2SLaurent Vivier 
8861e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8871e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
8881e2077e2SLaurent Vivier 
8891e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
8901e2077e2SLaurent Vivier     g_assert_nonnull(args);
8911e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
8921e2077e2SLaurent Vivier 
8931e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
8941e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
8951e2077e2SLaurent Vivier     qobject_unref(resp);
8961e2077e2SLaurent Vivier 
8971e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
8981e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
8991e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
9001e2077e2SLaurent Vivier     qobject_unref(resp);
9011e2077e2SLaurent Vivier 
9021e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
9031e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
9041e2077e2SLaurent Vivier 
9051e2077e2SLaurent Vivier     while (true) {
9061e2077e2SLaurent Vivier         ret = migrate_status(qts);
9071e2077e2SLaurent Vivier 
9081e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
9091e2077e2SLaurent Vivier         if (strcmp(status, "wait-unplug") != 0) {
9101e2077e2SLaurent Vivier             qobject_unref(ret);
9111e2077e2SLaurent Vivier             break;
9121e2077e2SLaurent Vivier         }
9131e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
9141e2077e2SLaurent Vivier         qobject_unref(ret);
9151e2077e2SLaurent Vivier     }
9161e2077e2SLaurent Vivier 
9171e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
9181e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
9191e2077e2SLaurent Vivier     qobject_unref(resp);
9201e2077e2SLaurent Vivier 
9211e2077e2SLaurent Vivier     while (true) {
9221e2077e2SLaurent Vivier         ret = migrate_status(qts);
9231e2077e2SLaurent Vivier 
9241e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
9251e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
9261e2077e2SLaurent Vivier             qobject_unref(ret);
9271e2077e2SLaurent Vivier             break;
9281e2077e2SLaurent Vivier         }
9291e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
9301e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
9311e2077e2SLaurent Vivier         qobject_unref(ret);
9321e2077e2SLaurent Vivier     }
9331e2077e2SLaurent Vivier 
9341e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9351e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
9361e2077e2SLaurent Vivier 
9371e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
9381e2077e2SLaurent Vivier     machine_stop(qts);
9391e2077e2SLaurent Vivier }
9401e2077e2SLaurent Vivier 
9411e2077e2SLaurent Vivier static void test_migrate_abort_timeout(gconstpointer opaque)
9421e2077e2SLaurent Vivier {
9431e2077e2SLaurent Vivier     QTestState *qts;
9441e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
9451e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
9461e2077e2SLaurent Vivier     const gchar *status;
9471e2077e2SLaurent Vivier     int total;
9481e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
9491e2077e2SLaurent Vivier 
9501e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
9511e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
9521e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
9531e2077e2SLaurent Vivier                      2);
9541e2077e2SLaurent Vivier 
9551e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
9561e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
9571e2077e2SLaurent Vivier 
9581e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
9591e2077e2SLaurent Vivier                          "{'bus': 'root0',"
9601e2077e2SLaurent Vivier                          "'failover': 'on',"
9611e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
9621e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
9631e2077e2SLaurent Vivier 
9641e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9651e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
9661e2077e2SLaurent Vivier 
9671e2077e2SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
9681e2077e2SLaurent Vivier 
9691e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9701e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
9711e2077e2SLaurent Vivier 
9721e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
9731e2077e2SLaurent Vivier                          "{'bus': 'root1',"
9741e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
9751e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
9761e2077e2SLaurent Vivier                          "'rombar': 0,"
9771e2077e2SLaurent Vivier                          "'romfile': '',"
9781e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
9791e2077e2SLaurent Vivier 
9801e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9811e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
9821e2077e2SLaurent Vivier 
9831e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
9841e2077e2SLaurent Vivier     g_assert_nonnull(args);
9851e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
9861e2077e2SLaurent Vivier 
9871e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
9881e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
9891e2077e2SLaurent Vivier     qobject_unref(resp);
9901e2077e2SLaurent Vivier 
9911e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
9921e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
9931e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
9941e2077e2SLaurent Vivier     qobject_unref(resp);
9951e2077e2SLaurent Vivier 
9961e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
9971e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
9981e2077e2SLaurent Vivier     qobject_unref(resp);
9991e2077e2SLaurent Vivier 
10001e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
10011e2077e2SLaurent Vivier 
10021e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
10031e2077e2SLaurent Vivier 
10041e2077e2SLaurent Vivier     total = 0;
10051e2077e2SLaurent Vivier     while (true) {
10061e2077e2SLaurent Vivier         ret = migrate_status(qts);
10071e2077e2SLaurent Vivier 
10081e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
10091e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
10101e2077e2SLaurent Vivier             qobject_unref(ret);
10111e2077e2SLaurent Vivier             break;
10121e2077e2SLaurent Vivier         }
10131e2077e2SLaurent Vivier         g_assert_cmpstr(status, ==, "cancelling");
10141e2077e2SLaurent Vivier         g_assert(qdict_haskey(ret, "total-time"));
10151e2077e2SLaurent Vivier         total = qdict_get_int(ret, "total-time");
10161e2077e2SLaurent Vivier         qobject_unref(ret);
10171e2077e2SLaurent Vivier     }
10181e2077e2SLaurent Vivier 
10191e2077e2SLaurent Vivier     /*
10201e2077e2SLaurent Vivier      * migration timeout in this case is 30 seconds
10211e2077e2SLaurent Vivier      * check we exit on the timeout (ms)
10221e2077e2SLaurent Vivier      */
10231e2077e2SLaurent Vivier     g_assert_cmpint(total, >, 30000);
10241e2077e2SLaurent Vivier 
10251e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
10261e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
10271e2077e2SLaurent Vivier 
10281e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
10291e2077e2SLaurent Vivier     machine_stop(qts);
10301e2077e2SLaurent Vivier }
10311e2077e2SLaurent Vivier 
1032e1e3d321SLaurent Vivier static void test_multi_out(gconstpointer opaque)
1033e1e3d321SLaurent Vivier {
1034e1e3d321SLaurent Vivier     QTestState *qts;
1035e1e3d321SLaurent Vivier     QDict *resp, *args, *ret;
1036e1e3d321SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1037e1e3d321SLaurent Vivier     const gchar *status, *expected;
1038e1e3d321SLaurent Vivier     QVirtioPCIDevice *vdev0, *vdev1;
1039e1e3d321SLaurent Vivier 
1040e1e3d321SLaurent Vivier     qts = machine_start(BASE_MACHINE
1041e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1042e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1043e1e3d321SLaurent Vivier                 "-netdev user,id=hs0 "
1044e1e3d321SLaurent Vivier                 "-netdev user,id=hs1 "
1045e1e3d321SLaurent Vivier                 "-netdev user,id=hs2 "
1046e1e3d321SLaurent Vivier                 "-netdev user,id=hs3 ",
1047e1e3d321SLaurent Vivier                 4);
1048e1e3d321SLaurent Vivier 
1049e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1050e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1051e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1052e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1053e1e3d321SLaurent Vivier 
1054e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1055e1e3d321SLaurent Vivier                          "{'bus': 'root0',"
1056e1e3d321SLaurent Vivier                          "'failover': 'on',"
1057e1e3d321SLaurent Vivier                          "'netdev': 'hs0',"
1058e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1059e1e3d321SLaurent Vivier 
1060e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1061e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1062e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1063e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1064e1e3d321SLaurent Vivier 
1065e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1066e1e3d321SLaurent Vivier                          "{'bus': 'root1',"
1067e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1068e1e3d321SLaurent Vivier                          "'netdev': 'hs1',"
1069e1e3d321SLaurent Vivier                          "'rombar': 0,"
1070e1e3d321SLaurent Vivier                          "'romfile': '',"
1071e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1072e1e3d321SLaurent Vivier 
1073e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1074e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1075e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1076e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1077e1e3d321SLaurent Vivier 
1078e1e3d321SLaurent Vivier     vdev0 = start_virtio_net(qts, 1, 0, "standby0");
1079e1e3d321SLaurent Vivier 
1080e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1081e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1082e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1083e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1084e1e3d321SLaurent Vivier 
1085e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1086e1e3d321SLaurent Vivier                          "{'bus': 'root2',"
1087e1e3d321SLaurent Vivier                          "'failover': 'on',"
1088e1e3d321SLaurent Vivier                          "'netdev': 'hs2',"
1089e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY1"'}");
1090e1e3d321SLaurent Vivier 
1091e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1092e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1093e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1094e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1095e1e3d321SLaurent Vivier 
1096e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1097e1e3d321SLaurent Vivier                          "{'bus': 'root3',"
1098e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby1',"
1099e1e3d321SLaurent Vivier                          "'netdev': 'hs3',"
1100e1e3d321SLaurent Vivier                          "'rombar': 0,"
1101e1e3d321SLaurent Vivier                          "'romfile': '',"
1102e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY1"'}");
1103e1e3d321SLaurent Vivier 
1104e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1105e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1106e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1107e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1108e1e3d321SLaurent Vivier 
1109e1e3d321SLaurent Vivier     vdev1 = start_virtio_net(qts, 3, 0, "standby1");
1110e1e3d321SLaurent Vivier 
1111e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1112e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1113e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1114e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1115e1e3d321SLaurent Vivier 
1116e1e3d321SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1117e1e3d321SLaurent Vivier     g_assert_nonnull(args);
1118e1e3d321SLaurent Vivier     qdict_put_str(args, "uri", uri);
1119e1e3d321SLaurent Vivier 
1120e1e3d321SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1121e1e3d321SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1122e1e3d321SLaurent Vivier     qobject_unref(resp);
1123e1e3d321SLaurent Vivier 
1124e1e3d321SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
1125e1e3d321SLaurent Vivier     resp = get_unplug_primary_event(qts);
1126e1e3d321SLaurent Vivier     if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
1127e1e3d321SLaurent Vivier         expected = "primary1";
1128e1e3d321SLaurent Vivier     } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
1129e1e3d321SLaurent Vivier         expected = "primary0";
1130e1e3d321SLaurent Vivier     } else {
1131e1e3d321SLaurent Vivier         g_assert_not_reached();
1132e1e3d321SLaurent Vivier     }
1133e1e3d321SLaurent Vivier     qobject_unref(resp);
1134e1e3d321SLaurent Vivier 
1135e1e3d321SLaurent Vivier     resp = get_unplug_primary_event(qts);
1136e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1137e1e3d321SLaurent Vivier     qobject_unref(resp);
1138e1e3d321SLaurent Vivier 
1139e1e3d321SLaurent Vivier     /* wait the end of the migration setup phase */
1140e1e3d321SLaurent Vivier     while (true) {
1141e1e3d321SLaurent Vivier         ret = migrate_status(qts);
1142e1e3d321SLaurent Vivier 
1143e1e3d321SLaurent Vivier         status = qdict_get_str(ret, "status");
1144e1e3d321SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
1145e1e3d321SLaurent Vivier             qobject_unref(ret);
1146e1e3d321SLaurent Vivier             break;
1147e1e3d321SLaurent Vivier         }
1148e1e3d321SLaurent Vivier 
1149e1e3d321SLaurent Vivier         /* The migration must not start if the card is not ejected */
1150e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
1151e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
1152e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1153e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1154e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1155e1e3d321SLaurent Vivier 
1156e1e3d321SLaurent Vivier         qobject_unref(ret);
1157e1e3d321SLaurent Vivier     }
1158e1e3d321SLaurent Vivier 
1159e1e3d321SLaurent Vivier     /* OS unplugs primary1, but we must wait the second */
1160e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1161e1e3d321SLaurent Vivier 
1162e1e3d321SLaurent Vivier     ret = migrate_status(qts);
1163e1e3d321SLaurent Vivier     status = qdict_get_str(ret, "status");
1164e1e3d321SLaurent Vivier     g_assert_cmpstr(status, ==, "wait-unplug");
1165e1e3d321SLaurent Vivier     qobject_unref(ret);
1166e1e3d321SLaurent Vivier 
1167e1e3d321SLaurent Vivier     if (g_test_slow()) {
1168e1e3d321SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
1169e1e3d321SLaurent Vivier         for (int i = 0; i < 5; i++) {
1170e1e3d321SLaurent Vivier             sleep(1);
1171e1e3d321SLaurent Vivier             ret = migrate_status(qts);
1172e1e3d321SLaurent Vivier             status = qdict_get_str(ret, "status");
1173e1e3d321SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
1174e1e3d321SLaurent Vivier             qobject_unref(ret);
1175e1e3d321SLaurent Vivier         }
1176e1e3d321SLaurent Vivier     }
1177e1e3d321SLaurent Vivier 
1178e1e3d321SLaurent Vivier     /* OS unplugs primary0, QEMU can move from wait-unplug state */
1179e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
1180e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1181e1e3d321SLaurent Vivier 
1182e1e3d321SLaurent Vivier     while (true) {
1183e1e3d321SLaurent Vivier         ret = migrate_status(qts);
1184e1e3d321SLaurent Vivier 
1185e1e3d321SLaurent Vivier         status = qdict_get_str(ret, "status");
1186e1e3d321SLaurent Vivier         if (strcmp(status, "completed") == 0) {
1187e1e3d321SLaurent Vivier             qobject_unref(ret);
1188e1e3d321SLaurent Vivier             break;
1189e1e3d321SLaurent Vivier         }
1190e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1191e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1192e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1193e1e3d321SLaurent Vivier         qobject_unref(ret);
1194e1e3d321SLaurent Vivier     }
1195e1e3d321SLaurent Vivier 
1196e1e3d321SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
1197e1e3d321SLaurent Vivier 
1198e1e3d321SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev0);
1199e1e3d321SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev1);
1200e1e3d321SLaurent Vivier     machine_stop(qts);
1201e1e3d321SLaurent Vivier }
1202e1e3d321SLaurent Vivier 
1203e1e3d321SLaurent Vivier static void test_multi_in(gconstpointer opaque)
1204e1e3d321SLaurent Vivier {
1205e1e3d321SLaurent Vivier     QTestState *qts;
1206e1e3d321SLaurent Vivier     QDict *resp, *args, *ret;
1207e1e3d321SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1208e1e3d321SLaurent Vivier 
1209e1e3d321SLaurent Vivier     qts = machine_start(BASE_MACHINE
1210e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1211e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1212e1e3d321SLaurent Vivier                 "-netdev user,id=hs0 "
1213e1e3d321SLaurent Vivier                 "-netdev user,id=hs1 "
1214e1e3d321SLaurent Vivier                 "-netdev user,id=hs2 "
1215e1e3d321SLaurent Vivier                 "-netdev user,id=hs3 "
1216e1e3d321SLaurent Vivier                 "-incoming defer ",
1217e1e3d321SLaurent Vivier                 4);
1218e1e3d321SLaurent Vivier 
1219e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1220e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1221e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1222e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1223e1e3d321SLaurent Vivier 
1224e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1225e1e3d321SLaurent Vivier                          "{'bus': 'root0',"
1226e1e3d321SLaurent Vivier                          "'failover': 'on',"
1227e1e3d321SLaurent Vivier                          "'netdev': 'hs0',"
1228e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1229e1e3d321SLaurent Vivier 
1230e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1231e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1232e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1233e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1234e1e3d321SLaurent Vivier 
1235e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1236e1e3d321SLaurent Vivier                          "{'bus': 'root1',"
1237e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1238e1e3d321SLaurent Vivier                          "'netdev': 'hs1',"
1239e1e3d321SLaurent Vivier                          "'rombar': 0,"
1240e1e3d321SLaurent Vivier                          "'romfile': '',"
1241e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1242e1e3d321SLaurent Vivier 
1243e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1244e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1245e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1246e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1247e1e3d321SLaurent Vivier 
1248e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1249e1e3d321SLaurent Vivier                          "{'bus': 'root2',"
1250e1e3d321SLaurent Vivier                          "'failover': 'on',"
1251e1e3d321SLaurent Vivier                          "'netdev': 'hs2',"
1252e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY1"'}");
1253e1e3d321SLaurent Vivier 
1254e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1255e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1256e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1257e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1258e1e3d321SLaurent Vivier 
1259e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1260e1e3d321SLaurent Vivier                          "{'bus': 'root3',"
1261e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby1',"
1262e1e3d321SLaurent Vivier                          "'netdev': 'hs3',"
1263e1e3d321SLaurent Vivier                          "'rombar': 0,"
1264e1e3d321SLaurent Vivier                          "'romfile': '',"
1265e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY1"'}");
1266e1e3d321SLaurent Vivier 
1267e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1268e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1269e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1270e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1271e1e3d321SLaurent Vivier 
1272e1e3d321SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1273e1e3d321SLaurent Vivier     g_assert_nonnull(args);
1274e1e3d321SLaurent Vivier     qdict_put_str(args, "uri", uri);
1275e1e3d321SLaurent Vivier 
1276e1e3d321SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1277e1e3d321SLaurent Vivier                      args);
1278e1e3d321SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1279e1e3d321SLaurent Vivier     qobject_unref(resp);
1280e1e3d321SLaurent Vivier 
1281e1e3d321SLaurent Vivier     resp = get_migration_event(qts);
1282e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1283e1e3d321SLaurent Vivier     qobject_unref(resp);
1284e1e3d321SLaurent Vivier 
1285e1e3d321SLaurent Vivier     resp = get_failover_negociated_event(qts);
1286e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1287e1e3d321SLaurent Vivier     qobject_unref(resp);
1288e1e3d321SLaurent Vivier 
1289e1e3d321SLaurent Vivier     resp = get_failover_negociated_event(qts);
1290e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1291e1e3d321SLaurent Vivier     qobject_unref(resp);
1292e1e3d321SLaurent Vivier 
1293e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1294e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1295e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1296e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1297e1e3d321SLaurent Vivier 
1298e1e3d321SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
1299e1e3d321SLaurent Vivier 
1300e1e3d321SLaurent Vivier     ret = migrate_status(qts);
1301e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1302e1e3d321SLaurent Vivier     qobject_unref(ret);
1303e1e3d321SLaurent Vivier 
1304e1e3d321SLaurent Vivier     machine_stop(qts);
1305e1e3d321SLaurent Vivier }
1306e1e3d321SLaurent Vivier 
1307e32b96b5SLaurent Vivier int main(int argc, char **argv)
1308e32b96b5SLaurent Vivier {
1309*e63ed64cSThomas Huth     gchar *tmpfile;
1310e32b96b5SLaurent Vivier     int ret;
1311e32b96b5SLaurent Vivier 
1312e32b96b5SLaurent Vivier     g_test_init(&argc, &argv, NULL);
1313e32b96b5SLaurent Vivier 
1314*e63ed64cSThomas Huth     ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
1315*e63ed64cSThomas Huth     g_assert_true(ret >= 0);
1316*e63ed64cSThomas Huth     close(ret);
1317*e63ed64cSThomas Huth 
1318e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1319e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1320e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on", test_on);
1321e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on_mismatch",
1322e32b96b5SLaurent Vivier                    test_on_mismatch);
1323e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/off", test_off);
1324e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
1325e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_1", test_hotplug_1);
1326e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_1_reverse",
1327e32b96b5SLaurent Vivier                    test_hotplug_1_reverse);
1328e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_2", test_hotplug_2);
1329e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_2_reverse",
1330e32b96b5SLaurent Vivier                    test_hotplug_2_reverse);
1331e32b96b5SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/out", tmpfile,
1332e32b96b5SLaurent Vivier                         test_migrate_out);
1333e32b96b5SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/in", tmpfile,
1334e32b96b5SLaurent Vivier                         test_migrate_in);
13351e2077e2SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
13361e2077e2SLaurent Vivier                         tmpfile, test_migrate_abort_wait_unplug);
13371e2077e2SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
13381e2077e2SLaurent Vivier                         test_migrate_abort_active);
13391e2077e2SLaurent Vivier     if (g_test_slow()) {
13401e2077e2SLaurent Vivier         qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
13411e2077e2SLaurent Vivier                             tmpfile, test_migrate_abort_timeout);
13421e2077e2SLaurent Vivier     }
1343e1e3d321SLaurent Vivier     qtest_add_data_func("failover-virtio-net/multi/out",
1344e1e3d321SLaurent Vivier                         tmpfile, test_multi_out);
1345e1e3d321SLaurent Vivier     qtest_add_data_func("failover-virtio-net/multi/in",
1346e1e3d321SLaurent Vivier                    tmpfile, test_multi_in);
1347e32b96b5SLaurent Vivier 
1348e32b96b5SLaurent Vivier     ret = g_test_run();
1349e32b96b5SLaurent Vivier 
1350e32b96b5SLaurent Vivier     unlink(tmpfile);
1351e32b96b5SLaurent Vivier     g_free(tmpfile);
1352e32b96b5SLaurent Vivier 
1353e32b96b5SLaurent Vivier     return ret;
1354e32b96b5SLaurent Vivier }
1355