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