xref: /qemu/tests/qtest/virtio-net-failover.c (revision b7d7f723a9853a68a648075a1f2ab96d410e929e)
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"
11907b5105SMarc-André Lureau #include "libqtest.h"
12e32b96b5SLaurent Vivier #include "libqos/pci.h"
13e32b96b5SLaurent Vivier #include "libqos/pci-pc.h"
14e6c57040SFabiano Rosas #include "migration/migration-qmp.h"
15*b7d7f723SFabiano Rosas #include "migration/migration-util.h"
16e32b96b5SLaurent Vivier #include "qapi/qmp/qdict.h"
17e32b96b5SLaurent Vivier #include "qapi/qmp/qlist.h"
18e32b96b5SLaurent Vivier #include "qapi/qmp/qjson.h"
19e32b96b5SLaurent Vivier #include "libqos/malloc-pc.h"
20e32b96b5SLaurent Vivier #include "libqos/virtio-pci.h"
21e32b96b5SLaurent Vivier #include "hw/pci/pci.h"
22e32b96b5SLaurent Vivier 
2393262464SLaurent Vivier #define VIRTIO_NET_F_STANDBY    62
2493262464SLaurent Vivier 
25e32b96b5SLaurent Vivier #define ACPI_PCIHP_ADDR_ICH9    0x0cc0
26e32b96b5SLaurent Vivier #define PCI_EJ_BASE             0x0008
27e1e3d321SLaurent Vivier #define PCI_SEL_BASE            0x0010
28e32b96b5SLaurent Vivier 
29e32b96b5SLaurent Vivier #define BASE_MACHINE "-M q35 -nodefaults " \
30e32b96b5SLaurent Vivier     "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
31e32b96b5SLaurent Vivier     "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "
32e32b96b5SLaurent Vivier 
33e32b96b5SLaurent Vivier #define MAC_PRIMARY0 "52:54:00:11:11:11"
34e32b96b5SLaurent Vivier #define MAC_STANDBY0 "52:54:00:22:22:22"
35e1e3d321SLaurent Vivier #define MAC_PRIMARY1 "52:54:00:33:33:33"
36e1e3d321SLaurent Vivier #define MAC_STANDBY1 "52:54:00:44:44:44"
37e32b96b5SLaurent Vivier 
38e32b96b5SLaurent Vivier static QGuestAllocator guest_malloc;
39e32b96b5SLaurent Vivier static QPCIBus *pcibus;
40e32b96b5SLaurent Vivier 
41e32b96b5SLaurent Vivier static QTestState *machine_start(const char *args, int numbus)
42e32b96b5SLaurent Vivier {
43e32b96b5SLaurent Vivier     QTestState *qts;
44e32b96b5SLaurent Vivier     QPCIDevice *dev;
45e32b96b5SLaurent Vivier     int bus;
46e32b96b5SLaurent Vivier 
47e32b96b5SLaurent Vivier     qts = qtest_init(args);
48e32b96b5SLaurent Vivier 
49e32b96b5SLaurent Vivier     pc_alloc_init(&guest_malloc, qts, 0);
50e32b96b5SLaurent Vivier     pcibus = qpci_new_pc(qts, &guest_malloc);
51e32b96b5SLaurent Vivier     g_assert(qpci_secondary_buses_init(pcibus) == numbus);
52e32b96b5SLaurent Vivier 
53e32b96b5SLaurent Vivier     for (bus = 1; bus <= numbus; bus++) {
54e32b96b5SLaurent Vivier         dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0));
55e32b96b5SLaurent Vivier         g_assert_nonnull(dev);
56e32b96b5SLaurent Vivier 
57e32b96b5SLaurent Vivier         qpci_device_enable(dev);
58e32b96b5SLaurent Vivier         qpci_iomap(dev, 4, NULL);
59e32b96b5SLaurent Vivier 
60e32b96b5SLaurent Vivier         g_free(dev);
61e32b96b5SLaurent Vivier     }
62e32b96b5SLaurent Vivier 
63e32b96b5SLaurent Vivier     return qts;
64e32b96b5SLaurent Vivier }
65e32b96b5SLaurent Vivier 
66e32b96b5SLaurent Vivier static void machine_stop(QTestState *qts)
67e32b96b5SLaurent Vivier {
68e32b96b5SLaurent Vivier     qpci_free_pc(pcibus);
69e32b96b5SLaurent Vivier     alloc_destroy(&guest_malloc);
70e32b96b5SLaurent Vivier     qtest_quit(qts);
71e32b96b5SLaurent Vivier }
72e32b96b5SLaurent Vivier 
73e32b96b5SLaurent Vivier static void test_error_id(void)
74e32b96b5SLaurent Vivier {
75e32b96b5SLaurent Vivier     QTestState *qts;
76e32b96b5SLaurent Vivier     QDict *resp;
77e32b96b5SLaurent Vivier     QDict *err;
78e32b96b5SLaurent Vivier 
79e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
80e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,failover=on",
81e32b96b5SLaurent Vivier                         2);
82e32b96b5SLaurent Vivier 
83e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{'execute': 'device_add',"
84e32b96b5SLaurent Vivier                           "'arguments': {"
85e32b96b5SLaurent Vivier                           "'driver': 'virtio-net',"
86e32b96b5SLaurent Vivier                           "'bus': 'root1',"
87e32b96b5SLaurent Vivier                           "'failover_pair_id': 'standby0'"
88e32b96b5SLaurent Vivier                           "} }");
89e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "error"));
90e32b96b5SLaurent Vivier 
91e32b96b5SLaurent Vivier     err = qdict_get_qdict(resp, "error");
92e32b96b5SLaurent Vivier     g_assert(qdict_haskey(err, "desc"));
93e32b96b5SLaurent Vivier 
94e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
95e32b96b5SLaurent Vivier                     "Device with failover_pair_id needs to have id");
96e32b96b5SLaurent Vivier 
97e32b96b5SLaurent Vivier     qobject_unref(resp);
98e32b96b5SLaurent Vivier 
99e32b96b5SLaurent Vivier     machine_stop(qts);
100e32b96b5SLaurent Vivier }
101e32b96b5SLaurent Vivier 
102e32b96b5SLaurent Vivier static void test_error_pcie(void)
103e32b96b5SLaurent Vivier {
104e32b96b5SLaurent Vivier     QTestState *qts;
105e32b96b5SLaurent Vivier     QDict *resp;
106e32b96b5SLaurent Vivier     QDict *err;
107e32b96b5SLaurent Vivier 
108e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
109e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,failover=on",
110e32b96b5SLaurent Vivier                         2);
111e32b96b5SLaurent Vivier 
112e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{'execute': 'device_add',"
113e32b96b5SLaurent Vivier                           "'arguments': {"
114e32b96b5SLaurent Vivier                           "'driver': 'virtio-net',"
115e32b96b5SLaurent Vivier                           "'id': 'primary0',"
116e32b96b5SLaurent Vivier                           "'bus': 'pcie.0',"
117e32b96b5SLaurent Vivier                           "'failover_pair_id': 'standby0'"
118e32b96b5SLaurent Vivier                           "} }");
119e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "error"));
120e32b96b5SLaurent Vivier 
121e32b96b5SLaurent Vivier     err = qdict_get_qdict(resp, "error");
122e32b96b5SLaurent Vivier     g_assert(qdict_haskey(err, "desc"));
123e32b96b5SLaurent Vivier 
124e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
125e32b96b5SLaurent Vivier                     "Bus 'pcie.0' does not support hotplugging");
126e32b96b5SLaurent Vivier 
127e32b96b5SLaurent Vivier     qobject_unref(resp);
128e32b96b5SLaurent Vivier 
129e32b96b5SLaurent Vivier     machine_stop(qts);
130e32b96b5SLaurent Vivier }
131e32b96b5SLaurent Vivier 
132e32b96b5SLaurent Vivier static QDict *find_device(QDict *bus, const char *name)
133e32b96b5SLaurent Vivier {
134e32b96b5SLaurent Vivier     const QObject *obj;
135e32b96b5SLaurent Vivier     QList *devices;
136e32b96b5SLaurent Vivier     QList *list;
137e32b96b5SLaurent Vivier 
138e32b96b5SLaurent Vivier     devices = qdict_get_qlist(bus, "devices");
139e32b96b5SLaurent Vivier     if (devices == NULL) {
140e32b96b5SLaurent Vivier         return NULL;
141e32b96b5SLaurent Vivier     }
142e32b96b5SLaurent Vivier 
143e32b96b5SLaurent Vivier     list = qlist_copy(devices);
144e32b96b5SLaurent Vivier     while ((obj = qlist_pop(list))) {
145e32b96b5SLaurent Vivier         QDict *device;
146e32b96b5SLaurent Vivier 
147e32b96b5SLaurent Vivier         device = qobject_to(QDict, obj);
148e32b96b5SLaurent Vivier 
149e32b96b5SLaurent Vivier         if (qdict_haskey(device, "pci_bridge")) {
150e32b96b5SLaurent Vivier             QDict *bridge;
151e32b96b5SLaurent Vivier             QDict *bridge_device;
152e32b96b5SLaurent Vivier 
153e32b96b5SLaurent Vivier             bridge = qdict_get_qdict(device, "pci_bridge");
154e32b96b5SLaurent Vivier 
155e32b96b5SLaurent Vivier             if (qdict_haskey(bridge, "devices")) {
156e32b96b5SLaurent Vivier                 bridge_device = find_device(bridge, name);
157e32b96b5SLaurent Vivier                 if (bridge_device) {
158e32b96b5SLaurent Vivier                     qobject_unref(device);
159e32b96b5SLaurent Vivier                     qobject_unref(list);
160e32b96b5SLaurent Vivier                     return bridge_device;
161e32b96b5SLaurent Vivier                 }
162e32b96b5SLaurent Vivier             }
163e32b96b5SLaurent Vivier         }
164e32b96b5SLaurent Vivier 
165e32b96b5SLaurent Vivier         if (!qdict_haskey(device, "qdev_id")) {
166e32b96b5SLaurent Vivier             qobject_unref(device);
167e32b96b5SLaurent Vivier             continue;
168e32b96b5SLaurent Vivier         }
169e32b96b5SLaurent Vivier 
170e32b96b5SLaurent Vivier         if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) {
171e32b96b5SLaurent Vivier             qobject_unref(list);
172e32b96b5SLaurent Vivier             return device;
173e32b96b5SLaurent Vivier         }
174e32b96b5SLaurent Vivier         qobject_unref(device);
175e32b96b5SLaurent Vivier     }
176e32b96b5SLaurent Vivier     qobject_unref(list);
177e32b96b5SLaurent Vivier 
178e32b96b5SLaurent Vivier     return NULL;
179e32b96b5SLaurent Vivier }
180e32b96b5SLaurent Vivier 
181e32b96b5SLaurent Vivier static QDict *get_bus(QTestState *qts, int num)
182e32b96b5SLaurent Vivier {
183e32b96b5SLaurent Vivier     QObject *obj;
184e32b96b5SLaurent Vivier     QDict *resp;
185e32b96b5SLaurent Vivier     QList *ret;
186e32b96b5SLaurent Vivier 
187e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }");
188e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
189e32b96b5SLaurent Vivier 
190e32b96b5SLaurent Vivier     ret = qdict_get_qlist(resp, "return");
191e32b96b5SLaurent Vivier     g_assert_nonnull(ret);
192e32b96b5SLaurent Vivier 
193e32b96b5SLaurent Vivier     while ((obj = qlist_pop(ret))) {
194e32b96b5SLaurent Vivier         QDict *bus;
195e32b96b5SLaurent Vivier 
196e32b96b5SLaurent Vivier         bus = qobject_to(QDict, obj);
197e32b96b5SLaurent Vivier         if (!qdict_haskey(bus, "bus")) {
198e32b96b5SLaurent Vivier             qobject_unref(bus);
199e32b96b5SLaurent Vivier             continue;
200e32b96b5SLaurent Vivier         }
201e32b96b5SLaurent Vivier         if (qdict_get_int(bus, "bus") == num) {
202e32b96b5SLaurent Vivier             qobject_unref(resp);
203e32b96b5SLaurent Vivier             return bus;
204e32b96b5SLaurent Vivier         }
205e32b96b5SLaurent Vivier         qobject_ref(bus);
206e32b96b5SLaurent Vivier     }
207e32b96b5SLaurent Vivier     qobject_unref(resp);
208e32b96b5SLaurent Vivier 
209e32b96b5SLaurent Vivier     return NULL;
210e32b96b5SLaurent Vivier }
211e32b96b5SLaurent Vivier 
212e32b96b5SLaurent Vivier static char *get_mac(QTestState *qts, const char *name)
213e32b96b5SLaurent Vivier {
214e32b96b5SLaurent Vivier     QDict *resp;
215e32b96b5SLaurent Vivier     char *mac;
216e32b96b5SLaurent Vivier 
217e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'qom-get', "
218e32b96b5SLaurent Vivier                      "'arguments': { "
219e32b96b5SLaurent Vivier                      "'path': %s, "
220e32b96b5SLaurent Vivier                      "'property': 'mac' } }", name);
221e32b96b5SLaurent Vivier 
222e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
223e32b96b5SLaurent Vivier 
224e32b96b5SLaurent Vivier     mac = g_strdup(qdict_get_str(resp, "return"));
225e32b96b5SLaurent Vivier 
226e32b96b5SLaurent Vivier     qobject_unref(resp);
227e32b96b5SLaurent Vivier 
228e32b96b5SLaurent Vivier     return mac;
229e32b96b5SLaurent Vivier }
230e32b96b5SLaurent Vivier 
2311a800870SLaurent Vivier #define check_one_card(qts, present, id, mac)                   \
2321a800870SLaurent Vivier do {                                                            \
2331a800870SLaurent Vivier     QDict *device;                                              \
2341a800870SLaurent Vivier     QDict *bus;                                                 \
2351a800870SLaurent Vivier     char *addr;                                                 \
2361a800870SLaurent Vivier     bus = get_bus(qts, 0);                                      \
2371a800870SLaurent Vivier     device = find_device(bus, id);                              \
2381a800870SLaurent Vivier     if (present) {                                              \
2391a800870SLaurent Vivier         char *path;                                             \
2401a800870SLaurent Vivier         g_assert_nonnull(device);                               \
2411a800870SLaurent Vivier         qobject_unref(device);                                  \
2421a800870SLaurent Vivier         path = g_strdup_printf("/machine/peripheral/%s", id);   \
2431a800870SLaurent Vivier         addr = get_mac(qts, path);                              \
2441a800870SLaurent Vivier         g_free(path);                                           \
2451a800870SLaurent Vivier         g_assert_cmpstr(mac, ==, addr);                         \
2461a800870SLaurent Vivier         g_free(addr);                                           \
2471a800870SLaurent Vivier     } else {                                                    \
2481a800870SLaurent Vivier        g_assert_null(device);                                   \
2491a800870SLaurent Vivier     }                                                           \
2501a800870SLaurent Vivier     qobject_unref(bus);                                         \
2511a800870SLaurent Vivier } while (0)
252e32b96b5SLaurent Vivier 
253e32b96b5SLaurent Vivier static QDict *get_failover_negociated_event(QTestState *qts)
254e32b96b5SLaurent Vivier {
255e32b96b5SLaurent Vivier     QDict *resp;
256e32b96b5SLaurent Vivier     QDict *data;
257e32b96b5SLaurent Vivier 
258e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED");
259e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
260e32b96b5SLaurent Vivier 
261e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
262e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
263e32b96b5SLaurent Vivier     qobject_ref(data);
264e32b96b5SLaurent Vivier     qobject_unref(resp);
265e32b96b5SLaurent Vivier 
266e32b96b5SLaurent Vivier     return data;
267e32b96b5SLaurent Vivier }
268e32b96b5SLaurent Vivier 
26993262464SLaurent Vivier static QVirtioPCIDevice *start_virtio_net_internal(QTestState *qts,
27093262464SLaurent Vivier                                                    int bus, int slot,
27193262464SLaurent Vivier                                                    uint64_t *features)
272e32b96b5SLaurent Vivier {
273e32b96b5SLaurent Vivier     QVirtioPCIDevice *dev;
274e32b96b5SLaurent Vivier     QPCIAddress addr;
275e32b96b5SLaurent Vivier 
276e32b96b5SLaurent Vivier     addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0);
277e32b96b5SLaurent Vivier     dev = virtio_pci_new(pcibus, &addr);
278e32b96b5SLaurent Vivier     g_assert_nonnull(dev);
279e32b96b5SLaurent Vivier     qvirtio_pci_device_enable(dev);
280e32b96b5SLaurent Vivier     qvirtio_start_device(&dev->vdev);
28193262464SLaurent Vivier     *features &= qvirtio_get_features(&dev->vdev);
28293262464SLaurent Vivier     qvirtio_set_features(&dev->vdev, *features);
28393262464SLaurent Vivier     qvirtio_set_driver_ok(&dev->vdev);
28493262464SLaurent Vivier     return dev;
28593262464SLaurent Vivier }
28693262464SLaurent Vivier 
28793262464SLaurent Vivier static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
28893262464SLaurent Vivier                                           const char *id, bool failover)
28993262464SLaurent Vivier {
29093262464SLaurent Vivier     QVirtioPCIDevice *dev;
29193262464SLaurent Vivier     uint64_t features;
29293262464SLaurent Vivier 
29393262464SLaurent Vivier     features = ~(QVIRTIO_F_BAD_FEATURE |
294e32b96b5SLaurent Vivier                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
295e32b96b5SLaurent Vivier                  (1ull << VIRTIO_RING_F_EVENT_IDX));
29693262464SLaurent Vivier 
29793262464SLaurent Vivier     dev = start_virtio_net_internal(qts, bus, slot, &features);
29893262464SLaurent Vivier 
29993262464SLaurent Vivier     g_assert(!!(features & (1ull << VIRTIO_NET_F_STANDBY)) == failover);
30093262464SLaurent Vivier 
30193262464SLaurent Vivier     if (failover) {
30293262464SLaurent Vivier         QDict *resp;
303e32b96b5SLaurent Vivier 
304e32b96b5SLaurent Vivier         resp = get_failover_negociated_event(qts);
305e32b96b5SLaurent Vivier         g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
306e32b96b5SLaurent Vivier         qobject_unref(resp);
30793262464SLaurent Vivier     }
308e32b96b5SLaurent Vivier 
309e32b96b5SLaurent Vivier     return dev;
310e32b96b5SLaurent Vivier }
311e32b96b5SLaurent Vivier 
31293262464SLaurent Vivier static void test_on(void)
31393262464SLaurent Vivier {
31493262464SLaurent Vivier     QTestState *qts;
31593262464SLaurent Vivier 
31693262464SLaurent Vivier     qts = machine_start(BASE_MACHINE
31793262464SLaurent Vivier                         "-netdev user,id=hs0 "
31893262464SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,"
31993262464SLaurent Vivier                         "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
32093262464SLaurent Vivier                         "-netdev user,id=hs1 "
32193262464SLaurent Vivier                         "-device virtio-net,bus=root1,id=primary0,"
32293262464SLaurent Vivier                         "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
32393262464SLaurent Vivier                         2);
32493262464SLaurent Vivier 
32593262464SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
32693262464SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
32793262464SLaurent Vivier 
32893262464SLaurent Vivier     machine_stop(qts);
32993262464SLaurent Vivier }
33093262464SLaurent Vivier 
33193262464SLaurent Vivier static void test_on_mismatch(void)
33293262464SLaurent Vivier {
33393262464SLaurent Vivier     QTestState *qts;
33493262464SLaurent Vivier     QVirtioPCIDevice *vdev;
33593262464SLaurent Vivier 
33693262464SLaurent Vivier     qts = machine_start(BASE_MACHINE
33793262464SLaurent Vivier                      "-netdev user,id=hs0 "
33893262464SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
33993262464SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
34093262464SLaurent Vivier                      "-netdev user,id=hs1 "
34193262464SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
34293262464SLaurent Vivier                      "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0,
34393262464SLaurent Vivier                      2);
34493262464SLaurent Vivier 
34593262464SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
34693262464SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
34793262464SLaurent Vivier 
34893262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
34993262464SLaurent Vivier 
35093262464SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
35193262464SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
35293262464SLaurent Vivier 
35393262464SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
35493262464SLaurent Vivier     machine_stop(qts);
35593262464SLaurent Vivier }
35693262464SLaurent Vivier 
35793262464SLaurent Vivier static void test_off(void)
35893262464SLaurent Vivier {
35993262464SLaurent Vivier     QTestState *qts;
36093262464SLaurent Vivier     QVirtioPCIDevice *vdev;
36193262464SLaurent Vivier 
36293262464SLaurent Vivier     qts = machine_start(BASE_MACHINE
36393262464SLaurent Vivier                      "-netdev user,id=hs0 "
36493262464SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
36593262464SLaurent Vivier                      "failover=off,netdev=hs0,mac="MAC_STANDBY0" "
36693262464SLaurent Vivier                      "-netdev user,id=hs1 "
36793262464SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
36893262464SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
36993262464SLaurent Vivier                      2);
37093262464SLaurent Vivier 
37193262464SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
37293262464SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
37393262464SLaurent Vivier 
37493262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
37593262464SLaurent Vivier 
37693262464SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
37793262464SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
37893262464SLaurent Vivier 
37993262464SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
38093262464SLaurent Vivier     machine_stop(qts);
38193262464SLaurent Vivier }
38293262464SLaurent Vivier 
383e32b96b5SLaurent Vivier static void test_enabled(void)
384e32b96b5SLaurent Vivier {
385e32b96b5SLaurent Vivier     QTestState *qts;
386e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
387e32b96b5SLaurent Vivier 
388e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
389e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
390e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
391e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
392e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
393e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
394e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
395e32b96b5SLaurent Vivier                      2);
396e32b96b5SLaurent Vivier 
397e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
398e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
399e32b96b5SLaurent Vivier 
40093262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
401e32b96b5SLaurent Vivier 
402e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
403e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
404e32b96b5SLaurent Vivier 
405e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
406e32b96b5SLaurent Vivier     machine_stop(qts);
407e32b96b5SLaurent Vivier }
408e32b96b5SLaurent Vivier 
40978475083SLaurent Vivier static void test_guest_off(void)
41078475083SLaurent Vivier {
41178475083SLaurent Vivier     QTestState *qts;
41278475083SLaurent Vivier     QVirtioPCIDevice *vdev;
41378475083SLaurent Vivier     uint64_t features;
41478475083SLaurent Vivier 
41578475083SLaurent Vivier     qts = machine_start(BASE_MACHINE
41678475083SLaurent Vivier                      "-netdev user,id=hs0 "
41778475083SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
41878475083SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
41978475083SLaurent Vivier                      "-netdev user,id=hs1 "
42078475083SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
42178475083SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
42278475083SLaurent Vivier                      2);
42378475083SLaurent Vivier 
42478475083SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
42578475083SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
42678475083SLaurent Vivier 
42778475083SLaurent Vivier     features = ~(QVIRTIO_F_BAD_FEATURE |
42878475083SLaurent Vivier                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
42978475083SLaurent Vivier                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
43078475083SLaurent Vivier                  (1ull << VIRTIO_NET_F_STANDBY));
43178475083SLaurent Vivier 
43278475083SLaurent Vivier     vdev = start_virtio_net_internal(qts, 1, 0, &features);
43378475083SLaurent Vivier 
43478475083SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
43578475083SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
43678475083SLaurent Vivier 
43778475083SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
43878475083SLaurent Vivier     machine_stop(qts);
43978475083SLaurent Vivier }
44078475083SLaurent Vivier 
441e32b96b5SLaurent Vivier static void test_hotplug_1(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                      "-device virtio-net,bus=root0,id=standby0,"
449e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
450e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ", 2);
451e32b96b5SLaurent Vivier 
452e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
453e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
454e32b96b5SLaurent Vivier 
45593262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
456e32b96b5SLaurent Vivier 
457e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
458e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
459e32b96b5SLaurent Vivier 
460e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
461e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
462e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
463e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
464e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
465e32b96b5SLaurent Vivier 
466e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
467e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
468e32b96b5SLaurent Vivier 
469e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
470e32b96b5SLaurent Vivier     machine_stop(qts);
471e32b96b5SLaurent Vivier }
472e32b96b5SLaurent Vivier 
473e32b96b5SLaurent Vivier static void test_hotplug_1_reverse(void)
474e32b96b5SLaurent Vivier {
475e32b96b5SLaurent Vivier     QTestState *qts;
476e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
477e32b96b5SLaurent Vivier 
478e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
479e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
480e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
481e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
482e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
483e32b96b5SLaurent Vivier                      2);
484e32b96b5SLaurent Vivier 
485e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
486e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
487e32b96b5SLaurent Vivier 
488e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
489e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
490b0193288SDaniel P. Berrangé                          "'failover': true,"
491e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
492e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
493e32b96b5SLaurent Vivier 
494e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
495e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
496e32b96b5SLaurent Vivier 
49793262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
498e32b96b5SLaurent Vivier 
499e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
500e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
501e32b96b5SLaurent Vivier 
502e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
503e32b96b5SLaurent Vivier     machine_stop(qts);
504e32b96b5SLaurent Vivier }
505e32b96b5SLaurent Vivier 
506e32b96b5SLaurent Vivier static void test_hotplug_2(void)
507e32b96b5SLaurent Vivier {
508e32b96b5SLaurent Vivier     QTestState *qts;
509e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
510e32b96b5SLaurent Vivier 
511e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
512e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
513e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
514e32b96b5SLaurent Vivier                      2);
515e32b96b5SLaurent Vivier 
516e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
517e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
518e32b96b5SLaurent Vivier 
519e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
520e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
521b0193288SDaniel P. Berrangé                          "'failover': true,"
522e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
523e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
524e32b96b5SLaurent Vivier 
525e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
526e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
527e32b96b5SLaurent Vivier 
52893262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
529e32b96b5SLaurent Vivier 
530e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
531e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
532e32b96b5SLaurent Vivier 
533e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
534e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
535e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
536e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
537e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
538e32b96b5SLaurent Vivier 
539e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
540e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
541e32b96b5SLaurent Vivier 
542e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
543e32b96b5SLaurent Vivier     machine_stop(qts);
544e32b96b5SLaurent Vivier }
545e32b96b5SLaurent Vivier 
546e32b96b5SLaurent Vivier static void test_hotplug_2_reverse(void)
547e32b96b5SLaurent Vivier {
548e32b96b5SLaurent Vivier     QTestState *qts;
549e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
550e32b96b5SLaurent Vivier 
551e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
552e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
553e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
554e32b96b5SLaurent Vivier                      2);
555e32b96b5SLaurent Vivier 
556e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
557e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
558e32b96b5SLaurent Vivier 
559e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
560e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
561e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
562e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
563e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
564e32b96b5SLaurent Vivier 
565e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
566e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
567e32b96b5SLaurent Vivier 
568e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
569e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
570b0193288SDaniel P. Berrangé                          "'failover': true,"
571e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
572e32b96b5SLaurent Vivier                          "'rombar': 0,"
573e32b96b5SLaurent Vivier                          "'romfile': '',"
574e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
575e32b96b5SLaurent Vivier 
576e32b96b5SLaurent Vivier     /*
577e32b96b5SLaurent Vivier      * XXX: sounds like a bug:
578e32b96b5SLaurent Vivier      * The primary should be hidden until the virtio-net driver
579e32b96b5SLaurent Vivier      * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
580e32b96b5SLaurent Vivier      */
581e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
582e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
583e32b96b5SLaurent Vivier 
58493262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
585e32b96b5SLaurent Vivier 
586e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
587e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
588e32b96b5SLaurent Vivier 
589e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
590e32b96b5SLaurent Vivier     machine_stop(qts);
591e32b96b5SLaurent Vivier }
592e32b96b5SLaurent Vivier 
593a6866706SXuzhou Cheng #ifndef _WIN32
594e32b96b5SLaurent Vivier static QDict *migrate_status(QTestState *qts)
595e32b96b5SLaurent Vivier {
596e32b96b5SLaurent Vivier     QDict *resp, *ret;
597e32b96b5SLaurent Vivier 
598e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
599e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
600e32b96b5SLaurent Vivier 
601e32b96b5SLaurent Vivier     ret = qdict_get_qdict(resp, "return");
602e32b96b5SLaurent Vivier     g_assert(qdict_haskey(ret, "status"));
603e32b96b5SLaurent Vivier     qobject_ref(ret);
604e32b96b5SLaurent Vivier     qobject_unref(resp);
605e32b96b5SLaurent Vivier 
606e32b96b5SLaurent Vivier     return ret;
607e32b96b5SLaurent Vivier }
608e32b96b5SLaurent Vivier 
609e32b96b5SLaurent Vivier static QDict *get_unplug_primary_event(QTestState *qts)
610e32b96b5SLaurent Vivier {
611e32b96b5SLaurent Vivier     QDict *resp;
612e32b96b5SLaurent Vivier     QDict *data;
613e32b96b5SLaurent Vivier 
614e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
615e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
616e32b96b5SLaurent Vivier 
617e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
618e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
619e32b96b5SLaurent Vivier     qobject_ref(data);
620e32b96b5SLaurent Vivier     qobject_unref(resp);
621e32b96b5SLaurent Vivier 
622e32b96b5SLaurent Vivier     return data;
623e32b96b5SLaurent Vivier }
624e32b96b5SLaurent Vivier 
625e32b96b5SLaurent Vivier static void test_migrate_out(gconstpointer opaque)
626e32b96b5SLaurent Vivier {
627e32b96b5SLaurent Vivier     QTestState *qts;
628e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
629e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
630e32b96b5SLaurent Vivier     const gchar *status;
631e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
632e32b96b5SLaurent Vivier 
633e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
634e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
635e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
636e32b96b5SLaurent Vivier                      2);
637e32b96b5SLaurent Vivier 
638e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
639e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
640e32b96b5SLaurent Vivier 
641e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
642e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
643b0193288SDaniel P. Berrangé                          "'failover': true,"
644e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
645e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
646e32b96b5SLaurent Vivier 
647e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
648e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
649e32b96b5SLaurent Vivier 
65093262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
651e32b96b5SLaurent Vivier 
652e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
653e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
654e32b96b5SLaurent Vivier 
655e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
656e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
657e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
658e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
659e32b96b5SLaurent Vivier                          "'rombar': 0,"
660e32b96b5SLaurent Vivier                          "'romfile': '',"
661e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
662e32b96b5SLaurent Vivier 
663e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
664e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
665e32b96b5SLaurent Vivier 
666e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
667e32b96b5SLaurent Vivier     g_assert_nonnull(args);
668e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
669e32b96b5SLaurent Vivier 
670e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
671e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
672e32b96b5SLaurent Vivier     qobject_unref(resp);
673e32b96b5SLaurent Vivier 
674e32b96b5SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
675e32b96b5SLaurent Vivier     resp = get_unplug_primary_event(qts);
676e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
677e32b96b5SLaurent Vivier     qobject_unref(resp);
678e32b96b5SLaurent Vivier 
679e32b96b5SLaurent Vivier     /* wait the end of the migration setup phase */
680e32b96b5SLaurent Vivier     while (true) {
681e32b96b5SLaurent Vivier         ret = migrate_status(qts);
682e32b96b5SLaurent Vivier 
683e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
684e32b96b5SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
685e32b96b5SLaurent Vivier             qobject_unref(ret);
686e32b96b5SLaurent Vivier             break;
687e32b96b5SLaurent Vivier         }
688e32b96b5SLaurent Vivier 
689e32b96b5SLaurent Vivier         /* The migration must not start if the card is not ejected */
690e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
691e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
692e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
693e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
694e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
695e32b96b5SLaurent Vivier 
696e32b96b5SLaurent Vivier         qobject_unref(ret);
697e32b96b5SLaurent Vivier     }
698e32b96b5SLaurent Vivier 
699e32b96b5SLaurent Vivier     if (g_test_slow()) {
700e32b96b5SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
701e32b96b5SLaurent Vivier         for (int i = 0; i < 5; i++) {
702e32b96b5SLaurent Vivier             sleep(1);
703e32b96b5SLaurent Vivier             ret = migrate_status(qts);
704e32b96b5SLaurent Vivier             status = qdict_get_str(ret, "status");
705e32b96b5SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
706e32b96b5SLaurent Vivier             qobject_unref(ret);
707e32b96b5SLaurent Vivier         }
708e32b96b5SLaurent Vivier     }
709e32b96b5SLaurent Vivier 
710e32b96b5SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
711e32b96b5SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
712e32b96b5SLaurent Vivier 
713e32b96b5SLaurent Vivier     while (true) {
714e32b96b5SLaurent Vivier         ret = migrate_status(qts);
715e32b96b5SLaurent Vivier 
716e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
717e32b96b5SLaurent Vivier         if (strcmp(status, "completed") == 0) {
718e32b96b5SLaurent Vivier             qobject_unref(ret);
719e32b96b5SLaurent Vivier             break;
720e32b96b5SLaurent Vivier         }
721e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
722e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
723e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
724e32b96b5SLaurent Vivier         qobject_unref(ret);
725e32b96b5SLaurent Vivier     }
726e32b96b5SLaurent Vivier 
727e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
728e32b96b5SLaurent Vivier 
729e32b96b5SLaurent Vivier     /*
730e32b96b5SLaurent Vivier      * in fact, the card is ejected from the point of view of kernel
731e32b96b5SLaurent Vivier      * but not really from QEMU to be able to hotplug it back if
732e32b96b5SLaurent Vivier      * migration fails. So we can't check that:
733e32b96b5SLaurent Vivier      *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
734e32b96b5SLaurent Vivier      *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
735e32b96b5SLaurent Vivier      */
736e32b96b5SLaurent Vivier 
737e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
738e32b96b5SLaurent Vivier     machine_stop(qts);
739e32b96b5SLaurent Vivier }
740e32b96b5SLaurent Vivier 
741e32b96b5SLaurent Vivier static void test_migrate_in(gconstpointer opaque)
742e32b96b5SLaurent Vivier {
743e32b96b5SLaurent Vivier     QTestState *qts;
7446830e53bSFabiano Rosas     QDict *resp, *ret;
745e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
746e32b96b5SLaurent Vivier 
747e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
748e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
749e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
750e32b96b5SLaurent Vivier                      "-incoming defer ",
751e32b96b5SLaurent Vivier                      2);
752e32b96b5SLaurent Vivier 
753e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
754e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
755e32b96b5SLaurent Vivier 
756e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
757e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
758b0193288SDaniel P. Berrangé                          "'failover': true,"
759e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
760e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
761e32b96b5SLaurent Vivier 
762e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
763e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
764e32b96b5SLaurent Vivier 
765e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
766e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
767e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
768e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
769e32b96b5SLaurent Vivier                          "'rombar': 0,"
770e32b96b5SLaurent Vivier                          "'romfile': '',"
771e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
772e32b96b5SLaurent Vivier 
773e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
774e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
775e32b96b5SLaurent Vivier 
7766830e53bSFabiano Rosas     migrate_incoming_qmp(qts, uri, "{}");
777e32b96b5SLaurent Vivier 
778e32b96b5SLaurent Vivier     resp = get_failover_negociated_event(qts);
779e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
780e32b96b5SLaurent Vivier     qobject_unref(resp);
781e32b96b5SLaurent Vivier 
782e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
783e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
784e32b96b5SLaurent Vivier 
785e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
786e32b96b5SLaurent Vivier 
787e32b96b5SLaurent Vivier     ret = migrate_status(qts);
788e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
789e32b96b5SLaurent Vivier     qobject_unref(ret);
790e32b96b5SLaurent Vivier 
791e32b96b5SLaurent Vivier     machine_stop(qts);
792e32b96b5SLaurent Vivier }
793e32b96b5SLaurent Vivier 
7947f998491SLaurent Vivier static void test_off_migrate_out(gconstpointer opaque)
7957f998491SLaurent Vivier {
7967f998491SLaurent Vivier     QTestState *qts;
7977f998491SLaurent Vivier     QDict *resp, *args, *ret;
7987f998491SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
7997f998491SLaurent Vivier     const gchar *status;
8007f998491SLaurent Vivier     QVirtioPCIDevice *vdev;
8017f998491SLaurent Vivier 
8027f998491SLaurent Vivier     qts = machine_start(BASE_MACHINE
8037f998491SLaurent Vivier                      "-netdev user,id=hs0 "
8047f998491SLaurent Vivier                      "-netdev user,id=hs1 ",
8057f998491SLaurent Vivier                      2);
8067f998491SLaurent Vivier 
8077f998491SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
8087f998491SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8097f998491SLaurent Vivier 
8107f998491SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
8117f998491SLaurent Vivier                          "{'bus': 'root0',"
812b0193288SDaniel P. Berrangé                          "'failover': false,"
8137f998491SLaurent Vivier                          "'netdev': 'hs0',"
8147f998491SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
8157f998491SLaurent Vivier 
8167f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8177f998491SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8187f998491SLaurent Vivier 
8197f998491SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
8207f998491SLaurent Vivier                          "{'bus': 'root1',"
8217f998491SLaurent Vivier                          "'failover_pair_id': 'standby0',"
8227f998491SLaurent Vivier                          "'netdev': 'hs1',"
8237f998491SLaurent Vivier                          "'rombar': 0,"
8247f998491SLaurent Vivier                          "'romfile': '',"
8257f998491SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
8267f998491SLaurent Vivier 
8277f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8287f998491SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
8297f998491SLaurent Vivier 
8307f998491SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
8317f998491SLaurent Vivier 
8327f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8337f998491SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
8347f998491SLaurent Vivier 
8357f998491SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
8367f998491SLaurent Vivier     g_assert_nonnull(args);
8377f998491SLaurent Vivier     qdict_put_str(args, "uri", uri);
8387f998491SLaurent Vivier 
8397f998491SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
8407f998491SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
8417f998491SLaurent Vivier     qobject_unref(resp);
8427f998491SLaurent Vivier 
8437f998491SLaurent Vivier     while (true) {
8447f998491SLaurent Vivier         ret = migrate_status(qts);
8457f998491SLaurent Vivier 
8467f998491SLaurent Vivier         status = qdict_get_str(ret, "status");
8477f998491SLaurent Vivier         if (strcmp(status, "completed") == 0) {
8487f998491SLaurent Vivier             qobject_unref(ret);
8497f998491SLaurent Vivier             break;
8507f998491SLaurent Vivier         }
8517f998491SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
8527f998491SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
8537f998491SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
8547f998491SLaurent Vivier         qobject_unref(ret);
8557f998491SLaurent Vivier     }
8567f998491SLaurent Vivier 
8577f998491SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
8587f998491SLaurent Vivier 
8597f998491SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
8607f998491SLaurent Vivier     machine_stop(qts);
8617f998491SLaurent Vivier }
8627f998491SLaurent Vivier 
8637f998491SLaurent Vivier static void test_off_migrate_in(gconstpointer opaque)
8647f998491SLaurent Vivier {
8657f998491SLaurent Vivier     QTestState *qts;
8666830e53bSFabiano Rosas     QDict *ret;
8677f998491SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
8687f998491SLaurent Vivier 
8697f998491SLaurent Vivier     qts = machine_start(BASE_MACHINE
8707f998491SLaurent Vivier                      "-netdev user,id=hs0 "
8717f998491SLaurent Vivier                      "-netdev user,id=hs1 "
8727f998491SLaurent Vivier                      "-incoming defer ",
8737f998491SLaurent Vivier                      2);
8747f998491SLaurent Vivier 
8757f998491SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
8767f998491SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8777f998491SLaurent Vivier 
8787f998491SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
8797f998491SLaurent Vivier                          "{'bus': 'root0',"
880b0193288SDaniel P. Berrangé                          "'failover': false,"
8817f998491SLaurent Vivier                          "'netdev': 'hs0',"
8827f998491SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
8837f998491SLaurent Vivier 
8847f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8857f998491SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8867f998491SLaurent Vivier 
8877f998491SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
8887f998491SLaurent Vivier                          "{'bus': 'root1',"
8897f998491SLaurent Vivier                          "'failover_pair_id': 'standby0',"
8907f998491SLaurent Vivier                          "'netdev': 'hs1',"
8917f998491SLaurent Vivier                          "'rombar': 0,"
8927f998491SLaurent Vivier                          "'romfile': '',"
8937f998491SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
8947f998491SLaurent Vivier 
8957f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8967f998491SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
8977f998491SLaurent Vivier 
8986830e53bSFabiano Rosas     migrate_incoming_qmp(qts, uri, "{}");
8997f998491SLaurent Vivier 
9007f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9017f998491SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
9027f998491SLaurent Vivier 
9037f998491SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
9047f998491SLaurent Vivier 
9057f998491SLaurent Vivier     ret = migrate_status(qts);
9067f998491SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
9077f998491SLaurent Vivier     qobject_unref(ret);
9087f998491SLaurent Vivier 
9097f998491SLaurent Vivier     machine_stop(qts);
9107f998491SLaurent Vivier }
9117f998491SLaurent Vivier 
912d9872c00SLaurent Vivier static void test_guest_off_migrate_out(gconstpointer opaque)
913d9872c00SLaurent Vivier {
914d9872c00SLaurent Vivier     QTestState *qts;
915d9872c00SLaurent Vivier     QDict *resp, *args, *ret;
916d9872c00SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
917d9872c00SLaurent Vivier     const gchar *status;
918d9872c00SLaurent Vivier     QVirtioPCIDevice *vdev;
919d9872c00SLaurent Vivier     uint64_t features;
920d9872c00SLaurent Vivier 
921d9872c00SLaurent Vivier     qts = machine_start(BASE_MACHINE
922d9872c00SLaurent Vivier                      "-netdev user,id=hs0 "
923d9872c00SLaurent Vivier                      "-netdev user,id=hs1 ",
924d9872c00SLaurent Vivier                      2);
925d9872c00SLaurent Vivier 
926d9872c00SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
927d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
928d9872c00SLaurent Vivier 
929d9872c00SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
930d9872c00SLaurent Vivier                          "{'bus': 'root0',"
931b0193288SDaniel P. Berrangé                          "'failover': true,"
932d9872c00SLaurent Vivier                          "'netdev': 'hs0',"
933d9872c00SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
934d9872c00SLaurent Vivier 
935d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
936d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
937d9872c00SLaurent Vivier 
938d9872c00SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
939d9872c00SLaurent Vivier                          "{'bus': 'root1',"
940d9872c00SLaurent Vivier                          "'failover_pair_id': 'standby0',"
941d9872c00SLaurent Vivier                          "'netdev': 'hs1',"
942d9872c00SLaurent Vivier                          "'rombar': 0,"
943d9872c00SLaurent Vivier                          "'romfile': '',"
944d9872c00SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
945d9872c00SLaurent Vivier 
946d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
947d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
948d9872c00SLaurent Vivier 
949d9872c00SLaurent Vivier     features = ~(QVIRTIO_F_BAD_FEATURE |
950d9872c00SLaurent Vivier                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
951d9872c00SLaurent Vivier                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
952d9872c00SLaurent Vivier                  (1ull << VIRTIO_NET_F_STANDBY));
953d9872c00SLaurent Vivier 
954d9872c00SLaurent Vivier     vdev = start_virtio_net_internal(qts, 1, 0, &features);
955d9872c00SLaurent Vivier 
956d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
957d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
958d9872c00SLaurent Vivier 
959d9872c00SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
960d9872c00SLaurent Vivier     g_assert_nonnull(args);
961d9872c00SLaurent Vivier     qdict_put_str(args, "uri", uri);
962d9872c00SLaurent Vivier 
963d9872c00SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
964d9872c00SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
965d9872c00SLaurent Vivier     qobject_unref(resp);
966d9872c00SLaurent Vivier 
967d9872c00SLaurent Vivier     while (true) {
968d9872c00SLaurent Vivier         ret = migrate_status(qts);
969d9872c00SLaurent Vivier 
970d9872c00SLaurent Vivier         status = qdict_get_str(ret, "status");
971d9872c00SLaurent Vivier         if (strcmp(status, "completed") == 0) {
972d9872c00SLaurent Vivier             qobject_unref(ret);
973d9872c00SLaurent Vivier             break;
974d9872c00SLaurent Vivier         }
975d9872c00SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
976d9872c00SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
977d9872c00SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
978d9872c00SLaurent Vivier         qobject_unref(ret);
979d9872c00SLaurent Vivier     }
980d9872c00SLaurent Vivier 
981d9872c00SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
982d9872c00SLaurent Vivier 
983d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
984d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
985d9872c00SLaurent Vivier 
986d9872c00SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
987d9872c00SLaurent Vivier     machine_stop(qts);
988d9872c00SLaurent Vivier }
989d9872c00SLaurent Vivier 
990d9872c00SLaurent Vivier static void test_guest_off_migrate_in(gconstpointer opaque)
991d9872c00SLaurent Vivier {
992d9872c00SLaurent Vivier     QTestState *qts;
9936830e53bSFabiano Rosas     QDict *ret;
994d9872c00SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
995d9872c00SLaurent Vivier 
996d9872c00SLaurent Vivier     qts = machine_start(BASE_MACHINE
997d9872c00SLaurent Vivier                      "-netdev user,id=hs0 "
998d9872c00SLaurent Vivier                      "-netdev user,id=hs1 "
999d9872c00SLaurent Vivier                      "-incoming defer ",
1000d9872c00SLaurent Vivier                      2);
1001d9872c00SLaurent Vivier 
1002d9872c00SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1003d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1004d9872c00SLaurent Vivier 
1005d9872c00SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1006d9872c00SLaurent Vivier                          "{'bus': 'root0',"
1007b0193288SDaniel P. Berrangé                          "'failover': true,"
1008d9872c00SLaurent Vivier                          "'netdev': 'hs0',"
1009d9872c00SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1010d9872c00SLaurent Vivier 
1011d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1012d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1013d9872c00SLaurent Vivier 
1014d9872c00SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1015d9872c00SLaurent Vivier                          "{'bus': 'root1',"
1016d9872c00SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1017d9872c00SLaurent Vivier                          "'netdev': 'hs1',"
1018d9872c00SLaurent Vivier                          "'rombar': 0,"
1019d9872c00SLaurent Vivier                          "'romfile': '',"
1020d9872c00SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1021d9872c00SLaurent Vivier 
1022d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1023d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1024d9872c00SLaurent Vivier 
10256830e53bSFabiano Rosas     migrate_incoming_qmp(qts, uri, "{}");
1026d9872c00SLaurent Vivier 
1027d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1028d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1029d9872c00SLaurent Vivier 
1030d9872c00SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
1031d9872c00SLaurent Vivier 
1032d9872c00SLaurent Vivier     ret = migrate_status(qts);
1033d9872c00SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1034d9872c00SLaurent Vivier     qobject_unref(ret);
1035d9872c00SLaurent Vivier 
1036d9872c00SLaurent Vivier     machine_stop(qts);
1037d9872c00SLaurent Vivier }
1038d9872c00SLaurent Vivier 
1039e20977b7SLaurent Vivier static void test_migrate_guest_off_abort(gconstpointer opaque)
1040e20977b7SLaurent Vivier {
1041e20977b7SLaurent Vivier     QTestState *qts;
1042e20977b7SLaurent Vivier     QDict *resp, *args, *ret;
1043e20977b7SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1044e20977b7SLaurent Vivier     const gchar *status;
1045e20977b7SLaurent Vivier     QVirtioPCIDevice *vdev;
1046e20977b7SLaurent Vivier     uint64_t features;
1047e20977b7SLaurent Vivier 
1048e20977b7SLaurent Vivier     qts = machine_start(BASE_MACHINE
1049e20977b7SLaurent Vivier                      "-netdev user,id=hs0 "
1050e20977b7SLaurent Vivier                      "-netdev user,id=hs1 ",
1051e20977b7SLaurent Vivier                      2);
1052e20977b7SLaurent Vivier 
1053e20977b7SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1054e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1055e20977b7SLaurent Vivier 
1056e20977b7SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1057e20977b7SLaurent Vivier                          "{'bus': 'root0',"
1058b0193288SDaniel P. Berrangé                          "'failover': true,"
1059e20977b7SLaurent Vivier                          "'netdev': 'hs0',"
1060e20977b7SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1061e20977b7SLaurent Vivier 
1062e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1063e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1064e20977b7SLaurent Vivier 
1065e20977b7SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1066e20977b7SLaurent Vivier                          "{'bus': 'root1',"
1067e20977b7SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1068e20977b7SLaurent Vivier                          "'netdev': 'hs1',"
1069e20977b7SLaurent Vivier                          "'rombar': 0,"
1070e20977b7SLaurent Vivier                          "'romfile': '',"
1071e20977b7SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1072e20977b7SLaurent Vivier 
1073e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1074e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1075e20977b7SLaurent Vivier 
1076e20977b7SLaurent Vivier     features = ~(QVIRTIO_F_BAD_FEATURE |
1077e20977b7SLaurent Vivier                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
1078e20977b7SLaurent Vivier                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
1079e20977b7SLaurent Vivier                  (1ull << VIRTIO_NET_F_STANDBY));
1080e20977b7SLaurent Vivier 
1081e20977b7SLaurent Vivier     vdev = start_virtio_net_internal(qts, 1, 0, &features);
1082e20977b7SLaurent Vivier 
1083e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1084e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1085e20977b7SLaurent Vivier 
1086e20977b7SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1087e20977b7SLaurent Vivier     g_assert_nonnull(args);
1088e20977b7SLaurent Vivier     qdict_put_str(args, "uri", uri);
1089e20977b7SLaurent Vivier 
1090e20977b7SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1091e20977b7SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1092e20977b7SLaurent Vivier     qobject_unref(resp);
1093e20977b7SLaurent Vivier 
1094e20977b7SLaurent Vivier     while (true) {
1095e20977b7SLaurent Vivier         ret = migrate_status(qts);
1096e20977b7SLaurent Vivier 
1097e20977b7SLaurent Vivier         status = qdict_get_str(ret, "status");
10986ae6a30cSLaurent Vivier         if (strcmp(status, "completed") == 0) {
10996ae6a30cSLaurent Vivier             g_test_skip("Failed to cancel the migration");
11006ae6a30cSLaurent Vivier             qobject_unref(ret);
11016ae6a30cSLaurent Vivier             goto out;
11026ae6a30cSLaurent Vivier         }
1103e20977b7SLaurent Vivier         if (strcmp(status, "active") == 0) {
1104e20977b7SLaurent Vivier             qobject_unref(ret);
1105e20977b7SLaurent Vivier             break;
1106e20977b7SLaurent Vivier         }
1107e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1108e20977b7SLaurent Vivier         qobject_unref(ret);
1109e20977b7SLaurent Vivier     }
1110e20977b7SLaurent Vivier 
1111e20977b7SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1112e20977b7SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1113e20977b7SLaurent Vivier     qobject_unref(resp);
1114e20977b7SLaurent Vivier 
1115e20977b7SLaurent Vivier     while (true) {
1116e20977b7SLaurent Vivier         ret = migrate_status(qts);
1117e20977b7SLaurent Vivier         status = qdict_get_str(ret, "status");
11186ae6a30cSLaurent Vivier         if (strcmp(status, "completed") == 0) {
11196ae6a30cSLaurent Vivier             g_test_skip("Failed to cancel the migration");
11206ae6a30cSLaurent Vivier             qobject_unref(ret);
11216ae6a30cSLaurent Vivier             goto out;
11226ae6a30cSLaurent Vivier         }
1123e20977b7SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
1124e20977b7SLaurent Vivier             qobject_unref(ret);
1125e20977b7SLaurent Vivier             break;
1126e20977b7SLaurent Vivier         }
1127e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1128e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
1129e20977b7SLaurent Vivier         qobject_unref(ret);
1130e20977b7SLaurent Vivier     }
1131e20977b7SLaurent Vivier 
1132e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1133e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1134e20977b7SLaurent Vivier 
11356ae6a30cSLaurent Vivier out:
1136e20977b7SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
1137e20977b7SLaurent Vivier     machine_stop(qts);
1138e20977b7SLaurent Vivier }
1139e20977b7SLaurent Vivier 
11401e2077e2SLaurent Vivier static void test_migrate_abort_wait_unplug(gconstpointer opaque)
11411e2077e2SLaurent Vivier {
11421e2077e2SLaurent Vivier     QTestState *qts;
11431e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
11441e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
11451e2077e2SLaurent Vivier     const gchar *status;
11461e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
11471e2077e2SLaurent Vivier 
11481e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
11491e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
11501e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
11511e2077e2SLaurent Vivier                      2);
11521e2077e2SLaurent Vivier 
11531e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
11541e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
11551e2077e2SLaurent Vivier 
11561e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
11571e2077e2SLaurent Vivier                          "{'bus': 'root0',"
1158b0193288SDaniel P. Berrangé                          "'failover': true,"
11591e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
11601e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
11611e2077e2SLaurent Vivier 
11621e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
11631e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
11641e2077e2SLaurent Vivier 
116593262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
11661e2077e2SLaurent Vivier 
11671e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
11681e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
11691e2077e2SLaurent Vivier 
11701e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
11711e2077e2SLaurent Vivier                          "{'bus': 'root1',"
11721e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
11731e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
11741e2077e2SLaurent Vivier                          "'rombar': 0,"
11751e2077e2SLaurent Vivier                          "'romfile': '',"
11761e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
11771e2077e2SLaurent Vivier 
11781e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
11791e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
11801e2077e2SLaurent Vivier 
11811e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
11821e2077e2SLaurent Vivier     g_assert_nonnull(args);
11831e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
11841e2077e2SLaurent Vivier 
11851e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
11861e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
11871e2077e2SLaurent Vivier     qobject_unref(resp);
11881e2077e2SLaurent Vivier 
11891e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
11901e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
11911e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
11921e2077e2SLaurent Vivier     qobject_unref(resp);
11931e2077e2SLaurent Vivier 
11941e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
11951e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
11961e2077e2SLaurent Vivier     qobject_unref(resp);
11971e2077e2SLaurent Vivier 
11981e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
11991e2077e2SLaurent Vivier 
12001e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
12011e2077e2SLaurent Vivier     ret = migrate_status(qts);
12021e2077e2SLaurent Vivier 
12031e2077e2SLaurent Vivier     status = qdict_get_str(ret, "status");
12041e2077e2SLaurent Vivier     g_assert_cmpstr(status, ==, "cancelling");
12051e2077e2SLaurent Vivier     qobject_unref(ret);
12061e2077e2SLaurent Vivier 
12071e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
12081e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
12091e2077e2SLaurent Vivier 
12101e2077e2SLaurent Vivier     while (true) {
12111e2077e2SLaurent Vivier         ret = migrate_status(qts);
12121e2077e2SLaurent Vivier 
12131e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
12141e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
12151e2077e2SLaurent Vivier             qobject_unref(ret);
12161e2077e2SLaurent Vivier             break;
12171e2077e2SLaurent Vivier         }
12186ae6a30cSLaurent Vivier         g_assert_cmpstr(status, ==, "cancelling");
12191e2077e2SLaurent Vivier         qobject_unref(ret);
12201e2077e2SLaurent Vivier     }
12211e2077e2SLaurent Vivier 
12221e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
12231e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
12241e2077e2SLaurent Vivier 
12251e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
12261e2077e2SLaurent Vivier     machine_stop(qts);
12271e2077e2SLaurent Vivier }
12281e2077e2SLaurent Vivier 
12291e2077e2SLaurent Vivier static void test_migrate_abort_active(gconstpointer opaque)
12301e2077e2SLaurent Vivier {
12311e2077e2SLaurent Vivier     QTestState *qts;
12321e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
12331e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
12341e2077e2SLaurent Vivier     const gchar *status;
12351e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
12361e2077e2SLaurent Vivier 
12371e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
12381e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
12391e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
12401e2077e2SLaurent Vivier                      2);
12411e2077e2SLaurent Vivier 
12421e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
12431e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
12441e2077e2SLaurent Vivier 
12451e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
12461e2077e2SLaurent Vivier                          "{'bus': 'root0',"
1247b0193288SDaniel P. Berrangé                          "'failover': true,"
12481e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
12491e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
12501e2077e2SLaurent Vivier 
12511e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
12521e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
12531e2077e2SLaurent Vivier 
125493262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
12551e2077e2SLaurent Vivier 
12561e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
12571e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
12581e2077e2SLaurent Vivier 
12591e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
12601e2077e2SLaurent Vivier                          "{'bus': 'root1',"
12611e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
12621e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
12631e2077e2SLaurent Vivier                          "'rombar': 0,"
12641e2077e2SLaurent Vivier                          "'romfile': '',"
12651e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
12661e2077e2SLaurent Vivier 
12671e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
12681e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
12691e2077e2SLaurent Vivier 
12701e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
12711e2077e2SLaurent Vivier     g_assert_nonnull(args);
12721e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
12731e2077e2SLaurent Vivier 
12741e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
12751e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
12761e2077e2SLaurent Vivier     qobject_unref(resp);
12771e2077e2SLaurent Vivier 
12781e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
12791e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
12801e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
12811e2077e2SLaurent Vivier     qobject_unref(resp);
12821e2077e2SLaurent Vivier 
12831e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
12841e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
12851e2077e2SLaurent Vivier 
12861e2077e2SLaurent Vivier     while (true) {
12871e2077e2SLaurent Vivier         ret = migrate_status(qts);
12881e2077e2SLaurent Vivier 
12891e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
12906ae6a30cSLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
12911e2077e2SLaurent Vivier         if (strcmp(status, "wait-unplug") != 0) {
12921e2077e2SLaurent Vivier             qobject_unref(ret);
12931e2077e2SLaurent Vivier             break;
12941e2077e2SLaurent Vivier         }
12951e2077e2SLaurent Vivier         qobject_unref(ret);
12961e2077e2SLaurent Vivier     }
12971e2077e2SLaurent Vivier 
12981e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
12991e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
13001e2077e2SLaurent Vivier     qobject_unref(resp);
13011e2077e2SLaurent Vivier 
13021e2077e2SLaurent Vivier     while (true) {
13031e2077e2SLaurent Vivier         ret = migrate_status(qts);
13041e2077e2SLaurent Vivier 
13051e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
13066ae6a30cSLaurent Vivier         if (strcmp(status, "completed") == 0) {
13076ae6a30cSLaurent Vivier             g_test_skip("Failed to cancel the migration");
13086ae6a30cSLaurent Vivier             qobject_unref(ret);
13096ae6a30cSLaurent Vivier             goto out;
13106ae6a30cSLaurent Vivier         }
13111e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
13121e2077e2SLaurent Vivier             qobject_unref(ret);
13131e2077e2SLaurent Vivier             break;
13141e2077e2SLaurent Vivier         }
13151e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
13161e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
13171e2077e2SLaurent Vivier         qobject_unref(ret);
13181e2077e2SLaurent Vivier     }
13191e2077e2SLaurent Vivier 
13201e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
13211e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
13221e2077e2SLaurent Vivier 
13236ae6a30cSLaurent Vivier out:
13241e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
13251e2077e2SLaurent Vivier     machine_stop(qts);
13261e2077e2SLaurent Vivier }
13271e2077e2SLaurent Vivier 
1328e20977b7SLaurent Vivier static void test_migrate_off_abort(gconstpointer opaque)
1329e20977b7SLaurent Vivier {
1330e20977b7SLaurent Vivier     QTestState *qts;
1331e20977b7SLaurent Vivier     QDict *resp, *args, *ret;
1332e20977b7SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1333e20977b7SLaurent Vivier     const gchar *status;
1334e20977b7SLaurent Vivier     QVirtioPCIDevice *vdev;
1335e20977b7SLaurent Vivier 
1336e20977b7SLaurent Vivier     qts = machine_start(BASE_MACHINE
1337e20977b7SLaurent Vivier                      "-netdev user,id=hs0 "
1338e20977b7SLaurent Vivier                      "-netdev user,id=hs1 ",
1339e20977b7SLaurent Vivier                      2);
1340e20977b7SLaurent Vivier 
1341e20977b7SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1342e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1343e20977b7SLaurent Vivier 
1344e20977b7SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1345e20977b7SLaurent Vivier                          "{'bus': 'root0',"
1346b0193288SDaniel P. Berrangé                          "'failover': false,"
1347e20977b7SLaurent Vivier                          "'netdev': 'hs0',"
1348e20977b7SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1349e20977b7SLaurent Vivier 
1350e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1351e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1352e20977b7SLaurent Vivier 
1353e20977b7SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
1354e20977b7SLaurent Vivier 
1355e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1356e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1357e20977b7SLaurent Vivier 
1358e20977b7SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1359e20977b7SLaurent Vivier                          "{'bus': 'root1',"
1360e20977b7SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1361e20977b7SLaurent Vivier                          "'netdev': 'hs1',"
1362e20977b7SLaurent Vivier                          "'rombar': 0,"
1363e20977b7SLaurent Vivier                          "'romfile': '',"
1364e20977b7SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1365e20977b7SLaurent Vivier 
1366e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1367e20977b7SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1368e20977b7SLaurent Vivier 
1369e20977b7SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1370e20977b7SLaurent Vivier     g_assert_nonnull(args);
1371e20977b7SLaurent Vivier     qdict_put_str(args, "uri", uri);
1372e20977b7SLaurent Vivier 
1373e20977b7SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1374e20977b7SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1375e20977b7SLaurent Vivier     qobject_unref(resp);
1376e20977b7SLaurent Vivier 
1377e20977b7SLaurent Vivier     while (true) {
1378e20977b7SLaurent Vivier         ret = migrate_status(qts);
1379e20977b7SLaurent Vivier 
1380e20977b7SLaurent Vivier         status = qdict_get_str(ret, "status");
1381e20977b7SLaurent Vivier         if (strcmp(status, "active") == 0) {
1382e20977b7SLaurent Vivier             qobject_unref(ret);
1383e20977b7SLaurent Vivier             break;
1384e20977b7SLaurent Vivier         }
1385e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1386e20977b7SLaurent Vivier         qobject_unref(ret);
1387e20977b7SLaurent Vivier     }
1388e20977b7SLaurent Vivier 
1389e20977b7SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1390e20977b7SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1391e20977b7SLaurent Vivier     qobject_unref(resp);
1392e20977b7SLaurent Vivier 
1393e20977b7SLaurent Vivier     while (true) {
1394e20977b7SLaurent Vivier         ret = migrate_status(qts);
1395e20977b7SLaurent Vivier 
1396e20977b7SLaurent Vivier         status = qdict_get_str(ret, "status");
13976ae6a30cSLaurent Vivier         if (strcmp(status, "completed") == 0) {
13986ae6a30cSLaurent Vivier             g_test_skip("Failed to cancel the migration");
13996ae6a30cSLaurent Vivier             qobject_unref(ret);
14006ae6a30cSLaurent Vivier             goto out;
14016ae6a30cSLaurent Vivier         }
1402e20977b7SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
1403e20977b7SLaurent Vivier             qobject_unref(ret);
1404e20977b7SLaurent Vivier             break;
1405e20977b7SLaurent Vivier         }
1406e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1407e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
1408e20977b7SLaurent Vivier         qobject_unref(ret);
1409e20977b7SLaurent Vivier     }
1410e20977b7SLaurent Vivier 
1411e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1412e20977b7SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1413e20977b7SLaurent Vivier 
14146ae6a30cSLaurent Vivier out:
1415e20977b7SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
1416e20977b7SLaurent Vivier     machine_stop(qts);
1417e20977b7SLaurent Vivier }
1418e20977b7SLaurent Vivier 
14191e2077e2SLaurent Vivier static void test_migrate_abort_timeout(gconstpointer opaque)
14201e2077e2SLaurent Vivier {
14211e2077e2SLaurent Vivier     QTestState *qts;
14221e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
14231e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
14241e2077e2SLaurent Vivier     const gchar *status;
14251e2077e2SLaurent Vivier     int total;
14261e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
14271e2077e2SLaurent Vivier 
14281e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
14291e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
14301e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
14311e2077e2SLaurent Vivier                      2);
14321e2077e2SLaurent Vivier 
14331e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
14341e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
14351e2077e2SLaurent Vivier 
14361e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
14371e2077e2SLaurent Vivier                          "{'bus': 'root0',"
1438b0193288SDaniel P. Berrangé                          "'failover': true,"
14391e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
14401e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
14411e2077e2SLaurent Vivier 
14421e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
14431e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
14441e2077e2SLaurent Vivier 
144593262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
14461e2077e2SLaurent Vivier 
14471e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
14481e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
14491e2077e2SLaurent Vivier 
14501e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
14511e2077e2SLaurent Vivier                          "{'bus': 'root1',"
14521e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
14531e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
14541e2077e2SLaurent Vivier                          "'rombar': 0,"
14551e2077e2SLaurent Vivier                          "'romfile': '',"
14561e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
14571e2077e2SLaurent Vivier 
14581e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
14591e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
14601e2077e2SLaurent Vivier 
14611e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
14621e2077e2SLaurent Vivier     g_assert_nonnull(args);
14631e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
14641e2077e2SLaurent Vivier 
14651e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
14661e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
14671e2077e2SLaurent Vivier     qobject_unref(resp);
14681e2077e2SLaurent Vivier 
14691e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
14701e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
14711e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
14721e2077e2SLaurent Vivier     qobject_unref(resp);
14731e2077e2SLaurent Vivier 
14741e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
14751e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
14761e2077e2SLaurent Vivier     qobject_unref(resp);
14771e2077e2SLaurent Vivier 
14781e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
14791e2077e2SLaurent Vivier 
14801e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
14811e2077e2SLaurent Vivier 
14821e2077e2SLaurent Vivier     total = 0;
14831e2077e2SLaurent Vivier     while (true) {
14841e2077e2SLaurent Vivier         ret = migrate_status(qts);
14851e2077e2SLaurent Vivier 
14861e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
14871e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
14881e2077e2SLaurent Vivier             qobject_unref(ret);
14891e2077e2SLaurent Vivier             break;
14901e2077e2SLaurent Vivier         }
14911e2077e2SLaurent Vivier         g_assert_cmpstr(status, ==, "cancelling");
14921e2077e2SLaurent Vivier         g_assert(qdict_haskey(ret, "total-time"));
14931e2077e2SLaurent Vivier         total = qdict_get_int(ret, "total-time");
14941e2077e2SLaurent Vivier         qobject_unref(ret);
14951e2077e2SLaurent Vivier     }
14961e2077e2SLaurent Vivier 
14971e2077e2SLaurent Vivier     /*
14981e2077e2SLaurent Vivier      * migration timeout in this case is 30 seconds
14991e2077e2SLaurent Vivier      * check we exit on the timeout (ms)
15001e2077e2SLaurent Vivier      */
15011e2077e2SLaurent Vivier     g_assert_cmpint(total, >, 30000);
15021e2077e2SLaurent Vivier 
15031e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
15041e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
15051e2077e2SLaurent Vivier 
15061e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
15071e2077e2SLaurent Vivier     machine_stop(qts);
15081e2077e2SLaurent Vivier }
15091e2077e2SLaurent Vivier 
1510e1e3d321SLaurent Vivier static void test_multi_out(gconstpointer opaque)
1511e1e3d321SLaurent Vivier {
1512e1e3d321SLaurent Vivier     QTestState *qts;
1513e1e3d321SLaurent Vivier     QDict *resp, *args, *ret;
1514e1e3d321SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1515e1e3d321SLaurent Vivier     const gchar *status, *expected;
1516e1e3d321SLaurent Vivier     QVirtioPCIDevice *vdev0, *vdev1;
1517e1e3d321SLaurent Vivier 
1518e1e3d321SLaurent Vivier     qts = machine_start(BASE_MACHINE
1519e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1520e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1521e1e3d321SLaurent Vivier                 "-netdev user,id=hs0 "
1522e1e3d321SLaurent Vivier                 "-netdev user,id=hs1 "
1523e1e3d321SLaurent Vivier                 "-netdev user,id=hs2 "
1524e1e3d321SLaurent Vivier                 "-netdev user,id=hs3 ",
1525e1e3d321SLaurent Vivier                 4);
1526e1e3d321SLaurent Vivier 
1527e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1528e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1529e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1530e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1531e1e3d321SLaurent Vivier 
1532e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1533e1e3d321SLaurent Vivier                          "{'bus': 'root0',"
1534b0193288SDaniel P. Berrangé                          "'failover': true,"
1535e1e3d321SLaurent Vivier                          "'netdev': 'hs0',"
1536e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1537e1e3d321SLaurent Vivier 
1538e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1539e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1540e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1541e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1542e1e3d321SLaurent Vivier 
1543e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1544e1e3d321SLaurent Vivier                          "{'bus': 'root1',"
1545e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1546e1e3d321SLaurent Vivier                          "'netdev': 'hs1',"
1547e1e3d321SLaurent Vivier                          "'rombar': 0,"
1548e1e3d321SLaurent Vivier                          "'romfile': '',"
1549e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1550e1e3d321SLaurent Vivier 
1551e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1552e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1553e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1554e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1555e1e3d321SLaurent Vivier 
155693262464SLaurent Vivier     vdev0 = start_virtio_net(qts, 1, 0, "standby0", true);
1557e1e3d321SLaurent Vivier 
1558e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1559e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1560e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1561e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1562e1e3d321SLaurent Vivier 
1563e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1564e1e3d321SLaurent Vivier                          "{'bus': 'root2',"
1565b0193288SDaniel P. Berrangé                          "'failover': true,"
1566e1e3d321SLaurent Vivier                          "'netdev': 'hs2',"
1567e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY1"'}");
1568e1e3d321SLaurent Vivier 
1569e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1570e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1571e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1572e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1573e1e3d321SLaurent Vivier 
1574e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1575e1e3d321SLaurent Vivier                          "{'bus': 'root3',"
1576e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby1',"
1577e1e3d321SLaurent Vivier                          "'netdev': 'hs3',"
1578e1e3d321SLaurent Vivier                          "'rombar': 0,"
1579e1e3d321SLaurent Vivier                          "'romfile': '',"
1580e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY1"'}");
1581e1e3d321SLaurent Vivier 
1582e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1583e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1584e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1585e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1586e1e3d321SLaurent Vivier 
158793262464SLaurent Vivier     vdev1 = start_virtio_net(qts, 3, 0, "standby1", true);
1588e1e3d321SLaurent Vivier 
1589e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1590e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1591e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1592e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1593e1e3d321SLaurent Vivier 
1594e1e3d321SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1595e1e3d321SLaurent Vivier     g_assert_nonnull(args);
1596e1e3d321SLaurent Vivier     qdict_put_str(args, "uri", uri);
1597e1e3d321SLaurent Vivier 
1598e1e3d321SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1599e1e3d321SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1600e1e3d321SLaurent Vivier     qobject_unref(resp);
1601e1e3d321SLaurent Vivier 
1602e1e3d321SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
1603e1e3d321SLaurent Vivier     resp = get_unplug_primary_event(qts);
1604e1e3d321SLaurent Vivier     if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
1605e1e3d321SLaurent Vivier         expected = "primary1";
1606e1e3d321SLaurent Vivier     } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
1607e1e3d321SLaurent Vivier         expected = "primary0";
1608e1e3d321SLaurent Vivier     } else {
1609e1e3d321SLaurent Vivier         g_assert_not_reached();
1610e1e3d321SLaurent Vivier     }
1611e1e3d321SLaurent Vivier     qobject_unref(resp);
1612e1e3d321SLaurent Vivier 
1613e1e3d321SLaurent Vivier     resp = get_unplug_primary_event(qts);
1614e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1615e1e3d321SLaurent Vivier     qobject_unref(resp);
1616e1e3d321SLaurent Vivier 
1617e1e3d321SLaurent Vivier     /* wait the end of the migration setup phase */
1618e1e3d321SLaurent Vivier     while (true) {
1619e1e3d321SLaurent Vivier         ret = migrate_status(qts);
1620e1e3d321SLaurent Vivier 
1621e1e3d321SLaurent Vivier         status = qdict_get_str(ret, "status");
1622e1e3d321SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
1623e1e3d321SLaurent Vivier             qobject_unref(ret);
1624e1e3d321SLaurent Vivier             break;
1625e1e3d321SLaurent Vivier         }
1626e1e3d321SLaurent Vivier 
1627e1e3d321SLaurent Vivier         /* The migration must not start if the card is not ejected */
1628e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
1629e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
1630e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1631e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1632e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1633e1e3d321SLaurent Vivier 
1634e1e3d321SLaurent Vivier         qobject_unref(ret);
1635e1e3d321SLaurent Vivier     }
1636e1e3d321SLaurent Vivier 
1637e1e3d321SLaurent Vivier     /* OS unplugs primary1, but we must wait the second */
1638e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1639e1e3d321SLaurent Vivier 
1640e1e3d321SLaurent Vivier     ret = migrate_status(qts);
1641e1e3d321SLaurent Vivier     status = qdict_get_str(ret, "status");
1642e1e3d321SLaurent Vivier     g_assert_cmpstr(status, ==, "wait-unplug");
1643e1e3d321SLaurent Vivier     qobject_unref(ret);
1644e1e3d321SLaurent Vivier 
1645e1e3d321SLaurent Vivier     if (g_test_slow()) {
1646e1e3d321SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
1647e1e3d321SLaurent Vivier         for (int i = 0; i < 5; i++) {
1648e1e3d321SLaurent Vivier             sleep(1);
1649e1e3d321SLaurent Vivier             ret = migrate_status(qts);
1650e1e3d321SLaurent Vivier             status = qdict_get_str(ret, "status");
1651e1e3d321SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
1652e1e3d321SLaurent Vivier             qobject_unref(ret);
1653e1e3d321SLaurent Vivier         }
1654e1e3d321SLaurent Vivier     }
1655e1e3d321SLaurent Vivier 
1656e1e3d321SLaurent Vivier     /* OS unplugs primary0, QEMU can move from wait-unplug state */
1657e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
1658e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1659e1e3d321SLaurent Vivier 
1660e1e3d321SLaurent Vivier     while (true) {
1661e1e3d321SLaurent Vivier         ret = migrate_status(qts);
1662e1e3d321SLaurent Vivier 
1663e1e3d321SLaurent Vivier         status = qdict_get_str(ret, "status");
1664e1e3d321SLaurent Vivier         if (strcmp(status, "completed") == 0) {
1665e1e3d321SLaurent Vivier             qobject_unref(ret);
1666e1e3d321SLaurent Vivier             break;
1667e1e3d321SLaurent Vivier         }
1668e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1669e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1670e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1671e1e3d321SLaurent Vivier         qobject_unref(ret);
1672e1e3d321SLaurent Vivier     }
1673e1e3d321SLaurent Vivier 
1674e1e3d321SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
1675e1e3d321SLaurent Vivier 
1676e1e3d321SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev0);
1677e1e3d321SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev1);
1678e1e3d321SLaurent Vivier     machine_stop(qts);
1679e1e3d321SLaurent Vivier }
1680e1e3d321SLaurent Vivier 
1681e1e3d321SLaurent Vivier static void test_multi_in(gconstpointer opaque)
1682e1e3d321SLaurent Vivier {
1683e1e3d321SLaurent Vivier     QTestState *qts;
16846830e53bSFabiano Rosas     QDict *resp, *ret;
1685e1e3d321SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1686e1e3d321SLaurent Vivier 
1687e1e3d321SLaurent Vivier     qts = machine_start(BASE_MACHINE
1688e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1689e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1690e1e3d321SLaurent Vivier                 "-netdev user,id=hs0 "
1691e1e3d321SLaurent Vivier                 "-netdev user,id=hs1 "
1692e1e3d321SLaurent Vivier                 "-netdev user,id=hs2 "
1693e1e3d321SLaurent Vivier                 "-netdev user,id=hs3 "
1694e1e3d321SLaurent Vivier                 "-incoming defer ",
1695e1e3d321SLaurent Vivier                 4);
1696e1e3d321SLaurent Vivier 
1697e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1698e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1699e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1700e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1701e1e3d321SLaurent Vivier 
1702e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1703e1e3d321SLaurent Vivier                          "{'bus': 'root0',"
1704b0193288SDaniel P. Berrangé                          "'failover': true,"
1705e1e3d321SLaurent Vivier                          "'netdev': 'hs0',"
1706e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1707e1e3d321SLaurent Vivier 
1708e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1709e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1710e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1711e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1712e1e3d321SLaurent Vivier 
1713e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1714e1e3d321SLaurent Vivier                          "{'bus': 'root1',"
1715e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1716e1e3d321SLaurent Vivier                          "'netdev': 'hs1',"
1717e1e3d321SLaurent Vivier                          "'rombar': 0,"
1718e1e3d321SLaurent Vivier                          "'romfile': '',"
1719e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1720e1e3d321SLaurent Vivier 
1721e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1722e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1723e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1724e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1725e1e3d321SLaurent Vivier 
1726e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1727e1e3d321SLaurent Vivier                          "{'bus': 'root2',"
1728b0193288SDaniel P. Berrangé                          "'failover': true,"
1729e1e3d321SLaurent Vivier                          "'netdev': 'hs2',"
1730e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY1"'}");
1731e1e3d321SLaurent Vivier 
1732e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1733e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1734e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1735e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1736e1e3d321SLaurent Vivier 
1737e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1738e1e3d321SLaurent Vivier                          "{'bus': 'root3',"
1739e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby1',"
1740e1e3d321SLaurent Vivier                          "'netdev': 'hs3',"
1741e1e3d321SLaurent Vivier                          "'rombar': 0,"
1742e1e3d321SLaurent Vivier                          "'romfile': '',"
1743e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY1"'}");
1744e1e3d321SLaurent Vivier 
1745e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1746e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1747e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1748e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1749e1e3d321SLaurent Vivier 
17506830e53bSFabiano Rosas     migrate_incoming_qmp(qts, uri, "{}");
1751e1e3d321SLaurent Vivier 
1752e1e3d321SLaurent Vivier     resp = get_failover_negociated_event(qts);
1753e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1754e1e3d321SLaurent Vivier     qobject_unref(resp);
1755e1e3d321SLaurent Vivier 
1756e1e3d321SLaurent Vivier     resp = get_failover_negociated_event(qts);
1757e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1758e1e3d321SLaurent Vivier     qobject_unref(resp);
1759e1e3d321SLaurent Vivier 
1760e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1761e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1762e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1763e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1764e1e3d321SLaurent Vivier 
1765e1e3d321SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
1766e1e3d321SLaurent Vivier 
1767e1e3d321SLaurent Vivier     ret = migrate_status(qts);
1768e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1769e1e3d321SLaurent Vivier     qobject_unref(ret);
1770e1e3d321SLaurent Vivier 
1771e1e3d321SLaurent Vivier     machine_stop(qts);
1772e1e3d321SLaurent Vivier }
1773a6866706SXuzhou Cheng #endif /* _WIN32 */
1774e1e3d321SLaurent Vivier 
1775e32b96b5SLaurent Vivier int main(int argc, char **argv)
1776e32b96b5SLaurent Vivier {
1777e63ed64cSThomas Huth     gchar *tmpfile;
1778e32b96b5SLaurent Vivier     int ret;
1779e32b96b5SLaurent Vivier 
1780e32b96b5SLaurent Vivier     g_test_init(&argc, &argv, NULL);
1781e32b96b5SLaurent Vivier 
1782e63ed64cSThomas Huth     ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
1783e63ed64cSThomas Huth     g_assert_true(ret >= 0);
1784e63ed64cSThomas Huth     close(ret);
1785e63ed64cSThomas Huth 
1786fbd2913cSLaurent Vivier     /* parameters tests */
1787e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1788e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1789e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on", test_on);
1790e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on_mismatch",
1791e32b96b5SLaurent Vivier                    test_on_mismatch);
1792e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/off", test_off);
1793e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
179478475083SLaurent Vivier     qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off);
1795fbd2913cSLaurent Vivier 
1796fbd2913cSLaurent Vivier     /* hotplug tests */
1797fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1);
1798fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/1_reverse",
1799e32b96b5SLaurent Vivier                    test_hotplug_1_reverse);
1800fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2);
1801fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/2_reverse",
1802e32b96b5SLaurent Vivier                    test_hotplug_2_reverse);
1803fbd2913cSLaurent Vivier 
1804a6866706SXuzhou Cheng #ifndef _WIN32
1805a6866706SXuzhou Cheng     /*
1806a6866706SXuzhou Cheng      * These migration tests cases use the exec migration protocol,
1807a6866706SXuzhou Cheng      * which is unsupported on Windows.
1808a6866706SXuzhou Cheng      */
1809fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile,
1810e32b96b5SLaurent Vivier                         test_migrate_out);
1811fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile,
1812e32b96b5SLaurent Vivier                         test_migrate_in);
18137f998491SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/off/out", tmpfile,
18147f998491SLaurent Vivier                         test_off_migrate_out);
18157f998491SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/off/in", tmpfile,
18167f998491SLaurent Vivier                         test_off_migrate_in);
1817e20977b7SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/off/abort", tmpfile,
1818e20977b7SLaurent Vivier                         test_migrate_off_abort);
1819d9872c00SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/guest_off/out", tmpfile,
1820d9872c00SLaurent Vivier                         test_guest_off_migrate_out);
1821d9872c00SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/guest_off/in", tmpfile,
1822d9872c00SLaurent Vivier                         test_guest_off_migrate_in);
1823e20977b7SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/guest_off/abort", tmpfile,
1824e20977b7SLaurent Vivier                         test_migrate_guest_off_abort);
18251e2077e2SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
18261e2077e2SLaurent Vivier                         tmpfile, test_migrate_abort_wait_unplug);
18271e2077e2SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
18281e2077e2SLaurent Vivier                         test_migrate_abort_active);
18291e2077e2SLaurent Vivier     if (g_test_slow()) {
18301e2077e2SLaurent Vivier         qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
18311e2077e2SLaurent Vivier                             tmpfile, test_migrate_abort_timeout);
18321e2077e2SLaurent Vivier     }
1833fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/multi/out",
1834e1e3d321SLaurent Vivier                         tmpfile, test_multi_out);
1835fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/multi/in",
1836e1e3d321SLaurent Vivier                    tmpfile, test_multi_in);
1837a6866706SXuzhou Cheng #endif /* _WIN32 */
1838e32b96b5SLaurent Vivier 
1839e32b96b5SLaurent Vivier     ret = g_test_run();
1840e32b96b5SLaurent Vivier 
1841e32b96b5SLaurent Vivier     unlink(tmpfile);
1842e32b96b5SLaurent Vivier     g_free(tmpfile);
1843e32b96b5SLaurent Vivier 
1844e32b96b5SLaurent Vivier     return ret;
1845e32b96b5SLaurent Vivier }
1846