1e32b96b5SLaurent Vivier /* 2e32b96b5SLaurent Vivier * QTest testcase for virtio-net failover 3e32b96b5SLaurent Vivier * 4e32b96b5SLaurent Vivier * See docs/system/virtio-net-failover.rst 5e32b96b5SLaurent Vivier * 6e32b96b5SLaurent Vivier * Copyright (c) 2021 Red Hat, Inc. 7e32b96b5SLaurent Vivier * 8e32b96b5SLaurent Vivier * SPDX-License-Identifier: GPL-2.0-or-later 9e32b96b5SLaurent Vivier */ 10e32b96b5SLaurent Vivier #include "qemu/osdep.h" 11e32b96b5SLaurent Vivier #include "libqos/libqtest.h" 12e32b96b5SLaurent Vivier #include "libqos/pci.h" 13e32b96b5SLaurent Vivier #include "libqos/pci-pc.h" 14e32b96b5SLaurent Vivier #include "qapi/qmp/qdict.h" 15e32b96b5SLaurent Vivier #include "qapi/qmp/qlist.h" 16e32b96b5SLaurent Vivier #include "qapi/qmp/qjson.h" 17e32b96b5SLaurent Vivier #include "libqos/malloc-pc.h" 18e32b96b5SLaurent Vivier #include "libqos/virtio-pci.h" 19e32b96b5SLaurent Vivier #include "hw/pci/pci.h" 20e32b96b5SLaurent Vivier 21e32b96b5SLaurent Vivier #define ACPI_PCIHP_ADDR_ICH9 0x0cc0 22e32b96b5SLaurent Vivier #define PCI_EJ_BASE 0x0008 23e1e3d321SLaurent Vivier #define PCI_SEL_BASE 0x0010 24e32b96b5SLaurent Vivier 25e32b96b5SLaurent Vivier #define BASE_MACHINE "-M q35 -nodefaults " \ 26e32b96b5SLaurent Vivier "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \ 27e32b96b5SLaurent Vivier "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 " 28e32b96b5SLaurent Vivier 29e32b96b5SLaurent Vivier #define MAC_PRIMARY0 "52:54:00:11:11:11" 30e32b96b5SLaurent Vivier #define MAC_STANDBY0 "52:54:00:22:22:22" 31e1e3d321SLaurent Vivier #define MAC_PRIMARY1 "52:54:00:33:33:33" 32e1e3d321SLaurent Vivier #define MAC_STANDBY1 "52:54:00:44:44:44" 33e32b96b5SLaurent Vivier 34e32b96b5SLaurent Vivier static QGuestAllocator guest_malloc; 35e32b96b5SLaurent Vivier static QPCIBus *pcibus; 36e32b96b5SLaurent Vivier 37e32b96b5SLaurent Vivier static QTestState *machine_start(const char *args, int numbus) 38e32b96b5SLaurent Vivier { 39e32b96b5SLaurent Vivier QTestState *qts; 40e32b96b5SLaurent Vivier QPCIDevice *dev; 41e32b96b5SLaurent Vivier int bus; 42e32b96b5SLaurent Vivier 43e32b96b5SLaurent Vivier qts = qtest_init(args); 44e32b96b5SLaurent Vivier 45e32b96b5SLaurent Vivier pc_alloc_init(&guest_malloc, qts, 0); 46e32b96b5SLaurent Vivier pcibus = qpci_new_pc(qts, &guest_malloc); 47e32b96b5SLaurent Vivier g_assert(qpci_secondary_buses_init(pcibus) == numbus); 48e32b96b5SLaurent Vivier 49e32b96b5SLaurent Vivier for (bus = 1; bus <= numbus; bus++) { 50e32b96b5SLaurent Vivier dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0)); 51e32b96b5SLaurent Vivier g_assert_nonnull(dev); 52e32b96b5SLaurent Vivier 53e32b96b5SLaurent Vivier qpci_device_enable(dev); 54e32b96b5SLaurent Vivier qpci_iomap(dev, 4, NULL); 55e32b96b5SLaurent Vivier 56e32b96b5SLaurent Vivier g_free(dev); 57e32b96b5SLaurent Vivier } 58e32b96b5SLaurent Vivier 59e32b96b5SLaurent Vivier return qts; 60e32b96b5SLaurent Vivier } 61e32b96b5SLaurent Vivier 62e32b96b5SLaurent Vivier static void machine_stop(QTestState *qts) 63e32b96b5SLaurent Vivier { 64e32b96b5SLaurent Vivier qpci_free_pc(pcibus); 65e32b96b5SLaurent Vivier alloc_destroy(&guest_malloc); 66e32b96b5SLaurent Vivier qtest_quit(qts); 67e32b96b5SLaurent Vivier } 68e32b96b5SLaurent Vivier 69e32b96b5SLaurent Vivier static void test_error_id(void) 70e32b96b5SLaurent Vivier { 71e32b96b5SLaurent Vivier QTestState *qts; 72e32b96b5SLaurent Vivier QDict *resp; 73e32b96b5SLaurent Vivier QDict *err; 74e32b96b5SLaurent Vivier 75e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 76e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0,failover=on", 77e32b96b5SLaurent Vivier 2); 78e32b96b5SLaurent Vivier 79e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{'execute': 'device_add'," 80e32b96b5SLaurent Vivier "'arguments': {" 81e32b96b5SLaurent Vivier "'driver': 'virtio-net'," 82e32b96b5SLaurent Vivier "'bus': 'root1'," 83e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'" 84e32b96b5SLaurent Vivier "} }"); 85e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "error")); 86e32b96b5SLaurent Vivier 87e32b96b5SLaurent Vivier err = qdict_get_qdict(resp, "error"); 88e32b96b5SLaurent Vivier g_assert(qdict_haskey(err, "desc")); 89e32b96b5SLaurent Vivier 90e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(err, "desc"), ==, 91e32b96b5SLaurent Vivier "Device with failover_pair_id needs to have id"); 92e32b96b5SLaurent Vivier 93e32b96b5SLaurent Vivier qobject_unref(resp); 94e32b96b5SLaurent Vivier 95e32b96b5SLaurent Vivier machine_stop(qts); 96e32b96b5SLaurent Vivier } 97e32b96b5SLaurent Vivier 98e32b96b5SLaurent Vivier static void test_error_pcie(void) 99e32b96b5SLaurent Vivier { 100e32b96b5SLaurent Vivier QTestState *qts; 101e32b96b5SLaurent Vivier QDict *resp; 102e32b96b5SLaurent Vivier QDict *err; 103e32b96b5SLaurent Vivier 104e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 105e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0,failover=on", 106e32b96b5SLaurent Vivier 2); 107e32b96b5SLaurent Vivier 108e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{'execute': 'device_add'," 109e32b96b5SLaurent Vivier "'arguments': {" 110e32b96b5SLaurent Vivier "'driver': 'virtio-net'," 111e32b96b5SLaurent Vivier "'id': 'primary0'," 112e32b96b5SLaurent Vivier "'bus': 'pcie.0'," 113e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'" 114e32b96b5SLaurent Vivier "} }"); 115e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "error")); 116e32b96b5SLaurent Vivier 117e32b96b5SLaurent Vivier err = qdict_get_qdict(resp, "error"); 118e32b96b5SLaurent Vivier g_assert(qdict_haskey(err, "desc")); 119e32b96b5SLaurent Vivier 120e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(err, "desc"), ==, 121e32b96b5SLaurent Vivier "Bus 'pcie.0' does not support hotplugging"); 122e32b96b5SLaurent Vivier 123e32b96b5SLaurent Vivier qobject_unref(resp); 124e32b96b5SLaurent Vivier 125e32b96b5SLaurent Vivier machine_stop(qts); 126e32b96b5SLaurent Vivier } 127e32b96b5SLaurent Vivier 128e32b96b5SLaurent Vivier static QDict *find_device(QDict *bus, const char *name) 129e32b96b5SLaurent Vivier { 130e32b96b5SLaurent Vivier const QObject *obj; 131e32b96b5SLaurent Vivier QList *devices; 132e32b96b5SLaurent Vivier QList *list; 133e32b96b5SLaurent Vivier 134e32b96b5SLaurent Vivier devices = qdict_get_qlist(bus, "devices"); 135e32b96b5SLaurent Vivier if (devices == NULL) { 136e32b96b5SLaurent Vivier return NULL; 137e32b96b5SLaurent Vivier } 138e32b96b5SLaurent Vivier 139e32b96b5SLaurent Vivier list = qlist_copy(devices); 140e32b96b5SLaurent Vivier while ((obj = qlist_pop(list))) { 141e32b96b5SLaurent Vivier QDict *device; 142e32b96b5SLaurent Vivier 143e32b96b5SLaurent Vivier device = qobject_to(QDict, obj); 144e32b96b5SLaurent Vivier 145e32b96b5SLaurent Vivier if (qdict_haskey(device, "pci_bridge")) { 146e32b96b5SLaurent Vivier QDict *bridge; 147e32b96b5SLaurent Vivier QDict *bridge_device; 148e32b96b5SLaurent Vivier 149e32b96b5SLaurent Vivier bridge = qdict_get_qdict(device, "pci_bridge"); 150e32b96b5SLaurent Vivier 151e32b96b5SLaurent Vivier if (qdict_haskey(bridge, "devices")) { 152e32b96b5SLaurent Vivier bridge_device = find_device(bridge, name); 153e32b96b5SLaurent Vivier if (bridge_device) { 154e32b96b5SLaurent Vivier qobject_unref(device); 155e32b96b5SLaurent Vivier qobject_unref(list); 156e32b96b5SLaurent Vivier return bridge_device; 157e32b96b5SLaurent Vivier } 158e32b96b5SLaurent Vivier } 159e32b96b5SLaurent Vivier } 160e32b96b5SLaurent Vivier 161e32b96b5SLaurent Vivier if (!qdict_haskey(device, "qdev_id")) { 162e32b96b5SLaurent Vivier qobject_unref(device); 163e32b96b5SLaurent Vivier continue; 164e32b96b5SLaurent Vivier } 165e32b96b5SLaurent Vivier 166e32b96b5SLaurent Vivier if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) { 167e32b96b5SLaurent Vivier qobject_unref(list); 168e32b96b5SLaurent Vivier return device; 169e32b96b5SLaurent Vivier } 170e32b96b5SLaurent Vivier qobject_unref(device); 171e32b96b5SLaurent Vivier } 172e32b96b5SLaurent Vivier qobject_unref(list); 173e32b96b5SLaurent Vivier 174e32b96b5SLaurent Vivier return NULL; 175e32b96b5SLaurent Vivier } 176e32b96b5SLaurent Vivier 177e32b96b5SLaurent Vivier static QDict *get_bus(QTestState *qts, int num) 178e32b96b5SLaurent Vivier { 179e32b96b5SLaurent Vivier QObject *obj; 180e32b96b5SLaurent Vivier QDict *resp; 181e32b96b5SLaurent Vivier QList *ret; 182e32b96b5SLaurent Vivier 183e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }"); 184e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 185e32b96b5SLaurent Vivier 186e32b96b5SLaurent Vivier ret = qdict_get_qlist(resp, "return"); 187e32b96b5SLaurent Vivier g_assert_nonnull(ret); 188e32b96b5SLaurent Vivier 189e32b96b5SLaurent Vivier while ((obj = qlist_pop(ret))) { 190e32b96b5SLaurent Vivier QDict *bus; 191e32b96b5SLaurent Vivier 192e32b96b5SLaurent Vivier bus = qobject_to(QDict, obj); 193e32b96b5SLaurent Vivier if (!qdict_haskey(bus, "bus")) { 194e32b96b5SLaurent Vivier qobject_unref(bus); 195e32b96b5SLaurent Vivier continue; 196e32b96b5SLaurent Vivier } 197e32b96b5SLaurent Vivier if (qdict_get_int(bus, "bus") == num) { 198e32b96b5SLaurent Vivier qobject_unref(resp); 199e32b96b5SLaurent Vivier return bus; 200e32b96b5SLaurent Vivier } 201e32b96b5SLaurent Vivier qobject_ref(bus); 202e32b96b5SLaurent Vivier } 203e32b96b5SLaurent Vivier qobject_unref(resp); 204e32b96b5SLaurent Vivier 205e32b96b5SLaurent Vivier return NULL; 206e32b96b5SLaurent Vivier } 207e32b96b5SLaurent Vivier 208e32b96b5SLaurent Vivier static char *get_mac(QTestState *qts, const char *name) 209e32b96b5SLaurent Vivier { 210e32b96b5SLaurent Vivier QDict *resp; 211e32b96b5SLaurent Vivier char *mac; 212e32b96b5SLaurent Vivier 213e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'qom-get', " 214e32b96b5SLaurent Vivier "'arguments': { " 215e32b96b5SLaurent Vivier "'path': %s, " 216e32b96b5SLaurent Vivier "'property': 'mac' } }", name); 217e32b96b5SLaurent Vivier 218e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 219e32b96b5SLaurent Vivier 220e32b96b5SLaurent Vivier mac = g_strdup(qdict_get_str(resp, "return")); 221e32b96b5SLaurent Vivier 222e32b96b5SLaurent Vivier qobject_unref(resp); 223e32b96b5SLaurent Vivier 224e32b96b5SLaurent Vivier return mac; 225e32b96b5SLaurent Vivier } 226e32b96b5SLaurent Vivier 227e32b96b5SLaurent Vivier static void check_one_card(QTestState *qts, bool present, 228e32b96b5SLaurent Vivier const char *id, const char *mac) 229e32b96b5SLaurent Vivier { 230e32b96b5SLaurent Vivier QDict *device; 231e32b96b5SLaurent Vivier QDict *bus; 232e32b96b5SLaurent Vivier char *addr; 233e32b96b5SLaurent Vivier 234e32b96b5SLaurent Vivier bus = get_bus(qts, 0); 235e32b96b5SLaurent Vivier device = find_device(bus, id); 236e32b96b5SLaurent Vivier if (present) { 237e32b96b5SLaurent Vivier char *path; 238e32b96b5SLaurent Vivier 239e32b96b5SLaurent Vivier g_assert_nonnull(device); 240e32b96b5SLaurent Vivier qobject_unref(device); 241e32b96b5SLaurent Vivier 242e32b96b5SLaurent Vivier path = g_strdup_printf("/machine/peripheral/%s", id); 243e32b96b5SLaurent Vivier addr = get_mac(qts, path); 244e32b96b5SLaurent Vivier g_free(path); 245e32b96b5SLaurent Vivier g_assert_cmpstr(mac, ==, addr); 246e32b96b5SLaurent Vivier g_free(addr); 247e32b96b5SLaurent Vivier } else { 248e32b96b5SLaurent Vivier g_assert_null(device); 249e32b96b5SLaurent Vivier } 250e32b96b5SLaurent Vivier 251e32b96b5SLaurent Vivier qobject_unref(bus); 252e32b96b5SLaurent Vivier } 253e32b96b5SLaurent Vivier 254e32b96b5SLaurent Vivier static void test_on(void) 255e32b96b5SLaurent Vivier { 256e32b96b5SLaurent Vivier QTestState *qts; 257e32b96b5SLaurent Vivier 258e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 259e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 260e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0," 261e32b96b5SLaurent Vivier "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 262e32b96b5SLaurent Vivier "-device virtio-net,bus=root1,id=primary0," 263e32b96b5SLaurent Vivier "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0, 264e32b96b5SLaurent Vivier 2); 265e32b96b5SLaurent Vivier 266e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 267e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 268e32b96b5SLaurent Vivier 269e32b96b5SLaurent Vivier machine_stop(qts); 270e32b96b5SLaurent Vivier } 271e32b96b5SLaurent Vivier 272e32b96b5SLaurent Vivier static void test_on_mismatch(void) 273e32b96b5SLaurent Vivier { 274e32b96b5SLaurent Vivier QTestState *qts; 275e32b96b5SLaurent Vivier 276e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 277e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 278e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0," 279e32b96b5SLaurent Vivier "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 280e32b96b5SLaurent Vivier "-netdev user,id=hs1 " 281e32b96b5SLaurent Vivier "-device virtio-net,bus=root1,id=primary0," 282e32b96b5SLaurent Vivier "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0, 283e32b96b5SLaurent Vivier 2); 284e32b96b5SLaurent Vivier 285e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 286e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 287e32b96b5SLaurent Vivier 288e32b96b5SLaurent Vivier machine_stop(qts); 289e32b96b5SLaurent Vivier } 290e32b96b5SLaurent Vivier 291e32b96b5SLaurent Vivier static void test_off(void) 292e32b96b5SLaurent Vivier { 293e32b96b5SLaurent Vivier QTestState *qts; 294e32b96b5SLaurent Vivier 295e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 296e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 297e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0," 298e32b96b5SLaurent Vivier "failover=off,netdev=hs0,mac="MAC_STANDBY0" " 299e32b96b5SLaurent Vivier "-netdev user,id=hs1 " 300e32b96b5SLaurent Vivier "-device virtio-net,bus=root1,id=primary0," 301e32b96b5SLaurent Vivier "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0, 302e32b96b5SLaurent Vivier 2); 303e32b96b5SLaurent Vivier 304e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 305e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 306e32b96b5SLaurent Vivier 307e32b96b5SLaurent Vivier machine_stop(qts); 308e32b96b5SLaurent Vivier } 309e32b96b5SLaurent Vivier 310e32b96b5SLaurent Vivier static QDict *get_failover_negociated_event(QTestState *qts) 311e32b96b5SLaurent Vivier { 312e32b96b5SLaurent Vivier QDict *resp; 313e32b96b5SLaurent Vivier QDict *data; 314e32b96b5SLaurent Vivier 315e32b96b5SLaurent Vivier resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED"); 316e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "data")); 317e32b96b5SLaurent Vivier 318e32b96b5SLaurent Vivier data = qdict_get_qdict(resp, "data"); 319e32b96b5SLaurent Vivier g_assert(qdict_haskey(data, "device-id")); 320e32b96b5SLaurent Vivier qobject_ref(data); 321e32b96b5SLaurent Vivier qobject_unref(resp); 322e32b96b5SLaurent Vivier 323e32b96b5SLaurent Vivier return data; 324e32b96b5SLaurent Vivier } 325e32b96b5SLaurent Vivier 326e32b96b5SLaurent Vivier static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot, 327e32b96b5SLaurent Vivier const char *id) 328e32b96b5SLaurent Vivier { 329e32b96b5SLaurent Vivier QVirtioPCIDevice *dev; 330e32b96b5SLaurent Vivier uint64_t features; 331e32b96b5SLaurent Vivier QPCIAddress addr; 332e32b96b5SLaurent Vivier QDict *resp; 333e32b96b5SLaurent Vivier 334e32b96b5SLaurent Vivier addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0); 335e32b96b5SLaurent Vivier dev = virtio_pci_new(pcibus, &addr); 336e32b96b5SLaurent Vivier g_assert_nonnull(dev); 337e32b96b5SLaurent Vivier qvirtio_pci_device_enable(dev); 338e32b96b5SLaurent Vivier qvirtio_start_device(&dev->vdev); 339e32b96b5SLaurent Vivier features = qvirtio_get_features(&dev->vdev); 340e32b96b5SLaurent Vivier features = features & ~(QVIRTIO_F_BAD_FEATURE | 341e32b96b5SLaurent Vivier (1ull << VIRTIO_RING_F_INDIRECT_DESC) | 342e32b96b5SLaurent Vivier (1ull << VIRTIO_RING_F_EVENT_IDX)); 343e32b96b5SLaurent Vivier qvirtio_set_features(&dev->vdev, features); 344e32b96b5SLaurent Vivier qvirtio_set_driver_ok(&dev->vdev); 345e32b96b5SLaurent Vivier 346e32b96b5SLaurent Vivier resp = get_failover_negociated_event(qts); 347e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id); 348e32b96b5SLaurent Vivier qobject_unref(resp); 349e32b96b5SLaurent Vivier 350e32b96b5SLaurent Vivier return dev; 351e32b96b5SLaurent Vivier } 352e32b96b5SLaurent Vivier 353e32b96b5SLaurent Vivier static void test_enabled(void) 354e32b96b5SLaurent Vivier { 355e32b96b5SLaurent Vivier QTestState *qts; 356e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 357e32b96b5SLaurent Vivier 358e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 359e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 360e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0," 361e32b96b5SLaurent Vivier "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 362e32b96b5SLaurent Vivier "-netdev user,id=hs1 " 363e32b96b5SLaurent Vivier "-device virtio-net,bus=root1,id=primary0," 364e32b96b5SLaurent Vivier "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ", 365e32b96b5SLaurent Vivier 2); 366e32b96b5SLaurent Vivier 367e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 368e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 369e32b96b5SLaurent Vivier 370e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 371e32b96b5SLaurent Vivier 372e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 373e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 374e32b96b5SLaurent Vivier 375e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 376e32b96b5SLaurent Vivier machine_stop(qts); 377e32b96b5SLaurent Vivier } 378e32b96b5SLaurent Vivier 379e32b96b5SLaurent Vivier static void test_hotplug_1(void) 380e32b96b5SLaurent Vivier { 381e32b96b5SLaurent Vivier QTestState *qts; 382e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 383e32b96b5SLaurent Vivier 384e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 385e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 386e32b96b5SLaurent Vivier "-device virtio-net,bus=root0,id=standby0," 387e32b96b5SLaurent Vivier "failover=on,netdev=hs0,mac="MAC_STANDBY0" " 388e32b96b5SLaurent Vivier "-netdev user,id=hs1 ", 2); 389e32b96b5SLaurent Vivier 390e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 391e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 392e32b96b5SLaurent Vivier 393e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 394e32b96b5SLaurent Vivier 395e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 396e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 397e32b96b5SLaurent Vivier 398e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 399e32b96b5SLaurent Vivier "{'bus': 'root1'," 400e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'," 401e32b96b5SLaurent Vivier "'netdev': 'hs1'," 402e32b96b5SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 403e32b96b5SLaurent Vivier 404e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 405e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 406e32b96b5SLaurent Vivier 407e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 408e32b96b5SLaurent Vivier machine_stop(qts); 409e32b96b5SLaurent Vivier } 410e32b96b5SLaurent Vivier 411e32b96b5SLaurent Vivier static void test_hotplug_1_reverse(void) 412e32b96b5SLaurent Vivier { 413e32b96b5SLaurent Vivier QTestState *qts; 414e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 415e32b96b5SLaurent Vivier 416e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 417e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 418e32b96b5SLaurent Vivier "-netdev user,id=hs1 " 419e32b96b5SLaurent Vivier "-device virtio-net,bus=root1,id=primary0," 420e32b96b5SLaurent Vivier "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ", 421e32b96b5SLaurent Vivier 2); 422e32b96b5SLaurent Vivier 423e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 424e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 425e32b96b5SLaurent Vivier 426e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 427e32b96b5SLaurent Vivier "{'bus': 'root0'," 428e32b96b5SLaurent Vivier "'failover': 'on'," 429e32b96b5SLaurent Vivier "'netdev': 'hs0'," 430e32b96b5SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 431e32b96b5SLaurent Vivier 432e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 433e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 434e32b96b5SLaurent Vivier 435e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 436e32b96b5SLaurent Vivier 437e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 438e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 439e32b96b5SLaurent Vivier 440e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 441e32b96b5SLaurent Vivier machine_stop(qts); 442e32b96b5SLaurent Vivier } 443e32b96b5SLaurent Vivier 444e32b96b5SLaurent Vivier static void test_hotplug_2(void) 445e32b96b5SLaurent Vivier { 446e32b96b5SLaurent Vivier QTestState *qts; 447e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 448e32b96b5SLaurent Vivier 449e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 450e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 451e32b96b5SLaurent Vivier "-netdev user,id=hs1 ", 452e32b96b5SLaurent Vivier 2); 453e32b96b5SLaurent Vivier 454e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 455e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 456e32b96b5SLaurent Vivier 457e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 458e32b96b5SLaurent Vivier "{'bus': 'root0'," 459e32b96b5SLaurent Vivier "'failover': 'on'," 460e32b96b5SLaurent Vivier "'netdev': 'hs0'," 461e32b96b5SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 462e32b96b5SLaurent Vivier 463e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 464e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 465e32b96b5SLaurent Vivier 466e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 467e32b96b5SLaurent Vivier 468e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 469e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 470e32b96b5SLaurent Vivier 471e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 472e32b96b5SLaurent Vivier "{'bus': 'root1'," 473e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'," 474e32b96b5SLaurent Vivier "'netdev': 'hs1'," 475e32b96b5SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 476e32b96b5SLaurent Vivier 477e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 478e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 479e32b96b5SLaurent Vivier 480e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 481e32b96b5SLaurent Vivier machine_stop(qts); 482e32b96b5SLaurent Vivier } 483e32b96b5SLaurent Vivier 484e32b96b5SLaurent Vivier static void test_hotplug_2_reverse(void) 485e32b96b5SLaurent Vivier { 486e32b96b5SLaurent Vivier QTestState *qts; 487e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 488e32b96b5SLaurent Vivier 489e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 490e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 491e32b96b5SLaurent Vivier "-netdev user,id=hs1 ", 492e32b96b5SLaurent Vivier 2); 493e32b96b5SLaurent Vivier 494e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 495e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 496e32b96b5SLaurent Vivier 497e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 498e32b96b5SLaurent Vivier "{'bus': 'root1'," 499e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'," 500e32b96b5SLaurent Vivier "'netdev': 'hs1'," 501e32b96b5SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 502e32b96b5SLaurent Vivier 503e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 504e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 505e32b96b5SLaurent Vivier 506e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 507e32b96b5SLaurent Vivier "{'bus': 'root0'," 508e32b96b5SLaurent Vivier "'failover': 'on'," 509e32b96b5SLaurent Vivier "'netdev': 'hs0'," 510e32b96b5SLaurent Vivier "'rombar': 0," 511e32b96b5SLaurent Vivier "'romfile': ''," 512e32b96b5SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 513e32b96b5SLaurent Vivier 514e32b96b5SLaurent Vivier /* 515e32b96b5SLaurent Vivier * XXX: sounds like a bug: 516e32b96b5SLaurent Vivier * The primary should be hidden until the virtio-net driver 517e32b96b5SLaurent Vivier * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net() 518e32b96b5SLaurent Vivier */ 519e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 520e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 521e32b96b5SLaurent Vivier 522e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 523e32b96b5SLaurent Vivier 524e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 525e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 526e32b96b5SLaurent Vivier 527e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 528e32b96b5SLaurent Vivier machine_stop(qts); 529e32b96b5SLaurent Vivier } 530e32b96b5SLaurent Vivier 531e32b96b5SLaurent Vivier static QDict *migrate_status(QTestState *qts) 532e32b96b5SLaurent Vivier { 533e32b96b5SLaurent Vivier QDict *resp, *ret; 534e32b96b5SLaurent Vivier 535e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }"); 536e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 537e32b96b5SLaurent Vivier 538e32b96b5SLaurent Vivier ret = qdict_get_qdict(resp, "return"); 539e32b96b5SLaurent Vivier g_assert(qdict_haskey(ret, "status")); 540e32b96b5SLaurent Vivier qobject_ref(ret); 541e32b96b5SLaurent Vivier qobject_unref(resp); 542e32b96b5SLaurent Vivier 543e32b96b5SLaurent Vivier return ret; 544e32b96b5SLaurent Vivier } 545e32b96b5SLaurent Vivier 546e32b96b5SLaurent Vivier static QDict *get_unplug_primary_event(QTestState *qts) 547e32b96b5SLaurent Vivier { 548e32b96b5SLaurent Vivier QDict *resp; 549e32b96b5SLaurent Vivier QDict *data; 550e32b96b5SLaurent Vivier 551e32b96b5SLaurent Vivier resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY"); 552e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "data")); 553e32b96b5SLaurent Vivier 554e32b96b5SLaurent Vivier data = qdict_get_qdict(resp, "data"); 555e32b96b5SLaurent Vivier g_assert(qdict_haskey(data, "device-id")); 556e32b96b5SLaurent Vivier qobject_ref(data); 557e32b96b5SLaurent Vivier qobject_unref(resp); 558e32b96b5SLaurent Vivier 559e32b96b5SLaurent Vivier return data; 560e32b96b5SLaurent Vivier } 561e32b96b5SLaurent Vivier 562e32b96b5SLaurent Vivier static void test_migrate_out(gconstpointer opaque) 563e32b96b5SLaurent Vivier { 564e32b96b5SLaurent Vivier QTestState *qts; 565e32b96b5SLaurent Vivier QDict *resp, *args, *ret; 566e32b96b5SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 567e32b96b5SLaurent Vivier const gchar *status; 568e32b96b5SLaurent Vivier QVirtioPCIDevice *vdev; 569e32b96b5SLaurent Vivier 570e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 571e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 572e32b96b5SLaurent Vivier "-netdev user,id=hs1 ", 573e32b96b5SLaurent Vivier 2); 574e32b96b5SLaurent Vivier 575e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 576e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 577e32b96b5SLaurent Vivier 578e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 579e32b96b5SLaurent Vivier "{'bus': 'root0'," 580e32b96b5SLaurent Vivier "'failover': 'on'," 581e32b96b5SLaurent Vivier "'netdev': 'hs0'," 582e32b96b5SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 583e32b96b5SLaurent Vivier 584e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 585e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 586e32b96b5SLaurent Vivier 587e32b96b5SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 588e32b96b5SLaurent Vivier 589e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 590e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 591e32b96b5SLaurent Vivier 592e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 593e32b96b5SLaurent Vivier "{'bus': 'root1'," 594e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'," 595e32b96b5SLaurent Vivier "'netdev': 'hs1'," 596e32b96b5SLaurent Vivier "'rombar': 0," 597e32b96b5SLaurent Vivier "'romfile': ''," 598e32b96b5SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 599e32b96b5SLaurent Vivier 600e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 601e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 602e32b96b5SLaurent Vivier 603e32b96b5SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 604e32b96b5SLaurent Vivier g_assert_nonnull(args); 605e32b96b5SLaurent Vivier qdict_put_str(args, "uri", uri); 606e32b96b5SLaurent Vivier 607e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 608e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 609e32b96b5SLaurent Vivier qobject_unref(resp); 610e32b96b5SLaurent Vivier 611e32b96b5SLaurent Vivier /* the event is sent when QEMU asks the OS to unplug the card */ 612e32b96b5SLaurent Vivier resp = get_unplug_primary_event(qts); 613e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 614e32b96b5SLaurent Vivier qobject_unref(resp); 615e32b96b5SLaurent Vivier 616e32b96b5SLaurent Vivier /* wait the end of the migration setup phase */ 617e32b96b5SLaurent Vivier while (true) { 618e32b96b5SLaurent Vivier ret = migrate_status(qts); 619e32b96b5SLaurent Vivier 620e32b96b5SLaurent Vivier status = qdict_get_str(ret, "status"); 621e32b96b5SLaurent Vivier if (strcmp(status, "wait-unplug") == 0) { 622e32b96b5SLaurent Vivier qobject_unref(ret); 623e32b96b5SLaurent Vivier break; 624e32b96b5SLaurent Vivier } 625e32b96b5SLaurent Vivier 626e32b96b5SLaurent Vivier /* The migration must not start if the card is not ejected */ 627e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "active"); 628e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "completed"); 629e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 630e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "cancelling"); 631e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "cancelled"); 632e32b96b5SLaurent Vivier 633e32b96b5SLaurent Vivier qobject_unref(ret); 634e32b96b5SLaurent Vivier } 635e32b96b5SLaurent Vivier 636e32b96b5SLaurent Vivier if (g_test_slow()) { 637e32b96b5SLaurent Vivier /* check we stay in wait-unplug while the card is not ejected */ 638e32b96b5SLaurent Vivier for (int i = 0; i < 5; i++) { 639e32b96b5SLaurent Vivier sleep(1); 640e32b96b5SLaurent Vivier ret = migrate_status(qts); 641e32b96b5SLaurent Vivier status = qdict_get_str(ret, "status"); 642e32b96b5SLaurent Vivier g_assert_cmpstr(status, ==, "wait-unplug"); 643e32b96b5SLaurent Vivier qobject_unref(ret); 644e32b96b5SLaurent Vivier } 645e32b96b5SLaurent Vivier } 646e32b96b5SLaurent Vivier 647e32b96b5SLaurent Vivier /* OS unplugs the cards, QEMU can move from wait-unplug state */ 648e32b96b5SLaurent Vivier qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 649e32b96b5SLaurent Vivier 650e32b96b5SLaurent Vivier while (true) { 651e32b96b5SLaurent Vivier ret = migrate_status(qts); 652e32b96b5SLaurent Vivier 653e32b96b5SLaurent Vivier status = qdict_get_str(ret, "status"); 654e32b96b5SLaurent Vivier if (strcmp(status, "completed") == 0) { 655e32b96b5SLaurent Vivier qobject_unref(ret); 656e32b96b5SLaurent Vivier break; 657e32b96b5SLaurent Vivier } 658e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 659e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "cancelling"); 660e32b96b5SLaurent Vivier g_assert_cmpstr(status, !=, "cancelled"); 661e32b96b5SLaurent Vivier qobject_unref(ret); 662e32b96b5SLaurent Vivier } 663e32b96b5SLaurent Vivier 664e32b96b5SLaurent Vivier qtest_qmp_eventwait(qts, "STOP"); 665e32b96b5SLaurent Vivier 666e32b96b5SLaurent Vivier /* 667e32b96b5SLaurent Vivier * in fact, the card is ejected from the point of view of kernel 668e32b96b5SLaurent Vivier * but not really from QEMU to be able to hotplug it back if 669e32b96b5SLaurent Vivier * migration fails. So we can't check that: 670e32b96b5SLaurent Vivier * check_one_card(qts, true, "standby0", MAC_STANDBY0); 671e32b96b5SLaurent Vivier * check_one_card(qts, false, "primary0", MAC_PRIMARY0); 672e32b96b5SLaurent Vivier */ 673e32b96b5SLaurent Vivier 674e32b96b5SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 675e32b96b5SLaurent Vivier machine_stop(qts); 676e32b96b5SLaurent Vivier } 677e32b96b5SLaurent Vivier 678e32b96b5SLaurent Vivier static QDict *get_migration_event(QTestState *qts) 679e32b96b5SLaurent Vivier { 680e32b96b5SLaurent Vivier QDict *resp; 681e32b96b5SLaurent Vivier QDict *data; 682e32b96b5SLaurent Vivier 683e32b96b5SLaurent Vivier resp = qtest_qmp_eventwait_ref(qts, "MIGRATION"); 684e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "data")); 685e32b96b5SLaurent Vivier 686e32b96b5SLaurent Vivier data = qdict_get_qdict(resp, "data"); 687e32b96b5SLaurent Vivier g_assert(qdict_haskey(data, "status")); 688e32b96b5SLaurent Vivier qobject_ref(data); 689e32b96b5SLaurent Vivier qobject_unref(resp); 690e32b96b5SLaurent Vivier 691e32b96b5SLaurent Vivier return data; 692e32b96b5SLaurent Vivier } 693e32b96b5SLaurent Vivier 694e32b96b5SLaurent Vivier static void test_migrate_in(gconstpointer opaque) 695e32b96b5SLaurent Vivier { 696e32b96b5SLaurent Vivier QTestState *qts; 697e32b96b5SLaurent Vivier QDict *resp, *args, *ret; 698e32b96b5SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); 699e32b96b5SLaurent Vivier 700e32b96b5SLaurent Vivier qts = machine_start(BASE_MACHINE 701e32b96b5SLaurent Vivier "-netdev user,id=hs0 " 702e32b96b5SLaurent Vivier "-netdev user,id=hs1 " 703e32b96b5SLaurent Vivier "-incoming defer ", 704e32b96b5SLaurent Vivier 2); 705e32b96b5SLaurent Vivier 706e32b96b5SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 707e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 708e32b96b5SLaurent Vivier 709e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 710e32b96b5SLaurent Vivier "{'bus': 'root0'," 711e32b96b5SLaurent Vivier "'failover': 'on'," 712e32b96b5SLaurent Vivier "'netdev': 'hs0'," 713e32b96b5SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 714e32b96b5SLaurent Vivier 715e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 716e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 717e32b96b5SLaurent Vivier 718e32b96b5SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 719e32b96b5SLaurent Vivier "{'bus': 'root1'," 720e32b96b5SLaurent Vivier "'failover_pair_id': 'standby0'," 721e32b96b5SLaurent Vivier "'netdev': 'hs1'," 722e32b96b5SLaurent Vivier "'rombar': 0," 723e32b96b5SLaurent Vivier "'romfile': ''," 724e32b96b5SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 725e32b96b5SLaurent Vivier 726e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 727e32b96b5SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 728e32b96b5SLaurent Vivier 729e32b96b5SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 730e32b96b5SLaurent Vivier g_assert_nonnull(args); 731e32b96b5SLaurent Vivier qdict_put_str(args, "uri", uri); 732e32b96b5SLaurent Vivier 733e32b96b5SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", 734e32b96b5SLaurent Vivier args); 735e32b96b5SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 736e32b96b5SLaurent Vivier qobject_unref(resp); 737e32b96b5SLaurent Vivier 738e32b96b5SLaurent Vivier resp = get_migration_event(qts); 739e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); 740e32b96b5SLaurent Vivier qobject_unref(resp); 741e32b96b5SLaurent Vivier 742e32b96b5SLaurent Vivier resp = get_failover_negociated_event(qts); 743e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0"); 744e32b96b5SLaurent Vivier qobject_unref(resp); 745e32b96b5SLaurent Vivier 746e32b96b5SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 747e32b96b5SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 748e32b96b5SLaurent Vivier 749e32b96b5SLaurent Vivier qtest_qmp_eventwait(qts, "RESUME"); 750e32b96b5SLaurent Vivier 751e32b96b5SLaurent Vivier ret = migrate_status(qts); 752e32b96b5SLaurent Vivier g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed"); 753e32b96b5SLaurent Vivier qobject_unref(ret); 754e32b96b5SLaurent Vivier 755e32b96b5SLaurent Vivier machine_stop(qts); 756e32b96b5SLaurent Vivier } 757e32b96b5SLaurent Vivier 7581e2077e2SLaurent Vivier static void test_migrate_abort_wait_unplug(gconstpointer opaque) 7591e2077e2SLaurent Vivier { 7601e2077e2SLaurent Vivier QTestState *qts; 7611e2077e2SLaurent Vivier QDict *resp, *args, *ret; 7621e2077e2SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 7631e2077e2SLaurent Vivier const gchar *status; 7641e2077e2SLaurent Vivier QVirtioPCIDevice *vdev; 7651e2077e2SLaurent Vivier 7661e2077e2SLaurent Vivier qts = machine_start(BASE_MACHINE 7671e2077e2SLaurent Vivier "-netdev user,id=hs0 " 7681e2077e2SLaurent Vivier "-netdev user,id=hs1 ", 7691e2077e2SLaurent Vivier 2); 7701e2077e2SLaurent Vivier 7711e2077e2SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 7721e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 7731e2077e2SLaurent Vivier 7741e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 7751e2077e2SLaurent Vivier "{'bus': 'root0'," 7761e2077e2SLaurent Vivier "'failover': 'on'," 7771e2077e2SLaurent Vivier "'netdev': 'hs0'," 7781e2077e2SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 7791e2077e2SLaurent Vivier 7801e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 7811e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 7821e2077e2SLaurent Vivier 7831e2077e2SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 7841e2077e2SLaurent Vivier 7851e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 7861e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 7871e2077e2SLaurent Vivier 7881e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 7891e2077e2SLaurent Vivier "{'bus': 'root1'," 7901e2077e2SLaurent Vivier "'failover_pair_id': 'standby0'," 7911e2077e2SLaurent Vivier "'netdev': 'hs1'," 7921e2077e2SLaurent Vivier "'rombar': 0," 7931e2077e2SLaurent Vivier "'romfile': ''," 7941e2077e2SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 7951e2077e2SLaurent Vivier 7961e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 7971e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 7981e2077e2SLaurent Vivier 7991e2077e2SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 8001e2077e2SLaurent Vivier g_assert_nonnull(args); 8011e2077e2SLaurent Vivier qdict_put_str(args, "uri", uri); 8021e2077e2SLaurent Vivier 8031e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 8041e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 8051e2077e2SLaurent Vivier qobject_unref(resp); 8061e2077e2SLaurent Vivier 8071e2077e2SLaurent Vivier /* the event is sent when QEMU asks the OS to unplug the card */ 8081e2077e2SLaurent Vivier resp = get_unplug_primary_event(qts); 8091e2077e2SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 8101e2077e2SLaurent Vivier qobject_unref(resp); 8111e2077e2SLaurent Vivier 8121e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); 8131e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 8141e2077e2SLaurent Vivier qobject_unref(resp); 8151e2077e2SLaurent Vivier 8161e2077e2SLaurent Vivier /* migration has been cancelled while the unplug was in progress */ 8171e2077e2SLaurent Vivier 8181e2077e2SLaurent Vivier /* while the card is not ejected, we must be in "cancelling" state */ 8191e2077e2SLaurent Vivier ret = migrate_status(qts); 8201e2077e2SLaurent Vivier 8211e2077e2SLaurent Vivier status = qdict_get_str(ret, "status"); 8221e2077e2SLaurent Vivier g_assert_cmpstr(status, ==, "cancelling"); 8231e2077e2SLaurent Vivier qobject_unref(ret); 8241e2077e2SLaurent Vivier 8251e2077e2SLaurent Vivier /* OS unplugs the cards, QEMU can move from wait-unplug state */ 8261e2077e2SLaurent Vivier qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 8271e2077e2SLaurent Vivier 8281e2077e2SLaurent Vivier while (true) { 8291e2077e2SLaurent Vivier ret = migrate_status(qts); 8301e2077e2SLaurent Vivier 8311e2077e2SLaurent Vivier status = qdict_get_str(ret, "status"); 8321e2077e2SLaurent Vivier if (strcmp(status, "cancelled") == 0) { 8331e2077e2SLaurent Vivier qobject_unref(ret); 8341e2077e2SLaurent Vivier break; 8351e2077e2SLaurent Vivier } 8361e2077e2SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 8371e2077e2SLaurent Vivier g_assert_cmpstr(status, !=, "active"); 8381e2077e2SLaurent Vivier qobject_unref(ret); 8391e2077e2SLaurent Vivier } 8401e2077e2SLaurent Vivier 8411e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 8421e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 8431e2077e2SLaurent Vivier 8441e2077e2SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 8451e2077e2SLaurent Vivier machine_stop(qts); 8461e2077e2SLaurent Vivier } 8471e2077e2SLaurent Vivier 8481e2077e2SLaurent Vivier static void test_migrate_abort_active(gconstpointer opaque) 8491e2077e2SLaurent Vivier { 8501e2077e2SLaurent Vivier QTestState *qts; 8511e2077e2SLaurent Vivier QDict *resp, *args, *ret; 8521e2077e2SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 8531e2077e2SLaurent Vivier const gchar *status; 8541e2077e2SLaurent Vivier QVirtioPCIDevice *vdev; 8551e2077e2SLaurent Vivier 8561e2077e2SLaurent Vivier qts = machine_start(BASE_MACHINE 8571e2077e2SLaurent Vivier "-netdev user,id=hs0 " 8581e2077e2SLaurent Vivier "-netdev user,id=hs1 ", 8591e2077e2SLaurent Vivier 2); 8601e2077e2SLaurent Vivier 8611e2077e2SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 8621e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 8631e2077e2SLaurent Vivier 8641e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 8651e2077e2SLaurent Vivier "{'bus': 'root0'," 8661e2077e2SLaurent Vivier "'failover': 'on'," 8671e2077e2SLaurent Vivier "'netdev': 'hs0'," 8681e2077e2SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 8691e2077e2SLaurent Vivier 8701e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 8711e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 8721e2077e2SLaurent Vivier 8731e2077e2SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 8741e2077e2SLaurent Vivier 8751e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 8761e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 8771e2077e2SLaurent Vivier 8781e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 8791e2077e2SLaurent Vivier "{'bus': 'root1'," 8801e2077e2SLaurent Vivier "'failover_pair_id': 'standby0'," 8811e2077e2SLaurent Vivier "'netdev': 'hs1'," 8821e2077e2SLaurent Vivier "'rombar': 0," 8831e2077e2SLaurent Vivier "'romfile': ''," 8841e2077e2SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 8851e2077e2SLaurent Vivier 8861e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 8871e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 8881e2077e2SLaurent Vivier 8891e2077e2SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 8901e2077e2SLaurent Vivier g_assert_nonnull(args); 8911e2077e2SLaurent Vivier qdict_put_str(args, "uri", uri); 8921e2077e2SLaurent Vivier 8931e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 8941e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 8951e2077e2SLaurent Vivier qobject_unref(resp); 8961e2077e2SLaurent Vivier 8971e2077e2SLaurent Vivier /* the event is sent when QEMU asks the OS to unplug the card */ 8981e2077e2SLaurent Vivier resp = get_unplug_primary_event(qts); 8991e2077e2SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 9001e2077e2SLaurent Vivier qobject_unref(resp); 9011e2077e2SLaurent Vivier 9021e2077e2SLaurent Vivier /* OS unplugs the cards, QEMU can move from wait-unplug state */ 9031e2077e2SLaurent Vivier qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 9041e2077e2SLaurent Vivier 9051e2077e2SLaurent Vivier while (true) { 9061e2077e2SLaurent Vivier ret = migrate_status(qts); 9071e2077e2SLaurent Vivier 9081e2077e2SLaurent Vivier status = qdict_get_str(ret, "status"); 9091e2077e2SLaurent Vivier if (strcmp(status, "wait-unplug") != 0) { 9101e2077e2SLaurent Vivier qobject_unref(ret); 9111e2077e2SLaurent Vivier break; 9121e2077e2SLaurent Vivier } 9131e2077e2SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 9141e2077e2SLaurent Vivier qobject_unref(ret); 9151e2077e2SLaurent Vivier } 9161e2077e2SLaurent Vivier 9171e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); 9181e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 9191e2077e2SLaurent Vivier qobject_unref(resp); 9201e2077e2SLaurent Vivier 9211e2077e2SLaurent Vivier while (true) { 9221e2077e2SLaurent Vivier ret = migrate_status(qts); 9231e2077e2SLaurent Vivier 9241e2077e2SLaurent Vivier status = qdict_get_str(ret, "status"); 9251e2077e2SLaurent Vivier if (strcmp(status, "cancelled") == 0) { 9261e2077e2SLaurent Vivier qobject_unref(ret); 9271e2077e2SLaurent Vivier break; 9281e2077e2SLaurent Vivier } 9291e2077e2SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 9301e2077e2SLaurent Vivier g_assert_cmpstr(status, !=, "active"); 9311e2077e2SLaurent Vivier qobject_unref(ret); 9321e2077e2SLaurent Vivier } 9331e2077e2SLaurent Vivier 9341e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 9351e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 9361e2077e2SLaurent Vivier 9371e2077e2SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 9381e2077e2SLaurent Vivier machine_stop(qts); 9391e2077e2SLaurent Vivier } 9401e2077e2SLaurent Vivier 9411e2077e2SLaurent Vivier static void test_migrate_abort_timeout(gconstpointer opaque) 9421e2077e2SLaurent Vivier { 9431e2077e2SLaurent Vivier QTestState *qts; 9441e2077e2SLaurent Vivier QDict *resp, *args, *ret; 9451e2077e2SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 9461e2077e2SLaurent Vivier const gchar *status; 9471e2077e2SLaurent Vivier int total; 9481e2077e2SLaurent Vivier QVirtioPCIDevice *vdev; 9491e2077e2SLaurent Vivier 9501e2077e2SLaurent Vivier qts = machine_start(BASE_MACHINE 9511e2077e2SLaurent Vivier "-netdev user,id=hs0 " 9521e2077e2SLaurent Vivier "-netdev user,id=hs1 ", 9531e2077e2SLaurent Vivier 2); 9541e2077e2SLaurent Vivier 9551e2077e2SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 9561e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 9571e2077e2SLaurent Vivier 9581e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 9591e2077e2SLaurent Vivier "{'bus': 'root0'," 9601e2077e2SLaurent Vivier "'failover': 'on'," 9611e2077e2SLaurent Vivier "'netdev': 'hs0'," 9621e2077e2SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 9631e2077e2SLaurent Vivier 9641e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 9651e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 9661e2077e2SLaurent Vivier 9671e2077e2SLaurent Vivier vdev = start_virtio_net(qts, 1, 0, "standby0"); 9681e2077e2SLaurent Vivier 9691e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 9701e2077e2SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 9711e2077e2SLaurent Vivier 9721e2077e2SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 9731e2077e2SLaurent Vivier "{'bus': 'root1'," 9741e2077e2SLaurent Vivier "'failover_pair_id': 'standby0'," 9751e2077e2SLaurent Vivier "'netdev': 'hs1'," 9761e2077e2SLaurent Vivier "'rombar': 0," 9771e2077e2SLaurent Vivier "'romfile': ''," 9781e2077e2SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 9791e2077e2SLaurent Vivier 9801e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 9811e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 9821e2077e2SLaurent Vivier 9831e2077e2SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 9841e2077e2SLaurent Vivier g_assert_nonnull(args); 9851e2077e2SLaurent Vivier qdict_put_str(args, "uri", uri); 9861e2077e2SLaurent Vivier 9871e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 9881e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 9891e2077e2SLaurent Vivier qobject_unref(resp); 9901e2077e2SLaurent Vivier 9911e2077e2SLaurent Vivier /* the event is sent when QEMU asks the OS to unplug the card */ 9921e2077e2SLaurent Vivier resp = get_unplug_primary_event(qts); 9931e2077e2SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0"); 9941e2077e2SLaurent Vivier qobject_unref(resp); 9951e2077e2SLaurent Vivier 9961e2077e2SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }"); 9971e2077e2SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 9981e2077e2SLaurent Vivier qobject_unref(resp); 9991e2077e2SLaurent Vivier 10001e2077e2SLaurent Vivier /* migration has been cancelled while the unplug was in progress */ 10011e2077e2SLaurent Vivier 10021e2077e2SLaurent Vivier /* while the card is not ejected, we must be in "cancelling" state */ 10031e2077e2SLaurent Vivier 10041e2077e2SLaurent Vivier total = 0; 10051e2077e2SLaurent Vivier while (true) { 10061e2077e2SLaurent Vivier ret = migrate_status(qts); 10071e2077e2SLaurent Vivier 10081e2077e2SLaurent Vivier status = qdict_get_str(ret, "status"); 10091e2077e2SLaurent Vivier if (strcmp(status, "cancelled") == 0) { 10101e2077e2SLaurent Vivier qobject_unref(ret); 10111e2077e2SLaurent Vivier break; 10121e2077e2SLaurent Vivier } 10131e2077e2SLaurent Vivier g_assert_cmpstr(status, ==, "cancelling"); 10141e2077e2SLaurent Vivier g_assert(qdict_haskey(ret, "total-time")); 10151e2077e2SLaurent Vivier total = qdict_get_int(ret, "total-time"); 10161e2077e2SLaurent Vivier qobject_unref(ret); 10171e2077e2SLaurent Vivier } 10181e2077e2SLaurent Vivier 10191e2077e2SLaurent Vivier /* 10201e2077e2SLaurent Vivier * migration timeout in this case is 30 seconds 10211e2077e2SLaurent Vivier * check we exit on the timeout (ms) 10221e2077e2SLaurent Vivier */ 10231e2077e2SLaurent Vivier g_assert_cmpint(total, >, 30000); 10241e2077e2SLaurent Vivier 10251e2077e2SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 10261e2077e2SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 10271e2077e2SLaurent Vivier 10281e2077e2SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev); 10291e2077e2SLaurent Vivier machine_stop(qts); 10301e2077e2SLaurent Vivier } 10311e2077e2SLaurent Vivier 1032e1e3d321SLaurent Vivier static void test_multi_out(gconstpointer opaque) 1033e1e3d321SLaurent Vivier { 1034e1e3d321SLaurent Vivier QTestState *qts; 1035e1e3d321SLaurent Vivier QDict *resp, *args, *ret; 1036e1e3d321SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); 1037e1e3d321SLaurent Vivier const gchar *status, *expected; 1038e1e3d321SLaurent Vivier QVirtioPCIDevice *vdev0, *vdev1; 1039e1e3d321SLaurent Vivier 1040e1e3d321SLaurent Vivier qts = machine_start(BASE_MACHINE 1041e1e3d321SLaurent Vivier "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 " 1042e1e3d321SLaurent Vivier "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 " 1043e1e3d321SLaurent Vivier "-netdev user,id=hs0 " 1044e1e3d321SLaurent Vivier "-netdev user,id=hs1 " 1045e1e3d321SLaurent Vivier "-netdev user,id=hs2 " 1046e1e3d321SLaurent Vivier "-netdev user,id=hs3 ", 1047e1e3d321SLaurent Vivier 4); 1048e1e3d321SLaurent Vivier 1049e1e3d321SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 1050e1e3d321SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1051e1e3d321SLaurent Vivier check_one_card(qts, false, "standby1", MAC_STANDBY1); 1052e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1053e1e3d321SLaurent Vivier 1054e1e3d321SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 1055e1e3d321SLaurent Vivier "{'bus': 'root0'," 1056e1e3d321SLaurent Vivier "'failover': 'on'," 1057e1e3d321SLaurent Vivier "'netdev': 'hs0'," 1058e1e3d321SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 1059e1e3d321SLaurent Vivier 1060e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1061e1e3d321SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1062e1e3d321SLaurent Vivier check_one_card(qts, false, "standby1", MAC_STANDBY1); 1063e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1064e1e3d321SLaurent Vivier 1065e1e3d321SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 1066e1e3d321SLaurent Vivier "{'bus': 'root1'," 1067e1e3d321SLaurent Vivier "'failover_pair_id': 'standby0'," 1068e1e3d321SLaurent Vivier "'netdev': 'hs1'," 1069e1e3d321SLaurent Vivier "'rombar': 0," 1070e1e3d321SLaurent Vivier "'romfile': ''," 1071e1e3d321SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 1072e1e3d321SLaurent Vivier 1073e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1074e1e3d321SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1075e1e3d321SLaurent Vivier check_one_card(qts, false, "standby1", MAC_STANDBY1); 1076e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1077e1e3d321SLaurent Vivier 1078e1e3d321SLaurent Vivier vdev0 = start_virtio_net(qts, 1, 0, "standby0"); 1079e1e3d321SLaurent Vivier 1080e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1081e1e3d321SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1082e1e3d321SLaurent Vivier check_one_card(qts, false, "standby1", MAC_STANDBY1); 1083e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1084e1e3d321SLaurent Vivier 1085e1e3d321SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby1", 1086e1e3d321SLaurent Vivier "{'bus': 'root2'," 1087e1e3d321SLaurent Vivier "'failover': 'on'," 1088e1e3d321SLaurent Vivier "'netdev': 'hs2'," 1089e1e3d321SLaurent Vivier "'mac': '"MAC_STANDBY1"'}"); 1090e1e3d321SLaurent Vivier 1091e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1092e1e3d321SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1093e1e3d321SLaurent Vivier check_one_card(qts, true, "standby1", MAC_STANDBY1); 1094e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1095e1e3d321SLaurent Vivier 1096e1e3d321SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary1", 1097e1e3d321SLaurent Vivier "{'bus': 'root3'," 1098e1e3d321SLaurent Vivier "'failover_pair_id': 'standby1'," 1099e1e3d321SLaurent Vivier "'netdev': 'hs3'," 1100e1e3d321SLaurent Vivier "'rombar': 0," 1101e1e3d321SLaurent Vivier "'romfile': ''," 1102e1e3d321SLaurent Vivier "'mac': '"MAC_PRIMARY1"'}"); 1103e1e3d321SLaurent Vivier 1104e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1105e1e3d321SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1106e1e3d321SLaurent Vivier check_one_card(qts, true, "standby1", MAC_STANDBY1); 1107e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1108e1e3d321SLaurent Vivier 1109e1e3d321SLaurent Vivier vdev1 = start_virtio_net(qts, 3, 0, "standby1"); 1110e1e3d321SLaurent Vivier 1111e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1112e1e3d321SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1113e1e3d321SLaurent Vivier check_one_card(qts, true, "standby1", MAC_STANDBY1); 1114e1e3d321SLaurent Vivier check_one_card(qts, true, "primary1", MAC_PRIMARY1); 1115e1e3d321SLaurent Vivier 1116e1e3d321SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 1117e1e3d321SLaurent Vivier g_assert_nonnull(args); 1118e1e3d321SLaurent Vivier qdict_put_str(args, "uri", uri); 1119e1e3d321SLaurent Vivier 1120e1e3d321SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); 1121e1e3d321SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 1122e1e3d321SLaurent Vivier qobject_unref(resp); 1123e1e3d321SLaurent Vivier 1124e1e3d321SLaurent Vivier /* the event is sent when QEMU asks the OS to unplug the card */ 1125e1e3d321SLaurent Vivier resp = get_unplug_primary_event(qts); 1126e1e3d321SLaurent Vivier if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) { 1127e1e3d321SLaurent Vivier expected = "primary1"; 1128e1e3d321SLaurent Vivier } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) { 1129e1e3d321SLaurent Vivier expected = "primary0"; 1130e1e3d321SLaurent Vivier } else { 1131e1e3d321SLaurent Vivier g_assert_not_reached(); 1132e1e3d321SLaurent Vivier } 1133e1e3d321SLaurent Vivier qobject_unref(resp); 1134e1e3d321SLaurent Vivier 1135e1e3d321SLaurent Vivier resp = get_unplug_primary_event(qts); 1136e1e3d321SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected); 1137e1e3d321SLaurent Vivier qobject_unref(resp); 1138e1e3d321SLaurent Vivier 1139e1e3d321SLaurent Vivier /* wait the end of the migration setup phase */ 1140e1e3d321SLaurent Vivier while (true) { 1141e1e3d321SLaurent Vivier ret = migrate_status(qts); 1142e1e3d321SLaurent Vivier 1143e1e3d321SLaurent Vivier status = qdict_get_str(ret, "status"); 1144e1e3d321SLaurent Vivier if (strcmp(status, "wait-unplug") == 0) { 1145e1e3d321SLaurent Vivier qobject_unref(ret); 1146e1e3d321SLaurent Vivier break; 1147e1e3d321SLaurent Vivier } 1148e1e3d321SLaurent Vivier 1149e1e3d321SLaurent Vivier /* The migration must not start if the card is not ejected */ 1150e1e3d321SLaurent Vivier g_assert_cmpstr(status, !=, "active"); 1151e1e3d321SLaurent Vivier g_assert_cmpstr(status, !=, "completed"); 1152e1e3d321SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 1153e1e3d321SLaurent Vivier g_assert_cmpstr(status, !=, "cancelling"); 1154e1e3d321SLaurent Vivier g_assert_cmpstr(status, !=, "cancelled"); 1155e1e3d321SLaurent Vivier 1156e1e3d321SLaurent Vivier qobject_unref(ret); 1157e1e3d321SLaurent Vivier } 1158e1e3d321SLaurent Vivier 1159e1e3d321SLaurent Vivier /* OS unplugs primary1, but we must wait the second */ 1160e1e3d321SLaurent Vivier qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 1161e1e3d321SLaurent Vivier 1162e1e3d321SLaurent Vivier ret = migrate_status(qts); 1163e1e3d321SLaurent Vivier status = qdict_get_str(ret, "status"); 1164e1e3d321SLaurent Vivier g_assert_cmpstr(status, ==, "wait-unplug"); 1165e1e3d321SLaurent Vivier qobject_unref(ret); 1166e1e3d321SLaurent Vivier 1167e1e3d321SLaurent Vivier if (g_test_slow()) { 1168e1e3d321SLaurent Vivier /* check we stay in wait-unplug while the card is not ejected */ 1169e1e3d321SLaurent Vivier for (int i = 0; i < 5; i++) { 1170e1e3d321SLaurent Vivier sleep(1); 1171e1e3d321SLaurent Vivier ret = migrate_status(qts); 1172e1e3d321SLaurent Vivier status = qdict_get_str(ret, "status"); 1173e1e3d321SLaurent Vivier g_assert_cmpstr(status, ==, "wait-unplug"); 1174e1e3d321SLaurent Vivier qobject_unref(ret); 1175e1e3d321SLaurent Vivier } 1176e1e3d321SLaurent Vivier } 1177e1e3d321SLaurent Vivier 1178e1e3d321SLaurent Vivier /* OS unplugs primary0, QEMU can move from wait-unplug state */ 1179e1e3d321SLaurent Vivier qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2); 1180e1e3d321SLaurent Vivier qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); 1181e1e3d321SLaurent Vivier 1182e1e3d321SLaurent Vivier while (true) { 1183e1e3d321SLaurent Vivier ret = migrate_status(qts); 1184e1e3d321SLaurent Vivier 1185e1e3d321SLaurent Vivier status = qdict_get_str(ret, "status"); 1186e1e3d321SLaurent Vivier if (strcmp(status, "completed") == 0) { 1187e1e3d321SLaurent Vivier qobject_unref(ret); 1188e1e3d321SLaurent Vivier break; 1189e1e3d321SLaurent Vivier } 1190e1e3d321SLaurent Vivier g_assert_cmpstr(status, !=, "failed"); 1191e1e3d321SLaurent Vivier g_assert_cmpstr(status, !=, "cancelling"); 1192e1e3d321SLaurent Vivier g_assert_cmpstr(status, !=, "cancelled"); 1193e1e3d321SLaurent Vivier qobject_unref(ret); 1194e1e3d321SLaurent Vivier } 1195e1e3d321SLaurent Vivier 1196e1e3d321SLaurent Vivier qtest_qmp_eventwait(qts, "STOP"); 1197e1e3d321SLaurent Vivier 1198e1e3d321SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev0); 1199e1e3d321SLaurent Vivier qos_object_destroy((QOSGraphObject *)vdev1); 1200e1e3d321SLaurent Vivier machine_stop(qts); 1201e1e3d321SLaurent Vivier } 1202e1e3d321SLaurent Vivier 1203e1e3d321SLaurent Vivier static void test_multi_in(gconstpointer opaque) 1204e1e3d321SLaurent Vivier { 1205e1e3d321SLaurent Vivier QTestState *qts; 1206e1e3d321SLaurent Vivier QDict *resp, *args, *ret; 1207e1e3d321SLaurent Vivier g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); 1208e1e3d321SLaurent Vivier 1209e1e3d321SLaurent Vivier qts = machine_start(BASE_MACHINE 1210e1e3d321SLaurent Vivier "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 " 1211e1e3d321SLaurent Vivier "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 " 1212e1e3d321SLaurent Vivier "-netdev user,id=hs0 " 1213e1e3d321SLaurent Vivier "-netdev user,id=hs1 " 1214e1e3d321SLaurent Vivier "-netdev user,id=hs2 " 1215e1e3d321SLaurent Vivier "-netdev user,id=hs3 " 1216e1e3d321SLaurent Vivier "-incoming defer ", 1217e1e3d321SLaurent Vivier 4); 1218e1e3d321SLaurent Vivier 1219e1e3d321SLaurent Vivier check_one_card(qts, false, "standby0", MAC_STANDBY0); 1220e1e3d321SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1221e1e3d321SLaurent Vivier check_one_card(qts, false, "standby1", MAC_STANDBY1); 1222e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1223e1e3d321SLaurent Vivier 1224e1e3d321SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby0", 1225e1e3d321SLaurent Vivier "{'bus': 'root0'," 1226e1e3d321SLaurent Vivier "'failover': 'on'," 1227e1e3d321SLaurent Vivier "'netdev': 'hs0'," 1228e1e3d321SLaurent Vivier "'mac': '"MAC_STANDBY0"'}"); 1229e1e3d321SLaurent Vivier 1230e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1231e1e3d321SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1232e1e3d321SLaurent Vivier check_one_card(qts, false, "standby1", MAC_STANDBY1); 1233e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1234e1e3d321SLaurent Vivier 1235e1e3d321SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary0", 1236e1e3d321SLaurent Vivier "{'bus': 'root1'," 1237e1e3d321SLaurent Vivier "'failover_pair_id': 'standby0'," 1238e1e3d321SLaurent Vivier "'netdev': 'hs1'," 1239e1e3d321SLaurent Vivier "'rombar': 0," 1240e1e3d321SLaurent Vivier "'romfile': ''," 1241e1e3d321SLaurent Vivier "'mac': '"MAC_PRIMARY0"'}"); 1242e1e3d321SLaurent Vivier 1243e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1244e1e3d321SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1245e1e3d321SLaurent Vivier check_one_card(qts, false, "standby1", MAC_STANDBY1); 1246e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1247e1e3d321SLaurent Vivier 1248e1e3d321SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "standby1", 1249e1e3d321SLaurent Vivier "{'bus': 'root2'," 1250e1e3d321SLaurent Vivier "'failover': 'on'," 1251e1e3d321SLaurent Vivier "'netdev': 'hs2'," 1252e1e3d321SLaurent Vivier "'mac': '"MAC_STANDBY1"'}"); 1253e1e3d321SLaurent Vivier 1254e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1255e1e3d321SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1256e1e3d321SLaurent Vivier check_one_card(qts, true, "standby1", MAC_STANDBY1); 1257e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1258e1e3d321SLaurent Vivier 1259e1e3d321SLaurent Vivier qtest_qmp_device_add(qts, "virtio-net", "primary1", 1260e1e3d321SLaurent Vivier "{'bus': 'root3'," 1261e1e3d321SLaurent Vivier "'failover_pair_id': 'standby1'," 1262e1e3d321SLaurent Vivier "'netdev': 'hs3'," 1263e1e3d321SLaurent Vivier "'rombar': 0," 1264e1e3d321SLaurent Vivier "'romfile': ''," 1265e1e3d321SLaurent Vivier "'mac': '"MAC_PRIMARY1"'}"); 1266e1e3d321SLaurent Vivier 1267e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1268e1e3d321SLaurent Vivier check_one_card(qts, false, "primary0", MAC_PRIMARY0); 1269e1e3d321SLaurent Vivier check_one_card(qts, true, "standby1", MAC_STANDBY1); 1270e1e3d321SLaurent Vivier check_one_card(qts, false, "primary1", MAC_PRIMARY1); 1271e1e3d321SLaurent Vivier 1272e1e3d321SLaurent Vivier args = qdict_from_jsonf_nofail("{}"); 1273e1e3d321SLaurent Vivier g_assert_nonnull(args); 1274e1e3d321SLaurent Vivier qdict_put_str(args, "uri", uri); 1275e1e3d321SLaurent Vivier 1276e1e3d321SLaurent Vivier resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", 1277e1e3d321SLaurent Vivier args); 1278e1e3d321SLaurent Vivier g_assert(qdict_haskey(resp, "return")); 1279e1e3d321SLaurent Vivier qobject_unref(resp); 1280e1e3d321SLaurent Vivier 1281e1e3d321SLaurent Vivier resp = get_migration_event(qts); 1282e1e3d321SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup"); 1283e1e3d321SLaurent Vivier qobject_unref(resp); 1284e1e3d321SLaurent Vivier 1285e1e3d321SLaurent Vivier resp = get_failover_negociated_event(qts); 1286e1e3d321SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0"); 1287e1e3d321SLaurent Vivier qobject_unref(resp); 1288e1e3d321SLaurent Vivier 1289e1e3d321SLaurent Vivier resp = get_failover_negociated_event(qts); 1290e1e3d321SLaurent Vivier g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1"); 1291e1e3d321SLaurent Vivier qobject_unref(resp); 1292e1e3d321SLaurent Vivier 1293e1e3d321SLaurent Vivier check_one_card(qts, true, "standby0", MAC_STANDBY0); 1294e1e3d321SLaurent Vivier check_one_card(qts, true, "primary0", MAC_PRIMARY0); 1295e1e3d321SLaurent Vivier check_one_card(qts, true, "standby1", MAC_STANDBY1); 1296e1e3d321SLaurent Vivier check_one_card(qts, true, "primary1", MAC_PRIMARY1); 1297e1e3d321SLaurent Vivier 1298e1e3d321SLaurent Vivier qtest_qmp_eventwait(qts, "RESUME"); 1299e1e3d321SLaurent Vivier 1300e1e3d321SLaurent Vivier ret = migrate_status(qts); 1301e1e3d321SLaurent Vivier g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed"); 1302e1e3d321SLaurent Vivier qobject_unref(ret); 1303e1e3d321SLaurent Vivier 1304e1e3d321SLaurent Vivier machine_stop(qts); 1305e1e3d321SLaurent Vivier } 1306e1e3d321SLaurent Vivier 1307e32b96b5SLaurent Vivier int main(int argc, char **argv) 1308e32b96b5SLaurent Vivier { 1309*e63ed64cSThomas Huth gchar *tmpfile; 1310e32b96b5SLaurent Vivier int ret; 1311e32b96b5SLaurent Vivier 1312e32b96b5SLaurent Vivier g_test_init(&argc, &argv, NULL); 1313e32b96b5SLaurent Vivier 1314*e63ed64cSThomas Huth ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL); 1315*e63ed64cSThomas Huth g_assert_true(ret >= 0); 1316*e63ed64cSThomas Huth close(ret); 1317*e63ed64cSThomas Huth 1318e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/error/id", test_error_id); 1319e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie); 1320e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/on", test_on); 1321e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/on_mismatch", 1322e32b96b5SLaurent Vivier test_on_mismatch); 1323e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/off", test_off); 1324e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/params/enabled", test_enabled); 1325e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/hotplug_1", test_hotplug_1); 1326e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/hotplug_1_reverse", 1327e32b96b5SLaurent Vivier test_hotplug_1_reverse); 1328e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/hotplug_2", test_hotplug_2); 1329e32b96b5SLaurent Vivier qtest_add_func("failover-virtio-net/hotplug_2_reverse", 1330e32b96b5SLaurent Vivier test_hotplug_2_reverse); 1331e32b96b5SLaurent Vivier qtest_add_data_func("failover-virtio-net/migrate/out", tmpfile, 1332e32b96b5SLaurent Vivier test_migrate_out); 1333e32b96b5SLaurent Vivier qtest_add_data_func("failover-virtio-net/migrate/in", tmpfile, 1334e32b96b5SLaurent Vivier test_migrate_in); 13351e2077e2SLaurent Vivier qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug", 13361e2077e2SLaurent Vivier tmpfile, test_migrate_abort_wait_unplug); 13371e2077e2SLaurent Vivier qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile, 13381e2077e2SLaurent Vivier test_migrate_abort_active); 13391e2077e2SLaurent Vivier if (g_test_slow()) { 13401e2077e2SLaurent Vivier qtest_add_data_func("failover-virtio-net/migrate/abort/timeout", 13411e2077e2SLaurent Vivier tmpfile, test_migrate_abort_timeout); 13421e2077e2SLaurent Vivier } 1343e1e3d321SLaurent Vivier qtest_add_data_func("failover-virtio-net/multi/out", 1344e1e3d321SLaurent Vivier tmpfile, test_multi_out); 1345e1e3d321SLaurent Vivier qtest_add_data_func("failover-virtio-net/multi/in", 1346e1e3d321SLaurent Vivier tmpfile, test_multi_in); 1347e32b96b5SLaurent Vivier 1348e32b96b5SLaurent Vivier ret = g_test_run(); 1349e32b96b5SLaurent Vivier 1350e32b96b5SLaurent Vivier unlink(tmpfile); 1351e32b96b5SLaurent Vivier g_free(tmpfile); 1352e32b96b5SLaurent Vivier 1353e32b96b5SLaurent Vivier return ret; 1354e32b96b5SLaurent Vivier } 1355