xref: /qemu/tests/qtest/virtio-net-failover.c (revision 1e2077e22332c4d2867043bbea2337d331106bfd)
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
23e32b96b5SLaurent Vivier 
24e32b96b5SLaurent Vivier #define BASE_MACHINE "-M q35 -nodefaults " \
25e32b96b5SLaurent Vivier     "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
26e32b96b5SLaurent Vivier     "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "
27e32b96b5SLaurent Vivier 
28e32b96b5SLaurent Vivier #define MAC_PRIMARY0 "52:54:00:11:11:11"
29e32b96b5SLaurent Vivier #define MAC_STANDBY0 "52:54:00:22:22:22"
30e32b96b5SLaurent Vivier 
31e32b96b5SLaurent Vivier static QGuestAllocator guest_malloc;
32e32b96b5SLaurent Vivier static QPCIBus *pcibus;
33e32b96b5SLaurent Vivier 
34e32b96b5SLaurent Vivier static QTestState *machine_start(const char *args, int numbus)
35e32b96b5SLaurent Vivier {
36e32b96b5SLaurent Vivier     QTestState *qts;
37e32b96b5SLaurent Vivier     QPCIDevice *dev;
38e32b96b5SLaurent Vivier     int bus;
39e32b96b5SLaurent Vivier 
40e32b96b5SLaurent Vivier     qts = qtest_init(args);
41e32b96b5SLaurent Vivier 
42e32b96b5SLaurent Vivier     pc_alloc_init(&guest_malloc, qts, 0);
43e32b96b5SLaurent Vivier     pcibus = qpci_new_pc(qts, &guest_malloc);
44e32b96b5SLaurent Vivier     g_assert(qpci_secondary_buses_init(pcibus) == numbus);
45e32b96b5SLaurent Vivier 
46e32b96b5SLaurent Vivier     for (bus = 1; bus <= numbus; bus++) {
47e32b96b5SLaurent Vivier         dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0));
48e32b96b5SLaurent Vivier         g_assert_nonnull(dev);
49e32b96b5SLaurent Vivier 
50e32b96b5SLaurent Vivier         qpci_device_enable(dev);
51e32b96b5SLaurent Vivier         qpci_iomap(dev, 4, NULL);
52e32b96b5SLaurent Vivier 
53e32b96b5SLaurent Vivier         g_free(dev);
54e32b96b5SLaurent Vivier     }
55e32b96b5SLaurent Vivier 
56e32b96b5SLaurent Vivier     return qts;
57e32b96b5SLaurent Vivier }
58e32b96b5SLaurent Vivier 
59e32b96b5SLaurent Vivier static void machine_stop(QTestState *qts)
60e32b96b5SLaurent Vivier {
61e32b96b5SLaurent Vivier     qpci_free_pc(pcibus);
62e32b96b5SLaurent Vivier     alloc_destroy(&guest_malloc);
63e32b96b5SLaurent Vivier     qtest_quit(qts);
64e32b96b5SLaurent Vivier }
65e32b96b5SLaurent Vivier 
66e32b96b5SLaurent Vivier static void test_error_id(void)
67e32b96b5SLaurent Vivier {
68e32b96b5SLaurent Vivier     QTestState *qts;
69e32b96b5SLaurent Vivier     QDict *resp;
70e32b96b5SLaurent Vivier     QDict *err;
71e32b96b5SLaurent Vivier 
72e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
73e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,failover=on",
74e32b96b5SLaurent Vivier                         2);
75e32b96b5SLaurent Vivier 
76e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{'execute': 'device_add',"
77e32b96b5SLaurent Vivier                           "'arguments': {"
78e32b96b5SLaurent Vivier                           "'driver': 'virtio-net',"
79e32b96b5SLaurent Vivier                           "'bus': 'root1',"
80e32b96b5SLaurent Vivier                           "'failover_pair_id': 'standby0'"
81e32b96b5SLaurent Vivier                           "} }");
82e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "error"));
83e32b96b5SLaurent Vivier 
84e32b96b5SLaurent Vivier     err = qdict_get_qdict(resp, "error");
85e32b96b5SLaurent Vivier     g_assert(qdict_haskey(err, "desc"));
86e32b96b5SLaurent Vivier 
87e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
88e32b96b5SLaurent Vivier                     "Device with failover_pair_id needs to have id");
89e32b96b5SLaurent Vivier 
90e32b96b5SLaurent Vivier     qobject_unref(resp);
91e32b96b5SLaurent Vivier 
92e32b96b5SLaurent Vivier     machine_stop(qts);
93e32b96b5SLaurent Vivier }
94e32b96b5SLaurent Vivier 
95e32b96b5SLaurent Vivier static void test_error_pcie(void)
96e32b96b5SLaurent Vivier {
97e32b96b5SLaurent Vivier     QTestState *qts;
98e32b96b5SLaurent Vivier     QDict *resp;
99e32b96b5SLaurent Vivier     QDict *err;
100e32b96b5SLaurent Vivier 
101e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
102e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,failover=on",
103e32b96b5SLaurent Vivier                         2);
104e32b96b5SLaurent Vivier 
105e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{'execute': 'device_add',"
106e32b96b5SLaurent Vivier                           "'arguments': {"
107e32b96b5SLaurent Vivier                           "'driver': 'virtio-net',"
108e32b96b5SLaurent Vivier                           "'id': 'primary0',"
109e32b96b5SLaurent Vivier                           "'bus': 'pcie.0',"
110e32b96b5SLaurent Vivier                           "'failover_pair_id': 'standby0'"
111e32b96b5SLaurent Vivier                           "} }");
112e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "error"));
113e32b96b5SLaurent Vivier 
114e32b96b5SLaurent Vivier     err = qdict_get_qdict(resp, "error");
115e32b96b5SLaurent Vivier     g_assert(qdict_haskey(err, "desc"));
116e32b96b5SLaurent Vivier 
117e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
118e32b96b5SLaurent Vivier                     "Bus 'pcie.0' does not support hotplugging");
119e32b96b5SLaurent Vivier 
120e32b96b5SLaurent Vivier     qobject_unref(resp);
121e32b96b5SLaurent Vivier 
122e32b96b5SLaurent Vivier     machine_stop(qts);
123e32b96b5SLaurent Vivier }
124e32b96b5SLaurent Vivier 
125e32b96b5SLaurent Vivier static QDict *find_device(QDict *bus, const char *name)
126e32b96b5SLaurent Vivier {
127e32b96b5SLaurent Vivier     const QObject *obj;
128e32b96b5SLaurent Vivier     QList *devices;
129e32b96b5SLaurent Vivier     QList *list;
130e32b96b5SLaurent Vivier 
131e32b96b5SLaurent Vivier     devices = qdict_get_qlist(bus, "devices");
132e32b96b5SLaurent Vivier     if (devices == NULL) {
133e32b96b5SLaurent Vivier         return NULL;
134e32b96b5SLaurent Vivier     }
135e32b96b5SLaurent Vivier 
136e32b96b5SLaurent Vivier     list = qlist_copy(devices);
137e32b96b5SLaurent Vivier     while ((obj = qlist_pop(list))) {
138e32b96b5SLaurent Vivier         QDict *device;
139e32b96b5SLaurent Vivier 
140e32b96b5SLaurent Vivier         device = qobject_to(QDict, obj);
141e32b96b5SLaurent Vivier 
142e32b96b5SLaurent Vivier         if (qdict_haskey(device, "pci_bridge")) {
143e32b96b5SLaurent Vivier             QDict *bridge;
144e32b96b5SLaurent Vivier             QDict *bridge_device;
145e32b96b5SLaurent Vivier 
146e32b96b5SLaurent Vivier             bridge = qdict_get_qdict(device, "pci_bridge");
147e32b96b5SLaurent Vivier 
148e32b96b5SLaurent Vivier             if (qdict_haskey(bridge, "devices")) {
149e32b96b5SLaurent Vivier                 bridge_device = find_device(bridge, name);
150e32b96b5SLaurent Vivier                 if (bridge_device) {
151e32b96b5SLaurent Vivier                     qobject_unref(device);
152e32b96b5SLaurent Vivier                     qobject_unref(list);
153e32b96b5SLaurent Vivier                     return bridge_device;
154e32b96b5SLaurent Vivier                 }
155e32b96b5SLaurent Vivier             }
156e32b96b5SLaurent Vivier         }
157e32b96b5SLaurent Vivier 
158e32b96b5SLaurent Vivier         if (!qdict_haskey(device, "qdev_id")) {
159e32b96b5SLaurent Vivier             qobject_unref(device);
160e32b96b5SLaurent Vivier             continue;
161e32b96b5SLaurent Vivier         }
162e32b96b5SLaurent Vivier 
163e32b96b5SLaurent Vivier         if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) {
164e32b96b5SLaurent Vivier             qobject_unref(list);
165e32b96b5SLaurent Vivier             return device;
166e32b96b5SLaurent Vivier         }
167e32b96b5SLaurent Vivier         qobject_unref(device);
168e32b96b5SLaurent Vivier     }
169e32b96b5SLaurent Vivier     qobject_unref(list);
170e32b96b5SLaurent Vivier 
171e32b96b5SLaurent Vivier     return NULL;
172e32b96b5SLaurent Vivier }
173e32b96b5SLaurent Vivier 
174e32b96b5SLaurent Vivier static QDict *get_bus(QTestState *qts, int num)
175e32b96b5SLaurent Vivier {
176e32b96b5SLaurent Vivier     QObject *obj;
177e32b96b5SLaurent Vivier     QDict *resp;
178e32b96b5SLaurent Vivier     QList *ret;
179e32b96b5SLaurent Vivier 
180e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }");
181e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
182e32b96b5SLaurent Vivier 
183e32b96b5SLaurent Vivier     ret = qdict_get_qlist(resp, "return");
184e32b96b5SLaurent Vivier     g_assert_nonnull(ret);
185e32b96b5SLaurent Vivier 
186e32b96b5SLaurent Vivier     while ((obj = qlist_pop(ret))) {
187e32b96b5SLaurent Vivier         QDict *bus;
188e32b96b5SLaurent Vivier 
189e32b96b5SLaurent Vivier         bus = qobject_to(QDict, obj);
190e32b96b5SLaurent Vivier         if (!qdict_haskey(bus, "bus")) {
191e32b96b5SLaurent Vivier             qobject_unref(bus);
192e32b96b5SLaurent Vivier             continue;
193e32b96b5SLaurent Vivier         }
194e32b96b5SLaurent Vivier         if (qdict_get_int(bus, "bus") == num) {
195e32b96b5SLaurent Vivier             qobject_unref(resp);
196e32b96b5SLaurent Vivier             return bus;
197e32b96b5SLaurent Vivier         }
198e32b96b5SLaurent Vivier         qobject_ref(bus);
199e32b96b5SLaurent Vivier     }
200e32b96b5SLaurent Vivier     qobject_unref(resp);
201e32b96b5SLaurent Vivier 
202e32b96b5SLaurent Vivier     return NULL;
203e32b96b5SLaurent Vivier }
204e32b96b5SLaurent Vivier 
205e32b96b5SLaurent Vivier static char *get_mac(QTestState *qts, const char *name)
206e32b96b5SLaurent Vivier {
207e32b96b5SLaurent Vivier     QDict *resp;
208e32b96b5SLaurent Vivier     char *mac;
209e32b96b5SLaurent Vivier 
210e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'qom-get', "
211e32b96b5SLaurent Vivier                      "'arguments': { "
212e32b96b5SLaurent Vivier                      "'path': %s, "
213e32b96b5SLaurent Vivier                      "'property': 'mac' } }", name);
214e32b96b5SLaurent Vivier 
215e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
216e32b96b5SLaurent Vivier 
217e32b96b5SLaurent Vivier     mac = g_strdup(qdict_get_str(resp, "return"));
218e32b96b5SLaurent Vivier 
219e32b96b5SLaurent Vivier     qobject_unref(resp);
220e32b96b5SLaurent Vivier 
221e32b96b5SLaurent Vivier     return mac;
222e32b96b5SLaurent Vivier }
223e32b96b5SLaurent Vivier 
224e32b96b5SLaurent Vivier static void check_one_card(QTestState *qts, bool present,
225e32b96b5SLaurent Vivier                            const char *id, const char *mac)
226e32b96b5SLaurent Vivier {
227e32b96b5SLaurent Vivier     QDict *device;
228e32b96b5SLaurent Vivier     QDict *bus;
229e32b96b5SLaurent Vivier     char *addr;
230e32b96b5SLaurent Vivier 
231e32b96b5SLaurent Vivier     bus = get_bus(qts, 0);
232e32b96b5SLaurent Vivier     device = find_device(bus, id);
233e32b96b5SLaurent Vivier     if (present) {
234e32b96b5SLaurent Vivier         char *path;
235e32b96b5SLaurent Vivier 
236e32b96b5SLaurent Vivier         g_assert_nonnull(device);
237e32b96b5SLaurent Vivier         qobject_unref(device);
238e32b96b5SLaurent Vivier 
239e32b96b5SLaurent Vivier         path = g_strdup_printf("/machine/peripheral/%s", id);
240e32b96b5SLaurent Vivier         addr = get_mac(qts, path);
241e32b96b5SLaurent Vivier         g_free(path);
242e32b96b5SLaurent Vivier         g_assert_cmpstr(mac, ==, addr);
243e32b96b5SLaurent Vivier         g_free(addr);
244e32b96b5SLaurent Vivier     } else {
245e32b96b5SLaurent Vivier        g_assert_null(device);
246e32b96b5SLaurent Vivier     }
247e32b96b5SLaurent Vivier 
248e32b96b5SLaurent Vivier     qobject_unref(bus);
249e32b96b5SLaurent Vivier }
250e32b96b5SLaurent Vivier 
251e32b96b5SLaurent Vivier static void test_on(void)
252e32b96b5SLaurent Vivier {
253e32b96b5SLaurent Vivier     QTestState *qts;
254e32b96b5SLaurent Vivier 
255e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
256e32b96b5SLaurent Vivier                         "-netdev user,id=hs0 "
257e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,"
258e32b96b5SLaurent Vivier                         "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
259e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root1,id=primary0,"
260e32b96b5SLaurent Vivier                         "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
261e32b96b5SLaurent Vivier                         2);
262e32b96b5SLaurent Vivier 
263e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
264e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
265e32b96b5SLaurent Vivier 
266e32b96b5SLaurent Vivier     machine_stop(qts);
267e32b96b5SLaurent Vivier }
268e32b96b5SLaurent Vivier 
269e32b96b5SLaurent Vivier static void test_on_mismatch(void)
270e32b96b5SLaurent Vivier {
271e32b96b5SLaurent Vivier     QTestState *qts;
272e32b96b5SLaurent Vivier 
273e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
274e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
275e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
276e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
277e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
278e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
279e32b96b5SLaurent Vivier                      "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0,
280e32b96b5SLaurent Vivier                      2);
281e32b96b5SLaurent Vivier 
282e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
283e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
284e32b96b5SLaurent Vivier 
285e32b96b5SLaurent Vivier     machine_stop(qts);
286e32b96b5SLaurent Vivier }
287e32b96b5SLaurent Vivier 
288e32b96b5SLaurent Vivier static void test_off(void)
289e32b96b5SLaurent Vivier {
290e32b96b5SLaurent Vivier     QTestState *qts;
291e32b96b5SLaurent Vivier 
292e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
293e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
294e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
295e32b96b5SLaurent Vivier                      "failover=off,netdev=hs0,mac="MAC_STANDBY0" "
296e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
297e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
298e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
299e32b96b5SLaurent Vivier                      2);
300e32b96b5SLaurent Vivier 
301e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
302e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
303e32b96b5SLaurent Vivier 
304e32b96b5SLaurent Vivier     machine_stop(qts);
305e32b96b5SLaurent Vivier }
306e32b96b5SLaurent Vivier 
307e32b96b5SLaurent Vivier static QDict *get_failover_negociated_event(QTestState *qts)
308e32b96b5SLaurent Vivier {
309e32b96b5SLaurent Vivier     QDict *resp;
310e32b96b5SLaurent Vivier     QDict *data;
311e32b96b5SLaurent Vivier 
312e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED");
313e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
314e32b96b5SLaurent Vivier 
315e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
316e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
317e32b96b5SLaurent Vivier     qobject_ref(data);
318e32b96b5SLaurent Vivier     qobject_unref(resp);
319e32b96b5SLaurent Vivier 
320e32b96b5SLaurent Vivier     return data;
321e32b96b5SLaurent Vivier }
322e32b96b5SLaurent Vivier 
323e32b96b5SLaurent Vivier static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
324e32b96b5SLaurent Vivier                              const char *id)
325e32b96b5SLaurent Vivier {
326e32b96b5SLaurent Vivier     QVirtioPCIDevice *dev;
327e32b96b5SLaurent Vivier     uint64_t features;
328e32b96b5SLaurent Vivier     QPCIAddress addr;
329e32b96b5SLaurent Vivier     QDict *resp;
330e32b96b5SLaurent Vivier 
331e32b96b5SLaurent Vivier     addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0);
332e32b96b5SLaurent Vivier     dev = virtio_pci_new(pcibus, &addr);
333e32b96b5SLaurent Vivier     g_assert_nonnull(dev);
334e32b96b5SLaurent Vivier     qvirtio_pci_device_enable(dev);
335e32b96b5SLaurent Vivier     qvirtio_start_device(&dev->vdev);
336e32b96b5SLaurent Vivier     features = qvirtio_get_features(&dev->vdev);
337e32b96b5SLaurent Vivier     features = features & ~(QVIRTIO_F_BAD_FEATURE |
338e32b96b5SLaurent Vivier                             (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
339e32b96b5SLaurent Vivier                             (1ull << VIRTIO_RING_F_EVENT_IDX));
340e32b96b5SLaurent Vivier     qvirtio_set_features(&dev->vdev, features);
341e32b96b5SLaurent Vivier     qvirtio_set_driver_ok(&dev->vdev);
342e32b96b5SLaurent Vivier 
343e32b96b5SLaurent Vivier     resp = get_failover_negociated_event(qts);
344e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
345e32b96b5SLaurent Vivier     qobject_unref(resp);
346e32b96b5SLaurent Vivier 
347e32b96b5SLaurent Vivier     return dev;
348e32b96b5SLaurent Vivier }
349e32b96b5SLaurent Vivier 
350e32b96b5SLaurent Vivier static void test_enabled(void)
351e32b96b5SLaurent Vivier {
352e32b96b5SLaurent Vivier     QTestState *qts;
353e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
354e32b96b5SLaurent Vivier 
355e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
356e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
357e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
358e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
359e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
360e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
361e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
362e32b96b5SLaurent Vivier                      2);
363e32b96b5SLaurent Vivier 
364e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
365e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
366e32b96b5SLaurent Vivier 
367e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
368e32b96b5SLaurent Vivier 
369e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
370e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
371e32b96b5SLaurent Vivier 
372e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
373e32b96b5SLaurent Vivier     machine_stop(qts);
374e32b96b5SLaurent Vivier }
375e32b96b5SLaurent Vivier 
376e32b96b5SLaurent Vivier static void test_hotplug_1(void)
377e32b96b5SLaurent Vivier {
378e32b96b5SLaurent Vivier     QTestState *qts;
379e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
380e32b96b5SLaurent Vivier 
381e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
382e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
383e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
384e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
385e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ", 2);
386e32b96b5SLaurent Vivier 
387e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
388e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
389e32b96b5SLaurent Vivier 
390e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
391e32b96b5SLaurent Vivier 
392e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
393e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
394e32b96b5SLaurent Vivier 
395e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
396e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
397e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
398e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
399e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
400e32b96b5SLaurent Vivier 
401e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
402e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
403e32b96b5SLaurent Vivier 
404e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
405e32b96b5SLaurent Vivier     machine_stop(qts);
406e32b96b5SLaurent Vivier }
407e32b96b5SLaurent Vivier 
408e32b96b5SLaurent Vivier static void test_hotplug_1_reverse(void)
409e32b96b5SLaurent Vivier {
410e32b96b5SLaurent Vivier     QTestState *qts;
411e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
412e32b96b5SLaurent Vivier 
413e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
414e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
415e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
416e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
417e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
418e32b96b5SLaurent Vivier                      2);
419e32b96b5SLaurent Vivier 
420e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
421e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
422e32b96b5SLaurent Vivier 
423e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
424e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
425e32b96b5SLaurent Vivier                          "'failover': 'on',"
426e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
427e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
428e32b96b5SLaurent Vivier 
429e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
430e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
431e32b96b5SLaurent Vivier 
432e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
433e32b96b5SLaurent Vivier 
434e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
435e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
436e32b96b5SLaurent Vivier 
437e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
438e32b96b5SLaurent Vivier     machine_stop(qts);
439e32b96b5SLaurent Vivier }
440e32b96b5SLaurent Vivier 
441e32b96b5SLaurent Vivier static void test_hotplug_2(void)
442e32b96b5SLaurent Vivier {
443e32b96b5SLaurent Vivier     QTestState *qts;
444e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
445e32b96b5SLaurent Vivier 
446e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
447e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
448e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
449e32b96b5SLaurent Vivier                      2);
450e32b96b5SLaurent Vivier 
451e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
452e32b96b5SLaurent Vivier     check_one_card(qts, false, "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, false, "primary0", MAC_PRIMARY0);
462e32b96b5SLaurent Vivier 
463e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
464e32b96b5SLaurent Vivier 
465e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
466e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
467e32b96b5SLaurent Vivier 
468e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
469e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
470e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
471e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
472e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
473e32b96b5SLaurent Vivier 
474e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
475e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
476e32b96b5SLaurent Vivier 
477e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
478e32b96b5SLaurent Vivier     machine_stop(qts);
479e32b96b5SLaurent Vivier }
480e32b96b5SLaurent Vivier 
481e32b96b5SLaurent Vivier static void test_hotplug_2_reverse(void)
482e32b96b5SLaurent Vivier {
483e32b96b5SLaurent Vivier     QTestState *qts;
484e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
485e32b96b5SLaurent Vivier 
486e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
487e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
488e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
489e32b96b5SLaurent Vivier                      2);
490e32b96b5SLaurent Vivier 
491e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
492e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
493e32b96b5SLaurent Vivier 
494e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
495e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
496e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
497e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
498e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
499e32b96b5SLaurent Vivier 
500e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
501e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
502e32b96b5SLaurent Vivier 
503e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
504e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
505e32b96b5SLaurent Vivier                          "'failover': 'on',"
506e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
507e32b96b5SLaurent Vivier                          "'rombar': 0,"
508e32b96b5SLaurent Vivier                          "'romfile': '',"
509e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
510e32b96b5SLaurent Vivier 
511e32b96b5SLaurent Vivier     /*
512e32b96b5SLaurent Vivier      * XXX: sounds like a bug:
513e32b96b5SLaurent Vivier      * The primary should be hidden until the virtio-net driver
514e32b96b5SLaurent Vivier      * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
515e32b96b5SLaurent Vivier      */
516e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
517e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
518e32b96b5SLaurent Vivier 
519e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
520e32b96b5SLaurent Vivier 
521e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
522e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
523e32b96b5SLaurent Vivier 
524e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
525e32b96b5SLaurent Vivier     machine_stop(qts);
526e32b96b5SLaurent Vivier }
527e32b96b5SLaurent Vivier 
528e32b96b5SLaurent Vivier static QDict *migrate_status(QTestState *qts)
529e32b96b5SLaurent Vivier {
530e32b96b5SLaurent Vivier     QDict *resp, *ret;
531e32b96b5SLaurent Vivier 
532e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
533e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
534e32b96b5SLaurent Vivier 
535e32b96b5SLaurent Vivier     ret = qdict_get_qdict(resp, "return");
536e32b96b5SLaurent Vivier     g_assert(qdict_haskey(ret, "status"));
537e32b96b5SLaurent Vivier     qobject_ref(ret);
538e32b96b5SLaurent Vivier     qobject_unref(resp);
539e32b96b5SLaurent Vivier 
540e32b96b5SLaurent Vivier     return ret;
541e32b96b5SLaurent Vivier }
542e32b96b5SLaurent Vivier 
543e32b96b5SLaurent Vivier static QDict *get_unplug_primary_event(QTestState *qts)
544e32b96b5SLaurent Vivier {
545e32b96b5SLaurent Vivier     QDict *resp;
546e32b96b5SLaurent Vivier     QDict *data;
547e32b96b5SLaurent Vivier 
548e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
549e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
550e32b96b5SLaurent Vivier 
551e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
552e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
553e32b96b5SLaurent Vivier     qobject_ref(data);
554e32b96b5SLaurent Vivier     qobject_unref(resp);
555e32b96b5SLaurent Vivier 
556e32b96b5SLaurent Vivier     return data;
557e32b96b5SLaurent Vivier }
558e32b96b5SLaurent Vivier 
559e32b96b5SLaurent Vivier static void test_migrate_out(gconstpointer opaque)
560e32b96b5SLaurent Vivier {
561e32b96b5SLaurent Vivier     QTestState *qts;
562e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
563e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
564e32b96b5SLaurent Vivier     const gchar *status;
565e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
566e32b96b5SLaurent Vivier 
567e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
568e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
569e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
570e32b96b5SLaurent Vivier                      2);
571e32b96b5SLaurent Vivier 
572e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
573e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
574e32b96b5SLaurent Vivier 
575e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
576e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
577e32b96b5SLaurent Vivier                          "'failover': 'on',"
578e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
579e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
580e32b96b5SLaurent Vivier 
581e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
582e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
583e32b96b5SLaurent Vivier 
584e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
585e32b96b5SLaurent Vivier 
586e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
587e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
588e32b96b5SLaurent Vivier 
589e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
590e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
591e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
592e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
593e32b96b5SLaurent Vivier                          "'rombar': 0,"
594e32b96b5SLaurent Vivier                          "'romfile': '',"
595e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
596e32b96b5SLaurent Vivier 
597e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
598e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
599e32b96b5SLaurent Vivier 
600e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
601e32b96b5SLaurent Vivier     g_assert_nonnull(args);
602e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
603e32b96b5SLaurent Vivier 
604e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
605e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
606e32b96b5SLaurent Vivier     qobject_unref(resp);
607e32b96b5SLaurent Vivier 
608e32b96b5SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
609e32b96b5SLaurent Vivier     resp = get_unplug_primary_event(qts);
610e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
611e32b96b5SLaurent Vivier     qobject_unref(resp);
612e32b96b5SLaurent Vivier 
613e32b96b5SLaurent Vivier     /* wait the end of the migration setup phase */
614e32b96b5SLaurent Vivier     while (true) {
615e32b96b5SLaurent Vivier         ret = migrate_status(qts);
616e32b96b5SLaurent Vivier 
617e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
618e32b96b5SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
619e32b96b5SLaurent Vivier             qobject_unref(ret);
620e32b96b5SLaurent Vivier             break;
621e32b96b5SLaurent Vivier         }
622e32b96b5SLaurent Vivier 
623e32b96b5SLaurent Vivier         /* The migration must not start if the card is not ejected */
624e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
625e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
626e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
627e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
628e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
629e32b96b5SLaurent Vivier 
630e32b96b5SLaurent Vivier         qobject_unref(ret);
631e32b96b5SLaurent Vivier     }
632e32b96b5SLaurent Vivier 
633e32b96b5SLaurent Vivier     if (g_test_slow()) {
634e32b96b5SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
635e32b96b5SLaurent Vivier         for (int i = 0; i < 5; i++) {
636e32b96b5SLaurent Vivier             sleep(1);
637e32b96b5SLaurent Vivier             ret = migrate_status(qts);
638e32b96b5SLaurent Vivier             status = qdict_get_str(ret, "status");
639e32b96b5SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
640e32b96b5SLaurent Vivier             qobject_unref(ret);
641e32b96b5SLaurent Vivier         }
642e32b96b5SLaurent Vivier     }
643e32b96b5SLaurent Vivier 
644e32b96b5SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
645e32b96b5SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
646e32b96b5SLaurent Vivier 
647e32b96b5SLaurent Vivier     while (true) {
648e32b96b5SLaurent Vivier         ret = migrate_status(qts);
649e32b96b5SLaurent Vivier 
650e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
651e32b96b5SLaurent Vivier         if (strcmp(status, "completed") == 0) {
652e32b96b5SLaurent Vivier             qobject_unref(ret);
653e32b96b5SLaurent Vivier             break;
654e32b96b5SLaurent Vivier         }
655e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
656e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
657e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
658e32b96b5SLaurent Vivier         qobject_unref(ret);
659e32b96b5SLaurent Vivier     }
660e32b96b5SLaurent Vivier 
661e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
662e32b96b5SLaurent Vivier 
663e32b96b5SLaurent Vivier     /*
664e32b96b5SLaurent Vivier      * in fact, the card is ejected from the point of view of kernel
665e32b96b5SLaurent Vivier      * but not really from QEMU to be able to hotplug it back if
666e32b96b5SLaurent Vivier      * migration fails. So we can't check that:
667e32b96b5SLaurent Vivier      *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
668e32b96b5SLaurent Vivier      *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
669e32b96b5SLaurent Vivier      */
670e32b96b5SLaurent Vivier 
671e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
672e32b96b5SLaurent Vivier     machine_stop(qts);
673e32b96b5SLaurent Vivier }
674e32b96b5SLaurent Vivier 
675e32b96b5SLaurent Vivier static QDict *get_migration_event(QTestState *qts)
676e32b96b5SLaurent Vivier {
677e32b96b5SLaurent Vivier     QDict *resp;
678e32b96b5SLaurent Vivier     QDict *data;
679e32b96b5SLaurent Vivier 
680e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "MIGRATION");
681e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
682e32b96b5SLaurent Vivier 
683e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
684e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "status"));
685e32b96b5SLaurent Vivier     qobject_ref(data);
686e32b96b5SLaurent Vivier     qobject_unref(resp);
687e32b96b5SLaurent Vivier 
688e32b96b5SLaurent Vivier     return data;
689e32b96b5SLaurent Vivier }
690e32b96b5SLaurent Vivier 
691e32b96b5SLaurent Vivier static void test_migrate_in(gconstpointer opaque)
692e32b96b5SLaurent Vivier {
693e32b96b5SLaurent Vivier     QTestState *qts;
694e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
695e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
696e32b96b5SLaurent Vivier 
697e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
698e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
699e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
700e32b96b5SLaurent Vivier                      "-incoming defer ",
701e32b96b5SLaurent Vivier                      2);
702e32b96b5SLaurent Vivier 
703e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
704e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
705e32b96b5SLaurent Vivier 
706e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
707e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
708e32b96b5SLaurent Vivier                          "'failover': 'on',"
709e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
710e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
711e32b96b5SLaurent Vivier 
712e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
713e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
714e32b96b5SLaurent Vivier 
715e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
716e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
717e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
718e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
719e32b96b5SLaurent Vivier                          "'rombar': 0,"
720e32b96b5SLaurent Vivier                          "'romfile': '',"
721e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
722e32b96b5SLaurent Vivier 
723e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
724e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
725e32b96b5SLaurent Vivier 
726e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
727e32b96b5SLaurent Vivier     g_assert_nonnull(args);
728e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
729e32b96b5SLaurent Vivier 
730e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
731e32b96b5SLaurent Vivier                      args);
732e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
733e32b96b5SLaurent Vivier     qobject_unref(resp);
734e32b96b5SLaurent Vivier 
735e32b96b5SLaurent Vivier     resp = get_migration_event(qts);
736e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
737e32b96b5SLaurent Vivier     qobject_unref(resp);
738e32b96b5SLaurent Vivier 
739e32b96b5SLaurent Vivier     resp = get_failover_negociated_event(qts);
740e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
741e32b96b5SLaurent Vivier     qobject_unref(resp);
742e32b96b5SLaurent Vivier 
743e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
744e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
745e32b96b5SLaurent Vivier 
746e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
747e32b96b5SLaurent Vivier 
748e32b96b5SLaurent Vivier     ret = migrate_status(qts);
749e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
750e32b96b5SLaurent Vivier     qobject_unref(ret);
751e32b96b5SLaurent Vivier 
752e32b96b5SLaurent Vivier     machine_stop(qts);
753e32b96b5SLaurent Vivier }
754e32b96b5SLaurent Vivier 
755*1e2077e2SLaurent Vivier static void test_migrate_abort_wait_unplug(gconstpointer opaque)
756*1e2077e2SLaurent Vivier {
757*1e2077e2SLaurent Vivier     QTestState *qts;
758*1e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
759*1e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
760*1e2077e2SLaurent Vivier     const gchar *status;
761*1e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
762*1e2077e2SLaurent Vivier 
763*1e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
764*1e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
765*1e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
766*1e2077e2SLaurent Vivier                      2);
767*1e2077e2SLaurent Vivier 
768*1e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
769*1e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
770*1e2077e2SLaurent Vivier 
771*1e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
772*1e2077e2SLaurent Vivier                          "{'bus': 'root0',"
773*1e2077e2SLaurent Vivier                          "'failover': 'on',"
774*1e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
775*1e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
776*1e2077e2SLaurent Vivier 
777*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
778*1e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
779*1e2077e2SLaurent Vivier 
780*1e2077e2SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
781*1e2077e2SLaurent Vivier 
782*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
783*1e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
784*1e2077e2SLaurent Vivier 
785*1e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
786*1e2077e2SLaurent Vivier                          "{'bus': 'root1',"
787*1e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
788*1e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
789*1e2077e2SLaurent Vivier                          "'rombar': 0,"
790*1e2077e2SLaurent Vivier                          "'romfile': '',"
791*1e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
792*1e2077e2SLaurent Vivier 
793*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
794*1e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
795*1e2077e2SLaurent Vivier 
796*1e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
797*1e2077e2SLaurent Vivier     g_assert_nonnull(args);
798*1e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
799*1e2077e2SLaurent Vivier 
800*1e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
801*1e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
802*1e2077e2SLaurent Vivier     qobject_unref(resp);
803*1e2077e2SLaurent Vivier 
804*1e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
805*1e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
806*1e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
807*1e2077e2SLaurent Vivier     qobject_unref(resp);
808*1e2077e2SLaurent Vivier 
809*1e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
810*1e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
811*1e2077e2SLaurent Vivier     qobject_unref(resp);
812*1e2077e2SLaurent Vivier 
813*1e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
814*1e2077e2SLaurent Vivier 
815*1e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
816*1e2077e2SLaurent Vivier     ret = migrate_status(qts);
817*1e2077e2SLaurent Vivier 
818*1e2077e2SLaurent Vivier     status = qdict_get_str(ret, "status");
819*1e2077e2SLaurent Vivier     g_assert_cmpstr(status, ==, "cancelling");
820*1e2077e2SLaurent Vivier     qobject_unref(ret);
821*1e2077e2SLaurent Vivier 
822*1e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
823*1e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
824*1e2077e2SLaurent Vivier 
825*1e2077e2SLaurent Vivier     while (true) {
826*1e2077e2SLaurent Vivier         ret = migrate_status(qts);
827*1e2077e2SLaurent Vivier 
828*1e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
829*1e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
830*1e2077e2SLaurent Vivier             qobject_unref(ret);
831*1e2077e2SLaurent Vivier             break;
832*1e2077e2SLaurent Vivier         }
833*1e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
834*1e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
835*1e2077e2SLaurent Vivier         qobject_unref(ret);
836*1e2077e2SLaurent Vivier     }
837*1e2077e2SLaurent Vivier 
838*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
839*1e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
840*1e2077e2SLaurent Vivier 
841*1e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
842*1e2077e2SLaurent Vivier     machine_stop(qts);
843*1e2077e2SLaurent Vivier }
844*1e2077e2SLaurent Vivier 
845*1e2077e2SLaurent Vivier static void test_migrate_abort_active(gconstpointer opaque)
846*1e2077e2SLaurent Vivier {
847*1e2077e2SLaurent Vivier     QTestState *qts;
848*1e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
849*1e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
850*1e2077e2SLaurent Vivier     const gchar *status;
851*1e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
852*1e2077e2SLaurent Vivier 
853*1e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
854*1e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
855*1e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
856*1e2077e2SLaurent Vivier                      2);
857*1e2077e2SLaurent Vivier 
858*1e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
859*1e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
860*1e2077e2SLaurent Vivier 
861*1e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
862*1e2077e2SLaurent Vivier                          "{'bus': 'root0',"
863*1e2077e2SLaurent Vivier                          "'failover': 'on',"
864*1e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
865*1e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
866*1e2077e2SLaurent Vivier 
867*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
868*1e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
869*1e2077e2SLaurent Vivier 
870*1e2077e2SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
871*1e2077e2SLaurent Vivier 
872*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
873*1e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
874*1e2077e2SLaurent Vivier 
875*1e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
876*1e2077e2SLaurent Vivier                          "{'bus': 'root1',"
877*1e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
878*1e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
879*1e2077e2SLaurent Vivier                          "'rombar': 0,"
880*1e2077e2SLaurent Vivier                          "'romfile': '',"
881*1e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
882*1e2077e2SLaurent Vivier 
883*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
884*1e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
885*1e2077e2SLaurent Vivier 
886*1e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
887*1e2077e2SLaurent Vivier     g_assert_nonnull(args);
888*1e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
889*1e2077e2SLaurent Vivier 
890*1e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
891*1e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
892*1e2077e2SLaurent Vivier     qobject_unref(resp);
893*1e2077e2SLaurent Vivier 
894*1e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
895*1e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
896*1e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
897*1e2077e2SLaurent Vivier     qobject_unref(resp);
898*1e2077e2SLaurent Vivier 
899*1e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
900*1e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
901*1e2077e2SLaurent Vivier 
902*1e2077e2SLaurent Vivier     while (true) {
903*1e2077e2SLaurent Vivier         ret = migrate_status(qts);
904*1e2077e2SLaurent Vivier 
905*1e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
906*1e2077e2SLaurent Vivier         if (strcmp(status, "wait-unplug") != 0) {
907*1e2077e2SLaurent Vivier             qobject_unref(ret);
908*1e2077e2SLaurent Vivier             break;
909*1e2077e2SLaurent Vivier         }
910*1e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
911*1e2077e2SLaurent Vivier         qobject_unref(ret);
912*1e2077e2SLaurent Vivier     }
913*1e2077e2SLaurent Vivier 
914*1e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
915*1e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
916*1e2077e2SLaurent Vivier     qobject_unref(resp);
917*1e2077e2SLaurent Vivier 
918*1e2077e2SLaurent Vivier     while (true) {
919*1e2077e2SLaurent Vivier         ret = migrate_status(qts);
920*1e2077e2SLaurent Vivier 
921*1e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
922*1e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
923*1e2077e2SLaurent Vivier             qobject_unref(ret);
924*1e2077e2SLaurent Vivier             break;
925*1e2077e2SLaurent Vivier         }
926*1e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
927*1e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
928*1e2077e2SLaurent Vivier         qobject_unref(ret);
929*1e2077e2SLaurent Vivier     }
930*1e2077e2SLaurent Vivier 
931*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
932*1e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
933*1e2077e2SLaurent Vivier 
934*1e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
935*1e2077e2SLaurent Vivier     machine_stop(qts);
936*1e2077e2SLaurent Vivier }
937*1e2077e2SLaurent Vivier 
938*1e2077e2SLaurent Vivier static void test_migrate_abort_timeout(gconstpointer opaque)
939*1e2077e2SLaurent Vivier {
940*1e2077e2SLaurent Vivier     QTestState *qts;
941*1e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
942*1e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
943*1e2077e2SLaurent Vivier     const gchar *status;
944*1e2077e2SLaurent Vivier     int total;
945*1e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
946*1e2077e2SLaurent Vivier 
947*1e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
948*1e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
949*1e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
950*1e2077e2SLaurent Vivier                      2);
951*1e2077e2SLaurent Vivier 
952*1e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
953*1e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
954*1e2077e2SLaurent Vivier 
955*1e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
956*1e2077e2SLaurent Vivier                          "{'bus': 'root0',"
957*1e2077e2SLaurent Vivier                          "'failover': 'on',"
958*1e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
959*1e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
960*1e2077e2SLaurent Vivier 
961*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
962*1e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
963*1e2077e2SLaurent Vivier 
964*1e2077e2SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
965*1e2077e2SLaurent Vivier 
966*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
967*1e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
968*1e2077e2SLaurent Vivier 
969*1e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
970*1e2077e2SLaurent Vivier                          "{'bus': 'root1',"
971*1e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
972*1e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
973*1e2077e2SLaurent Vivier                          "'rombar': 0,"
974*1e2077e2SLaurent Vivier                          "'romfile': '',"
975*1e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
976*1e2077e2SLaurent Vivier 
977*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
978*1e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
979*1e2077e2SLaurent Vivier 
980*1e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
981*1e2077e2SLaurent Vivier     g_assert_nonnull(args);
982*1e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
983*1e2077e2SLaurent Vivier 
984*1e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
985*1e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
986*1e2077e2SLaurent Vivier     qobject_unref(resp);
987*1e2077e2SLaurent Vivier 
988*1e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
989*1e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
990*1e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
991*1e2077e2SLaurent Vivier     qobject_unref(resp);
992*1e2077e2SLaurent Vivier 
993*1e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
994*1e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
995*1e2077e2SLaurent Vivier     qobject_unref(resp);
996*1e2077e2SLaurent Vivier 
997*1e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
998*1e2077e2SLaurent Vivier 
999*1e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
1000*1e2077e2SLaurent Vivier 
1001*1e2077e2SLaurent Vivier     total = 0;
1002*1e2077e2SLaurent Vivier     while (true) {
1003*1e2077e2SLaurent Vivier         ret = migrate_status(qts);
1004*1e2077e2SLaurent Vivier 
1005*1e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
1006*1e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
1007*1e2077e2SLaurent Vivier             qobject_unref(ret);
1008*1e2077e2SLaurent Vivier             break;
1009*1e2077e2SLaurent Vivier         }
1010*1e2077e2SLaurent Vivier         g_assert_cmpstr(status, ==, "cancelling");
1011*1e2077e2SLaurent Vivier         g_assert(qdict_haskey(ret, "total-time"));
1012*1e2077e2SLaurent Vivier         total = qdict_get_int(ret, "total-time");
1013*1e2077e2SLaurent Vivier         qobject_unref(ret);
1014*1e2077e2SLaurent Vivier     }
1015*1e2077e2SLaurent Vivier 
1016*1e2077e2SLaurent Vivier     /*
1017*1e2077e2SLaurent Vivier      * migration timeout in this case is 30 seconds
1018*1e2077e2SLaurent Vivier      * check we exit on the timeout (ms)
1019*1e2077e2SLaurent Vivier      */
1020*1e2077e2SLaurent Vivier     g_assert_cmpint(total, >, 30000);
1021*1e2077e2SLaurent Vivier 
1022*1e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1023*1e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1024*1e2077e2SLaurent Vivier 
1025*1e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
1026*1e2077e2SLaurent Vivier     machine_stop(qts);
1027*1e2077e2SLaurent Vivier }
1028*1e2077e2SLaurent Vivier 
1029e32b96b5SLaurent Vivier int main(int argc, char **argv)
1030e32b96b5SLaurent Vivier {
1031e32b96b5SLaurent Vivier     const gchar *tmpdir = g_get_tmp_dir();
1032e32b96b5SLaurent Vivier     gchar *tmpfile = g_strdup_printf("%s/failover_test_migrate-%u-%u",
1033e32b96b5SLaurent Vivier                                      tmpdir, getpid(), g_test_rand_int());
1034e32b96b5SLaurent Vivier     int ret;
1035e32b96b5SLaurent Vivier 
1036e32b96b5SLaurent Vivier     g_test_init(&argc, &argv, NULL);
1037e32b96b5SLaurent Vivier 
1038e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1039e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1040e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on", test_on);
1041e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on_mismatch",
1042e32b96b5SLaurent Vivier                    test_on_mismatch);
1043e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/off", test_off);
1044e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
1045e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_1", test_hotplug_1);
1046e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_1_reverse",
1047e32b96b5SLaurent Vivier                    test_hotplug_1_reverse);
1048e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_2", test_hotplug_2);
1049e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_2_reverse",
1050e32b96b5SLaurent Vivier                    test_hotplug_2_reverse);
1051e32b96b5SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/out", tmpfile,
1052e32b96b5SLaurent Vivier                         test_migrate_out);
1053e32b96b5SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/in", tmpfile,
1054e32b96b5SLaurent Vivier                         test_migrate_in);
1055*1e2077e2SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
1056*1e2077e2SLaurent Vivier                         tmpfile, test_migrate_abort_wait_unplug);
1057*1e2077e2SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
1058*1e2077e2SLaurent Vivier                         test_migrate_abort_active);
1059*1e2077e2SLaurent Vivier     if (g_test_slow()) {
1060*1e2077e2SLaurent Vivier         qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
1061*1e2077e2SLaurent Vivier                             tmpfile, test_migrate_abort_timeout);
1062*1e2077e2SLaurent Vivier     }
1063e32b96b5SLaurent Vivier 
1064e32b96b5SLaurent Vivier     ret = g_test_run();
1065e32b96b5SLaurent Vivier 
1066e32b96b5SLaurent Vivier     unlink(tmpfile);
1067e32b96b5SLaurent Vivier     g_free(tmpfile);
1068e32b96b5SLaurent Vivier 
1069e32b96b5SLaurent Vivier     return ret;
1070e32b96b5SLaurent Vivier }
1071