xref: /qemu/tests/qtest/virtio-net-failover.c (revision e32b96b559cefb8cbb7038e913b94567e1a18045)
1*e32b96b5SLaurent Vivier /*
2*e32b96b5SLaurent Vivier  * QTest testcase for virtio-net failover
3*e32b96b5SLaurent Vivier  *
4*e32b96b5SLaurent Vivier  * See docs/system/virtio-net-failover.rst
5*e32b96b5SLaurent Vivier  *
6*e32b96b5SLaurent Vivier  * Copyright (c) 2021 Red Hat, Inc.
7*e32b96b5SLaurent Vivier  *
8*e32b96b5SLaurent Vivier  * SPDX-License-Identifier: GPL-2.0-or-later
9*e32b96b5SLaurent Vivier  */
10*e32b96b5SLaurent Vivier #include "qemu/osdep.h"
11*e32b96b5SLaurent Vivier #include "libqos/libqtest.h"
12*e32b96b5SLaurent Vivier #include "libqos/pci.h"
13*e32b96b5SLaurent Vivier #include "libqos/pci-pc.h"
14*e32b96b5SLaurent Vivier #include "qapi/qmp/qdict.h"
15*e32b96b5SLaurent Vivier #include "qapi/qmp/qlist.h"
16*e32b96b5SLaurent Vivier #include "qapi/qmp/qjson.h"
17*e32b96b5SLaurent Vivier #include "libqos/malloc-pc.h"
18*e32b96b5SLaurent Vivier #include "libqos/virtio-pci.h"
19*e32b96b5SLaurent Vivier #include "hw/pci/pci.h"
20*e32b96b5SLaurent Vivier 
21*e32b96b5SLaurent Vivier #define ACPI_PCIHP_ADDR_ICH9    0x0cc0
22*e32b96b5SLaurent Vivier #define PCI_EJ_BASE             0x0008
23*e32b96b5SLaurent Vivier 
24*e32b96b5SLaurent Vivier #define BASE_MACHINE "-M q35 -nodefaults " \
25*e32b96b5SLaurent Vivier     "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
26*e32b96b5SLaurent Vivier     "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "
27*e32b96b5SLaurent Vivier 
28*e32b96b5SLaurent Vivier #define MAC_PRIMARY0 "52:54:00:11:11:11"
29*e32b96b5SLaurent Vivier #define MAC_STANDBY0 "52:54:00:22:22:22"
30*e32b96b5SLaurent Vivier 
31*e32b96b5SLaurent Vivier static QGuestAllocator guest_malloc;
32*e32b96b5SLaurent Vivier static QPCIBus *pcibus;
33*e32b96b5SLaurent Vivier 
34*e32b96b5SLaurent Vivier static QTestState *machine_start(const char *args, int numbus)
35*e32b96b5SLaurent Vivier {
36*e32b96b5SLaurent Vivier     QTestState *qts;
37*e32b96b5SLaurent Vivier     QPCIDevice *dev;
38*e32b96b5SLaurent Vivier     int bus;
39*e32b96b5SLaurent Vivier 
40*e32b96b5SLaurent Vivier     qts = qtest_init(args);
41*e32b96b5SLaurent Vivier 
42*e32b96b5SLaurent Vivier     pc_alloc_init(&guest_malloc, qts, 0);
43*e32b96b5SLaurent Vivier     pcibus = qpci_new_pc(qts, &guest_malloc);
44*e32b96b5SLaurent Vivier     g_assert(qpci_secondary_buses_init(pcibus) == numbus);
45*e32b96b5SLaurent Vivier 
46*e32b96b5SLaurent Vivier     for (bus = 1; bus <= numbus; bus++) {
47*e32b96b5SLaurent Vivier         dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0));
48*e32b96b5SLaurent Vivier         g_assert_nonnull(dev);
49*e32b96b5SLaurent Vivier 
50*e32b96b5SLaurent Vivier         qpci_device_enable(dev);
51*e32b96b5SLaurent Vivier         qpci_iomap(dev, 4, NULL);
52*e32b96b5SLaurent Vivier 
53*e32b96b5SLaurent Vivier         g_free(dev);
54*e32b96b5SLaurent Vivier     }
55*e32b96b5SLaurent Vivier 
56*e32b96b5SLaurent Vivier     return qts;
57*e32b96b5SLaurent Vivier }
58*e32b96b5SLaurent Vivier 
59*e32b96b5SLaurent Vivier static void machine_stop(QTestState *qts)
60*e32b96b5SLaurent Vivier {
61*e32b96b5SLaurent Vivier     qpci_free_pc(pcibus);
62*e32b96b5SLaurent Vivier     alloc_destroy(&guest_malloc);
63*e32b96b5SLaurent Vivier     qtest_quit(qts);
64*e32b96b5SLaurent Vivier }
65*e32b96b5SLaurent Vivier 
66*e32b96b5SLaurent Vivier static void test_error_id(void)
67*e32b96b5SLaurent Vivier {
68*e32b96b5SLaurent Vivier     QTestState *qts;
69*e32b96b5SLaurent Vivier     QDict *resp;
70*e32b96b5SLaurent Vivier     QDict *err;
71*e32b96b5SLaurent Vivier 
72*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
73*e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,failover=on",
74*e32b96b5SLaurent Vivier                         2);
75*e32b96b5SLaurent Vivier 
76*e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{'execute': 'device_add',"
77*e32b96b5SLaurent Vivier                           "'arguments': {"
78*e32b96b5SLaurent Vivier                           "'driver': 'virtio-net',"
79*e32b96b5SLaurent Vivier                           "'bus': 'root1',"
80*e32b96b5SLaurent Vivier                           "'failover_pair_id': 'standby0'"
81*e32b96b5SLaurent Vivier                           "} }");
82*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "error"));
83*e32b96b5SLaurent Vivier 
84*e32b96b5SLaurent Vivier     err = qdict_get_qdict(resp, "error");
85*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(err, "desc"));
86*e32b96b5SLaurent Vivier 
87*e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
88*e32b96b5SLaurent Vivier                     "Device with failover_pair_id needs to have id");
89*e32b96b5SLaurent Vivier 
90*e32b96b5SLaurent Vivier     qobject_unref(resp);
91*e32b96b5SLaurent Vivier 
92*e32b96b5SLaurent Vivier     machine_stop(qts);
93*e32b96b5SLaurent Vivier }
94*e32b96b5SLaurent Vivier 
95*e32b96b5SLaurent Vivier static void test_error_pcie(void)
96*e32b96b5SLaurent Vivier {
97*e32b96b5SLaurent Vivier     QTestState *qts;
98*e32b96b5SLaurent Vivier     QDict *resp;
99*e32b96b5SLaurent Vivier     QDict *err;
100*e32b96b5SLaurent Vivier 
101*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
102*e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,failover=on",
103*e32b96b5SLaurent Vivier                         2);
104*e32b96b5SLaurent Vivier 
105*e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{'execute': 'device_add',"
106*e32b96b5SLaurent Vivier                           "'arguments': {"
107*e32b96b5SLaurent Vivier                           "'driver': 'virtio-net',"
108*e32b96b5SLaurent Vivier                           "'id': 'primary0',"
109*e32b96b5SLaurent Vivier                           "'bus': 'pcie.0',"
110*e32b96b5SLaurent Vivier                           "'failover_pair_id': 'standby0'"
111*e32b96b5SLaurent Vivier                           "} }");
112*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "error"));
113*e32b96b5SLaurent Vivier 
114*e32b96b5SLaurent Vivier     err = qdict_get_qdict(resp, "error");
115*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(err, "desc"));
116*e32b96b5SLaurent Vivier 
117*e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
118*e32b96b5SLaurent Vivier                     "Bus 'pcie.0' does not support hotplugging");
119*e32b96b5SLaurent Vivier 
120*e32b96b5SLaurent Vivier     qobject_unref(resp);
121*e32b96b5SLaurent Vivier 
122*e32b96b5SLaurent Vivier     machine_stop(qts);
123*e32b96b5SLaurent Vivier }
124*e32b96b5SLaurent Vivier 
125*e32b96b5SLaurent Vivier static QDict *find_device(QDict *bus, const char *name)
126*e32b96b5SLaurent Vivier {
127*e32b96b5SLaurent Vivier     const QObject *obj;
128*e32b96b5SLaurent Vivier     QList *devices;
129*e32b96b5SLaurent Vivier     QList *list;
130*e32b96b5SLaurent Vivier 
131*e32b96b5SLaurent Vivier     devices = qdict_get_qlist(bus, "devices");
132*e32b96b5SLaurent Vivier     if (devices == NULL) {
133*e32b96b5SLaurent Vivier         return NULL;
134*e32b96b5SLaurent Vivier     }
135*e32b96b5SLaurent Vivier 
136*e32b96b5SLaurent Vivier     list = qlist_copy(devices);
137*e32b96b5SLaurent Vivier     while ((obj = qlist_pop(list))) {
138*e32b96b5SLaurent Vivier         QDict *device;
139*e32b96b5SLaurent Vivier 
140*e32b96b5SLaurent Vivier         device = qobject_to(QDict, obj);
141*e32b96b5SLaurent Vivier 
142*e32b96b5SLaurent Vivier         if (qdict_haskey(device, "pci_bridge")) {
143*e32b96b5SLaurent Vivier             QDict *bridge;
144*e32b96b5SLaurent Vivier             QDict *bridge_device;
145*e32b96b5SLaurent Vivier 
146*e32b96b5SLaurent Vivier             bridge = qdict_get_qdict(device, "pci_bridge");
147*e32b96b5SLaurent Vivier 
148*e32b96b5SLaurent Vivier             if (qdict_haskey(bridge, "devices")) {
149*e32b96b5SLaurent Vivier                 bridge_device = find_device(bridge, name);
150*e32b96b5SLaurent Vivier                 if (bridge_device) {
151*e32b96b5SLaurent Vivier                     qobject_unref(device);
152*e32b96b5SLaurent Vivier                     qobject_unref(list);
153*e32b96b5SLaurent Vivier                     return bridge_device;
154*e32b96b5SLaurent Vivier                 }
155*e32b96b5SLaurent Vivier             }
156*e32b96b5SLaurent Vivier         }
157*e32b96b5SLaurent Vivier 
158*e32b96b5SLaurent Vivier         if (!qdict_haskey(device, "qdev_id")) {
159*e32b96b5SLaurent Vivier             qobject_unref(device);
160*e32b96b5SLaurent Vivier             continue;
161*e32b96b5SLaurent Vivier         }
162*e32b96b5SLaurent Vivier 
163*e32b96b5SLaurent Vivier         if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) {
164*e32b96b5SLaurent Vivier             qobject_unref(list);
165*e32b96b5SLaurent Vivier             return device;
166*e32b96b5SLaurent Vivier         }
167*e32b96b5SLaurent Vivier         qobject_unref(device);
168*e32b96b5SLaurent Vivier     }
169*e32b96b5SLaurent Vivier     qobject_unref(list);
170*e32b96b5SLaurent Vivier 
171*e32b96b5SLaurent Vivier     return NULL;
172*e32b96b5SLaurent Vivier }
173*e32b96b5SLaurent Vivier 
174*e32b96b5SLaurent Vivier static QDict *get_bus(QTestState *qts, int num)
175*e32b96b5SLaurent Vivier {
176*e32b96b5SLaurent Vivier     QObject *obj;
177*e32b96b5SLaurent Vivier     QDict *resp;
178*e32b96b5SLaurent Vivier     QList *ret;
179*e32b96b5SLaurent Vivier 
180*e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }");
181*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
182*e32b96b5SLaurent Vivier 
183*e32b96b5SLaurent Vivier     ret = qdict_get_qlist(resp, "return");
184*e32b96b5SLaurent Vivier     g_assert_nonnull(ret);
185*e32b96b5SLaurent Vivier 
186*e32b96b5SLaurent Vivier     while ((obj = qlist_pop(ret))) {
187*e32b96b5SLaurent Vivier         QDict *bus;
188*e32b96b5SLaurent Vivier 
189*e32b96b5SLaurent Vivier         bus = qobject_to(QDict, obj);
190*e32b96b5SLaurent Vivier         if (!qdict_haskey(bus, "bus")) {
191*e32b96b5SLaurent Vivier             qobject_unref(bus);
192*e32b96b5SLaurent Vivier             continue;
193*e32b96b5SLaurent Vivier         }
194*e32b96b5SLaurent Vivier         if (qdict_get_int(bus, "bus") == num) {
195*e32b96b5SLaurent Vivier             qobject_unref(resp);
196*e32b96b5SLaurent Vivier             return bus;
197*e32b96b5SLaurent Vivier         }
198*e32b96b5SLaurent Vivier         qobject_ref(bus);
199*e32b96b5SLaurent Vivier     }
200*e32b96b5SLaurent Vivier     qobject_unref(resp);
201*e32b96b5SLaurent Vivier 
202*e32b96b5SLaurent Vivier     return NULL;
203*e32b96b5SLaurent Vivier }
204*e32b96b5SLaurent Vivier 
205*e32b96b5SLaurent Vivier static char *get_mac(QTestState *qts, const char *name)
206*e32b96b5SLaurent Vivier {
207*e32b96b5SLaurent Vivier     QDict *resp;
208*e32b96b5SLaurent Vivier     char *mac;
209*e32b96b5SLaurent Vivier 
210*e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'qom-get', "
211*e32b96b5SLaurent Vivier                      "'arguments': { "
212*e32b96b5SLaurent Vivier                      "'path': %s, "
213*e32b96b5SLaurent Vivier                      "'property': 'mac' } }", name);
214*e32b96b5SLaurent Vivier 
215*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
216*e32b96b5SLaurent Vivier 
217*e32b96b5SLaurent Vivier     mac = g_strdup(qdict_get_str(resp, "return"));
218*e32b96b5SLaurent Vivier 
219*e32b96b5SLaurent Vivier     qobject_unref(resp);
220*e32b96b5SLaurent Vivier 
221*e32b96b5SLaurent Vivier     return mac;
222*e32b96b5SLaurent Vivier }
223*e32b96b5SLaurent Vivier 
224*e32b96b5SLaurent Vivier static void check_one_card(QTestState *qts, bool present,
225*e32b96b5SLaurent Vivier                            const char *id, const char *mac)
226*e32b96b5SLaurent Vivier {
227*e32b96b5SLaurent Vivier     QDict *device;
228*e32b96b5SLaurent Vivier     QDict *bus;
229*e32b96b5SLaurent Vivier     char *addr;
230*e32b96b5SLaurent Vivier 
231*e32b96b5SLaurent Vivier     bus = get_bus(qts, 0);
232*e32b96b5SLaurent Vivier     device = find_device(bus, id);
233*e32b96b5SLaurent Vivier     if (present) {
234*e32b96b5SLaurent Vivier         char *path;
235*e32b96b5SLaurent Vivier 
236*e32b96b5SLaurent Vivier         g_assert_nonnull(device);
237*e32b96b5SLaurent Vivier         qobject_unref(device);
238*e32b96b5SLaurent Vivier 
239*e32b96b5SLaurent Vivier         path = g_strdup_printf("/machine/peripheral/%s", id);
240*e32b96b5SLaurent Vivier         addr = get_mac(qts, path);
241*e32b96b5SLaurent Vivier         g_free(path);
242*e32b96b5SLaurent Vivier         g_assert_cmpstr(mac, ==, addr);
243*e32b96b5SLaurent Vivier         g_free(addr);
244*e32b96b5SLaurent Vivier     } else {
245*e32b96b5SLaurent Vivier        g_assert_null(device);
246*e32b96b5SLaurent Vivier     }
247*e32b96b5SLaurent Vivier 
248*e32b96b5SLaurent Vivier     qobject_unref(bus);
249*e32b96b5SLaurent Vivier }
250*e32b96b5SLaurent Vivier 
251*e32b96b5SLaurent Vivier static void test_on(void)
252*e32b96b5SLaurent Vivier {
253*e32b96b5SLaurent Vivier     QTestState *qts;
254*e32b96b5SLaurent Vivier 
255*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
256*e32b96b5SLaurent Vivier                         "-netdev user,id=hs0 "
257*e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root0,id=standby0,"
258*e32b96b5SLaurent Vivier                         "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
259*e32b96b5SLaurent Vivier                         "-device virtio-net,bus=root1,id=primary0,"
260*e32b96b5SLaurent Vivier                         "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
261*e32b96b5SLaurent Vivier                         2);
262*e32b96b5SLaurent Vivier 
263*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
264*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
265*e32b96b5SLaurent Vivier 
266*e32b96b5SLaurent Vivier     machine_stop(qts);
267*e32b96b5SLaurent Vivier }
268*e32b96b5SLaurent Vivier 
269*e32b96b5SLaurent Vivier static void test_on_mismatch(void)
270*e32b96b5SLaurent Vivier {
271*e32b96b5SLaurent Vivier     QTestState *qts;
272*e32b96b5SLaurent Vivier 
273*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
274*e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
275*e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
276*e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
277*e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
278*e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
279*e32b96b5SLaurent Vivier                      "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0,
280*e32b96b5SLaurent Vivier                      2);
281*e32b96b5SLaurent Vivier 
282*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
283*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
284*e32b96b5SLaurent Vivier 
285*e32b96b5SLaurent Vivier     machine_stop(qts);
286*e32b96b5SLaurent Vivier }
287*e32b96b5SLaurent Vivier 
288*e32b96b5SLaurent Vivier static void test_off(void)
289*e32b96b5SLaurent Vivier {
290*e32b96b5SLaurent Vivier     QTestState *qts;
291*e32b96b5SLaurent Vivier 
292*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
293*e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
294*e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
295*e32b96b5SLaurent Vivier                      "failover=off,netdev=hs0,mac="MAC_STANDBY0" "
296*e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
297*e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
298*e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
299*e32b96b5SLaurent Vivier                      2);
300*e32b96b5SLaurent Vivier 
301*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
302*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
303*e32b96b5SLaurent Vivier 
304*e32b96b5SLaurent Vivier     machine_stop(qts);
305*e32b96b5SLaurent Vivier }
306*e32b96b5SLaurent Vivier 
307*e32b96b5SLaurent Vivier static QDict *get_failover_negociated_event(QTestState *qts)
308*e32b96b5SLaurent Vivier {
309*e32b96b5SLaurent Vivier     QDict *resp;
310*e32b96b5SLaurent Vivier     QDict *data;
311*e32b96b5SLaurent Vivier 
312*e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED");
313*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
314*e32b96b5SLaurent Vivier 
315*e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
316*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
317*e32b96b5SLaurent Vivier     qobject_ref(data);
318*e32b96b5SLaurent Vivier     qobject_unref(resp);
319*e32b96b5SLaurent Vivier 
320*e32b96b5SLaurent Vivier     return data;
321*e32b96b5SLaurent Vivier }
322*e32b96b5SLaurent Vivier 
323*e32b96b5SLaurent Vivier static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
324*e32b96b5SLaurent Vivier                              const char *id)
325*e32b96b5SLaurent Vivier {
326*e32b96b5SLaurent Vivier     QVirtioPCIDevice *dev;
327*e32b96b5SLaurent Vivier     uint64_t features;
328*e32b96b5SLaurent Vivier     QPCIAddress addr;
329*e32b96b5SLaurent Vivier     QDict *resp;
330*e32b96b5SLaurent Vivier 
331*e32b96b5SLaurent Vivier     addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0);
332*e32b96b5SLaurent Vivier     dev = virtio_pci_new(pcibus, &addr);
333*e32b96b5SLaurent Vivier     g_assert_nonnull(dev);
334*e32b96b5SLaurent Vivier     qvirtio_pci_device_enable(dev);
335*e32b96b5SLaurent Vivier     qvirtio_start_device(&dev->vdev);
336*e32b96b5SLaurent Vivier     features = qvirtio_get_features(&dev->vdev);
337*e32b96b5SLaurent Vivier     features = features & ~(QVIRTIO_F_BAD_FEATURE |
338*e32b96b5SLaurent Vivier                             (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
339*e32b96b5SLaurent Vivier                             (1ull << VIRTIO_RING_F_EVENT_IDX));
340*e32b96b5SLaurent Vivier     qvirtio_set_features(&dev->vdev, features);
341*e32b96b5SLaurent Vivier     qvirtio_set_driver_ok(&dev->vdev);
342*e32b96b5SLaurent Vivier 
343*e32b96b5SLaurent Vivier     resp = get_failover_negociated_event(qts);
344*e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
345*e32b96b5SLaurent Vivier     qobject_unref(resp);
346*e32b96b5SLaurent Vivier 
347*e32b96b5SLaurent Vivier     return dev;
348*e32b96b5SLaurent Vivier }
349*e32b96b5SLaurent Vivier 
350*e32b96b5SLaurent Vivier static void test_enabled(void)
351*e32b96b5SLaurent Vivier {
352*e32b96b5SLaurent Vivier     QTestState *qts;
353*e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
354*e32b96b5SLaurent Vivier 
355*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
356*e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
357*e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
358*e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
359*e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
360*e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
361*e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
362*e32b96b5SLaurent Vivier                      2);
363*e32b96b5SLaurent Vivier 
364*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
365*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
366*e32b96b5SLaurent Vivier 
367*e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
368*e32b96b5SLaurent Vivier 
369*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
370*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
371*e32b96b5SLaurent Vivier 
372*e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
373*e32b96b5SLaurent Vivier     machine_stop(qts);
374*e32b96b5SLaurent Vivier }
375*e32b96b5SLaurent Vivier 
376*e32b96b5SLaurent Vivier static void test_hotplug_1(void)
377*e32b96b5SLaurent Vivier {
378*e32b96b5SLaurent Vivier     QTestState *qts;
379*e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
380*e32b96b5SLaurent Vivier 
381*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
382*e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
383*e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root0,id=standby0,"
384*e32b96b5SLaurent Vivier                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
385*e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ", 2);
386*e32b96b5SLaurent Vivier 
387*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
388*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
389*e32b96b5SLaurent Vivier 
390*e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
391*e32b96b5SLaurent Vivier 
392*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
393*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
394*e32b96b5SLaurent Vivier 
395*e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
396*e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
397*e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
398*e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
399*e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
400*e32b96b5SLaurent Vivier 
401*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
402*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
403*e32b96b5SLaurent Vivier 
404*e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
405*e32b96b5SLaurent Vivier     machine_stop(qts);
406*e32b96b5SLaurent Vivier }
407*e32b96b5SLaurent Vivier 
408*e32b96b5SLaurent Vivier static void test_hotplug_1_reverse(void)
409*e32b96b5SLaurent Vivier {
410*e32b96b5SLaurent Vivier     QTestState *qts;
411*e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
412*e32b96b5SLaurent Vivier 
413*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
414*e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
415*e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
416*e32b96b5SLaurent Vivier                      "-device virtio-net,bus=root1,id=primary0,"
417*e32b96b5SLaurent Vivier                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
418*e32b96b5SLaurent Vivier                      2);
419*e32b96b5SLaurent Vivier 
420*e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
421*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
422*e32b96b5SLaurent Vivier 
423*e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
424*e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
425*e32b96b5SLaurent Vivier                          "'failover': 'on',"
426*e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
427*e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
428*e32b96b5SLaurent Vivier 
429*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
430*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
431*e32b96b5SLaurent Vivier 
432*e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
433*e32b96b5SLaurent Vivier 
434*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
435*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
436*e32b96b5SLaurent Vivier 
437*e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
438*e32b96b5SLaurent Vivier     machine_stop(qts);
439*e32b96b5SLaurent Vivier }
440*e32b96b5SLaurent Vivier 
441*e32b96b5SLaurent Vivier static void test_hotplug_2(void)
442*e32b96b5SLaurent Vivier {
443*e32b96b5SLaurent Vivier     QTestState *qts;
444*e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
445*e32b96b5SLaurent Vivier 
446*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
447*e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
448*e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
449*e32b96b5SLaurent Vivier                      2);
450*e32b96b5SLaurent Vivier 
451*e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
452*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
453*e32b96b5SLaurent Vivier 
454*e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
455*e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
456*e32b96b5SLaurent Vivier                          "'failover': 'on',"
457*e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
458*e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
459*e32b96b5SLaurent Vivier 
460*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
461*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
462*e32b96b5SLaurent Vivier 
463*e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
464*e32b96b5SLaurent Vivier 
465*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
466*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
467*e32b96b5SLaurent Vivier 
468*e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
469*e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
470*e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
471*e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
472*e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
473*e32b96b5SLaurent Vivier 
474*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
475*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
476*e32b96b5SLaurent Vivier 
477*e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
478*e32b96b5SLaurent Vivier     machine_stop(qts);
479*e32b96b5SLaurent Vivier }
480*e32b96b5SLaurent Vivier 
481*e32b96b5SLaurent Vivier static void test_hotplug_2_reverse(void)
482*e32b96b5SLaurent Vivier {
483*e32b96b5SLaurent Vivier     QTestState *qts;
484*e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
485*e32b96b5SLaurent Vivier 
486*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
487*e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
488*e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
489*e32b96b5SLaurent Vivier                      2);
490*e32b96b5SLaurent Vivier 
491*e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
492*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
493*e32b96b5SLaurent Vivier 
494*e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
495*e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
496*e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
497*e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
498*e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
499*e32b96b5SLaurent Vivier 
500*e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
501*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
502*e32b96b5SLaurent Vivier 
503*e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
504*e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
505*e32b96b5SLaurent Vivier                          "'failover': 'on',"
506*e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
507*e32b96b5SLaurent Vivier                          "'rombar': 0,"
508*e32b96b5SLaurent Vivier                          "'romfile': '',"
509*e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
510*e32b96b5SLaurent Vivier 
511*e32b96b5SLaurent Vivier     /*
512*e32b96b5SLaurent Vivier      * XXX: sounds like a bug:
513*e32b96b5SLaurent Vivier      * The primary should be hidden until the virtio-net driver
514*e32b96b5SLaurent Vivier      * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
515*e32b96b5SLaurent Vivier      */
516*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
517*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
518*e32b96b5SLaurent Vivier 
519*e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
520*e32b96b5SLaurent Vivier 
521*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
522*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
523*e32b96b5SLaurent Vivier 
524*e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
525*e32b96b5SLaurent Vivier     machine_stop(qts);
526*e32b96b5SLaurent Vivier }
527*e32b96b5SLaurent Vivier 
528*e32b96b5SLaurent Vivier static QDict *migrate_status(QTestState *qts)
529*e32b96b5SLaurent Vivier {
530*e32b96b5SLaurent Vivier     QDict *resp, *ret;
531*e32b96b5SLaurent Vivier 
532*e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
533*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
534*e32b96b5SLaurent Vivier 
535*e32b96b5SLaurent Vivier     ret = qdict_get_qdict(resp, "return");
536*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(ret, "status"));
537*e32b96b5SLaurent Vivier     qobject_ref(ret);
538*e32b96b5SLaurent Vivier     qobject_unref(resp);
539*e32b96b5SLaurent Vivier 
540*e32b96b5SLaurent Vivier     return ret;
541*e32b96b5SLaurent Vivier }
542*e32b96b5SLaurent Vivier 
543*e32b96b5SLaurent Vivier static QDict *get_unplug_primary_event(QTestState *qts)
544*e32b96b5SLaurent Vivier {
545*e32b96b5SLaurent Vivier     QDict *resp;
546*e32b96b5SLaurent Vivier     QDict *data;
547*e32b96b5SLaurent Vivier 
548*e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
549*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
550*e32b96b5SLaurent Vivier 
551*e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
552*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "device-id"));
553*e32b96b5SLaurent Vivier     qobject_ref(data);
554*e32b96b5SLaurent Vivier     qobject_unref(resp);
555*e32b96b5SLaurent Vivier 
556*e32b96b5SLaurent Vivier     return data;
557*e32b96b5SLaurent Vivier }
558*e32b96b5SLaurent Vivier 
559*e32b96b5SLaurent Vivier static void test_migrate_out(gconstpointer opaque)
560*e32b96b5SLaurent Vivier {
561*e32b96b5SLaurent Vivier     QTestState *qts;
562*e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
563*e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
564*e32b96b5SLaurent Vivier     const gchar *status;
565*e32b96b5SLaurent Vivier     QVirtioPCIDevice *vdev;
566*e32b96b5SLaurent Vivier 
567*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
568*e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
569*e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 ",
570*e32b96b5SLaurent Vivier                      2);
571*e32b96b5SLaurent Vivier 
572*e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
573*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
574*e32b96b5SLaurent Vivier 
575*e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
576*e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
577*e32b96b5SLaurent Vivier                          "'failover': 'on',"
578*e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
579*e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
580*e32b96b5SLaurent Vivier 
581*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
582*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
583*e32b96b5SLaurent Vivier 
584*e32b96b5SLaurent Vivier     vdev = start_virtio_net(qts, 1, 0, "standby0");
585*e32b96b5SLaurent Vivier 
586*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
587*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
588*e32b96b5SLaurent Vivier 
589*e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
590*e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
591*e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
592*e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
593*e32b96b5SLaurent Vivier                          "'rombar': 0,"
594*e32b96b5SLaurent Vivier                          "'romfile': '',"
595*e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
596*e32b96b5SLaurent Vivier 
597*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
598*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
599*e32b96b5SLaurent Vivier 
600*e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
601*e32b96b5SLaurent Vivier     g_assert_nonnull(args);
602*e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
603*e32b96b5SLaurent Vivier 
604*e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
605*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
606*e32b96b5SLaurent Vivier     qobject_unref(resp);
607*e32b96b5SLaurent Vivier 
608*e32b96b5SLaurent Vivier     /* the event is sent when QEMU asks the OS to unplug the card */
609*e32b96b5SLaurent Vivier     resp = get_unplug_primary_event(qts);
610*e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
611*e32b96b5SLaurent Vivier     qobject_unref(resp);
612*e32b96b5SLaurent Vivier 
613*e32b96b5SLaurent Vivier     /* wait the end of the migration setup phase */
614*e32b96b5SLaurent Vivier     while (true) {
615*e32b96b5SLaurent Vivier         ret = migrate_status(qts);
616*e32b96b5SLaurent Vivier 
617*e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
618*e32b96b5SLaurent Vivier         if (strcmp(status, "wait-unplug") == 0) {
619*e32b96b5SLaurent Vivier             qobject_unref(ret);
620*e32b96b5SLaurent Vivier             break;
621*e32b96b5SLaurent Vivier         }
622*e32b96b5SLaurent Vivier 
623*e32b96b5SLaurent Vivier         /* The migration must not start if the card is not ejected */
624*e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "active");
625*e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "completed");
626*e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
627*e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
628*e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
629*e32b96b5SLaurent Vivier 
630*e32b96b5SLaurent Vivier         qobject_unref(ret);
631*e32b96b5SLaurent Vivier     }
632*e32b96b5SLaurent Vivier 
633*e32b96b5SLaurent Vivier     if (g_test_slow()) {
634*e32b96b5SLaurent Vivier         /* check we stay in wait-unplug while the card is not ejected */
635*e32b96b5SLaurent Vivier         for (int i = 0; i < 5; i++) {
636*e32b96b5SLaurent Vivier             sleep(1);
637*e32b96b5SLaurent Vivier             ret = migrate_status(qts);
638*e32b96b5SLaurent Vivier             status = qdict_get_str(ret, "status");
639*e32b96b5SLaurent Vivier             g_assert_cmpstr(status, ==, "wait-unplug");
640*e32b96b5SLaurent Vivier             qobject_unref(ret);
641*e32b96b5SLaurent Vivier         }
642*e32b96b5SLaurent Vivier     }
643*e32b96b5SLaurent Vivier 
644*e32b96b5SLaurent Vivier     /* OS unplugs the cards, QEMU can move from wait-unplug state */
645*e32b96b5SLaurent Vivier     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
646*e32b96b5SLaurent Vivier 
647*e32b96b5SLaurent Vivier     while (true) {
648*e32b96b5SLaurent Vivier         ret = migrate_status(qts);
649*e32b96b5SLaurent Vivier 
650*e32b96b5SLaurent Vivier         status = qdict_get_str(ret, "status");
651*e32b96b5SLaurent Vivier         if (strcmp(status, "completed") == 0) {
652*e32b96b5SLaurent Vivier             qobject_unref(ret);
653*e32b96b5SLaurent Vivier             break;
654*e32b96b5SLaurent Vivier         }
655*e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "failed");
656*e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelling");
657*e32b96b5SLaurent Vivier         g_assert_cmpstr(status, !=, "cancelled");
658*e32b96b5SLaurent Vivier         qobject_unref(ret);
659*e32b96b5SLaurent Vivier     }
660*e32b96b5SLaurent Vivier 
661*e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "STOP");
662*e32b96b5SLaurent Vivier 
663*e32b96b5SLaurent Vivier     /*
664*e32b96b5SLaurent Vivier      * in fact, the card is ejected from the point of view of kernel
665*e32b96b5SLaurent Vivier      * but not really from QEMU to be able to hotplug it back if
666*e32b96b5SLaurent Vivier      * migration fails. So we can't check that:
667*e32b96b5SLaurent Vivier      *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
668*e32b96b5SLaurent Vivier      *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
669*e32b96b5SLaurent Vivier      */
670*e32b96b5SLaurent Vivier 
671*e32b96b5SLaurent Vivier     qos_object_destroy((QOSGraphObject *)vdev);
672*e32b96b5SLaurent Vivier     machine_stop(qts);
673*e32b96b5SLaurent Vivier }
674*e32b96b5SLaurent Vivier 
675*e32b96b5SLaurent Vivier static QDict *get_migration_event(QTestState *qts)
676*e32b96b5SLaurent Vivier {
677*e32b96b5SLaurent Vivier     QDict *resp;
678*e32b96b5SLaurent Vivier     QDict *data;
679*e32b96b5SLaurent Vivier 
680*e32b96b5SLaurent Vivier     resp = qtest_qmp_eventwait_ref(qts, "MIGRATION");
681*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "data"));
682*e32b96b5SLaurent Vivier 
683*e32b96b5SLaurent Vivier     data = qdict_get_qdict(resp, "data");
684*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(data, "status"));
685*e32b96b5SLaurent Vivier     qobject_ref(data);
686*e32b96b5SLaurent Vivier     qobject_unref(resp);
687*e32b96b5SLaurent Vivier 
688*e32b96b5SLaurent Vivier     return data;
689*e32b96b5SLaurent Vivier }
690*e32b96b5SLaurent Vivier 
691*e32b96b5SLaurent Vivier static void test_migrate_in(gconstpointer opaque)
692*e32b96b5SLaurent Vivier {
693*e32b96b5SLaurent Vivier     QTestState *qts;
694*e32b96b5SLaurent Vivier     QDict *resp, *args, *ret;
695*e32b96b5SLaurent Vivier     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
696*e32b96b5SLaurent Vivier 
697*e32b96b5SLaurent Vivier     qts = machine_start(BASE_MACHINE
698*e32b96b5SLaurent Vivier                      "-netdev user,id=hs0 "
699*e32b96b5SLaurent Vivier                      "-netdev user,id=hs1 "
700*e32b96b5SLaurent Vivier                      "-incoming defer ",
701*e32b96b5SLaurent Vivier                      2);
702*e32b96b5SLaurent Vivier 
703*e32b96b5SLaurent Vivier     check_one_card(qts, false, "standby0", MAC_STANDBY0);
704*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
705*e32b96b5SLaurent Vivier 
706*e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "standby0",
707*e32b96b5SLaurent Vivier                          "{'bus': 'root0',"
708*e32b96b5SLaurent Vivier                          "'failover': 'on',"
709*e32b96b5SLaurent Vivier                          "'netdev': 'hs0',"
710*e32b96b5SLaurent Vivier                          "'mac': '"MAC_STANDBY0"'}");
711*e32b96b5SLaurent Vivier 
712*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
713*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
714*e32b96b5SLaurent Vivier 
715*e32b96b5SLaurent Vivier     qtest_qmp_device_add(qts, "virtio-net", "primary0",
716*e32b96b5SLaurent Vivier                          "{'bus': 'root1',"
717*e32b96b5SLaurent Vivier                          "'failover_pair_id': 'standby0',"
718*e32b96b5SLaurent Vivier                          "'netdev': 'hs1',"
719*e32b96b5SLaurent Vivier                          "'rombar': 0,"
720*e32b96b5SLaurent Vivier                          "'romfile': '',"
721*e32b96b5SLaurent Vivier                          "'mac': '"MAC_PRIMARY0"'}");
722*e32b96b5SLaurent Vivier 
723*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
724*e32b96b5SLaurent Vivier     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
725*e32b96b5SLaurent Vivier 
726*e32b96b5SLaurent Vivier     args = qdict_from_jsonf_nofail("{}");
727*e32b96b5SLaurent Vivier     g_assert_nonnull(args);
728*e32b96b5SLaurent Vivier     qdict_put_str(args, "uri", uri);
729*e32b96b5SLaurent Vivier 
730*e32b96b5SLaurent Vivier     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
731*e32b96b5SLaurent Vivier                      args);
732*e32b96b5SLaurent Vivier     g_assert(qdict_haskey(resp, "return"));
733*e32b96b5SLaurent Vivier     qobject_unref(resp);
734*e32b96b5SLaurent Vivier 
735*e32b96b5SLaurent Vivier     resp = get_migration_event(qts);
736*e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
737*e32b96b5SLaurent Vivier     qobject_unref(resp);
738*e32b96b5SLaurent Vivier 
739*e32b96b5SLaurent Vivier     resp = get_failover_negociated_event(qts);
740*e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
741*e32b96b5SLaurent Vivier     qobject_unref(resp);
742*e32b96b5SLaurent Vivier 
743*e32b96b5SLaurent Vivier     check_one_card(qts, true, "standby0", MAC_STANDBY0);
744*e32b96b5SLaurent Vivier     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
745*e32b96b5SLaurent Vivier 
746*e32b96b5SLaurent Vivier     qtest_qmp_eventwait(qts, "RESUME");
747*e32b96b5SLaurent Vivier 
748*e32b96b5SLaurent Vivier     ret = migrate_status(qts);
749*e32b96b5SLaurent Vivier     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
750*e32b96b5SLaurent Vivier     qobject_unref(ret);
751*e32b96b5SLaurent Vivier 
752*e32b96b5SLaurent Vivier     machine_stop(qts);
753*e32b96b5SLaurent Vivier }
754*e32b96b5SLaurent Vivier 
755*e32b96b5SLaurent Vivier int main(int argc, char **argv)
756*e32b96b5SLaurent Vivier {
757*e32b96b5SLaurent Vivier     const gchar *tmpdir = g_get_tmp_dir();
758*e32b96b5SLaurent Vivier     gchar *tmpfile = g_strdup_printf("%s/failover_test_migrate-%u-%u",
759*e32b96b5SLaurent Vivier                                      tmpdir, getpid(), g_test_rand_int());
760*e32b96b5SLaurent Vivier     int ret;
761*e32b96b5SLaurent Vivier 
762*e32b96b5SLaurent Vivier     g_test_init(&argc, &argv, NULL);
763*e32b96b5SLaurent Vivier 
764*e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
765*e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
766*e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on", test_on);
767*e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/on_mismatch",
768*e32b96b5SLaurent Vivier                    test_on_mismatch);
769*e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/off", test_off);
770*e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
771*e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_1", test_hotplug_1);
772*e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_1_reverse",
773*e32b96b5SLaurent Vivier                    test_hotplug_1_reverse);
774*e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_2", test_hotplug_2);
775*e32b96b5SLaurent Vivier     qtest_add_func("failover-virtio-net/hotplug_2_reverse",
776*e32b96b5SLaurent Vivier                    test_hotplug_2_reverse);
777*e32b96b5SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/out", tmpfile,
778*e32b96b5SLaurent Vivier                         test_migrate_out);
779*e32b96b5SLaurent Vivier     qtest_add_data_func("failover-virtio-net/migrate/in", tmpfile,
780*e32b96b5SLaurent Vivier                         test_migrate_in);
781*e32b96b5SLaurent Vivier 
782*e32b96b5SLaurent Vivier     ret = g_test_run();
783*e32b96b5SLaurent Vivier 
784*e32b96b5SLaurent Vivier     unlink(tmpfile);
785*e32b96b5SLaurent Vivier     g_free(tmpfile);
786*e32b96b5SLaurent Vivier 
787*e32b96b5SLaurent Vivier     return ret;
788*e32b96b5SLaurent Vivier }
789