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