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 21e32b96b5SLaurent Vivier #define ACPI_PCIHP_ADDR_ICH9 0x0cc0 22e32b96b5SLaurent Vivier #define PCI_EJ_BASE 0x0008 23e32b96b5SLaurent Vivier 24e32b96b5SLaurent Vivier #define BASE_MACHINE "-M q35 -nodefaults " \ 25e32b96b5SLaurent Vivier "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \ 26e32b96b5SLaurent Vivier "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 " 27e32b96b5SLaurent Vivier 28e32b96b5SLaurent Vivier #define MAC_PRIMARY0 "52:54:00:11:11:11" 29e32b96b5SLaurent Vivier #define MAC_STANDBY0 "52:54:00:22:22:22" 30e32b96b5SLaurent Vivier 31e32b96b5SLaurent Vivier static QGuestAllocator guest_malloc; 32e32b96b5SLaurent Vivier static QPCIBus *pcibus; 33e32b96b5SLaurent Vivier 34e32b96b5SLaurent Vivier static QTestState *machine_start(const char *args, int numbus) 35e32b96b5SLaurent Vivier { 36e32b96b5SLaurent Vivier QTestState *qts; 37e32b96b5SLaurent Vivier QPCIDevice *dev; 38e32b96b5SLaurent Vivier int bus; 39e32b96b5SLaurent Vivier 40e32b96b5SLaurent Vivier qts = qtest_init(args); 41e32b96b5SLaurent Vivier 42e32b96b5SLaurent Vivier pc_alloc_init(&guest_malloc, qts, 0); 43e32b96b5SLaurent Vivier pcibus = qpci_new_pc(qts, &guest_malloc); 44e32b96b5SLaurent Vivier g_assert(qpci_secondary_buses_init(pcibus) == numbus); 45e32b96b5SLaurent Vivier 46e32b96b5SLaurent Vivier for (bus = 1; bus <= numbus; bus++) { 47e32b96b5SLaurent Vivier dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0)); 48e32b96b5SLaurent Vivier g_assert_nonnull(dev); 49e32b96b5SLaurent Vivier 50e32b96b5SLaurent Vivier qpci_device_enable(dev); 51e32b96b5SLaurent Vivier qpci_iomap(dev, 4, NULL); 52e32b96b5SLaurent Vivier 53e32b96b5SLaurent Vivier g_free(dev); 54e32b96b5SLaurent Vivier } 55e32b96b5SLaurent Vivier 56e32b96b5SLaurent Vivier return qts; 57e32b96b5SLaurent Vivier } 58e32b96b5SLaurent Vivier 59e32b96b5SLaurent Vivier static void machine_stop(QTestState *qts) 60e32b96b5SLaurent Vivier { 61e32b96b5SLaurent Vivier qpci_free_pc(pcibus); 62e32b96b5SLaurent Vivier alloc_destroy(&guest_malloc); 63e32b96b5SLaurent Vivier qtest_quit(qts); 64e32b96b5SLaurent Vivier } 65e32b96b5SLaurent Vivier 66e32b96b5SLaurent Vivier static void test_error_id(void) 67e32b96b5SLaurent Vivier { 68e32b96b5SLaurent Vivier QTestState *qts; 69e32b96b5SLaurent Vivier QDict *resp; 70e32b96b5SLaurent Vivier QDict *err; 71e32b96b5SLaurent Vivier 72e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 73e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0,failover=on", 74e32b96b5SLaurent Vivier 2); 75e32b96b5SLaurent Vivier 76e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{'execute': 'device_add'," 77e32b96b5SLaurent Vivier "'arguments': {" 78e32b96b5SLaurent Vivier "'driver': 'virtio-net'," 79e32b96b5SLaurent Vivier "'bus': 'root1'," 80e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'" 81e32b96b5SLaurent Vivier "} }"); 82e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "error")); 83e32b96b5SLaurent Vivier 84e32b96b5SLaurent Vivier err = qdict_get_qdict(resp, "error"); 85e32b96b5SLaurent Vivier g_assert(qdict_haskey(err, "desc")); 86e32b96b5SLaurent Vivier 87e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(err, "desc"), ==, 88e32b96b5SLaurent Vivier "Device with failover_pair_id needs to have id"); 89e32b96b5SLaurent Vivier 90e32b96b5SLaurent Vivier qobject_unref(resp); 91e32b96b5SLaurent Vivier 92e32b96b5SLaurent Vivier machine_stop(qts); 93e32b96b5SLaurent Vivier } 94e32b96b5SLaurent Vivier 95e32b96b5SLaurent Vivier static void test_error_pcie(void) 96e32b96b5SLaurent Vivier { 97e32b96b5SLaurent Vivier QTestState *qts; 98e32b96b5SLaurent Vivier QDict *resp; 99e32b96b5SLaurent Vivier QDict *err; 100e32b96b5SLaurent Vivier 101e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 102e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0,failover=on", 103e32b96b5SLaurent Vivier 2); 104e32b96b5SLaurent Vivier 105e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{'execute': 'device_add'," 106e32b96b5SLaurent Vivier "'arguments': {" 107e32b96b5SLaurent Vivier "'driver': 'virtio-net'," 108e32b96b5SLaurent Vivier "'id': 'primary0'," 109e32b96b5SLaurent Vivier "'bus': 'pcie.0'," 110e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'" 111e32b96b5SLaurent Vivier "} }"); 112e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "error")); 113e32b96b5SLaurent Vivier 114e32b96b5SLaurent Vivier err = qdict_get_qdict(resp, "error"); 115e32b96b5SLaurent Vivier g_assert(qdict_haskey(err, "desc")); 116e32b96b5SLaurent Vivier 117e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(err, "desc"), ==, 118e32b96b5SLaurent Vivier "Bus 'pcie.0' does not support hotplugging"); 119e32b96b5SLaurent Vivier 120e32b96b5SLaurent Vivier qobject_unref(resp); 121e32b96b5SLaurent Vivier 122e32b96b5SLaurent Vivier machine_stop(qts); 123e32b96b5SLaurent Vivier } 124e32b96b5SLaurent Vivier 125e32b96b5SLaurent Vivier static QDict *find_device(QDict *bus, const char *name) 126e32b96b5SLaurent Vivier { 127e32b96b5SLaurent Vivier const QObject *obj; 128e32b96b5SLaurent Vivier QList *devices; 129e32b96b5SLaurent Vivier QList *list; 130e32b96b5SLaurent Vivier 131e32b96b5SLaurent Vivier devices = qdict_get_qlist(bus, "devices"); 132e32b96b5SLaurent Vivier if (devices == NULL) { 133e32b96b5SLaurent Vivier return NULL; 134e32b96b5SLaurent Vivier } 135e32b96b5SLaurent Vivier 136e32b96b5SLaurent Vivier list = qlist_copy(devices); 137e32b96b5SLaurent Vivier while ((obj = qlist_pop(list))) { 138e32b96b5SLaurent Vivier QDict *device; 139e32b96b5SLaurent Vivier 140e32b96b5SLaurent Vivier device = qobject_to(QDict, obj); 141e32b96b5SLaurent Vivier 142e32b96b5SLaurent Vivier if (qdict_haskey(device, "pci_bridge")) { 143e32b96b5SLaurent Vivier QDict *bridge; 144e32b96b5SLaurent Vivier QDict *bridge_device; 145e32b96b5SLaurent Vivier 146e32b96b5SLaurent Vivier bridge = qdict_get_qdict(device, "pci_bridge"); 147e32b96b5SLaurent Vivier 148e32b96b5SLaurent Vivier if (qdict_haskey(bridge, "devices")) { 149e32b96b5SLaurent Vivier bridge_device = find_device(bridge, name); 150e32b96b5SLaurent Vivier if (bridge_device) { 151e32b96b5SLaurent Vivier qobject_unref(device); 152e32b96b5SLaurent Vivier qobject_unref(list); 153e32b96b5SLaurent Vivier return bridge_device; 154e32b96b5SLaurent Vivier } 155e32b96b5SLaurent Vivier } 156e32b96b5SLaurent Vivier } 157e32b96b5SLaurent Vivier 158e32b96b5SLaurent Vivier if (!qdict_haskey(device, "qdev_id")) { 159e32b96b5SLaurent Vivier qobject_unref(device); 160e32b96b5SLaurent Vivier continue; 161e32b96b5SLaurent Vivier } 162e32b96b5SLaurent Vivier 163e32b96b5SLaurent Vivier if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) { 164e32b96b5SLaurent Vivier qobject_unref(list); 165e32b96b5SLaurent Vivier return device; 166e32b96b5SLaurent Vivier } 167e32b96b5SLaurent Vivier qobject_unref(device); 168e32b96b5SLaurent Vivier } 169e32b96b5SLaurent Vivier qobject_unref(list); 170e32b96b5SLaurent Vivier 171e32b96b5SLaurent Vivier return NULL; 172e32b96b5SLaurent Vivier } 173e32b96b5SLaurent Vivier 174e32b96b5SLaurent Vivier static QDict *get_bus(QTestState *qts, int num) 175e32b96b5SLaurent Vivier { 176e32b96b5SLaurent Vivier QObject *obj; 177e32b96b5SLaurent Vivier QDict *resp; 178e32b96b5SLaurent Vivier QList *ret; 179e32b96b5SLaurent Vivier 180e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }"); 181e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 182e32b96b5SLaurent Vivier 183e32b96b5SLaurent Vivier ret = qdict_get_qlist(resp, "return"); 184e32b96b5SLaurent Vivier g_assert_nonnull(ret); 185e32b96b5SLaurent Vivier 186e32b96b5SLaurent Vivier while ((obj = qlist_pop(ret))) { 187e32b96b5SLaurent Vivier QDict *bus; 188e32b96b5SLaurent Vivier 189e32b96b5SLaurent Vivier bus = qobject_to(QDict, obj); 190e32b96b5SLaurent Vivier if (!qdict_haskey(bus, "bus")) { 191e32b96b5SLaurent Vivier qobject_unref(bus); 192e32b96b5SLaurent Vivier continue; 193e32b96b5SLaurent Vivier } 194e32b96b5SLaurent Vivier if (qdict_get_int(bus, "bus") == num) { 195e32b96b5SLaurent Vivier qobject_unref(resp); 196e32b96b5SLaurent Vivier return bus; 197e32b96b5SLaurent Vivier } 198e32b96b5SLaurent Vivier qobject_ref(bus); 199e32b96b5SLaurent Vivier } 200e32b96b5SLaurent Vivier qobject_unref(resp); 201e32b96b5SLaurent Vivier 202e32b96b5SLaurent Vivier return NULL; 203e32b96b5SLaurent Vivier } 204e32b96b5SLaurent Vivier 205e32b96b5SLaurent Vivier static char *get_mac(QTestState *qts, const char *name) 206e32b96b5SLaurent Vivier { 207e32b96b5SLaurent Vivier QDict *resp; 208e32b96b5SLaurent Vivier char *mac; 209e32b96b5SLaurent Vivier 210e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'qom-get', " 211e32b96b5SLaurent Vivier "'arguments': { " 212e32b96b5SLaurent Vivier "'path': %s, " 213e32b96b5SLaurent Vivier "'property': 'mac' } }", name); 214e32b96b5SLaurent Vivier 215e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 216e32b96b5SLaurent Vivier 217e32b96b5SLaurent Vivier mac = g_strdup(qdict_get_str(resp, "return")); 218e32b96b5SLaurent Vivier 219e32b96b5SLaurent Vivier qobject_unref(resp); 220e32b96b5SLaurent Vivier 221e32b96b5SLaurent Vivier return mac; 222e32b96b5SLaurent Vivier } 223e32b96b5SLaurent Vivier 224e32b96b5SLaurent Vivier static void check_one_card(QTestState *qts, bool present, 225e32b96b5SLaurent Vivier const char *id, const char *mac) 226e32b96b5SLaurent Vivier { 227e32b96b5SLaurent Vivier QDict *device; 228e32b96b5SLaurent Vivier QDict *bus; 229e32b96b5SLaurent Vivier char *addr; 230e32b96b5SLaurent Vivier 231e32b96b5SLaurent Vivier bus = get_bus(qts, 0); 232e32b96b5SLaurent Vivier device = find_device(bus, id); 233e32b96b5SLaurent Vivier if (present) { 234e32b96b5SLaurent Vivier char *path; 235e32b96b5SLaurent Vivier 236e32b96b5SLaurent Vivier g_assert_nonnull(device); 237e32b96b5SLaurent Vivier qobject_unref(device); 238e32b96b5SLaurent Vivier 239e32b96b5SLaurent Vivier path = g_strdup_printf("/machine/peripheral/%s", id); 240e32b96b5SLaurent Vivier addr = get_mac(qts, path); 241e32b96b5SLaurent Vivier g_free(path); 242e32b96b5SLaurent Vivier g_assert_cmpstr(mac, ==, addr); 243e32b96b5SLaurent Vivier g_free(addr); 244e32b96b5SLaurent Vivier } else { 245e32b96b5SLaurent Vivier g_assert_null(device); 246e32b96b5SLaurent Vivier } 247e32b96b5SLaurent Vivier 248e32b96b5SLaurent Vivier qobject_unref(bus); 249e32b96b5SLaurent Vivier } 250e32b96b5SLaurent Vivier 251e32b96b5SLaurent Vivier static void test_on(void) 252e32b96b5SLaurent Vivier { 253e32b96b5SLaurent Vivier QTestState *qts; 254e32b96b5SLaurent Vivier 255e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 256e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 257e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0," 258e32b96b5SLaurent Vivier "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 259e32b96b5SLaurent Vivier "-device virtio-net,bus=root1,id=primary0," 260e32b96b5SLaurent Vivier "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0, 261e32b96b5SLaurent Vivier 2); 262e32b96b5SLaurent Vivier 263e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 264e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 265e32b96b5SLaurent Vivier 266e32b96b5SLaurent Vivier machine_stop(qts); 267e32b96b5SLaurent Vivier } 268e32b96b5SLaurent Vivier 269e32b96b5SLaurent Vivier static void test_on_mismatch(void) 270e32b96b5SLaurent Vivier { 271e32b96b5SLaurent Vivier QTestState *qts; 272e32b96b5SLaurent Vivier 273e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 274e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 275e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0," 276e32b96b5SLaurent Vivier "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 277e32b96b5SLaurent Vivier "-netdev user,id=hs1 " 278e32b96b5SLaurent Vivier "-device virtio-net,bus=root1,id=primary0," 279e32b96b5SLaurent Vivier "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0, 280e32b96b5SLaurent Vivier 2); 281e32b96b5SLaurent Vivier 282e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 283e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 284e32b96b5SLaurent Vivier 285e32b96b5SLaurent Vivier machine_stop(qts); 286e32b96b5SLaurent Vivier } 287e32b96b5SLaurent Vivier 288e32b96b5SLaurent Vivier static void test_off(void) 289e32b96b5SLaurent Vivier { 290e32b96b5SLaurent Vivier QTestState *qts; 291e32b96b5SLaurent Vivier 292e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 293e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 294e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0," 295e32b96b5SLaurent Vivier "failover=off,netdev=hs0,mac="MAC_STANDBY0" " 296e32b96b5SLaurent Vivier "-netdev user,id=hs1 " 297e32b96b5SLaurent Vivier "-device virtio-net,bus=root1,id=primary0," 298e32b96b5SLaurent Vivier "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0, 299e32b96b5SLaurent Vivier 2); 300e32b96b5SLaurent Vivier 301e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 302e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 303e32b96b5SLaurent Vivier 304e32b96b5SLaurent Vivier machine_stop(qts); 305e32b96b5SLaurent Vivier } 306e32b96b5SLaurent Vivier 307e32b96b5SLaurent Vivier static QDict *get_failover_negociated_event(QTestState *qts) 308e32b96b5SLaurent Vivier { 309e32b96b5SLaurent Vivier QDict *resp; 310e32b96b5SLaurent Vivier QDict *data; 311e32b96b5SLaurent Vivier 312e32b96b5SLaurent Vivier resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED"); 313e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "data")); 314e32b96b5SLaurent Vivier 315e32b96b5SLaurent Vivier data = qdict_get_qdict(resp, "data"); 316e32b96b5SLaurent Vivier g_assert(qdict_haskey(data, "device-id")); 317e32b96b5SLaurent Vivier qobject_ref(data); 318e32b96b5SLaurent Vivier qobject_unref(resp); 319e32b96b5SLaurent Vivier 320e32b96b5SLaurent Vivier return data; 321e32b96b5SLaurent Vivier } 322e32b96b5SLaurent Vivier 323e32b96b5SLaurent Vivier static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot, 324e32b96b5SLaurent Vivier const char *id) 325e32b96b5SLaurent Vivier { 326e32b96b5SLaurent Vivier QVirtioPCIDevice *dev; 327e32b96b5SLaurent Vivier uint64_t features; 328e32b96b5SLaurent Vivier QPCIAddress addr; 329e32b96b5SLaurent Vivier QDict *resp; 330e32b96b5SLaurent Vivier 331e32b96b5SLaurent Vivier addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0); 332e32b96b5SLaurent Vivier dev = virtio_pci_new(pcibus, &addr); 333e32b96b5SLaurent Vivier g_assert_nonnull(dev); 334e32b96b5SLaurent Vivier qvirtio_pci_device_enable(dev); 335e32b96b5SLaurent Vivier qvirtio_start_device(&dev->vdev); 336e32b96b5SLaurent Vivier features = qvirtio_get_features(&dev->vdev); 337e32b96b5SLaurent Vivier features = features & ~(QVIRTIO_F_BAD_FEATURE | 338e32b96b5SLaurent Vivier (1ull << VIRTIO_RING_F_INDIRECT_DESC) | 339e32b96b5SLaurent Vivier (1ull << VIRTIO_RING_F_EVENT_IDX)); 340e32b96b5SLaurent Vivier qvirtio_set_features(&dev->vdev, features); 341e32b96b5SLaurent Vivier qvirtio_set_driver_ok(&dev->vdev); 342e32b96b5SLaurent Vivier 343e32b96b5SLaurent Vivier resp = get_failover_negociated_event(qts); 344e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id); 345e32b96b5SLaurent Vivier qobject_unref(resp); 346e32b96b5SLaurent Vivier 347e32b96b5SLaurent Vivier return dev; 348e32b96b5SLaurent Vivier } 349e32b96b5SLaurent Vivier 350e32b96b5SLaurent Vivier static void test_enabled(void) 351e32b96b5SLaurent Vivier { 352e32b96b5SLaurent Vivier QTestState *qts; 353e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 354e32b96b5SLaurent Vivier 355e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 356e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 357e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0," 358e32b96b5SLaurent Vivier "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 359e32b96b5SLaurent Vivier "-netdev user,id=hs1 " 360e32b96b5SLaurent Vivier "-device virtio-net,bus=root1,id=primary0," 361e32b96b5SLaurent Vivier "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ", 362e32b96b5SLaurent Vivier 2); 363e32b96b5SLaurent Vivier 364e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 365e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 366e32b96b5SLaurent Vivier 367e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 368e32b96b5SLaurent Vivier 369e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 370e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 371e32b96b5SLaurent Vivier 372e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 373e32b96b5SLaurent Vivier machine_stop(qts); 374e32b96b5SLaurent Vivier } 375e32b96b5SLaurent Vivier 376e32b96b5SLaurent Vivier static void test_hotplug_1(void) 377e32b96b5SLaurent Vivier { 378e32b96b5SLaurent Vivier QTestState *qts; 379e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 380e32b96b5SLaurent Vivier 381e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 382e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 383e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0," 384e32b96b5SLaurent Vivier "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 385e32b96b5SLaurent Vivier "-netdev user,id=hs1 ", 2); 386e32b96b5SLaurent Vivier 387e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 388e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 389e32b96b5SLaurent Vivier 390e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 391e32b96b5SLaurent Vivier 392e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 393e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 394e32b96b5SLaurent Vivier 395e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 396e32b96b5SLaurent Vivier "{'bus': 'root1'," 397e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'," 398e32b96b5SLaurent Vivier "'netdev': 'hs1'," 399e32b96b5SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 400e32b96b5SLaurent Vivier 401e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 402e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 403e32b96b5SLaurent Vivier 404e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 405e32b96b5SLaurent Vivier machine_stop(qts); 406e32b96b5SLaurent Vivier } 407e32b96b5SLaurent Vivier 408e32b96b5SLaurent Vivier static void test_hotplug_1_reverse(void) 409e32b96b5SLaurent Vivier { 410e32b96b5SLaurent Vivier QTestState *qts; 411e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 412e32b96b5SLaurent Vivier 413e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 414e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 415e32b96b5SLaurent Vivier "-netdev user,id=hs1 " 416e32b96b5SLaurent Vivier "-device virtio-net,bus=root1,id=primary0," 417e32b96b5SLaurent Vivier "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ", 418e32b96b5SLaurent Vivier 2); 419e32b96b5SLaurent Vivier 420e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 421e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 422e32b96b5SLaurent Vivier 423e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 424e32b96b5SLaurent Vivier "{'bus': 'root0'," 425e32b96b5SLaurent Vivier "'failover': 'on'," 426e32b96b5SLaurent Vivier "'netdev': 'hs0'," 427e32b96b5SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 428e32b96b5SLaurent Vivier 429e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 430e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 431e32b96b5SLaurent Vivier 432e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 433e32b96b5SLaurent Vivier 434e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 435e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 436e32b96b5SLaurent Vivier 437e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 438e32b96b5SLaurent Vivier machine_stop(qts); 439e32b96b5SLaurent Vivier } 440e32b96b5SLaurent Vivier 441e32b96b5SLaurent Vivier static void test_hotplug_2(void) 442e32b96b5SLaurent Vivier { 443e32b96b5SLaurent Vivier QTestState *qts; 444e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 445e32b96b5SLaurent Vivier 446e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 447e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 448e32b96b5SLaurent Vivier "-netdev user,id=hs1 ", 449e32b96b5SLaurent Vivier 2); 450e32b96b5SLaurent Vivier 451e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 452e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 453e32b96b5SLaurent Vivier 454e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 455e32b96b5SLaurent Vivier "{'bus': 'root0'," 456e32b96b5SLaurent Vivier "'failover': 'on'," 457e32b96b5SLaurent Vivier "'netdev': 'hs0'," 458e32b96b5SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 459e32b96b5SLaurent Vivier 460e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 461e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 462e32b96b5SLaurent Vivier 463e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 464e32b96b5SLaurent Vivier 465e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 466e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 467e32b96b5SLaurent Vivier 468e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 469e32b96b5SLaurent Vivier "{'bus': 'root1'," 470e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'," 471e32b96b5SLaurent Vivier "'netdev': 'hs1'," 472e32b96b5SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 473e32b96b5SLaurent Vivier 474e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 475e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 476e32b96b5SLaurent Vivier 477e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 478e32b96b5SLaurent Vivier machine_stop(qts); 479e32b96b5SLaurent Vivier } 480e32b96b5SLaurent Vivier 481e32b96b5SLaurent Vivier static void test_hotplug_2_reverse(void) 482e32b96b5SLaurent Vivier { 483e32b96b5SLaurent Vivier QTestState *qts; 484e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 485e32b96b5SLaurent Vivier 486e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 487e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 488e32b96b5SLaurent Vivier "-netdev user,id=hs1 ", 489e32b96b5SLaurent Vivier 2); 490e32b96b5SLaurent Vivier 491e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 492e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 493e32b96b5SLaurent Vivier 494e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 495e32b96b5SLaurent Vivier "{'bus': 'root1'," 496e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'," 497e32b96b5SLaurent Vivier "'netdev': 'hs1'," 498e32b96b5SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 499e32b96b5SLaurent Vivier 500e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 501e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 502e32b96b5SLaurent Vivier 503e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 504e32b96b5SLaurent Vivier "{'bus': 'root0'," 505e32b96b5SLaurent Vivier "'failover': 'on'," 506e32b96b5SLaurent Vivier "'netdev': 'hs0'," 507e32b96b5SLaurent Vivier "'rombar': 0," 508e32b96b5SLaurent Vivier "'romfile': ''," 509e32b96b5SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 510e32b96b5SLaurent Vivier 511e32b96b5SLaurent Vivier /* 512e32b96b5SLaurent Vivier * XXX: sounds like a bug: 513e32b96b5SLaurent Vivier * The primary should be hidden until the virtio-net driver 514e32b96b5SLaurent Vivier * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net() 515e32b96b5SLaurent Vivier */ 516e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 517e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 518e32b96b5SLaurent Vivier 519e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 520e32b96b5SLaurent Vivier 521e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 522e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 523e32b96b5SLaurent Vivier 524e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 525e32b96b5SLaurent Vivier machine_stop(qts); 526e32b96b5SLaurent Vivier } 527e32b96b5SLaurent Vivier 528e32b96b5SLaurent Vivier static QDict *migrate_status(QTestState *qts) 529e32b96b5SLaurent Vivier { 530e32b96b5SLaurent Vivier QDict *resp, *ret; 531e32b96b5SLaurent Vivier 532e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }"); 533e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 534e32b96b5SLaurent Vivier 535e32b96b5SLaurent Vivier ret = qdict_get_qdict(resp, "return"); 536e32b96b5SLaurent Vivier g_assert(qdict_haskey(ret, "status")); 537e32b96b5SLaurent Vivier qobject_ref(ret); 538e32b96b5SLaurent Vivier qobject_unref(resp); 539e32b96b5SLaurent Vivier 540e32b96b5SLaurent Vivier return ret; 541e32b96b5SLaurent Vivier } 542e32b96b5SLaurent Vivier 543e32b96b5SLaurent Vivier static QDict *get_unplug_primary_event(QTestState *qts) 544e32b96b5SLaurent Vivier { 545e32b96b5SLaurent Vivier QDict *resp; 546e32b96b5SLaurent Vivier QDict *data; 547e32b96b5SLaurent Vivier 548e32b96b5SLaurent Vivier resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY"); 549e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "data")); 550e32b96b5SLaurent Vivier 551e32b96b5SLaurent Vivier data = qdict_get_qdict(resp, "data"); 552e32b96b5SLaurent Vivier g_assert(qdict_haskey(data, "device-id")); 553e32b96b5SLaurent Vivier qobject_ref(data); 554e32b96b5SLaurent Vivier qobject_unref(resp); 555e32b96b5SLaurent Vivier 556e32b96b5SLaurent Vivier return data; 557e32b96b5SLaurent Vivier } 558e32b96b5SLaurent Vivier 559e32b96b5SLaurent Vivier static void test_migrate_out(gconstpointer opaque) 560e32b96b5SLaurent Vivier { 561e32b96b5SLaurent Vivier QTestState *qts; 562e32b96b5SLaurent Vivier QDict *resp, *args, *ret; 563e32b96b5SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 564e32b96b5SLaurent Vivier const gchar *status; 565e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 566e32b96b5SLaurent Vivier 567e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 568e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 569e32b96b5SLaurent Vivier "-netdev user,id=hs1 ", 570e32b96b5SLaurent Vivier 2); 571e32b96b5SLaurent Vivier 572e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 573e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 574e32b96b5SLaurent Vivier 575e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 576e32b96b5SLaurent Vivier "{'bus': 'root0'," 577e32b96b5SLaurent Vivier "'failover': 'on'," 578e32b96b5SLaurent Vivier "'netdev': 'hs0'," 579e32b96b5SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 580e32b96b5SLaurent Vivier 581e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 582e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 583e32b96b5SLaurent Vivier 584e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 585e32b96b5SLaurent Vivier 586e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 587e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 588e32b96b5SLaurent Vivier 589e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 590e32b96b5SLaurent Vivier "{'bus': 'root1'," 591e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'," 592e32b96b5SLaurent Vivier "'netdev': 'hs1'," 593e32b96b5SLaurent Vivier "'rombar': 0," 594e32b96b5SLaurent Vivier "'romfile': ''," 595e32b96b5SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 596e32b96b5SLaurent Vivier 597e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 598e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 599e32b96b5SLaurent Vivier 600e32b96b5SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 601e32b96b5SLaurent Vivier g_assert_nonnull(args); 602e32b96b5SLaurent Vivier qdict_put_str(args, "uri", uri); 603e32b96b5SLaurent Vivier 604e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 605e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 606e32b96b5SLaurent Vivier qobject_unref(resp); 607e32b96b5SLaurent Vivier 608e32b96b5SLaurent Vivier /* the event is sent when QEMU asks the OS to unplug the card */ 609e32b96b5SLaurent Vivier resp = get_unplug_primary_event(qts); 610e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 611e32b96b5SLaurent Vivier qobject_unref(resp); 612e32b96b5SLaurent Vivier 613e32b96b5SLaurent Vivier /* wait the end of the migration setup phase */ 614e32b96b5SLaurent Vivier while (true) { 615e32b96b5SLaurent Vivier ret = migrate_status(qts); 616e32b96b5SLaurent Vivier 617e32b96b5SLaurent Vivier status = qdict_get_str(ret, "status"); 618e32b96b5SLaurent Vivier if (strcmp(status, "wait-unplug") == 0) { 619e32b96b5SLaurent Vivier qobject_unref(ret); 620e32b96b5SLaurent Vivier break; 621e32b96b5SLaurent Vivier } 622e32b96b5SLaurent Vivier 623e32b96b5SLaurent Vivier /* The migration must not start if the card is not ejected */ 624e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "active"); 625e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "completed"); 626e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 627e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "cancelling"); 628e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "cancelled"); 629e32b96b5SLaurent Vivier 630e32b96b5SLaurent Vivier qobject_unref(ret); 631e32b96b5SLaurent Vivier } 632e32b96b5SLaurent Vivier 633e32b96b5SLaurent Vivier if (g_test_slow()) { 634e32b96b5SLaurent Vivier /* check we stay in wait-unplug while the card is not ejected */ 635e32b96b5SLaurent Vivier for (int i = 0; i < 5; i++) { 636e32b96b5SLaurent Vivier sleep(1); 637e32b96b5SLaurent Vivier ret = migrate_status(qts); 638e32b96b5SLaurent Vivier status = qdict_get_str(ret, "status"); 639e32b96b5SLaurent Vivier g_assert_cmpstr(status, ==, "wait-unplug"); 640e32b96b5SLaurent Vivier qobject_unref(ret); 641e32b96b5SLaurent Vivier } 642e32b96b5SLaurent Vivier } 643e32b96b5SLaurent Vivier 644e32b96b5SLaurent Vivier /* OS unplugs the cards, QEMU can move from wait-unplug state */ 645e32b96b5SLaurent Vivier qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 646e32b96b5SLaurent Vivier 647e32b96b5SLaurent Vivier while (true) { 648e32b96b5SLaurent Vivier ret = migrate_status(qts); 649e32b96b5SLaurent Vivier 650e32b96b5SLaurent Vivier status = qdict_get_str(ret, "status"); 651e32b96b5SLaurent Vivier if (strcmp(status, "completed") == 0) { 652e32b96b5SLaurent Vivier qobject_unref(ret); 653e32b96b5SLaurent Vivier break; 654e32b96b5SLaurent Vivier } 655e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 656e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "cancelling"); 657e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "cancelled"); 658e32b96b5SLaurent Vivier qobject_unref(ret); 659e32b96b5SLaurent Vivier } 660e32b96b5SLaurent Vivier 661e32b96b5SLaurent Vivier qtest_qmp_eventwait(qts, "STOP"); 662e32b96b5SLaurent Vivier 663e32b96b5SLaurent Vivier /* 664e32b96b5SLaurent Vivier * in fact, the card is ejected from the point of view of kernel 665e32b96b5SLaurent Vivier * but not really from QEMU to be able to hotplug it back if 666e32b96b5SLaurent Vivier * migration fails. So we can't check that: 667e32b96b5SLaurent Vivier * check_one_card(qts, true, "standby0", MAC_STANDBY0); 668e32b96b5SLaurent Vivier * check_one_card(qts, false, "primary0", MAC_PRIMARY0); 669e32b96b5SLaurent Vivier */ 670e32b96b5SLaurent Vivier 671e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 672e32b96b5SLaurent Vivier machine_stop(qts); 673e32b96b5SLaurent Vivier } 674e32b96b5SLaurent Vivier 675e32b96b5SLaurent Vivier static QDict *get_migration_event(QTestState *qts) 676e32b96b5SLaurent Vivier { 677e32b96b5SLaurent Vivier QDict *resp; 678e32b96b5SLaurent Vivier QDict *data; 679e32b96b5SLaurent Vivier 680e32b96b5SLaurent Vivier resp = qtest_qmp_eventwait_ref(qts, "MIGRATION"); 681e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "data")); 682e32b96b5SLaurent Vivier 683e32b96b5SLaurent Vivier data = qdict_get_qdict(resp, "data"); 684e32b96b5SLaurent Vivier g_assert(qdict_haskey(data, "status")); 685e32b96b5SLaurent Vivier qobject_ref(data); 686e32b96b5SLaurent Vivier qobject_unref(resp); 687e32b96b5SLaurent Vivier 688e32b96b5SLaurent Vivier return data; 689e32b96b5SLaurent Vivier } 690e32b96b5SLaurent Vivier 691e32b96b5SLaurent Vivier static void test_migrate_in(gconstpointer opaque) 692e32b96b5SLaurent Vivier { 693e32b96b5SLaurent Vivier QTestState *qts; 694e32b96b5SLaurent Vivier QDict *resp, *args, *ret; 695e32b96b5SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); 696e32b96b5SLaurent Vivier 697e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 698e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 699e32b96b5SLaurent Vivier "-netdev user,id=hs1 " 700e32b96b5SLaurent Vivier "-incoming defer ", 701e32b96b5SLaurent Vivier 2); 702e32b96b5SLaurent Vivier 703e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 704e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 705e32b96b5SLaurent Vivier 706e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 707e32b96b5SLaurent Vivier "{'bus': 'root0'," 708e32b96b5SLaurent Vivier "'failover': 'on'," 709e32b96b5SLaurent Vivier "'netdev': 'hs0'," 710e32b96b5SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 711e32b96b5SLaurent Vivier 712e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 713e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 714e32b96b5SLaurent Vivier 715e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 716e32b96b5SLaurent Vivier "{'bus': 'root1'," 717e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'," 718e32b96b5SLaurent Vivier "'netdev': 'hs1'," 719e32b96b5SLaurent Vivier "'rombar': 0," 720e32b96b5SLaurent Vivier "'romfile': ''," 721e32b96b5SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 722e32b96b5SLaurent Vivier 723e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 724e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 725e32b96b5SLaurent Vivier 726e32b96b5SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 727e32b96b5SLaurent Vivier g_assert_nonnull(args); 728e32b96b5SLaurent Vivier qdict_put_str(args, "uri", uri); 729e32b96b5SLaurent Vivier 730e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", 731e32b96b5SLaurent Vivier args); 732e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 733e32b96b5SLaurent Vivier qobject_unref(resp); 734e32b96b5SLaurent Vivier 735e32b96b5SLaurent Vivier resp = get_migration_event(qts); 736e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); 737e32b96b5SLaurent Vivier qobject_unref(resp); 738e32b96b5SLaurent Vivier 739e32b96b5SLaurent Vivier resp = get_failover_negociated_event(qts); 740e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0"); 741e32b96b5SLaurent Vivier qobject_unref(resp); 742e32b96b5SLaurent Vivier 743e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 744e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 745e32b96b5SLaurent Vivier 746e32b96b5SLaurent Vivier qtest_qmp_eventwait(qts, "RESUME"); 747e32b96b5SLaurent Vivier 748e32b96b5SLaurent Vivier ret = migrate_status(qts); 749e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed"); 750e32b96b5SLaurent Vivier qobject_unref(ret); 751e32b96b5SLaurent Vivier 752e32b96b5SLaurent Vivier machine_stop(qts); 753e32b96b5SLaurent Vivier } 754e32b96b5SLaurent Vivier 755*1e2077e2SLaurent Vivier static void test_migrate_abort_wait_unplug(gconstpointer opaque) 756*1e2077e2SLaurent Vivier { 757*1e2077e2SLaurent Vivier QTestState *qts; 758*1e2077e2SLaurent Vivier QDict *resp, *args, *ret; 759*1e2077e2SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 760*1e2077e2SLaurent Vivier const gchar *status; 761*1e2077e2SLaurent Vivier QVirtioPCIDevice *vdev; 762*1e2077e2SLaurent Vivier 763*1e2077e2SLaurent Vivier qts = machine_start(BASE_MACHINE 764*1e2077e2SLaurent Vivier "-netdev user,id=hs0 " 765*1e2077e2SLaurent Vivier "-netdev user,id=hs1 ", 766*1e2077e2SLaurent Vivier 2); 767*1e2077e2SLaurent Vivier 768*1e2077e2SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 769*1e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 770*1e2077e2SLaurent Vivier 771*1e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 772*1e2077e2SLaurent Vivier "{'bus': 'root0'," 773*1e2077e2SLaurent Vivier "'failover': 'on'," 774*1e2077e2SLaurent Vivier "'netdev': 'hs0'," 775*1e2077e2SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 776*1e2077e2SLaurent Vivier 777*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 778*1e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 779*1e2077e2SLaurent Vivier 780*1e2077e2SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 781*1e2077e2SLaurent Vivier 782*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 783*1e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 784*1e2077e2SLaurent Vivier 785*1e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 786*1e2077e2SLaurent Vivier "{'bus': 'root1'," 787*1e2077e2SLaurent Vivier "'failover_pair_id': 'standby0'," 788*1e2077e2SLaurent Vivier "'netdev': 'hs1'," 789*1e2077e2SLaurent Vivier "'rombar': 0," 790*1e2077e2SLaurent Vivier "'romfile': ''," 791*1e2077e2SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 792*1e2077e2SLaurent Vivier 793*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 794*1e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 795*1e2077e2SLaurent Vivier 796*1e2077e2SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 797*1e2077e2SLaurent Vivier g_assert_nonnull(args); 798*1e2077e2SLaurent Vivier qdict_put_str(args, "uri", uri); 799*1e2077e2SLaurent Vivier 800*1e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 801*1e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 802*1e2077e2SLaurent Vivier qobject_unref(resp); 803*1e2077e2SLaurent Vivier 804*1e2077e2SLaurent Vivier /* the event is sent when QEMU asks the OS to unplug the card */ 805*1e2077e2SLaurent Vivier resp = get_unplug_primary_event(qts); 806*1e2077e2SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 807*1e2077e2SLaurent Vivier qobject_unref(resp); 808*1e2077e2SLaurent Vivier 809*1e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); 810*1e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 811*1e2077e2SLaurent Vivier qobject_unref(resp); 812*1e2077e2SLaurent Vivier 813*1e2077e2SLaurent Vivier /* migration has been cancelled while the unplug was in progress */ 814*1e2077e2SLaurent Vivier 815*1e2077e2SLaurent Vivier /* while the card is not ejected, we must be in "cancelling" state */ 816*1e2077e2SLaurent Vivier ret = migrate_status(qts); 817*1e2077e2SLaurent Vivier 818*1e2077e2SLaurent Vivier status = qdict_get_str(ret, "status"); 819*1e2077e2SLaurent Vivier g_assert_cmpstr(status, ==, "cancelling"); 820*1e2077e2SLaurent Vivier qobject_unref(ret); 821*1e2077e2SLaurent Vivier 822*1e2077e2SLaurent Vivier /* OS unplugs the cards, QEMU can move from wait-unplug state */ 823*1e2077e2SLaurent Vivier qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 824*1e2077e2SLaurent Vivier 825*1e2077e2SLaurent Vivier while (true) { 826*1e2077e2SLaurent Vivier ret = migrate_status(qts); 827*1e2077e2SLaurent Vivier 828*1e2077e2SLaurent Vivier status = qdict_get_str(ret, "status"); 829*1e2077e2SLaurent Vivier if (strcmp(status, "cancelled") == 0) { 830*1e2077e2SLaurent Vivier qobject_unref(ret); 831*1e2077e2SLaurent Vivier break; 832*1e2077e2SLaurent Vivier } 833*1e2077e2SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 834*1e2077e2SLaurent Vivier g_assert_cmpstr(status, !=, "active"); 835*1e2077e2SLaurent Vivier qobject_unref(ret); 836*1e2077e2SLaurent Vivier } 837*1e2077e2SLaurent Vivier 838*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 839*1e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 840*1e2077e2SLaurent Vivier 841*1e2077e2SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 842*1e2077e2SLaurent Vivier machine_stop(qts); 843*1e2077e2SLaurent Vivier } 844*1e2077e2SLaurent Vivier 845*1e2077e2SLaurent Vivier static void test_migrate_abort_active(gconstpointer opaque) 846*1e2077e2SLaurent Vivier { 847*1e2077e2SLaurent Vivier QTestState *qts; 848*1e2077e2SLaurent Vivier QDict *resp, *args, *ret; 849*1e2077e2SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 850*1e2077e2SLaurent Vivier const gchar *status; 851*1e2077e2SLaurent Vivier QVirtioPCIDevice *vdev; 852*1e2077e2SLaurent Vivier 853*1e2077e2SLaurent Vivier qts = machine_start(BASE_MACHINE 854*1e2077e2SLaurent Vivier "-netdev user,id=hs0 " 855*1e2077e2SLaurent Vivier "-netdev user,id=hs1 ", 856*1e2077e2SLaurent Vivier 2); 857*1e2077e2SLaurent Vivier 858*1e2077e2SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 859*1e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 860*1e2077e2SLaurent Vivier 861*1e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 862*1e2077e2SLaurent Vivier "{'bus': 'root0'," 863*1e2077e2SLaurent Vivier "'failover': 'on'," 864*1e2077e2SLaurent Vivier "'netdev': 'hs0'," 865*1e2077e2SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 866*1e2077e2SLaurent Vivier 867*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 868*1e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 869*1e2077e2SLaurent Vivier 870*1e2077e2SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 871*1e2077e2SLaurent Vivier 872*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 873*1e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 874*1e2077e2SLaurent Vivier 875*1e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 876*1e2077e2SLaurent Vivier "{'bus': 'root1'," 877*1e2077e2SLaurent Vivier "'failover_pair_id': 'standby0'," 878*1e2077e2SLaurent Vivier "'netdev': 'hs1'," 879*1e2077e2SLaurent Vivier "'rombar': 0," 880*1e2077e2SLaurent Vivier "'romfile': ''," 881*1e2077e2SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 882*1e2077e2SLaurent Vivier 883*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 884*1e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 885*1e2077e2SLaurent Vivier 886*1e2077e2SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 887*1e2077e2SLaurent Vivier g_assert_nonnull(args); 888*1e2077e2SLaurent Vivier qdict_put_str(args, "uri", uri); 889*1e2077e2SLaurent Vivier 890*1e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 891*1e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 892*1e2077e2SLaurent Vivier qobject_unref(resp); 893*1e2077e2SLaurent Vivier 894*1e2077e2SLaurent Vivier /* the event is sent when QEMU asks the OS to unplug the card */ 895*1e2077e2SLaurent Vivier resp = get_unplug_primary_event(qts); 896*1e2077e2SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 897*1e2077e2SLaurent Vivier qobject_unref(resp); 898*1e2077e2SLaurent Vivier 899*1e2077e2SLaurent Vivier /* OS unplugs the cards, QEMU can move from wait-unplug state */ 900*1e2077e2SLaurent Vivier qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 901*1e2077e2SLaurent Vivier 902*1e2077e2SLaurent Vivier while (true) { 903*1e2077e2SLaurent Vivier ret = migrate_status(qts); 904*1e2077e2SLaurent Vivier 905*1e2077e2SLaurent Vivier status = qdict_get_str(ret, "status"); 906*1e2077e2SLaurent Vivier if (strcmp(status, "wait-unplug") != 0) { 907*1e2077e2SLaurent Vivier qobject_unref(ret); 908*1e2077e2SLaurent Vivier break; 909*1e2077e2SLaurent Vivier } 910*1e2077e2SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 911*1e2077e2SLaurent Vivier qobject_unref(ret); 912*1e2077e2SLaurent Vivier } 913*1e2077e2SLaurent Vivier 914*1e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); 915*1e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 916*1e2077e2SLaurent Vivier qobject_unref(resp); 917*1e2077e2SLaurent Vivier 918*1e2077e2SLaurent Vivier while (true) { 919*1e2077e2SLaurent Vivier ret = migrate_status(qts); 920*1e2077e2SLaurent Vivier 921*1e2077e2SLaurent Vivier status = qdict_get_str(ret, "status"); 922*1e2077e2SLaurent Vivier if (strcmp(status, "cancelled") == 0) { 923*1e2077e2SLaurent Vivier qobject_unref(ret); 924*1e2077e2SLaurent Vivier break; 925*1e2077e2SLaurent Vivier } 926*1e2077e2SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 927*1e2077e2SLaurent Vivier g_assert_cmpstr(status, !=, "active"); 928*1e2077e2SLaurent Vivier qobject_unref(ret); 929*1e2077e2SLaurent Vivier } 930*1e2077e2SLaurent Vivier 931*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 932*1e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 933*1e2077e2SLaurent Vivier 934*1e2077e2SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 935*1e2077e2SLaurent Vivier machine_stop(qts); 936*1e2077e2SLaurent Vivier } 937*1e2077e2SLaurent Vivier 938*1e2077e2SLaurent Vivier static void test_migrate_abort_timeout(gconstpointer opaque) 939*1e2077e2SLaurent Vivier { 940*1e2077e2SLaurent Vivier QTestState *qts; 941*1e2077e2SLaurent Vivier QDict *resp, *args, *ret; 942*1e2077e2SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 943*1e2077e2SLaurent Vivier const gchar *status; 944*1e2077e2SLaurent Vivier int total; 945*1e2077e2SLaurent Vivier QVirtioPCIDevice *vdev; 946*1e2077e2SLaurent Vivier 947*1e2077e2SLaurent Vivier qts = machine_start(BASE_MACHINE 948*1e2077e2SLaurent Vivier "-netdev user,id=hs0 " 949*1e2077e2SLaurent Vivier "-netdev user,id=hs1 ", 950*1e2077e2SLaurent Vivier 2); 951*1e2077e2SLaurent Vivier 952*1e2077e2SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 953*1e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 954*1e2077e2SLaurent Vivier 955*1e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 956*1e2077e2SLaurent Vivier "{'bus': 'root0'," 957*1e2077e2SLaurent Vivier "'failover': 'on'," 958*1e2077e2SLaurent Vivier "'netdev': 'hs0'," 959*1e2077e2SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 960*1e2077e2SLaurent Vivier 961*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 962*1e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 963*1e2077e2SLaurent Vivier 964*1e2077e2SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 965*1e2077e2SLaurent Vivier 966*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 967*1e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 968*1e2077e2SLaurent Vivier 969*1e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 970*1e2077e2SLaurent Vivier "{'bus': 'root1'," 971*1e2077e2SLaurent Vivier "'failover_pair_id': 'standby0'," 972*1e2077e2SLaurent Vivier "'netdev': 'hs1'," 973*1e2077e2SLaurent Vivier "'rombar': 0," 974*1e2077e2SLaurent Vivier "'romfile': ''," 975*1e2077e2SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 976*1e2077e2SLaurent Vivier 977*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 978*1e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 979*1e2077e2SLaurent Vivier 980*1e2077e2SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 981*1e2077e2SLaurent Vivier g_assert_nonnull(args); 982*1e2077e2SLaurent Vivier qdict_put_str(args, "uri", uri); 983*1e2077e2SLaurent Vivier 984*1e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 985*1e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 986*1e2077e2SLaurent Vivier qobject_unref(resp); 987*1e2077e2SLaurent Vivier 988*1e2077e2SLaurent Vivier /* the event is sent when QEMU asks the OS to unplug the card */ 989*1e2077e2SLaurent Vivier resp = get_unplug_primary_event(qts); 990*1e2077e2SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 991*1e2077e2SLaurent Vivier qobject_unref(resp); 992*1e2077e2SLaurent Vivier 993*1e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); 994*1e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 995*1e2077e2SLaurent Vivier qobject_unref(resp); 996*1e2077e2SLaurent Vivier 997*1e2077e2SLaurent Vivier /* migration has been cancelled while the unplug was in progress */ 998*1e2077e2SLaurent Vivier 999*1e2077e2SLaurent Vivier /* while the card is not ejected, we must be in "cancelling" state */ 1000*1e2077e2SLaurent Vivier 1001*1e2077e2SLaurent Vivier total = 0; 1002*1e2077e2SLaurent Vivier while (true) { 1003*1e2077e2SLaurent Vivier ret = migrate_status(qts); 1004*1e2077e2SLaurent Vivier 1005*1e2077e2SLaurent Vivier status = qdict_get_str(ret, "status"); 1006*1e2077e2SLaurent Vivier if (strcmp(status, "cancelled") == 0) { 1007*1e2077e2SLaurent Vivier qobject_unref(ret); 1008*1e2077e2SLaurent Vivier break; 1009*1e2077e2SLaurent Vivier } 1010*1e2077e2SLaurent Vivier g_assert_cmpstr(status, ==, "cancelling"); 1011*1e2077e2SLaurent Vivier g_assert(qdict_haskey(ret, "total-time")); 1012*1e2077e2SLaurent Vivier total = qdict_get_int(ret, "total-time"); 1013*1e2077e2SLaurent Vivier qobject_unref(ret); 1014*1e2077e2SLaurent Vivier } 1015*1e2077e2SLaurent Vivier 1016*1e2077e2SLaurent Vivier /* 1017*1e2077e2SLaurent Vivier * migration timeout in this case is 30 seconds 1018*1e2077e2SLaurent Vivier * check we exit on the timeout (ms) 1019*1e2077e2SLaurent Vivier */ 1020*1e2077e2SLaurent Vivier g_assert_cmpint(total, >, 30000); 1021*1e2077e2SLaurent Vivier 1022*1e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1023*1e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1024*1e2077e2SLaurent Vivier 1025*1e2077e2SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 1026*1e2077e2SLaurent Vivier machine_stop(qts); 1027*1e2077e2SLaurent Vivier } 1028*1e2077e2SLaurent Vivier 1029e32b96b5SLaurent Vivier int main(int argc, char **argv) 1030e32b96b5SLaurent Vivier { 1031e32b96b5SLaurent Vivier const gchar *tmpdir = g_get_tmp_dir(); 1032e32b96b5SLaurent Vivier gchar *tmpfile = g_strdup_printf("%s/failover_test_migrate-%u-%u", 1033e32b96b5SLaurent Vivier tmpdir, getpid(), g_test_rand_int()); 1034e32b96b5SLaurent Vivier int ret; 1035e32b96b5SLaurent Vivier 1036e32b96b5SLaurent Vivier g_test_init(&argc, &argv, NULL); 1037e32b96b5SLaurent Vivier 1038e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/error/id", test_error_id); 1039e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie); 1040e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/on", test_on); 1041e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/on_mismatch", 1042e32b96b5SLaurent Vivier test_on_mismatch); 1043e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/off", test_off); 1044e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/enabled", test_enabled); 1045e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/hotplug_1", test_hotplug_1); 1046e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/hotplug_1_reverse", 1047e32b96b5SLaurent Vivier test_hotplug_1_reverse); 1048e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/hotplug_2", test_hotplug_2); 1049e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/hotplug_2_reverse", 1050e32b96b5SLaurent Vivier test_hotplug_2_reverse); 1051e32b96b5SLaurent Vivier qtest_add_data_func("failover-virtio-net/migrate/out", tmpfile, 1052e32b96b5SLaurent Vivier test_migrate_out); 1053e32b96b5SLaurent Vivier qtest_add_data_func("failover-virtio-net/migrate/in", tmpfile, 1054e32b96b5SLaurent Vivier test_migrate_in); 1055*1e2077e2SLaurent Vivier qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug", 1056*1e2077e2SLaurent Vivier tmpfile, test_migrate_abort_wait_unplug); 1057*1e2077e2SLaurent Vivier qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile, 1058*1e2077e2SLaurent Vivier test_migrate_abort_active); 1059*1e2077e2SLaurent Vivier if (g_test_slow()) { 1060*1e2077e2SLaurent Vivier qtest_add_data_func("failover-virtio-net/migrate/abort/timeout", 1061*1e2077e2SLaurent Vivier tmpfile, test_migrate_abort_timeout); 1062*1e2077e2SLaurent Vivier } 1063e32b96b5SLaurent Vivier 1064e32b96b5SLaurent Vivier ret = g_test_run(); 1065e32b96b5SLaurent Vivier 1066e32b96b5SLaurent Vivier unlink(tmpfile); 1067e32b96b5SLaurent Vivier g_free(tmpfile); 1068e32b96b5SLaurent Vivier 1069e32b96b5SLaurent Vivier return ret; 1070e32b96b5SLaurent Vivier } 1071