qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

virtio-net-failover.c (63060B)


      1 /*
      2  * QTest testcase for virtio-net failover
      3  *
      4  * See docs/system/virtio-net-failover.rst
      5  *
      6  * Copyright (c) 2021 Red Hat, Inc.
      7  *
      8  * SPDX-License-Identifier: GPL-2.0-or-later
      9  */
     10 #include "qemu/osdep.h"
     11 #include "libqtest.h"
     12 #include "libqos/pci.h"
     13 #include "libqos/pci-pc.h"
     14 #include "qapi/qmp/qdict.h"
     15 #include "qapi/qmp/qlist.h"
     16 #include "qapi/qmp/qjson.h"
     17 #include "libqos/malloc-pc.h"
     18 #include "libqos/virtio-pci.h"
     19 #include "hw/pci/pci.h"
     20 
     21 #define VIRTIO_NET_F_STANDBY    62
     22 
     23 #define ACPI_PCIHP_ADDR_ICH9    0x0cc0
     24 #define PCI_EJ_BASE             0x0008
     25 #define PCI_SEL_BASE            0x0010
     26 
     27 #define BASE_MACHINE "-M q35 -nodefaults " \
     28     "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
     29     "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "
     30 
     31 #define MAC_PRIMARY0 "52:54:00:11:11:11"
     32 #define MAC_STANDBY0 "52:54:00:22:22:22"
     33 #define MAC_PRIMARY1 "52:54:00:33:33:33"
     34 #define MAC_STANDBY1 "52:54:00:44:44:44"
     35 
     36 static QGuestAllocator guest_malloc;
     37 static QPCIBus *pcibus;
     38 
     39 static QTestState *machine_start(const char *args, int numbus)
     40 {
     41     QTestState *qts;
     42     QPCIDevice *dev;
     43     int bus;
     44 
     45     qts = qtest_init(args);
     46 
     47     pc_alloc_init(&guest_malloc, qts, 0);
     48     pcibus = qpci_new_pc(qts, &guest_malloc);
     49     g_assert(qpci_secondary_buses_init(pcibus) == numbus);
     50 
     51     for (bus = 1; bus <= numbus; bus++) {
     52         dev = qpci_device_find(pcibus, QPCI_DEVFN(bus, 0));
     53         g_assert_nonnull(dev);
     54 
     55         qpci_device_enable(dev);
     56         qpci_iomap(dev, 4, NULL);
     57 
     58         g_free(dev);
     59     }
     60 
     61     return qts;
     62 }
     63 
     64 static void machine_stop(QTestState *qts)
     65 {
     66     qpci_free_pc(pcibus);
     67     alloc_destroy(&guest_malloc);
     68     qtest_quit(qts);
     69 }
     70 
     71 static void test_error_id(void)
     72 {
     73     QTestState *qts;
     74     QDict *resp;
     75     QDict *err;
     76 
     77     qts = machine_start(BASE_MACHINE
     78                         "-device virtio-net,bus=root0,id=standby0,failover=on",
     79                         2);
     80 
     81     resp = qtest_qmp(qts, "{'execute': 'device_add',"
     82                           "'arguments': {"
     83                           "'driver': 'virtio-net',"
     84                           "'bus': 'root1',"
     85                           "'failover_pair_id': 'standby0'"
     86                           "} }");
     87     g_assert(qdict_haskey(resp, "error"));
     88 
     89     err = qdict_get_qdict(resp, "error");
     90     g_assert(qdict_haskey(err, "desc"));
     91 
     92     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
     93                     "Device with failover_pair_id needs to have id");
     94 
     95     qobject_unref(resp);
     96 
     97     machine_stop(qts);
     98 }
     99 
    100 static void test_error_pcie(void)
    101 {
    102     QTestState *qts;
    103     QDict *resp;
    104     QDict *err;
    105 
    106     qts = machine_start(BASE_MACHINE
    107                         "-device virtio-net,bus=root0,id=standby0,failover=on",
    108                         2);
    109 
    110     resp = qtest_qmp(qts, "{'execute': 'device_add',"
    111                           "'arguments': {"
    112                           "'driver': 'virtio-net',"
    113                           "'id': 'primary0',"
    114                           "'bus': 'pcie.0',"
    115                           "'failover_pair_id': 'standby0'"
    116                           "} }");
    117     g_assert(qdict_haskey(resp, "error"));
    118 
    119     err = qdict_get_qdict(resp, "error");
    120     g_assert(qdict_haskey(err, "desc"));
    121 
    122     g_assert_cmpstr(qdict_get_str(err, "desc"), ==,
    123                     "Bus 'pcie.0' does not support hotplugging");
    124 
    125     qobject_unref(resp);
    126 
    127     machine_stop(qts);
    128 }
    129 
    130 static QDict *find_device(QDict *bus, const char *name)
    131 {
    132     const QObject *obj;
    133     QList *devices;
    134     QList *list;
    135 
    136     devices = qdict_get_qlist(bus, "devices");
    137     if (devices == NULL) {
    138         return NULL;
    139     }
    140 
    141     list = qlist_copy(devices);
    142     while ((obj = qlist_pop(list))) {
    143         QDict *device;
    144 
    145         device = qobject_to(QDict, obj);
    146 
    147         if (qdict_haskey(device, "pci_bridge")) {
    148             QDict *bridge;
    149             QDict *bridge_device;
    150 
    151             bridge = qdict_get_qdict(device, "pci_bridge");
    152 
    153             if (qdict_haskey(bridge, "devices")) {
    154                 bridge_device = find_device(bridge, name);
    155                 if (bridge_device) {
    156                     qobject_unref(device);
    157                     qobject_unref(list);
    158                     return bridge_device;
    159                 }
    160             }
    161         }
    162 
    163         if (!qdict_haskey(device, "qdev_id")) {
    164             qobject_unref(device);
    165             continue;
    166         }
    167 
    168         if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) {
    169             qobject_unref(list);
    170             return device;
    171         }
    172         qobject_unref(device);
    173     }
    174     qobject_unref(list);
    175 
    176     return NULL;
    177 }
    178 
    179 static QDict *get_bus(QTestState *qts, int num)
    180 {
    181     QObject *obj;
    182     QDict *resp;
    183     QList *ret;
    184 
    185     resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }");
    186     g_assert(qdict_haskey(resp, "return"));
    187 
    188     ret = qdict_get_qlist(resp, "return");
    189     g_assert_nonnull(ret);
    190 
    191     while ((obj = qlist_pop(ret))) {
    192         QDict *bus;
    193 
    194         bus = qobject_to(QDict, obj);
    195         if (!qdict_haskey(bus, "bus")) {
    196             qobject_unref(bus);
    197             continue;
    198         }
    199         if (qdict_get_int(bus, "bus") == num) {
    200             qobject_unref(resp);
    201             return bus;
    202         }
    203         qobject_ref(bus);
    204     }
    205     qobject_unref(resp);
    206 
    207     return NULL;
    208 }
    209 
    210 static char *get_mac(QTestState *qts, const char *name)
    211 {
    212     QDict *resp;
    213     char *mac;
    214 
    215     resp = qtest_qmp(qts, "{ 'execute': 'qom-get', "
    216                      "'arguments': { "
    217                      "'path': %s, "
    218                      "'property': 'mac' } }", name);
    219 
    220     g_assert(qdict_haskey(resp, "return"));
    221 
    222     mac = g_strdup(qdict_get_str(resp, "return"));
    223 
    224     qobject_unref(resp);
    225 
    226     return mac;
    227 }
    228 
    229 #define check_one_card(qts, present, id, mac)                   \
    230 do {                                                            \
    231     QDict *device;                                              \
    232     QDict *bus;                                                 \
    233     char *addr;                                                 \
    234     bus = get_bus(qts, 0);                                      \
    235     device = find_device(bus, id);                              \
    236     if (present) {                                              \
    237         char *path;                                             \
    238         g_assert_nonnull(device);                               \
    239         qobject_unref(device);                                  \
    240         path = g_strdup_printf("/machine/peripheral/%s", id);   \
    241         addr = get_mac(qts, path);                              \
    242         g_free(path);                                           \
    243         g_assert_cmpstr(mac, ==, addr);                         \
    244         g_free(addr);                                           \
    245     } else {                                                    \
    246        g_assert_null(device);                                   \
    247     }                                                           \
    248     qobject_unref(bus);                                         \
    249 } while (0)
    250 
    251 static QDict *get_failover_negociated_event(QTestState *qts)
    252 {
    253     QDict *resp;
    254     QDict *data;
    255 
    256     resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED");
    257     g_assert(qdict_haskey(resp, "data"));
    258 
    259     data = qdict_get_qdict(resp, "data");
    260     g_assert(qdict_haskey(data, "device-id"));
    261     qobject_ref(data);
    262     qobject_unref(resp);
    263 
    264     return data;
    265 }
    266 
    267 static QVirtioPCIDevice *start_virtio_net_internal(QTestState *qts,
    268                                                    int bus, int slot,
    269                                                    uint64_t *features)
    270 {
    271     QVirtioPCIDevice *dev;
    272     QPCIAddress addr;
    273 
    274     addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0);
    275     dev = virtio_pci_new(pcibus, &addr);
    276     g_assert_nonnull(dev);
    277     qvirtio_pci_device_enable(dev);
    278     qvirtio_start_device(&dev->vdev);
    279     *features &= qvirtio_get_features(&dev->vdev);
    280     qvirtio_set_features(&dev->vdev, *features);
    281     qvirtio_set_driver_ok(&dev->vdev);
    282     return dev;
    283 }
    284 
    285 static QVirtioPCIDevice *start_virtio_net(QTestState *qts, int bus, int slot,
    286                                           const char *id, bool failover)
    287 {
    288     QVirtioPCIDevice *dev;
    289     uint64_t features;
    290 
    291     features = ~(QVIRTIO_F_BAD_FEATURE |
    292                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
    293                  (1ull << VIRTIO_RING_F_EVENT_IDX));
    294 
    295     dev = start_virtio_net_internal(qts, bus, slot, &features);
    296 
    297     g_assert(!!(features & (1ull << VIRTIO_NET_F_STANDBY)) == failover);
    298 
    299     if (failover) {
    300         QDict *resp;
    301 
    302         resp = get_failover_negociated_event(qts);
    303         g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, id);
    304         qobject_unref(resp);
    305     }
    306 
    307     return dev;
    308 }
    309 
    310 static void test_on(void)
    311 {
    312     QTestState *qts;
    313 
    314     qts = machine_start(BASE_MACHINE
    315                         "-netdev user,id=hs0 "
    316                         "-device virtio-net,bus=root0,id=standby0,"
    317                         "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
    318                         "-netdev user,id=hs1 "
    319                         "-device virtio-net,bus=root1,id=primary0,"
    320                         "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
    321                         2);
    322 
    323     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    324     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    325 
    326     machine_stop(qts);
    327 }
    328 
    329 static void test_on_mismatch(void)
    330 {
    331     QTestState *qts;
    332     QVirtioPCIDevice *vdev;
    333 
    334     qts = machine_start(BASE_MACHINE
    335                      "-netdev user,id=hs0 "
    336                      "-device virtio-net,bus=root0,id=standby0,"
    337                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
    338                      "-netdev user,id=hs1 "
    339                      "-device virtio-net,bus=root1,id=primary0,"
    340                      "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY0,
    341                      2);
    342 
    343     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    344     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    345 
    346     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
    347 
    348     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    349     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    350 
    351     qos_object_destroy((QOSGraphObject *)vdev);
    352     machine_stop(qts);
    353 }
    354 
    355 static void test_off(void)
    356 {
    357     QTestState *qts;
    358     QVirtioPCIDevice *vdev;
    359 
    360     qts = machine_start(BASE_MACHINE
    361                      "-netdev user,id=hs0 "
    362                      "-device virtio-net,bus=root0,id=standby0,"
    363                      "failover=off,netdev=hs0,mac="MAC_STANDBY0" "
    364                      "-netdev user,id=hs1 "
    365                      "-device virtio-net,bus=root1,id=primary0,"
    366                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0,
    367                      2);
    368 
    369     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    370     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    371 
    372     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
    373 
    374     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    375     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    376 
    377     qos_object_destroy((QOSGraphObject *)vdev);
    378     machine_stop(qts);
    379 }
    380 
    381 static void test_enabled(void)
    382 {
    383     QTestState *qts;
    384     QVirtioPCIDevice *vdev;
    385 
    386     qts = machine_start(BASE_MACHINE
    387                      "-netdev user,id=hs0 "
    388                      "-device virtio-net,bus=root0,id=standby0,"
    389                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
    390                      "-netdev user,id=hs1 "
    391                      "-device virtio-net,bus=root1,id=primary0,"
    392                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
    393                      2);
    394 
    395     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    396     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    397 
    398     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
    399 
    400     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    401     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    402 
    403     qos_object_destroy((QOSGraphObject *)vdev);
    404     machine_stop(qts);
    405 }
    406 
    407 static void test_guest_off(void)
    408 {
    409     QTestState *qts;
    410     QVirtioPCIDevice *vdev;
    411     uint64_t features;
    412 
    413     qts = machine_start(BASE_MACHINE
    414                      "-netdev user,id=hs0 "
    415                      "-device virtio-net,bus=root0,id=standby0,"
    416                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
    417                      "-netdev user,id=hs1 "
    418                      "-device virtio-net,bus=root1,id=primary0,"
    419                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
    420                      2);
    421 
    422     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    423     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    424 
    425     features = ~(QVIRTIO_F_BAD_FEATURE |
    426                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
    427                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
    428                  (1ull << VIRTIO_NET_F_STANDBY));
    429 
    430     vdev = start_virtio_net_internal(qts, 1, 0, &features);
    431 
    432     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    433     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    434 
    435     qos_object_destroy((QOSGraphObject *)vdev);
    436     machine_stop(qts);
    437 }
    438 
    439 static void test_hotplug_1(void)
    440 {
    441     QTestState *qts;
    442     QVirtioPCIDevice *vdev;
    443 
    444     qts = machine_start(BASE_MACHINE
    445                      "-netdev user,id=hs0 "
    446                      "-device virtio-net,bus=root0,id=standby0,"
    447                      "failover=on,netdev=hs0,mac="MAC_STANDBY0" "
    448                      "-netdev user,id=hs1 ", 2);
    449 
    450     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    451     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    452 
    453     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
    454 
    455     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    456     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    457 
    458     qtest_qmp_device_add(qts, "virtio-net", "primary0",
    459                          "{'bus': 'root1',"
    460                          "'failover_pair_id': 'standby0',"
    461                          "'netdev': 'hs1',"
    462                          "'mac': '"MAC_PRIMARY0"'}");
    463 
    464     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    465     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    466 
    467     qos_object_destroy((QOSGraphObject *)vdev);
    468     machine_stop(qts);
    469 }
    470 
    471 static void test_hotplug_1_reverse(void)
    472 {
    473     QTestState *qts;
    474     QVirtioPCIDevice *vdev;
    475 
    476     qts = machine_start(BASE_MACHINE
    477                      "-netdev user,id=hs0 "
    478                      "-netdev user,id=hs1 "
    479                      "-device virtio-net,bus=root1,id=primary0,"
    480                      "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY0" ",
    481                      2);
    482 
    483     check_one_card(qts, false, "standby0", MAC_STANDBY0);
    484     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    485 
    486     qtest_qmp_device_add(qts, "virtio-net", "standby0",
    487                          "{'bus': 'root0',"
    488                          "'failover': 'on',"
    489                          "'netdev': 'hs0',"
    490                          "'mac': '"MAC_STANDBY0"'}");
    491 
    492     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    493     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    494 
    495     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
    496 
    497     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    498     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    499 
    500     qos_object_destroy((QOSGraphObject *)vdev);
    501     machine_stop(qts);
    502 }
    503 
    504 static void test_hotplug_2(void)
    505 {
    506     QTestState *qts;
    507     QVirtioPCIDevice *vdev;
    508 
    509     qts = machine_start(BASE_MACHINE
    510                      "-netdev user,id=hs0 "
    511                      "-netdev user,id=hs1 ",
    512                      2);
    513 
    514     check_one_card(qts, false, "standby0", MAC_STANDBY0);
    515     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    516 
    517     qtest_qmp_device_add(qts, "virtio-net", "standby0",
    518                          "{'bus': 'root0',"
    519                          "'failover': 'on',"
    520                          "'netdev': 'hs0',"
    521                          "'mac': '"MAC_STANDBY0"'}");
    522 
    523     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    524     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    525 
    526     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
    527 
    528     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    529     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    530 
    531     qtest_qmp_device_add(qts, "virtio-net", "primary0",
    532                          "{'bus': 'root1',"
    533                          "'failover_pair_id': 'standby0',"
    534                          "'netdev': 'hs1',"
    535                          "'mac': '"MAC_PRIMARY0"'}");
    536 
    537     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    538     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    539 
    540     qos_object_destroy((QOSGraphObject *)vdev);
    541     machine_stop(qts);
    542 }
    543 
    544 static void test_hotplug_2_reverse(void)
    545 {
    546     QTestState *qts;
    547     QVirtioPCIDevice *vdev;
    548 
    549     qts = machine_start(BASE_MACHINE
    550                      "-netdev user,id=hs0 "
    551                      "-netdev user,id=hs1 ",
    552                      2);
    553 
    554     check_one_card(qts, false, "standby0", MAC_STANDBY0);
    555     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    556 
    557     qtest_qmp_device_add(qts, "virtio-net", "primary0",
    558                          "{'bus': 'root1',"
    559                          "'failover_pair_id': 'standby0',"
    560                          "'netdev': 'hs1',"
    561                          "'mac': '"MAC_PRIMARY0"'}");
    562 
    563     check_one_card(qts, false, "standby0", MAC_STANDBY0);
    564     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    565 
    566     qtest_qmp_device_add(qts, "virtio-net", "standby0",
    567                          "{'bus': 'root0',"
    568                          "'failover': 'on',"
    569                          "'netdev': 'hs0',"
    570                          "'rombar': 0,"
    571                          "'romfile': '',"
    572                          "'mac': '"MAC_STANDBY0"'}");
    573 
    574     /*
    575      * XXX: sounds like a bug:
    576      * The primary should be hidden until the virtio-net driver
    577      * negotiates the VIRTIO_NET_F_STANDBY feature by start_virtio_net()
    578      */
    579     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    580     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    581 
    582     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
    583 
    584     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    585     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    586 
    587     qos_object_destroy((QOSGraphObject *)vdev);
    588     machine_stop(qts);
    589 }
    590 
    591 #ifndef _WIN32
    592 static QDict *migrate_status(QTestState *qts)
    593 {
    594     QDict *resp, *ret;
    595 
    596     resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
    597     g_assert(qdict_haskey(resp, "return"));
    598 
    599     ret = qdict_get_qdict(resp, "return");
    600     g_assert(qdict_haskey(ret, "status"));
    601     qobject_ref(ret);
    602     qobject_unref(resp);
    603 
    604     return ret;
    605 }
    606 
    607 static QDict *get_unplug_primary_event(QTestState *qts)
    608 {
    609     QDict *resp;
    610     QDict *data;
    611 
    612     resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
    613     g_assert(qdict_haskey(resp, "data"));
    614 
    615     data = qdict_get_qdict(resp, "data");
    616     g_assert(qdict_haskey(data, "device-id"));
    617     qobject_ref(data);
    618     qobject_unref(resp);
    619 
    620     return data;
    621 }
    622 
    623 static void test_migrate_out(gconstpointer opaque)
    624 {
    625     QTestState *qts;
    626     QDict *resp, *args, *ret;
    627     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
    628     const gchar *status;
    629     QVirtioPCIDevice *vdev;
    630 
    631     qts = machine_start(BASE_MACHINE
    632                      "-netdev user,id=hs0 "
    633                      "-netdev user,id=hs1 ",
    634                      2);
    635 
    636     check_one_card(qts, false, "standby0", MAC_STANDBY0);
    637     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    638 
    639     qtest_qmp_device_add(qts, "virtio-net", "standby0",
    640                          "{'bus': 'root0',"
    641                          "'failover': 'on',"
    642                          "'netdev': 'hs0',"
    643                          "'mac': '"MAC_STANDBY0"'}");
    644 
    645     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    646     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    647 
    648     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
    649 
    650     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    651     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    652 
    653     qtest_qmp_device_add(qts, "virtio-net", "primary0",
    654                          "{'bus': 'root1',"
    655                          "'failover_pair_id': 'standby0',"
    656                          "'netdev': 'hs1',"
    657                          "'rombar': 0,"
    658                          "'romfile': '',"
    659                          "'mac': '"MAC_PRIMARY0"'}");
    660 
    661     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    662     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    663 
    664     args = qdict_from_jsonf_nofail("{}");
    665     g_assert_nonnull(args);
    666     qdict_put_str(args, "uri", uri);
    667 
    668     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
    669     g_assert(qdict_haskey(resp, "return"));
    670     qobject_unref(resp);
    671 
    672     /* the event is sent when QEMU asks the OS to unplug the card */
    673     resp = get_unplug_primary_event(qts);
    674     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
    675     qobject_unref(resp);
    676 
    677     /* wait the end of the migration setup phase */
    678     while (true) {
    679         ret = migrate_status(qts);
    680 
    681         status = qdict_get_str(ret, "status");
    682         if (strcmp(status, "wait-unplug") == 0) {
    683             qobject_unref(ret);
    684             break;
    685         }
    686 
    687         /* The migration must not start if the card is not ejected */
    688         g_assert_cmpstr(status, !=, "active");
    689         g_assert_cmpstr(status, !=, "completed");
    690         g_assert_cmpstr(status, !=, "failed");
    691         g_assert_cmpstr(status, !=, "cancelling");
    692         g_assert_cmpstr(status, !=, "cancelled");
    693 
    694         qobject_unref(ret);
    695     }
    696 
    697     if (g_test_slow()) {
    698         /* check we stay in wait-unplug while the card is not ejected */
    699         for (int i = 0; i < 5; i++) {
    700             sleep(1);
    701             ret = migrate_status(qts);
    702             status = qdict_get_str(ret, "status");
    703             g_assert_cmpstr(status, ==, "wait-unplug");
    704             qobject_unref(ret);
    705         }
    706     }
    707 
    708     /* OS unplugs the cards, QEMU can move from wait-unplug state */
    709     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
    710 
    711     while (true) {
    712         ret = migrate_status(qts);
    713 
    714         status = qdict_get_str(ret, "status");
    715         if (strcmp(status, "completed") == 0) {
    716             qobject_unref(ret);
    717             break;
    718         }
    719         g_assert_cmpstr(status, !=, "failed");
    720         g_assert_cmpstr(status, !=, "cancelling");
    721         g_assert_cmpstr(status, !=, "cancelled");
    722         qobject_unref(ret);
    723     }
    724 
    725     qtest_qmp_eventwait(qts, "STOP");
    726 
    727     /*
    728      * in fact, the card is ejected from the point of view of kernel
    729      * but not really from QEMU to be able to hotplug it back if
    730      * migration fails. So we can't check that:
    731      *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
    732      *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    733      */
    734 
    735     qos_object_destroy((QOSGraphObject *)vdev);
    736     machine_stop(qts);
    737 }
    738 
    739 static QDict *get_migration_event(QTestState *qts)
    740 {
    741     QDict *resp;
    742     QDict *data;
    743 
    744     resp = qtest_qmp_eventwait_ref(qts, "MIGRATION");
    745     g_assert(qdict_haskey(resp, "data"));
    746 
    747     data = qdict_get_qdict(resp, "data");
    748     g_assert(qdict_haskey(data, "status"));
    749     qobject_ref(data);
    750     qobject_unref(resp);
    751 
    752     return data;
    753 }
    754 
    755 static void test_migrate_in(gconstpointer opaque)
    756 {
    757     QTestState *qts;
    758     QDict *resp, *args, *ret;
    759     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
    760 
    761     qts = machine_start(BASE_MACHINE
    762                      "-netdev user,id=hs0 "
    763                      "-netdev user,id=hs1 "
    764                      "-incoming defer ",
    765                      2);
    766 
    767     check_one_card(qts, false, "standby0", MAC_STANDBY0);
    768     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    769 
    770     qtest_qmp_device_add(qts, "virtio-net", "standby0",
    771                          "{'bus': 'root0',"
    772                          "'failover': 'on',"
    773                          "'netdev': 'hs0',"
    774                          "'mac': '"MAC_STANDBY0"'}");
    775 
    776     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    777     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    778 
    779     qtest_qmp_device_add(qts, "virtio-net", "primary0",
    780                          "{'bus': 'root1',"
    781                          "'failover_pair_id': 'standby0',"
    782                          "'netdev': 'hs1',"
    783                          "'rombar': 0,"
    784                          "'romfile': '',"
    785                          "'mac': '"MAC_PRIMARY0"'}");
    786 
    787     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    788     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    789 
    790     args = qdict_from_jsonf_nofail("{}");
    791     g_assert_nonnull(args);
    792     qdict_put_str(args, "uri", uri);
    793 
    794     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
    795                      args);
    796     g_assert(qdict_haskey(resp, "return"));
    797     qobject_unref(resp);
    798 
    799     resp = get_migration_event(qts);
    800     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
    801     qobject_unref(resp);
    802 
    803     resp = get_failover_negociated_event(qts);
    804     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
    805     qobject_unref(resp);
    806 
    807     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    808     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    809 
    810     qtest_qmp_eventwait(qts, "RESUME");
    811 
    812     ret = migrate_status(qts);
    813     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
    814     qobject_unref(ret);
    815 
    816     machine_stop(qts);
    817 }
    818 
    819 static void test_off_migrate_out(gconstpointer opaque)
    820 {
    821     QTestState *qts;
    822     QDict *resp, *args, *ret;
    823     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
    824     const gchar *status;
    825     QVirtioPCIDevice *vdev;
    826 
    827     qts = machine_start(BASE_MACHINE
    828                      "-netdev user,id=hs0 "
    829                      "-netdev user,id=hs1 ",
    830                      2);
    831 
    832     check_one_card(qts, false, "standby0", MAC_STANDBY0);
    833     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    834 
    835     qtest_qmp_device_add(qts, "virtio-net", "standby0",
    836                          "{'bus': 'root0',"
    837                          "'failover': 'off',"
    838                          "'netdev': 'hs0',"
    839                          "'mac': '"MAC_STANDBY0"'}");
    840 
    841     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    842     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    843 
    844     qtest_qmp_device_add(qts, "virtio-net", "primary0",
    845                          "{'bus': 'root1',"
    846                          "'failover_pair_id': 'standby0',"
    847                          "'netdev': 'hs1',"
    848                          "'rombar': 0,"
    849                          "'romfile': '',"
    850                          "'mac': '"MAC_PRIMARY0"'}");
    851 
    852     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    853     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    854 
    855     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
    856 
    857     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    858     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    859 
    860     args = qdict_from_jsonf_nofail("{}");
    861     g_assert_nonnull(args);
    862     qdict_put_str(args, "uri", uri);
    863 
    864     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
    865     g_assert(qdict_haskey(resp, "return"));
    866     qobject_unref(resp);
    867 
    868     while (true) {
    869         ret = migrate_status(qts);
    870 
    871         status = qdict_get_str(ret, "status");
    872         if (strcmp(status, "completed") == 0) {
    873             qobject_unref(ret);
    874             break;
    875         }
    876         g_assert_cmpstr(status, !=, "failed");
    877         g_assert_cmpstr(status, !=, "cancelling");
    878         g_assert_cmpstr(status, !=, "cancelled");
    879         qobject_unref(ret);
    880     }
    881 
    882     qtest_qmp_eventwait(qts, "STOP");
    883 
    884     qos_object_destroy((QOSGraphObject *)vdev);
    885     machine_stop(qts);
    886 }
    887 
    888 static void test_off_migrate_in(gconstpointer opaque)
    889 {
    890     QTestState *qts;
    891     QDict *resp, *args, *ret;
    892     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
    893 
    894     qts = machine_start(BASE_MACHINE
    895                      "-netdev user,id=hs0 "
    896                      "-netdev user,id=hs1 "
    897                      "-incoming defer ",
    898                      2);
    899 
    900     check_one_card(qts, false, "standby0", MAC_STANDBY0);
    901     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    902 
    903     qtest_qmp_device_add(qts, "virtio-net", "standby0",
    904                          "{'bus': 'root0',"
    905                          "'failover': 'off',"
    906                          "'netdev': 'hs0',"
    907                          "'mac': '"MAC_STANDBY0"'}");
    908 
    909     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    910     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    911 
    912     qtest_qmp_device_add(qts, "virtio-net", "primary0",
    913                          "{'bus': 'root1',"
    914                          "'failover_pair_id': 'standby0',"
    915                          "'netdev': 'hs1',"
    916                          "'rombar': 0,"
    917                          "'romfile': '',"
    918                          "'mac': '"MAC_PRIMARY0"'}");
    919 
    920     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    921     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    922 
    923     args = qdict_from_jsonf_nofail("{}");
    924     g_assert_nonnull(args);
    925     qdict_put_str(args, "uri", uri);
    926 
    927     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
    928                      args);
    929     g_assert(qdict_haskey(resp, "return"));
    930     qobject_unref(resp);
    931 
    932     resp = get_migration_event(qts);
    933     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
    934     qobject_unref(resp);
    935 
    936     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    937     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
    938 
    939     qtest_qmp_eventwait(qts, "RESUME");
    940 
    941     ret = migrate_status(qts);
    942     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
    943     qobject_unref(ret);
    944 
    945     machine_stop(qts);
    946 }
    947 
    948 static void test_guest_off_migrate_out(gconstpointer opaque)
    949 {
    950     QTestState *qts;
    951     QDict *resp, *args, *ret;
    952     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
    953     const gchar *status;
    954     QVirtioPCIDevice *vdev;
    955     uint64_t features;
    956 
    957     qts = machine_start(BASE_MACHINE
    958                      "-netdev user,id=hs0 "
    959                      "-netdev user,id=hs1 ",
    960                      2);
    961 
    962     check_one_card(qts, false, "standby0", MAC_STANDBY0);
    963     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    964 
    965     qtest_qmp_device_add(qts, "virtio-net", "standby0",
    966                          "{'bus': 'root0',"
    967                          "'failover': 'on',"
    968                          "'netdev': 'hs0',"
    969                          "'mac': '"MAC_STANDBY0"'}");
    970 
    971     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    972     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    973 
    974     qtest_qmp_device_add(qts, "virtio-net", "primary0",
    975                          "{'bus': 'root1',"
    976                          "'failover_pair_id': 'standby0',"
    977                          "'netdev': 'hs1',"
    978                          "'rombar': 0,"
    979                          "'romfile': '',"
    980                          "'mac': '"MAC_PRIMARY0"'}");
    981 
    982     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    983     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    984 
    985     features = ~(QVIRTIO_F_BAD_FEATURE |
    986                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
    987                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
    988                  (1ull << VIRTIO_NET_F_STANDBY));
    989 
    990     vdev = start_virtio_net_internal(qts, 1, 0, &features);
    991 
    992     check_one_card(qts, true, "standby0", MAC_STANDBY0);
    993     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
    994 
    995     args = qdict_from_jsonf_nofail("{}");
    996     g_assert_nonnull(args);
    997     qdict_put_str(args, "uri", uri);
    998 
    999     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
   1000     g_assert(qdict_haskey(resp, "return"));
   1001     qobject_unref(resp);
   1002 
   1003     while (true) {
   1004         ret = migrate_status(qts);
   1005 
   1006         status = qdict_get_str(ret, "status");
   1007         if (strcmp(status, "completed") == 0) {
   1008             qobject_unref(ret);
   1009             break;
   1010         }
   1011         g_assert_cmpstr(status, !=, "failed");
   1012         g_assert_cmpstr(status, !=, "cancelling");
   1013         g_assert_cmpstr(status, !=, "cancelled");
   1014         qobject_unref(ret);
   1015     }
   1016 
   1017     qtest_qmp_eventwait(qts, "STOP");
   1018 
   1019     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1020     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1021 
   1022     qos_object_destroy((QOSGraphObject *)vdev);
   1023     machine_stop(qts);
   1024 }
   1025 
   1026 static void test_guest_off_migrate_in(gconstpointer opaque)
   1027 {
   1028     QTestState *qts;
   1029     QDict *resp, *args, *ret;
   1030     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
   1031 
   1032     qts = machine_start(BASE_MACHINE
   1033                      "-netdev user,id=hs0 "
   1034                      "-netdev user,id=hs1 "
   1035                      "-incoming defer ",
   1036                      2);
   1037 
   1038     check_one_card(qts, false, "standby0", MAC_STANDBY0);
   1039     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1040 
   1041     qtest_qmp_device_add(qts, "virtio-net", "standby0",
   1042                          "{'bus': 'root0',"
   1043                          "'failover': 'on',"
   1044                          "'netdev': 'hs0',"
   1045                          "'mac': '"MAC_STANDBY0"'}");
   1046 
   1047     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1048     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1049 
   1050     qtest_qmp_device_add(qts, "virtio-net", "primary0",
   1051                          "{'bus': 'root1',"
   1052                          "'failover_pair_id': 'standby0',"
   1053                          "'netdev': 'hs1',"
   1054                          "'rombar': 0,"
   1055                          "'romfile': '',"
   1056                          "'mac': '"MAC_PRIMARY0"'}");
   1057 
   1058     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1059     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1060 
   1061     args = qdict_from_jsonf_nofail("{}");
   1062     g_assert_nonnull(args);
   1063     qdict_put_str(args, "uri", uri);
   1064 
   1065     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
   1066                      args);
   1067     g_assert(qdict_haskey(resp, "return"));
   1068     qobject_unref(resp);
   1069 
   1070     resp = get_migration_event(qts);
   1071     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
   1072     qobject_unref(resp);
   1073 
   1074     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1075     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1076 
   1077     qtest_qmp_eventwait(qts, "RESUME");
   1078 
   1079     ret = migrate_status(qts);
   1080     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
   1081     qobject_unref(ret);
   1082 
   1083     machine_stop(qts);
   1084 }
   1085 
   1086 static void test_migrate_guest_off_abort(gconstpointer opaque)
   1087 {
   1088     QTestState *qts;
   1089     QDict *resp, *args, *ret;
   1090     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
   1091     const gchar *status;
   1092     QVirtioPCIDevice *vdev;
   1093     uint64_t features;
   1094 
   1095     qts = machine_start(BASE_MACHINE
   1096                      "-netdev user,id=hs0 "
   1097                      "-netdev user,id=hs1 ",
   1098                      2);
   1099 
   1100     check_one_card(qts, false, "standby0", MAC_STANDBY0);
   1101     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1102 
   1103     qtest_qmp_device_add(qts, "virtio-net", "standby0",
   1104                          "{'bus': 'root0',"
   1105                          "'failover': 'on',"
   1106                          "'netdev': 'hs0',"
   1107                          "'mac': '"MAC_STANDBY0"'}");
   1108 
   1109     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1110     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1111 
   1112     qtest_qmp_device_add(qts, "virtio-net", "primary0",
   1113                          "{'bus': 'root1',"
   1114                          "'failover_pair_id': 'standby0',"
   1115                          "'netdev': 'hs1',"
   1116                          "'rombar': 0,"
   1117                          "'romfile': '',"
   1118                          "'mac': '"MAC_PRIMARY0"'}");
   1119 
   1120     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1121     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1122 
   1123     features = ~(QVIRTIO_F_BAD_FEATURE |
   1124                  (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
   1125                  (1ull << VIRTIO_RING_F_EVENT_IDX) |
   1126                  (1ull << VIRTIO_NET_F_STANDBY));
   1127 
   1128     vdev = start_virtio_net_internal(qts, 1, 0, &features);
   1129 
   1130     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1131     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1132 
   1133     args = qdict_from_jsonf_nofail("{}");
   1134     g_assert_nonnull(args);
   1135     qdict_put_str(args, "uri", uri);
   1136 
   1137     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
   1138     g_assert(qdict_haskey(resp, "return"));
   1139     qobject_unref(resp);
   1140 
   1141     while (true) {
   1142         ret = migrate_status(qts);
   1143 
   1144         status = qdict_get_str(ret, "status");
   1145         if (strcmp(status, "completed") == 0) {
   1146             g_test_skip("Failed to cancel the migration");
   1147             qobject_unref(ret);
   1148             goto out;
   1149         }
   1150         if (strcmp(status, "active") == 0) {
   1151             qobject_unref(ret);
   1152             break;
   1153         }
   1154         g_assert_cmpstr(status, !=, "failed");
   1155         qobject_unref(ret);
   1156     }
   1157 
   1158     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
   1159     g_assert(qdict_haskey(resp, "return"));
   1160     qobject_unref(resp);
   1161 
   1162     while (true) {
   1163         ret = migrate_status(qts);
   1164         status = qdict_get_str(ret, "status");
   1165         if (strcmp(status, "completed") == 0) {
   1166             g_test_skip("Failed to cancel the migration");
   1167             qobject_unref(ret);
   1168             goto out;
   1169         }
   1170         if (strcmp(status, "cancelled") == 0) {
   1171             qobject_unref(ret);
   1172             break;
   1173         }
   1174         g_assert_cmpstr(status, !=, "failed");
   1175         g_assert_cmpstr(status, !=, "active");
   1176         qobject_unref(ret);
   1177     }
   1178 
   1179     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1180     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1181 
   1182 out:
   1183     qos_object_destroy((QOSGraphObject *)vdev);
   1184     machine_stop(qts);
   1185 }
   1186 
   1187 static void test_migrate_abort_wait_unplug(gconstpointer opaque)
   1188 {
   1189     QTestState *qts;
   1190     QDict *resp, *args, *ret;
   1191     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
   1192     const gchar *status;
   1193     QVirtioPCIDevice *vdev;
   1194 
   1195     qts = machine_start(BASE_MACHINE
   1196                      "-netdev user,id=hs0 "
   1197                      "-netdev user,id=hs1 ",
   1198                      2);
   1199 
   1200     check_one_card(qts, false, "standby0", MAC_STANDBY0);
   1201     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1202 
   1203     qtest_qmp_device_add(qts, "virtio-net", "standby0",
   1204                          "{'bus': 'root0',"
   1205                          "'failover': 'on',"
   1206                          "'netdev': 'hs0',"
   1207                          "'mac': '"MAC_STANDBY0"'}");
   1208 
   1209     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1210     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1211 
   1212     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
   1213 
   1214     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1215     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1216 
   1217     qtest_qmp_device_add(qts, "virtio-net", "primary0",
   1218                          "{'bus': 'root1',"
   1219                          "'failover_pair_id': 'standby0',"
   1220                          "'netdev': 'hs1',"
   1221                          "'rombar': 0,"
   1222                          "'romfile': '',"
   1223                          "'mac': '"MAC_PRIMARY0"'}");
   1224 
   1225     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1226     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1227 
   1228     args = qdict_from_jsonf_nofail("{}");
   1229     g_assert_nonnull(args);
   1230     qdict_put_str(args, "uri", uri);
   1231 
   1232     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
   1233     g_assert(qdict_haskey(resp, "return"));
   1234     qobject_unref(resp);
   1235 
   1236     /* the event is sent when QEMU asks the OS to unplug the card */
   1237     resp = get_unplug_primary_event(qts);
   1238     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
   1239     qobject_unref(resp);
   1240 
   1241     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
   1242     g_assert(qdict_haskey(resp, "return"));
   1243     qobject_unref(resp);
   1244 
   1245     /* migration has been cancelled while the unplug was in progress */
   1246 
   1247     /* while the card is not ejected, we must be in "cancelling" state */
   1248     ret = migrate_status(qts);
   1249 
   1250     status = qdict_get_str(ret, "status");
   1251     g_assert_cmpstr(status, ==, "cancelling");
   1252     qobject_unref(ret);
   1253 
   1254     /* OS unplugs the cards, QEMU can move from wait-unplug state */
   1255     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
   1256 
   1257     while (true) {
   1258         ret = migrate_status(qts);
   1259 
   1260         status = qdict_get_str(ret, "status");
   1261         if (strcmp(status, "cancelled") == 0) {
   1262             qobject_unref(ret);
   1263             break;
   1264         }
   1265         g_assert_cmpstr(status, ==, "cancelling");
   1266         qobject_unref(ret);
   1267     }
   1268 
   1269     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1270     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1271 
   1272     qos_object_destroy((QOSGraphObject *)vdev);
   1273     machine_stop(qts);
   1274 }
   1275 
   1276 static void test_migrate_abort_active(gconstpointer opaque)
   1277 {
   1278     QTestState *qts;
   1279     QDict *resp, *args, *ret;
   1280     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
   1281     const gchar *status;
   1282     QVirtioPCIDevice *vdev;
   1283 
   1284     qts = machine_start(BASE_MACHINE
   1285                      "-netdev user,id=hs0 "
   1286                      "-netdev user,id=hs1 ",
   1287                      2);
   1288 
   1289     check_one_card(qts, false, "standby0", MAC_STANDBY0);
   1290     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1291 
   1292     qtest_qmp_device_add(qts, "virtio-net", "standby0",
   1293                          "{'bus': 'root0',"
   1294                          "'failover': 'on',"
   1295                          "'netdev': 'hs0',"
   1296                          "'mac': '"MAC_STANDBY0"'}");
   1297 
   1298     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1299     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1300 
   1301     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
   1302 
   1303     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1304     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1305 
   1306     qtest_qmp_device_add(qts, "virtio-net", "primary0",
   1307                          "{'bus': 'root1',"
   1308                          "'failover_pair_id': 'standby0',"
   1309                          "'netdev': 'hs1',"
   1310                          "'rombar': 0,"
   1311                          "'romfile': '',"
   1312                          "'mac': '"MAC_PRIMARY0"'}");
   1313 
   1314     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1315     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1316 
   1317     args = qdict_from_jsonf_nofail("{}");
   1318     g_assert_nonnull(args);
   1319     qdict_put_str(args, "uri", uri);
   1320 
   1321     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
   1322     g_assert(qdict_haskey(resp, "return"));
   1323     qobject_unref(resp);
   1324 
   1325     /* the event is sent when QEMU asks the OS to unplug the card */
   1326     resp = get_unplug_primary_event(qts);
   1327     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
   1328     qobject_unref(resp);
   1329 
   1330     /* OS unplugs the cards, QEMU can move from wait-unplug state */
   1331     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
   1332 
   1333     while (true) {
   1334         ret = migrate_status(qts);
   1335 
   1336         status = qdict_get_str(ret, "status");
   1337         g_assert_cmpstr(status, !=, "failed");
   1338         if (strcmp(status, "wait-unplug") != 0) {
   1339             qobject_unref(ret);
   1340             break;
   1341         }
   1342         qobject_unref(ret);
   1343     }
   1344 
   1345     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
   1346     g_assert(qdict_haskey(resp, "return"));
   1347     qobject_unref(resp);
   1348 
   1349     while (true) {
   1350         ret = migrate_status(qts);
   1351 
   1352         status = qdict_get_str(ret, "status");
   1353         if (strcmp(status, "completed") == 0) {
   1354             g_test_skip("Failed to cancel the migration");
   1355             qobject_unref(ret);
   1356             goto out;
   1357         }
   1358         if (strcmp(status, "cancelled") == 0) {
   1359             qobject_unref(ret);
   1360             break;
   1361         }
   1362         g_assert_cmpstr(status, !=, "failed");
   1363         g_assert_cmpstr(status, !=, "active");
   1364         qobject_unref(ret);
   1365     }
   1366 
   1367     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1368     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1369 
   1370 out:
   1371     qos_object_destroy((QOSGraphObject *)vdev);
   1372     machine_stop(qts);
   1373 }
   1374 
   1375 static void test_migrate_off_abort(gconstpointer opaque)
   1376 {
   1377     QTestState *qts;
   1378     QDict *resp, *args, *ret;
   1379     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
   1380     const gchar *status;
   1381     QVirtioPCIDevice *vdev;
   1382 
   1383     qts = machine_start(BASE_MACHINE
   1384                      "-netdev user,id=hs0 "
   1385                      "-netdev user,id=hs1 ",
   1386                      2);
   1387 
   1388     check_one_card(qts, false, "standby0", MAC_STANDBY0);
   1389     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1390 
   1391     qtest_qmp_device_add(qts, "virtio-net", "standby0",
   1392                          "{'bus': 'root0',"
   1393                          "'failover': 'off',"
   1394                          "'netdev': 'hs0',"
   1395                          "'mac': '"MAC_STANDBY0"'}");
   1396 
   1397     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1398     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1399 
   1400     vdev = start_virtio_net(qts, 1, 0, "standby0", false);
   1401 
   1402     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1403     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1404 
   1405     qtest_qmp_device_add(qts, "virtio-net", "primary0",
   1406                          "{'bus': 'root1',"
   1407                          "'failover_pair_id': 'standby0',"
   1408                          "'netdev': 'hs1',"
   1409                          "'rombar': 0,"
   1410                          "'romfile': '',"
   1411                          "'mac': '"MAC_PRIMARY0"'}");
   1412 
   1413     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1414     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1415 
   1416     args = qdict_from_jsonf_nofail("{}");
   1417     g_assert_nonnull(args);
   1418     qdict_put_str(args, "uri", uri);
   1419 
   1420     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
   1421     g_assert(qdict_haskey(resp, "return"));
   1422     qobject_unref(resp);
   1423 
   1424     while (true) {
   1425         ret = migrate_status(qts);
   1426 
   1427         status = qdict_get_str(ret, "status");
   1428         if (strcmp(status, "active") == 0) {
   1429             qobject_unref(ret);
   1430             break;
   1431         }
   1432         g_assert_cmpstr(status, !=, "failed");
   1433         qobject_unref(ret);
   1434     }
   1435 
   1436     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
   1437     g_assert(qdict_haskey(resp, "return"));
   1438     qobject_unref(resp);
   1439 
   1440     while (true) {
   1441         ret = migrate_status(qts);
   1442 
   1443         status = qdict_get_str(ret, "status");
   1444         if (strcmp(status, "completed") == 0) {
   1445             g_test_skip("Failed to cancel the migration");
   1446             qobject_unref(ret);
   1447             goto out;
   1448         }
   1449         if (strcmp(status, "cancelled") == 0) {
   1450             qobject_unref(ret);
   1451             break;
   1452         }
   1453         g_assert_cmpstr(status, !=, "failed");
   1454         g_assert_cmpstr(status, !=, "active");
   1455         qobject_unref(ret);
   1456     }
   1457 
   1458     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1459     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1460 
   1461 out:
   1462     qos_object_destroy((QOSGraphObject *)vdev);
   1463     machine_stop(qts);
   1464 }
   1465 
   1466 static void test_migrate_abort_timeout(gconstpointer opaque)
   1467 {
   1468     QTestState *qts;
   1469     QDict *resp, *args, *ret;
   1470     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
   1471     const gchar *status;
   1472     int total;
   1473     QVirtioPCIDevice *vdev;
   1474 
   1475     qts = machine_start(BASE_MACHINE
   1476                      "-netdev user,id=hs0 "
   1477                      "-netdev user,id=hs1 ",
   1478                      2);
   1479 
   1480     check_one_card(qts, false, "standby0", MAC_STANDBY0);
   1481     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1482 
   1483     qtest_qmp_device_add(qts, "virtio-net", "standby0",
   1484                          "{'bus': 'root0',"
   1485                          "'failover': 'on',"
   1486                          "'netdev': 'hs0',"
   1487                          "'mac': '"MAC_STANDBY0"'}");
   1488 
   1489     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1490     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1491 
   1492     vdev = start_virtio_net(qts, 1, 0, "standby0", true);
   1493 
   1494     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1495     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1496 
   1497     qtest_qmp_device_add(qts, "virtio-net", "primary0",
   1498                          "{'bus': 'root1',"
   1499                          "'failover_pair_id': 'standby0',"
   1500                          "'netdev': 'hs1',"
   1501                          "'rombar': 0,"
   1502                          "'romfile': '',"
   1503                          "'mac': '"MAC_PRIMARY0"'}");
   1504 
   1505     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1506     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1507 
   1508     args = qdict_from_jsonf_nofail("{}");
   1509     g_assert_nonnull(args);
   1510     qdict_put_str(args, "uri", uri);
   1511 
   1512     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
   1513     g_assert(qdict_haskey(resp, "return"));
   1514     qobject_unref(resp);
   1515 
   1516     /* the event is sent when QEMU asks the OS to unplug the card */
   1517     resp = get_unplug_primary_event(qts);
   1518     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
   1519     qobject_unref(resp);
   1520 
   1521     resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
   1522     g_assert(qdict_haskey(resp, "return"));
   1523     qobject_unref(resp);
   1524 
   1525     /* migration has been cancelled while the unplug was in progress */
   1526 
   1527     /* while the card is not ejected, we must be in "cancelling" state */
   1528 
   1529     total = 0;
   1530     while (true) {
   1531         ret = migrate_status(qts);
   1532 
   1533         status = qdict_get_str(ret, "status");
   1534         if (strcmp(status, "cancelled") == 0) {
   1535             qobject_unref(ret);
   1536             break;
   1537         }
   1538         g_assert_cmpstr(status, ==, "cancelling");
   1539         g_assert(qdict_haskey(ret, "total-time"));
   1540         total = qdict_get_int(ret, "total-time");
   1541         qobject_unref(ret);
   1542     }
   1543 
   1544     /*
   1545      * migration timeout in this case is 30 seconds
   1546      * check we exit on the timeout (ms)
   1547      */
   1548     g_assert_cmpint(total, >, 30000);
   1549 
   1550     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1551     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1552 
   1553     qos_object_destroy((QOSGraphObject *)vdev);
   1554     machine_stop(qts);
   1555 }
   1556 
   1557 static void test_multi_out(gconstpointer opaque)
   1558 {
   1559     QTestState *qts;
   1560     QDict *resp, *args, *ret;
   1561     g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
   1562     const gchar *status, *expected;
   1563     QVirtioPCIDevice *vdev0, *vdev1;
   1564 
   1565     qts = machine_start(BASE_MACHINE
   1566                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
   1567                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
   1568                 "-netdev user,id=hs0 "
   1569                 "-netdev user,id=hs1 "
   1570                 "-netdev user,id=hs2 "
   1571                 "-netdev user,id=hs3 ",
   1572                 4);
   1573 
   1574     check_one_card(qts, false, "standby0", MAC_STANDBY0);
   1575     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1576     check_one_card(qts, false, "standby1", MAC_STANDBY1);
   1577     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1578 
   1579     qtest_qmp_device_add(qts, "virtio-net", "standby0",
   1580                          "{'bus': 'root0',"
   1581                          "'failover': 'on',"
   1582                          "'netdev': 'hs0',"
   1583                          "'mac': '"MAC_STANDBY0"'}");
   1584 
   1585     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1586     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1587     check_one_card(qts, false, "standby1", MAC_STANDBY1);
   1588     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1589 
   1590     qtest_qmp_device_add(qts, "virtio-net", "primary0",
   1591                          "{'bus': 'root1',"
   1592                          "'failover_pair_id': 'standby0',"
   1593                          "'netdev': 'hs1',"
   1594                          "'rombar': 0,"
   1595                          "'romfile': '',"
   1596                          "'mac': '"MAC_PRIMARY0"'}");
   1597 
   1598     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1599     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1600     check_one_card(qts, false, "standby1", MAC_STANDBY1);
   1601     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1602 
   1603     vdev0 = start_virtio_net(qts, 1, 0, "standby0", true);
   1604 
   1605     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1606     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1607     check_one_card(qts, false, "standby1", MAC_STANDBY1);
   1608     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1609 
   1610     qtest_qmp_device_add(qts, "virtio-net", "standby1",
   1611                          "{'bus': 'root2',"
   1612                          "'failover': 'on',"
   1613                          "'netdev': 'hs2',"
   1614                          "'mac': '"MAC_STANDBY1"'}");
   1615 
   1616     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1617     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1618     check_one_card(qts, true, "standby1", MAC_STANDBY1);
   1619     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1620 
   1621     qtest_qmp_device_add(qts, "virtio-net", "primary1",
   1622                          "{'bus': 'root3',"
   1623                          "'failover_pair_id': 'standby1',"
   1624                          "'netdev': 'hs3',"
   1625                          "'rombar': 0,"
   1626                          "'romfile': '',"
   1627                          "'mac': '"MAC_PRIMARY1"'}");
   1628 
   1629     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1630     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1631     check_one_card(qts, true, "standby1", MAC_STANDBY1);
   1632     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1633 
   1634     vdev1 = start_virtio_net(qts, 3, 0, "standby1", true);
   1635 
   1636     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1637     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1638     check_one_card(qts, true, "standby1", MAC_STANDBY1);
   1639     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
   1640 
   1641     args = qdict_from_jsonf_nofail("{}");
   1642     g_assert_nonnull(args);
   1643     qdict_put_str(args, "uri", uri);
   1644 
   1645     resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
   1646     g_assert(qdict_haskey(resp, "return"));
   1647     qobject_unref(resp);
   1648 
   1649     /* the event is sent when QEMU asks the OS to unplug the card */
   1650     resp = get_unplug_primary_event(qts);
   1651     if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
   1652         expected = "primary1";
   1653     } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
   1654         expected = "primary0";
   1655     } else {
   1656         g_assert_not_reached();
   1657     }
   1658     qobject_unref(resp);
   1659 
   1660     resp = get_unplug_primary_event(qts);
   1661     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
   1662     qobject_unref(resp);
   1663 
   1664     /* wait the end of the migration setup phase */
   1665     while (true) {
   1666         ret = migrate_status(qts);
   1667 
   1668         status = qdict_get_str(ret, "status");
   1669         if (strcmp(status, "wait-unplug") == 0) {
   1670             qobject_unref(ret);
   1671             break;
   1672         }
   1673 
   1674         /* The migration must not start if the card is not ejected */
   1675         g_assert_cmpstr(status, !=, "active");
   1676         g_assert_cmpstr(status, !=, "completed");
   1677         g_assert_cmpstr(status, !=, "failed");
   1678         g_assert_cmpstr(status, !=, "cancelling");
   1679         g_assert_cmpstr(status, !=, "cancelled");
   1680 
   1681         qobject_unref(ret);
   1682     }
   1683 
   1684     /* OS unplugs primary1, but we must wait the second */
   1685     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
   1686 
   1687     ret = migrate_status(qts);
   1688     status = qdict_get_str(ret, "status");
   1689     g_assert_cmpstr(status, ==, "wait-unplug");
   1690     qobject_unref(ret);
   1691 
   1692     if (g_test_slow()) {
   1693         /* check we stay in wait-unplug while the card is not ejected */
   1694         for (int i = 0; i < 5; i++) {
   1695             sleep(1);
   1696             ret = migrate_status(qts);
   1697             status = qdict_get_str(ret, "status");
   1698             g_assert_cmpstr(status, ==, "wait-unplug");
   1699             qobject_unref(ret);
   1700         }
   1701     }
   1702 
   1703     /* OS unplugs primary0, QEMU can move from wait-unplug state */
   1704     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
   1705     qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
   1706 
   1707     while (true) {
   1708         ret = migrate_status(qts);
   1709 
   1710         status = qdict_get_str(ret, "status");
   1711         if (strcmp(status, "completed") == 0) {
   1712             qobject_unref(ret);
   1713             break;
   1714         }
   1715         g_assert_cmpstr(status, !=, "failed");
   1716         g_assert_cmpstr(status, !=, "cancelling");
   1717         g_assert_cmpstr(status, !=, "cancelled");
   1718         qobject_unref(ret);
   1719     }
   1720 
   1721     qtest_qmp_eventwait(qts, "STOP");
   1722 
   1723     qos_object_destroy((QOSGraphObject *)vdev0);
   1724     qos_object_destroy((QOSGraphObject *)vdev1);
   1725     machine_stop(qts);
   1726 }
   1727 
   1728 static void test_multi_in(gconstpointer opaque)
   1729 {
   1730     QTestState *qts;
   1731     QDict *resp, *args, *ret;
   1732     g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
   1733 
   1734     qts = machine_start(BASE_MACHINE
   1735                 "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
   1736                 "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
   1737                 "-netdev user,id=hs0 "
   1738                 "-netdev user,id=hs1 "
   1739                 "-netdev user,id=hs2 "
   1740                 "-netdev user,id=hs3 "
   1741                 "-incoming defer ",
   1742                 4);
   1743 
   1744     check_one_card(qts, false, "standby0", MAC_STANDBY0);
   1745     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1746     check_one_card(qts, false, "standby1", MAC_STANDBY1);
   1747     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1748 
   1749     qtest_qmp_device_add(qts, "virtio-net", "standby0",
   1750                          "{'bus': 'root0',"
   1751                          "'failover': 'on',"
   1752                          "'netdev': 'hs0',"
   1753                          "'mac': '"MAC_STANDBY0"'}");
   1754 
   1755     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1756     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1757     check_one_card(qts, false, "standby1", MAC_STANDBY1);
   1758     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1759 
   1760     qtest_qmp_device_add(qts, "virtio-net", "primary0",
   1761                          "{'bus': 'root1',"
   1762                          "'failover_pair_id': 'standby0',"
   1763                          "'netdev': 'hs1',"
   1764                          "'rombar': 0,"
   1765                          "'romfile': '',"
   1766                          "'mac': '"MAC_PRIMARY0"'}");
   1767 
   1768     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1769     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1770     check_one_card(qts, false, "standby1", MAC_STANDBY1);
   1771     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1772 
   1773     qtest_qmp_device_add(qts, "virtio-net", "standby1",
   1774                          "{'bus': 'root2',"
   1775                          "'failover': 'on',"
   1776                          "'netdev': 'hs2',"
   1777                          "'mac': '"MAC_STANDBY1"'}");
   1778 
   1779     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1780     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1781     check_one_card(qts, true, "standby1", MAC_STANDBY1);
   1782     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1783 
   1784     qtest_qmp_device_add(qts, "virtio-net", "primary1",
   1785                          "{'bus': 'root3',"
   1786                          "'failover_pair_id': 'standby1',"
   1787                          "'netdev': 'hs3',"
   1788                          "'rombar': 0,"
   1789                          "'romfile': '',"
   1790                          "'mac': '"MAC_PRIMARY1"'}");
   1791 
   1792     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1793     check_one_card(qts, false, "primary0", MAC_PRIMARY0);
   1794     check_one_card(qts, true, "standby1", MAC_STANDBY1);
   1795     check_one_card(qts, false, "primary1", MAC_PRIMARY1);
   1796 
   1797     args = qdict_from_jsonf_nofail("{}");
   1798     g_assert_nonnull(args);
   1799     qdict_put_str(args, "uri", uri);
   1800 
   1801     resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
   1802                      args);
   1803     g_assert(qdict_haskey(resp, "return"));
   1804     qobject_unref(resp);
   1805 
   1806     resp = get_migration_event(qts);
   1807     g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
   1808     qobject_unref(resp);
   1809 
   1810     resp = get_failover_negociated_event(qts);
   1811     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
   1812     qobject_unref(resp);
   1813 
   1814     resp = get_failover_negociated_event(qts);
   1815     g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
   1816     qobject_unref(resp);
   1817 
   1818     check_one_card(qts, true, "standby0", MAC_STANDBY0);
   1819     check_one_card(qts, true, "primary0", MAC_PRIMARY0);
   1820     check_one_card(qts, true, "standby1", MAC_STANDBY1);
   1821     check_one_card(qts, true, "primary1", MAC_PRIMARY1);
   1822 
   1823     qtest_qmp_eventwait(qts, "RESUME");
   1824 
   1825     ret = migrate_status(qts);
   1826     g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
   1827     qobject_unref(ret);
   1828 
   1829     machine_stop(qts);
   1830 }
   1831 #endif /* _WIN32 */
   1832 
   1833 int main(int argc, char **argv)
   1834 {
   1835     gchar *tmpfile;
   1836     int ret;
   1837 
   1838     g_test_init(&argc, &argv, NULL);
   1839 
   1840     ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
   1841     g_assert_true(ret >= 0);
   1842     close(ret);
   1843 
   1844     /* parameters tests */
   1845     qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
   1846     qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
   1847     qtest_add_func("failover-virtio-net/params/on", test_on);
   1848     qtest_add_func("failover-virtio-net/params/on_mismatch",
   1849                    test_on_mismatch);
   1850     qtest_add_func("failover-virtio-net/params/off", test_off);
   1851     qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
   1852     qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off);
   1853 
   1854     /* hotplug tests */
   1855     qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1);
   1856     qtest_add_func("failover-virtio-net/hotplug/1_reverse",
   1857                    test_hotplug_1_reverse);
   1858     qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2);
   1859     qtest_add_func("failover-virtio-net/hotplug/2_reverse",
   1860                    test_hotplug_2_reverse);
   1861 
   1862 #ifndef _WIN32
   1863     /*
   1864      * These migration tests cases use the exec migration protocol,
   1865      * which is unsupported on Windows.
   1866      */
   1867     qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile,
   1868                         test_migrate_out);
   1869     qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile,
   1870                         test_migrate_in);
   1871     qtest_add_data_func("failover-virtio-net/migrate/off/out", tmpfile,
   1872                         test_off_migrate_out);
   1873     qtest_add_data_func("failover-virtio-net/migrate/off/in", tmpfile,
   1874                         test_off_migrate_in);
   1875     qtest_add_data_func("failover-virtio-net/migrate/off/abort", tmpfile,
   1876                         test_migrate_off_abort);
   1877     qtest_add_data_func("failover-virtio-net/migrate/guest_off/out", tmpfile,
   1878                         test_guest_off_migrate_out);
   1879     qtest_add_data_func("failover-virtio-net/migrate/guest_off/in", tmpfile,
   1880                         test_guest_off_migrate_in);
   1881     qtest_add_data_func("failover-virtio-net/migrate/guest_off/abort", tmpfile,
   1882                         test_migrate_guest_off_abort);
   1883     qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
   1884                         tmpfile, test_migrate_abort_wait_unplug);
   1885     qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
   1886                         test_migrate_abort_active);
   1887     if (g_test_slow()) {
   1888         qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
   1889                             tmpfile, test_migrate_abort_timeout);
   1890     }
   1891     qtest_add_data_func("failover-virtio-net/migrate/multi/out",
   1892                         tmpfile, test_multi_out);
   1893     qtest_add_data_func("failover-virtio-net/migrate/multi/in",
   1894                    tmpfile, test_multi_in);
   1895 #endif /* _WIN32 */
   1896 
   1897     ret = g_test_run();
   1898 
   1899     unlink(tmpfile);
   1900     g_free(tmpfile);
   1901 
   1902     return ret;
   1903 }