qemu/tests/qtest/virtio-net-failover.c
<<
>>
Prefs
   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 "libqos/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
  36static QGuestAllocator guest_malloc;
  37static QPCIBus *pcibus;
  38
  39static 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
  64static void machine_stop(QTestState *qts)
  65{
  66    qpci_free_pc(pcibus);
  67    alloc_destroy(&guest_malloc);
  68    qtest_quit(qts);
  69}
  70
  71static 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
 100static 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
 130static 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
 179static 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
 210static 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)                   \
 230do {                                                            \
 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
 251static 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
 267static 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
 285static 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
 310static 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
 329static 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
 355static 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
 381static 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
 407static 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
 439static 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
 471static 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
 504static 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
 544static 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
 591static QDict *migrate_status(QTestState *qts)
 592{
 593    QDict *resp, *ret;
 594
 595    resp = qtest_qmp(qts, "{ 'execute': 'query-migrate' }");
 596    g_assert(qdict_haskey(resp, "return"));
 597
 598    ret = qdict_get_qdict(resp, "return");
 599    g_assert(qdict_haskey(ret, "status"));
 600    qobject_ref(ret);
 601    qobject_unref(resp);
 602
 603    return ret;
 604}
 605
 606static QDict *get_unplug_primary_event(QTestState *qts)
 607{
 608    QDict *resp;
 609    QDict *data;
 610
 611    resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY");
 612    g_assert(qdict_haskey(resp, "data"));
 613
 614    data = qdict_get_qdict(resp, "data");
 615    g_assert(qdict_haskey(data, "device-id"));
 616    qobject_ref(data);
 617    qobject_unref(resp);
 618
 619    return data;
 620}
 621
 622static void test_migrate_out(gconstpointer opaque)
 623{
 624    QTestState *qts;
 625    QDict *resp, *args, *ret;
 626    g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
 627    const gchar *status;
 628    QVirtioPCIDevice *vdev;
 629
 630    qts = machine_start(BASE_MACHINE
 631                     "-netdev user,id=hs0 "
 632                     "-netdev user,id=hs1 ",
 633                     2);
 634
 635    check_one_card(qts, false, "standby0", MAC_STANDBY0);
 636    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 637
 638    qtest_qmp_device_add(qts, "virtio-net", "standby0",
 639                         "{'bus': 'root0',"
 640                         "'failover': 'on',"
 641                         "'netdev': 'hs0',"
 642                         "'mac': '"MAC_STANDBY0"'}");
 643
 644    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 645    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 646
 647    vdev = start_virtio_net(qts, 1, 0, "standby0", true);
 648
 649    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 650    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 651
 652    qtest_qmp_device_add(qts, "virtio-net", "primary0",
 653                         "{'bus': 'root1',"
 654                         "'failover_pair_id': 'standby0',"
 655                         "'netdev': 'hs1',"
 656                         "'rombar': 0,"
 657                         "'romfile': '',"
 658                         "'mac': '"MAC_PRIMARY0"'}");
 659
 660    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 661    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
 662
 663    args = qdict_from_jsonf_nofail("{}");
 664    g_assert_nonnull(args);
 665    qdict_put_str(args, "uri", uri);
 666
 667    resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
 668    g_assert(qdict_haskey(resp, "return"));
 669    qobject_unref(resp);
 670
 671    /* the event is sent when QEMU asks the OS to unplug the card */
 672    resp = get_unplug_primary_event(qts);
 673    g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
 674    qobject_unref(resp);
 675
 676    /* wait the end of the migration setup phase */
 677    while (true) {
 678        ret = migrate_status(qts);
 679
 680        status = qdict_get_str(ret, "status");
 681        if (strcmp(status, "wait-unplug") == 0) {
 682            qobject_unref(ret);
 683            break;
 684        }
 685
 686        /* The migration must not start if the card is not ejected */
 687        g_assert_cmpstr(status, !=, "active");
 688        g_assert_cmpstr(status, !=, "completed");
 689        g_assert_cmpstr(status, !=, "failed");
 690        g_assert_cmpstr(status, !=, "cancelling");
 691        g_assert_cmpstr(status, !=, "cancelled");
 692
 693        qobject_unref(ret);
 694    }
 695
 696    if (g_test_slow()) {
 697        /* check we stay in wait-unplug while the card is not ejected */
 698        for (int i = 0; i < 5; i++) {
 699            sleep(1);
 700            ret = migrate_status(qts);
 701            status = qdict_get_str(ret, "status");
 702            g_assert_cmpstr(status, ==, "wait-unplug");
 703            qobject_unref(ret);
 704        }
 705    }
 706
 707    /* OS unplugs the cards, QEMU can move from wait-unplug state */
 708    qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
 709
 710    while (true) {
 711        ret = migrate_status(qts);
 712
 713        status = qdict_get_str(ret, "status");
 714        if (strcmp(status, "completed") == 0) {
 715            qobject_unref(ret);
 716            break;
 717        }
 718        g_assert_cmpstr(status, !=, "failed");
 719        g_assert_cmpstr(status, !=, "cancelling");
 720        g_assert_cmpstr(status, !=, "cancelled");
 721        qobject_unref(ret);
 722    }
 723
 724    qtest_qmp_eventwait(qts, "STOP");
 725
 726    /*
 727     * in fact, the card is ejected from the point of view of kernel
 728     * but not really from QEMU to be able to hotplug it back if
 729     * migration fails. So we can't check that:
 730     *   check_one_card(qts, true, "standby0", MAC_STANDBY0);
 731     *   check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 732     */
 733
 734    qos_object_destroy((QOSGraphObject *)vdev);
 735    machine_stop(qts);
 736}
 737
 738static QDict *get_migration_event(QTestState *qts)
 739{
 740    QDict *resp;
 741    QDict *data;
 742
 743    resp = qtest_qmp_eventwait_ref(qts, "MIGRATION");
 744    g_assert(qdict_haskey(resp, "data"));
 745
 746    data = qdict_get_qdict(resp, "data");
 747    g_assert(qdict_haskey(data, "status"));
 748    qobject_ref(data);
 749    qobject_unref(resp);
 750
 751    return data;
 752}
 753
 754static void test_migrate_in(gconstpointer opaque)
 755{
 756    QTestState *qts;
 757    QDict *resp, *args, *ret;
 758    g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
 759
 760    qts = machine_start(BASE_MACHINE
 761                     "-netdev user,id=hs0 "
 762                     "-netdev user,id=hs1 "
 763                     "-incoming defer ",
 764                     2);
 765
 766    check_one_card(qts, false, "standby0", MAC_STANDBY0);
 767    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 768
 769    qtest_qmp_device_add(qts, "virtio-net", "standby0",
 770                         "{'bus': 'root0',"
 771                         "'failover': 'on',"
 772                         "'netdev': 'hs0',"
 773                         "'mac': '"MAC_STANDBY0"'}");
 774
 775    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 776    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 777
 778    qtest_qmp_device_add(qts, "virtio-net", "primary0",
 779                         "{'bus': 'root1',"
 780                         "'failover_pair_id': 'standby0',"
 781                         "'netdev': 'hs1',"
 782                         "'rombar': 0,"
 783                         "'romfile': '',"
 784                         "'mac': '"MAC_PRIMARY0"'}");
 785
 786    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 787    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 788
 789    args = qdict_from_jsonf_nofail("{}");
 790    g_assert_nonnull(args);
 791    qdict_put_str(args, "uri", uri);
 792
 793    resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
 794                     args);
 795    g_assert(qdict_haskey(resp, "return"));
 796    qobject_unref(resp);
 797
 798    resp = get_migration_event(qts);
 799    g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
 800    qobject_unref(resp);
 801
 802    resp = get_failover_negociated_event(qts);
 803    g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
 804    qobject_unref(resp);
 805
 806    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 807    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
 808
 809    qtest_qmp_eventwait(qts, "RESUME");
 810
 811    ret = migrate_status(qts);
 812    g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
 813    qobject_unref(ret);
 814
 815    machine_stop(qts);
 816}
 817
 818static void test_off_migrate_out(gconstpointer opaque)
 819{
 820    QTestState *qts;
 821    QDict *resp, *args, *ret;
 822    g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
 823    const gchar *status;
 824    QVirtioPCIDevice *vdev;
 825
 826    qts = machine_start(BASE_MACHINE
 827                     "-netdev user,id=hs0 "
 828                     "-netdev user,id=hs1 ",
 829                     2);
 830
 831    check_one_card(qts, false, "standby0", MAC_STANDBY0);
 832    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 833
 834    qtest_qmp_device_add(qts, "virtio-net", "standby0",
 835                         "{'bus': 'root0',"
 836                         "'failover': 'off',"
 837                         "'netdev': 'hs0',"
 838                         "'mac': '"MAC_STANDBY0"'}");
 839
 840    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 841    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 842
 843    qtest_qmp_device_add(qts, "virtio-net", "primary0",
 844                         "{'bus': 'root1',"
 845                         "'failover_pair_id': 'standby0',"
 846                         "'netdev': 'hs1',"
 847                         "'rombar': 0,"
 848                         "'romfile': '',"
 849                         "'mac': '"MAC_PRIMARY0"'}");
 850
 851    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 852    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
 853
 854    vdev = start_virtio_net(qts, 1, 0, "standby0", false);
 855
 856    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 857    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
 858
 859    args = qdict_from_jsonf_nofail("{}");
 860    g_assert_nonnull(args);
 861    qdict_put_str(args, "uri", uri);
 862
 863    resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
 864    g_assert(qdict_haskey(resp, "return"));
 865    qobject_unref(resp);
 866
 867    while (true) {
 868        ret = migrate_status(qts);
 869
 870        status = qdict_get_str(ret, "status");
 871        if (strcmp(status, "completed") == 0) {
 872            qobject_unref(ret);
 873            break;
 874        }
 875        g_assert_cmpstr(status, !=, "failed");
 876        g_assert_cmpstr(status, !=, "cancelling");
 877        g_assert_cmpstr(status, !=, "cancelled");
 878        qobject_unref(ret);
 879    }
 880
 881    qtest_qmp_eventwait(qts, "STOP");
 882
 883    qos_object_destroy((QOSGraphObject *)vdev);
 884    machine_stop(qts);
 885}
 886
 887static void test_off_migrate_in(gconstpointer opaque)
 888{
 889    QTestState *qts;
 890    QDict *resp, *args, *ret;
 891    g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
 892
 893    qts = machine_start(BASE_MACHINE
 894                     "-netdev user,id=hs0 "
 895                     "-netdev user,id=hs1 "
 896                     "-incoming defer ",
 897                     2);
 898
 899    check_one_card(qts, false, "standby0", MAC_STANDBY0);
 900    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 901
 902    qtest_qmp_device_add(qts, "virtio-net", "standby0",
 903                         "{'bus': 'root0',"
 904                         "'failover': 'off',"
 905                         "'netdev': 'hs0',"
 906                         "'mac': '"MAC_STANDBY0"'}");
 907
 908    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 909    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 910
 911    qtest_qmp_device_add(qts, "virtio-net", "primary0",
 912                         "{'bus': 'root1',"
 913                         "'failover_pair_id': 'standby0',"
 914                         "'netdev': 'hs1',"
 915                         "'rombar': 0,"
 916                         "'romfile': '',"
 917                         "'mac': '"MAC_PRIMARY0"'}");
 918
 919    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 920    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
 921
 922    args = qdict_from_jsonf_nofail("{}");
 923    g_assert_nonnull(args);
 924    qdict_put_str(args, "uri", uri);
 925
 926    resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
 927                     args);
 928    g_assert(qdict_haskey(resp, "return"));
 929    qobject_unref(resp);
 930
 931    resp = get_migration_event(qts);
 932    g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
 933    qobject_unref(resp);
 934
 935    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 936    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
 937
 938    qtest_qmp_eventwait(qts, "RESUME");
 939
 940    ret = migrate_status(qts);
 941    g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
 942    qobject_unref(ret);
 943
 944    machine_stop(qts);
 945}
 946
 947static void test_guest_off_migrate_out(gconstpointer opaque)
 948{
 949    QTestState *qts;
 950    QDict *resp, *args, *ret;
 951    g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
 952    const gchar *status;
 953    QVirtioPCIDevice *vdev;
 954    uint64_t features;
 955
 956    qts = machine_start(BASE_MACHINE
 957                     "-netdev user,id=hs0 "
 958                     "-netdev user,id=hs1 ",
 959                     2);
 960
 961    check_one_card(qts, false, "standby0", MAC_STANDBY0);
 962    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 963
 964    qtest_qmp_device_add(qts, "virtio-net", "standby0",
 965                         "{'bus': 'root0',"
 966                         "'failover': 'on',"
 967                         "'netdev': 'hs0',"
 968                         "'mac': '"MAC_STANDBY0"'}");
 969
 970    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 971    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 972
 973    qtest_qmp_device_add(qts, "virtio-net", "primary0",
 974                         "{'bus': 'root1',"
 975                         "'failover_pair_id': 'standby0',"
 976                         "'netdev': 'hs1',"
 977                         "'rombar': 0,"
 978                         "'romfile': '',"
 979                         "'mac': '"MAC_PRIMARY0"'}");
 980
 981    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 982    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 983
 984    features = ~(QVIRTIO_F_BAD_FEATURE |
 985                 (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
 986                 (1ull << VIRTIO_RING_F_EVENT_IDX) |
 987                 (1ull << VIRTIO_NET_F_STANDBY));
 988
 989    vdev = start_virtio_net_internal(qts, 1, 0, &features);
 990
 991    check_one_card(qts, true, "standby0", MAC_STANDBY0);
 992    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
 993
 994    args = qdict_from_jsonf_nofail("{}");
 995    g_assert_nonnull(args);
 996    qdict_put_str(args, "uri", uri);
 997
 998    resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
 999    g_assert(qdict_haskey(resp, "return"));
1000    qobject_unref(resp);
1001
1002    while (true) {
1003        ret = migrate_status(qts);
1004
1005        status = qdict_get_str(ret, "status");
1006        if (strcmp(status, "completed") == 0) {
1007            qobject_unref(ret);
1008            break;
1009        }
1010        g_assert_cmpstr(status, !=, "failed");
1011        g_assert_cmpstr(status, !=, "cancelling");
1012        g_assert_cmpstr(status, !=, "cancelled");
1013        qobject_unref(ret);
1014    }
1015
1016    qtest_qmp_eventwait(qts, "STOP");
1017
1018    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1019    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1020
1021    qos_object_destroy((QOSGraphObject *)vdev);
1022    machine_stop(qts);
1023}
1024
1025static void test_guest_off_migrate_in(gconstpointer opaque)
1026{
1027    QTestState *qts;
1028    QDict *resp, *args, *ret;
1029    g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1030
1031    qts = machine_start(BASE_MACHINE
1032                     "-netdev user,id=hs0 "
1033                     "-netdev user,id=hs1 "
1034                     "-incoming defer ",
1035                     2);
1036
1037    check_one_card(qts, false, "standby0", MAC_STANDBY0);
1038    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1039
1040    qtest_qmp_device_add(qts, "virtio-net", "standby0",
1041                         "{'bus': 'root0',"
1042                         "'failover': 'on',"
1043                         "'netdev': 'hs0',"
1044                         "'mac': '"MAC_STANDBY0"'}");
1045
1046    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1047    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1048
1049    qtest_qmp_device_add(qts, "virtio-net", "primary0",
1050                         "{'bus': 'root1',"
1051                         "'failover_pair_id': 'standby0',"
1052                         "'netdev': 'hs1',"
1053                         "'rombar': 0,"
1054                         "'romfile': '',"
1055                         "'mac': '"MAC_PRIMARY0"'}");
1056
1057    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1058    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1059
1060    args = qdict_from_jsonf_nofail("{}");
1061    g_assert_nonnull(args);
1062    qdict_put_str(args, "uri", uri);
1063
1064    resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1065                     args);
1066    g_assert(qdict_haskey(resp, "return"));
1067    qobject_unref(resp);
1068
1069    resp = get_migration_event(qts);
1070    g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1071    qobject_unref(resp);
1072
1073    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1074    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1075
1076    qtest_qmp_eventwait(qts, "RESUME");
1077
1078    ret = migrate_status(qts);
1079    g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1080    qobject_unref(ret);
1081
1082    machine_stop(qts);
1083}
1084
1085static void test_migrate_guest_off_abort(gconstpointer opaque)
1086{
1087    QTestState *qts;
1088    QDict *resp, *args, *ret;
1089    g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1090    const gchar *status;
1091    QVirtioPCIDevice *vdev;
1092    uint64_t features;
1093
1094    qts = machine_start(BASE_MACHINE
1095                     "-netdev user,id=hs0 "
1096                     "-netdev user,id=hs1 ",
1097                     2);
1098
1099    check_one_card(qts, false, "standby0", MAC_STANDBY0);
1100    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1101
1102    qtest_qmp_device_add(qts, "virtio-net", "standby0",
1103                         "{'bus': 'root0',"
1104                         "'failover': 'on',"
1105                         "'netdev': 'hs0',"
1106                         "'mac': '"MAC_STANDBY0"'}");
1107
1108    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1109    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1110
1111    qtest_qmp_device_add(qts, "virtio-net", "primary0",
1112                         "{'bus': 'root1',"
1113                         "'failover_pair_id': 'standby0',"
1114                         "'netdev': 'hs1',"
1115                         "'rombar': 0,"
1116                         "'romfile': '',"
1117                         "'mac': '"MAC_PRIMARY0"'}");
1118
1119    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1120    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1121
1122    features = ~(QVIRTIO_F_BAD_FEATURE |
1123                 (1ull << VIRTIO_RING_F_INDIRECT_DESC) |
1124                 (1ull << VIRTIO_RING_F_EVENT_IDX) |
1125                 (1ull << VIRTIO_NET_F_STANDBY));
1126
1127    vdev = start_virtio_net_internal(qts, 1, 0, &features);
1128
1129    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1130    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1131
1132    args = qdict_from_jsonf_nofail("{}");
1133    g_assert_nonnull(args);
1134    qdict_put_str(args, "uri", uri);
1135
1136    resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1137    g_assert(qdict_haskey(resp, "return"));
1138    qobject_unref(resp);
1139
1140    while (true) {
1141        ret = migrate_status(qts);
1142
1143        status = qdict_get_str(ret, "status");
1144        if (strcmp(status, "completed") == 0) {
1145            g_test_skip("Failed to cancel the migration");
1146            qobject_unref(ret);
1147            goto out;
1148        }
1149        if (strcmp(status, "active") == 0) {
1150            qobject_unref(ret);
1151            break;
1152        }
1153        g_assert_cmpstr(status, !=, "failed");
1154        qobject_unref(ret);
1155    }
1156
1157    resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1158    g_assert(qdict_haskey(resp, "return"));
1159    qobject_unref(resp);
1160
1161    while (true) {
1162        ret = migrate_status(qts);
1163        status = qdict_get_str(ret, "status");
1164        if (strcmp(status, "completed") == 0) {
1165            g_test_skip("Failed to cancel the migration");
1166            qobject_unref(ret);
1167            goto out;
1168        }
1169        if (strcmp(status, "cancelled") == 0) {
1170            qobject_unref(ret);
1171            break;
1172        }
1173        g_assert_cmpstr(status, !=, "failed");
1174        g_assert_cmpstr(status, !=, "active");
1175        qobject_unref(ret);
1176    }
1177
1178    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1179    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1180
1181out:
1182    qos_object_destroy((QOSGraphObject *)vdev);
1183    machine_stop(qts);
1184}
1185
1186static void test_migrate_abort_wait_unplug(gconstpointer opaque)
1187{
1188    QTestState *qts;
1189    QDict *resp, *args, *ret;
1190    g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1191    const gchar *status;
1192    QVirtioPCIDevice *vdev;
1193
1194    qts = machine_start(BASE_MACHINE
1195                     "-netdev user,id=hs0 "
1196                     "-netdev user,id=hs1 ",
1197                     2);
1198
1199    check_one_card(qts, false, "standby0", MAC_STANDBY0);
1200    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1201
1202    qtest_qmp_device_add(qts, "virtio-net", "standby0",
1203                         "{'bus': 'root0',"
1204                         "'failover': 'on',"
1205                         "'netdev': 'hs0',"
1206                         "'mac': '"MAC_STANDBY0"'}");
1207
1208    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1209    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1210
1211    vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1212
1213    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1214    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1215
1216    qtest_qmp_device_add(qts, "virtio-net", "primary0",
1217                         "{'bus': 'root1',"
1218                         "'failover_pair_id': 'standby0',"
1219                         "'netdev': 'hs1',"
1220                         "'rombar': 0,"
1221                         "'romfile': '',"
1222                         "'mac': '"MAC_PRIMARY0"'}");
1223
1224    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1225    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1226
1227    args = qdict_from_jsonf_nofail("{}");
1228    g_assert_nonnull(args);
1229    qdict_put_str(args, "uri", uri);
1230
1231    resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1232    g_assert(qdict_haskey(resp, "return"));
1233    qobject_unref(resp);
1234
1235    /* the event is sent when QEMU asks the OS to unplug the card */
1236    resp = get_unplug_primary_event(qts);
1237    g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1238    qobject_unref(resp);
1239
1240    resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1241    g_assert(qdict_haskey(resp, "return"));
1242    qobject_unref(resp);
1243
1244    /* migration has been cancelled while the unplug was in progress */
1245
1246    /* while the card is not ejected, we must be in "cancelling" state */
1247    ret = migrate_status(qts);
1248
1249    status = qdict_get_str(ret, "status");
1250    g_assert_cmpstr(status, ==, "cancelling");
1251    qobject_unref(ret);
1252
1253    /* OS unplugs the cards, QEMU can move from wait-unplug state */
1254    qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1255
1256    while (true) {
1257        ret = migrate_status(qts);
1258
1259        status = qdict_get_str(ret, "status");
1260        if (strcmp(status, "cancelled") == 0) {
1261            qobject_unref(ret);
1262            break;
1263        }
1264        g_assert_cmpstr(status, ==, "cancelling");
1265        qobject_unref(ret);
1266    }
1267
1268    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1269    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1270
1271    qos_object_destroy((QOSGraphObject *)vdev);
1272    machine_stop(qts);
1273}
1274
1275static void test_migrate_abort_active(gconstpointer opaque)
1276{
1277    QTestState *qts;
1278    QDict *resp, *args, *ret;
1279    g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1280    const gchar *status;
1281    QVirtioPCIDevice *vdev;
1282
1283    qts = machine_start(BASE_MACHINE
1284                     "-netdev user,id=hs0 "
1285                     "-netdev user,id=hs1 ",
1286                     2);
1287
1288    check_one_card(qts, false, "standby0", MAC_STANDBY0);
1289    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1290
1291    qtest_qmp_device_add(qts, "virtio-net", "standby0",
1292                         "{'bus': 'root0',"
1293                         "'failover': 'on',"
1294                         "'netdev': 'hs0',"
1295                         "'mac': '"MAC_STANDBY0"'}");
1296
1297    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1298    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1299
1300    vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1301
1302    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1303    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1304
1305    qtest_qmp_device_add(qts, "virtio-net", "primary0",
1306                         "{'bus': 'root1',"
1307                         "'failover_pair_id': 'standby0',"
1308                         "'netdev': 'hs1',"
1309                         "'rombar': 0,"
1310                         "'romfile': '',"
1311                         "'mac': '"MAC_PRIMARY0"'}");
1312
1313    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1314    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1315
1316    args = qdict_from_jsonf_nofail("{}");
1317    g_assert_nonnull(args);
1318    qdict_put_str(args, "uri", uri);
1319
1320    resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1321    g_assert(qdict_haskey(resp, "return"));
1322    qobject_unref(resp);
1323
1324    /* the event is sent when QEMU asks the OS to unplug the card */
1325    resp = get_unplug_primary_event(qts);
1326    g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1327    qobject_unref(resp);
1328
1329    /* OS unplugs the cards, QEMU can move from wait-unplug state */
1330    qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1331
1332    while (true) {
1333        ret = migrate_status(qts);
1334
1335        status = qdict_get_str(ret, "status");
1336        g_assert_cmpstr(status, !=, "failed");
1337        if (strcmp(status, "wait-unplug") != 0) {
1338            qobject_unref(ret);
1339            break;
1340        }
1341        qobject_unref(ret);
1342    }
1343
1344    resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1345    g_assert(qdict_haskey(resp, "return"));
1346    qobject_unref(resp);
1347
1348    while (true) {
1349        ret = migrate_status(qts);
1350
1351        status = qdict_get_str(ret, "status");
1352        if (strcmp(status, "completed") == 0) {
1353            g_test_skip("Failed to cancel the migration");
1354            qobject_unref(ret);
1355            goto out;
1356        }
1357        if (strcmp(status, "cancelled") == 0) {
1358            qobject_unref(ret);
1359            break;
1360        }
1361        g_assert_cmpstr(status, !=, "failed");
1362        g_assert_cmpstr(status, !=, "active");
1363        qobject_unref(ret);
1364    }
1365
1366    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1367    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1368
1369out:
1370    qos_object_destroy((QOSGraphObject *)vdev);
1371    machine_stop(qts);
1372}
1373
1374static void test_migrate_off_abort(gconstpointer opaque)
1375{
1376    QTestState *qts;
1377    QDict *resp, *args, *ret;
1378    g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1379    const gchar *status;
1380    QVirtioPCIDevice *vdev;
1381
1382    qts = machine_start(BASE_MACHINE
1383                     "-netdev user,id=hs0 "
1384                     "-netdev user,id=hs1 ",
1385                     2);
1386
1387    check_one_card(qts, false, "standby0", MAC_STANDBY0);
1388    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1389
1390    qtest_qmp_device_add(qts, "virtio-net", "standby0",
1391                         "{'bus': 'root0',"
1392                         "'failover': 'off',"
1393                         "'netdev': 'hs0',"
1394                         "'mac': '"MAC_STANDBY0"'}");
1395
1396    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1397    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1398
1399    vdev = start_virtio_net(qts, 1, 0, "standby0", false);
1400
1401    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1402    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1403
1404    qtest_qmp_device_add(qts, "virtio-net", "primary0",
1405                         "{'bus': 'root1',"
1406                         "'failover_pair_id': 'standby0',"
1407                         "'netdev': 'hs1',"
1408                         "'rombar': 0,"
1409                         "'romfile': '',"
1410                         "'mac': '"MAC_PRIMARY0"'}");
1411
1412    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1413    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1414
1415    args = qdict_from_jsonf_nofail("{}");
1416    g_assert_nonnull(args);
1417    qdict_put_str(args, "uri", uri);
1418
1419    resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1420    g_assert(qdict_haskey(resp, "return"));
1421    qobject_unref(resp);
1422
1423    while (true) {
1424        ret = migrate_status(qts);
1425
1426        status = qdict_get_str(ret, "status");
1427        if (strcmp(status, "active") == 0) {
1428            qobject_unref(ret);
1429            break;
1430        }
1431        g_assert_cmpstr(status, !=, "failed");
1432        qobject_unref(ret);
1433    }
1434
1435    resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1436    g_assert(qdict_haskey(resp, "return"));
1437    qobject_unref(resp);
1438
1439    while (true) {
1440        ret = migrate_status(qts);
1441
1442        status = qdict_get_str(ret, "status");
1443        if (strcmp(status, "completed") == 0) {
1444            g_test_skip("Failed to cancel the migration");
1445            qobject_unref(ret);
1446            goto out;
1447        }
1448        if (strcmp(status, "cancelled") == 0) {
1449            qobject_unref(ret);
1450            break;
1451        }
1452        g_assert_cmpstr(status, !=, "failed");
1453        g_assert_cmpstr(status, !=, "active");
1454        qobject_unref(ret);
1455    }
1456
1457    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1458    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1459
1460out:
1461    qos_object_destroy((QOSGraphObject *)vdev);
1462    machine_stop(qts);
1463}
1464
1465static void test_migrate_abort_timeout(gconstpointer opaque)
1466{
1467    QTestState *qts;
1468    QDict *resp, *args, *ret;
1469    g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1470    const gchar *status;
1471    int total;
1472    QVirtioPCIDevice *vdev;
1473
1474    qts = machine_start(BASE_MACHINE
1475                     "-netdev user,id=hs0 "
1476                     "-netdev user,id=hs1 ",
1477                     2);
1478
1479    check_one_card(qts, false, "standby0", MAC_STANDBY0);
1480    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1481
1482    qtest_qmp_device_add(qts, "virtio-net", "standby0",
1483                         "{'bus': 'root0',"
1484                         "'failover': 'on',"
1485                         "'netdev': 'hs0',"
1486                         "'mac': '"MAC_STANDBY0"'}");
1487
1488    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1489    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1490
1491    vdev = start_virtio_net(qts, 1, 0, "standby0", true);
1492
1493    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1494    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1495
1496    qtest_qmp_device_add(qts, "virtio-net", "primary0",
1497                         "{'bus': 'root1',"
1498                         "'failover_pair_id': 'standby0',"
1499                         "'netdev': 'hs1',"
1500                         "'rombar': 0,"
1501                         "'romfile': '',"
1502                         "'mac': '"MAC_PRIMARY0"'}");
1503
1504    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1505    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1506
1507    args = qdict_from_jsonf_nofail("{}");
1508    g_assert_nonnull(args);
1509    qdict_put_str(args, "uri", uri);
1510
1511    resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1512    g_assert(qdict_haskey(resp, "return"));
1513    qobject_unref(resp);
1514
1515    /* the event is sent when QEMU asks the OS to unplug the card */
1516    resp = get_unplug_primary_event(qts);
1517    g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "primary0");
1518    qobject_unref(resp);
1519
1520    resp = qtest_qmp(qts, "{ 'execute': 'migrate_cancel' }");
1521    g_assert(qdict_haskey(resp, "return"));
1522    qobject_unref(resp);
1523
1524    /* migration has been cancelled while the unplug was in progress */
1525
1526    /* while the card is not ejected, we must be in "cancelling" state */
1527
1528    total = 0;
1529    while (true) {
1530        ret = migrate_status(qts);
1531
1532        status = qdict_get_str(ret, "status");
1533        if (strcmp(status, "cancelled") == 0) {
1534            qobject_unref(ret);
1535            break;
1536        }
1537        g_assert_cmpstr(status, ==, "cancelling");
1538        g_assert(qdict_haskey(ret, "total-time"));
1539        total = qdict_get_int(ret, "total-time");
1540        qobject_unref(ret);
1541    }
1542
1543    /*
1544     * migration timeout in this case is 30 seconds
1545     * check we exit on the timeout (ms)
1546     */
1547    g_assert_cmpint(total, >, 30000);
1548
1549    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1550    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1551
1552    qos_object_destroy((QOSGraphObject *)vdev);
1553    machine_stop(qts);
1554}
1555
1556static void test_multi_out(gconstpointer opaque)
1557{
1558    QTestState *qts;
1559    QDict *resp, *args, *ret;
1560    g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque);
1561    const gchar *status, *expected;
1562    QVirtioPCIDevice *vdev0, *vdev1;
1563
1564    qts = machine_start(BASE_MACHINE
1565                "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1566                "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1567                "-netdev user,id=hs0 "
1568                "-netdev user,id=hs1 "
1569                "-netdev user,id=hs2 "
1570                "-netdev user,id=hs3 ",
1571                4);
1572
1573    check_one_card(qts, false, "standby0", MAC_STANDBY0);
1574    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1575    check_one_card(qts, false, "standby1", MAC_STANDBY1);
1576    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1577
1578    qtest_qmp_device_add(qts, "virtio-net", "standby0",
1579                         "{'bus': 'root0',"
1580                         "'failover': 'on',"
1581                         "'netdev': 'hs0',"
1582                         "'mac': '"MAC_STANDBY0"'}");
1583
1584    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1585    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1586    check_one_card(qts, false, "standby1", MAC_STANDBY1);
1587    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1588
1589    qtest_qmp_device_add(qts, "virtio-net", "primary0",
1590                         "{'bus': 'root1',"
1591                         "'failover_pair_id': 'standby0',"
1592                         "'netdev': 'hs1',"
1593                         "'rombar': 0,"
1594                         "'romfile': '',"
1595                         "'mac': '"MAC_PRIMARY0"'}");
1596
1597    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1598    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1599    check_one_card(qts, false, "standby1", MAC_STANDBY1);
1600    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1601
1602    vdev0 = start_virtio_net(qts, 1, 0, "standby0", true);
1603
1604    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1605    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1606    check_one_card(qts, false, "standby1", MAC_STANDBY1);
1607    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1608
1609    qtest_qmp_device_add(qts, "virtio-net", "standby1",
1610                         "{'bus': 'root2',"
1611                         "'failover': 'on',"
1612                         "'netdev': 'hs2',"
1613                         "'mac': '"MAC_STANDBY1"'}");
1614
1615    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1616    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1617    check_one_card(qts, true, "standby1", MAC_STANDBY1);
1618    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1619
1620    qtest_qmp_device_add(qts, "virtio-net", "primary1",
1621                         "{'bus': 'root3',"
1622                         "'failover_pair_id': 'standby1',"
1623                         "'netdev': 'hs3',"
1624                         "'rombar': 0,"
1625                         "'romfile': '',"
1626                         "'mac': '"MAC_PRIMARY1"'}");
1627
1628    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1629    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1630    check_one_card(qts, true, "standby1", MAC_STANDBY1);
1631    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1632
1633    vdev1 = start_virtio_net(qts, 3, 0, "standby1", true);
1634
1635    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1636    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1637    check_one_card(qts, true, "standby1", MAC_STANDBY1);
1638    check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1639
1640    args = qdict_from_jsonf_nofail("{}");
1641    g_assert_nonnull(args);
1642    qdict_put_str(args, "uri", uri);
1643
1644    resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args);
1645    g_assert(qdict_haskey(resp, "return"));
1646    qobject_unref(resp);
1647
1648    /* the event is sent when QEMU asks the OS to unplug the card */
1649    resp = get_unplug_primary_event(qts);
1650    if (strcmp(qdict_get_str(resp, "device-id"), "primary0") == 0) {
1651        expected = "primary1";
1652    } else if (strcmp(qdict_get_str(resp, "device-id"), "primary1") == 0) {
1653        expected = "primary0";
1654    } else {
1655        g_assert_not_reached();
1656    }
1657    qobject_unref(resp);
1658
1659    resp = get_unplug_primary_event(qts);
1660    g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, expected);
1661    qobject_unref(resp);
1662
1663    /* wait the end of the migration setup phase */
1664    while (true) {
1665        ret = migrate_status(qts);
1666
1667        status = qdict_get_str(ret, "status");
1668        if (strcmp(status, "wait-unplug") == 0) {
1669            qobject_unref(ret);
1670            break;
1671        }
1672
1673        /* The migration must not start if the card is not ejected */
1674        g_assert_cmpstr(status, !=, "active");
1675        g_assert_cmpstr(status, !=, "completed");
1676        g_assert_cmpstr(status, !=, "failed");
1677        g_assert_cmpstr(status, !=, "cancelling");
1678        g_assert_cmpstr(status, !=, "cancelled");
1679
1680        qobject_unref(ret);
1681    }
1682
1683    /* OS unplugs primary1, but we must wait the second */
1684    qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1685
1686    ret = migrate_status(qts);
1687    status = qdict_get_str(ret, "status");
1688    g_assert_cmpstr(status, ==, "wait-unplug");
1689    qobject_unref(ret);
1690
1691    if (g_test_slow()) {
1692        /* check we stay in wait-unplug while the card is not ejected */
1693        for (int i = 0; i < 5; i++) {
1694            sleep(1);
1695            ret = migrate_status(qts);
1696            status = qdict_get_str(ret, "status");
1697            g_assert_cmpstr(status, ==, "wait-unplug");
1698            qobject_unref(ret);
1699        }
1700    }
1701
1702    /* OS unplugs primary0, QEMU can move from wait-unplug state */
1703    qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_SEL_BASE, 2);
1704    qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1);
1705
1706    while (true) {
1707        ret = migrate_status(qts);
1708
1709        status = qdict_get_str(ret, "status");
1710        if (strcmp(status, "completed") == 0) {
1711            qobject_unref(ret);
1712            break;
1713        }
1714        g_assert_cmpstr(status, !=, "failed");
1715        g_assert_cmpstr(status, !=, "cancelling");
1716        g_assert_cmpstr(status, !=, "cancelled");
1717        qobject_unref(ret);
1718    }
1719
1720    qtest_qmp_eventwait(qts, "STOP");
1721
1722    qos_object_destroy((QOSGraphObject *)vdev0);
1723    qos_object_destroy((QOSGraphObject *)vdev1);
1724    machine_stop(qts);
1725}
1726
1727static void test_multi_in(gconstpointer opaque)
1728{
1729    QTestState *qts;
1730    QDict *resp, *args, *ret;
1731    g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque);
1732
1733    qts = machine_start(BASE_MACHINE
1734                "-device pcie-root-port,id=root2,addr=0x3,bus=pcie.0,chassis=3 "
1735                "-device pcie-root-port,id=root3,addr=0x4,bus=pcie.0,chassis=4 "
1736                "-netdev user,id=hs0 "
1737                "-netdev user,id=hs1 "
1738                "-netdev user,id=hs2 "
1739                "-netdev user,id=hs3 "
1740                "-incoming defer ",
1741                4);
1742
1743    check_one_card(qts, false, "standby0", MAC_STANDBY0);
1744    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1745    check_one_card(qts, false, "standby1", MAC_STANDBY1);
1746    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1747
1748    qtest_qmp_device_add(qts, "virtio-net", "standby0",
1749                         "{'bus': 'root0',"
1750                         "'failover': 'on',"
1751                         "'netdev': 'hs0',"
1752                         "'mac': '"MAC_STANDBY0"'}");
1753
1754    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1755    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1756    check_one_card(qts, false, "standby1", MAC_STANDBY1);
1757    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1758
1759    qtest_qmp_device_add(qts, "virtio-net", "primary0",
1760                         "{'bus': 'root1',"
1761                         "'failover_pair_id': 'standby0',"
1762                         "'netdev': 'hs1',"
1763                         "'rombar': 0,"
1764                         "'romfile': '',"
1765                         "'mac': '"MAC_PRIMARY0"'}");
1766
1767    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1768    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1769    check_one_card(qts, false, "standby1", MAC_STANDBY1);
1770    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1771
1772    qtest_qmp_device_add(qts, "virtio-net", "standby1",
1773                         "{'bus': 'root2',"
1774                         "'failover': 'on',"
1775                         "'netdev': 'hs2',"
1776                         "'mac': '"MAC_STANDBY1"'}");
1777
1778    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1779    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1780    check_one_card(qts, true, "standby1", MAC_STANDBY1);
1781    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1782
1783    qtest_qmp_device_add(qts, "virtio-net", "primary1",
1784                         "{'bus': 'root3',"
1785                         "'failover_pair_id': 'standby1',"
1786                         "'netdev': 'hs3',"
1787                         "'rombar': 0,"
1788                         "'romfile': '',"
1789                         "'mac': '"MAC_PRIMARY1"'}");
1790
1791    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1792    check_one_card(qts, false, "primary0", MAC_PRIMARY0);
1793    check_one_card(qts, true, "standby1", MAC_STANDBY1);
1794    check_one_card(qts, false, "primary1", MAC_PRIMARY1);
1795
1796    args = qdict_from_jsonf_nofail("{}");
1797    g_assert_nonnull(args);
1798    qdict_put_str(args, "uri", uri);
1799
1800    resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
1801                     args);
1802    g_assert(qdict_haskey(resp, "return"));
1803    qobject_unref(resp);
1804
1805    resp = get_migration_event(qts);
1806    g_assert_cmpstr(qdict_get_str(resp, "status"), ==, "setup");
1807    qobject_unref(resp);
1808
1809    resp = get_failover_negociated_event(qts);
1810    g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby0");
1811    qobject_unref(resp);
1812
1813    resp = get_failover_negociated_event(qts);
1814    g_assert_cmpstr(qdict_get_str(resp, "device-id"), ==, "standby1");
1815    qobject_unref(resp);
1816
1817    check_one_card(qts, true, "standby0", MAC_STANDBY0);
1818    check_one_card(qts, true, "primary0", MAC_PRIMARY0);
1819    check_one_card(qts, true, "standby1", MAC_STANDBY1);
1820    check_one_card(qts, true, "primary1", MAC_PRIMARY1);
1821
1822    qtest_qmp_eventwait(qts, "RESUME");
1823
1824    ret = migrate_status(qts);
1825    g_assert_cmpstr(qdict_get_str(ret, "status"), ==, "completed");
1826    qobject_unref(ret);
1827
1828    machine_stop(qts);
1829}
1830
1831int main(int argc, char **argv)
1832{
1833    gchar *tmpfile;
1834    int ret;
1835
1836    g_test_init(&argc, &argv, NULL);
1837
1838    ret = g_file_open_tmp("failover_test_migrate-XXXXXX", &tmpfile, NULL);
1839    g_assert_true(ret >= 0);
1840    close(ret);
1841
1842    /* parameters tests */
1843    qtest_add_func("failover-virtio-net/params/error/id", test_error_id);
1844    qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie);
1845    qtest_add_func("failover-virtio-net/params/on", test_on);
1846    qtest_add_func("failover-virtio-net/params/on_mismatch",
1847                   test_on_mismatch);
1848    qtest_add_func("failover-virtio-net/params/off", test_off);
1849    qtest_add_func("failover-virtio-net/params/enabled", test_enabled);
1850    qtest_add_func("failover-virtio-net/params/guest_off", test_guest_off);
1851
1852    /* hotplug tests */
1853    qtest_add_func("failover-virtio-net/hotplug/1", test_hotplug_1);
1854    qtest_add_func("failover-virtio-net/hotplug/1_reverse",
1855                   test_hotplug_1_reverse);
1856    qtest_add_func("failover-virtio-net/hotplug/2", test_hotplug_2);
1857    qtest_add_func("failover-virtio-net/hotplug/2_reverse",
1858                   test_hotplug_2_reverse);
1859
1860    /* migration tests */
1861    qtest_add_data_func("failover-virtio-net/migrate/on/out", tmpfile,
1862                        test_migrate_out);
1863    qtest_add_data_func("failover-virtio-net/migrate/on/in", tmpfile,
1864                        test_migrate_in);
1865    qtest_add_data_func("failover-virtio-net/migrate/off/out", tmpfile,
1866                        test_off_migrate_out);
1867    qtest_add_data_func("failover-virtio-net/migrate/off/in", tmpfile,
1868                        test_off_migrate_in);
1869    qtest_add_data_func("failover-virtio-net/migrate/off/abort", tmpfile,
1870                        test_migrate_off_abort);
1871    qtest_add_data_func("failover-virtio-net/migrate/guest_off/out", tmpfile,
1872                        test_guest_off_migrate_out);
1873    qtest_add_data_func("failover-virtio-net/migrate/guest_off/in", tmpfile,
1874                        test_guest_off_migrate_in);
1875    qtest_add_data_func("failover-virtio-net/migrate/guest_off/abort", tmpfile,
1876                        test_migrate_guest_off_abort);
1877    qtest_add_data_func("failover-virtio-net/migrate/abort/wait-unplug",
1878                        tmpfile, test_migrate_abort_wait_unplug);
1879    qtest_add_data_func("failover-virtio-net/migrate/abort/active", tmpfile,
1880                        test_migrate_abort_active);
1881    if (g_test_slow()) {
1882        qtest_add_data_func("failover-virtio-net/migrate/abort/timeout",
1883                            tmpfile, test_migrate_abort_timeout);
1884    }
1885    qtest_add_data_func("failover-virtio-net/migrate/multi/out",
1886                        tmpfile, test_multi_out);
1887    qtest_add_data_func("failover-virtio-net/migrate/multi/in",
1888                   tmpfile, test_multi_in);
1889
1890    ret = g_test_run();
1891
1892    unlink(tmpfile);
1893    g_free(tmpfile);
1894
1895    return ret;
1896}
1897