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