xref: /qemu/tests/qtest/virtio-net-failover.c (revision 78475083f7352ff54b078d2b2e758bc55ff60453)
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 
407*78475083SLaurent Vivier static void test_guest_off(void)
408*78475083SLaurent Vivier {
409*78475083SLaurent Vivier     QTestState *qts;
410*78475083SLaurent Vivier     QVirtioPCIDevice *vdev;
411*78475083SLaurent Vivier     uint64_t features;
412*78475083SLaurent Vivier 
413*78475083SLaurent Vivier     qts = machine_start(BASE_MACHINE
414*78475083SLaurent Vivier                      "-netdev user,id=hs0 "
415*78475083SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
416*78475083SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
417*78475083SLaurent Vivier                      "-netdev user,id=hs1 "
418*78475083SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
419*78475083SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
420*78475083SLaurent Vivier                      2);
421*78475083SLaurent Vivier 
422*78475083SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
423*78475083SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
424*78475083SLaurent Vivier 
425*78475083SLaurent Vivier     features = ~(QVIRTIO_F_BAD_FEATURE |
426*78475083SLaurent Vivier                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
427*78475083SLaurent Vivier                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
428*78475083SLaurent Vivier                  (1ull << VIRTIO_NET_F_STANDBY));
429*78475083SLaurent Vivier 
430*78475083SLaurent Vivier     vdev = start_virtio_net_internal(qts, 1, 0, &features);
431*78475083SLaurent Vivier 
432*78475083SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
433*78475083SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
434*78475083SLaurent Vivier 
435*78475083SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
436*78475083SLaurent Vivier     machine_stop(qts);
437*78475083SLaurent Vivier }
438*78475083SLaurent 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 
8181e2077e2SLaurent Vivier static void test_migrate_abort_wait_unplug(gconstpointer opaque)
8191e2077e2SLaurent Vivier {
8201e2077e2SLaurent Vivier     QTestState *qts;
8211e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
8221e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
8231e2077e2SLaurent Vivier     const gchar *status;
8241e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
8251e2077e2SLaurent Vivier 
8261e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
8271e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
8281e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
8291e2077e2SLaurent Vivier                      2);
8301e2077e2SLaurent Vivier 
8311e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
8321e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8331e2077e2SLaurent Vivier 
8341e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
8351e2077e2SLaurent Vivier                          "{'bus': 'root0',"
8361e2077e2SLaurent Vivier                          "'failover': 'on',"
8371e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
8381e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
8391e2077e2SLaurent Vivier 
8401e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8411e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8421e2077e2SLaurent Vivier 
84393262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
8441e2077e2SLaurent Vivier 
8451e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8461e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
8471e2077e2SLaurent Vivier 
8481e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
8491e2077e2SLaurent Vivier                          "{'bus': 'root1',"
8501e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
8511e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
8521e2077e2SLaurent Vivier                          "'rombar': 0,"
8531e2077e2SLaurent Vivier                          "'romfile': '',"
8541e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
8551e2077e2SLaurent Vivier 
8561e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
8571e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
8581e2077e2SLaurent Vivier 
8591e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
8601e2077e2SLaurent Vivier     g_assert_nonnull(args);
8611e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
8621e2077e2SLaurent Vivier 
8631e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
8641e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
8651e2077e2SLaurent Vivier     qobject_unref(resp);
8661e2077e2SLaurent Vivier 
8671e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
8681e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
8691e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
8701e2077e2SLaurent Vivier     qobject_unref(resp);
8711e2077e2SLaurent Vivier 
8721e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
8731e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
8741e2077e2SLaurent Vivier     qobject_unref(resp);
8751e2077e2SLaurent Vivier 
8761e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
8771e2077e2SLaurent Vivier 
8781e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
8791e2077e2SLaurent Vivier     ret = migrate_status(qts);
8801e2077e2SLaurent Vivier 
8811e2077e2SLaurent Vivier     status = qdict_get_str(ret, "status");
8821e2077e2SLaurent Vivier     g_assert_cmpstr(status, ==, "cancelling");
8831e2077e2SLaurent Vivier     qobject_unref(ret);
8841e2077e2SLaurent Vivier 
8851e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
8861e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
8871e2077e2SLaurent Vivier 
8881e2077e2SLaurent Vivier     while (true) {
8891e2077e2SLaurent Vivier         ret = migrate_status(qts);
8901e2077e2SLaurent Vivier 
8911e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
8921e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
8931e2077e2SLaurent Vivier             qobject_unref(ret);
8941e2077e2SLaurent Vivier             break;
8951e2077e2SLaurent Vivier         }
8961e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
8971e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
8981e2077e2SLaurent Vivier         qobject_unref(ret);
8991e2077e2SLaurent Vivier     }
9001e2077e2SLaurent Vivier 
9011e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9021e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
9031e2077e2SLaurent Vivier 
9041e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
9051e2077e2SLaurent Vivier     machine_stop(qts);
9061e2077e2SLaurent Vivier }
9071e2077e2SLaurent Vivier 
9081e2077e2SLaurent Vivier static void test_migrate_abort_active(gconstpointer opaque)
9091e2077e2SLaurent Vivier {
9101e2077e2SLaurent Vivier     QTestState *qts;
9111e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
9121e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
9131e2077e2SLaurent Vivier     const gchar *status;
9141e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
9151e2077e2SLaurent Vivier 
9161e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
9171e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
9181e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
9191e2077e2SLaurent Vivier                      2);
9201e2077e2SLaurent Vivier 
9211e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
9221e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
9231e2077e2SLaurent Vivier 
9241e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
9251e2077e2SLaurent Vivier                          "{'bus': 'root0',"
9261e2077e2SLaurent Vivier                          "'failover': 'on',"
9271e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
9281e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
9291e2077e2SLaurent Vivier 
9301e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9311e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
9321e2077e2SLaurent Vivier 
93393262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
9341e2077e2SLaurent Vivier 
9351e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9361e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
9371e2077e2SLaurent Vivier 
9381e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
9391e2077e2SLaurent Vivier                          "{'bus': 'root1',"
9401e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
9411e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
9421e2077e2SLaurent Vivier                          "'rombar': 0,"
9431e2077e2SLaurent Vivier                          "'romfile': '',"
9441e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
9451e2077e2SLaurent Vivier 
9461e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9471e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
9481e2077e2SLaurent Vivier 
9491e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
9501e2077e2SLaurent Vivier     g_assert_nonnull(args);
9511e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
9521e2077e2SLaurent Vivier 
9531e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
9541e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
9551e2077e2SLaurent Vivier     qobject_unref(resp);
9561e2077e2SLaurent Vivier 
9571e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
9581e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
9591e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
9601e2077e2SLaurent Vivier     qobject_unref(resp);
9611e2077e2SLaurent Vivier 
9621e2077e2SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
9631e2077e2SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
9641e2077e2SLaurent Vivier 
9651e2077e2SLaurent Vivier     while (true) {
9661e2077e2SLaurent Vivier         ret = migrate_status(qts);
9671e2077e2SLaurent Vivier 
9681e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
9691e2077e2SLaurent Vivier         if (strcmp(status, "wait-unplug") != 0) {
9701e2077e2SLaurent Vivier             qobject_unref(ret);
9711e2077e2SLaurent Vivier             break;
9721e2077e2SLaurent Vivier         }
9731e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
9741e2077e2SLaurent Vivier         qobject_unref(ret);
9751e2077e2SLaurent Vivier     }
9761e2077e2SLaurent Vivier 
9771e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
9781e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
9791e2077e2SLaurent Vivier     qobject_unref(resp);
9801e2077e2SLaurent Vivier 
9811e2077e2SLaurent Vivier     while (true) {
9821e2077e2SLaurent Vivier         ret = migrate_status(qts);
9831e2077e2SLaurent Vivier 
9841e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
9851e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
9861e2077e2SLaurent Vivier             qobject_unref(ret);
9871e2077e2SLaurent Vivier             break;
9881e2077e2SLaurent Vivier         }
9891e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
9901e2077e2SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
9911e2077e2SLaurent Vivier         qobject_unref(ret);
9921e2077e2SLaurent Vivier     }
9931e2077e2SLaurent Vivier 
9941e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
9951e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
9961e2077e2SLaurent Vivier 
9971e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
9981e2077e2SLaurent Vivier     machine_stop(qts);
9991e2077e2SLaurent Vivier }
10001e2077e2SLaurent Vivier 
10011e2077e2SLaurent Vivier static void test_migrate_abort_timeout(gconstpointer opaque)
10021e2077e2SLaurent Vivier {
10031e2077e2SLaurent Vivier     QTestState *qts;
10041e2077e2SLaurent Vivier     QDict *resp, *args, *ret;
10051e2077e2SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
10061e2077e2SLaurent Vivier     const gchar *status;
10071e2077e2SLaurent Vivier     int total;
10081e2077e2SLaurent Vivier     QVirtioPCIDevice *vdev;
10091e2077e2SLaurent Vivier 
10101e2077e2SLaurent Vivier     qts = machine_start(BASE_MACHINE
10111e2077e2SLaurent Vivier                      "-netdev user,id=hs0 "
10121e2077e2SLaurent Vivier                      "-netdev user,id=hs1 ",
10131e2077e2SLaurent Vivier                      2);
10141e2077e2SLaurent Vivier 
10151e2077e2SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
10161e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
10171e2077e2SLaurent Vivier 
10181e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
10191e2077e2SLaurent Vivier                          "{'bus': 'root0',"
10201e2077e2SLaurent Vivier                          "'failover': 'on',"
10211e2077e2SLaurent Vivier                          "'netdev': 'hs0',"
10221e2077e2SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
10231e2077e2SLaurent Vivier 
10241e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
10251e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
10261e2077e2SLaurent Vivier 
102793262464SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
10281e2077e2SLaurent Vivier 
10291e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
10301e2077e2SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
10311e2077e2SLaurent Vivier 
10321e2077e2SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
10331e2077e2SLaurent Vivier                          "{'bus': 'root1',"
10341e2077e2SLaurent Vivier                          "'failover_pair_id': 'standby0',"
10351e2077e2SLaurent Vivier                          "'netdev': 'hs1',"
10361e2077e2SLaurent Vivier                          "'rombar': 0,"
10371e2077e2SLaurent Vivier                          "'romfile': '',"
10381e2077e2SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
10391e2077e2SLaurent Vivier 
10401e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
10411e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
10421e2077e2SLaurent Vivier 
10431e2077e2SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
10441e2077e2SLaurent Vivier     g_assert_nonnull(args);
10451e2077e2SLaurent Vivier     qdict_put_str(args, "uri", uri);
10461e2077e2SLaurent Vivier 
10471e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
10481e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
10491e2077e2SLaurent Vivier     qobject_unref(resp);
10501e2077e2SLaurent Vivier 
10511e2077e2SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
10521e2077e2SLaurent Vivier     resp = get_unplug_primary_event(qts);
10531e2077e2SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
10541e2077e2SLaurent Vivier     qobject_unref(resp);
10551e2077e2SLaurent Vivier 
10561e2077e2SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
10571e2077e2SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
10581e2077e2SLaurent Vivier     qobject_unref(resp);
10591e2077e2SLaurent Vivier 
10601e2077e2SLaurent Vivier     /* migration has been cancelled while the unplug was in progress */
10611e2077e2SLaurent Vivier 
10621e2077e2SLaurent Vivier     /* while the card is not ejected, we must be in "cancelling" state */
10631e2077e2SLaurent Vivier 
10641e2077e2SLaurent Vivier     total = 0;
10651e2077e2SLaurent Vivier     while (true) {
10661e2077e2SLaurent Vivier         ret = migrate_status(qts);
10671e2077e2SLaurent Vivier 
10681e2077e2SLaurent Vivier         status = qdict_get_str(ret, "status");
10691e2077e2SLaurent Vivier         if (strcmp(status, "cancelled") == 0) {
10701e2077e2SLaurent Vivier             qobject_unref(ret);
10711e2077e2SLaurent Vivier             break;
10721e2077e2SLaurent Vivier         }
10731e2077e2SLaurent Vivier         g_assert_cmpstr(status, ==, "cancelling");
10741e2077e2SLaurent Vivier         g_assert(qdict_haskey(ret, "total-time"));
10751e2077e2SLaurent Vivier         total = qdict_get_int(ret, "total-time");
10761e2077e2SLaurent Vivier         qobject_unref(ret);
10771e2077e2SLaurent Vivier     }
10781e2077e2SLaurent Vivier 
10791e2077e2SLaurent Vivier     /*
10801e2077e2SLaurent Vivier      * migration timeout in this case is 30 seconds
10811e2077e2SLaurent Vivier      * check we exit on the timeout (ms)
10821e2077e2SLaurent Vivier      */
10831e2077e2SLaurent Vivier     g_assert_cmpint(total, >, 30000);
10841e2077e2SLaurent Vivier 
10851e2077e2SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
10861e2077e2SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
10871e2077e2SLaurent Vivier 
10881e2077e2SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
10891e2077e2SLaurent Vivier     machine_stop(qts);
10901e2077e2SLaurent Vivier }
10911e2077e2SLaurent Vivier 
1092e1e3d321SLaurent Vivier static void test_multi_out(gconstpointer opaque)
1093e1e3d321SLaurent Vivier {
1094e1e3d321SLaurent Vivier     QTestState *qts;
1095e1e3d321SLaurent Vivier     QDict *resp, *args, *ret;
1096e1e3d321SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1097e1e3d321SLaurent Vivier     const gchar *status, *expected;
1098e1e3d321SLaurent Vivier     QVirtioPCIDevice *vdev0, *vdev1;
1099e1e3d321SLaurent Vivier 
1100e1e3d321SLaurent Vivier     qts = machine_start(BASE_MACHINE
1101e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1102e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1103e1e3d321SLaurent Vivier                 "-netdev user,id=hs0 "
1104e1e3d321SLaurent Vivier                 "-netdev user,id=hs1 "
1105e1e3d321SLaurent Vivier                 "-netdev user,id=hs2 "
1106e1e3d321SLaurent Vivier                 "-netdev user,id=hs3 ",
1107e1e3d321SLaurent Vivier                 4);
1108e1e3d321SLaurent Vivier 
1109e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1110e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1111e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1112e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1113e1e3d321SLaurent Vivier 
1114e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1115e1e3d321SLaurent Vivier                          "{'bus': 'root0',"
1116e1e3d321SLaurent Vivier                          "'failover': 'on',"
1117e1e3d321SLaurent Vivier                          "'netdev': 'hs0',"
1118e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1119e1e3d321SLaurent Vivier 
1120e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1121e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1122e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1123e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1124e1e3d321SLaurent Vivier 
1125e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1126e1e3d321SLaurent Vivier                          "{'bus': 'root1',"
1127e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1128e1e3d321SLaurent Vivier                          "'netdev': 'hs1',"
1129e1e3d321SLaurent Vivier                          "'rombar': 0,"
1130e1e3d321SLaurent Vivier                          "'romfile': '',"
1131e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1132e1e3d321SLaurent Vivier 
1133e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1134e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1135e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1136e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1137e1e3d321SLaurent Vivier 
113893262464SLaurent Vivier     vdev0 = start_virtio_net(qts, 1, 0, "standby0", true);
1139e1e3d321SLaurent Vivier 
1140e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1141e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1142e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1143e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1144e1e3d321SLaurent Vivier 
1145e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1146e1e3d321SLaurent Vivier                          "{'bus': 'root2',"
1147e1e3d321SLaurent Vivier                          "'failover': 'on',"
1148e1e3d321SLaurent Vivier                          "'netdev': 'hs2',"
1149e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY1"'}");
1150e1e3d321SLaurent Vivier 
1151e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1152e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1153e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1154e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1155e1e3d321SLaurent Vivier 
1156e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1157e1e3d321SLaurent Vivier                          "{'bus': 'root3',"
1158e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby1',"
1159e1e3d321SLaurent Vivier                          "'netdev': 'hs3',"
1160e1e3d321SLaurent Vivier                          "'rombar': 0,"
1161e1e3d321SLaurent Vivier                          "'romfile': '',"
1162e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY1"'}");
1163e1e3d321SLaurent Vivier 
1164e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1165e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1166e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1167e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1168e1e3d321SLaurent Vivier 
116993262464SLaurent Vivier     vdev1 = start_virtio_net(qts, 3, 0, "standby1", true);
1170e1e3d321SLaurent Vivier 
1171e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1172e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1173e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1174e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1175e1e3d321SLaurent Vivier 
1176e1e3d321SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1177e1e3d321SLaurent Vivier     g_assert_nonnull(args);
1178e1e3d321SLaurent Vivier     qdict_put_str(args, "uri", uri);
1179e1e3d321SLaurent Vivier 
1180e1e3d321SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1181e1e3d321SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1182e1e3d321SLaurent Vivier     qobject_unref(resp);
1183e1e3d321SLaurent Vivier 
1184e1e3d321SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
1185e1e3d321SLaurent Vivier     resp = get_unplug_primary_event(qts);
1186e1e3d321SLaurent Vivier     if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
1187e1e3d321SLaurent Vivier         expected = "primary1";
1188e1e3d321SLaurent Vivier     } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
1189e1e3d321SLaurent Vivier         expected = "primary0";
1190e1e3d321SLaurent Vivier     } else {
1191e1e3d321SLaurent Vivier         g_assert_not_reached();
1192e1e3d321SLaurent Vivier     }
1193e1e3d321SLaurent Vivier     qobject_unref(resp);
1194e1e3d321SLaurent Vivier 
1195e1e3d321SLaurent Vivier     resp = get_unplug_primary_event(qts);
1196e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1197e1e3d321SLaurent Vivier     qobject_unref(resp);
1198e1e3d321SLaurent Vivier 
1199e1e3d321SLaurent Vivier     /* wait the end of the migration setup phase */
1200e1e3d321SLaurent Vivier     while (true) {
1201e1e3d321SLaurent Vivier         ret = migrate_status(qts);
1202e1e3d321SLaurent Vivier 
1203e1e3d321SLaurent Vivier         status = qdict_get_str(ret, "status");
1204e1e3d321SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
1205e1e3d321SLaurent Vivier             qobject_unref(ret);
1206e1e3d321SLaurent Vivier             break;
1207e1e3d321SLaurent Vivier         }
1208e1e3d321SLaurent Vivier 
1209e1e3d321SLaurent Vivier         /* The migration must not start if the card is not ejected */
1210e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
1211e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
1212e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1213e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1214e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1215e1e3d321SLaurent Vivier 
1216e1e3d321SLaurent Vivier         qobject_unref(ret);
1217e1e3d321SLaurent Vivier     }
1218e1e3d321SLaurent Vivier 
1219e1e3d321SLaurent Vivier     /* OS unplugs primary1, but we must wait the second */
1220e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1221e1e3d321SLaurent Vivier 
1222e1e3d321SLaurent Vivier     ret = migrate_status(qts);
1223e1e3d321SLaurent Vivier     status = qdict_get_str(ret, "status");
1224e1e3d321SLaurent Vivier     g_assert_cmpstr(status, ==, "wait-unplug");
1225e1e3d321SLaurent Vivier     qobject_unref(ret);
1226e1e3d321SLaurent Vivier 
1227e1e3d321SLaurent Vivier     if (g_test_slow()) {
1228e1e3d321SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
1229e1e3d321SLaurent Vivier         for (int i = 0; i < 5; i++) {
1230e1e3d321SLaurent Vivier             sleep(1);
1231e1e3d321SLaurent Vivier             ret = migrate_status(qts);
1232e1e3d321SLaurent Vivier             status = qdict_get_str(ret, "status");
1233e1e3d321SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
1234e1e3d321SLaurent Vivier             qobject_unref(ret);
1235e1e3d321SLaurent Vivier         }
1236e1e3d321SLaurent Vivier     }
1237e1e3d321SLaurent Vivier 
1238e1e3d321SLaurent Vivier     /* OS unplugs primary0, QEMU can move from wait-unplug state */
1239e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
1240e1e3d321SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1241e1e3d321SLaurent Vivier 
1242e1e3d321SLaurent Vivier     while (true) {
1243e1e3d321SLaurent Vivier         ret = migrate_status(qts);
1244e1e3d321SLaurent Vivier 
1245e1e3d321SLaurent Vivier         status = qdict_get_str(ret, "status");
1246e1e3d321SLaurent Vivier         if (strcmp(status, "completed") == 0) {
1247e1e3d321SLaurent Vivier             qobject_unref(ret);
1248e1e3d321SLaurent Vivier             break;
1249e1e3d321SLaurent Vivier         }
1250e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
1251e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
1252e1e3d321SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
1253e1e3d321SLaurent Vivier         qobject_unref(ret);
1254e1e3d321SLaurent Vivier     }
1255e1e3d321SLaurent Vivier 
1256e1e3d321SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
1257e1e3d321SLaurent Vivier 
1258e1e3d321SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev0);
1259e1e3d321SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev1);
1260e1e3d321SLaurent Vivier     machine_stop(qts);
1261e1e3d321SLaurent Vivier }
1262e1e3d321SLaurent Vivier 
1263e1e3d321SLaurent Vivier static void test_multi_in(gconstpointer opaque)
1264e1e3d321SLaurent Vivier {
1265e1e3d321SLaurent Vivier     QTestState *qts;
1266e1e3d321SLaurent Vivier     QDict *resp, *args, *ret;
1267e1e3d321SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1268e1e3d321SLaurent Vivier 
1269e1e3d321SLaurent Vivier     qts = machine_start(BASE_MACHINE
1270e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1271e1e3d321SLaurent Vivier                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1272e1e3d321SLaurent Vivier                 "-netdev user,id=hs0 "
1273e1e3d321SLaurent Vivier                 "-netdev user,id=hs1 "
1274e1e3d321SLaurent Vivier                 "-netdev user,id=hs2 "
1275e1e3d321SLaurent Vivier                 "-netdev user,id=hs3 "
1276e1e3d321SLaurent Vivier                 "-incoming defer ",
1277e1e3d321SLaurent Vivier                 4);
1278e1e3d321SLaurent Vivier 
1279e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
1280e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1281e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1282e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1283e1e3d321SLaurent Vivier 
1284e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
1285e1e3d321SLaurent Vivier                          "{'bus': 'root0',"
1286e1e3d321SLaurent Vivier                          "'failover': 'on',"
1287e1e3d321SLaurent Vivier                          "'netdev': 'hs0',"
1288e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
1289e1e3d321SLaurent Vivier 
1290e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1291e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1292e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1293e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1294e1e3d321SLaurent Vivier 
1295e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
1296e1e3d321SLaurent Vivier                          "{'bus': 'root1',"
1297e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby0',"
1298e1e3d321SLaurent Vivier                          "'netdev': 'hs1',"
1299e1e3d321SLaurent Vivier                          "'rombar': 0,"
1300e1e3d321SLaurent Vivier                          "'romfile': '',"
1301e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
1302e1e3d321SLaurent Vivier 
1303e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1304e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1305e1e3d321SLaurent Vivier     check_one_card(qts, false, "standby1", MAC_STANDBY1);
1306e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1307e1e3d321SLaurent Vivier 
1308e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby1",
1309e1e3d321SLaurent Vivier                          "{'bus': 'root2',"
1310e1e3d321SLaurent Vivier                          "'failover': 'on',"
1311e1e3d321SLaurent Vivier                          "'netdev': 'hs2',"
1312e1e3d321SLaurent Vivier                          "'mac': '"MAC_STANDBY1"'}");
1313e1e3d321SLaurent Vivier 
1314e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1315e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1316e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1317e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1318e1e3d321SLaurent Vivier 
1319e1e3d321SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary1",
1320e1e3d321SLaurent Vivier                          "{'bus': 'root3',"
1321e1e3d321SLaurent Vivier                          "'failover_pair_id': 'standby1',"
1322e1e3d321SLaurent Vivier                          "'netdev': 'hs3',"
1323e1e3d321SLaurent Vivier                          "'rombar': 0,"
1324e1e3d321SLaurent Vivier                          "'romfile': '',"
1325e1e3d321SLaurent Vivier                          "'mac': '"MAC_PRIMARY1"'}");
1326e1e3d321SLaurent Vivier 
1327e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1328e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1329e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1330e1e3d321SLaurent Vivier     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1331e1e3d321SLaurent Vivier 
1332e1e3d321SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
1333e1e3d321SLaurent Vivier     g_assert_nonnull(args);
1334e1e3d321SLaurent Vivier     qdict_put_str(args, "uri", uri);
1335e1e3d321SLaurent Vivier 
1336e1e3d321SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1337e1e3d321SLaurent Vivier                      args);
1338e1e3d321SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
1339e1e3d321SLaurent Vivier     qobject_unref(resp);
1340e1e3d321SLaurent Vivier 
1341e1e3d321SLaurent Vivier     resp = get_migration_event(qts);
1342e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1343e1e3d321SLaurent Vivier     qobject_unref(resp);
1344e1e3d321SLaurent Vivier 
1345e1e3d321SLaurent Vivier     resp = get_failover_negociated_event(qts);
1346e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1347e1e3d321SLaurent Vivier     qobject_unref(resp);
1348e1e3d321SLaurent Vivier 
1349e1e3d321SLaurent Vivier     resp = get_failover_negociated_event(qts);
1350e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1351e1e3d321SLaurent Vivier     qobject_unref(resp);
1352e1e3d321SLaurent Vivier 
1353e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
1354e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1355e1e3d321SLaurent Vivier     check_one_card(qts, true, "standby1", MAC_STANDBY1);
1356e1e3d321SLaurent Vivier     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1357e1e3d321SLaurent Vivier 
1358e1e3d321SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
1359e1e3d321SLaurent Vivier 
1360e1e3d321SLaurent Vivier     ret = migrate_status(qts);
1361e1e3d321SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1362e1e3d321SLaurent Vivier     qobject_unref(ret);
1363e1e3d321SLaurent Vivier 
1364e1e3d321SLaurent Vivier     machine_stop(qts);
1365e1e3d321SLaurent Vivier }
1366e1e3d321SLaurent Vivier 
1367e32b96b5SLaurent Vivier int main(int argc, char **argv)
1368e32b96b5SLaurent Vivier {
1369e63ed64cSThomas Huth     gchar *tmpfile;
1370e32b96b5SLaurent Vivier     int ret;
1371e32b96b5SLaurent Vivier 
1372e32b96b5SLaurent Vivier     g_test_init(&argc, &argv, NULL);
1373e32b96b5SLaurent Vivier 
1374e63ed64cSThomas Huth     ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
1375e63ed64cSThomas Huth     g_assert_true(ret >= 0);
1376e63ed64cSThomas Huth     close(ret);
1377e63ed64cSThomas Huth 
1378fbd2913cSLaurent Vivier     /* parameters tests */
1379e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1380e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1381e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on", test_on);
1382e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on_mismatch",
1383e32b96b5SLaurent Vivier                    test_on_mismatch);
1384e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/off", test_off);
1385e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
1386*78475083SLaurent Vivier     qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off);
1387fbd2913cSLaurent Vivier 
1388fbd2913cSLaurent Vivier     /* hotplug tests */
1389fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1);
1390fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/1_reverse",
1391e32b96b5SLaurent Vivier                    test_hotplug_1_reverse);
1392fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2);
1393fbd2913cSLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug/2_reverse",
1394e32b96b5SLaurent Vivier                    test_hotplug_2_reverse);
1395fbd2913cSLaurent Vivier 
1396fbd2913cSLaurent Vivier     /* migration tests */
1397fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile,
1398e32b96b5SLaurent Vivier                         test_migrate_out);
1399fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile,
1400e32b96b5SLaurent Vivier                         test_migrate_in);
14011e2077e2SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
14021e2077e2SLaurent Vivier                         tmpfile, test_migrate_abort_wait_unplug);
14031e2077e2SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
14041e2077e2SLaurent Vivier                         test_migrate_abort_active);
14051e2077e2SLaurent Vivier     if (g_test_slow()) {
14061e2077e2SLaurent Vivier         qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
14071e2077e2SLaurent Vivier                             tmpfile, test_migrate_abort_timeout);
14081e2077e2SLaurent Vivier     }
1409fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/multi/out",
1410e1e3d321SLaurent Vivier                         tmpfile, test_multi_out);
1411fbd2913cSLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/multi/in",
1412e1e3d321SLaurent Vivier                    tmpfile, test_multi_in);
1413e32b96b5SLaurent Vivier 
1414e32b96b5SLaurent Vivier     ret = g_test_run();
1415e32b96b5SLaurent Vivier 
1416e32b96b5SLaurent Vivier     unlink(tmpfile);
1417e32b96b5SLaurent Vivier     g_free(tmpfile);
1418e32b96b5SLaurent Vivier 
1419e32b96b5SLaurent Vivier     return ret;
1420e32b96b5SLaurent Vivier }
1421