xref: /qemu/tests/qtest/virtio-net-failover.c (revision 6ae6a30ca579be81d5a4a0e2cbfe714d375e0560)
1e32b96b5SLaurent Vivier /*
2e32b96b5SLaurent Vivier  * QTest testcase for virtio-net failover
3e32b96b5SLaurent Vivier  *
4e32b96b5SLaurent Vivier  * See docs/system/virtio-net-failover.rst
5e32b96b5SLaurent Vivier  *
6e32b96b5SLaurent Vivier  * Copyright (c) 2021 Red Hat, Inc.
7e32b96b5SLaurent Vivier  *
8e32b96b5SLaurent Vivier  * SPDX-License-Identifier: GPL-2.0-or-later
9e32b96b5SLaurent Vivier  */
10e32b96b5SLaurent Vivier #include "qemu/osdep.h"
11e32b96b5SLaurent Vivier #include "libqos/libqtest.h"
12e32b96b5SLaurent Vivier #include "libqos/pci.h"
13e32b96b5SLaurent Vivier #include "libqos/pci-pc.h"
14e32b96b5SLaurent Vivier #include "qapi/qmp/qdict.h"
15e32b96b5SLaurent Vivier #include "qapi/qmp/qlist.h"
16e32b96b5SLaurent Vivier #include "qapi/qmp/qjson.h"
17e32b96b5SLaurent Vivier #include "libqos/malloc-pc.h"
18e32b96b5SLaurent Vivier #include "libqos/virtio-pci.h"
19e32b96b5SLaurent Vivier #include "hw/pci/pci.h"
20e32b96b5SLaurent Vivier 
2193262464SLaurent Vivier #define VIRTIO_NET_F_STANDBY    62
2293262464SLaurent Vivier 
23e32b96b5SLaurent Vivier #define ACPI_PCIHP_ADDR_ICH9    0x0cc0
24e32b96b5SLaurent Vivier #define PCI_EJ_BASE             0x0008
25e1e3d321SLaurent Vivier #define PCI_SEL_BASE            0x0010
26e32b96b5SLaurent Vivier 
27e32b96b5SLaurent Vivier #define BASE_MACHINE "-M q35 -nodefaults " \
28e32b96b5SLaurent Vivier     "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
29e32b96b5SLaurent Vivier     "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "
30e32b96b5SLaurent Vivier 
31e32b96b5SLaurent Vivier #define MAC_PRIMARY0 "52:54:00:11:11:11"
32e32b96b5SLaurent Vivier #define MAC_STANDBY0 "52:54:00:22:22:22"
33e1e3d321SLaurent Vivier #define MAC_PRIMARY1 "52:54:00:33:33:33"
34e1e3d321SLaurent Vivier #define MAC_STANDBY1 "52:54:00:44:44:44"
35e32b96b5SLaurent Vivier 
36e32b96b5SLaurent Vivier static QGuestAllocator guest_malloc;
37e32b96b5SLaurent Vivier static QPCIBus *pcibus;
38e32b96b5SLaurent Vivier 
39e32b96b5SLaurent Vivier static QTestState *machine_start(const char *args, int numbus)
40e32b96b5SLaurent Vivier {
41e32b96b5SLaurent Vivier     QTestState *qts;
42e32b96b5SLaurent Vivier     QPCIDevice *dev;
43e32b96b5SLaurent Vivier     int bus;
44e32b96b5SLaurent Vivier 
45e32b96b5SLaurent Vivier     qts = qtest_init(args);
46e32b96b5SLaurent Vivier 
47e32b96b5SLaurent Vivier     pc_alloc_init(&guest_malloc, qts, 0);
48e32b96b5SLaurent Vivier     pcibus = qpci_new_pc(qts, &guest_malloc);
49e32b96b5SLaurent Vivier     g_assert(qpci_secondary_buses_init(pcibus) == numbus);
50e32b96b5SLaurent Vivier 
51e32b96b5SLaurent Vivier     for (bus = 1; bus <= numbus; bus++) {
52e32b96b5SLaurent Vivier         dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0));
53e32b96b5SLaurent Vivier         g_assert_nonnull(dev);
54e32b96b5SLaurent Vivier 
55e32b96b5SLaurent Vivier         qpci_device_enable(dev);
56e32b96b5SLaurent Vivier         qpci_iomap(dev, 4, NULL);
57e32b96b5SLaurent Vivier 
58e32b96b5SLaurent Vivier         g_free(dev);
59e32b96b5SLaurent Vivier     }
60e32b96b5SLaurent Vivier 
61e32b96b5SLaurent Vivier     return qts;
62e32b96b5SLaurent Vivier }
63e32b96b5SLaurent Vivier 
64e32b96b5SLaurent Vivier static void machine_stop(QTestState *qts)
65e32b96b5SLaurent Vivier {
66e32b96b5SLaurent Vivier     qpci_free_pc(pcibus);
67e32b96b5SLaurent Vivier     alloc_destroy(&guest_malloc);
68e32b96b5SLaurent Vivier     qtest_quit(qts);
69e32b96b5SLaurent Vivier }
70e32b96b5SLaurent Vivier 
71e32b96b5SLaurent Vivier static void test_error_id(void)
72e32b96b5SLaurent Vivier {
73e32b96b5SLaurent Vivier     QTestState *qts;
74e32b96b5SLaurent Vivier     QDict *resp;
75e32b96b5SLaurent Vivier     QDict *err;
76e32b96b5SLaurent Vivier 
77e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
78e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,failover=on",
79e32b96b5SLaurent Vivier                         2);
80e32b96b5SLaurent Vivier 
81e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{'execute': 'device_add',"
82e32b96b5SLaurent Vivier                           "'arguments': {"
83e32b96b5SLaurent Vivier                           "'driver': 'virtio-net',"
84e32b96b5SLaurent Vivier                           "'bus': 'root1',"
85e32b96b5SLaurent Vivier                           "'failover_pair_id': 'standby0'"
86e32b96b5SLaurent Vivier                           "} }");
87e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "error"));
88e32b96b5SLaurent Vivier 
89e32b96b5SLaurent Vivier     err = qdict_get_qdict(resp, "error");
90e32b96b5SLaurent Vivier     g_assert(qdict_haskey(err, "desc"));
91e32b96b5SLaurent Vivier 
92e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
93e32b96b5SLaurent Vivier                     "Device with failover_pair_id needs to have id");
94e32b96b5SLaurent Vivier 
95e32b96b5SLaurent Vivier     qobject_unref(resp);
96e32b96b5SLaurent Vivier 
97e32b96b5SLaurent Vivier     machine_stop(qts);
98e32b96b5SLaurent Vivier }
99e32b96b5SLaurent Vivier 
100e32b96b5SLaurent Vivier static void test_error_pcie(void)
101e32b96b5SLaurent Vivier {
102e32b96b5SLaurent Vivier     QTestState *qts;
103e32b96b5SLaurent Vivier     QDict *resp;
104e32b96b5SLaurent Vivier     QDict *err;
105e32b96b5SLaurent Vivier 
106e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
107e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,failover=on",
108e32b96b5SLaurent Vivier                         2);
109e32b96b5SLaurent Vivier 
110e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{'execute': 'device_add',"
111e32b96b5SLaurent Vivier                           "'arguments': {"
112e32b96b5SLaurent Vivier                           "'driver': 'virtio-net',"
113e32b96b5SLaurent Vivier                           "'id': 'primary0',"
114e32b96b5SLaurent Vivier                           "'bus': 'pcie.0',"
115e32b96b5SLaurent Vivier                           "'failover_pair_id': 'standby0'"
116e32b96b5SLaurent Vivier                           "} }");
117e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "error"));
118e32b96b5SLaurent Vivier 
119e32b96b5SLaurent Vivier     err = qdict_get_qdict(resp, "error");
120e32b96b5SLaurent Vivier     g_assert(qdict_haskey(err, "desc"));
121e32b96b5SLaurent Vivier 
122e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
123e32b96b5SLaurent Vivier                     "Bus 'pcie.0' does not support hotplugging");
124e32b96b5SLaurent Vivier 
125e32b96b5SLaurent Vivier     qobject_unref(resp);
126e32b96b5SLaurent Vivier 
127e32b96b5SLaurent Vivier     machine_stop(qts);
128e32b96b5SLaurent Vivier }
129e32b96b5SLaurent Vivier 
130e32b96b5SLaurent Vivier static QDict *find_device(QDict *bus, const char *name)
131e32b96b5SLaurent Vivier {
132e32b96b5SLaurent Vivier     const QObject *obj;
133e32b96b5SLaurent Vivier     QList *devices;
134e32b96b5SLaurent Vivier     QList *list;
135e32b96b5SLaurent Vivier 
136e32b96b5SLaurent Vivier     devices = qdict_get_qlist(bus, "devices");
137e32b96b5SLaurent Vivier     if (devices == NULL) {
138e32b96b5SLaurent Vivier         return NULL;
139e32b96b5SLaurent Vivier     }
140e32b96b5SLaurent Vivier 
141e32b96b5SLaurent Vivier     list = qlist_copy(devices);
142e32b96b5SLaurent Vivier     while ((obj = qlist_pop(list))) {
143e32b96b5SLaurent Vivier         QDict *device;
144e32b96b5SLaurent Vivier 
145e32b96b5SLaurent Vivier         device = qobject_to(QDict, obj);
146e32b96b5SLaurent Vivier 
147e32b96b5SLaurent Vivier         if (qdict_haskey(device, "pci_bridge")) {
148e32b96b5SLaurent Vivier             QDict *bridge;
149e32b96b5SLaurent Vivier             QDict *bridge_device;
150e32b96b5SLaurent Vivier 
151e32b96b5SLaurent Vivier             bridge = qdict_get_qdict(device, "pci_bridge");
152e32b96b5SLaurent Vivier 
153e32b96b5SLaurent Vivier             if (qdict_haskey(bridge, "devices")) {
154e32b96b5SLaurent Vivier                 bridge_device = find_device(bridge, name);
155e32b96b5SLaurent Vivier                 if (bridge_device) {
156e32b96b5SLaurent Vivier                     qobject_unref(device);
157e32b96b5SLaurent Vivier                     qobject_unref(list);
158e32b96b5SLaurent Vivier                     return bridge_device;
159e32b96b5SLaurent Vivier                 }
160e32b96b5SLaurent Vivier             }
161e32b96b5SLaurent Vivier         }
162e32b96b5SLaurent Vivier 
163e32b96b5SLaurent Vivier         if (!qdict_haskey(device, "qdev_id")) {
164e32b96b5SLaurent Vivier             qobject_unref(device);
165e32b96b5SLaurent Vivier             continue;
166e32b96b5SLaurent Vivier         }
167e32b96b5SLaurent Vivier 
168e32b96b5SLaurent Vivier         if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) {
169e32b96b5SLaurent Vivier             qobject_unref(list);
170e32b96b5SLaurent Vivier             return device;
171e32b96b5SLaurent Vivier         }
172e32b96b5SLaurent Vivier         qobject_unref(device);
173e32b96b5SLaurent Vivier     }
174e32b96b5SLaurent Vivier     qobject_unref(list);
175e32b96b5SLaurent Vivier 
176e32b96b5SLaurent Vivier     return NULL;
177e32b96b5SLaurent Vivier }
178e32b96b5SLaurent Vivier 
179e32b96b5SLaurent Vivier static QDict *get_bus(QTestState *qts, int num)
180e32b96b5SLaurent Vivier {
181e32b96b5SLaurent Vivier     QObject *obj;
182e32b96b5SLaurent Vivier     QDict *resp;
183e32b96b5SLaurent Vivier     QList *ret;
184e32b96b5SLaurent Vivier 
185e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }");
186e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
187e32b96b5SLaurent Vivier 
188e32b96b5SLaurent Vivier     ret = qdict_get_qlist(resp, "return");
189e32b96b5SLaurent Vivier     g_assert_nonnull(ret);
190e32b96b5SLaurent Vivier 
191e32b96b5SLaurent Vivier     while ((obj = qlist_pop(ret))) {
192e32b96b5SLaurent Vivier         QDict *bus;
193e32b96b5SLaurent Vivier 
194e32b96b5SLaurent Vivier         bus = qobject_to(QDict, obj);
195e32b96b5SLaurent Vivier         if (!qdict_haskey(bus, "bus")) {
196e32b96b5SLaurent Vivier             qobject_unref(bus);
197e32b96b5SLaurent Vivier             continue;
198e32b96b5SLaurent Vivier         }
199e32b96b5SLaurent Vivier         if (qdict_get_int(bus, "bus") == num) {
200e32b96b5SLaurent Vivier             qobject_unref(resp);
201e32b96b5SLaurent Vivier             return bus;
202e32b96b5SLaurent Vivier         }
203e32b96b5SLaurent Vivier         qobject_ref(bus);
204e32b96b5SLaurent Vivier     }
205e32b96b5SLaurent Vivier     qobject_unref(resp);
206e32b96b5SLaurent Vivier 
207e32b96b5SLaurent Vivier     return NULL;
208e32b96b5SLaurent Vivier }
209e32b96b5SLaurent Vivier 
210e32b96b5SLaurent Vivier static char *get_mac(QTestState *qts, const char *name)
211e32b96b5SLaurent Vivier {
212e32b96b5SLaurent Vivier     QDict *resp;
213e32b96b5SLaurent Vivier     char *mac;
214e32b96b5SLaurent Vivier 
215e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'qom-get', "
216e32b96b5SLaurent Vivier                      "'arguments': { "
217e32b96b5SLaurent Vivier                      "'path': %s, "
218e32b96b5SLaurent Vivier                      "'property': 'mac' } }", name);
219e32b96b5SLaurent Vivier 
220e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
221e32b96b5SLaurent Vivier 
222e32b96b5SLaurent Vivier     mac = g_strdup(qdict_get_str(resp, "return"));
223e32b96b5SLaurent Vivier 
224e32b96b5SLaurent Vivier     qobject_unref(resp);
225e32b96b5SLaurent Vivier 
226e32b96b5SLaurent Vivier     return mac;
227e32b96b5SLaurent Vivier }
228e32b96b5SLaurent Vivier 
2291a800870SLaurent Vivier #define check_one_card(qts, present, id, mac)                   \
2301a800870SLaurent Vivier do {                                                            \
2311a800870SLaurent Vivier     QDict *device;                                              \
2321a800870SLaurent Vivier     QDict *bus;                                                 \
2331a800870SLaurent Vivier     char *addr;                                                 \
2341a800870SLaurent Vivier     bus = get_bus(qts, 0);                                      \
2351a800870SLaurent Vivier     device = find_device(bus, id);                              \
2361a800870SLaurent Vivier     if (present) {                                              \
2371a800870SLaurent Vivier         char *path;                                             \
2381a800870SLaurent Vivier         g_assert_nonnull(device);                               \
2391a800870SLaurent Vivier         qobject_unref(device);                                  \
2401a800870SLaurent Vivier         path = g_strdup_printf("/machine/peripheral/%s", id);   \
2411a800870SLaurent Vivier         addr = get_mac(qts, path);                              \
2421a800870SLaurent Vivier         g_free(path);                                           \
2431a800870SLaurent Vivier         g_assert_cmpstr(mac, ==, addr);                         \
2441a800870SLaurent Vivier         g_free(addr);                                           \
2451a800870SLaurent Vivier     } else {                                                    \
2461a800870SLaurent Vivier        g_assert_null(device);                                   \
2471a800870SLaurent Vivier     }                                                           \
2481a800870SLaurent Vivier     qobject_unref(bus);                                         \
2491a800870SLaurent Vivier } while (0)
250e32b96b5SLaurent Vivier 
251e32b96b5SLaurent Vivier static QDict *get_failover_negociated_event(QTestState *qts)
252e32b96b5SLaurent Vivier {
253e32b96b5SLaurent Vivier     QDict *resp;
254e32b96b5SLaurent Vivier     QDict *data;
255e32b96b5SLaurent Vivier 
256e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED");
257e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
258e32b96b5SLaurent Vivier 
259e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
260e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
261e32b96b5SLaurent Vivier     qobject_ref(data);
262e32b96b5SLaurent Vivier     qobject_unref(resp);
263e32b96b5SLaurent Vivier 
264e32b96b5SLaurent Vivier     return data;
265e32b96b5SLaurent Vivier }
266e32b96b5SLaurent Vivier 
26793262464SLaurent Vivier static QVirtioPCIDevice *start_virtio_net_internal(QTestState *qts,
26893262464SLaurent Vivier                                                    int bus, int slot,
26993262464SLaurent Vivier                                                    uint64_t *features)
270e32b96b5SLaurent Vivier {
271e32b96b5SLaurent Vivier     QVirtioPCIDevice *dev;
272e32b96b5SLaurent Vivier     QPCIAddress addr;
273e32b96b5SLaurent Vivier 
274e32b96b5SLaurent Vivier     addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0);
275e32b96b5SLaurent Vivier     dev = virtio_pci_new(pcibus, &addr);
276e32b96b5SLaurent Vivier     g_assert_nonnull(dev);
277e32b96b5SLaurent Vivier     qvirtio_pci_device_enable(dev);
278e32b96b5SLaurent Vivier     qvirtio_start_device(&dev->vdev);
27993262464SLaurent Vivier     *features &= qvirtio_get_features(&dev->vdev);
28093262464SLaurent Vivier     qvirtio_set_features(&dev->vdev, *features);
28193262464SLaurent Vivier     qvirtio_set_driver_ok(&dev->vdev);
28293262464SLaurent Vivier     return dev;
28393262464SLaurent Vivier }
28493262464SLaurent Vivier 
28593262464SLaurent Vivier static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
28693262464SLaurent Vivier                                           const char *id, bool failover)
28793262464SLaurent Vivier {
28893262464SLaurent Vivier     QVirtioPCIDevice *dev;
28993262464SLaurent Vivier     uint64_t features;
29093262464SLaurent Vivier 
29193262464SLaurent Vivier     features = ~(QVIRTIO_F_BAD_FEATURE |
292e32b96b5SLaurent Vivier                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
293e32b96b5SLaurent Vivier                  (1ull << VIRTIO_RING_F_EVENT_IDX));
29493262464SLaurent Vivier 
29593262464SLaurent Vivier     dev = start_virtio_net_internal(qts, bus, slot, &features);
29693262464SLaurent Vivier 
29793262464SLaurent Vivier     g_assert(!!(features & (1ull << VIRTIO_NET_F_STANDBY)) == failover);
29893262464SLaurent Vivier 
29993262464SLaurent Vivier     if (failover) {
30093262464SLaurent Vivier         QDict *resp;
301e32b96b5SLaurent Vivier 
302e32b96b5SLaurent Vivier         resp = get_failover_negociated_event(qts);
303e32b96b5SLaurent Vivier         g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
304e32b96b5SLaurent Vivier         qobject_unref(resp);
30593262464SLaurent Vivier     }
306e32b96b5SLaurent Vivier 
307e32b96b5SLaurent Vivier     return dev;
308e32b96b5SLaurent Vivier }
309e32b96b5SLaurent Vivier 
31093262464SLaurent Vivier static void test_on(void)
31193262464SLaurent Vivier {
31293262464SLaurent Vivier     QTestState *qts;
31393262464SLaurent Vivier 
31493262464SLaurent Vivier     qts = machine_start(BASE_MACHINE
31593262464SLaurent Vivier                         "-netdev user,id=hs0 "
31693262464SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,"
31793262464SLaurent Vivier                         "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
31893262464SLaurent Vivier                         "-netdev user,id=hs1 "
31993262464SLaurent Vivier                         "-device virtio-net,bus=root1,id=primary0,"
32093262464SLaurent Vivier                         "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
32193262464SLaurent Vivier                         2);
32293262464SLaurent Vivier 
32393262464SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
32493262464SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
32593262464SLaurent Vivier 
32693262464SLaurent Vivier     machine_stop(qts);
32793262464SLaurent Vivier }
32893262464SLaurent Vivier 
32993262464SLaurent Vivier static void test_on_mismatch(void)
33093262464SLaurent Vivier {
33193262464SLaurent Vivier     QTestState *qts;
33293262464SLaurent Vivier     QVirtioPCIDevice *vdev;
33393262464SLaurent Vivier 
33493262464SLaurent Vivier     qts = machine_start(BASE_MACHINE
33593262464SLaurent Vivier                      "-netdev user,id=hs0 "
33693262464SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
33793262464SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
33893262464SLaurent Vivier                      "-netdev user,id=hs1 "
33993262464SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
34093262464SLaurent Vivier                      "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0,
34193262464SLaurent Vivier                      2);
34293262464SLaurent Vivier 
34393262464SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
34493262464SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
34593262464SLaurent Vivier 
34693262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
34793262464SLaurent Vivier 
34893262464SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
34993262464SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
35093262464SLaurent Vivier 
35193262464SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
35293262464SLaurent Vivier     machine_stop(qts);
35393262464SLaurent Vivier }
35493262464SLaurent Vivier 
35593262464SLaurent Vivier static void test_off(void)
35693262464SLaurent Vivier {
35793262464SLaurent Vivier     QTestState *qts;
35893262464SLaurent Vivier     QVirtioPCIDevice *vdev;
35993262464SLaurent Vivier 
36093262464SLaurent Vivier     qts = machine_start(BASE_MACHINE
36193262464SLaurent Vivier                      "-netdev user,id=hs0 "
36293262464SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
36393262464SLaurent Vivier                      "failover=off,netdev=hs0,mac="MAC_STANDBY0" "
36493262464SLaurent Vivier                      "-netdev user,id=hs1 "
36593262464SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
36693262464SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
36793262464SLaurent Vivier                      2);
36893262464SLaurent Vivier 
36993262464SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
37093262464SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
37193262464SLaurent Vivier 
37293262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
37393262464SLaurent Vivier 
37493262464SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
37593262464SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
37693262464SLaurent Vivier 
37793262464SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
37893262464SLaurent Vivier     machine_stop(qts);
37993262464SLaurent Vivier }
38093262464SLaurent Vivier 
381e32b96b5SLaurent Vivier static void test_enabled(void)
382e32b96b5SLaurent Vivier {
383e32b96b5SLaurent Vivier     QTestState *qts;
384e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
385e32b96b5SLaurent Vivier 
386e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
387e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
388e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
389e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
390e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
391e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
392e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
393e32b96b5SLaurent Vivier                      2);
394e32b96b5SLaurent Vivier 
395e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
396e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
397e32b96b5SLaurent Vivier 
39893262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
399e32b96b5SLaurent Vivier 
400e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
401e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
402e32b96b5SLaurent Vivier 
403e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
404e32b96b5SLaurent Vivier     machine_stop(qts);
405e32b96b5SLaurent Vivier }
406e32b96b5SLaurent Vivier 
40778475083SLaurent Vivier static void test_guest_off(void)
40878475083SLaurent Vivier {
40978475083SLaurent Vivier     QTestState *qts;
41078475083SLaurent Vivier     QVirtioPCIDevice *vdev;
41178475083SLaurent Vivier     uint64_t features;
41278475083SLaurent Vivier 
41378475083SLaurent Vivier     qts = machine_start(BASE_MACHINE
41478475083SLaurent Vivier                      "-netdev user,id=hs0 "
41578475083SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
41678475083SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
41778475083SLaurent Vivier                      "-netdev user,id=hs1 "
41878475083SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
41978475083SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
42078475083SLaurent Vivier                      2);
42178475083SLaurent Vivier 
42278475083SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
42378475083SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
42478475083SLaurent Vivier 
42578475083SLaurent Vivier     features = ~(QVIRTIO_F_BAD_FEATURE |
42678475083SLaurent Vivier                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
42778475083SLaurent Vivier                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
42878475083SLaurent Vivier                  (1ull << VIRTIO_NET_F_STANDBY));
42978475083SLaurent Vivier 
43078475083SLaurent Vivier     vdev = start_virtio_net_internal(qts, 1, 0, &features);
43178475083SLaurent Vivier 
43278475083SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
43378475083SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
43478475083SLaurent Vivier 
43578475083SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
43678475083SLaurent Vivier     machine_stop(qts);
43778475083SLaurent Vivier }
43878475083SLaurent Vivier 
439e32b96b5SLaurent Vivier static void test_hotplug_1(void)
440e32b96b5SLaurent Vivier {
441e32b96b5SLaurent Vivier     QTestState *qts;
442e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
443e32b96b5SLaurent Vivier 
444e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
445e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
446e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
447e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
448e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ", 2);
449e32b96b5SLaurent Vivier 
450e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
451e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
452e32b96b5SLaurent Vivier 
45393262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
454e32b96b5SLaurent Vivier 
455e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
456e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
457e32b96b5SLaurent Vivier 
458e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
459e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
460e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
461e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
462e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
463e32b96b5SLaurent Vivier 
464e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
465e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
466e32b96b5SLaurent Vivier 
467e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
468e32b96b5SLaurent Vivier     machine_stop(qts);
469e32b96b5SLaurent Vivier }
470e32b96b5SLaurent Vivier 
471e32b96b5SLaurent Vivier static void test_hotplug_1_reverse(void)
472e32b96b5SLaurent Vivier {
473e32b96b5SLaurent Vivier     QTestState *qts;
474e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
475e32b96b5SLaurent Vivier 
476e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
477e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
478e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
479e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
480e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
481e32b96b5SLaurent Vivier                      2);
482e32b96b5SLaurent Vivier 
483e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
484e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
485e32b96b5SLaurent Vivier 
486e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
487e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
488e32b96b5SLaurent Vivier                          "'failover': 'on',"
489e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
490e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
491e32b96b5SLaurent Vivier 
492e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
493e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
494e32b96b5SLaurent Vivier 
49593262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
496e32b96b5SLaurent Vivier 
497e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
498e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
499e32b96b5SLaurent Vivier 
500e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
501e32b96b5SLaurent Vivier     machine_stop(qts);
502e32b96b5SLaurent Vivier }
503e32b96b5SLaurent Vivier 
504e32b96b5SLaurent Vivier static void test_hotplug_2(void)
505e32b96b5SLaurent Vivier {
506e32b96b5SLaurent Vivier     QTestState *qts;
507e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
508e32b96b5SLaurent Vivier 
509e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
510e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
511e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
512e32b96b5SLaurent Vivier                      2);
513e32b96b5SLaurent Vivier 
514e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
515e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
516e32b96b5SLaurent Vivier 
517e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
518e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
519e32b96b5SLaurent Vivier                          "'failover': 'on',"
520e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
521e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
522e32b96b5SLaurent Vivier 
523e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
524e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
525e32b96b5SLaurent Vivier 
52693262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
527e32b96b5SLaurent Vivier 
528e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
529e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
530e32b96b5SLaurent Vivier 
531e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
532e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
533e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
534e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
535e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
536e32b96b5SLaurent Vivier 
537e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
538e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
539e32b96b5SLaurent Vivier 
540e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
541e32b96b5SLaurent Vivier     machine_stop(qts);
542e32b96b5SLaurent Vivier }
543e32b96b5SLaurent Vivier 
544e32b96b5SLaurent Vivier static void test_hotplug_2_reverse(void)
545e32b96b5SLaurent Vivier {
546e32b96b5SLaurent Vivier     QTestState *qts;
547e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
548e32b96b5SLaurent Vivier 
549e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
550e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
551e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
552e32b96b5SLaurent Vivier                      2);
553e32b96b5SLaurent Vivier 
554e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
555e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
556e32b96b5SLaurent Vivier 
557e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
558e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
559e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
560e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
561e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
562e32b96b5SLaurent Vivier 
563e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
564e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
565e32b96b5SLaurent Vivier 
566e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
567e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
568e32b96b5SLaurent Vivier                          "'failover': 'on',"
569e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
570e32b96b5SLaurent Vivier                          "'rombar': 0,"
571e32b96b5SLaurent Vivier                          "'romfile': '',"
572e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
573e32b96b5SLaurent Vivier 
574e32b96b5SLaurent Vivier     /*
575e32b96b5SLaurent Vivier      * XXX: sounds like a bug:
576e32b96b5SLaurent Vivier      * The primary should be hidden until the virtio-net driver
577e32b96b5SLaurent Vivier      * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
578e32b96b5SLaurent Vivier      */
579e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
580e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
581e32b96b5SLaurent Vivier 
58293262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
583e32b96b5SLaurent Vivier 
584e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
585e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
586e32b96b5SLaurent Vivier 
587e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
588e32b96b5SLaurent Vivier     machine_stop(qts);
589e32b96b5SLaurent Vivier }
590e32b96b5SLaurent Vivier 
591e32b96b5SLaurent Vivier static QDict *migrate_status(QTestState *qts)
592e32b96b5SLaurent Vivier {
593e32b96b5SLaurent Vivier     QDict *resp, *ret;
594e32b96b5SLaurent Vivier 
595e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
596e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
597e32b96b5SLaurent Vivier 
598e32b96b5SLaurent Vivier     ret = qdict_get_qdict(resp, "return");
599e32b96b5SLaurent Vivier     g_assert(qdict_haskey(ret, "status"));
600e32b96b5SLaurent Vivier     qobject_ref(ret);
601e32b96b5SLaurent Vivier     qobject_unref(resp);
602e32b96b5SLaurent Vivier 
603e32b96b5SLaurent Vivier     return ret;
604e32b96b5SLaurent Vivier }
605e32b96b5SLaurent Vivier 
606e32b96b5SLaurent Vivier static QDict *get_unplug_primary_event(QTestState *qts)
607e32b96b5SLaurent Vivier {
608e32b96b5SLaurent Vivier     QDict *resp;
609e32b96b5SLaurent Vivier     QDict *data;
610e32b96b5SLaurent Vivier 
611e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
612e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
613e32b96b5SLaurent Vivier 
614e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
615e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
616e32b96b5SLaurent Vivier     qobject_ref(data);
617e32b96b5SLaurent Vivier     qobject_unref(resp);
618e32b96b5SLaurent Vivier 
619e32b96b5SLaurent Vivier     return data;
620e32b96b5SLaurent Vivier }
621e32b96b5SLaurent Vivier 
622e32b96b5SLaurent Vivier static void test_migrate_out(gconstpointer opaque)
623e32b96b5SLaurent Vivier {
624e32b96b5SLaurent Vivier     QTestState *qts;
625e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
626e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
627e32b96b5SLaurent Vivier     const gchar *status;
628e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
629e32b96b5SLaurent Vivier 
630e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
631e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
632e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
633e32b96b5SLaurent Vivier                      2);
634e32b96b5SLaurent Vivier 
635e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
636e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
637e32b96b5SLaurent Vivier 
638e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
639e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
640e32b96b5SLaurent Vivier                          "'failover': 'on',"
641e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
642e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
643e32b96b5SLaurent Vivier 
644e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
645e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
646e32b96b5SLaurent Vivier 
64793262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
648e32b96b5SLaurent Vivier 
649e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
650e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
651e32b96b5SLaurent Vivier 
652e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
653e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
654e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
655e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
656e32b96b5SLaurent Vivier                          "'rombar': 0,"
657e32b96b5SLaurent Vivier                          "'romfile': '',"
658e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
659e32b96b5SLaurent Vivier 
660e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
661e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
662e32b96b5SLaurent Vivier 
663e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
664e32b96b5SLaurent Vivier     g_assert_nonnull(args);
665e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
666e32b96b5SLaurent Vivier 
667e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
668e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
669e32b96b5SLaurent Vivier     qobject_unref(resp);
670e32b96b5SLaurent Vivier 
671e32b96b5SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
672e32b96b5SLaurent Vivier     resp = get_unplug_primary_event(qts);
673e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
674e32b96b5SLaurent Vivier     qobject_unref(resp);
675e32b96b5SLaurent Vivier 
676e32b96b5SLaurent Vivier     /* wait the end of the migration setup phase */
677e32b96b5SLaurent Vivier     while (true) {
678e32b96b5SLaurent Vivier         ret = migrate_status(qts);
679e32b96b5SLaurent Vivier 
680e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
681e32b96b5SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
682e32b96b5SLaurent Vivier             qobject_unref(ret);
683e32b96b5SLaurent Vivier             break;
684e32b96b5SLaurent Vivier         }
685e32b96b5SLaurent Vivier 
686e32b96b5SLaurent Vivier         /* The migration must not start if the card is not ejected */
687e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
688e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
689e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
690e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
691e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
692e32b96b5SLaurent Vivier 
693e32b96b5SLaurent Vivier         qobject_unref(ret);
694e32b96b5SLaurent Vivier     }
695e32b96b5SLaurent Vivier 
696e32b96b5SLaurent Vivier     if (g_test_slow()) {
697e32b96b5SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
698e32b96b5SLaurent Vivier         for (int i = 0; i < 5; i++) {
699e32b96b5SLaurent Vivier             sleep(1);
700e32b96b5SLaurent Vivier             ret = migrate_status(qts);
701e32b96b5SLaurent Vivier             status = qdict_get_str(ret, "status");
702e32b96b5SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
703e32b96b5SLaurent Vivier             qobject_unref(ret);
704e32b96b5SLaurent Vivier         }
705e32b96b5SLaurent Vivier     }
706e32b96b5SLaurent Vivier 
707e32b96b5SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
708e32b96b5SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
709e32b96b5SLaurent Vivier 
710e32b96b5SLaurent Vivier     while (true) {
711e32b96b5SLaurent Vivier         ret = migrate_status(qts);
712e32b96b5SLaurent Vivier 
713e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
714e32b96b5SLaurent Vivier         if (strcmp(status, "completed") == 0) {
715e32b96b5SLaurent Vivier             qobject_unref(ret);
716e32b96b5SLaurent Vivier             break;
717e32b96b5SLaurent Vivier         }
718e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
719e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
720e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
721e32b96b5SLaurent Vivier         qobject_unref(ret);
722e32b96b5SLaurent Vivier     }
723e32b96b5SLaurent Vivier 
724e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
725e32b96b5SLaurent Vivier 
726e32b96b5SLaurent Vivier     /*
727e32b96b5SLaurent Vivier      * in fact, the card is ejected from the point of view of kernel
728e32b96b5SLaurent Vivier      * but not really from QEMU to be able to hotplug it back if
729e32b96b5SLaurent Vivier      * migration fails. So we can't check that:
730e32b96b5SLaurent Vivier      *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
731e32b96b5SLaurent Vivier      *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
732e32b96b5SLaurent Vivier      */
733e32b96b5SLaurent Vivier 
734e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
735e32b96b5SLaurent Vivier     machine_stop(qts);
736e32b96b5SLaurent Vivier }
737e32b96b5SLaurent Vivier 
738e32b96b5SLaurent Vivier static QDict *get_migration_event(QTestState *qts)
739e32b96b5SLaurent Vivier {
740e32b96b5SLaurent Vivier     QDict *resp;
741e32b96b5SLaurent Vivier     QDict *data;
742e32b96b5SLaurent Vivier 
743e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "MIGRATION");
744e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
745e32b96b5SLaurent Vivier 
746e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
747e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "status"));
748e32b96b5SLaurent Vivier     qobject_ref(data);
749e32b96b5SLaurent Vivier     qobject_unref(resp);
750e32b96b5SLaurent Vivier 
751e32b96b5SLaurent Vivier     return data;
752e32b96b5SLaurent Vivier }
753e32b96b5SLaurent Vivier 
754e32b96b5SLaurent Vivier static void test_migrate_in(gconstpointer opaque)
755e32b96b5SLaurent Vivier {
756e32b96b5SLaurent Vivier     QTestState *qts;
757e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
758e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
759e32b96b5SLaurent Vivier 
760e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
761e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
762e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
763e32b96b5SLaurent Vivier                      "-incoming defer ",
764e32b96b5SLaurent Vivier                      2);
765e32b96b5SLaurent Vivier 
766e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
767e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
768e32b96b5SLaurent Vivier 
769e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
770e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
771e32b96b5SLaurent Vivier                          "'failover': 'on',"
772e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
773e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
774e32b96b5SLaurent Vivier 
775e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
776e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
777e32b96b5SLaurent Vivier 
778e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
779e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
780e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
781e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
782e32b96b5SLaurent Vivier                          "'rombar': 0,"
783e32b96b5SLaurent Vivier                          "'romfile': '',"
784e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
785e32b96b5SLaurent Vivier 
786e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
787e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
788e32b96b5SLaurent Vivier 
789e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
790e32b96b5SLaurent Vivier     g_assert_nonnull(args);
791e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
792e32b96b5SLaurent Vivier 
793e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
794e32b96b5SLaurent Vivier                      args);
795e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
796e32b96b5SLaurent Vivier     qobject_unref(resp);
797e32b96b5SLaurent Vivier 
798e32b96b5SLaurent Vivier     resp = get_migration_event(qts);
799e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
800e32b96b5SLaurent Vivier     qobject_unref(resp);
801e32b96b5SLaurent Vivier 
802e32b96b5SLaurent Vivier     resp = get_failover_negociated_event(qts);
803e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
804e32b96b5SLaurent Vivier     qobject_unref(resp);
805e32b96b5SLaurent Vivier 
806e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
807e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
808e32b96b5SLaurent Vivier 
809e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
810e32b96b5SLaurent Vivier 
811e32b96b5SLaurent Vivier     ret = migrate_status(qts);
812e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
813e32b96b5SLaurent Vivier     qobject_unref(ret);
814e32b96b5SLaurent Vivier 
815e32b96b5SLaurent Vivier     machine_stop(qts);
816e32b96b5SLaurent Vivier }
817e32b96b5SLaurent Vivier 
8187f998491SLaurent Vivier static void test_off_migrate_out(gconstpointer opaque)
8197f998491SLaurent Vivier {
8207f998491SLaurent Vivier     QTestState *qts;
8217f998491SLaurent Vivier     QDict *resp, *args, *ret;
8227f998491SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
8237f998491SLaurent Vivier     const gchar *status;
8247f998491SLaurent Vivier     QVirtioPCIDevice *vdev;
8257f998491SLaurent Vivier 
8267f998491SLaurent Vivier     qts = machine_start(BASE_MACHINE
8277f998491SLaurent Vivier                      "-netdev user,id=hs0 "
8287f998491SLaurent Vivier                      "-netdev user,id=hs1 ",
8297f998491SLaurent Vivier                      2);
8307f998491SLaurent Vivier 
8317f998491SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
8327f998491SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8337f998491SLaurent Vivier 
8347f998491SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
8357f998491SLaurent Vivier                          "{'bus': 'root0',"
8367f998491SLaurent Vivier                          "'failover': 'off',"
8377f998491SLaurent Vivier                          "'netdev': 'hs0',"
8387f998491SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
8397f998491SLaurent Vivier 
8407f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8417f998491SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8427f998491SLaurent Vivier 
8437f998491SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
8447f998491SLaurent Vivier                          "{'bus': 'root1',"
8457f998491SLaurent Vivier                          "'failover_pair_id': 'standby0',"
8467f998491SLaurent Vivier                          "'netdev': 'hs1',"
8477f998491SLaurent Vivier                          "'rombar': 0,"
8487f998491SLaurent Vivier                          "'romfile': '',"
8497f998491SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
8507f998491SLaurent Vivier 
8517f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8527f998491SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
8537f998491SLaurent Vivier 
8547f998491SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
8557f998491SLaurent Vivier 
8567f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8577f998491SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
8587f998491SLaurent Vivier 
8597f998491SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
8607f998491SLaurent Vivier     g_assert_nonnull(args);
8617f998491SLaurent Vivier     qdict_put_str(args, "uri", uri);
8627f998491SLaurent Vivier 
8637f998491SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
8647f998491SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
8657f998491SLaurent Vivier     qobject_unref(resp);
8667f998491SLaurent Vivier 
8677f998491SLaurent Vivier     while (true) {
8687f998491SLaurent Vivier         ret = migrate_status(qts);
8697f998491SLaurent Vivier 
8707f998491SLaurent Vivier         status = qdict_get_str(ret, "status");
8717f998491SLaurent Vivier         if (strcmp(status, "completed") == 0) {
8727f998491SLaurent Vivier             qobject_unref(ret);
8737f998491SLaurent Vivier             break;
8747f998491SLaurent Vivier         }
8757f998491SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
8767f998491SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
8777f998491SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
8787f998491SLaurent Vivier         qobject_unref(ret);
8797f998491SLaurent Vivier     }
8807f998491SLaurent Vivier 
8817f998491SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
8827f998491SLaurent Vivier 
8837f998491SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
8847f998491SLaurent Vivier     machine_stop(qts);
8857f998491SLaurent Vivier }
8867f998491SLaurent Vivier 
8877f998491SLaurent Vivier static void test_off_migrate_in(gconstpointer opaque)
8887f998491SLaurent Vivier {
8897f998491SLaurent Vivier     QTestState *qts;
8907f998491SLaurent Vivier     QDict *resp, *args, *ret;
8917f998491SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
8927f998491SLaurent Vivier 
8937f998491SLaurent Vivier     qts = machine_start(BASE_MACHINE
8947f998491SLaurent Vivier                      "-netdev user,id=hs0 "
8957f998491SLaurent Vivier                      "-netdev user,id=hs1 "
8967f998491SLaurent Vivier                      "-incoming defer ",
8977f998491SLaurent Vivier                      2);
8987f998491SLaurent Vivier 
8997f998491SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
9007f998491SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
9017f998491SLaurent Vivier 
9027f998491SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
9037f998491SLaurent Vivier                          "{'bus': 'root0',"
9047f998491SLaurent Vivier                          "'failover': 'off',"
9057f998491SLaurent Vivier                          "'netdev': 'hs0',"
9067f998491SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
9077f998491SLaurent Vivier 
9087f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9097f998491SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
9107f998491SLaurent Vivier 
9117f998491SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
9127f998491SLaurent Vivier                          "{'bus': 'root1',"
9137f998491SLaurent Vivier                          "'failover_pair_id': 'standby0',"
9147f998491SLaurent Vivier                          "'netdev': 'hs1',"
9157f998491SLaurent Vivier                          "'rombar': 0,"
9167f998491SLaurent Vivier                          "'romfile': '',"
9177f998491SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
9187f998491SLaurent Vivier 
9197f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9207f998491SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
9217f998491SLaurent Vivier 
9227f998491SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
9237f998491SLaurent Vivier     g_assert_nonnull(args);
9247f998491SLaurent Vivier     qdict_put_str(args, "uri", uri);
9257f998491SLaurent Vivier 
9267f998491SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
9277f998491SLaurent Vivier                      args);
9287f998491SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
9297f998491SLaurent Vivier     qobject_unref(resp);
9307f998491SLaurent Vivier 
9317f998491SLaurent Vivier     resp = get_migration_event(qts);
9327f998491SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
9337f998491SLaurent Vivier     qobject_unref(resp);
9347f998491SLaurent Vivier 
9357f998491SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9367f998491SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
9377f998491SLaurent Vivier 
9387f998491SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
9397f998491SLaurent Vivier 
9407f998491SLaurent Vivier     ret = migrate_status(qts);
9417f998491SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
9427f998491SLaurent Vivier     qobject_unref(ret);
9437f998491SLaurent Vivier 
9447f998491SLaurent Vivier     machine_stop(qts);
9457f998491SLaurent Vivier }
9467f998491SLaurent Vivier 
947d9872c00SLaurent Vivier static void test_guest_off_migrate_out(gconstpointer opaque)
948d9872c00SLaurent Vivier {
949d9872c00SLaurent Vivier     QTestState *qts;
950d9872c00SLaurent Vivier     QDict *resp, *args, *ret;
951d9872c00SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
952d9872c00SLaurent Vivier     const gchar *status;
953d9872c00SLaurent Vivier     QVirtioPCIDevice *vdev;
954d9872c00SLaurent Vivier     uint64_t features;
955d9872c00SLaurent Vivier 
956d9872c00SLaurent Vivier     qts = machine_start(BASE_MACHINE
957d9872c00SLaurent Vivier                      "-netdev user,id=hs0 "
958d9872c00SLaurent Vivier                      "-netdev user,id=hs1 ",
959d9872c00SLaurent Vivier                      2);
960d9872c00SLaurent Vivier 
961d9872c00SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
962d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
963d9872c00SLaurent Vivier 
964d9872c00SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
965d9872c00SLaurent Vivier                          "{'bus': 'root0',"
966d9872c00SLaurent Vivier                          "'failover': 'on',"
967d9872c00SLaurent Vivier                          "'netdev': 'hs0',"
968d9872c00SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
969d9872c00SLaurent Vivier 
970d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
971d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
972d9872c00SLaurent Vivier 
973d9872c00SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
974d9872c00SLaurent Vivier                          "{'bus': 'root1',"
975d9872c00SLaurent Vivier                          "'failover_pair_id': 'standby0',"
976d9872c00SLaurent Vivier                          "'netdev': 'hs1',"
977d9872c00SLaurent Vivier                          "'rombar': 0,"
978d9872c00SLaurent Vivier                          "'romfile': '',"
979d9872c00SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
980d9872c00SLaurent Vivier 
981d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
982d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
983d9872c00SLaurent Vivier 
984d9872c00SLaurent Vivier     features = ~(QVIRTIO_F_BAD_FEATURE |
985d9872c00SLaurent Vivier                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
986d9872c00SLaurent Vivier                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
987d9872c00SLaurent Vivier                  (1ull << VIRTIO_NET_F_STANDBY));
988d9872c00SLaurent Vivier 
989d9872c00SLaurent Vivier     vdev = start_virtio_net_internal(qts, 1, 0, &features);
990d9872c00SLaurent Vivier 
991d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
992d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
993d9872c00SLaurent Vivier 
994d9872c00SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
995d9872c00SLaurent Vivier     g_assert_nonnull(args);
996d9872c00SLaurent Vivier     qdict_put_str(args, "uri", uri);
997d9872c00SLaurent Vivier 
998d9872c00SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
999d9872c00SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1000d9872c00SLaurent Vivier     qobject_unref(resp);
1001d9872c00SLaurent Vivier 
1002d9872c00SLaurent Vivier     while (true) {
1003d9872c00SLaurent Vivier         ret = migrate_status(qts);
1004d9872c00SLaurent Vivier 
1005d9872c00SLaurent Vivier         status = qdict_get_str(ret, "status");
1006d9872c00SLaurent Vivier         if (strcmp(status, "completed") == 0) {
1007d9872c00SLaurent Vivier             qobject_unref(ret);
1008d9872c00SLaurent Vivier             break;
1009d9872c00SLaurent Vivier         }
1010d9872c00SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1011d9872c00SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1012d9872c00SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1013d9872c00SLaurent Vivier         qobject_unref(ret);
1014d9872c00SLaurent Vivier     }
1015d9872c00SLaurent Vivier 
1016d9872c00SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
1017d9872c00SLaurent Vivier 
1018d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1019d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1020d9872c00SLaurent Vivier 
1021d9872c00SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
1022d9872c00SLaurent Vivier     machine_stop(qts);
1023d9872c00SLaurent Vivier }
1024d9872c00SLaurent Vivier 
1025d9872c00SLaurent Vivier static void test_guest_off_migrate_in(gconstpointer opaque)
1026d9872c00SLaurent Vivier {
1027d9872c00SLaurent Vivier     QTestState *qts;
1028d9872c00SLaurent Vivier     QDict *resp, *args, *ret;
1029d9872c00SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1030d9872c00SLaurent Vivier 
1031d9872c00SLaurent Vivier     qts = machine_start(BASE_MACHINE
1032d9872c00SLaurent Vivier                      "-netdev user,id=hs0 "
1033d9872c00SLaurent Vivier                      "-netdev user,id=hs1 "
1034d9872c00SLaurent Vivier                      "-incoming defer ",
1035d9872c00SLaurent Vivier                      2);
1036d9872c00SLaurent Vivier 
1037d9872c00SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1038d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1039d9872c00SLaurent Vivier 
1040d9872c00SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1041d9872c00SLaurent Vivier                          "{'bus': 'root0',"
1042d9872c00SLaurent Vivier                          "'failover': 'on',"
1043d9872c00SLaurent Vivier                          "'netdev': 'hs0',"
1044d9872c00SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1045d9872c00SLaurent Vivier 
1046d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1047d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1048d9872c00SLaurent Vivier 
1049d9872c00SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1050d9872c00SLaurent Vivier                          "{'bus': 'root1',"
1051d9872c00SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1052d9872c00SLaurent Vivier                          "'netdev': 'hs1',"
1053d9872c00SLaurent Vivier                          "'rombar': 0,"
1054d9872c00SLaurent Vivier                          "'romfile': '',"
1055d9872c00SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1056d9872c00SLaurent Vivier 
1057d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1058d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1059d9872c00SLaurent Vivier 
1060d9872c00SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1061d9872c00SLaurent Vivier     g_assert_nonnull(args);
1062d9872c00SLaurent Vivier     qdict_put_str(args, "uri", uri);
1063d9872c00SLaurent Vivier 
1064d9872c00SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1065d9872c00SLaurent Vivier                      args);
1066d9872c00SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1067d9872c00SLaurent Vivier     qobject_unref(resp);
1068d9872c00SLaurent Vivier 
1069d9872c00SLaurent Vivier     resp = get_migration_event(qts);
1070d9872c00SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1071d9872c00SLaurent Vivier     qobject_unref(resp);
1072d9872c00SLaurent Vivier 
1073d9872c00SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1074d9872c00SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1075d9872c00SLaurent Vivier 
1076d9872c00SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
1077d9872c00SLaurent Vivier 
1078d9872c00SLaurent Vivier     ret = migrate_status(qts);
1079d9872c00SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1080d9872c00SLaurent Vivier     qobject_unref(ret);
1081d9872c00SLaurent Vivier 
1082d9872c00SLaurent Vivier     machine_stop(qts);
1083d9872c00SLaurent Vivier }
1084d9872c00SLaurent Vivier 
1085e20977b7SLaurent Vivier static void test_migrate_guest_off_abort(gconstpointer opaque)
1086e20977b7SLaurent Vivier {
1087e20977b7SLaurent Vivier     QTestState *qts;
1088e20977b7SLaurent Vivier     QDict *resp, *args, *ret;
1089e20977b7SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1090e20977b7SLaurent Vivier     const gchar *status;
1091e20977b7SLaurent Vivier     QVirtioPCIDevice *vdev;
1092e20977b7SLaurent Vivier     uint64_t features;
1093e20977b7SLaurent Vivier 
1094e20977b7SLaurent Vivier     qts = machine_start(BASE_MACHINE
1095e20977b7SLaurent Vivier                      "-netdev user,id=hs0 "
1096e20977b7SLaurent Vivier                      "-netdev user,id=hs1 ",
1097e20977b7SLaurent Vivier                      2);
1098e20977b7SLaurent Vivier 
1099e20977b7SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1100e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1101e20977b7SLaurent Vivier 
1102e20977b7SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1103e20977b7SLaurent Vivier                          "{'bus': 'root0',"
1104e20977b7SLaurent Vivier                          "'failover': 'on',"
1105e20977b7SLaurent Vivier                          "'netdev': 'hs0',"
1106e20977b7SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1107e20977b7SLaurent Vivier 
1108e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1109e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1110e20977b7SLaurent Vivier 
1111e20977b7SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1112e20977b7SLaurent Vivier                          "{'bus': 'root1',"
1113e20977b7SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1114e20977b7SLaurent Vivier                          "'netdev': 'hs1',"
1115e20977b7SLaurent Vivier                          "'rombar': 0,"
1116e20977b7SLaurent Vivier                          "'romfile': '',"
1117e20977b7SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1118e20977b7SLaurent Vivier 
1119e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1120e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1121e20977b7SLaurent Vivier 
1122e20977b7SLaurent Vivier     features = ~(QVIRTIO_F_BAD_FEATURE |
1123e20977b7SLaurent Vivier                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
1124e20977b7SLaurent Vivier                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
1125e20977b7SLaurent Vivier                  (1ull << VIRTIO_NET_F_STANDBY));
1126e20977b7SLaurent Vivier 
1127e20977b7SLaurent Vivier     vdev = start_virtio_net_internal(qts, 1, 0, &features);
1128e20977b7SLaurent Vivier 
1129e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1130e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1131e20977b7SLaurent Vivier 
1132e20977b7SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1133e20977b7SLaurent Vivier     g_assert_nonnull(args);
1134e20977b7SLaurent Vivier     qdict_put_str(args, "uri", uri);
1135e20977b7SLaurent Vivier 
1136e20977b7SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1137e20977b7SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1138e20977b7SLaurent Vivier     qobject_unref(resp);
1139e20977b7SLaurent Vivier 
1140e20977b7SLaurent Vivier     while (true) {
1141e20977b7SLaurent Vivier         ret = migrate_status(qts);
1142e20977b7SLaurent Vivier 
1143e20977b7SLaurent Vivier         status = qdict_get_str(ret, "status");
1144*6ae6a30cSLaurent Vivier         if (strcmp(status, "completed") == 0) {
1145*6ae6a30cSLaurent Vivier             g_test_skip("Failed to cancel the migration");
1146*6ae6a30cSLaurent Vivier             qobject_unref(ret);
1147*6ae6a30cSLaurent Vivier             goto out;
1148*6ae6a30cSLaurent Vivier         }
1149e20977b7SLaurent Vivier         if (strcmp(status, "active") == 0) {
1150e20977b7SLaurent Vivier             qobject_unref(ret);
1151e20977b7SLaurent Vivier             break;
1152e20977b7SLaurent Vivier         }
1153e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1154e20977b7SLaurent Vivier         qobject_unref(ret);
1155e20977b7SLaurent Vivier     }
1156e20977b7SLaurent Vivier 
1157e20977b7SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1158e20977b7SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1159e20977b7SLaurent Vivier     qobject_unref(resp);
1160e20977b7SLaurent Vivier 
1161e20977b7SLaurent Vivier     while (true) {
1162e20977b7SLaurent Vivier         ret = migrate_status(qts);
1163e20977b7SLaurent Vivier         status = qdict_get_str(ret, "status");
1164*6ae6a30cSLaurent Vivier         if (strcmp(status, "completed") == 0) {
1165*6ae6a30cSLaurent Vivier             g_test_skip("Failed to cancel the migration");
1166*6ae6a30cSLaurent Vivier             qobject_unref(ret);
1167*6ae6a30cSLaurent Vivier             goto out;
1168*6ae6a30cSLaurent Vivier         }
1169e20977b7SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
1170e20977b7SLaurent Vivier             qobject_unref(ret);
1171e20977b7SLaurent Vivier             break;
1172e20977b7SLaurent Vivier         }
1173e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1174e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
1175e20977b7SLaurent Vivier         qobject_unref(ret);
1176e20977b7SLaurent Vivier     }
1177e20977b7SLaurent Vivier 
1178e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1179e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1180e20977b7SLaurent Vivier 
1181*6ae6a30cSLaurent Vivier out:
1182e20977b7SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
1183e20977b7SLaurent Vivier     machine_stop(qts);
1184e20977b7SLaurent Vivier }
1185e20977b7SLaurent Vivier 
11861e2077e2SLaurent Vivier static void test_migrate_abort_wait_unplug(gconstpointer opaque)
11871e2077e2SLaurent Vivier {
11881e2077e2SLaurent Vivier     QTestState *qts;
11891e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
11901e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
11911e2077e2SLaurent Vivier     const gchar *status;
11921e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
11931e2077e2SLaurent Vivier 
11941e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
11951e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
11961e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
11971e2077e2SLaurent Vivier                      2);
11981e2077e2SLaurent Vivier 
11991e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
12001e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
12011e2077e2SLaurent Vivier 
12021e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
12031e2077e2SLaurent Vivier                          "{'bus': 'root0',"
12041e2077e2SLaurent Vivier                          "'failover': 'on',"
12051e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
12061e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
12071e2077e2SLaurent Vivier 
12081e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
12091e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
12101e2077e2SLaurent Vivier 
121193262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
12121e2077e2SLaurent Vivier 
12131e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
12141e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
12151e2077e2SLaurent Vivier 
12161e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
12171e2077e2SLaurent Vivier                          "{'bus': 'root1',"
12181e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
12191e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
12201e2077e2SLaurent Vivier                          "'rombar': 0,"
12211e2077e2SLaurent Vivier                          "'romfile': '',"
12221e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
12231e2077e2SLaurent Vivier 
12241e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
12251e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
12261e2077e2SLaurent Vivier 
12271e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
12281e2077e2SLaurent Vivier     g_assert_nonnull(args);
12291e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
12301e2077e2SLaurent Vivier 
12311e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
12321e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
12331e2077e2SLaurent Vivier     qobject_unref(resp);
12341e2077e2SLaurent Vivier 
12351e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
12361e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
12371e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
12381e2077e2SLaurent Vivier     qobject_unref(resp);
12391e2077e2SLaurent Vivier 
12401e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
12411e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
12421e2077e2SLaurent Vivier     qobject_unref(resp);
12431e2077e2SLaurent Vivier 
12441e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
12451e2077e2SLaurent Vivier 
12461e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
12471e2077e2SLaurent Vivier     ret = migrate_status(qts);
12481e2077e2SLaurent Vivier 
12491e2077e2SLaurent Vivier     status = qdict_get_str(ret, "status");
12501e2077e2SLaurent Vivier     g_assert_cmpstr(status, ==, "cancelling");
12511e2077e2SLaurent Vivier     qobject_unref(ret);
12521e2077e2SLaurent Vivier 
12531e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
12541e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
12551e2077e2SLaurent Vivier 
12561e2077e2SLaurent Vivier     while (true) {
12571e2077e2SLaurent Vivier         ret = migrate_status(qts);
12581e2077e2SLaurent Vivier 
12591e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
12601e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
12611e2077e2SLaurent Vivier             qobject_unref(ret);
12621e2077e2SLaurent Vivier             break;
12631e2077e2SLaurent Vivier         }
1264*6ae6a30cSLaurent Vivier         g_assert_cmpstr(status, ==, "cancelling");
12651e2077e2SLaurent Vivier         qobject_unref(ret);
12661e2077e2SLaurent Vivier     }
12671e2077e2SLaurent Vivier 
12681e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
12691e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
12701e2077e2SLaurent Vivier 
12711e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
12721e2077e2SLaurent Vivier     machine_stop(qts);
12731e2077e2SLaurent Vivier }
12741e2077e2SLaurent Vivier 
12751e2077e2SLaurent Vivier static void test_migrate_abort_active(gconstpointer opaque)
12761e2077e2SLaurent Vivier {
12771e2077e2SLaurent Vivier     QTestState *qts;
12781e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
12791e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
12801e2077e2SLaurent Vivier     const gchar *status;
12811e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
12821e2077e2SLaurent Vivier 
12831e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
12841e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
12851e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
12861e2077e2SLaurent Vivier                      2);
12871e2077e2SLaurent Vivier 
12881e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
12891e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
12901e2077e2SLaurent Vivier 
12911e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
12921e2077e2SLaurent Vivier                          "{'bus': 'root0',"
12931e2077e2SLaurent Vivier                          "'failover': 'on',"
12941e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
12951e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
12961e2077e2SLaurent Vivier 
12971e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
12981e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
12991e2077e2SLaurent Vivier 
130093262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
13011e2077e2SLaurent Vivier 
13021e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
13031e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
13041e2077e2SLaurent Vivier 
13051e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
13061e2077e2SLaurent Vivier                          "{'bus': 'root1',"
13071e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
13081e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
13091e2077e2SLaurent Vivier                          "'rombar': 0,"
13101e2077e2SLaurent Vivier                          "'romfile': '',"
13111e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
13121e2077e2SLaurent Vivier 
13131e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
13141e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
13151e2077e2SLaurent Vivier 
13161e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
13171e2077e2SLaurent Vivier     g_assert_nonnull(args);
13181e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
13191e2077e2SLaurent Vivier 
13201e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
13211e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
13221e2077e2SLaurent Vivier     qobject_unref(resp);
13231e2077e2SLaurent Vivier 
13241e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
13251e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
13261e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
13271e2077e2SLaurent Vivier     qobject_unref(resp);
13281e2077e2SLaurent Vivier 
13291e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
13301e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
13311e2077e2SLaurent Vivier 
13321e2077e2SLaurent Vivier     while (true) {
13331e2077e2SLaurent Vivier         ret = migrate_status(qts);
13341e2077e2SLaurent Vivier 
13351e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
1336*6ae6a30cSLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
13371e2077e2SLaurent Vivier         if (strcmp(status, "wait-unplug") != 0) {
13381e2077e2SLaurent Vivier             qobject_unref(ret);
13391e2077e2SLaurent Vivier             break;
13401e2077e2SLaurent Vivier         }
13411e2077e2SLaurent Vivier         qobject_unref(ret);
13421e2077e2SLaurent Vivier     }
13431e2077e2SLaurent Vivier 
13441e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
13451e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
13461e2077e2SLaurent Vivier     qobject_unref(resp);
13471e2077e2SLaurent Vivier 
13481e2077e2SLaurent Vivier     while (true) {
13491e2077e2SLaurent Vivier         ret = migrate_status(qts);
13501e2077e2SLaurent Vivier 
13511e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
1352*6ae6a30cSLaurent Vivier         if (strcmp(status, "completed") == 0) {
1353*6ae6a30cSLaurent Vivier             g_test_skip("Failed to cancel the migration");
1354*6ae6a30cSLaurent Vivier             qobject_unref(ret);
1355*6ae6a30cSLaurent Vivier             goto out;
1356*6ae6a30cSLaurent Vivier         }
13571e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
13581e2077e2SLaurent Vivier             qobject_unref(ret);
13591e2077e2SLaurent Vivier             break;
13601e2077e2SLaurent Vivier         }
13611e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
13621e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
13631e2077e2SLaurent Vivier         qobject_unref(ret);
13641e2077e2SLaurent Vivier     }
13651e2077e2SLaurent Vivier 
13661e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
13671e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
13681e2077e2SLaurent Vivier 
1369*6ae6a30cSLaurent Vivier out:
13701e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
13711e2077e2SLaurent Vivier     machine_stop(qts);
13721e2077e2SLaurent Vivier }
13731e2077e2SLaurent Vivier 
1374e20977b7SLaurent Vivier static void test_migrate_off_abort(gconstpointer opaque)
1375e20977b7SLaurent Vivier {
1376e20977b7SLaurent Vivier     QTestState *qts;
1377e20977b7SLaurent Vivier     QDict *resp, *args, *ret;
1378e20977b7SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1379e20977b7SLaurent Vivier     const gchar *status;
1380e20977b7SLaurent Vivier     QVirtioPCIDevice *vdev;
1381e20977b7SLaurent Vivier 
1382e20977b7SLaurent Vivier     qts = machine_start(BASE_MACHINE
1383e20977b7SLaurent Vivier                      "-netdev user,id=hs0 "
1384e20977b7SLaurent Vivier                      "-netdev user,id=hs1 ",
1385e20977b7SLaurent Vivier                      2);
1386e20977b7SLaurent Vivier 
1387e20977b7SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1388e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1389e20977b7SLaurent Vivier 
1390e20977b7SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1391e20977b7SLaurent Vivier                          "{'bus': 'root0',"
1392e20977b7SLaurent Vivier                          "'failover': 'off',"
1393e20977b7SLaurent Vivier                          "'netdev': 'hs0',"
1394e20977b7SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1395e20977b7SLaurent Vivier 
1396e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1397e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1398e20977b7SLaurent Vivier 
1399e20977b7SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
1400e20977b7SLaurent Vivier 
1401e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1402e20977b7SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1403e20977b7SLaurent Vivier 
1404e20977b7SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1405e20977b7SLaurent Vivier                          "{'bus': 'root1',"
1406e20977b7SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1407e20977b7SLaurent Vivier                          "'netdev': 'hs1',"
1408e20977b7SLaurent Vivier                          "'rombar': 0,"
1409e20977b7SLaurent Vivier                          "'romfile': '',"
1410e20977b7SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1411e20977b7SLaurent Vivier 
1412e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1413e20977b7SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1414e20977b7SLaurent Vivier 
1415e20977b7SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1416e20977b7SLaurent Vivier     g_assert_nonnull(args);
1417e20977b7SLaurent Vivier     qdict_put_str(args, "uri", uri);
1418e20977b7SLaurent Vivier 
1419e20977b7SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1420e20977b7SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1421e20977b7SLaurent Vivier     qobject_unref(resp);
1422e20977b7SLaurent Vivier 
1423e20977b7SLaurent Vivier     while (true) {
1424e20977b7SLaurent Vivier         ret = migrate_status(qts);
1425e20977b7SLaurent Vivier 
1426e20977b7SLaurent Vivier         status = qdict_get_str(ret, "status");
1427e20977b7SLaurent Vivier         if (strcmp(status, "active") == 0) {
1428e20977b7SLaurent Vivier             qobject_unref(ret);
1429e20977b7SLaurent Vivier             break;
1430e20977b7SLaurent Vivier         }
1431e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1432e20977b7SLaurent Vivier         qobject_unref(ret);
1433e20977b7SLaurent Vivier     }
1434e20977b7SLaurent Vivier 
1435e20977b7SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1436e20977b7SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1437e20977b7SLaurent Vivier     qobject_unref(resp);
1438e20977b7SLaurent Vivier 
1439e20977b7SLaurent Vivier     while (true) {
1440e20977b7SLaurent Vivier         ret = migrate_status(qts);
1441e20977b7SLaurent Vivier 
1442e20977b7SLaurent Vivier         status = qdict_get_str(ret, "status");
1443*6ae6a30cSLaurent Vivier         if (strcmp(status, "completed") == 0) {
1444*6ae6a30cSLaurent Vivier             g_test_skip("Failed to cancel the migration");
1445*6ae6a30cSLaurent Vivier             qobject_unref(ret);
1446*6ae6a30cSLaurent Vivier             goto out;
1447*6ae6a30cSLaurent Vivier         }
1448e20977b7SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
1449e20977b7SLaurent Vivier             qobject_unref(ret);
1450e20977b7SLaurent Vivier             break;
1451e20977b7SLaurent Vivier         }
1452e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1453e20977b7SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
1454e20977b7SLaurent Vivier         qobject_unref(ret);
1455e20977b7SLaurent Vivier     }
1456e20977b7SLaurent Vivier 
1457e20977b7SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1458e20977b7SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1459e20977b7SLaurent Vivier 
1460*6ae6a30cSLaurent Vivier out:
1461e20977b7SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
1462e20977b7SLaurent Vivier     machine_stop(qts);
1463e20977b7SLaurent Vivier }
1464e20977b7SLaurent Vivier 
14651e2077e2SLaurent Vivier static void test_migrate_abort_timeout(gconstpointer opaque)
14661e2077e2SLaurent Vivier {
14671e2077e2SLaurent Vivier     QTestState *qts;
14681e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
14691e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
14701e2077e2SLaurent Vivier     const gchar *status;
14711e2077e2SLaurent Vivier     int total;
14721e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
14731e2077e2SLaurent Vivier 
14741e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
14751e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
14761e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
14771e2077e2SLaurent Vivier                      2);
14781e2077e2SLaurent Vivier 
14791e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
14801e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
14811e2077e2SLaurent Vivier 
14821e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
14831e2077e2SLaurent Vivier                          "{'bus': 'root0',"
14841e2077e2SLaurent Vivier                          "'failover': 'on',"
14851e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
14861e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
14871e2077e2SLaurent Vivier 
14881e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
14891e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
14901e2077e2SLaurent Vivier 
149193262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
14921e2077e2SLaurent Vivier 
14931e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
14941e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
14951e2077e2SLaurent Vivier 
14961e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
14971e2077e2SLaurent Vivier                          "{'bus': 'root1',"
14981e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
14991e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
15001e2077e2SLaurent Vivier                          "'rombar': 0,"
15011e2077e2SLaurent Vivier                          "'romfile': '',"
15021e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
15031e2077e2SLaurent Vivier 
15041e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
15051e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
15061e2077e2SLaurent Vivier 
15071e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
15081e2077e2SLaurent Vivier     g_assert_nonnull(args);
15091e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
15101e2077e2SLaurent Vivier 
15111e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
15121e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
15131e2077e2SLaurent Vivier     qobject_unref(resp);
15141e2077e2SLaurent Vivier 
15151e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
15161e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
15171e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
15181e2077e2SLaurent Vivier     qobject_unref(resp);
15191e2077e2SLaurent Vivier 
15201e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
15211e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
15221e2077e2SLaurent Vivier     qobject_unref(resp);
15231e2077e2SLaurent Vivier 
15241e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
15251e2077e2SLaurent Vivier 
15261e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
15271e2077e2SLaurent Vivier 
15281e2077e2SLaurent Vivier     total = 0;
15291e2077e2SLaurent Vivier     while (true) {
15301e2077e2SLaurent Vivier         ret = migrate_status(qts);
15311e2077e2SLaurent Vivier 
15321e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
15331e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
15341e2077e2SLaurent Vivier             qobject_unref(ret);
15351e2077e2SLaurent Vivier             break;
15361e2077e2SLaurent Vivier         }
15371e2077e2SLaurent Vivier         g_assert_cmpstr(status, ==, "cancelling");
15381e2077e2SLaurent Vivier         g_assert(qdict_haskey(ret, "total-time"));
15391e2077e2SLaurent Vivier         total = qdict_get_int(ret, "total-time");
15401e2077e2SLaurent Vivier         qobject_unref(ret);
15411e2077e2SLaurent Vivier     }
15421e2077e2SLaurent Vivier 
15431e2077e2SLaurent Vivier     /*
15441e2077e2SLaurent Vivier      * migration timeout in this case is 30 seconds
15451e2077e2SLaurent Vivier      * check we exit on the timeout (ms)
15461e2077e2SLaurent Vivier      */
15471e2077e2SLaurent Vivier     g_assert_cmpint(total, >, 30000);
15481e2077e2SLaurent Vivier 
15491e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
15501e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
15511e2077e2SLaurent Vivier 
15521e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
15531e2077e2SLaurent Vivier     machine_stop(qts);
15541e2077e2SLaurent Vivier }
15551e2077e2SLaurent Vivier 
1556e1e3d321SLaurent Vivier static void test_multi_out(gconstpointer opaque)
1557e1e3d321SLaurent Vivier {
1558e1e3d321SLaurent Vivier     QTestState *qts;
1559e1e3d321SLaurent Vivier     QDict *resp, *args, *ret;
1560e1e3d321SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1561e1e3d321SLaurent Vivier     const gchar *status, *expected;
1562e1e3d321SLaurent Vivier     QVirtioPCIDevice *vdev0, *vdev1;
1563e1e3d321SLaurent Vivier 
1564e1e3d321SLaurent Vivier     qts = machine_start(BASE_MACHINE
1565e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1566e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1567e1e3d321SLaurent Vivier                 "-netdev user,id=hs0 "
1568e1e3d321SLaurent Vivier                 "-netdev user,id=hs1 "
1569e1e3d321SLaurent Vivier                 "-netdev user,id=hs2 "
1570e1e3d321SLaurent Vivier                 "-netdev user,id=hs3 ",
1571e1e3d321SLaurent Vivier                 4);
1572e1e3d321SLaurent Vivier 
1573e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1574e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1575e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1576e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1577e1e3d321SLaurent Vivier 
1578e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1579e1e3d321SLaurent Vivier                          "{'bus': 'root0',"
1580e1e3d321SLaurent Vivier                          "'failover': 'on',"
1581e1e3d321SLaurent Vivier                          "'netdev': 'hs0',"
1582e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1583e1e3d321SLaurent Vivier 
1584e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1585e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1586e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1587e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1588e1e3d321SLaurent Vivier 
1589e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1590e1e3d321SLaurent Vivier                          "{'bus': 'root1',"
1591e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1592e1e3d321SLaurent Vivier                          "'netdev': 'hs1',"
1593e1e3d321SLaurent Vivier                          "'rombar': 0,"
1594e1e3d321SLaurent Vivier                          "'romfile': '',"
1595e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1596e1e3d321SLaurent Vivier 
1597e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1598e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1599e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1600e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1601e1e3d321SLaurent Vivier 
160293262464SLaurent Vivier     vdev0 = start_virtio_net(qts, 1, 0, "standby0", true);
1603e1e3d321SLaurent Vivier 
1604e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1605e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1606e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1607e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1608e1e3d321SLaurent Vivier 
1609e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1610e1e3d321SLaurent Vivier                          "{'bus': 'root2',"
1611e1e3d321SLaurent Vivier                          "'failover': 'on',"
1612e1e3d321SLaurent Vivier                          "'netdev': 'hs2',"
1613e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY1"'}");
1614e1e3d321SLaurent Vivier 
1615e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1616e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1617e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1618e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1619e1e3d321SLaurent Vivier 
1620e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1621e1e3d321SLaurent Vivier                          "{'bus': 'root3',"
1622e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby1',"
1623e1e3d321SLaurent Vivier                          "'netdev': 'hs3',"
1624e1e3d321SLaurent Vivier                          "'rombar': 0,"
1625e1e3d321SLaurent Vivier                          "'romfile': '',"
1626e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY1"'}");
1627e1e3d321SLaurent Vivier 
1628e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1629e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1630e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1631e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1632e1e3d321SLaurent Vivier 
163393262464SLaurent Vivier     vdev1 = start_virtio_net(qts, 3, 0, "standby1", true);
1634e1e3d321SLaurent Vivier 
1635e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1636e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1637e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1638e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1639e1e3d321SLaurent Vivier 
1640e1e3d321SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1641e1e3d321SLaurent Vivier     g_assert_nonnull(args);
1642e1e3d321SLaurent Vivier     qdict_put_str(args, "uri", uri);
1643e1e3d321SLaurent Vivier 
1644e1e3d321SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1645e1e3d321SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1646e1e3d321SLaurent Vivier     qobject_unref(resp);
1647e1e3d321SLaurent Vivier 
1648e1e3d321SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
1649e1e3d321SLaurent Vivier     resp = get_unplug_primary_event(qts);
1650e1e3d321SLaurent Vivier     if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
1651e1e3d321SLaurent Vivier         expected = "primary1";
1652e1e3d321SLaurent Vivier     } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
1653e1e3d321SLaurent Vivier         expected = "primary0";
1654e1e3d321SLaurent Vivier     } else {
1655e1e3d321SLaurent Vivier         g_assert_not_reached();
1656e1e3d321SLaurent Vivier     }
1657e1e3d321SLaurent Vivier     qobject_unref(resp);
1658e1e3d321SLaurent Vivier 
1659e1e3d321SLaurent Vivier     resp = get_unplug_primary_event(qts);
1660e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1661e1e3d321SLaurent Vivier     qobject_unref(resp);
1662e1e3d321SLaurent Vivier 
1663e1e3d321SLaurent Vivier     /* wait the end of the migration setup phase */
1664e1e3d321SLaurent Vivier     while (true) {
1665e1e3d321SLaurent Vivier         ret = migrate_status(qts);
1666e1e3d321SLaurent Vivier 
1667e1e3d321SLaurent Vivier         status = qdict_get_str(ret, "status");
1668e1e3d321SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
1669e1e3d321SLaurent Vivier             qobject_unref(ret);
1670e1e3d321SLaurent Vivier             break;
1671e1e3d321SLaurent Vivier         }
1672e1e3d321SLaurent Vivier 
1673e1e3d321SLaurent Vivier         /* The migration must not start if the card is not ejected */
1674e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
1675e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
1676e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1677e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1678e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1679e1e3d321SLaurent Vivier 
1680e1e3d321SLaurent Vivier         qobject_unref(ret);
1681e1e3d321SLaurent Vivier     }
1682e1e3d321SLaurent Vivier 
1683e1e3d321SLaurent Vivier     /* OS unplugs primary1, but we must wait the second */
1684e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1685e1e3d321SLaurent Vivier 
1686e1e3d321SLaurent Vivier     ret = migrate_status(qts);
1687e1e3d321SLaurent Vivier     status = qdict_get_str(ret, "status");
1688e1e3d321SLaurent Vivier     g_assert_cmpstr(status, ==, "wait-unplug");
1689e1e3d321SLaurent Vivier     qobject_unref(ret);
1690e1e3d321SLaurent Vivier 
1691e1e3d321SLaurent Vivier     if (g_test_slow()) {
1692e1e3d321SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
1693e1e3d321SLaurent Vivier         for (int i = 0; i < 5; i++) {
1694e1e3d321SLaurent Vivier             sleep(1);
1695e1e3d321SLaurent Vivier             ret = migrate_status(qts);
1696e1e3d321SLaurent Vivier             status = qdict_get_str(ret, "status");
1697e1e3d321SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
1698e1e3d321SLaurent Vivier             qobject_unref(ret);
1699e1e3d321SLaurent Vivier         }
1700e1e3d321SLaurent Vivier     }
1701e1e3d321SLaurent Vivier 
1702e1e3d321SLaurent Vivier     /* OS unplugs primary0, QEMU can move from wait-unplug state */
1703e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
1704e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1705e1e3d321SLaurent Vivier 
1706e1e3d321SLaurent Vivier     while (true) {
1707e1e3d321SLaurent Vivier         ret = migrate_status(qts);
1708e1e3d321SLaurent Vivier 
1709e1e3d321SLaurent Vivier         status = qdict_get_str(ret, "status");
1710e1e3d321SLaurent Vivier         if (strcmp(status, "completed") == 0) {
1711e1e3d321SLaurent Vivier             qobject_unref(ret);
1712e1e3d321SLaurent Vivier             break;
1713e1e3d321SLaurent Vivier         }
1714e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1715e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1716e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1717e1e3d321SLaurent Vivier         qobject_unref(ret);
1718e1e3d321SLaurent Vivier     }
1719e1e3d321SLaurent Vivier 
1720e1e3d321SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
1721e1e3d321SLaurent Vivier 
1722e1e3d321SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev0);
1723e1e3d321SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev1);
1724e1e3d321SLaurent Vivier     machine_stop(qts);
1725e1e3d321SLaurent Vivier }
1726e1e3d321SLaurent Vivier 
1727e1e3d321SLaurent Vivier static void test_multi_in(gconstpointer opaque)
1728e1e3d321SLaurent Vivier {
1729e1e3d321SLaurent Vivier     QTestState *qts;
1730e1e3d321SLaurent Vivier     QDict *resp, *args, *ret;
1731e1e3d321SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1732e1e3d321SLaurent Vivier 
1733e1e3d321SLaurent Vivier     qts = machine_start(BASE_MACHINE
1734e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1735e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1736e1e3d321SLaurent Vivier                 "-netdev user,id=hs0 "
1737e1e3d321SLaurent Vivier                 "-netdev user,id=hs1 "
1738e1e3d321SLaurent Vivier                 "-netdev user,id=hs2 "
1739e1e3d321SLaurent Vivier                 "-netdev user,id=hs3 "
1740e1e3d321SLaurent Vivier                 "-incoming defer ",
1741e1e3d321SLaurent Vivier                 4);
1742e1e3d321SLaurent Vivier 
1743e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1744e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1745e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1746e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1747e1e3d321SLaurent Vivier 
1748e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1749e1e3d321SLaurent Vivier                          "{'bus': 'root0',"
1750e1e3d321SLaurent Vivier                          "'failover': 'on',"
1751e1e3d321SLaurent Vivier                          "'netdev': 'hs0',"
1752e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1753e1e3d321SLaurent Vivier 
1754e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1755e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1756e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1757e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1758e1e3d321SLaurent Vivier 
1759e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1760e1e3d321SLaurent Vivier                          "{'bus': 'root1',"
1761e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1762e1e3d321SLaurent Vivier                          "'netdev': 'hs1',"
1763e1e3d321SLaurent Vivier                          "'rombar': 0,"
1764e1e3d321SLaurent Vivier                          "'romfile': '',"
1765e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1766e1e3d321SLaurent Vivier 
1767e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1768e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1769e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1770e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1771e1e3d321SLaurent Vivier 
1772e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1773e1e3d321SLaurent Vivier                          "{'bus': 'root2',"
1774e1e3d321SLaurent Vivier                          "'failover': 'on',"
1775e1e3d321SLaurent Vivier                          "'netdev': 'hs2',"
1776e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY1"'}");
1777e1e3d321SLaurent Vivier 
1778e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1779e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1780e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1781e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1782e1e3d321SLaurent Vivier 
1783e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1784e1e3d321SLaurent Vivier                          "{'bus': 'root3',"
1785e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby1',"
1786e1e3d321SLaurent Vivier                          "'netdev': 'hs3',"
1787e1e3d321SLaurent Vivier                          "'rombar': 0,"
1788e1e3d321SLaurent Vivier                          "'romfile': '',"
1789e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY1"'}");
1790e1e3d321SLaurent Vivier 
1791e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1792e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1793e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1794e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1795e1e3d321SLaurent Vivier 
1796e1e3d321SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1797e1e3d321SLaurent Vivier     g_assert_nonnull(args);
1798e1e3d321SLaurent Vivier     qdict_put_str(args, "uri", uri);
1799e1e3d321SLaurent Vivier 
1800e1e3d321SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1801e1e3d321SLaurent Vivier                      args);
1802e1e3d321SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1803e1e3d321SLaurent Vivier     qobject_unref(resp);
1804e1e3d321SLaurent Vivier 
1805e1e3d321SLaurent Vivier     resp = get_migration_event(qts);
1806e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1807e1e3d321SLaurent Vivier     qobject_unref(resp);
1808e1e3d321SLaurent Vivier 
1809e1e3d321SLaurent Vivier     resp = get_failover_negociated_event(qts);
1810e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1811e1e3d321SLaurent Vivier     qobject_unref(resp);
1812e1e3d321SLaurent Vivier 
1813e1e3d321SLaurent Vivier     resp = get_failover_negociated_event(qts);
1814e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1815e1e3d321SLaurent Vivier     qobject_unref(resp);
1816e1e3d321SLaurent Vivier 
1817e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1818e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1819e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1820e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1821e1e3d321SLaurent Vivier 
1822e1e3d321SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
1823e1e3d321SLaurent Vivier 
1824e1e3d321SLaurent Vivier     ret = migrate_status(qts);
1825e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1826e1e3d321SLaurent Vivier     qobject_unref(ret);
1827e1e3d321SLaurent Vivier 
1828e1e3d321SLaurent Vivier     machine_stop(qts);
1829e1e3d321SLaurent Vivier }
1830e1e3d321SLaurent Vivier 
1831e32b96b5SLaurent Vivier int main(int argc, char **argv)
1832e32b96b5SLaurent Vivier {
1833e63ed64cSThomas Huth     gchar *tmpfile;
1834e32b96b5SLaurent Vivier     int ret;
1835e32b96b5SLaurent Vivier 
1836e32b96b5SLaurent Vivier     g_test_init(&argc, &argv, NULL);
1837e32b96b5SLaurent Vivier 
1838e63ed64cSThomas Huth     ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
1839e63ed64cSThomas Huth     g_assert_true(ret >= 0);
1840e63ed64cSThomas Huth     close(ret);
1841e63ed64cSThomas Huth 
1842fbd2913cSLaurent Vivier     /* parameters tests */
1843e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1844e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1845e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on", test_on);
1846e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on_mismatch",
1847e32b96b5SLaurent Vivier                    test_on_mismatch);
1848e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/off", test_off);
1849e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
185078475083SLaurent Vivier     qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off);
1851fbd2913cSLaurent Vivier 
1852fbd2913cSLaurent Vivier     /* hotplug tests */
1853fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1);
1854fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/1_reverse",
1855e32b96b5SLaurent Vivier                    test_hotplug_1_reverse);
1856fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2);
1857fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/2_reverse",
1858e32b96b5SLaurent Vivier                    test_hotplug_2_reverse);
1859fbd2913cSLaurent Vivier 
1860fbd2913cSLaurent Vivier     /* migration tests */
1861fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile,
1862e32b96b5SLaurent Vivier                         test_migrate_out);
1863fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile,
1864e32b96b5SLaurent Vivier                         test_migrate_in);
18657f998491SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/off/out", tmpfile,
18667f998491SLaurent Vivier                         test_off_migrate_out);
18677f998491SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/off/in", tmpfile,
18687f998491SLaurent Vivier                         test_off_migrate_in);
1869e20977b7SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/off/abort", tmpfile,
1870e20977b7SLaurent Vivier                         test_migrate_off_abort);
1871d9872c00SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/guest_off/out", tmpfile,
1872d9872c00SLaurent Vivier                         test_guest_off_migrate_out);
1873d9872c00SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/guest_off/in", tmpfile,
1874d9872c00SLaurent Vivier                         test_guest_off_migrate_in);
1875e20977b7SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/guest_off/abort", tmpfile,
1876e20977b7SLaurent Vivier                         test_migrate_guest_off_abort);
18771e2077e2SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
18781e2077e2SLaurent Vivier                         tmpfile, test_migrate_abort_wait_unplug);
18791e2077e2SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
18801e2077e2SLaurent Vivier                         test_migrate_abort_active);
18811e2077e2SLaurent Vivier     if (g_test_slow()) {
18821e2077e2SLaurent Vivier         qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
18831e2077e2SLaurent Vivier                             tmpfile, test_migrate_abort_timeout);
18841e2077e2SLaurent Vivier     }
1885fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/multi/out",
1886e1e3d321SLaurent Vivier                         tmpfile, test_multi_out);
1887fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/multi/in",
1888e1e3d321SLaurent Vivier                    tmpfile, test_multi_in);
1889e32b96b5SLaurent Vivier 
1890e32b96b5SLaurent Vivier     ret = g_test_run();
1891e32b96b5SLaurent Vivier 
1892e32b96b5SLaurent Vivier     unlink(tmpfile);
1893e32b96b5SLaurent Vivier     g_free(tmpfile);
1894e32b96b5SLaurent Vivier 
1895e32b96b5SLaurent Vivier     return ret;
1896e32b96b5SLaurent Vivier }
1897