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