xref: /qemu/tests/qtest/virtio-net-failover.c (revision 1a800870c5208e12e10fae638045121bb574d958)
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 
227*1a800870SLaurent Vivier #define check_one_card(qts, present, id, mac)                   \
228*1a800870SLaurent Vivier do {                                                            \
229*1a800870SLaurent Vivier     QDict *device;                                              \
230*1a800870SLaurent Vivier     QDict *bus;                                                 \
231*1a800870SLaurent Vivier     char *addr;                                                 \
232*1a800870SLaurent Vivier     bus = get_bus(qts, 0);                                      \
233*1a800870SLaurent Vivier     device = find_device(bus, id);                              \
234*1a800870SLaurent Vivier     if (present) {                                              \
235*1a800870SLaurent Vivier         char *path;                                             \
236*1a800870SLaurent Vivier         g_assert_nonnull(device);                               \
237*1a800870SLaurent Vivier         qobject_unref(device);                                  \
238*1a800870SLaurent Vivier         path = g_strdup_printf("/machine/peripheral/%s", id);   \
239*1a800870SLaurent Vivier         addr = get_mac(qts, path);                              \
240*1a800870SLaurent Vivier         g_free(path);                                           \
241*1a800870SLaurent Vivier         g_assert_cmpstr(mac, ==, addr);                         \
242*1a800870SLaurent Vivier         g_free(addr);                                           \
243*1a800870SLaurent Vivier     } else {                                                    \
244*1a800870SLaurent Vivier        g_assert_null(device);                                   \
245*1a800870SLaurent Vivier     }                                                           \
246*1a800870SLaurent Vivier     qobject_unref(bus);                                         \
247*1a800870SLaurent Vivier } while (0)
248e32b96b5SLaurent Vivier 
249e32b96b5SLaurent Vivier static void test_on(void)
250e32b96b5SLaurent Vivier {
251e32b96b5SLaurent Vivier     QTestState *qts;
252e32b96b5SLaurent Vivier 
253e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
254e32b96b5SLaurent Vivier                         "-netdev user,id=hs0 "
255e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,"
256e32b96b5SLaurent Vivier                         "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
257e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root1,id=primary0,"
258e32b96b5SLaurent Vivier                         "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
259e32b96b5SLaurent Vivier                         2);
260e32b96b5SLaurent Vivier 
261e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
262e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
263e32b96b5SLaurent Vivier 
264e32b96b5SLaurent Vivier     machine_stop(qts);
265e32b96b5SLaurent Vivier }
266e32b96b5SLaurent Vivier 
267e32b96b5SLaurent Vivier static void test_on_mismatch(void)
268e32b96b5SLaurent Vivier {
269e32b96b5SLaurent Vivier     QTestState *qts;
270e32b96b5SLaurent Vivier 
271e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
272e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
273e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
274e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
275e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
276e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
277e32b96b5SLaurent Vivier                      "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0,
278e32b96b5SLaurent Vivier                      2);
279e32b96b5SLaurent Vivier 
280e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
281e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
282e32b96b5SLaurent Vivier 
283e32b96b5SLaurent Vivier     machine_stop(qts);
284e32b96b5SLaurent Vivier }
285e32b96b5SLaurent Vivier 
286e32b96b5SLaurent Vivier static void test_off(void)
287e32b96b5SLaurent Vivier {
288e32b96b5SLaurent Vivier     QTestState *qts;
289e32b96b5SLaurent Vivier 
290e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
291e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
292e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
293e32b96b5SLaurent Vivier                      "failover=off,netdev=hs0,mac="MAC_STANDBY0" "
294e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
295e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
296e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
297e32b96b5SLaurent Vivier                      2);
298e32b96b5SLaurent Vivier 
299e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
300e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
301e32b96b5SLaurent Vivier 
302e32b96b5SLaurent Vivier     machine_stop(qts);
303e32b96b5SLaurent Vivier }
304e32b96b5SLaurent Vivier 
305e32b96b5SLaurent Vivier static QDict *get_failover_negociated_event(QTestState *qts)
306e32b96b5SLaurent Vivier {
307e32b96b5SLaurent Vivier     QDict *resp;
308e32b96b5SLaurent Vivier     QDict *data;
309e32b96b5SLaurent Vivier 
310e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED");
311e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
312e32b96b5SLaurent Vivier 
313e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
314e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
315e32b96b5SLaurent Vivier     qobject_ref(data);
316e32b96b5SLaurent Vivier     qobject_unref(resp);
317e32b96b5SLaurent Vivier 
318e32b96b5SLaurent Vivier     return data;
319e32b96b5SLaurent Vivier }
320e32b96b5SLaurent Vivier 
321e32b96b5SLaurent Vivier static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
322e32b96b5SLaurent Vivier                              const char *id)
323e32b96b5SLaurent Vivier {
324e32b96b5SLaurent Vivier     QVirtioPCIDevice *dev;
325e32b96b5SLaurent Vivier     uint64_t features;
326e32b96b5SLaurent Vivier     QPCIAddress addr;
327e32b96b5SLaurent Vivier     QDict *resp;
328e32b96b5SLaurent Vivier 
329e32b96b5SLaurent Vivier     addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0);
330e32b96b5SLaurent Vivier     dev = virtio_pci_new(pcibus, &addr);
331e32b96b5SLaurent Vivier     g_assert_nonnull(dev);
332e32b96b5SLaurent Vivier     qvirtio_pci_device_enable(dev);
333e32b96b5SLaurent Vivier     qvirtio_start_device(&dev->vdev);
334e32b96b5SLaurent Vivier     features = qvirtio_get_features(&dev->vdev);
335e32b96b5SLaurent Vivier     features = features & ~(QVIRTIO_F_BAD_FEATURE |
336e32b96b5SLaurent Vivier                             (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
337e32b96b5SLaurent Vivier                             (1ull << VIRTIO_RING_F_EVENT_IDX));
338e32b96b5SLaurent Vivier     qvirtio_set_features(&dev->vdev, features);
339e32b96b5SLaurent Vivier     qvirtio_set_driver_ok(&dev->vdev);
340e32b96b5SLaurent Vivier 
341e32b96b5SLaurent Vivier     resp = get_failover_negociated_event(qts);
342e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
343e32b96b5SLaurent Vivier     qobject_unref(resp);
344e32b96b5SLaurent Vivier 
345e32b96b5SLaurent Vivier     return dev;
346e32b96b5SLaurent Vivier }
347e32b96b5SLaurent Vivier 
348e32b96b5SLaurent Vivier static void test_enabled(void)
349e32b96b5SLaurent Vivier {
350e32b96b5SLaurent Vivier     QTestState *qts;
351e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
352e32b96b5SLaurent Vivier 
353e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
354e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
355e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
356e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
357e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
358e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
359e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
360e32b96b5SLaurent Vivier                      2);
361e32b96b5SLaurent Vivier 
362e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
363e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
364e32b96b5SLaurent Vivier 
365e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
366e32b96b5SLaurent Vivier 
367e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
368e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
369e32b96b5SLaurent Vivier 
370e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
371e32b96b5SLaurent Vivier     machine_stop(qts);
372e32b96b5SLaurent Vivier }
373e32b96b5SLaurent Vivier 
374e32b96b5SLaurent Vivier static void test_hotplug_1(void)
375e32b96b5SLaurent Vivier {
376e32b96b5SLaurent Vivier     QTestState *qts;
377e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
378e32b96b5SLaurent Vivier 
379e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
380e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
381e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
382e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
383e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ", 2);
384e32b96b5SLaurent Vivier 
385e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
386e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
387e32b96b5SLaurent Vivier 
388e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
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     qtest_qmp_device_add(qts, "virtio-net", "primary0",
394e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
395e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
396e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
397e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
398e32b96b5SLaurent Vivier 
399e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
400e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
401e32b96b5SLaurent Vivier 
402e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
403e32b96b5SLaurent Vivier     machine_stop(qts);
404e32b96b5SLaurent Vivier }
405e32b96b5SLaurent Vivier 
406e32b96b5SLaurent Vivier static void test_hotplug_1_reverse(void)
407e32b96b5SLaurent Vivier {
408e32b96b5SLaurent Vivier     QTestState *qts;
409e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
410e32b96b5SLaurent Vivier 
411e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
412e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
413e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
414e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
415e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
416e32b96b5SLaurent Vivier                      2);
417e32b96b5SLaurent Vivier 
418e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
419e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
420e32b96b5SLaurent Vivier 
421e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
422e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
423e32b96b5SLaurent Vivier                          "'failover': 'on',"
424e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
425e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
426e32b96b5SLaurent Vivier 
427e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
428e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
429e32b96b5SLaurent Vivier 
430e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "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     qos_object_destroy((QOSGraphObject *)vdev);
436e32b96b5SLaurent Vivier     machine_stop(qts);
437e32b96b5SLaurent Vivier }
438e32b96b5SLaurent Vivier 
439e32b96b5SLaurent Vivier static void test_hotplug_2(void)
440e32b96b5SLaurent Vivier {
441e32b96b5SLaurent Vivier     QTestState *qts;
442e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
443e32b96b5SLaurent Vivier 
444e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
445e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
446e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
447e32b96b5SLaurent Vivier                      2);
448e32b96b5SLaurent Vivier 
449e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
450e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
451e32b96b5SLaurent Vivier 
452e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
453e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
454e32b96b5SLaurent Vivier                          "'failover': 'on',"
455e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
456e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
457e32b96b5SLaurent Vivier 
458e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
459e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
460e32b96b5SLaurent Vivier 
461e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "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     qtest_qmp_device_add(qts, "virtio-net", "primary0",
467e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
468e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
469e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
470e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
471e32b96b5SLaurent Vivier 
472e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
473e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
474e32b96b5SLaurent Vivier 
475e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
476e32b96b5SLaurent Vivier     machine_stop(qts);
477e32b96b5SLaurent Vivier }
478e32b96b5SLaurent Vivier 
479e32b96b5SLaurent Vivier static void test_hotplug_2_reverse(void)
480e32b96b5SLaurent Vivier {
481e32b96b5SLaurent Vivier     QTestState *qts;
482e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
483e32b96b5SLaurent Vivier 
484e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
485e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
486e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
487e32b96b5SLaurent Vivier                      2);
488e32b96b5SLaurent Vivier 
489e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
490e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
491e32b96b5SLaurent Vivier 
492e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
493e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
494e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
495e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
496e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
497e32b96b5SLaurent Vivier 
498e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
499e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
500e32b96b5SLaurent Vivier 
501e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
502e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
503e32b96b5SLaurent Vivier                          "'failover': 'on',"
504e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
505e32b96b5SLaurent Vivier                          "'rombar': 0,"
506e32b96b5SLaurent Vivier                          "'romfile': '',"
507e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
508e32b96b5SLaurent Vivier 
509e32b96b5SLaurent Vivier     /*
510e32b96b5SLaurent Vivier      * XXX: sounds like a bug:
511e32b96b5SLaurent Vivier      * The primary should be hidden until the virtio-net driver
512e32b96b5SLaurent Vivier      * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
513e32b96b5SLaurent Vivier      */
514e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
515e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
516e32b96b5SLaurent Vivier 
517e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
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     qos_object_destroy((QOSGraphObject *)vdev);
523e32b96b5SLaurent Vivier     machine_stop(qts);
524e32b96b5SLaurent Vivier }
525e32b96b5SLaurent Vivier 
526e32b96b5SLaurent Vivier static QDict *migrate_status(QTestState *qts)
527e32b96b5SLaurent Vivier {
528e32b96b5SLaurent Vivier     QDict *resp, *ret;
529e32b96b5SLaurent Vivier 
530e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
531e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
532e32b96b5SLaurent Vivier 
533e32b96b5SLaurent Vivier     ret = qdict_get_qdict(resp, "return");
534e32b96b5SLaurent Vivier     g_assert(qdict_haskey(ret, "status"));
535e32b96b5SLaurent Vivier     qobject_ref(ret);
536e32b96b5SLaurent Vivier     qobject_unref(resp);
537e32b96b5SLaurent Vivier 
538e32b96b5SLaurent Vivier     return ret;
539e32b96b5SLaurent Vivier }
540e32b96b5SLaurent Vivier 
541e32b96b5SLaurent Vivier static QDict *get_unplug_primary_event(QTestState *qts)
542e32b96b5SLaurent Vivier {
543e32b96b5SLaurent Vivier     QDict *resp;
544e32b96b5SLaurent Vivier     QDict *data;
545e32b96b5SLaurent Vivier 
546e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
547e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
548e32b96b5SLaurent Vivier 
549e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
550e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
551e32b96b5SLaurent Vivier     qobject_ref(data);
552e32b96b5SLaurent Vivier     qobject_unref(resp);
553e32b96b5SLaurent Vivier 
554e32b96b5SLaurent Vivier     return data;
555e32b96b5SLaurent Vivier }
556e32b96b5SLaurent Vivier 
557e32b96b5SLaurent Vivier static void test_migrate_out(gconstpointer opaque)
558e32b96b5SLaurent Vivier {
559e32b96b5SLaurent Vivier     QTestState *qts;
560e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
561e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
562e32b96b5SLaurent Vivier     const gchar *status;
563e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
564e32b96b5SLaurent Vivier 
565e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
566e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
567e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
568e32b96b5SLaurent Vivier                      2);
569e32b96b5SLaurent Vivier 
570e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
571e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
572e32b96b5SLaurent Vivier 
573e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
574e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
575e32b96b5SLaurent Vivier                          "'failover': 'on',"
576e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
577e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
578e32b96b5SLaurent Vivier 
579e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
580e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
581e32b96b5SLaurent Vivier 
582e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "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     qtest_qmp_device_add(qts, "virtio-net", "primary0",
588e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
589e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
590e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
591e32b96b5SLaurent Vivier                          "'rombar': 0,"
592e32b96b5SLaurent Vivier                          "'romfile': '',"
593e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
594e32b96b5SLaurent Vivier 
595e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
596e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
597e32b96b5SLaurent Vivier 
598e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
599e32b96b5SLaurent Vivier     g_assert_nonnull(args);
600e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
601e32b96b5SLaurent Vivier 
602e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
603e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
604e32b96b5SLaurent Vivier     qobject_unref(resp);
605e32b96b5SLaurent Vivier 
606e32b96b5SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
607e32b96b5SLaurent Vivier     resp = get_unplug_primary_event(qts);
608e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
609e32b96b5SLaurent Vivier     qobject_unref(resp);
610e32b96b5SLaurent Vivier 
611e32b96b5SLaurent Vivier     /* wait the end of the migration setup phase */
612e32b96b5SLaurent Vivier     while (true) {
613e32b96b5SLaurent Vivier         ret = migrate_status(qts);
614e32b96b5SLaurent Vivier 
615e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
616e32b96b5SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
617e32b96b5SLaurent Vivier             qobject_unref(ret);
618e32b96b5SLaurent Vivier             break;
619e32b96b5SLaurent Vivier         }
620e32b96b5SLaurent Vivier 
621e32b96b5SLaurent Vivier         /* The migration must not start if the card is not ejected */
622e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
623e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
624e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
625e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
626e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
627e32b96b5SLaurent Vivier 
628e32b96b5SLaurent Vivier         qobject_unref(ret);
629e32b96b5SLaurent Vivier     }
630e32b96b5SLaurent Vivier 
631e32b96b5SLaurent Vivier     if (g_test_slow()) {
632e32b96b5SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
633e32b96b5SLaurent Vivier         for (int i = 0; i < 5; i++) {
634e32b96b5SLaurent Vivier             sleep(1);
635e32b96b5SLaurent Vivier             ret = migrate_status(qts);
636e32b96b5SLaurent Vivier             status = qdict_get_str(ret, "status");
637e32b96b5SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
638e32b96b5SLaurent Vivier             qobject_unref(ret);
639e32b96b5SLaurent Vivier         }
640e32b96b5SLaurent Vivier     }
641e32b96b5SLaurent Vivier 
642e32b96b5SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
643e32b96b5SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
644e32b96b5SLaurent Vivier 
645e32b96b5SLaurent Vivier     while (true) {
646e32b96b5SLaurent Vivier         ret = migrate_status(qts);
647e32b96b5SLaurent Vivier 
648e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
649e32b96b5SLaurent Vivier         if (strcmp(status, "completed") == 0) {
650e32b96b5SLaurent Vivier             qobject_unref(ret);
651e32b96b5SLaurent Vivier             break;
652e32b96b5SLaurent Vivier         }
653e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
654e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
655e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
656e32b96b5SLaurent Vivier         qobject_unref(ret);
657e32b96b5SLaurent Vivier     }
658e32b96b5SLaurent Vivier 
659e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
660e32b96b5SLaurent Vivier 
661e32b96b5SLaurent Vivier     /*
662e32b96b5SLaurent Vivier      * in fact, the card is ejected from the point of view of kernel
663e32b96b5SLaurent Vivier      * but not really from QEMU to be able to hotplug it back if
664e32b96b5SLaurent Vivier      * migration fails. So we can't check that:
665e32b96b5SLaurent Vivier      *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
666e32b96b5SLaurent Vivier      *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
667e32b96b5SLaurent Vivier      */
668e32b96b5SLaurent Vivier 
669e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
670e32b96b5SLaurent Vivier     machine_stop(qts);
671e32b96b5SLaurent Vivier }
672e32b96b5SLaurent Vivier 
673e32b96b5SLaurent Vivier static QDict *get_migration_event(QTestState *qts)
674e32b96b5SLaurent Vivier {
675e32b96b5SLaurent Vivier     QDict *resp;
676e32b96b5SLaurent Vivier     QDict *data;
677e32b96b5SLaurent Vivier 
678e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "MIGRATION");
679e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
680e32b96b5SLaurent Vivier 
681e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
682e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "status"));
683e32b96b5SLaurent Vivier     qobject_ref(data);
684e32b96b5SLaurent Vivier     qobject_unref(resp);
685e32b96b5SLaurent Vivier 
686e32b96b5SLaurent Vivier     return data;
687e32b96b5SLaurent Vivier }
688e32b96b5SLaurent Vivier 
689e32b96b5SLaurent Vivier static void test_migrate_in(gconstpointer opaque)
690e32b96b5SLaurent Vivier {
691e32b96b5SLaurent Vivier     QTestState *qts;
692e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
693e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
694e32b96b5SLaurent Vivier 
695e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
696e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
697e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
698e32b96b5SLaurent Vivier                      "-incoming defer ",
699e32b96b5SLaurent Vivier                      2);
700e32b96b5SLaurent Vivier 
701e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
702e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
703e32b96b5SLaurent Vivier 
704e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
705e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
706e32b96b5SLaurent Vivier                          "'failover': 'on',"
707e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
708e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
709e32b96b5SLaurent Vivier 
710e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
711e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
712e32b96b5SLaurent Vivier 
713e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
714e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
715e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
716e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
717e32b96b5SLaurent Vivier                          "'rombar': 0,"
718e32b96b5SLaurent Vivier                          "'romfile': '',"
719e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
720e32b96b5SLaurent Vivier 
721e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
722e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
723e32b96b5SLaurent Vivier 
724e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
725e32b96b5SLaurent Vivier     g_assert_nonnull(args);
726e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
727e32b96b5SLaurent Vivier 
728e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
729e32b96b5SLaurent Vivier                      args);
730e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
731e32b96b5SLaurent Vivier     qobject_unref(resp);
732e32b96b5SLaurent Vivier 
733e32b96b5SLaurent Vivier     resp = get_migration_event(qts);
734e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
735e32b96b5SLaurent Vivier     qobject_unref(resp);
736e32b96b5SLaurent Vivier 
737e32b96b5SLaurent Vivier     resp = get_failover_negociated_event(qts);
738e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
739e32b96b5SLaurent Vivier     qobject_unref(resp);
740e32b96b5SLaurent Vivier 
741e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
742e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
743e32b96b5SLaurent Vivier 
744e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
745e32b96b5SLaurent Vivier 
746e32b96b5SLaurent Vivier     ret = migrate_status(qts);
747e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
748e32b96b5SLaurent Vivier     qobject_unref(ret);
749e32b96b5SLaurent Vivier 
750e32b96b5SLaurent Vivier     machine_stop(qts);
751e32b96b5SLaurent Vivier }
752e32b96b5SLaurent Vivier 
7531e2077e2SLaurent Vivier static void test_migrate_abort_wait_unplug(gconstpointer opaque)
7541e2077e2SLaurent Vivier {
7551e2077e2SLaurent Vivier     QTestState *qts;
7561e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
7571e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
7581e2077e2SLaurent Vivier     const gchar *status;
7591e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
7601e2077e2SLaurent Vivier 
7611e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
7621e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
7631e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
7641e2077e2SLaurent Vivier                      2);
7651e2077e2SLaurent Vivier 
7661e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
7671e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
7681e2077e2SLaurent Vivier 
7691e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
7701e2077e2SLaurent Vivier                          "{'bus': 'root0',"
7711e2077e2SLaurent Vivier                          "'failover': 'on',"
7721e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
7731e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
7741e2077e2SLaurent Vivier 
7751e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
7761e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
7771e2077e2SLaurent Vivier 
7781e2077e2SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "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     qtest_qmp_device_add(qts, "virtio-net", "primary0",
7841e2077e2SLaurent Vivier                          "{'bus': 'root1',"
7851e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
7861e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
7871e2077e2SLaurent Vivier                          "'rombar': 0,"
7881e2077e2SLaurent Vivier                          "'romfile': '',"
7891e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
7901e2077e2SLaurent Vivier 
7911e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
7921e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
7931e2077e2SLaurent Vivier 
7941e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
7951e2077e2SLaurent Vivier     g_assert_nonnull(args);
7961e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
7971e2077e2SLaurent Vivier 
7981e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
7991e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
8001e2077e2SLaurent Vivier     qobject_unref(resp);
8011e2077e2SLaurent Vivier 
8021e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
8031e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
8041e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
8051e2077e2SLaurent Vivier     qobject_unref(resp);
8061e2077e2SLaurent Vivier 
8071e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
8081e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
8091e2077e2SLaurent Vivier     qobject_unref(resp);
8101e2077e2SLaurent Vivier 
8111e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
8121e2077e2SLaurent Vivier 
8131e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
8141e2077e2SLaurent Vivier     ret = migrate_status(qts);
8151e2077e2SLaurent Vivier 
8161e2077e2SLaurent Vivier     status = qdict_get_str(ret, "status");
8171e2077e2SLaurent Vivier     g_assert_cmpstr(status, ==, "cancelling");
8181e2077e2SLaurent Vivier     qobject_unref(ret);
8191e2077e2SLaurent Vivier 
8201e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
8211e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
8221e2077e2SLaurent Vivier 
8231e2077e2SLaurent Vivier     while (true) {
8241e2077e2SLaurent Vivier         ret = migrate_status(qts);
8251e2077e2SLaurent Vivier 
8261e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
8271e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
8281e2077e2SLaurent Vivier             qobject_unref(ret);
8291e2077e2SLaurent Vivier             break;
8301e2077e2SLaurent Vivier         }
8311e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
8321e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
8331e2077e2SLaurent Vivier         qobject_unref(ret);
8341e2077e2SLaurent Vivier     }
8351e2077e2SLaurent Vivier 
8361e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8371e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
8381e2077e2SLaurent Vivier 
8391e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
8401e2077e2SLaurent Vivier     machine_stop(qts);
8411e2077e2SLaurent Vivier }
8421e2077e2SLaurent Vivier 
8431e2077e2SLaurent Vivier static void test_migrate_abort_active(gconstpointer opaque)
8441e2077e2SLaurent Vivier {
8451e2077e2SLaurent Vivier     QTestState *qts;
8461e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
8471e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
8481e2077e2SLaurent Vivier     const gchar *status;
8491e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
8501e2077e2SLaurent Vivier 
8511e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
8521e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
8531e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
8541e2077e2SLaurent Vivier                      2);
8551e2077e2SLaurent Vivier 
8561e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
8571e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8581e2077e2SLaurent Vivier 
8591e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
8601e2077e2SLaurent Vivier                          "{'bus': 'root0',"
8611e2077e2SLaurent Vivier                          "'failover': 'on',"
8621e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
8631e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
8641e2077e2SLaurent Vivier 
8651e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8661e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8671e2077e2SLaurent Vivier 
8681e2077e2SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "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     qtest_qmp_device_add(qts, "virtio-net", "primary0",
8741e2077e2SLaurent Vivier                          "{'bus': 'root1',"
8751e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
8761e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
8771e2077e2SLaurent Vivier                          "'rombar': 0,"
8781e2077e2SLaurent Vivier                          "'romfile': '',"
8791e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
8801e2077e2SLaurent Vivier 
8811e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8821e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
8831e2077e2SLaurent Vivier 
8841e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
8851e2077e2SLaurent Vivier     g_assert_nonnull(args);
8861e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
8871e2077e2SLaurent Vivier 
8881e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
8891e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
8901e2077e2SLaurent Vivier     qobject_unref(resp);
8911e2077e2SLaurent Vivier 
8921e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
8931e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
8941e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
8951e2077e2SLaurent Vivier     qobject_unref(resp);
8961e2077e2SLaurent Vivier 
8971e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
8981e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
8991e2077e2SLaurent Vivier 
9001e2077e2SLaurent Vivier     while (true) {
9011e2077e2SLaurent Vivier         ret = migrate_status(qts);
9021e2077e2SLaurent Vivier 
9031e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
9041e2077e2SLaurent Vivier         if (strcmp(status, "wait-unplug") != 0) {
9051e2077e2SLaurent Vivier             qobject_unref(ret);
9061e2077e2SLaurent Vivier             break;
9071e2077e2SLaurent Vivier         }
9081e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
9091e2077e2SLaurent Vivier         qobject_unref(ret);
9101e2077e2SLaurent Vivier     }
9111e2077e2SLaurent Vivier 
9121e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
9131e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
9141e2077e2SLaurent Vivier     qobject_unref(resp);
9151e2077e2SLaurent Vivier 
9161e2077e2SLaurent Vivier     while (true) {
9171e2077e2SLaurent Vivier         ret = migrate_status(qts);
9181e2077e2SLaurent Vivier 
9191e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
9201e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
9211e2077e2SLaurent Vivier             qobject_unref(ret);
9221e2077e2SLaurent Vivier             break;
9231e2077e2SLaurent Vivier         }
9241e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
9251e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
9261e2077e2SLaurent Vivier         qobject_unref(ret);
9271e2077e2SLaurent Vivier     }
9281e2077e2SLaurent Vivier 
9291e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9301e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
9311e2077e2SLaurent Vivier 
9321e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
9331e2077e2SLaurent Vivier     machine_stop(qts);
9341e2077e2SLaurent Vivier }
9351e2077e2SLaurent Vivier 
9361e2077e2SLaurent Vivier static void test_migrate_abort_timeout(gconstpointer opaque)
9371e2077e2SLaurent Vivier {
9381e2077e2SLaurent Vivier     QTestState *qts;
9391e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
9401e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
9411e2077e2SLaurent Vivier     const gchar *status;
9421e2077e2SLaurent Vivier     int total;
9431e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
9441e2077e2SLaurent Vivier 
9451e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
9461e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
9471e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
9481e2077e2SLaurent Vivier                      2);
9491e2077e2SLaurent Vivier 
9501e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
9511e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
9521e2077e2SLaurent Vivier 
9531e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
9541e2077e2SLaurent Vivier                          "{'bus': 'root0',"
9551e2077e2SLaurent Vivier                          "'failover': 'on',"
9561e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
9571e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
9581e2077e2SLaurent Vivier 
9591e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9601e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
9611e2077e2SLaurent Vivier 
9621e2077e2SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "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     qtest_qmp_device_add(qts, "virtio-net", "primary0",
9681e2077e2SLaurent Vivier                          "{'bus': 'root1',"
9691e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
9701e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
9711e2077e2SLaurent Vivier                          "'rombar': 0,"
9721e2077e2SLaurent Vivier                          "'romfile': '',"
9731e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
9741e2077e2SLaurent Vivier 
9751e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9761e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
9771e2077e2SLaurent Vivier 
9781e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
9791e2077e2SLaurent Vivier     g_assert_nonnull(args);
9801e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
9811e2077e2SLaurent Vivier 
9821e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
9831e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
9841e2077e2SLaurent Vivier     qobject_unref(resp);
9851e2077e2SLaurent Vivier 
9861e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
9871e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
9881e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
9891e2077e2SLaurent Vivier     qobject_unref(resp);
9901e2077e2SLaurent Vivier 
9911e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
9921e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
9931e2077e2SLaurent Vivier     qobject_unref(resp);
9941e2077e2SLaurent Vivier 
9951e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
9961e2077e2SLaurent Vivier 
9971e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
9981e2077e2SLaurent Vivier 
9991e2077e2SLaurent Vivier     total = 0;
10001e2077e2SLaurent Vivier     while (true) {
10011e2077e2SLaurent Vivier         ret = migrate_status(qts);
10021e2077e2SLaurent Vivier 
10031e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
10041e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
10051e2077e2SLaurent Vivier             qobject_unref(ret);
10061e2077e2SLaurent Vivier             break;
10071e2077e2SLaurent Vivier         }
10081e2077e2SLaurent Vivier         g_assert_cmpstr(status, ==, "cancelling");
10091e2077e2SLaurent Vivier         g_assert(qdict_haskey(ret, "total-time"));
10101e2077e2SLaurent Vivier         total = qdict_get_int(ret, "total-time");
10111e2077e2SLaurent Vivier         qobject_unref(ret);
10121e2077e2SLaurent Vivier     }
10131e2077e2SLaurent Vivier 
10141e2077e2SLaurent Vivier     /*
10151e2077e2SLaurent Vivier      * migration timeout in this case is 30 seconds
10161e2077e2SLaurent Vivier      * check we exit on the timeout (ms)
10171e2077e2SLaurent Vivier      */
10181e2077e2SLaurent Vivier     g_assert_cmpint(total, >, 30000);
10191e2077e2SLaurent Vivier 
10201e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
10211e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
10221e2077e2SLaurent Vivier 
10231e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
10241e2077e2SLaurent Vivier     machine_stop(qts);
10251e2077e2SLaurent Vivier }
10261e2077e2SLaurent Vivier 
1027e1e3d321SLaurent Vivier static void test_multi_out(gconstpointer opaque)
1028e1e3d321SLaurent Vivier {
1029e1e3d321SLaurent Vivier     QTestState *qts;
1030e1e3d321SLaurent Vivier     QDict *resp, *args, *ret;
1031e1e3d321SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1032e1e3d321SLaurent Vivier     const gchar *status, *expected;
1033e1e3d321SLaurent Vivier     QVirtioPCIDevice *vdev0, *vdev1;
1034e1e3d321SLaurent Vivier 
1035e1e3d321SLaurent Vivier     qts = machine_start(BASE_MACHINE
1036e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1037e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1038e1e3d321SLaurent Vivier                 "-netdev user,id=hs0 "
1039e1e3d321SLaurent Vivier                 "-netdev user,id=hs1 "
1040e1e3d321SLaurent Vivier                 "-netdev user,id=hs2 "
1041e1e3d321SLaurent Vivier                 "-netdev user,id=hs3 ",
1042e1e3d321SLaurent Vivier                 4);
1043e1e3d321SLaurent Vivier 
1044e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1045e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1046e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1047e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1048e1e3d321SLaurent Vivier 
1049e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1050e1e3d321SLaurent Vivier                          "{'bus': 'root0',"
1051e1e3d321SLaurent Vivier                          "'failover': 'on',"
1052e1e3d321SLaurent Vivier                          "'netdev': 'hs0',"
1053e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1054e1e3d321SLaurent Vivier 
1055e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1056e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1057e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1058e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1059e1e3d321SLaurent Vivier 
1060e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1061e1e3d321SLaurent Vivier                          "{'bus': 'root1',"
1062e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1063e1e3d321SLaurent Vivier                          "'netdev': 'hs1',"
1064e1e3d321SLaurent Vivier                          "'rombar': 0,"
1065e1e3d321SLaurent Vivier                          "'romfile': '',"
1066e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1067e1e3d321SLaurent Vivier 
1068e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1069e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1070e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1071e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1072e1e3d321SLaurent Vivier 
1073e1e3d321SLaurent Vivier     vdev0 = start_virtio_net(qts, 1, 0, "standby0");
1074e1e3d321SLaurent Vivier 
1075e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1076e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1077e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1078e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1079e1e3d321SLaurent Vivier 
1080e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1081e1e3d321SLaurent Vivier                          "{'bus': 'root2',"
1082e1e3d321SLaurent Vivier                          "'failover': 'on',"
1083e1e3d321SLaurent Vivier                          "'netdev': 'hs2',"
1084e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY1"'}");
1085e1e3d321SLaurent Vivier 
1086e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1087e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1088e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1089e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1090e1e3d321SLaurent Vivier 
1091e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1092e1e3d321SLaurent Vivier                          "{'bus': 'root3',"
1093e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby1',"
1094e1e3d321SLaurent Vivier                          "'netdev': 'hs3',"
1095e1e3d321SLaurent Vivier                          "'rombar': 0,"
1096e1e3d321SLaurent Vivier                          "'romfile': '',"
1097e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY1"'}");
1098e1e3d321SLaurent Vivier 
1099e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1100e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1101e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1102e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1103e1e3d321SLaurent Vivier 
1104e1e3d321SLaurent Vivier     vdev1 = start_virtio_net(qts, 3, 0, "standby1");
1105e1e3d321SLaurent Vivier 
1106e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1107e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1108e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1109e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1110e1e3d321SLaurent Vivier 
1111e1e3d321SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1112e1e3d321SLaurent Vivier     g_assert_nonnull(args);
1113e1e3d321SLaurent Vivier     qdict_put_str(args, "uri", uri);
1114e1e3d321SLaurent Vivier 
1115e1e3d321SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1116e1e3d321SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1117e1e3d321SLaurent Vivier     qobject_unref(resp);
1118e1e3d321SLaurent Vivier 
1119e1e3d321SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
1120e1e3d321SLaurent Vivier     resp = get_unplug_primary_event(qts);
1121e1e3d321SLaurent Vivier     if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
1122e1e3d321SLaurent Vivier         expected = "primary1";
1123e1e3d321SLaurent Vivier     } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
1124e1e3d321SLaurent Vivier         expected = "primary0";
1125e1e3d321SLaurent Vivier     } else {
1126e1e3d321SLaurent Vivier         g_assert_not_reached();
1127e1e3d321SLaurent Vivier     }
1128e1e3d321SLaurent Vivier     qobject_unref(resp);
1129e1e3d321SLaurent Vivier 
1130e1e3d321SLaurent Vivier     resp = get_unplug_primary_event(qts);
1131e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1132e1e3d321SLaurent Vivier     qobject_unref(resp);
1133e1e3d321SLaurent Vivier 
1134e1e3d321SLaurent Vivier     /* wait the end of the migration setup phase */
1135e1e3d321SLaurent Vivier     while (true) {
1136e1e3d321SLaurent Vivier         ret = migrate_status(qts);
1137e1e3d321SLaurent Vivier 
1138e1e3d321SLaurent Vivier         status = qdict_get_str(ret, "status");
1139e1e3d321SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
1140e1e3d321SLaurent Vivier             qobject_unref(ret);
1141e1e3d321SLaurent Vivier             break;
1142e1e3d321SLaurent Vivier         }
1143e1e3d321SLaurent Vivier 
1144e1e3d321SLaurent Vivier         /* The migration must not start if the card is not ejected */
1145e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
1146e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
1147e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1148e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1149e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1150e1e3d321SLaurent Vivier 
1151e1e3d321SLaurent Vivier         qobject_unref(ret);
1152e1e3d321SLaurent Vivier     }
1153e1e3d321SLaurent Vivier 
1154e1e3d321SLaurent Vivier     /* OS unplugs primary1, but we must wait the second */
1155e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1156e1e3d321SLaurent Vivier 
1157e1e3d321SLaurent Vivier     ret = migrate_status(qts);
1158e1e3d321SLaurent Vivier     status = qdict_get_str(ret, "status");
1159e1e3d321SLaurent Vivier     g_assert_cmpstr(status, ==, "wait-unplug");
1160e1e3d321SLaurent Vivier     qobject_unref(ret);
1161e1e3d321SLaurent Vivier 
1162e1e3d321SLaurent Vivier     if (g_test_slow()) {
1163e1e3d321SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
1164e1e3d321SLaurent Vivier         for (int i = 0; i < 5; i++) {
1165e1e3d321SLaurent Vivier             sleep(1);
1166e1e3d321SLaurent Vivier             ret = migrate_status(qts);
1167e1e3d321SLaurent Vivier             status = qdict_get_str(ret, "status");
1168e1e3d321SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
1169e1e3d321SLaurent Vivier             qobject_unref(ret);
1170e1e3d321SLaurent Vivier         }
1171e1e3d321SLaurent Vivier     }
1172e1e3d321SLaurent Vivier 
1173e1e3d321SLaurent Vivier     /* OS unplugs primary0, QEMU can move from wait-unplug state */
1174e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
1175e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1176e1e3d321SLaurent Vivier 
1177e1e3d321SLaurent Vivier     while (true) {
1178e1e3d321SLaurent Vivier         ret = migrate_status(qts);
1179e1e3d321SLaurent Vivier 
1180e1e3d321SLaurent Vivier         status = qdict_get_str(ret, "status");
1181e1e3d321SLaurent Vivier         if (strcmp(status, "completed") == 0) {
1182e1e3d321SLaurent Vivier             qobject_unref(ret);
1183e1e3d321SLaurent Vivier             break;
1184e1e3d321SLaurent Vivier         }
1185e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1186e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1187e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1188e1e3d321SLaurent Vivier         qobject_unref(ret);
1189e1e3d321SLaurent Vivier     }
1190e1e3d321SLaurent Vivier 
1191e1e3d321SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
1192e1e3d321SLaurent Vivier 
1193e1e3d321SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev0);
1194e1e3d321SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev1);
1195e1e3d321SLaurent Vivier     machine_stop(qts);
1196e1e3d321SLaurent Vivier }
1197e1e3d321SLaurent Vivier 
1198e1e3d321SLaurent Vivier static void test_multi_in(gconstpointer opaque)
1199e1e3d321SLaurent Vivier {
1200e1e3d321SLaurent Vivier     QTestState *qts;
1201e1e3d321SLaurent Vivier     QDict *resp, *args, *ret;
1202e1e3d321SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1203e1e3d321SLaurent Vivier 
1204e1e3d321SLaurent Vivier     qts = machine_start(BASE_MACHINE
1205e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1206e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1207e1e3d321SLaurent Vivier                 "-netdev user,id=hs0 "
1208e1e3d321SLaurent Vivier                 "-netdev user,id=hs1 "
1209e1e3d321SLaurent Vivier                 "-netdev user,id=hs2 "
1210e1e3d321SLaurent Vivier                 "-netdev user,id=hs3 "
1211e1e3d321SLaurent Vivier                 "-incoming defer ",
1212e1e3d321SLaurent Vivier                 4);
1213e1e3d321SLaurent Vivier 
1214e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1215e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1216e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1217e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1218e1e3d321SLaurent Vivier 
1219e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1220e1e3d321SLaurent Vivier                          "{'bus': 'root0',"
1221e1e3d321SLaurent Vivier                          "'failover': 'on',"
1222e1e3d321SLaurent Vivier                          "'netdev': 'hs0',"
1223e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1224e1e3d321SLaurent Vivier 
1225e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1226e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1227e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1228e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1229e1e3d321SLaurent Vivier 
1230e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1231e1e3d321SLaurent Vivier                          "{'bus': 'root1',"
1232e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1233e1e3d321SLaurent Vivier                          "'netdev': 'hs1',"
1234e1e3d321SLaurent Vivier                          "'rombar': 0,"
1235e1e3d321SLaurent Vivier                          "'romfile': '',"
1236e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1237e1e3d321SLaurent Vivier 
1238e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1239e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1240e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1241e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1242e1e3d321SLaurent Vivier 
1243e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1244e1e3d321SLaurent Vivier                          "{'bus': 'root2',"
1245e1e3d321SLaurent Vivier                          "'failover': 'on',"
1246e1e3d321SLaurent Vivier                          "'netdev': 'hs2',"
1247e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY1"'}");
1248e1e3d321SLaurent Vivier 
1249e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1250e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1251e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1252e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1253e1e3d321SLaurent Vivier 
1254e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1255e1e3d321SLaurent Vivier                          "{'bus': 'root3',"
1256e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby1',"
1257e1e3d321SLaurent Vivier                          "'netdev': 'hs3',"
1258e1e3d321SLaurent Vivier                          "'rombar': 0,"
1259e1e3d321SLaurent Vivier                          "'romfile': '',"
1260e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY1"'}");
1261e1e3d321SLaurent Vivier 
1262e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1263e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1264e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1265e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1266e1e3d321SLaurent Vivier 
1267e1e3d321SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1268e1e3d321SLaurent Vivier     g_assert_nonnull(args);
1269e1e3d321SLaurent Vivier     qdict_put_str(args, "uri", uri);
1270e1e3d321SLaurent Vivier 
1271e1e3d321SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1272e1e3d321SLaurent Vivier                      args);
1273e1e3d321SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1274e1e3d321SLaurent Vivier     qobject_unref(resp);
1275e1e3d321SLaurent Vivier 
1276e1e3d321SLaurent Vivier     resp = get_migration_event(qts);
1277e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1278e1e3d321SLaurent Vivier     qobject_unref(resp);
1279e1e3d321SLaurent Vivier 
1280e1e3d321SLaurent Vivier     resp = get_failover_negociated_event(qts);
1281e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1282e1e3d321SLaurent Vivier     qobject_unref(resp);
1283e1e3d321SLaurent Vivier 
1284e1e3d321SLaurent Vivier     resp = get_failover_negociated_event(qts);
1285e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1286e1e3d321SLaurent Vivier     qobject_unref(resp);
1287e1e3d321SLaurent Vivier 
1288e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1289e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1290e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1291e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1292e1e3d321SLaurent Vivier 
1293e1e3d321SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
1294e1e3d321SLaurent Vivier 
1295e1e3d321SLaurent Vivier     ret = migrate_status(qts);
1296e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1297e1e3d321SLaurent Vivier     qobject_unref(ret);
1298e1e3d321SLaurent Vivier 
1299e1e3d321SLaurent Vivier     machine_stop(qts);
1300e1e3d321SLaurent Vivier }
1301e1e3d321SLaurent Vivier 
1302e32b96b5SLaurent Vivier int main(int argc, char **argv)
1303e32b96b5SLaurent Vivier {
1304e63ed64cSThomas Huth     gchar *tmpfile;
1305e32b96b5SLaurent Vivier     int ret;
1306e32b96b5SLaurent Vivier 
1307e32b96b5SLaurent Vivier     g_test_init(&argc, &argv, NULL);
1308e32b96b5SLaurent Vivier 
1309e63ed64cSThomas Huth     ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
1310e63ed64cSThomas Huth     g_assert_true(ret >= 0);
1311e63ed64cSThomas Huth     close(ret);
1312e63ed64cSThomas Huth 
1313fbd2913cSLaurent Vivier     /* parameters tests */
1314e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1315e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1316e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on", test_on);
1317e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on_mismatch",
1318e32b96b5SLaurent Vivier                    test_on_mismatch);
1319e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/off", test_off);
1320e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
1321fbd2913cSLaurent Vivier 
1322fbd2913cSLaurent Vivier     /* hotplug tests */
1323fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1);
1324fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/1_reverse",
1325e32b96b5SLaurent Vivier                    test_hotplug_1_reverse);
1326fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2);
1327fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/2_reverse",
1328e32b96b5SLaurent Vivier                    test_hotplug_2_reverse);
1329fbd2913cSLaurent Vivier 
1330fbd2913cSLaurent Vivier     /* migration tests */
1331fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile,
1332e32b96b5SLaurent Vivier                         test_migrate_out);
1333fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/on/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     }
1343fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/multi/out",
1344e1e3d321SLaurent Vivier                         tmpfile, test_multi_out);
1345fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/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