qemu_migration.c 179.2 KB
Newer Older
1 2 3
/*
 * qemu_migration.c: QEMU migration handling
 *
4
 * Copyright (C) 2006-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22 23
 *
 */

#include <config.h>

J
Ján Tomko 已提交
24 25
#include <netdb.h>
#include <sys/socket.h>
26
#include <sys/time.h>
27
#ifdef WITH_GNUTLS
28 29 30
# include <gnutls/gnutls.h>
# include <gnutls/x509.h>
#endif
31
#include <fcntl.h>
32
#include <poll.h>
33 34 35 36 37 38

#include "qemu_migration.h"
#include "qemu_monitor.h"
#include "qemu_domain.h"
#include "qemu_process.h"
#include "qemu_capabilities.h"
39
#include "qemu_command.h"
40
#include "qemu_cgroup.h"
41
#include "qemu_hotplug.h"
42

43
#include "domain_audit.h"
44
#include "virlog.h"
45
#include "virerror.h"
46
#include "viralloc.h"
E
Eric Blake 已提交
47
#include "virfile.h"
48 49
#include "datatypes.h"
#include "fdstream.h"
50
#include "viruuid.h"
51
#include "virtime.h"
52
#include "locking/domain_lock.h"
53
#include "rpc/virnetsocket.h"
54
#include "virstoragefile.h"
M
Martin Kletzander 已提交
55
#include "viruri.h"
56
#include "virhook.h"
57
#include "virstring.h"
58
#include "virtypedparam.h"
M
Michael R. Hines 已提交
59
#include "virprocess.h"
60
#include "nwfilter_conf.h"
61 62 63

#define VIR_FROM_THIS VIR_FROM_QEMU

64 65
VIR_LOG_INIT("qemu.qemu_migration");

66 67 68 69 70 71 72 73 74 75 76 77 78
VIR_ENUM_IMPL(qemuMigrationJobPhase, QEMU_MIGRATION_PHASE_LAST,
              "none",
              "perform2",
              "begin3",
              "perform3",
              "perform3_done",
              "confirm3_cancelled",
              "confirm3",
              "prepare",
              "finish2",
              "finish3",
);

79
enum qemuMigrationCookieFlags {
80
    QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS,
81
    QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE,
82
    QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT,
83
    QEMU_MIGRATION_COOKIE_FLAG_NETWORK,
84
    QEMU_MIGRATION_COOKIE_FLAG_NBD,
85
    QEMU_MIGRATION_COOKIE_FLAG_STATS,
86 87 88 89 90 91 92

    QEMU_MIGRATION_COOKIE_FLAG_LAST
};

VIR_ENUM_DECL(qemuMigrationCookieFlag);
VIR_ENUM_IMPL(qemuMigrationCookieFlag,
              QEMU_MIGRATION_COOKIE_FLAG_LAST,
93 94 95 96
              "graphics",
              "lockstate",
              "persistent",
              "network",
97 98
              "nbd",
              "statistics");
99 100 101

enum qemuMigrationCookieFeatures {
    QEMU_MIGRATION_COOKIE_GRAPHICS  = (1 << QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS),
102
    QEMU_MIGRATION_COOKIE_LOCKSTATE = (1 << QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE),
103
    QEMU_MIGRATION_COOKIE_PERSISTENT = (1 << QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT),
104
    QEMU_MIGRATION_COOKIE_NETWORK = (1 << QEMU_MIGRATION_COOKIE_FLAG_NETWORK),
105
    QEMU_MIGRATION_COOKIE_NBD = (1 << QEMU_MIGRATION_COOKIE_FLAG_NBD),
106
    QEMU_MIGRATION_COOKIE_STATS = (1 << QEMU_MIGRATION_COOKIE_FLAG_STATS),
107 108 109 110 111 112 113 114 115 116 117 118
};

typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics;
typedef qemuMigrationCookieGraphics *qemuMigrationCookieGraphicsPtr;
struct _qemuMigrationCookieGraphics {
    int type;
    int port;
    int tlsPort;
    char *listen;
    char *tlsSubject;
};

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
typedef struct _qemuMigrationCookieNetData qemuMigrationCookieNetData;
typedef qemuMigrationCookieNetData *qemuMigrationCookieNetDataPtr;
struct _qemuMigrationCookieNetData {
    int vporttype; /* enum virNetDevVPortProfile */

    /*
     * Array of pointers to saved data. Each VIF will have it's own
     * data to transfer.
     */
    char *portdata;
};

typedef struct _qemuMigrationCookieNetwork qemuMigrationCookieNetwork;
typedef qemuMigrationCookieNetwork *qemuMigrationCookieNetworkPtr;
struct _qemuMigrationCookieNetwork {
    /* How many virtual NICs are we saving data for? */
    int nnets;

    qemuMigrationCookieNetDataPtr net;
};

140 141 142 143
typedef struct _qemuMigrationCookieNBD qemuMigrationCookieNBD;
typedef qemuMigrationCookieNBD *qemuMigrationCookieNBDPtr;
struct _qemuMigrationCookieNBD {
    int port; /* on which port does NBD server listen for incoming data */
144 145 146 147 148 149

    size_t ndisks;  /* Number of items in @disk array */
    struct {
        char *target;                   /* Disk target */
        unsigned long long capacity;    /* And its capacity */
    } *disks;
150 151
};

152 153 154
typedef struct _qemuMigrationCookie qemuMigrationCookie;
typedef qemuMigrationCookie *qemuMigrationCookiePtr;
struct _qemuMigrationCookie {
E
Eric Blake 已提交
155 156
    unsigned int flags;
    unsigned int flagsMandatory;
157 158

    /* Host properties */
159 160 161 162
    unsigned char localHostuuid[VIR_UUID_BUFLEN];
    unsigned char remoteHostuuid[VIR_UUID_BUFLEN];
    char *localHostname;
    char *remoteHostname;
163 164 165 166

    /* Guest properties */
    unsigned char uuid[VIR_UUID_BUFLEN];
    char *name;
167

168 169 170 171
    /* If (flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) */
    char *lockState;
    char *lockDriver;

172 173
    /* If (flags & QEMU_MIGRATION_COOKIE_GRAPHICS) */
    qemuMigrationCookieGraphicsPtr graphics;
174 175 176

    /* If (flags & QEMU_MIGRATION_COOKIE_PERSISTENT) */
    virDomainDefPtr persistent;
177 178 179

    /* If (flags & QEMU_MIGRATION_COOKIE_NETWORK) */
    qemuMigrationCookieNetworkPtr network;
180 181 182

    /* If (flags & QEMU_MIGRATION_COOKIE_NBD) */
    qemuMigrationCookieNBDPtr nbd;
183 184 185

    /* If (flags & QEMU_MIGRATION_COOKIE_STATS) */
    qemuDomainJobInfoPtr jobInfo;
186 187
};

188 189 190 191 192 193 194 195 196
static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap)
{
    if (!grap)
        return;
    VIR_FREE(grap->listen);
    VIR_FREE(grap->tlsSubject);
    VIR_FREE(grap);
}

197

198 199 200
static void
qemuMigrationCookieNetworkFree(qemuMigrationCookieNetworkPtr network)
{
201
    size_t i;
202 203 204 205 206 207 208 209 210 211 212 213 214

    if (!network)
        return;

    if (network->net) {
        for (i = 0; i < network->nnets; i++)
            VIR_FREE(network->net[i].portdata);
    }
    VIR_FREE(network->net);
    VIR_FREE(network);
}


215 216 217 218 219 220 221 222 223 224 225 226
static void qemuMigrationCookieNBDFree(qemuMigrationCookieNBDPtr nbd)
{
    if (!nbd)
        return;

    while (nbd->ndisks)
        VIR_FREE(nbd->disks[--nbd->ndisks].target);
    VIR_FREE(nbd->disks);
    VIR_FREE(nbd);
}


227 228 229 230 231
static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig)
{
    if (!mig)
        return;

232 233
    qemuMigrationCookieGraphicsFree(mig->graphics);
    qemuMigrationCookieNetworkFree(mig->network);
234
    qemuMigrationCookieNBDFree(mig->nbd);
235

236 237
    VIR_FREE(mig->localHostname);
    VIR_FREE(mig->remoteHostname);
238
    VIR_FREE(mig->name);
239 240
    VIR_FREE(mig->lockState);
    VIR_FREE(mig->lockDriver);
241
    VIR_FREE(mig->jobInfo);
242 243 244 245
    VIR_FREE(mig);
}


246
#ifdef WITH_GNUTLS
247 248 249 250 251 252 253 254 255 256 257 258
static char *
qemuDomainExtractTLSSubject(const char *certdir)
{
    char *certfile = NULL;
    char *subject = NULL;
    char *pemdata = NULL;
    gnutls_datum_t pemdatum;
    gnutls_x509_crt_t cert;
    int ret;
    size_t subjectlen;

    if (virAsprintf(&certfile, "%s/server-cert.pem", certdir) < 0)
259
        goto error;
260 261

    if (virFileReadAll(certfile, 8192, &pemdata) < 0) {
262 263
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unable to read server cert %s"), certfile);
264 265 266 267 268
        goto error;
    }

    ret = gnutls_x509_crt_init(&cert);
    if (ret < 0) {
269 270 271
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot initialize cert object: %s"),
                       gnutls_strerror(ret));
272 273 274 275 276 277 278 279
        goto error;
    }

    pemdatum.data = (unsigned char *)pemdata;
    pemdatum.size = strlen(pemdata);

    ret = gnutls_x509_crt_import(cert, &pemdatum, GNUTLS_X509_FMT_PEM);
    if (ret < 0) {
280 281 282
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot load cert data from %s: %s"),
                       certfile, gnutls_strerror(ret));
283 284 285 286 287
        goto error;
    }

    subjectlen = 1024;
    if (VIR_ALLOC_N(subject, subjectlen+1) < 0)
288
        goto error;
289 290 291 292 293 294 295 296 297

    gnutls_x509_crt_get_dn(cert, subject, &subjectlen);
    subject[subjectlen] = '\0';

    VIR_FREE(certfile);
    VIR_FREE(pemdata);

    return subject;

298
 error:
299 300 301 302
    VIR_FREE(certfile);
    VIR_FREE(pemdata);
    return NULL;
}
303
#endif
304 305

static qemuMigrationCookieGraphicsPtr
306
qemuMigrationCookieGraphicsAlloc(virQEMUDriverPtr driver,
307 308 309 310
                                 virDomainGraphicsDefPtr def)
{
    qemuMigrationCookieGraphicsPtr mig = NULL;
    const char *listenAddr;
311
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
312 313

    if (VIR_ALLOC(mig) < 0)
314
        goto error;
315 316 317 318

    mig->type = def->type;
    if (mig->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
        mig->port = def->data.vnc.port;
319
        listenAddr = virDomainGraphicsListenGetAddress(def, 0);
320
        if (!listenAddr)
321
            listenAddr = cfg->vncListen;
322

323
#ifdef WITH_GNUTLS
324 325
        if (cfg->vncTLS &&
            !(mig->tlsSubject = qemuDomainExtractTLSSubject(cfg->vncTLSx509certdir)))
326
            goto error;
327
#endif
328 329
    } else {
        mig->port = def->data.spice.port;
330
        if (cfg->spiceTLS)
331 332 333
            mig->tlsPort = def->data.spice.tlsPort;
        else
            mig->tlsPort = -1;
334
        listenAddr = virDomainGraphicsListenGetAddress(def, 0);
335
        if (!listenAddr)
336
            listenAddr = cfg->spiceListen;
337

338
#ifdef WITH_GNUTLS
339 340
        if (cfg->spiceTLS &&
            !(mig->tlsSubject = qemuDomainExtractTLSSubject(cfg->spiceTLSx509certdir)))
341
            goto error;
342
#endif
343
    }
344 345
    if (VIR_STRDUP(mig->listen, listenAddr) < 0)
        goto error;
346

347
    virObjectUnref(cfg);
348 349
    return mig;

350
 error:
351
    qemuMigrationCookieGraphicsFree(mig);
352
    virObjectUnref(cfg);
353 354 355 356
    return NULL;
}


357
static qemuMigrationCookieNetworkPtr
358
qemuMigrationCookieNetworkAlloc(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
359 360 361
                                virDomainDefPtr def)
{
    qemuMigrationCookieNetworkPtr mig;
362
    size_t i;
363 364

    if (VIR_ALLOC(mig) < 0)
365
        goto error;
366 367 368 369

    mig->nnets = def->nnets;

    if (VIR_ALLOC_N(mig->net, def->nnets) <0)
370
        goto error;
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385

    for (i = 0; i < def->nnets; i++) {
        virDomainNetDefPtr netptr;
        virNetDevVPortProfilePtr vport;

        netptr = def->nets[i];
        vport = virDomainNetGetActualVirtPortProfile(netptr);

        if (vport) {
            mig->net[i].vporttype = vport->virtPortType;

            switch (vport->virtPortType) {
            case VIR_NETDEV_VPORT_PROFILE_NONE:
            case VIR_NETDEV_VPORT_PROFILE_8021QBG:
            case VIR_NETDEV_VPORT_PROFILE_8021QBH:
386
               break;
387
            case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
388 389
                if (virNetDevOpenvswitchGetMigrateData(&mig->net[i].portdata,
                                                       netptr->ifname) != 0) {
J
Jiri Denemark 已提交
390 391 392
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("Unable to run command to get OVS port data for "
                                         "interface %s"), netptr->ifname);
393 394 395
                        goto error;
                }
                break;
396 397 398 399 400 401 402
            default:
                break;
            }
        }
    }
    return mig;

403
 error:
404 405 406 407
    qemuMigrationCookieNetworkFree(mig);
    return NULL;
}

408 409 410
static qemuMigrationCookiePtr
qemuMigrationCookieNew(virDomainObjPtr dom)
{
J
Jiri Denemark 已提交
411
    qemuDomainObjPrivatePtr priv = dom->privateData;
412
    qemuMigrationCookiePtr mig = NULL;
J
Jiri Denemark 已提交
413
    const char *name;
414 415

    if (VIR_ALLOC(mig) < 0)
416
        goto error;
417

J
Jiri Denemark 已提交
418 419 420 421
    if (priv->origname)
        name = priv->origname;
    else
        name = dom->def->name;
422 423
    if (VIR_STRDUP(mig->name, name) < 0)
        goto error;
424 425
    memcpy(mig->uuid, dom->def->uuid, VIR_UUID_BUFLEN);

426
    if (!(mig->localHostname = virGetHostname()))
427
        goto error;
428
    if (virGetHostUUID(mig->localHostuuid) < 0) {
429 430
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to obtain host UUID"));
431 432 433 434 435
        goto error;
    }

    return mig;

436
 error:
437 438 439 440 441
    qemuMigrationCookieFree(mig);
    return NULL;
}


442 443
static int
qemuMigrationCookieAddGraphics(qemuMigrationCookiePtr mig,
444
                               virQEMUDriverPtr driver,
445 446
                               virDomainObjPtr dom)
{
447 448
    size_t i = 0;

449
    if (mig->flags & QEMU_MIGRATION_COOKIE_GRAPHICS) {
450 451
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Migration graphics data already present"));
452 453 454
        return -1;
    }

455 456 457 458 459 460 461 462
    for (i = 0; i < dom->def->ngraphics; i++) {
       if (dom->def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
           if (!(mig->graphics =
                 qemuMigrationCookieGraphicsAlloc(driver, dom->def->graphics[i])))
               return -1;
           mig->flags |= QEMU_MIGRATION_COOKIE_GRAPHICS;
           break;
       }
463
    }
464 465 466 467 468

    return 0;
}


469 470
static int
qemuMigrationCookieAddLockstate(qemuMigrationCookiePtr mig,
471
                                virQEMUDriverPtr driver,
472 473 474 475 476
                                virDomainObjPtr dom)
{
    qemuDomainObjPrivatePtr priv = dom->privateData;

    if (mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) {
477 478
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Migration lockstate data already present"));
479 480 481 482
        return -1;
    }

    if (virDomainObjGetState(dom, NULL) == VIR_DOMAIN_PAUSED) {
483
        if (VIR_STRDUP(mig->lockState, priv->lockState) < 0)
484 485 486 487 488 489
            return -1;
    } else {
        if (virDomainLockProcessInquire(driver->lockManager, dom, &mig->lockState) < 0)
            return -1;
    }

490
    if (VIR_STRDUP(mig->lockDriver, virLockManagerPluginGetName(driver->lockManager)) < 0) {
491 492 493 494 495 496 497 498 499 500 501
        VIR_FREE(mig->lockState);
        return -1;
    }

    mig->flags |= QEMU_MIGRATION_COOKIE_LOCKSTATE;
    mig->flagsMandatory |= QEMU_MIGRATION_COOKIE_LOCKSTATE;

    return 0;
}


502 503 504 505 506
static int
qemuMigrationCookieAddPersistent(qemuMigrationCookiePtr mig,
                                 virDomainObjPtr dom)
{
    if (mig->flags & QEMU_MIGRATION_COOKIE_PERSISTENT) {
507 508
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Migration persistent data already present"));
509 510 511 512 513 514 515 516 517 518 519 520 521
        return -1;
    }

    if (!dom->newDef)
        return 0;

    mig->persistent = dom->newDef;
    mig->flags |= QEMU_MIGRATION_COOKIE_PERSISTENT;
    mig->flagsMandatory |= QEMU_MIGRATION_COOKIE_PERSISTENT;
    return 0;
}


522 523
static int
qemuMigrationCookieAddNetwork(qemuMigrationCookiePtr mig,
524
                              virQEMUDriverPtr driver,
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
                              virDomainObjPtr dom)
{
    if (mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Network migration data already present"));
        return -1;
    }

    if (dom->def->nnets > 0) {
        mig->network = qemuMigrationCookieNetworkAlloc(driver, dom->def);
        if (!mig->network)
            return -1;
        mig->flags |= QEMU_MIGRATION_COOKIE_NETWORK;
    }

    return 0;
}

543

544 545
static int
qemuMigrationCookieAddNBD(qemuMigrationCookiePtr mig,
546
                          virQEMUDriverPtr driver,
547 548 549
                          virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
550 551 552
    virHashTablePtr stats = NULL;
    size_t i;
    int ret = -1;
553 554 555

    /* It is not a bug if there already is a NBD data */
    if (!mig->nbd &&
556
        VIR_ALLOC(mig->nbd) < 0)
557 558
        return -1;

559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
    if (vm->def->ndisks &&
        VIR_ALLOC_N(mig->nbd->disks, vm->def->ndisks) < 0)
        return -1;
    mig->nbd->ndisks = 0;

    for (i = 0; i < vm->def->ndisks; i++) {
        virDomainDiskDefPtr disk = vm->def->disks[i];
        qemuBlockStats *entry;

        if (!stats) {
            if (!(stats = virHashCreate(10, virHashValueFree)))
                goto cleanup;

            qemuDomainObjEnterMonitor(driver, vm);
            if (qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats) < 0) {
                qemuDomainObjExitMonitor(driver, vm);
                goto cleanup;
            }
            qemuDomainObjExitMonitor(driver, vm);

            if (!virDomainObjIsActive(vm)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("domain exited meanwhile"));
                goto cleanup;
            }
        }

        if (!disk->info.alias ||
            !(entry = virHashLookup(stats, disk->info.alias)))
            continue;

        if (VIR_STRDUP(mig->nbd->disks[mig->nbd->ndisks].target,
                       disk->dst) < 0)
            goto cleanup;
        mig->nbd->disks[mig->nbd->ndisks].capacity = entry->capacity;
        mig->nbd->ndisks++;
    }

597 598 599
    mig->nbd->port = priv->nbdPort;
    mig->flags |= QEMU_MIGRATION_COOKIE_NBD;

600 601 602 603
    ret = 0;
 cleanup:
    virHashFree(stats);
    return ret;
604 605 606
}


607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
static int
qemuMigrationCookieAddStatistics(qemuMigrationCookiePtr mig,
                                 virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

    if (!priv->job.completed)
        return 0;

    if (!mig->jobInfo && VIR_ALLOC(mig->jobInfo) < 0)
        return -1;

    *mig->jobInfo = *priv->job.completed;
    mig->flags |= QEMU_MIGRATION_COOKIE_STATS;

    return 0;
}


626 627 628
static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf,
                                                 qemuMigrationCookieGraphicsPtr grap)
{
629
    virBufferAsprintf(buf, "<graphics type='%s' port='%d' listen='%s'",
630 631 632 633 634 635
                      virDomainGraphicsTypeToString(grap->type),
                      grap->port, grap->listen);
    if (grap->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE)
        virBufferAsprintf(buf, " tlsPort='%d'", grap->tlsPort);
    if (grap->tlsSubject) {
        virBufferAddLit(buf, ">\n");
636 637 638 639
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<cert info='subject' value='%s'/>\n", grap->tlsSubject);
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</graphics>\n");
640 641 642 643 644 645
    } else {
        virBufferAddLit(buf, "/>\n");
    }
}


646 647 648 649
static void
qemuMigrationCookieNetworkXMLFormat(virBufferPtr buf,
                                    qemuMigrationCookieNetworkPtr optr)
{
650
    size_t i;
651 652 653 654 655 656
    bool empty = true;

    for (i = 0; i < optr->nnets; i++) {
        /* If optr->net[i].vporttype is not set, there is nothing to transfer */
        if (optr->net[i].vporttype != VIR_NETDEV_VPORT_PROFILE_NONE) {
            if (empty) {
657 658
                virBufferAddLit(buf, "<network>\n");
                virBufferAdjustIndent(buf, 2);
659 660
                empty = false;
            }
661
            virBufferAsprintf(buf, "<interface index='%zu' vporttype='%s'",
662 663 664
                              i, virNetDevVPortTypeToString(optr->net[i].vporttype));
            if (optr->net[i].portdata) {
                virBufferAddLit(buf, ">\n");
665 666
                virBufferAdjustIndent(buf, 2);
                virBufferEscapeString(buf, "<portdata>%s</portdata>\n",
667
                                      optr->net[i].portdata);
668 669
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</interface>\n");
670 671 672 673 674
            } else {
                virBufferAddLit(buf, "/>\n");
            }
        }
    }
675 676 677 678
    if (!empty) {
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</network>\n");
    }
679 680 681
}


682 683 684 685 686 687 688 689 690
static void
qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf,
                                       qemuDomainJobInfoPtr jobInfo)
{
    qemuMonitorMigrationStatus *status = &jobInfo->status;

    virBufferAddLit(buf, "<statistics>\n");
    virBufferAdjustIndent(buf, 2);

691 692 693
    virBufferAsprintf(buf, "<started>%llu</started>\n", jobInfo->started);
    virBufferAsprintf(buf, "<stopped>%llu</stopped>\n", jobInfo->stopped);

694 695 696 697 698 699 700 701 702 703
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_TIME_ELAPSED,
                      jobInfo->timeElapsed);
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_TIME_REMAINING,
                      jobInfo->timeRemaining);
    if (status->downtime_set)
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_DOWNTIME,
                          status->downtime);
704 705 706 707
    if (status->setup_time_set)
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_SETUP_TIME,
                          status->setup_time);
708 709 710 711 712 713 714 715 716 717

    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_MEMORY_TOTAL,
                      status->ram_total);
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_MEMORY_PROCESSED,
                      status->ram_transferred);
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_MEMORY_REMAINING,
                      status->ram_remaining);
718 719 720
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_MEMORY_BPS,
                      status->ram_bps);
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742

    if (status->ram_duplicate_set) {
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_MEMORY_CONSTANT,
                          status->ram_duplicate);
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_MEMORY_NORMAL,
                          status->ram_normal);
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES,
                          status->ram_normal_bytes);
    }

    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_DISK_TOTAL,
                      status->disk_total);
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_DISK_PROCESSED,
                      status->disk_transferred);
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_DISK_REMAINING,
                      status->disk_remaining);
743 744 745
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_DISK_BPS,
                      status->disk_bps);
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769

    if (status->xbzrle_set) {
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_COMPRESSION_CACHE,
                          status->xbzrle_cache_size);
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_COMPRESSION_BYTES,
                          status->xbzrle_bytes);
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_COMPRESSION_PAGES,
                          status->xbzrle_pages);
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES,
                          status->xbzrle_cache_miss);
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW,
                          status->xbzrle_overflow);
    }

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</statistics>\n");
}


770
static int
771
qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver,
772
                             virBufferPtr buf,
773
                             qemuMigrationCookiePtr mig)
774 775 776
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    char hostuuidstr[VIR_UUID_STRING_BUFLEN];
777
    size_t i;
778 779

    virUUIDFormat(mig->uuid, uuidstr);
780
    virUUIDFormat(mig->localHostuuid, hostuuidstr);
781

782
    virBufferAddLit(buf, "<qemu-migration>\n");
783 784 785 786 787
    virBufferAdjustIndent(buf, 2);
    virBufferEscapeString(buf, "<name>%s</name>\n", mig->name);
    virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr);
    virBufferEscapeString(buf, "<hostname>%s</hostname>\n", mig->localHostname);
    virBufferAsprintf(buf, "<hostuuid>%s</hostuuid>\n", hostuuidstr);
788

789
    for (i = 0; i < QEMU_MIGRATION_COOKIE_FLAG_LAST; i++) {
790
        if (mig->flagsMandatory & (1 << i))
791
            virBufferAsprintf(buf, "<feature name='%s'/>\n",
792 793 794
                              qemuMigrationCookieFlagTypeToString(i));
    }

795 796
    if ((mig->flags & QEMU_MIGRATION_COOKIE_GRAPHICS) &&
        mig->graphics)
797 798
        qemuMigrationCookieGraphicsXMLFormat(buf, mig->graphics);

799 800
    if ((mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) &&
        mig->lockState) {
801
        virBufferAsprintf(buf, "<lockstate driver='%s'>\n",
802
                          mig->lockDriver);
803 804
        virBufferAdjustIndent(buf, 2);
        virBufferAsprintf(buf, "<leases>%s</leases>\n",
805
                          mig->lockState);
806 807
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</lockstate>\n");
808 809
    }

810 811
    if ((mig->flags & QEMU_MIGRATION_COOKIE_PERSISTENT) &&
        mig->persistent) {
812 813 814
        if (qemuDomainDefFormatBuf(driver,
                                   mig->persistent,
                                   VIR_DOMAIN_XML_INACTIVE |
815 816
                                   VIR_DOMAIN_XML_SECURE |
                                   VIR_DOMAIN_XML_MIGRATABLE,
817
                                   buf) < 0)
818
            return -1;
819 820
    }

821 822 823
    if ((mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) && mig->network)
        qemuMigrationCookieNetworkXMLFormat(buf, mig->network);

824
    if ((mig->flags & QEMU_MIGRATION_COOKIE_NBD) && mig->nbd) {
825
        virBufferAddLit(buf, "<nbd");
826 827
        if (mig->nbd->port)
            virBufferAsprintf(buf, " port='%d'", mig->nbd->port);
828 829 830 831 832 833 834 835 836 837 838 839 840 841
        if (mig->nbd->ndisks) {
            virBufferAddLit(buf, ">\n");
            virBufferAdjustIndent(buf, 2);
            for (i = 0; i < mig->nbd->ndisks; i++) {
                virBufferEscapeString(buf, "<disk target='%s'",
                                      mig->nbd->disks[i].target);
                virBufferAsprintf(buf, " capacity='%llu'/>\n",
                                  mig->nbd->disks[i].capacity);
            }
            virBufferAdjustIndent(buf, -2);
            virBufferAddLit(buf, "</nbd>\n");
        } else {
            virBufferAddLit(buf, "/>\n");
        }
842 843
    }

844 845 846
    if (mig->flags & QEMU_MIGRATION_COOKIE_STATS && mig->jobInfo)
        qemuMigrationCookieStatisticsXMLFormat(buf, mig->jobInfo);

847
    virBufferAdjustIndent(buf, -2);
848
    virBufferAddLit(buf, "</qemu-migration>\n");
849
    return 0;
850 851 852
}


853
static char *qemuMigrationCookieXMLFormatStr(virQEMUDriverPtr driver,
854
                                             qemuMigrationCookiePtr mig)
855 856 857
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;

858
    if (qemuMigrationCookieXMLFormat(driver, &buf, mig) < 0) {
859 860 861
        virBufferFreeAndReset(&buf);
        return NULL;
    }
862

863
    if (virBufferCheckError(&buf) < 0)
864 865 866 867 868 869
        return NULL;

    return virBufferContentAndReset(&buf);
}


870 871 872 873 874 875 876
static qemuMigrationCookieGraphicsPtr
qemuMigrationCookieGraphicsXMLParse(xmlXPathContextPtr ctxt)
{
    qemuMigrationCookieGraphicsPtr grap;
    char *tmp;

    if (VIR_ALLOC(grap) < 0)
877
        goto error;
878 879

    if (!(tmp = virXPathString("string(./graphics/@type)", ctxt))) {
880 881
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing type attribute in migration data"));
882 883 884
        goto error;
    }
    if ((grap->type = virDomainGraphicsTypeFromString(tmp)) < 0) {
885 886
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown graphics type %s"), tmp);
887 888 889
        VIR_FREE(tmp);
        goto error;
    }
E
Eric Blake 已提交
890
    VIR_FREE(tmp);
891
    if (virXPathInt("string(./graphics/@port)", ctxt, &grap->port) < 0) {
892 893
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing port attribute in migration data"));
894 895 896 897
        goto error;
    }
    if (grap->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
        if (virXPathInt("string(./graphics/@tlsPort)", ctxt, &grap->tlsPort) < 0) {
898 899
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing tlsPort attribute in migration data"));
900 901 902 903
            goto error;
        }
    }
    if (!(grap->listen = virXPathString("string(./graphics/@listen)", ctxt))) {
904 905
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing listen attribute in migration data"));
906 907 908
        goto error;
    }
    /* Optional */
909
    grap->tlsSubject = virXPathString("string(./graphics/cert[@info='subject']/@value)", ctxt);
910 911 912

    return grap;

913
 error:
914 915 916 917 918
    qemuMigrationCookieGraphicsFree(grap);
    return NULL;
}


919 920 921 922
static qemuMigrationCookieNetworkPtr
qemuMigrationCookieNetworkXMLParse(xmlXPathContextPtr ctxt)
{
    qemuMigrationCookieNetworkPtr optr;
923
    size_t i;
924 925 926 927 928 929
    int n;
    xmlNodePtr *interfaces = NULL;
    char *vporttype;
    xmlNodePtr save_ctxt = ctxt->node;

    if (VIR_ALLOC(optr) < 0)
930
        goto error;
931 932 933 934 935 936 937 938

    if ((n = virXPathNodeSet("./network/interface", ctxt, &interfaces)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing interface information"));
        goto error;
    }

    optr->nnets = n;
939
    if (VIR_ALLOC_N(optr->net, optr->nnets) < 0)
940
        goto error;
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956

    for (i = 0; i < n; i++) {
        /* portdata is optional, and may not exist */
        ctxt->node = interfaces[i];
        optr->net[i].portdata = virXPathString("string(./portdata[1])", ctxt);

        if (!(vporttype = virXMLPropString(interfaces[i], "vporttype"))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing vporttype attribute in migration data"));
            goto error;
        }
        optr->net[i].vporttype = virNetDevVPortTypeFromString(vporttype);
    }

    VIR_FREE(interfaces);

957
 cleanup:
958 959 960
    ctxt->node = save_ctxt;
    return optr;

961
 error:
962 963 964 965 966 967 968
    VIR_FREE(interfaces);
    qemuMigrationCookieNetworkFree(optr);
    optr = NULL;
    goto cleanup;
}


969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
static qemuMigrationCookieNBDPtr
qemuMigrationCookieNBDXMLParse(xmlXPathContextPtr ctxt)
{
    qemuMigrationCookieNBDPtr ret = NULL;
    char *port = NULL, *capacity = NULL;
    size_t i;
    int n;
    xmlNodePtr *disks = NULL;
    xmlNodePtr save_ctxt = ctxt->node;

    if (VIR_ALLOC(ret) < 0)
        goto error;

    port = virXPathString("string(./nbd/@port)", ctxt);
    if (port && virStrToLong_i(port, NULL, 10, &ret->port) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Malformed nbd port '%s'"),
                       port);
        goto error;
    }

    /* Now check if source sent a list of disks to prealloc. We might be
     * talking to an older server, so it's not an error if the list is
     * missing. */
    if ((n = virXPathNodeSet("./nbd/disk", ctxt, &disks)) > 0) {
        if (VIR_ALLOC_N(ret->disks, n) < 0)
            goto error;
        ret->ndisks = n;

        for (i = 0; i < n; i++) {
            ctxt->node = disks[i];
            VIR_FREE(capacity);

            if (!(ret->disks[i].target = virXPathString("string(./@target)", ctxt))) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Malformed disk target"));
                goto error;
            }

            capacity = virXPathString("string(./@capacity)", ctxt);
            if (!capacity ||
                virStrToLong_ull(capacity, NULL, 10,
                                 &ret->disks[i].capacity) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Malformed disk capacity: '%s'"),
                               NULLSTR(capacity));
                goto error;
            }
        }
    }

 cleanup:
    VIR_FREE(port);
    VIR_FREE(capacity);
    VIR_FREE(disks);
    ctxt->node = save_ctxt;
    return ret;
 error:
    qemuMigrationCookieNBDFree(ret);
    ret = NULL;
    goto cleanup;
}


1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
static qemuDomainJobInfoPtr
qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt)
{
    qemuDomainJobInfoPtr jobInfo = NULL;
    qemuMonitorMigrationStatus *status;
    xmlNodePtr save_ctxt = ctxt->node;

    if (!(ctxt->node = virXPathNode("./statistics", ctxt)))
        goto cleanup;

    if (VIR_ALLOC(jobInfo) < 0)
        goto cleanup;

    status = &jobInfo->status;
    jobInfo->type = VIR_DOMAIN_JOB_COMPLETED;

1049 1050 1051
    virXPathULongLong("string(./started[1])", ctxt, &jobInfo->started);
    virXPathULongLong("string(./stopped[1])", ctxt, &jobInfo->stopped);

1052 1053 1054 1055 1056 1057 1058
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_TIME_ELAPSED "[1])",
                      ctxt, &jobInfo->timeElapsed);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_TIME_REMAINING "[1])",
                      ctxt, &jobInfo->timeRemaining);
    if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_DOWNTIME "[1])",
                          ctxt, &status->downtime) == 0)
        status->downtime_set = true;
1059 1060 1061
    if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_SETUP_TIME "[1])",
                          ctxt, &status->setup_time) == 0)
        status->setup_time_set = true;
1062 1063 1064 1065 1066 1067 1068

    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_TOTAL "[1])",
                      ctxt, &status->ram_total);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_PROCESSED "[1])",
                      ctxt, &status->ram_transferred);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_REMAINING "[1])",
                      ctxt, &status->ram_remaining);
1069 1070
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_BPS "[1])",
                      ctxt, &status->ram_bps);
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085

    if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_CONSTANT "[1])",
                          ctxt, &status->ram_duplicate) == 0)
        status->ram_duplicate_set = true;
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_NORMAL "[1])",
                      ctxt, &status->ram_normal);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES "[1])",
                      ctxt, &status->ram_normal_bytes);

    virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_TOTAL "[1])",
                      ctxt, &status->disk_total);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_PROCESSED "[1])",
                      ctxt, &status->disk_transferred);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_REMAINING "[1])",
                      ctxt, &status->disk_remaining);
1086 1087
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_BPS "[1])",
                      ctxt, &status->disk_bps);
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106

    if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE "[1])",
                          ctxt, &status->xbzrle_cache_size) == 0)
        status->xbzrle_set = true;
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_BYTES "[1])",
                      ctxt, &status->xbzrle_bytes);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_PAGES "[1])",
                      ctxt, &status->xbzrle_pages);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES "[1])",
                      ctxt, &status->xbzrle_cache_miss);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW "[1])",
                      ctxt, &status->xbzrle_overflow);

 cleanup:
    ctxt->node = save_ctxt;
    return jobInfo;
}


1107 1108
static int
qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig,
1109
                            virQEMUDriverPtr driver,
1110
                            xmlDocPtr doc,
1111
                            xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
1112
                            unsigned int flags)
1113 1114
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
1115
    char *tmp = NULL;
1116
    xmlNodePtr *nodes = NULL;
1117 1118
    size_t i;
    int n;
1119 1120 1121 1122
    virCapsPtr caps = NULL;

    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto error;
1123 1124 1125 1126 1127 1128 1129 1130

    /* We don't store the uuid, name, hostname, or hostuuid
     * values. We just compare them to local data to do some
     * sanity checking on migration operation
     */

    /* Extract domain name */
    if (!(tmp = virXPathString("string(./name[1])", ctxt))) {
1131 1132
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing name element in migration data"));
1133 1134 1135
        goto error;
    }
    if (STRNEQ(tmp, mig->name)) {
1136 1137 1138
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Incoming cookie data had unexpected name %s vs %s"),
                       tmp, mig->name);
1139 1140 1141 1142 1143 1144 1145
        goto error;
    }
    VIR_FREE(tmp);

    /* Extract domain uuid */
    tmp = virXPathString("string(./uuid[1])", ctxt);
    if (!tmp) {
1146 1147
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing uuid element in migration data"));
1148 1149 1150 1151
        goto error;
    }
    virUUIDFormat(mig->uuid, uuidstr);
    if (STRNEQ(tmp, uuidstr)) {
1152 1153 1154
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Incoming cookie data had unexpected UUID %s vs %s"),
                       tmp, uuidstr);
1155 1156 1157 1158
    }
    VIR_FREE(tmp);

    /* Check & forbid "localhost" migration */
1159
    if (!(mig->remoteHostname = virXPathString("string(./hostname[1])", ctxt))) {
1160 1161
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing hostname element in migration data"));
1162 1163
        goto error;
    }
1164
    if (STREQ(mig->remoteHostname, mig->localHostname)) {
1165 1166 1167
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Attempt to migrate guest to the same host %s"),
                       mig->remoteHostname);
1168 1169 1170 1171
        goto error;
    }

    if (!(tmp = virXPathString("string(./hostuuid[1])", ctxt))) {
1172 1173 1174
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing hostuuid element in migration data"));
        goto error;
1175
    }
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
    if (virUUIDParse(tmp, mig->remoteHostuuid) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed hostuuid element in migration data"));
        goto error;
    }
    if (memcmp(mig->remoteHostuuid, mig->localHostuuid, VIR_UUID_BUFLEN) == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Attempt to migrate guest to the same host %s"),
                       tmp);
        goto error;
    }
    VIR_FREE(tmp);
1188

1189 1190
    /* Check to ensure all mandatory features from XML are also
     * present in 'flags' */
1191
    if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0)
1192 1193
        goto error;

1194
    for (i = 0; i < n; i++) {
1195 1196 1197
        int val;
        char *str = virXMLPropString(nodes[i], "name");
        if (!str) {
1198 1199
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing feature name"));
1200 1201 1202 1203
            goto error;
        }

        if ((val = qemuMigrationCookieFlagTypeFromString(str)) < 0) {
1204 1205 1206
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown migration cookie feature %s"),
                           str);
1207 1208 1209 1210 1211
            VIR_FREE(str);
            goto error;
        }

        if ((flags & (1 << val)) == 0) {
1212 1213 1214
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unsupported migration cookie feature %s"),
                           str);
1215 1216 1217 1218 1219 1220
            VIR_FREE(str);
        }
        VIR_FREE(str);
    }
    VIR_FREE(nodes);

1221 1222 1223 1224 1225
    if ((flags & QEMU_MIGRATION_COOKIE_GRAPHICS) &&
        virXPathBoolean("count(./graphics) > 0", ctxt) &&
        (!(mig->graphics = qemuMigrationCookieGraphicsXMLParse(ctxt))))
        goto error;

1226 1227 1228 1229
    if ((flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) &&
        virXPathBoolean("count(./lockstate) > 0", ctxt)) {
        mig->lockDriver = virXPathString("string(./lockstate[1]/@driver)", ctxt);
        if (!mig->lockDriver) {
1230 1231
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing lock driver name in migration cookie"));
1232 1233 1234 1235 1236 1237 1238
            goto error;
        }
        mig->lockState = virXPathString("string(./lockstate[1]/leases[1])", ctxt);
        if (mig->lockState && STREQ(mig->lockState, ""))
            VIR_FREE(mig->lockState);
    }

1239 1240 1241
    if ((flags & QEMU_MIGRATION_COOKIE_PERSISTENT) &&
        virXPathBoolean("count(./domain) > 0", ctxt)) {
        if ((n = virXPathNodeSet("./domain", ctxt, &nodes)) > 1) {
1242 1243 1244 1245
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Too many domain elements in "
                             "migration cookie: %d"),
                           n);
1246 1247
            goto error;
        }
1248 1249
        mig->persistent = virDomainDefParseNode(doc, nodes[0],
                                                caps, driver->xmlopt,
1250 1251 1252 1253 1254 1255 1256 1257 1258
                                                -1, VIR_DOMAIN_XML_INACTIVE);
        if (!mig->persistent) {
            /* virDomainDefParseNode already reported
             * an error for us */
            goto error;
        }
        VIR_FREE(nodes);
    }

1259 1260 1261 1262 1263
    if ((flags & QEMU_MIGRATION_COOKIE_NETWORK) &&
        virXPathBoolean("count(./network) > 0", ctxt) &&
        (!(mig->network = qemuMigrationCookieNetworkXMLParse(ctxt))))
        goto error;

1264
    if (flags & QEMU_MIGRATION_COOKIE_NBD &&
1265 1266 1267
        virXPathBoolean("boolean(./nbd)", ctxt) &&
        (!(mig->nbd = qemuMigrationCookieNBDXMLParse(ctxt))))
        goto error;
1268

1269 1270 1271 1272 1273
    if (flags & QEMU_MIGRATION_COOKIE_STATS &&
        virXPathBoolean("boolean(./statistics)", ctxt) &&
        (!(mig->jobInfo = qemuMigrationCookieStatisticsXMLParse(ctxt))))
        goto error;

1274
    virObjectUnref(caps);
1275 1276
    return 0;

1277
 error:
1278
    VIR_FREE(tmp);
1279
    VIR_FREE(nodes);
1280
    virObjectUnref(caps);
1281 1282 1283 1284 1285 1286
    return -1;
}


static int
qemuMigrationCookieXMLParseStr(qemuMigrationCookiePtr mig,
1287
                               virQEMUDriverPtr driver,
1288
                               const char *xml,
E
Eric Blake 已提交
1289
                               unsigned int flags)
1290 1291 1292
{
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr ctxt = NULL;
1293
    int ret = -1;
1294 1295 1296

    VIR_DEBUG("xml=%s", NULLSTR(xml));

1297
    if (!(doc = virXMLParseStringCtxt(xml, _("(qemu_migration_cookie)"), &ctxt)))
1298 1299
        goto cleanup;

1300
    ret = qemuMigrationCookieXMLParse(mig, driver, doc, ctxt, flags);
1301

1302
 cleanup:
1303 1304 1305 1306 1307 1308 1309 1310 1311
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(doc);

    return ret;
}


static int
qemuMigrationBakeCookie(qemuMigrationCookiePtr mig,
1312
                        virQEMUDriverPtr driver,
1313
                        virDomainObjPtr dom,
1314 1315
                        char **cookieout,
                        int *cookieoutlen,
E
Eric Blake 已提交
1316
                        unsigned int flags)
1317
{
1318 1319
    if (!cookieout || !cookieoutlen)
        return 0;
1320 1321 1322

    *cookieoutlen = 0;

1323 1324 1325 1326
    if (flags & QEMU_MIGRATION_COOKIE_GRAPHICS &&
        qemuMigrationCookieAddGraphics(mig, driver, dom) < 0)
        return -1;

1327 1328 1329 1330
    if (flags & QEMU_MIGRATION_COOKIE_LOCKSTATE &&
        qemuMigrationCookieAddLockstate(mig, driver, dom) < 0)
        return -1;

1331 1332 1333 1334
    if (flags & QEMU_MIGRATION_COOKIE_PERSISTENT &&
        qemuMigrationCookieAddPersistent(mig, dom) < 0)
        return -1;

1335 1336 1337 1338 1339
    if (flags & QEMU_MIGRATION_COOKIE_NETWORK &&
        qemuMigrationCookieAddNetwork(mig, driver, dom) < 0) {
        return -1;
    }

1340 1341 1342 1343
    if ((flags & QEMU_MIGRATION_COOKIE_NBD) &&
        qemuMigrationCookieAddNBD(mig, driver, dom) < 0)
        return -1;

1344 1345 1346 1347
    if (flags & QEMU_MIGRATION_COOKIE_STATS &&
        qemuMigrationCookieAddStatistics(mig, dom) < 0)
        return -1;

1348
    if (!(*cookieout = qemuMigrationCookieXMLFormatStr(driver, mig)))
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
        return -1;

    *cookieoutlen = strlen(*cookieout) + 1;

    VIR_DEBUG("cookielen=%d cookie=%s", *cookieoutlen, *cookieout);

    return 0;
}


static qemuMigrationCookiePtr
1360
qemuMigrationEatCookie(virQEMUDriverPtr driver,
1361
                       virDomainObjPtr dom,
1362 1363
                       const char *cookiein,
                       int cookieinlen,
E
Eric Blake 已提交
1364
                       unsigned int flags)
1365 1366 1367 1368 1369 1370
{
    qemuMigrationCookiePtr mig = NULL;

    /* Parse & validate incoming cookie (if any) */
    if (cookiein && cookieinlen &&
        cookiein[cookieinlen-1] != '\0') {
1371 1372
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Migration cookie was not NULL terminated"));
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
        goto error;
    }

    VIR_DEBUG("cookielen=%d cookie='%s'", cookieinlen, NULLSTR(cookiein));

    if (!(mig = qemuMigrationCookieNew(dom)))
        return NULL;

    if (cookiein && cookieinlen &&
        qemuMigrationCookieXMLParseStr(mig,
1383
                                       driver,
1384 1385 1386 1387
                                       cookiein,
                                       flags) < 0)
        goto error;

1388 1389 1390
    if (mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) {
        if (!mig->lockDriver) {
            if (virLockManagerPluginUsesState(driver->lockManager)) {
1391 1392 1393
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing %s lock state for migration cookie"),
                               virLockManagerPluginGetName(driver->lockManager));
1394 1395 1396 1397
                goto error;
            }
        } else if (STRNEQ(mig->lockDriver,
                          virLockManagerPluginGetName(driver->lockManager))) {
1398 1399 1400 1401
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Source host lock driver %s different from target %s"),
                           mig->lockDriver,
                           virLockManagerPluginGetName(driver->lockManager));
1402 1403 1404 1405
            goto error;
        }
    }

1406 1407
    return mig;

1408
 error:
1409 1410 1411
    qemuMigrationCookieFree(mig);
    return NULL;
}
1412

1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
static void
qemuMigrationStoreDomainState(virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    priv->preMigrationState = virDomainObjGetState(vm, NULL);

    VIR_DEBUG("Storing pre-migration state=%d domain=%p",
              priv->preMigrationState, vm);
}

/* Returns true if the domain was resumed, false otherwise */
static bool
qemuMigrationRestoreDomainState(virConnectPtr conn, virDomainObjPtr vm)
{
    virQEMUDriverPtr driver = conn->privateData;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int state = virDomainObjGetState(vm, NULL);
    bool ret = false;

    VIR_DEBUG("driver=%p, vm=%p, pre-mig-state=%d, state=%d",
              driver, vm, priv->preMigrationState, state);

    if (state == VIR_DOMAIN_PAUSED &&
        priv->preMigrationState == VIR_DOMAIN_RUNNING) {
        /* This is basically the only restore possibility that's safe
         * and we should attempt to do */

        VIR_DEBUG("Restoring pre-migration state due to migration error");

        /* we got here through some sort of failure; start the domain again */
        if (qemuProcessStartCPUs(driver, vm, conn,
                                 VIR_DOMAIN_RUNNING_MIGRATION_CANCELED,
                                 QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) {
            /* Hm, we already know we are in error here.  We don't want to
             * overwrite the previous error, though, so we just throw something
             * to the logs and hope for the best */
            VIR_ERROR(_("Failed to resume guest %s after failure"), vm->def->name);
            goto cleanup;
        }
        ret = true;
    }

 cleanup:
    priv->preMigrationState = VIR_DOMAIN_NOSTATE;
    return ret;
}

1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
/**
 * qemuMigrationStartNBDServer:
 * @driver: qemu driver
 * @vm: domain
 *
 * Starts NBD server. This is a newer method to copy
 * storage during migration than using 'blk' and 'inc'
 * arguments in 'migrate' monitor command.
 * Error is reported here.
 *
 * Returns 0 on success, -1 otherwise.
 */
static int
qemuMigrationStartNBDServer(virQEMUDriverPtr driver,
J
Ján Tomko 已提交
1474 1475
                            virDomainObjPtr vm,
                            const char *listenAddr)
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    unsigned short port = 0;
    char *diskAlias = NULL;
    size_t i;

    for (i = 0; i < vm->def->ndisks; i++) {
        virDomainDiskDefPtr disk = vm->def->disks[i];

        /* skip shared, RO and source-less disks */
1487 1488
        if (disk->src->shared || disk->src->readonly ||
            !virDomainDiskGetSource(disk))
1489 1490 1491 1492
            continue;

        VIR_FREE(diskAlias);
        if (virAsprintf(&diskAlias, "%s%s",
1493
                        QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0)
1494 1495 1496 1497 1498 1499 1500
            goto cleanup;

        if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                           QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
            goto cleanup;

        if (!port &&
1501
            ((virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) ||
1502
             (qemuMonitorNBDServerStart(priv->mon, listenAddr, port) < 0))) {
1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516
            qemuDomainObjExitMonitor(driver, vm);
            goto cleanup;
        }

        if (qemuMonitorNBDServerAdd(priv->mon, diskAlias, true) < 0) {
            qemuDomainObjExitMonitor(driver, vm);
            goto cleanup;
        }
        qemuDomainObjExitMonitor(driver, vm);
    }

    priv->nbdPort = port;
    ret = 0;

1517
 cleanup:
1518
    VIR_FREE(diskAlias);
1519
    if (ret < 0)
1520
        virPortAllocatorRelease(driver->migrationPorts, port);
1521 1522 1523
    return ret;
}

1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
/**
 * qemuMigrationDriveMirror:
 * @driver: qemu driver
 * @vm: domain
 * @mig: migration cookie
 * @host: where are we migrating to
 * @speed: how much should the copying be limited
 * @migrate_flags: migrate monitor command flags
 *
 * Run drive-mirror to feed NBD server running on dst and wait
 * till the process switches into another phase where writes go
 * simultaneously to both source and destination. And this switch
 * is what we are waiting for before proceeding with the next
 * disk. On success, update @migrate_flags so we don't tell
 * 'migrate' command to do the very same operation.
 *
 * Returns 0 on success (@migrate_flags updated),
 *        -1 otherwise.
 */
static int
qemuMigrationDriveMirror(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         qemuMigrationCookiePtr mig,
                         const char *host,
                         unsigned long speed,
                         unsigned int *migrate_flags)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
    int mon_ret;
    int port;
    size_t i, lastGood = 0;
    char *diskAlias = NULL;
    char *nbd_dest = NULL;
1558
    char *hoststr = NULL;
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577
    unsigned int mirror_flags = VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT;
    virErrorPtr err = NULL;

    if (!(*migrate_flags & (QEMU_MONITOR_MIGRATE_NON_SHARED_DISK |
                            QEMU_MONITOR_MIGRATE_NON_SHARED_INC)))
        return 0;

    if (!mig->nbd) {
        /* Destination doesn't support NBD server.
         * Fall back to previous implementation. */
        VIR_DEBUG("Destination doesn't support NBD server "
                  "Falling back to previous implementation.");
        return 0;
    }

    /* steal NBD port and thus prevent its propagation back to destination */
    port = mig->nbd->port;
    mig->nbd->port = 0;

1578 1579
    /* escape literal IPv6 address */
    if (strchr(host, ':')) {
1580
        if (virAsprintf(&hoststr, "[%s]", host) < 0)
1581 1582 1583 1584 1585
            goto error;
    } else if (VIR_STRDUP(hoststr, host) < 0) {
        goto error;
    }

1586 1587 1588 1589 1590 1591 1592 1593
    if (*migrate_flags & QEMU_MONITOR_MIGRATE_NON_SHARED_INC)
        mirror_flags |= VIR_DOMAIN_BLOCK_REBASE_SHALLOW;

    for (i = 0; i < vm->def->ndisks; i++) {
        virDomainDiskDefPtr disk = vm->def->disks[i];
        virDomainBlockJobInfo info;

        /* skip shared, RO and source-less disks */
1594 1595
        if (disk->src->shared || disk->src->readonly ||
            !virDomainDiskGetSource(disk))
1596 1597 1598 1599 1600 1601 1602
            continue;

        VIR_FREE(diskAlias);
        VIR_FREE(nbd_dest);
        if ((virAsprintf(&diskAlias, "%s%s",
                         QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0) ||
            (virAsprintf(&nbd_dest, "nbd:%s:%d:exportname=%s",
1603
                         hoststr, port, diskAlias) < 0))
1604 1605 1606 1607 1608 1609
            goto error;

        if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                           QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            goto error;
        mon_ret = qemuMonitorDriveMirror(priv->mon, diskAlias, nbd_dest,
1610
                                         NULL, speed, 0, 0, mirror_flags);
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632
        qemuDomainObjExitMonitor(driver, vm);

        if (mon_ret < 0)
            goto error;

        lastGood = i;

        /* wait for completion */
        while (true) {
            /* Poll every 500ms for progress & to allow cancellation */
            struct timespec ts = { .tv_sec = 0, .tv_nsec = 500 * 1000 * 1000ull };

            memset(&info, 0, sizeof(info));

            if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                               QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
                goto error;
            if (priv->job.asyncAbort) {
                /* explicitly do this *after* we entered the monitor,
                 * as this is a critical section so we are guaranteed
                 * priv->job.asyncAbort will not change */
                qemuDomainObjExitMonitor(driver, vm);
1633
                priv->job.current->type = VIR_DOMAIN_JOB_CANCELLED;
1634 1635 1636 1637 1638
                virReportError(VIR_ERR_OPERATION_ABORTED, _("%s: %s"),
                               qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
                               _("canceled by client"));
                goto error;
            }
1639 1640
            mon_ret = qemuMonitorBlockJobInfo(priv->mon, diskAlias, &info,
                                              NULL);
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
            qemuDomainObjExitMonitor(driver, vm);

            if (mon_ret < 0)
                goto error;

            if (info.cur == info.end) {
                VIR_DEBUG("Drive mirroring of '%s' completed", diskAlias);
                break;
            }

            /* XXX Frankly speaking, we should listen to the events,
             * instead of doing this. But this works for now and we
             * are doing something similar in migration itself anyway */

            virObjectUnlock(vm);

            nanosleep(&ts, NULL);

            virObjectLock(vm);
        }
    }

    /* Okay, copied. Modify migrate_flags */
    *migrate_flags &= ~(QEMU_MONITOR_MIGRATE_NON_SHARED_DISK |
                        QEMU_MONITOR_MIGRATE_NON_SHARED_INC);
    ret = 0;

1668
 cleanup:
1669 1670
    VIR_FREE(diskAlias);
    VIR_FREE(nbd_dest);
1671
    VIR_FREE(hoststr);
1672 1673
    return ret;

1674
 error:
1675 1676 1677 1678 1679 1680 1681
    /* don't overwrite any errors */
    err = virSaveLastError();
    /* cancel any outstanding jobs */
    while (lastGood) {
        virDomainDiskDefPtr disk = vm->def->disks[--lastGood];

        /* skip shared, RO disks */
1682 1683
        if (disk->src->shared || disk->src->readonly ||
            !virDomainDiskGetSource(disk))
1684 1685 1686 1687
            continue;

        VIR_FREE(diskAlias);
        if (virAsprintf(&diskAlias, "%s%s",
1688
                        QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0)
1689 1690 1691
            continue;
        if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                           QEMU_ASYNC_JOB_MIGRATION_OUT) == 0) {
1692
            if (qemuMonitorBlockJob(priv->mon, diskAlias, NULL, NULL, 0,
1693
                                    BLOCK_JOB_ABORT, true) < 0) {
1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705
                VIR_WARN("Unable to cancel block-job on '%s'", diskAlias);
            }
            qemuDomainObjExitMonitor(driver, vm);
        } else {
            VIR_WARN("Unable to enter monitor. No block job cancelled");
        }
    }
    if (err)
        virSetError(err);
    virFreeError(err);
    goto cleanup;
}
1706

1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726

static void
qemuMigrationStopNBDServer(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           qemuMigrationCookiePtr mig)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

    if (!mig->nbd)
        return;

    if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                       QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
        return;

    if (qemuMonitorNBDServerStop(priv->mon) < 0)
        VIR_WARN("Unable to stop NBD server");

    qemuDomainObjExitMonitor(driver, vm);

1727
    virPortAllocatorRelease(driver->migrationPorts, priv->nbdPort);
1728 1729 1730
    priv->nbdPort = 0;
}

1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745
static void
qemuMigrationCancelDriveMirror(qemuMigrationCookiePtr mig,
                               virQEMUDriverPtr driver,
                               virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    size_t i;
    char *diskAlias = NULL;

    VIR_DEBUG("mig=%p nbdPort=%d", mig->nbd, priv->nbdPort);

    for (i = 0; i < vm->def->ndisks; i++) {
        virDomainDiskDefPtr disk = vm->def->disks[i];

        /* skip shared, RO and source-less disks */
1746 1747
        if (disk->src->shared || disk->src->readonly ||
            !virDomainDiskGetSource(disk))
1748 1749 1750 1751
            continue;

        VIR_FREE(diskAlias);
        if (virAsprintf(&diskAlias, "%s%s",
1752
                        QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0)
1753 1754 1755 1756 1757 1758
            goto cleanup;

        if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                           QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            goto cleanup;

1759
        if (qemuMonitorBlockJob(priv->mon, diskAlias, NULL, NULL, 0,
1760
                                BLOCK_JOB_ABORT, true) < 0)
1761 1762 1763 1764
            VIR_WARN("Unable to stop block job on %s", diskAlias);
        qemuDomainObjExitMonitor(driver, vm);
    }

1765
 cleanup:
1766 1767 1768 1769
    VIR_FREE(diskAlias);
    return;
}

1770 1771 1772 1773 1774 1775 1776 1777 1778
/* Validate whether the domain is safe to migrate.  If vm is NULL,
 * then this is being run in the v2 Prepare stage on the destination
 * (where we only have the target xml); if vm is provided, then this
 * is being run in either v2 Perform or v3 Begin (where we also have
 * access to all of the domain's metadata, such as whether it is
 * marked autodestroy or has snapshots).  While it would be nice to
 * assume that checking on source is sufficient to prevent ever
 * talking to the destination in the first place, we are stuck with
 * the fact that older servers did not do checks on the source. */
1779
bool
1780
qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm,
1781
                       virDomainDefPtr def, bool remote, bool abort_on_error)
1782
{
1783
    int nsnapshots;
1784
    int pauseReason;
1785
    bool forbid;
1786
    size_t i;
1787 1788 1789

    if (vm) {
        if (qemuProcessAutoDestroyActive(driver, vm)) {
1790 1791
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is marked for auto destroy"));
1792 1793
            return false;
        }
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806

        /* perform these checks only when migrating to remote hosts */
        if (remote) {
            nsnapshots = virDomainSnapshotObjListNum(vm->snapshots, NULL, 0);
            if (nsnapshots < 0)
                return false;

            if (nsnapshots > 0) {
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("cannot migrate domain with %d snapshots"),
                               nsnapshots);
                return false;
            }
1807 1808

            /* cancel migration if disk I/O error is emitted while migrating */
1809 1810
            if (abort_on_error &&
                virDomainObjGetState(vm, &pauseReason) == VIR_DOMAIN_PAUSED &&
1811 1812 1813 1814 1815 1816
                pauseReason == VIR_DOMAIN_PAUSED_IOERROR) {
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("cannot migrate domain with I/O error"));
                return false;
            }

1817
        }
1818

E
Eric Blake 已提交
1819 1820
        if (virDomainHasDiskMirror(vm)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1821
                           _("domain has an active block job"));
E
Eric Blake 已提交
1822 1823
            return false;
        }
1824 1825 1826

        def = vm->def;
    }
1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841

    /* Migration with USB host devices is allowed, all other devices are
     * forbidden.
     */
    forbid = false;
    for (i = 0; i < def->nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
            forbid = true;
            break;
        }
    }
    if (forbid) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1842
                       _("domain has assigned non-USB host devices"));
1843 1844 1845
        return false;
    }

1846 1847 1848
    if (def->cpu && def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH) {
        for (i = 0; i < def->cpu->nfeatures; i++) {
            virCPUFeatureDefPtr feature = &def->cpu->features[i];
J
Ján Tomko 已提交
1849

1850 1851
            if (feature->policy != VIR_CPU_FEATURE_REQUIRE)
                continue;
J
Ján Tomko 已提交
1852

1853 1854 1855 1856 1857 1858 1859
            /* QEMU blocks migration and save with invariant TSC enabled */
            if (STREQ(feature->name, "invtsc")) {
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("domain has CPU feature: %s"),
                               feature->name);
                return false;
            }
J
Ján Tomko 已提交
1860 1861 1862
        }
    }

1863 1864 1865
    return true;
}

1866 1867 1868
static bool
qemuMigrationIsSafe(virDomainDefPtr def)
{
1869
    size_t i;
1870

1871
    for (i = 0; i < def->ndisks; i++) {
1872
        virDomainDiskDefPtr disk = def->disks[i];
1873
        const char *src = virDomainDiskGetSource(disk);
1874

1875 1876
        /* Our code elsewhere guarantees shared disks are either readonly (in
         * which case cache mode doesn't matter) or used with cache=none */
1877
        if (src &&
1878 1879
            !disk->src->shared &&
            !disk->src->readonly &&
1880
            disk->cachemode != VIR_DOMAIN_DISK_CACHE_DISABLE) {
1881
            int rc;
1882

E
Eric Blake 已提交
1883
            if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_FILE) {
1884
                if ((rc = virFileIsSharedFS(src)) < 0)
1885 1886
                    return false;
                else if (rc == 0)
1887
                    continue;
1888
                if ((rc = virStorageFileIsClusterFS(src)) < 0)
1889
                    return false;
1890 1891
                else if (rc == 1)
                    continue;
1892 1893
            } else if (disk->src->type == VIR_STORAGE_TYPE_NETWORK &&
                       disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD) {
1894
                continue;
1895
            }
1896

1897 1898 1899
            virReportError(VIR_ERR_MIGRATE_UNSAFE, "%s",
                           _("Migration may lead to data corruption if disks"
                             " use cache != none"));
1900 1901 1902 1903 1904 1905 1906
            return false;
        }
    }

    return true;
}

1907 1908 1909 1910
/** qemuMigrationSetOffline
 * Pause domain for non-live migration.
 */
int
1911
qemuMigrationSetOffline(virQEMUDriverPtr driver,
1912 1913 1914
                        virDomainObjPtr vm)
{
    int ret;
1915
    VIR_DEBUG("driver=%p vm=%p", driver, vm);
1916 1917
    ret = qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_MIGRATION,
                              QEMU_ASYNC_JOB_MIGRATION_OUT);
1918
    if (ret == 0) {
1919
        virObjectEventPtr event;
1920

1921
        event = virDomainEventLifecycleNewFromObj(vm,
1922 1923 1924 1925 1926 1927 1928 1929 1930 1931
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }

    return ret;
}


1932 1933 1934
static int
qemuMigrationSetCompression(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
1935
                            bool state,
1936
                            qemuDomainAsyncJob job)
1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret;

    if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0)
        return -1;

    ret = qemuMonitorGetMigrationCapability(
                priv->mon,
                QEMU_MONITOR_MIGRATION_CAPS_XBZRLE);

    if (ret < 0) {
        goto cleanup;
1950 1951 1952
    } else if (ret == 0 && !state) {
        /* Unsupported but we want it off anyway */
        goto cleanup;
1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968
    } else if (ret == 0) {
        if (job == QEMU_ASYNC_JOB_MIGRATION_IN) {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("Compressed migration is not supported by "
                             "target QEMU binary"));
        } else {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("Compressed migration is not supported by "
                             "source QEMU binary"));
        }
        ret = -1;
        goto cleanup;
    }

    ret = qemuMonitorSetMigrationCapability(
                priv->mon,
1969 1970
                QEMU_MONITOR_MIGRATION_CAPS_XBZRLE,
                state);
1971

1972
 cleanup:
1973 1974 1975 1976
    qemuDomainObjExitMonitor(driver, vm);
    return ret;
}

1977 1978 1979
static int
qemuMigrationSetAutoConverge(virQEMUDriverPtr driver,
                             virDomainObjPtr vm,
1980
                             bool state,
1981
                             qemuDomainAsyncJob job)
1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret;

    if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0)
        return -1;

    ret = qemuMonitorGetMigrationCapability(
                priv->mon,
                QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE);

    if (ret < 0) {
        goto cleanup;
1995 1996 1997
    } else if (ret == 0 && !state) {
        /* Unsupported but we want it off anyway */
        goto cleanup;
1998 1999 2000 2001 2002 2003 2004 2005 2006 2007
    } else if (ret == 0) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Auto-Converge is not supported by "
                         "QEMU binary"));
        ret = -1;
        goto cleanup;
    }

    ret = qemuMonitorSetMigrationCapability(
                priv->mon,
2008 2009
                QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE,
                state);
2010

2011
 cleanup:
2012 2013 2014 2015 2016
    qemuDomainObjExitMonitor(driver, vm);
    return ret;
}


2017 2018 2019
static int
qemuMigrationSetPinAll(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
2020
                       bool state,
2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034
                       qemuDomainAsyncJob job)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret;

    if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0)
        return -1;

    ret = qemuMonitorGetMigrationCapability(
                priv->mon,
                QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL);

    if (ret < 0) {
        goto cleanup;
2035 2036 2037
    } else if (ret == 0 && !state) {
        /* Unsupported but we want it off anyway */
        goto cleanup;
2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053
    } else if (ret == 0) {
        if (job == QEMU_ASYNC_JOB_MIGRATION_IN) {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("rdma pinning migration is not supported by "
                             "target QEMU binary"));
        } else {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("rdma pinning migration is not supported by "
                             "source QEMU binary"));
        }
        ret = -1;
        goto cleanup;
    }

    ret = qemuMonitorSetMigrationCapability(
                priv->mon,
2054 2055
                QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL,
                state);
2056 2057 2058 2059 2060 2061

 cleanup:
    qemuDomainObjExitMonitor(driver, vm);
    return ret;
}

2062 2063 2064 2065 2066 2067 2068
static int
qemuMigrationWaitForSpice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    bool wait_for_spice = false;
    bool spice_migrated = false;
2069
    size_t i = 0;
2070

2071 2072 2073 2074 2075 2076 2077 2078
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_SEAMLESS_MIGRATION)) {
        for (i = 0; i < vm->def->ngraphics; i++) {
            if (vm->def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
                wait_for_spice = true;
                break;
            }
        }
    }
2079 2080 2081 2082 2083 2084 2085 2086

    if (!wait_for_spice)
        return 0;

    while (!spice_migrated) {
        /* Poll every 50ms for progress & to allow cancellation */
        struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };

2087 2088 2089 2090
        if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                           QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            return -1;

2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103
        if (qemuMonitorGetSpiceMigrationStatus(priv->mon,
                                               &spice_migrated) < 0) {
            qemuDomainObjExitMonitor(driver, vm);
            return -1;
        }
        qemuDomainObjExitMonitor(driver, vm);
        virObjectUnlock(vm);
        nanosleep(&ts, NULL);
        virObjectLock(vm);
    }

    return 0;
}
2104

2105
static int
2106
qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
2107
                             virDomainObjPtr vm,
2108
                             const char *job,
2109
                             qemuDomainAsyncJob asyncJob)
2110
{
2111
    qemuDomainObjPrivatePtr priv = vm->privateData;
2112
    qemuMonitorMigrationStatus status;
J
Jiri Denemark 已提交
2113 2114
    qemuDomainJobInfoPtr jobInfo;
    int ret;
2115 2116

    memset(&status, 0, sizeof(status));
2117

2118 2119
    ret = qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob);
    if (ret < 0) {
2120 2121 2122
        /* Guest already exited or waiting for the job timed out; nothing
         * further to update. */
        return ret;
2123
    }
2124
    ret = qemuMonitorGetMigrationStatus(priv->mon, &status);
2125

2126
    qemuDomainObjExitMonitor(driver, vm);
2127

J
Jiri Denemark 已提交
2128 2129
    if (ret < 0 ||
        qemuDomainJobInfoUpdateTime(priv->job.current) < 0)
2130
        return -1;
2131

2132
    ret = -1;
J
Jiri Denemark 已提交
2133 2134 2135 2136 2137
    jobInfo = priv->job.current;
    switch (status.status) {
    case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED:
        jobInfo->type = VIR_DOMAIN_JOB_COMPLETED;
        /* fall through */
M
Michael Avdienko 已提交
2138
    case QEMU_MONITOR_MIGRATION_STATUS_SETUP:
2139 2140 2141 2142
    case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE:
        ret = 0;
        break;

J
Jiri Denemark 已提交
2143 2144 2145 2146
    case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
        jobInfo->type = VIR_DOMAIN_JOB_NONE;
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("%s: %s"), job, _("is not active"));
2147 2148 2149
        break;

    case QEMU_MONITOR_MIGRATION_STATUS_ERROR:
J
Jiri Denemark 已提交
2150
        jobInfo->type = VIR_DOMAIN_JOB_FAILED;
2151 2152
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("%s: %s"), job, _("unexpectedly failed"));
2153 2154 2155
        break;

    case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED:
J
Jiri Denemark 已提交
2156
        jobInfo->type = VIR_DOMAIN_JOB_CANCELLED;
2157 2158
        virReportError(VIR_ERR_OPERATION_ABORTED,
                       _("%s: %s"), job, _("canceled by client"));
2159 2160
        break;
    }
J
Jiri Denemark 已提交
2161
    jobInfo->status = status;
2162 2163 2164 2165 2166

    return ret;
}


2167 2168 2169
/* Returns 0 on success, -2 when migration needs to be cancelled, or -1 when
 * QEMU reports failed migration.
 */
2170
static int
J
Jiri Denemark 已提交
2171 2172
qemuMigrationWaitForCompletion(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
2173
                               qemuDomainAsyncJob asyncJob,
J
Jiri Denemark 已提交
2174 2175
                               virConnectPtr dconn,
                               bool abort_on_error)
2176
{
2177
    qemuDomainObjPrivatePtr priv = vm->privateData;
J
Jiri Denemark 已提交
2178
    qemuDomainJobInfoPtr jobInfo = priv->job.current;
2179
    const char *job;
2180
    int pauseReason;
2181

2182 2183
    switch (priv->job.asyncJob) {
    case QEMU_ASYNC_JOB_MIGRATION_OUT:
2184 2185
        job = _("migration job");
        break;
2186
    case QEMU_ASYNC_JOB_SAVE:
2187 2188
        job = _("domain save job");
        break;
2189
    case QEMU_ASYNC_JOB_DUMP:
2190 2191 2192 2193 2194
        job = _("domain core dump job");
        break;
    default:
        job = _("job");
    }
2195

J
Jiri Denemark 已提交
2196
    jobInfo->type = VIR_DOMAIN_JOB_UNBOUNDED;
2197

J
Jiri Denemark 已提交
2198
    while (jobInfo->type == VIR_DOMAIN_JOB_UNBOUNDED) {
2199 2200 2201
        /* Poll every 50ms for progress & to allow cancellation */
        struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };

2202
        if (qemuMigrationUpdateJobStatus(driver, vm, job, asyncJob) == -1)
2203
            break;
2204

2205
        /* cancel migration if disk I/O error is emitted while migrating */
2206
        if (abort_on_error &&
2207
            virDomainObjGetState(vm, &pauseReason) == VIR_DOMAIN_PAUSED &&
2208 2209 2210 2211 2212
            pauseReason == VIR_DOMAIN_PAUSED_IOERROR) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("%s: %s"), job, _("failed due to I/O error"));
            break;
        }
2213

2214
        if (dconn && virConnectIsAlive(dconn) <= 0) {
2215 2216
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Lost connection to destination host"));
2217
            break;
2218 2219
        }

2220
        virObjectUnlock(vm);
2221 2222 2223

        nanosleep(&ts, NULL);

2224
        virObjectLock(vm);
2225 2226
    }

J
Jiri Denemark 已提交
2227
    if (jobInfo->type == VIR_DOMAIN_JOB_COMPLETED) {
2228
        qemuDomainJobInfoUpdateDowntime(jobInfo);
2229 2230 2231
        VIR_FREE(priv->job.completed);
        if (VIR_ALLOC(priv->job.completed) == 0)
            *priv->job.completed = *jobInfo;
2232
        return 0;
J
Jiri Denemark 已提交
2233
    } else if (jobInfo->type == VIR_DOMAIN_JOB_UNBOUNDED) {
2234 2235 2236
        /* The migration was aborted by us rather than QEMU itself so let's
         * update the job type and notify the caller to send migrate_cancel.
         */
J
Jiri Denemark 已提交
2237
        jobInfo->type = VIR_DOMAIN_JOB_FAILED;
2238 2239
        return -2;
    } else {
2240
        return -1;
2241
    }
2242 2243 2244
}


2245
static int
2246
qemuDomainMigrateGraphicsRelocate(virQEMUDriverPtr driver,
2247
                                  virDomainObjPtr vm,
2248 2249
                                  qemuMigrationCookiePtr cookie,
                                  const char *graphicsuri)
2250 2251
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
2252 2253
    int ret = -1;
    const char *listenAddress = NULL;
2254
    virSocketAddr addr;
2255 2256 2257 2258 2259
    virURIPtr uri = NULL;
    int type = -1;
    int port = -1;
    int tlsPort = -1;
    const char *tlsSubject = NULL;
2260

2261
    if (!cookie || (!cookie->graphics && !graphicsuri))
2262 2263
        return 0;

2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282
    if (graphicsuri && !(uri = virURIParse(graphicsuri)))
        goto cleanup;

    if (cookie->graphics) {
        type = cookie->graphics->type;

        listenAddress = cookie->graphics->listen;

        if (!listenAddress ||
            (virSocketAddrParse(&addr, listenAddress, AF_UNSPEC) > 0 &&
             virSocketAddrIsWildcard(&addr)))
            listenAddress = cookie->remoteHostname;

        port = cookie->graphics->port;
        tlsPort = cookie->graphics->tlsPort;
        tlsSubject = cookie->graphics->tlsSubject;
    }

    if (uri) {
2283
        size_t i;
2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310

        if ((type = virDomainGraphicsTypeFromString(uri->scheme)) < 0) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("unknown graphics type %s"), uri->scheme);
            goto cleanup;
        }

        if (uri->server)
            listenAddress = uri->server;
        if (uri->port > 0)
            port = uri->port;

        for (i = 0; i < uri->paramsCount; i++) {
            virURIParamPtr param = uri->params + i;

            if (STRCASEEQ(param->name, "tlsPort")) {
                if (virStrToLong_i(param->value, NULL, 10, &tlsPort) < 0) {
                    virReportError(VIR_ERR_INVALID_ARG,
                                   _("invalid tlsPort number: %s"),
                                   param->value);
                    goto cleanup;
                }
            } else if (STRCASEEQ(param->name, "tlsSubject")) {
                tlsSubject = param->value;
            }
        }
    }
2311 2312 2313 2314

    /* QEMU doesn't support VNC relocation yet, so
     * skip it to avoid generating an error
     */
2315 2316 2317 2318
    if (type != VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
        ret = 0;
        goto cleanup;
    }
2319

2320 2321 2322 2323
    if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                       QEMU_ASYNC_JOB_MIGRATION_OUT) == 0) {
        ret = qemuMonitorGraphicsRelocate(priv->mon, type, listenAddress,
                                          port, tlsPort, tlsSubject);
2324
        qemuDomainObjExitMonitor(driver, vm);
2325
    }
2326

2327
 cleanup:
2328
    virURIFree(uri);
2329 2330 2331 2332
    return ret;
}


2333
static int
2334
qemuDomainMigrateOPDRelocate(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
2335 2336 2337
                             virDomainObjPtr vm,
                             qemuMigrationCookiePtr cookie)
{
2338 2339
    virDomainNetDefPtr netptr;
    int ret = -1;
2340
    size_t i;
2341 2342 2343 2344 2345 2346 2347 2348

    for (i = 0; i < cookie->network->nnets; i++) {
        netptr = vm->def->nets[i];

        switch (cookie->network->net[i].vporttype) {
        case VIR_NETDEV_VPORT_PROFILE_NONE:
        case VIR_NETDEV_VPORT_PROFILE_8021QBG:
        case VIR_NETDEV_VPORT_PROFILE_8021QBH:
2349
           break;
2350
        case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
2351 2352
            if (virNetDevOpenvswitchSetMigrateData(cookie->network->net[i].portdata,
                                                   netptr->ifname) != 0) {
J
Jiri Denemark 已提交
2353 2354 2355
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to run command to set OVS port data for "
                                 "interface %s"), netptr->ifname);
2356 2357 2358
                goto cleanup;
            }
            break;
2359 2360 2361 2362 2363
        default:
            break;
        }
    }

2364
    ret = 0;
2365
 cleanup:
2366 2367 2368 2369
    return ret;
}


2370 2371 2372 2373 2374 2375
/* This is called for outgoing non-p2p migrations when a connection to the
 * client which initiated the migration was closed but we were waiting for it
 * to follow up with the next phase, that is, in between
 * qemuDomainMigrateBegin3 and qemuDomainMigratePerform3 or
 * qemuDomainMigratePerform3 and qemuDomainMigrateConfirm3.
 */
2376 2377 2378 2379
static virDomainObjPtr
qemuMigrationCleanup(virDomainObjPtr vm,
                     virConnectPtr conn,
                     void *opaque)
2380
{
2381
    virQEMUDriverPtr driver = opaque;
2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396
    qemuDomainObjPrivatePtr priv = vm->privateData;

    VIR_DEBUG("vm=%s, conn=%p, asyncJob=%s, phase=%s",
              vm->def->name, conn,
              qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
              qemuDomainAsyncJobPhaseToString(priv->job.asyncJob,
                                              priv->job.phase));

    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT))
        goto cleanup;

    VIR_DEBUG("The connection which started outgoing migration of domain %s"
              " was closed; canceling the migration",
              vm->def->name);

2397
    switch ((qemuMigrationJobPhase) priv->job.phase) {
2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427
    case QEMU_MIGRATION_PHASE_BEGIN3:
        /* just forget we were about to migrate */
        qemuDomainObjDiscardAsyncJob(driver, vm);
        break;

    case QEMU_MIGRATION_PHASE_PERFORM3_DONE:
        VIR_WARN("Migration of domain %s finished but we don't know if the"
                 " domain was successfully started on destination or not",
                 vm->def->name);
        /* clear the job and let higher levels decide what to do */
        qemuDomainObjDiscardAsyncJob(driver, vm);
        break;

    case QEMU_MIGRATION_PHASE_PERFORM3:
        /* cannot be seen without an active migration API; unreachable */
    case QEMU_MIGRATION_PHASE_CONFIRM3:
    case QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED:
        /* all done; unreachable */
    case QEMU_MIGRATION_PHASE_PREPARE:
    case QEMU_MIGRATION_PHASE_FINISH2:
    case QEMU_MIGRATION_PHASE_FINISH3:
        /* incoming migration; unreachable */
    case QEMU_MIGRATION_PHASE_PERFORM2:
        /* single phase outgoing migration; unreachable */
    case QEMU_MIGRATION_PHASE_NONE:
    case QEMU_MIGRATION_PHASE_LAST:
        /* unreachable */
        ;
    }

2428
 cleanup:
2429 2430 2431
    return vm;
}

2432

2433
/* The caller is supposed to lock the vm and start a migration job. */
2434 2435
static char
*qemuMigrationBeginPhase(virQEMUDriverPtr driver,
2436
                         virDomainObjPtr vm,
2437
                         const char *xmlin,
2438
                         const char *dname,
2439
                         char **cookieout,
2440 2441
                         int *cookieoutlen,
                         unsigned long flags)
2442 2443 2444
{
    char *rv = NULL;
    qemuMigrationCookiePtr mig = NULL;
2445
    virDomainDefPtr def = NULL;
2446
    qemuDomainObjPrivatePtr priv = vm->privateData;
2447
    virCapsPtr caps = NULL;
2448
    unsigned int cookieFlags = QEMU_MIGRATION_COOKIE_LOCKSTATE;
2449
    bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
2450

2451
    VIR_DEBUG("driver=%p, vm=%p, xmlin=%s, dname=%s,"
2452
              " cookieout=%p, cookieoutlen=%p, flags=%lx",
2453
              driver, vm, NULLSTR(xmlin), NULLSTR(dname),
2454
              cookieout, cookieoutlen, flags);
2455

2456 2457 2458
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

2459 2460 2461 2462 2463 2464
    /* Only set the phase if we are inside QEMU_ASYNC_JOB_MIGRATION_OUT.
     * Otherwise we will start the async job later in the perform phase losing
     * change protection.
     */
    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT)
        qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_BEGIN3);
2465

2466
    if (!qemuMigrationIsAllowed(driver, vm, NULL, true, abort_on_error))
2467 2468
        goto cleanup;

2469 2470 2471
    if (!(flags & VIR_MIGRATE_UNSAFE) && !qemuMigrationIsSafe(vm->def))
        goto cleanup;

2472
    if (flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC) &&
2473
        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_MIRROR)) {
2474
        /* TODO support NBD for TUNNELLED migration */
2475
        if (flags & VIR_MIGRATE_TUNNELLED) {
2476 2477 2478 2479
            VIR_WARN("NBD in tunnelled migration is currently not supported");
        } else {
            cookieFlags |= QEMU_MIGRATION_COOKIE_NBD;
            priv->nbdPort = 0;
2480 2481 2482
        }
    }

2483
    if (!(mig = qemuMigrationEatCookie(driver, vm, NULL, 0, 0)))
2484 2485 2486 2487
        goto cleanup;

    if (qemuMigrationBakeCookie(mig, driver, vm,
                                cookieout, cookieoutlen,
2488
                                cookieFlags) < 0)
2489 2490
        goto cleanup;

L
liguang 已提交
2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512
    if (flags & VIR_MIGRATE_OFFLINE) {
        if (flags & (VIR_MIGRATE_NON_SHARED_DISK |
                     VIR_MIGRATE_NON_SHARED_INC)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("offline migration cannot handle "
                             "non-shared storage"));
            goto cleanup;
        }
        if (!(flags & VIR_MIGRATE_PERSIST_DEST)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("offline migration must be specified with "
                             "the persistent flag set"));
            goto cleanup;
        }
        if (flags & VIR_MIGRATE_TUNNELLED) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("tunnelled offline migration does not "
                             "make sense"));
            goto cleanup;
        }
    }

2513
    if (xmlin) {
2514
        if (!(def = virDomainDefParseString(xmlin, caps, driver->xmlopt,
M
Matthias Bolte 已提交
2515
                                            QEMU_EXPECTED_VIRT_TYPES,
2516 2517 2518
                                            VIR_DOMAIN_XML_INACTIVE)))
            goto cleanup;

2519
        if (!qemuDomainDefCheckABIStability(driver, vm->def, def))
2520 2521
            goto cleanup;

2522
        rv = qemuDomainDefFormatLive(driver, def, false, true);
2523
    } else {
2524
        rv = qemuDomainDefFormatLive(driver, vm->def, false, true);
2525
    }
2526

2527
 cleanup:
2528
    qemuMigrationCookieFree(mig);
2529
    virObjectUnref(caps);
2530
    virDomainDefFree(def);
2531 2532 2533
    return rv;
}

2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544
char *
qemuMigrationBegin(virConnectPtr conn,
                   virDomainObjPtr vm,
                   const char *xmlin,
                   const char *dname,
                   char **cookieout,
                   int *cookieoutlen,
                   unsigned long flags)
{
    virQEMUDriverPtr driver = conn->privateData;
    char *xml = NULL;
2545
    qemuDomainAsyncJob asyncJob;
2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556

    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            goto cleanup;
        asyncJob = QEMU_ASYNC_JOB_MIGRATION_OUT;
    } else {
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
            goto cleanup;
        asyncJob = QEMU_ASYNC_JOB_NONE;
    }

2557 2558
    qemuMigrationStoreDomainState(vm);

2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581
    if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto endjob;
    }

    /* Check if there is any ejected media.
     * We don't want to require them on the destination.
     */
    if (!(flags & VIR_MIGRATE_OFFLINE) &&
        qemuDomainCheckEjectableMedia(driver, vm, asyncJob) < 0)
        goto endjob;

    if (!(xml = qemuMigrationBeginPhase(driver, vm, xmlin, dname,
                                        cookieout, cookieoutlen,
                                        flags)))
        goto endjob;

    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        /* We keep the job active across API calls until the confirm() call.
         * This prevents any other APIs being invoked while migration is taking
         * place.
         */
2582 2583
        if (virCloseCallbacksSet(driver->closeCallbacks, vm, conn,
                                 qemuMigrationCleanup) < 0)
2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596
            goto endjob;
        if (qemuMigrationJobContinue(vm) == 0) {
            vm = NULL;
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("domain disappeared"));
            VIR_FREE(xml);
            if (cookieout)
                VIR_FREE(*cookieout);
        }
    } else {
        goto endjob;
    }

2597
 cleanup:
2598 2599 2600 2601
    if (vm)
        virObjectUnlock(vm);
    return xml;

2602
 endjob:
2603 2604 2605 2606
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobFinish(driver, vm) == 0)
            vm = NULL;
    } else {
E
Eric Blake 已提交
2607
        if (!qemuDomainObjEndJob(driver, vm))
2608 2609 2610 2611 2612
            vm = NULL;
    }
    goto cleanup;
}

2613

2614 2615
/* Prepare is the first step, and it runs on the destination host.
 */
2616

2617
static void
2618
qemuMigrationPrepareCleanup(virQEMUDriverPtr driver,
2619 2620 2621 2622 2623 2624 2625 2626 2627 2628
                            virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

    VIR_DEBUG("driver=%p, vm=%s, job=%s, asyncJob=%s",
              driver,
              vm->def->name,
              qemuDomainJobTypeToString(priv->job.active),
              qemuDomainAsyncJobTypeToString(priv->job.asyncJob));

2629 2630 2631
    virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort);
    priv->migrationPort = 0;

2632 2633 2634 2635 2636
    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN))
        return;
    qemuDomainObjDiscardAsyncJob(driver, vm);
}

2637
static int
2638
qemuMigrationPrepareAny(virQEMUDriverPtr driver,
2639 2640 2641 2642 2643
                        virConnectPtr dconn,
                        const char *cookiein,
                        int cookieinlen,
                        char **cookieout,
                        int *cookieoutlen,
2644
                        virDomainDefPtr *def,
2645
                        const char *origname,
L
liguang 已提交
2646
                        virStreamPtr st,
2647
                        const char *protocol,
2648 2649
                        unsigned short port,
                        bool autoPort,
2650
                        const char *listenAddress,
L
liguang 已提交
2651
                        unsigned long flags)
2652 2653
{
    virDomainObjPtr vm = NULL;
2654
    virObjectEventPtr event = NULL;
2655
    int ret = -1;
2656
    int dataFD[2] = { -1, -1 };
2657
    qemuDomainObjPrivatePtr priv = NULL;
J
Jiri Denemark 已提交
2658
    unsigned long long now;
2659
    qemuMigrationCookiePtr mig = NULL;
2660
    bool tunnel = !!st;
J
Jiri Denemark 已提交
2661
    char *xmlout = NULL;
L
liguang 已提交
2662
    unsigned int cookieFlags;
2663
    virCapsPtr caps = NULL;
J
Ján Tomko 已提交
2664
    char *migrateFrom = NULL;
2665
    bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
2666
    bool taint_hook = false;
2667

2668
    if (virTimeMillisNow(&now) < 0)
2669 2670
        return -1;

2671 2672
    virNWFilterReadLockFilterUpdates();

L
liguang 已提交
2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694
    if (flags & VIR_MIGRATE_OFFLINE) {
        if (flags & (VIR_MIGRATE_NON_SHARED_DISK |
                     VIR_MIGRATE_NON_SHARED_INC)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("offline migration cannot handle "
                             "non-shared storage"));
            goto cleanup;
        }
        if (!(flags & VIR_MIGRATE_PERSIST_DEST)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("offline migration must be specified with "
                             "the persistent flag set"));
            goto cleanup;
        }
        if (tunnel) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("tunnelled offline migration does not "
                             "make sense"));
            goto cleanup;
        }
    }

2695 2696 2697
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

2698
    if (!qemuMigrationIsAllowed(driver, NULL, *def, true, abort_on_error))
2699 2700
        goto cleanup;

J
Jiri Denemark 已提交
2701 2702 2703 2704 2705
    /* Let migration hook filter domain XML */
    if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
        char *xml;
        int hookret;

2706
        if (!(xml = qemuDomainDefFormatXML(driver, *def,
2707 2708
                                           VIR_DOMAIN_XML_SECURE |
                                           VIR_DOMAIN_XML_MIGRATABLE)))
J
Jiri Denemark 已提交
2709 2710
            goto cleanup;

2711
        hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, (*def)->name,
J
Jiri Denemark 已提交
2712 2713 2714 2715 2716 2717 2718
                              VIR_HOOK_QEMU_OP_MIGRATE, VIR_HOOK_SUBOP_BEGIN,
                              NULL, xml, &xmlout);
        VIR_FREE(xml);

        if (hookret < 0) {
            goto cleanup;
        } else if (hookret == 0) {
2719
            if (virStringIsEmpty(xmlout)) {
J
Jiri Denemark 已提交
2720 2721 2722 2723 2724 2725
                VIR_DEBUG("Migrate hook filter returned nothing; using the"
                          " original XML");
            } else {
                virDomainDefPtr newdef;

                VIR_DEBUG("Using hook-filtered domain XML: %s", xmlout);
2726
                newdef = virDomainDefParseString(xmlout, caps, driver->xmlopt,
J
Jiri Denemark 已提交
2727 2728 2729 2730 2731
                                                 QEMU_EXPECTED_VIRT_TYPES,
                                                 VIR_DOMAIN_XML_INACTIVE);
                if (!newdef)
                    goto cleanup;

2732
                if (!qemuDomainDefCheckABIStability(driver, *def, newdef)) {
J
Jiri Denemark 已提交
2733 2734 2735 2736
                    virDomainDefFree(newdef);
                    goto cleanup;
                }

2737 2738
                virDomainDefFree(*def);
                *def = newdef;
2739 2740 2741 2742
                /* We should taint the domain here. However, @vm and therefore
                 * privateData too are still NULL, so just notice the fact and
                 * taint it later. */
                taint_hook = true;
J
Jiri Denemark 已提交
2743 2744 2745 2746
            }
        }
    }

J
Ján Tomko 已提交
2747 2748 2749 2750
    if (tunnel) {
        /* QEMU will be started with -incoming stdio
         * (which qemu_command might convert to exec:cat or fd:n)
         */
2751
        if (VIR_STRDUP(migrateFrom, "stdio") < 0)
J
Ján Tomko 已提交
2752 2753
            goto cleanup;
    } else {
2754 2755 2756
        bool encloseAddress = false;
        bool hostIPv6Capable = false;
        bool qemuIPv6Capable = false;
J
Ján Tomko 已提交
2757 2758 2759 2760
        virQEMUCapsPtr qemuCaps = NULL;
        struct addrinfo *info = NULL;
        struct addrinfo hints = { .ai_flags = AI_ADDRCONFIG,
                                  .ai_socktype = SOCK_STREAM };
2761
        const char *incFormat;
J
Ján Tomko 已提交
2762

2763 2764 2765 2766
        if (getaddrinfo("::", NULL, &hints, &info) == 0) {
            freeaddrinfo(info);
            hostIPv6Capable = true;
        }
J
Ján Tomko 已提交
2767
        if (!(qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache,
2768
                                                    (*def)->emulator)))
J
Ján Tomko 已提交
2769 2770
            goto cleanup;

2771 2772 2773 2774
        qemuIPv6Capable = virQEMUCapsGet(qemuCaps, QEMU_CAPS_IPV6_MIGRATION);
        virObjectUnref(qemuCaps);

        if (listenAddress) {
2775 2776 2777 2778 2779 2780 2781 2782 2783
            if (virSocketAddrNumericFamily(listenAddress) == AF_INET6) {
                if (!qemuIPv6Capable) {
                    virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                                   _("qemu isn't capable of IPv6"));
                    goto cleanup;
                }
                if (!hostIPv6Capable) {
                    virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                                   _("host isn't capable of IPv6"));
2784 2785
                    goto cleanup;
                }
2786 2787
                /* IPv6 address must be escaped in brackets on the cmd line */
                encloseAddress = true;
2788
            } else {
2789
                /* listenAddress is a hostname or IPv4 */
2790
            }
2791
        } else if (qemuIPv6Capable && hostIPv6Capable) {
2792 2793 2794
            /* Listen on :: instead of 0.0.0.0 if QEMU understands it
             * and there is at least one IPv6 address configured
             */
2795 2796 2797 2798
            listenAddress = "::";
            encloseAddress = true;
        } else {
            listenAddress = "0.0.0.0";
J
Ján Tomko 已提交
2799 2800
        }

2801 2802 2803 2804
        /* QEMU will be started with
         *   -incoming protocol:[<IPv6 addr>]:port,
         *   -incoming protocol:<IPv4 addr>:port, or
         *   -incoming protocol:<hostname>:port
J
Ján Tomko 已提交
2805
         */
2806 2807 2808 2809 2810 2811
        if (encloseAddress)
            incFormat = "%s:[%s]:%d";
        else
            incFormat = "%s:%s:%d";
        if (virAsprintf(&migrateFrom, incFormat,
                        protocol, listenAddress, port) < 0)
J
Ján Tomko 已提交
2812 2813 2814
            goto cleanup;
    }

2815
    if (!(vm = virDomainObjListAdd(driver->domains, *def,
2816
                                   driver->xmlopt,
2817 2818 2819
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
2820
        goto cleanup;
2821

2822
    *def = NULL;
2823
    priv = vm->privateData;
2824 2825
    if (VIR_STRDUP(priv->origname, origname) < 0)
        goto cleanup;
2826

2827 2828 2829 2830 2831
    if (taint_hook) {
        /* Domain XML has been altered by a hook script. */
        priv->hookRun = true;
    }

2832
    if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen,
2833 2834
                                       QEMU_MIGRATION_COOKIE_LOCKSTATE |
                                       QEMU_MIGRATION_COOKIE_NBD)))
2835 2836
        goto cleanup;

2837
    if (STREQ_NULLABLE(protocol, "rdma") && !vm->def->mem.hard_limit) {
M
Michael R. Hines 已提交
2838 2839 2840 2841 2842 2843
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot start RDMA migration with no memory hard "
                         "limit set"));
        goto cleanup;
    }

2844
    if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
2845
        goto cleanup;
2846
    qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PREPARE);
2847 2848 2849 2850

    /* Domain starts inactive, even if the domain XML had an id field. */
    vm->def->id = -1;

L
liguang 已提交
2851 2852 2853
    if (flags & VIR_MIGRATE_OFFLINE)
        goto done;

2854 2855
    if (tunnel &&
        (pipe(dataFD) < 0 || virSetCloseExec(dataFD[1]) < 0)) {
2856 2857
        virReportSystemError(errno, "%s",
                             _("cannot create pipe for tunnelled migration"));
2858 2859 2860 2861
        goto endjob;
    }

    /* Start the QEMU daemon, with the same command-line arguments plus
2862
     * -incoming $migrateFrom
2863
     */
2864 2865
    if (qemuProcessStart(dconn, driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN,
                         migrateFrom, dataFD[0], NULL, NULL,
2866 2867
                         VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START,
                         VIR_QEMU_PROCESS_START_PAUSED |
2868
                         VIR_QEMU_PROCESS_START_AUTODESTROY) < 0) {
2869
        virDomainAuditStart(vm, "migrated", false);
2870 2871 2872
        goto endjob;
    }

2873 2874 2875 2876
    if (tunnel) {
        if (virFDStreamOpen(st, dataFD[1]) < 0) {
            virReportSystemError(errno, "%s",
                                 _("cannot pass pipe for tunnelled migration"));
2877
            goto stop;
2878
        }
2879
        dataFD[1] = -1; /* 'st' owns the FD now & will close it */
2880 2881
    }

2882 2883
    if (qemuMigrationSetCompression(driver, vm,
                                    flags & VIR_MIGRATE_COMPRESSED,
2884 2885 2886
                                    QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
        goto stop;

2887
    if (STREQ_NULLABLE(protocol, "rdma") &&
M
Michael R. Hines 已提交
2888 2889 2890 2891
        virProcessSetMaxMemLock(vm->pid, vm->def->mem.hard_limit << 10) < 0) {
        goto stop;
    }

2892 2893 2894
    if (qemuMigrationSetPinAll(driver, vm,
                               flags & VIR_MIGRATE_RDMA_PIN_ALL,
                               QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
2895 2896
        goto stop;

2897 2898 2899 2900 2901 2902 2903 2904
    if (mig->lockState) {
        VIR_DEBUG("Received lockstate %s", mig->lockState);
        VIR_FREE(priv->lockState);
        priv->lockState = mig->lockState;
        mig->lockState = NULL;
    } else {
        VIR_DEBUG("Received no lockstate");
    }
2905

2906
 done:
L
liguang 已提交
2907 2908 2909 2910 2911
    if (flags & VIR_MIGRATE_OFFLINE)
        cookieFlags = 0;
    else
        cookieFlags = QEMU_MIGRATION_COOKIE_GRAPHICS;

2912 2913 2914
    if (mig->nbd &&
        flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC) &&
        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NBD_SERVER)) {
2915
        if (qemuMigrationStartNBDServer(driver, vm, listenAddress) < 0) {
2916 2917
            /* error already reported */
            goto endjob;
2918
        }
2919
        cookieFlags |= QEMU_MIGRATION_COOKIE_NBD;
2920 2921 2922 2923
    }

    if (qemuMigrationBakeCookie(mig, driver, vm, cookieout,
                                cookieoutlen, cookieFlags) < 0) {
2924 2925 2926 2927 2928 2929 2930
        /* We could tear down the whole guest here, but
         * cookie data is (so far) non-critical, so that
         * seems a little harsh. We'll just warn for now.
         */
        VIR_WARN("Unable to encode migration cookie");
    }

2931 2932 2933
    if (qemuDomainCleanupAdd(vm, qemuMigrationPrepareCleanup) < 0)
        goto endjob;

L
liguang 已提交
2934 2935
    if (!(flags & VIR_MIGRATE_OFFLINE)) {
        virDomainAuditStart(vm, "migrated", true);
2936
        event = virDomainEventLifecycleNewFromObj(vm,
L
liguang 已提交
2937 2938 2939
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_MIGRATED);
    }
2940

2941 2942 2943 2944
    /* We keep the job active across API calls until the finish() call.
     * This prevents any other APIs being invoked while incoming
     * migration is taking place.
     */
2945
    if (!qemuMigrationJobContinue(vm)) {
2946
        vm = NULL;
2947 2948
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("domain disappeared"));
2949
        goto cleanup;
2950
    }
2951

2952 2953
    if (autoPort)
        priv->migrationPort = port;
2954
    ret = 0;
2955

2956
 cleanup:
J
Ján Tomko 已提交
2957
    VIR_FREE(migrateFrom);
J
Jiri Denemark 已提交
2958
    VIR_FREE(xmlout);
2959 2960
    VIR_FORCE_CLOSE(dataFD[0]);
    VIR_FORCE_CLOSE(dataFD[1]);
2961
    if (vm) {
2962
        if (ret < 0) {
2963
            virPortAllocatorRelease(driver->migrationPorts, priv->nbdPort);
2964 2965
            priv->nbdPort = 0;
        }
2966 2967 2968 2969
        if (ret >= 0 || vm->persistent)
            virObjectUnlock(vm);
        else
            qemuDomainRemoveInactive(driver, vm);
2970
    }
2971 2972
    if (event)
        qemuDomainEventQueue(driver, event);
2973
    qemuMigrationCookieFree(mig);
2974
    virObjectUnref(caps);
2975
    virNWFilterUnlockFilterUpdates();
2976
    return ret;
2977

2978
 stop:
2979 2980 2981
    virDomainAuditStart(vm, "migrated", false);
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);

2982
 endjob:
2983
    if (!qemuMigrationJobFinish(driver, vm))
2984 2985
        vm = NULL;
    goto cleanup;
2986 2987 2988
}


2989 2990 2991 2992 2993
/*
 * This version starts an empty VM listening on a localhost TCP port, and
 * sets up the corresponding virStream to handle the incoming data.
 */
int
2994
qemuMigrationPrepareTunnel(virQEMUDriverPtr driver,
2995 2996 2997 2998 2999 3000
                           virConnectPtr dconn,
                           const char *cookiein,
                           int cookieinlen,
                           char **cookieout,
                           int *cookieoutlen,
                           virStreamPtr st,
3001
                           virDomainDefPtr *def,
3002
                           const char *origname,
L
liguang 已提交
3003
                           unsigned long flags)
3004 3005 3006 3007
{
    int ret;

    VIR_DEBUG("driver=%p, dconn=%p, cookiein=%s, cookieinlen=%d, "
3008
              "cookieout=%p, cookieoutlen=%p, st=%p, def=%p, "
3009
              "origname=%s, flags=%lx",
3010
              driver, dconn, NULLSTR(cookiein), cookieinlen,
3011
              cookieout, cookieoutlen, st, *def, origname, flags);
3012

3013 3014 3015 3016 3017 3018
    if (st == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("tunnelled migration requested but NULL stream passed"));
        return -1;
    }

3019
    ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
3020
                                  cookieout, cookieoutlen, def, origname,
3021
                                  st, NULL, 0, false, NULL, flags);
3022 3023 3024 3025
    return ret;
}


3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048
static virURIPtr
qemuMigrationParseURI(const char *uri, bool *wellFormed)
{
    char *tmp = NULL;
    virURIPtr parsed;

    /* For compatibility reasons tcp://... URIs are sent as tcp:...
     * We need to transform them to a well-formed URI before parsing. */
    if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri + 4, "//")) {
        if (virAsprintf(&tmp, "tcp://%s", uri + 4) < 0)
            return NULL;
        uri = tmp;
    }

    parsed = virURIParse(uri);
    if (parsed && wellFormed)
        *wellFormed = !tmp;
    VIR_FREE(tmp);

    return parsed;
}


3049
int
3050
qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
3051
                           virConnectPtr dconn,
3052 3053 3054 3055
                           const char *cookiein,
                           int cookieinlen,
                           char **cookieout,
                           int *cookieoutlen,
3056 3057
                           const char *uri_in,
                           char **uri_out,
3058
                           virDomainDefPtr *def,
3059
                           const char *origname,
3060
                           const char *listenAddress,
L
liguang 已提交
3061
                           unsigned long flags)
3062
{
3063 3064
    unsigned short port = 0;
    bool autoPort = true;
3065 3066
    char *hostname = NULL;
    int ret = -1;
3067
    virURIPtr uri = NULL;
3068 3069
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    const char *migrateHost = cfg->migrateHost;
J
Jiri Denemark 已提交
3070

3071 3072
    VIR_DEBUG("driver=%p, dconn=%p, cookiein=%s, cookieinlen=%d, "
              "cookieout=%p, cookieoutlen=%p, uri_in=%s, uri_out=%p, "
3073
              "def=%p, origname=%s, listenAddress=%s, flags=%lx",
3074 3075
              driver, dconn, NULLSTR(cookiein), cookieinlen,
              cookieout, cookieoutlen, NULLSTR(uri_in), uri_out,
3076
              *def, origname, NULLSTR(listenAddress), flags);
3077

3078 3079
    *uri_out = NULL;

3080 3081 3082
    /* The URI passed in may be NULL or a string "tcp://somehostname:port".
     *
     * If the URI passed in is NULL then we allocate a port number
3083 3084 3085
     * from our pool of port numbers, and if the migrateHost is configured,
     * we return a URI of "tcp://migrateHost:port", otherwise return a URI
     * of "tcp://ourhostname:port".
3086 3087 3088 3089 3090 3091
     *
     * If the URI passed in is not NULL then we try to parse out the
     * port number and use that (note that the hostname is assumed
     * to be a correct hostname which refers to the target machine).
     */
    if (uri_in == NULL) {
3092 3093 3094
        bool encloseAddress = false;
        const char *incFormat;

3095
        if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0)
3096
            goto cleanup;
3097

3098
        if (migrateHost != NULL) {
3099 3100
            if (virSocketAddrNumericFamily(migrateHost) == AF_INET6)
                encloseAddress = true;
3101

3102
            if (VIR_STRDUP(hostname, migrateHost) < 0)
3103 3104 3105 3106 3107
                goto cleanup;
        } else {
            if ((hostname = virGetHostname()) == NULL)
                goto cleanup;
        }
3108 3109

        if (STRPREFIX(hostname, "localhost")) {
3110 3111 3112
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("hostname on destination resolved to localhost,"
                             " but migration requires an FQDN"));
3113 3114 3115 3116 3117
            goto cleanup;
        }

        /* XXX this really should have been a properly well-formed
         * URI, but we can't add in tcp:// now without breaking
3118
         * compatibility with old targets. We at least make the
3119 3120
         * new targets accept both syntaxes though.
         */
3121 3122 3123 3124 3125 3126
        if (encloseAddress)
            incFormat = "%s:[%s]:%d";
        else
            incFormat = "%s:%s:%d";

        if (virAsprintf(uri_out, incFormat, "tcp", hostname, port) < 0)
3127 3128
            goto cleanup;
    } else {
3129
        bool well_formed_uri;
J
Ján Tomko 已提交
3130

3131 3132
        if (!(uri = qemuMigrationParseURI(uri_in, &well_formed_uri)))
            goto cleanup;
J
Ján Tomko 已提交
3133

M
Michael R. Hines 已提交
3134 3135
        if (STRNEQ(uri->scheme, "tcp") &&
            STRNEQ(uri->scheme, "rdma")) {
3136 3137 3138
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                           _("unsupported scheme %s in migration URI %s"),
                           uri->scheme, uri_in);
J
Ján Tomko 已提交
3139 3140 3141 3142 3143 3144 3145 3146 3147 3148
            goto cleanup;
        }

        if (uri->server == NULL) {
            virReportError(VIR_ERR_INVALID_ARG, _("missing host in migration"
                                                  " URI: %s"), uri_in);
            goto cleanup;
        }

        if (uri->port == 0) {
3149
            if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0)
3150
                goto cleanup;
3151

3152
            /* Send well-formed URI only if uri_in was well-formed */
3153 3154 3155 3156 3157 3158 3159 3160
            if (well_formed_uri) {
                uri->port = port;
                if (!(*uri_out = virURIFormat(uri)))
                    goto cleanup;
            } else {
                if (virAsprintf(uri_out, "%s:%d", uri_in, port) < 0)
                    goto cleanup;
            }
3161
        } else {
3162 3163
            port = uri->port;
            autoPort = false;
3164 3165 3166 3167 3168 3169
        }
    }

    if (*uri_out)
        VIR_DEBUG("Generated uri_out=%s", *uri_out);

3170
    ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
3171
                                  cookieout, cookieoutlen, def, origname,
3172 3173
                                  NULL, uri ? uri->scheme : "tcp",
                                  port, autoPort, listenAddress, flags);
3174
 cleanup:
3175
    virURIFree(uri);
3176
    VIR_FREE(hostname);
3177
    virObjectUnref(cfg);
3178
    if (ret != 0) {
3179
        VIR_FREE(*uri_out);
3180 3181 3182
        if (autoPort)
            virPortAllocatorRelease(driver->migrationPorts, port);
    }
3183 3184 3185 3186
    return ret;
}


3187 3188 3189
virDomainDefPtr
qemuMigrationPrepareDef(virQEMUDriverPtr driver,
                        const char *dom_xml,
3190 3191
                        const char *dname,
                        char **origname)
3192 3193 3194
{
    virCapsPtr caps = NULL;
    virDomainDefPtr def;
3195
    char *name = NULL;
3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211

    if (!dom_xml) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no domain XML passed"));
        return NULL;
    }

    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        return NULL;

    if (!(def = virDomainDefParseString(dom_xml, caps, driver->xmlopt,
                                        QEMU_EXPECTED_VIRT_TYPES,
                                        VIR_DOMAIN_XML_INACTIVE)))
        goto cleanup;

    if (dname) {
3212
        name = def->name;
3213 3214 3215 3216 3217 3218
        if (VIR_STRDUP(def->name, dname) < 0) {
            virDomainDefFree(def);
            def = NULL;
        }
    }

3219
 cleanup:
3220
    virObjectUnref(caps);
3221 3222 3223 3224
    if (def && origname)
        *origname = name;
    else
        VIR_FREE(name);
3225 3226 3227 3228
    return def;
}


3229 3230 3231 3232 3233 3234 3235 3236 3237 3238
static int
qemuMigrationConfirmPhase(virQEMUDriverPtr driver,
                          virConnectPtr conn,
                          virDomainObjPtr vm,
                          const char *cookiein,
                          int cookieinlen,
                          unsigned int flags,
                          int retcode)
{
    qemuMigrationCookiePtr mig;
3239
    virObjectEventPtr event = NULL;
3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254
    int rv = -1;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);

    VIR_DEBUG("driver=%p, conn=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
              "flags=%x, retcode=%d",
              driver, conn, vm, NULLSTR(cookiein), cookieinlen,
              flags, retcode);

    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);

    qemuMigrationJobSetPhase(driver, vm,
                             retcode == 0
                             ? QEMU_MIGRATION_PHASE_CONFIRM3
                             : QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED);

3255 3256
    if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen,
                                       QEMU_MIGRATION_COOKIE_STATS)))
3257 3258
        goto cleanup;

3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275
    /* Update total times with the values sent by the destination daemon */
    if (mig->jobInfo) {
        qemuDomainObjPrivatePtr priv = vm->privateData;
        if (priv->job.completed) {
            qemuDomainJobInfoPtr jobInfo = priv->job.completed;
            if (mig->jobInfo->status.downtime_set) {
                jobInfo->status.downtime = mig->jobInfo->status.downtime;
                jobInfo->status.downtime_set = true;
            }
            if (mig->jobInfo->timeElapsed)
                jobInfo->timeElapsed = mig->jobInfo->timeElapsed;
        } else {
            priv->job.completed = mig->jobInfo;
            mig->jobInfo = NULL;
        }
    }

3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290
    if (flags & VIR_MIGRATE_OFFLINE)
        goto done;

    /* Did the migration go as planned?  If yes, kill off the
     * domain object, but if no, resume CPUs
     */
    if (retcode == 0) {
        /* If guest uses SPICE and supports seamless migration we have to hold
         * up domain shutdown until SPICE server transfers its data */
        qemuMigrationWaitForSpice(driver, vm);

        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED,
                        VIR_QEMU_PROCESS_STOP_MIGRATED);
        virDomainAuditStop(vm, "migrated");

3291
        event = virDomainEventLifecycleNewFromObj(vm,
3292 3293 3294 3295 3296 3297 3298
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
    } else {

        /* cancel any outstanding NBD jobs */
        qemuMigrationCancelDriveMirror(mig, driver, vm);

3299 3300 3301 3302
        if (qemuMigrationRestoreDomainState(conn, vm)) {
            event = virDomainEventLifecycleNewFromObj(vm,
                                                      VIR_DOMAIN_EVENT_RESUMED,
                                                      VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
3303 3304 3305 3306 3307 3308 3309 3310
        }

        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
            goto cleanup;
        }
    }

3311
 done:
3312 3313 3314
    qemuMigrationCookieFree(mig);
    rv = 0;

3315
 cleanup:
3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330
    if (event)
        qemuDomainEventQueue(driver, event);
    virObjectUnref(cfg);
    return rv;
}

int
qemuMigrationConfirm(virConnectPtr conn,
                     virDomainObjPtr vm,
                     const char *cookiein,
                     int cookieinlen,
                     unsigned int flags,
                     int cancelled)
{
    virQEMUDriverPtr driver = conn->privateData;
3331
    qemuMigrationJobPhase phase;
3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345
    virQEMUDriverConfigPtr cfg = NULL;
    int ret = -1;

    cfg = virQEMUDriverGetConfig(driver);

    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT))
        goto cleanup;

    if (cancelled)
        phase = QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED;
    else
        phase = QEMU_MIGRATION_PHASE_CONFIRM3;

    qemuMigrationJobStartPhase(driver, vm, phase);
3346 3347
    virCloseCallbacksUnset(driver->closeCallbacks, vm,
                           qemuMigrationCleanup);
3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362

    ret = qemuMigrationConfirmPhase(driver, conn, vm,
                                    cookiein, cookieinlen,
                                    flags, cancelled);

    if (qemuMigrationJobFinish(driver, vm) == 0) {
        vm = NULL;
    } else if (!virDomainObjIsActive(vm) &&
               (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE))) {
        if (flags & VIR_MIGRATE_UNDEFINE_SOURCE)
            virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm);
        qemuDomainRemoveInactive(driver, vm);
        vm = NULL;
    }

3363
 cleanup:
3364 3365 3366 3367 3368 3369 3370
    if (vm)
        virObjectUnlock(vm);
    virObjectUnref(cfg);
    return ret;
}


3371 3372
enum qemuMigrationDestinationType {
    MIGRATION_DEST_HOST,
3373
    MIGRATION_DEST_CONNECT_HOST,
3374
    MIGRATION_DEST_UNIX,
3375
    MIGRATION_DEST_FD,
3376
};
3377

3378 3379 3380 3381
enum qemuMigrationForwardType {
    MIGRATION_FWD_DIRECT,
    MIGRATION_FWD_STREAM,
};
3382

3383 3384 3385 3386 3387 3388
typedef struct _qemuMigrationSpec qemuMigrationSpec;
typedef qemuMigrationSpec *qemuMigrationSpecPtr;
struct _qemuMigrationSpec {
    enum qemuMigrationDestinationType destType;
    union {
        struct {
3389
            const char *protocol;
3390 3391 3392 3393 3394
            const char *name;
            int port;
        } host;

        struct {
3395
            char *file;
3396 3397
            int sock;
        } unix_socket;
3398 3399 3400 3401 3402

        struct {
            int qemu;
            int local;
        } fd;
3403 3404 3405 3406 3407 3408 3409
    } dest;

    enum qemuMigrationForwardType fwdType;
    union {
        virStreamPtr stream;
    } fwd;
};
3410 3411 3412

#define TUNNEL_SEND_BUF_SIZE 65536

3413 3414 3415 3416 3417 3418 3419
typedef struct _qemuMigrationIOThread qemuMigrationIOThread;
typedef qemuMigrationIOThread *qemuMigrationIOThreadPtr;
struct _qemuMigrationIOThread {
    virThread thread;
    virStreamPtr st;
    int sock;
    virError err;
3420 3421
    int wakeupRecvFD;
    int wakeupSendFD;
3422 3423 3424
};

static void qemuMigrationIOFunc(void *arg)
3425
{
3426
    qemuMigrationIOThreadPtr data = arg;
3427 3428 3429 3430 3431 3432 3433
    char *buffer = NULL;
    struct pollfd fds[2];
    int timeout = -1;
    virErrorPtr err = NULL;

    VIR_DEBUG("Running migration tunnel; stream=%p, sock=%d",
              data->st, data->sock);
3434

3435
    if (VIR_ALLOC_N(buffer, TUNNEL_SEND_BUF_SIZE) < 0)
3436
        goto abrt;
3437

3438 3439 3440
    fds[0].fd = data->sock;
    fds[1].fd = data->wakeupRecvFD;

3441
    for (;;) {
3442 3443 3444 3445 3446 3447 3448 3449 3450 3451
        int ret;

        fds[0].events = fds[1].events = POLLIN;
        fds[0].revents = fds[1].revents = 0;

        ret = poll(fds, ARRAY_CARDINALITY(fds), timeout);

        if (ret < 0) {
            if (errno == EAGAIN || errno == EINTR)
                continue;
3452
            virReportSystemError(errno, "%s",
3453 3454
                                 _("poll failed in migration tunnel"));
            goto abrt;
3455
        }
3456 3457 3458 3459 3460 3461 3462

        if (ret == 0) {
            /* We were asked to gracefully stop but reading would block. This
             * can only happen if qemu told us migration finished but didn't
             * close the migration fd. We handle this in the same way as EOF.
             */
            VIR_DEBUG("QEMU forgot to close migration fd");
3463
            break;
3464
        }
3465

3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481
        if (fds[1].revents & (POLLIN | POLLERR | POLLHUP)) {
            char stop = 0;

            if (saferead(data->wakeupRecvFD, &stop, 1) != 1) {
                virReportSystemError(errno, "%s",
                                     _("failed to read from wakeup fd"));
                goto abrt;
            }

            VIR_DEBUG("Migration tunnel was asked to %s",
                      stop ? "abort" : "finish");
            if (stop) {
                goto abrt;
            } else {
                timeout = 0;
            }
3482 3483
        }

3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500
        if (fds[0].revents & (POLLIN | POLLERR | POLLHUP)) {
            int nbytes;

            nbytes = saferead(data->sock, buffer, TUNNEL_SEND_BUF_SIZE);
            if (nbytes > 0) {
                if (virStreamSend(data->st, buffer, nbytes) < 0)
                    goto error;
            } else if (nbytes < 0) {
                virReportSystemError(errno, "%s",
                        _("tunnelled migration failed to read from qemu"));
                goto abrt;
            } else {
                /* EOF; get out of here */
                break;
            }
        }
    }
3501

3502 3503
    if (virStreamFinish(data->st) < 0)
        goto error;
3504

3505 3506
    VIR_FREE(buffer);

3507 3508
    return;

3509
 abrt:
3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520
    err = virSaveLastError();
    if (err && err->code == VIR_ERR_OK) {
        virFreeError(err);
        err = NULL;
    }
    virStreamAbort(data->st);
    if (err) {
        virSetError(err);
        virFreeError(err);
    }

3521
 error:
3522 3523
    virCopyLastError(&data->err);
    virResetLastError();
3524
    VIR_FREE(buffer);
3525 3526 3527 3528 3529 3530 3531
}


static qemuMigrationIOThreadPtr
qemuMigrationStartTunnel(virStreamPtr st,
                         int sock)
{
3532 3533
    qemuMigrationIOThreadPtr io = NULL;
    int wakeupFD[2] = { -1, -1 };
3534

3535 3536 3537 3538
    if (pipe2(wakeupFD, O_CLOEXEC) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to make pipe"));
        goto error;
3539 3540
    }

3541
    if (VIR_ALLOC(io) < 0)
3542
        goto error;
3543

3544 3545
    io->st = st;
    io->sock = sock;
3546 3547
    io->wakeupRecvFD = wakeupFD[0];
    io->wakeupSendFD = wakeupFD[1];
3548 3549 3550 3551 3552 3553

    if (virThreadCreate(&io->thread, true,
                        qemuMigrationIOFunc,
                        io) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to create migration thread"));
3554
        goto error;
3555 3556 3557
    }

    return io;
3558

3559
 error:
3560 3561 3562 3563
    VIR_FORCE_CLOSE(wakeupFD[0]);
    VIR_FORCE_CLOSE(wakeupFD[1]);
    VIR_FREE(io);
    return NULL;
3564 3565 3566
}

static int
3567
qemuMigrationStopTunnel(qemuMigrationIOThreadPtr io, bool error)
3568 3569
{
    int rv = -1;
3570 3571 3572 3573 3574 3575 3576 3577 3578
    char stop = error ? 1 : 0;

    /* make sure the thread finishes its job and is joinable */
    if (safewrite(io->wakeupSendFD, &stop, 1) != 1) {
        virReportSystemError(errno, "%s",
                             _("failed to wakeup migration tunnel"));
        goto cleanup;
    }

3579 3580 3581 3582
    virThreadJoin(&io->thread);

    /* Forward error from the IO thread, to this thread */
    if (io->err.code != VIR_ERR_OK) {
3583 3584 3585 3586
        if (error)
            rv = 0;
        else
            virSetError(&io->err);
3587 3588 3589 3590 3591 3592
        virResetError(&io->err);
        goto cleanup;
    }

    rv = 0;

3593
 cleanup:
3594 3595
    VIR_FORCE_CLOSE(io->wakeupSendFD);
    VIR_FORCE_CLOSE(io->wakeupRecvFD);
3596 3597
    VIR_FREE(io);
    return rv;
3598 3599
}

3600
static int
3601
qemuMigrationConnect(virQEMUDriverPtr driver,
3602 3603 3604 3605 3606 3607 3608 3609 3610
                     virDomainObjPtr vm,
                     qemuMigrationSpecPtr spec)
{
    virNetSocketPtr sock;
    const char *host;
    char *port = NULL;
    int ret = -1;

    host = spec->dest.host.name;
3611
    if (virAsprintf(&port, "%d", spec->dest.host.port) < 0)
3612 3613 3614 3615 3616 3617 3618 3619 3620
        return -1;

    spec->destType = MIGRATION_DEST_FD;
    spec->dest.fd.qemu = -1;

    if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0)
        goto cleanup;
    if (virNetSocketNewConnectTCP(host, port, &sock) == 0) {
        spec->dest.fd.qemu = virNetSocketDupFD(sock, true);
3621
        virObjectUnref(sock);
3622 3623 3624 3625 3626
    }
    if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0 ||
        spec->dest.fd.qemu == -1)
        goto cleanup;

3627 3628 3629 3630 3631 3632 3633
    /* Migration expects a blocking FD */
    if (virSetBlocking(spec->dest.fd.qemu, true) < 0) {
        virReportSystemError(errno, _("Unable to set FD %d blocking"),
                             spec->dest.fd.qemu);
        goto cleanup;
    }

3634 3635
    ret = 0;

3636
 cleanup:
3637 3638 3639 3640 3641 3642
    VIR_FREE(port);
    if (ret < 0)
        VIR_FORCE_CLOSE(spec->dest.fd.qemu);
    return ret;
}

3643
static int
3644
qemuMigrationRun(virQEMUDriverPtr driver,
3645 3646 3647 3648 3649 3650 3651
                 virDomainObjPtr vm,
                 const char *cookiein,
                 int cookieinlen,
                 char **cookieout,
                 int *cookieoutlen,
                 unsigned long flags,
                 unsigned long resource,
3652
                 qemuMigrationSpecPtr spec,
3653 3654
                 virConnectPtr dconn,
                 const char *graphicsuri)
3655
{
3656
    int ret = -1;
3657 3658
    unsigned int migrate_flags = QEMU_MONITOR_MIGRATE_BACKGROUND;
    qemuDomainObjPrivatePtr priv = vm->privateData;
3659
    qemuMigrationCookiePtr mig = NULL;
3660
    qemuMigrationIOThreadPtr iothread = NULL;
3661
    int fd = -1;
3662
    unsigned long migrate_speed = resource ? resource : priv->migMaxBandwidth;
3663
    virErrorPtr orig_err = NULL;
3664
    unsigned int cookieFlags = 0;
3665
    bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
3666
    int rc;
3667 3668 3669

    VIR_DEBUG("driver=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
              "cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu, "
3670
              "spec=%p (dest=%d, fwd=%d), dconn=%p, graphicsuri=%s",
3671 3672
              driver, vm, NULLSTR(cookiein), cookieinlen,
              cookieout, cookieoutlen, flags, resource,
3673 3674
              spec, spec->destType, spec->fwdType, dconn,
              NULLSTR(graphicsuri));
3675

3676 3677 3678 3679 3680 3681 3682 3683 3684 3685
    if (flags & VIR_MIGRATE_NON_SHARED_DISK) {
        migrate_flags |= QEMU_MONITOR_MIGRATE_NON_SHARED_DISK;
        cookieFlags |= QEMU_MIGRATION_COOKIE_NBD;
    }

    if (flags & VIR_MIGRATE_NON_SHARED_INC) {
        migrate_flags |= QEMU_MONITOR_MIGRATE_NON_SHARED_INC;
        cookieFlags |= QEMU_MIGRATION_COOKIE_NBD;
    }

3686 3687
    if (virLockManagerPluginUsesState(driver->lockManager) &&
        !cookieout) {
3688 3689 3690 3691
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Migration with lock driver %s requires"
                         " cookie support"),
                       virLockManagerPluginGetName(driver->lockManager));
3692 3693 3694
        return -1;
    }

3695 3696 3697
    mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen,
                                 cookieFlags | QEMU_MIGRATION_COOKIE_GRAPHICS);
    if (!mig)
3698 3699
        goto cleanup;

3700
    if (qemuDomainMigrateGraphicsRelocate(driver, vm, mig, graphicsuri) < 0)
3701 3702
        VIR_WARN("unable to provide data for graphics client relocation");

3703 3704 3705 3706 3707 3708 3709
    /* this will update migrate_flags on success */
    if (qemuMigrationDriveMirror(driver, vm, mig, spec->dest.host.name,
                                 migrate_speed, &migrate_flags) < 0) {
        /* error reported by helper func */
        goto cleanup;
    }

3710
    /* Before EnterMonitor, since qemuMigrationSetOffline already does that */
3711 3712 3713 3714 3715 3716
    if (!(flags & VIR_MIGRATE_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
        if (qemuMigrationSetOffline(driver, vm) < 0)
            goto cleanup;
    }

3717 3718
    if (qemuMigrationSetCompression(driver, vm,
                                    flags & VIR_MIGRATE_COMPRESSED,
3719 3720 3721
                                    QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
        goto cleanup;

3722 3723
    if (qemuMigrationSetAutoConverge(driver, vm,
                                     flags & VIR_MIGRATE_AUTO_CONVERGE,
3724 3725 3726
                                     QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
        goto cleanup;

3727 3728
    if (qemuMigrationSetPinAll(driver, vm,
                               flags & VIR_MIGRATE_RDMA_PIN_ALL,
3729 3730 3731
                               QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
        goto cleanup;

3732 3733
    if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                       QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
3734 3735
        goto cleanup;

3736 3737 3738 3739
    if (priv->job.asyncAbort) {
        /* explicitly do this *after* we entered the monitor,
         * as this is a critical section so we are guaranteed
         * priv->job.asyncAbort will not change */
3740
        qemuDomainObjExitMonitor(driver, vm);
3741
        priv->job.current->type = VIR_DOMAIN_JOB_CANCELLED;
3742 3743 3744 3745 3746 3747
        virReportError(VIR_ERR_OPERATION_ABORTED, _("%s: %s"),
                       qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
                       _("canceled by client"));
        goto cleanup;
    }

3748
    if (qemuMonitorSetMigrationSpeed(priv->mon, migrate_speed) < 0) {
3749
        qemuDomainObjExitMonitor(driver, vm);
3750 3751
        goto cleanup;
    }
3752

3753 3754
    /* connect to the destination qemu if needed */
    if (spec->destType == MIGRATION_DEST_CONNECT_HOST &&
3755
        qemuMigrationConnect(driver, vm, spec) < 0) {
3756
        qemuDomainObjExitMonitor(driver, vm);
3757
        goto cleanup;
3758
    }
3759

3760 3761
    switch (spec->destType) {
    case MIGRATION_DEST_HOST:
M
Michael R. Hines 已提交
3762 3763 3764 3765 3766
        if (STREQ(spec->dest.host.protocol, "rdma") &&
            virProcessSetMaxMemLock(vm->pid, vm->def->mem.hard_limit << 10) < 0) {
            qemuDomainObjExitMonitor(driver, vm);
            goto cleanup;
        }
3767
        ret = qemuMonitorMigrateToHost(priv->mon, migrate_flags,
3768
                                       spec->dest.host.protocol,
3769 3770 3771 3772
                                       spec->dest.host.name,
                                       spec->dest.host.port);
        break;

3773 3774 3775 3776
    case MIGRATION_DEST_CONNECT_HOST:
        /* handled above and transformed into MIGRATION_DEST_FD */
        break;

3777
    case MIGRATION_DEST_UNIX:
3778
        if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_UNIX)) {
3779 3780 3781 3782 3783 3784 3785 3786 3787
            ret = qemuMonitorMigrateToUnix(priv->mon, migrate_flags,
                                           spec->dest.unix_socket.file);
        } else {
            const char *args[] = {
                "nc", "-U", spec->dest.unix_socket.file, NULL
            };
            ret = qemuMonitorMigrateToCommand(priv->mon, migrate_flags, args);
        }
        break;
3788 3789

    case MIGRATION_DEST_FD:
3790
        if (spec->fwdType != MIGRATION_FWD_DIRECT) {
3791
            fd = spec->dest.fd.local;
3792 3793
            spec->dest.fd.local = -1;
        }
3794 3795 3796 3797
        ret = qemuMonitorMigrateToFd(priv->mon, migrate_flags,
                                     spec->dest.fd.qemu);
        VIR_FORCE_CLOSE(spec->dest.fd.qemu);
        break;
3798
    }
3799
    qemuDomainObjExitMonitor(driver, vm);
3800
    if (ret < 0)
3801 3802
        goto cleanup;
    ret = -1;
3803 3804

    if (!virDomainObjIsActive(vm)) {
3805 3806
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
3807 3808 3809 3810 3811 3812
        goto cleanup;
    }

    /* From this point onwards we *must* call cancel to abort the
     * migration on source if anything goes wrong */

3813 3814 3815 3816 3817 3818 3819 3820
    if (spec->destType == MIGRATION_DEST_UNIX) {
        /* It is also possible that the migrate didn't fail initially, but
         * rather failed later on.  Check its status before waiting for a
         * connection from qemu which may never be initiated.
         */
        if (qemuMigrationUpdateJobStatus(driver, vm, _("migration job"),
                                         QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            goto cancel;
3821

3822 3823 3824 3825 3826 3827 3828
        while ((fd = accept(spec->dest.unix_socket.sock, NULL, NULL)) < 0) {
            if (errno == EAGAIN || errno == EINTR)
                continue;
            virReportSystemError(errno, "%s",
                                 _("failed to accept connection from qemu"));
            goto cancel;
        }
3829 3830
    }

3831 3832
    if (spec->fwdType != MIGRATION_FWD_DIRECT &&
        !(iothread = qemuMigrationStartTunnel(spec->fwd.stream, fd)))
3833 3834
        goto cancel;

3835 3836 3837 3838 3839 3840
    rc = qemuMigrationWaitForCompletion(driver, vm,
                                        QEMU_ASYNC_JOB_MIGRATION_OUT,
                                        dconn, abort_on_error);
    if (rc == -2)
        goto cancel;
    else if (rc == -1)
3841
        goto cleanup;
3842

3843 3844 3845 3846 3847 3848 3849 3850 3851
    /* When migration completed, QEMU will have paused the
     * CPUs for us, but unless we're using the JSON monitor
     * we won't have been notified of this, so might still
     * think we're running. For v2 protocol this doesn't
     * matter because we'll kill the VM soon, but for v3
     * this is important because we stay paused until the
     * confirm3 step, but need to release the lock state
     */
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
3852 3853
        if (qemuMigrationSetOffline(driver, vm) < 0) {
            priv->job.current->type = VIR_DOMAIN_JOB_FAILED;
3854
            goto cleanup;
3855
        }
3856 3857
    }

3858
    ret = 0;
3859

3860
 cleanup:
3861 3862 3863
    if (ret < 0 && !orig_err)
        orig_err = virSaveLastError();

3864
    /* cancel any outstanding NBD jobs */
3865 3866
    if (mig)
        qemuMigrationCancelDriveMirror(mig, driver, vm);
3867

3868
    if (spec->fwdType != MIGRATION_FWD_DIRECT) {
3869
        if (iothread && qemuMigrationStopTunnel(iothread, ret < 0) < 0)
3870
            ret = -1;
3871
        VIR_FORCE_CLOSE(fd);
3872
    }
3873

3874
    if (priv->job.completed) {
3875
        qemuDomainJobInfoUpdateTime(priv->job.completed);
3876 3877
        qemuDomainJobInfoUpdateDowntime(priv->job.completed);
    }
3878

3879 3880 3881
    if (priv->job.current->type == VIR_DOMAIN_JOB_UNBOUNDED)
        priv->job.current->type = VIR_DOMAIN_JOB_FAILED;

3882 3883
    cookieFlags |= QEMU_MIGRATION_COOKIE_NETWORK |
                   QEMU_MIGRATION_COOKIE_STATS;
3884 3885
    if (flags & VIR_MIGRATE_PERSIST_DEST)
        cookieFlags |= QEMU_MIGRATION_COOKIE_PERSISTENT;
3886
    if (ret == 0 &&
3887 3888
        qemuMigrationBakeCookie(mig, driver, vm, cookieout,
                                cookieoutlen, cookieFlags) < 0) {
3889
        VIR_WARN("Unable to encode migration cookie");
3890
    }
3891

3892 3893
    qemuMigrationCookieFree(mig);

3894 3895 3896 3897 3898
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }

3899 3900
    return ret;

3901
 cancel:
3902 3903
    orig_err = virSaveLastError();

3904
    if (virDomainObjIsActive(vm)) {
3905 3906
        if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                           QEMU_ASYNC_JOB_MIGRATION_OUT) == 0) {
3907
            qemuMonitorMigrateCancel(priv->mon);
3908
            qemuDomainObjExitMonitor(driver, vm);
3909
        }
3910
    }
3911 3912 3913
    goto cleanup;
}

3914
/* Perform migration using QEMU's native migrate support,
3915 3916
 * not encrypted obviously
 */
3917
static int doNativeMigrate(virQEMUDriverPtr driver,
3918 3919 3920 3921 3922 3923 3924
                           virDomainObjPtr vm,
                           const char *uri,
                           const char *cookiein,
                           int cookieinlen,
                           char **cookieout,
                           int *cookieoutlen,
                           unsigned long flags,
3925
                           unsigned long resource,
3926 3927
                           virConnectPtr dconn,
                           const char *graphicsuri)
3928
{
3929
    qemuDomainObjPrivatePtr priv = vm->privateData;
M
Martin Kletzander 已提交
3930
    virURIPtr uribits = NULL;
3931
    int ret = -1;
3932 3933 3934
    qemuMigrationSpec spec;

    VIR_DEBUG("driver=%p, vm=%p, uri=%s, cookiein=%s, cookieinlen=%d, "
3935 3936
              "cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu, "
              "graphicsuri=%s",
3937
              driver, vm, uri, NULLSTR(cookiein), cookieinlen,
3938 3939
              cookieout, cookieoutlen, flags, resource,
              NULLSTR(graphicsuri));
3940

3941
    if (!(uribits = qemuMigrationParseURI(uri, NULL)))
3942 3943
        return -1;

M
Michael R. Hines 已提交
3944 3945 3946 3947 3948
    if (STREQ(uribits->scheme, "rdma")) {
        if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_RDMA)) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("outgoing RDMA migration is not supported "
                             "with this QEMU binary"));
3949
            goto cleanup;
M
Michael R. Hines 已提交
3950 3951 3952 3953 3954
        }
        if (!vm->def->mem.hard_limit) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot start RDMA migration with no memory hard "
                             "limit set"));
3955
            goto cleanup;
M
Michael R. Hines 已提交
3956 3957 3958 3959 3960
        }
    }

    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD) &&
        STRNEQ(uribits->scheme, "rdma"))
3961 3962
        spec.destType = MIGRATION_DEST_CONNECT_HOST;
    else
3963
        spec.destType = MIGRATION_DEST_HOST;
3964
    spec.dest.host.protocol = uribits->scheme;
3965 3966 3967
    spec.dest.host.name = uribits->server;
    spec.dest.host.port = uribits->port;
    spec.fwdType = MIGRATION_FWD_DIRECT;
3968

3969
    ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout,
3970 3971
                           cookieoutlen, flags, resource, &spec, dconn,
                           graphicsuri);
3972 3973 3974 3975

    if (spec.destType == MIGRATION_DEST_FD)
        VIR_FORCE_CLOSE(spec.dest.fd.qemu);

3976
 cleanup:
3977
    virURIFree(uribits);
3978 3979 3980 3981 3982

    return ret;
}


3983
static int doTunnelMigrate(virQEMUDriverPtr driver,
3984 3985 3986 3987 3988 3989 3990
                           virDomainObjPtr vm,
                           virStreamPtr st,
                           const char *cookiein,
                           int cookieinlen,
                           char **cookieout,
                           int *cookieoutlen,
                           unsigned long flags,
3991
                           unsigned long resource,
3992 3993
                           virConnectPtr dconn,
                           const char *graphicsuri)
3994 3995
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3996
    virNetSocketPtr sock = NULL;
3997 3998
    int ret = -1;
    qemuMigrationSpec spec;
3999
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
4000 4001

    VIR_DEBUG("driver=%p, vm=%p, st=%p, cookiein=%s, cookieinlen=%d, "
4002 4003
              "cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu, "
              "graphicsuri=%s",
4004
              driver, vm, st, NULLSTR(cookiein), cookieinlen,
4005 4006
              cookieout, cookieoutlen, flags, resource,
              NULLSTR(graphicsuri));
4007

4008 4009 4010
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD) &&
        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_UNIX) &&
        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_EXEC)) {
4011 4012
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Source qemu is too old to support tunnelled migration"));
4013
        virObjectUnref(cfg);
4014
        return -1;
4015 4016 4017 4018 4019
    }

    spec.fwdType = MIGRATION_FWD_STREAM;
    spec.fwd.stream = st;

4020
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD)) {
4021 4022 4023 4024 4025 4026
        int fds[2];

        spec.destType = MIGRATION_DEST_FD;
        spec.dest.fd.qemu = -1;
        spec.dest.fd.local = -1;

4027
        if (pipe2(fds, O_CLOEXEC) == 0) {
4028 4029 4030 4031
            spec.dest.fd.qemu = fds[1];
            spec.dest.fd.local = fds[0];
        }
        if (spec.dest.fd.qemu == -1 ||
4032
            virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def,
4033
                                              spec.dest.fd.qemu) < 0) {
4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044
            virReportSystemError(errno, "%s",
                        _("cannot create pipe for tunnelled migration"));
            goto cleanup;
        }
    } else {
        spec.destType = MIGRATION_DEST_UNIX;
        spec.dest.unix_socket.sock = -1;
        spec.dest.unix_socket.file = NULL;

        if (virAsprintf(&spec.dest.unix_socket.file,
                        "%s/qemu.tunnelmigrate.src.%s",
4045
                        cfg->libDir, vm->def->name) < 0)
4046 4047 4048
            goto cleanup;

        if (virNetSocketNewListenUNIX(spec.dest.unix_socket.file, 0700,
4049
                                      cfg->user, cfg->group,
4050 4051 4052 4053 4054 4055 4056
                                      &sock) < 0 ||
            virNetSocketListen(sock, 1) < 0)
            goto cleanup;

        spec.dest.unix_socket.sock = virNetSocketGetFD(sock);
    }

4057
    ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout,
4058 4059
                           cookieoutlen, flags, resource, &spec, dconn,
                           graphicsuri);
4060

4061
 cleanup:
4062 4063 4064 4065
    if (spec.destType == MIGRATION_DEST_FD) {
        VIR_FORCE_CLOSE(spec.dest.fd.qemu);
        VIR_FORCE_CLOSE(spec.dest.fd.local);
    } else {
4066
        virObjectUnref(sock);
4067 4068
        VIR_FREE(spec.dest.unix_socket.file);
    }
4069

4070
    virObjectUnref(cfg);
4071 4072 4073 4074
    return ret;
}


4075 4076 4077 4078
/* This is essentially a re-impl of virDomainMigrateVersion2
 * from libvirt.c, but running in source libvirtd context,
 * instead of client app context & also adding in tunnel
 * handling */
4079
static int doPeer2PeerMigrate2(virQEMUDriverPtr driver,
4080
                               virConnectPtr sconn ATTRIBUTE_UNUSED,
4081 4082
                               virConnectPtr dconn,
                               virDomainObjPtr vm,
4083
                               const char *dconnuri,
4084 4085 4086
                               unsigned long flags,
                               const char *dname,
                               unsigned long resource)
4087 4088 4089
{
    virDomainPtr ddomain = NULL;
    char *uri_out = NULL;
4090
    char *cookie = NULL;
4091 4092 4093
    char *dom_xml = NULL;
    int cookielen = 0, ret;
    virErrorPtr orig_err = NULL;
4094
    bool cancelled;
4095
    virStreamPtr st = NULL;
4096
    unsigned long destflags;
4097

4098
    VIR_DEBUG("driver=%p, sconn=%p, dconn=%p, vm=%p, dconnuri=%s, "
4099
              "flags=%lx, dname=%s, resource=%lu",
4100 4101
              driver, sconn, dconn, vm, NULLSTR(dconnuri),
              flags, NULLSTR(dname), resource);
4102

4103 4104 4105 4106 4107
    /* In version 2 of the protocol, the prepare step is slightly
     * different.  We fetch the domain XML of the source domain
     * and pass it to Prepare2.
     */
    if (!(dom_xml = qemuDomainFormatXML(driver, vm,
4108 4109
                                        QEMU_DOMAIN_FORMAT_LIVE_FLAGS |
                                        VIR_DOMAIN_XML_MIGRATABLE)))
4110 4111 4112 4113 4114
        return -1;

    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED)
        flags |= VIR_MIGRATE_PAUSED;

4115 4116
    destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
                          VIR_MIGRATE_AUTO_CONVERGE);
4117

4118 4119 4120 4121 4122 4123 4124 4125 4126 4127
    VIR_DEBUG("Prepare2 %p", dconn);
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /*
         * Tunnelled Migrate Version 2 does not support cookies
         * due to missing parameters in the prepareTunnel() API.
         */

        if (!(st = virStreamNew(dconn, 0)))
            goto cleanup;

4128
        qemuDomainObjEnterRemote(vm);
4129
        ret = dconn->driver->domainMigratePrepareTunnel
4130
            (dconn, st, destflags, dname, resource, dom_xml);
4131
        qemuDomainObjExitRemote(vm);
4132
    } else {
4133
        qemuDomainObjEnterRemote(vm);
4134 4135
        ret = dconn->driver->domainMigratePrepare2
            (dconn, &cookie, &cookielen, NULL, &uri_out,
4136
             destflags, dname, resource, dom_xml);
4137
        qemuDomainObjExitRemote(vm);
4138 4139 4140
    }
    VIR_FREE(dom_xml);
    if (ret == -1)
4141 4142 4143
        goto cleanup;

    /* the domain may have shutdown or crashed while we had the locks dropped
4144
     * in qemuDomainObjEnterRemote, so check again
4145 4146
     */
    if (!virDomainObjIsActive(vm)) {
4147 4148
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
4149 4150 4151
        goto cleanup;
    }

4152 4153
    if (!(flags & VIR_MIGRATE_TUNNELLED) &&
        (uri_out == NULL)) {
4154 4155
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domainMigratePrepare2 did not set uri"));
4156
        cancelled = true;
4157
        orig_err = virSaveLastError();
4158
        goto finish;
4159 4160
    }

4161 4162 4163 4164
    /* Perform the migration.  The driver isn't supposed to return
     * until the migration is complete.
     */
    VIR_DEBUG("Perform %p", sconn);
4165
    qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM2);
4166
    if (flags & VIR_MIGRATE_TUNNELLED)
4167 4168
        ret = doTunnelMigrate(driver, vm, st,
                              NULL, 0, NULL, NULL,
4169
                              flags, resource, dconn, NULL);
4170 4171 4172 4173
    else
        ret = doNativeMigrate(driver, vm, uri_out,
                              cookie, cookielen,
                              NULL, NULL, /* No out cookie with v2 migration */
4174
                              flags, resource, dconn, NULL);
4175 4176 4177 4178

    /* Perform failed. Make sure Finish doesn't overwrite the error */
    if (ret < 0)
        orig_err = virSaveLastError();
4179

4180 4181 4182
    /* If Perform returns < 0, then we need to cancel the VM
     * startup on the destination
     */
4183
    cancelled = ret < 0;
4184

4185
 finish:
4186 4187 4188 4189
    /* In version 2 of the migration protocol, we pass the
     * status code from the sender to the destination host,
     * so it can do any cleanup if the migration failed.
     */
4190
    dname = dname ? dname : vm->def->name;
4191
    VIR_DEBUG("Finish2 %p ret=%d", dconn, ret);
4192
    qemuDomainObjEnterRemote(vm);
4193
    ddomain = dconn->driver->domainMigrateFinish2
4194
        (dconn, dname, cookie, cookielen,
4195
         uri_out ? uri_out : dconnuri, destflags, cancelled);
4196
    qemuDomainObjExitRemote(vm);
4197 4198
    if (cancelled && ddomain)
        VIR_ERROR(_("finish step ignored that migration was cancelled"));
4199

4200
 cleanup:
4201
    if (ddomain) {
4202
        virObjectUnref(ddomain);
4203 4204 4205 4206
        ret = 0;
    } else {
        ret = -1;
    }
4207

4208
    virObjectUnref(st);
4209 4210 4211 4212 4213 4214

    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
    VIR_FREE(uri_out);
4215
    VIR_FREE(cookie);
4216 4217

    return ret;
4218 4219 4220
}


4221 4222 4223 4224
/* This is essentially a re-impl of virDomainMigrateVersion3
 * from libvirt.c, but running in source libvirtd context,
 * instead of client app context & also adding in tunnel
 * handling */
4225 4226 4227 4228 4229 4230 4231 4232 4233
static int
doPeer2PeerMigrate3(virQEMUDriverPtr driver,
                    virConnectPtr sconn,
                    virConnectPtr dconn,
                    const char *dconnuri,
                    virDomainObjPtr vm,
                    const char *xmlin,
                    const char *dname,
                    const char *uri,
4234
                    const char *graphicsuri,
4235
                    const char *listenAddress,
4236 4237 4238
                    unsigned long long bandwidth,
                    bool useParams,
                    unsigned long flags)
4239 4240 4241 4242 4243 4244 4245 4246 4247 4248
{
    virDomainPtr ddomain = NULL;
    char *uri_out = NULL;
    char *cookiein = NULL;
    char *cookieout = NULL;
    char *dom_xml = NULL;
    int cookieinlen = 0;
    int cookieoutlen = 0;
    int ret = -1;
    virErrorPtr orig_err = NULL;
4249
    bool cancelled = true;
4250
    virStreamPtr st = NULL;
4251
    unsigned long destflags;
4252 4253 4254 4255 4256
    virTypedParameterPtr params = NULL;
    int nparams = 0;
    int maxparams = 0;

    VIR_DEBUG("driver=%p, sconn=%p, dconn=%p, dconnuri=%s, vm=%p, xmlin=%s, "
4257 4258
              "dname=%s, uri=%s, graphicsuri=%s, listenAddress=%s, "
              "bandwidth=%llu, useParams=%d, flags=%lx",
4259
              driver, sconn, dconn, NULLSTR(dconnuri), vm, NULLSTR(xmlin),
4260 4261
              NULLSTR(dname), NULLSTR(uri), NULLSTR(graphicsuri),
              NULLSTR(listenAddress), bandwidth, useParams, flags);
4262

4263 4264 4265 4266 4267
    /* Unlike the virDomainMigrateVersion3 counterpart, we don't need
     * to worry about auto-setting the VIR_MIGRATE_CHANGE_PROTECTION
     * bit here, because we are already running inside the context of
     * a single job.  */

4268 4269
    dom_xml = qemuMigrationBeginPhase(driver, vm, xmlin, dname,
                                      &cookieout, &cookieoutlen, flags);
4270 4271 4272
    if (!dom_xml)
        goto cleanup;

4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292
    if (useParams) {
        if (virTypedParamsAddString(&params, &nparams, &maxparams,
                                    VIR_MIGRATE_PARAM_DEST_XML, dom_xml) < 0)
            goto cleanup;

        if (dname &&
            virTypedParamsAddString(&params, &nparams, &maxparams,
                                    VIR_MIGRATE_PARAM_DEST_NAME, dname) < 0)
            goto cleanup;

        if (uri &&
            virTypedParamsAddString(&params, &nparams, &maxparams,
                                    VIR_MIGRATE_PARAM_URI, uri) < 0)
            goto cleanup;

        if (bandwidth &&
            virTypedParamsAddULLong(&params, &nparams, &maxparams,
                                    VIR_MIGRATE_PARAM_BANDWIDTH,
                                    bandwidth) < 0)
            goto cleanup;
4293 4294 4295 4296 4297 4298

        if (graphicsuri &&
            virTypedParamsAddString(&params, &nparams, &maxparams,
                                    VIR_MIGRATE_PARAM_GRAPHICS_URI,
                                    graphicsuri) < 0)
            goto cleanup;
4299 4300 4301 4302 4303
        if (listenAddress &&
            virTypedParamsAddString(&params, &nparams, &maxparams,
                                    VIR_MIGRATE_PARAM_LISTEN_ADDRESS,
                                    listenAddress) < 0)
            goto cleanup;
4304 4305
    }

4306 4307 4308
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED)
        flags |= VIR_MIGRATE_PAUSED;

4309 4310
    destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
                          VIR_MIGRATE_AUTO_CONVERGE);
4311

4312 4313 4314 4315 4316 4317 4318 4319 4320
    VIR_DEBUG("Prepare3 %p", dconn);
    cookiein = cookieout;
    cookieinlen = cookieoutlen;
    cookieout = NULL;
    cookieoutlen = 0;
    if (flags & VIR_MIGRATE_TUNNELLED) {
        if (!(st = virStreamNew(dconn, 0)))
            goto cleanup;

4321
        qemuDomainObjEnterRemote(vm);
4322 4323 4324 4325 4326 4327 4328 4329 4330
        if (useParams) {
            ret = dconn->driver->domainMigratePrepareTunnel3Params
                (dconn, st, params, nparams, cookiein, cookieinlen,
                 &cookieout, &cookieoutlen, destflags);
        } else {
            ret = dconn->driver->domainMigratePrepareTunnel3
                (dconn, st, cookiein, cookieinlen, &cookieout, &cookieoutlen,
                 destflags, dname, bandwidth, dom_xml);
        }
4331
        qemuDomainObjExitRemote(vm);
4332
    } else {
4333
        qemuDomainObjEnterRemote(vm);
4334 4335 4336 4337 4338 4339 4340 4341 4342
        if (useParams) {
            ret = dconn->driver->domainMigratePrepare3Params
                (dconn, params, nparams, cookiein, cookieinlen,
                 &cookieout, &cookieoutlen, &uri_out, destflags);
        } else {
            ret = dconn->driver->domainMigratePrepare3
                (dconn, cookiein, cookieinlen, &cookieout, &cookieoutlen,
                 uri, &uri_out, destflags, dname, bandwidth, dom_xml);
        }
4343
        qemuDomainObjExitRemote(vm);
4344 4345 4346 4347 4348
    }
    VIR_FREE(dom_xml);
    if (ret == -1)
        goto cleanup;

L
liguang 已提交
4349 4350 4351 4352
    if (flags & VIR_MIGRATE_OFFLINE) {
        VIR_DEBUG("Offline migration, skipping Perform phase");
        VIR_FREE(cookieout);
        cookieoutlen = 0;
4353
        cancelled = false;
L
liguang 已提交
4354 4355 4356
        goto finish;
    }

4357 4358 4359 4360
    if (uri_out) {
        uri = uri_out;
        if (useParams &&
            virTypedParamsReplaceString(&params, &nparams,
4361 4362
                                        VIR_MIGRATE_PARAM_URI, uri_out) < 0) {
            orig_err = virSaveLastError();
4363
            goto finish;
4364
        }
4365
    } else if (!uri && !(flags & VIR_MIGRATE_TUNNELLED)) {
4366 4367
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domainMigratePrepare3 did not set uri"));
4368
        orig_err = virSaveLastError();
4369 4370 4371 4372 4373 4374 4375 4376
        goto finish;
    }

    /* Perform the migration.  The driver isn't supposed to return
     * until the migration is complete. The src VM should remain
     * running, but in paused state until the destination can
     * confirm migration completion.
     */
4377
    VIR_DEBUG("Perform3 %p uri=%s", sconn, NULLSTR(uri));
4378
    qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3);
4379 4380 4381 4382 4383
    VIR_FREE(cookiein);
    cookiein = cookieout;
    cookieinlen = cookieoutlen;
    cookieout = NULL;
    cookieoutlen = 0;
4384
    if (flags & VIR_MIGRATE_TUNNELLED) {
4385 4386 4387
        ret = doTunnelMigrate(driver, vm, st,
                              cookiein, cookieinlen,
                              &cookieout, &cookieoutlen,
4388
                              flags, bandwidth, dconn, graphicsuri);
4389 4390
    } else {
        ret = doNativeMigrate(driver, vm, uri,
4391 4392
                              cookiein, cookieinlen,
                              &cookieout, &cookieoutlen,
4393
                              flags, bandwidth, dconn, graphicsuri);
4394
    }
4395 4396

    /* Perform failed. Make sure Finish doesn't overwrite the error */
4397
    if (ret < 0) {
4398
        orig_err = virSaveLastError();
4399 4400 4401 4402
    } else {
        qemuMigrationJobSetPhase(driver, vm,
                                 QEMU_MIGRATION_PHASE_PERFORM3_DONE);
    }
4403 4404 4405 4406

    /* If Perform returns < 0, then we need to cancel the VM
     * startup on the destination
     */
4407
    cancelled = ret < 0;
4408

4409
 finish:
4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421
    /*
     * The status code from the source is passed to the destination.
     * The dest can cleanup in the source indicated it failed to
     * send all migration data. Returns NULL for ddomain if
     * the dest was unable to complete migration.
     */
    VIR_DEBUG("Finish3 %p ret=%d", dconn, ret);
    VIR_FREE(cookiein);
    cookiein = cookieout;
    cookieinlen = cookieoutlen;
    cookieout = NULL;
    cookieoutlen = 0;
4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444

    if (useParams) {
        if (virTypedParamsGetString(params, nparams,
                                    VIR_MIGRATE_PARAM_DEST_NAME, NULL) <= 0 &&
            virTypedParamsReplaceString(&params, &nparams,
                                        VIR_MIGRATE_PARAM_DEST_NAME,
                                        vm->def->name) < 0) {
            ddomain = NULL;
        } else {
            qemuDomainObjEnterRemote(vm);
            ddomain = dconn->driver->domainMigrateFinish3Params
                (dconn, params, nparams, cookiein, cookieinlen,
                 &cookieout, &cookieoutlen, destflags, cancelled);
            qemuDomainObjExitRemote(vm);
        }
    } else {
        dname = dname ? dname : vm->def->name;
        qemuDomainObjEnterRemote(vm);
        ddomain = dconn->driver->domainMigrateFinish3
            (dconn, dname, cookiein, cookieinlen, &cookieout, &cookieoutlen,
             dconnuri, uri, destflags, cancelled);
        qemuDomainObjExitRemote(vm);
    }
4445 4446
    if (cancelled && ddomain)
        VIR_ERROR(_("finish step ignored that migration was cancelled"));
4447

4448 4449 4450 4451 4452 4453 4454
    /* If ddomain is NULL, then we were unable to start
     * the guest on the target, and must restart on the
     * source. There is a small chance that the ddomain
     * is NULL due to an RPC failure, in which case
     * ddomain could in fact be running on the dest.
     * The lock manager plugins should take care of
     * safety in this scenario.
4455
     */
4456
    cancelled = ddomain == NULL;
4457

4458 4459 4460 4461 4462 4463
    /* If finish3 set an error, and we don't have an earlier
     * one we need to preserve it in case confirm3 overwrites
     */
    if (!orig_err)
        orig_err = virSaveLastError();

4464 4465 4466 4467
    /*
     * If cancelled, then src VM will be restarted, else
     * it will be killed
     */
4468
    VIR_DEBUG("Confirm3 %p cancelled=%d vm=%p", sconn, cancelled, vm);
4469 4470 4471 4472 4473
    VIR_FREE(cookiein);
    cookiein = cookieout;
    cookieinlen = cookieoutlen;
    cookieout = NULL;
    cookieoutlen = 0;
4474 4475 4476
    ret = qemuMigrationConfirmPhase(driver, sconn, vm,
                                    cookiein, cookieinlen,
                                    flags, cancelled);
4477 4478 4479 4480
    /* If Confirm3 returns -1, there's nothing more we can
     * do, but fortunately worst case is that there is a
     * domain left in 'paused' state on source.
     */
4481 4482 4483
    if (ret < 0)
        VIR_WARN("Guest %s probably left in 'paused' state on source",
                 vm->def->name);
4484 4485 4486

 cleanup:
    if (ddomain) {
4487
        virObjectUnref(ddomain);
4488 4489 4490 4491 4492
        ret = 0;
    } else {
        ret = -1;
    }

4493
    virObjectUnref(st);
4494 4495 4496 4497 4498 4499 4500 4501

    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
    VIR_FREE(uri_out);
    VIR_FREE(cookiein);
    VIR_FREE(cookieout);
4502
    virTypedParamsFree(params, nparams);
4503 4504 4505 4506
    return ret;
}


4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518
static int virConnectCredType[] = {
    VIR_CRED_AUTHNAME,
    VIR_CRED_PASSPHRASE,
};


static virConnectAuth virConnectAuthConfig = {
    .credtype = virConnectCredType,
    .ncredtype = ARRAY_CARDINALITY(virConnectCredType),
};


4519
static int doPeer2PeerMigrate(virQEMUDriverPtr driver,
4520
                              virConnectPtr sconn,
4521
                              virDomainObjPtr vm,
4522
                              const char *xmlin,
4523
                              const char *dconnuri,
4524
                              const char *uri,
4525
                              const char *graphicsuri,
4526
                              const char *listenAddress,
4527 4528
                              unsigned long flags,
                              const char *dname,
4529 4530
                              unsigned long resource,
                              bool *v3proto)
4531 4532 4533 4534
{
    int ret = -1;
    virConnectPtr dconn = NULL;
    bool p2p;
4535
    virErrorPtr orig_err = NULL;
4536
    bool offline = false;
4537
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
4538
    bool useParams;
4539

4540
    VIR_DEBUG("driver=%p, sconn=%p, vm=%p, xmlin=%s, dconnuri=%s, "
4541 4542
              "uri=%s, graphicsuri=%s, listenAddress=%s, flags=%lx, "
              "dname=%s, resource=%lu",
4543
              driver, sconn, vm, NULLSTR(xmlin), NULLSTR(dconnuri),
4544 4545
              NULLSTR(uri), NULLSTR(graphicsuri), NULLSTR(listenAddress),
              flags, NULLSTR(dname), resource);
4546 4547 4548 4549 4550

    /* the order of operations is important here; we make sure the
     * destination side is completely setup before we touch the source
     */

4551
    qemuDomainObjEnterRemote(vm);
4552
    dconn = virConnectOpenAuth(dconnuri, &virConnectAuthConfig, 0);
4553
    qemuDomainObjExitRemote(vm);
4554
    if (dconn == NULL) {
4555
        virReportError(VIR_ERR_OPERATION_FAILED,
4556 4557
                       _("Failed to connect to remote libvirt URI %s: %s"),
                       dconnuri, virGetLastErrorMessage());
4558
        virObjectUnref(cfg);
4559 4560 4561
        return -1;
    }

4562 4563
    if (virConnectSetKeepAlive(dconn, cfg->keepAliveInterval,
                               cfg->keepAliveCount) < 0)
4564 4565
        goto cleanup;

4566
    qemuDomainObjEnterRemote(vm);
4567 4568
    p2p = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
                                   VIR_DRV_FEATURE_MIGRATION_P2P);
4569
        /* v3proto reflects whether the caller used Perform3, but with
4570
         * p2p migrate, regardless of whether Perform2 or Perform3
4571 4572 4573 4574
         * were used, we decide protocol based on what target supports
         */
    *v3proto = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
                                        VIR_DRV_FEATURE_MIGRATION_V3);
4575 4576
    useParams = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
                                         VIR_DRV_FEATURE_MIGRATION_PARAMS);
L
liguang 已提交
4577 4578 4579
    if (flags & VIR_MIGRATE_OFFLINE)
        offline = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
                                           VIR_DRV_FEATURE_MIGRATION_OFFLINE);
4580
    qemuDomainObjExitRemote(vm);
4581

4582
    if (!p2p) {
4583 4584
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Destination libvirt does not support peer-to-peer migration protocol"));
4585 4586 4587
        goto cleanup;
    }

4588 4589
    /* Only xmlin, dname, uri, and bandwidth parameters can be used with
     * old-style APIs. */
4590
    if (!useParams && graphicsuri) {
4591 4592 4593 4594 4595 4596
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Migration APIs with extensible parameters are not "
                         "supported but extended parameters were passed"));
        goto cleanup;
    }

L
liguang 已提交
4597 4598 4599 4600 4601 4602 4603
    if (flags & VIR_MIGRATE_OFFLINE && !offline) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("offline migration is not supported by "
                         "the destination host"));
        goto cleanup;
    }

4604
    /* domain may have been stopped while we were talking to remote daemon */
L
liguang 已提交
4605
    if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
4606 4607
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
4608 4609 4610
        goto cleanup;
    }

4611 4612 4613 4614 4615 4616 4617
    /* Change protection is only required on the source side (us), and
     * only for v3 migration when begin and perform are separate jobs.
     * But peer-2-peer is already a single job, and we still want to
     * talk to older destinations that would reject the flag.
     * Therefore it is safe to clear the bit here.  */
    flags &= ~VIR_MIGRATE_CHANGE_PROTECTION;

4618 4619
    if (*v3proto) {
        ret = doPeer2PeerMigrate3(driver, sconn, dconn, dconnuri, vm, xmlin,
4620 4621
                                  dname, uri, graphicsuri, listenAddress,
                                  resource, useParams, flags);
4622
    } else {
4623
        ret = doPeer2PeerMigrate2(driver, sconn, dconn, vm,
4624
                                  dconnuri, flags, dname, resource);
4625
    }
4626

4627
 cleanup:
4628
    orig_err = virSaveLastError();
4629
    qemuDomainObjEnterRemote(vm);
4630
    virObjectUnref(dconn);
4631
    qemuDomainObjExitRemote(vm);
4632 4633 4634 4635
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
4636
    virObjectUnref(cfg);
4637 4638 4639 4640
    return ret;
}


4641 4642 4643 4644 4645 4646
/*
 * This implements perform part of the migration protocol when migration job
 * does not need to be active across several APIs, i.e., peer2peer migration or
 * perform phase of v2 non-peer2peer migration.
 */
static int
4647
qemuMigrationPerformJob(virQEMUDriverPtr driver,
4648 4649 4650 4651 4652
                        virConnectPtr conn,
                        virDomainObjPtr vm,
                        const char *xmlin,
                        const char *dconnuri,
                        const char *uri,
4653
                        const char *graphicsuri,
4654
                        const char *listenAddress,
4655
                        const char *cookiein,
4656 4657 4658 4659 4660 4661 4662
                        int cookieinlen,
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
                        const char *dname,
                        unsigned long resource,
                        bool v3proto)
4663
{
4664
    virObjectEventPtr event = NULL;
4665
    int ret = -1;
4666
    virErrorPtr orig_err = NULL;
4667
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
4668
    bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
4669

4670
    if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
4671 4672
        goto cleanup;

L
liguang 已提交
4673
    if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
4674 4675
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
4676 4677 4678
        goto endjob;
    }

4679
    if (!qemuMigrationIsAllowed(driver, vm, NULL, true, abort_on_error))
4680
        goto endjob;
4681

4682
    if (!(flags & VIR_MIGRATE_UNSAFE) && !qemuMigrationIsSafe(vm->def))
4683
        goto endjob;
4684

4685
    qemuMigrationStoreDomainState(vm);
4686 4687

    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
4688
        ret = doPeer2PeerMigrate(driver, conn, vm, xmlin,
4689 4690
                                 dconnuri, uri, graphicsuri, listenAddress,
                                 flags, dname, resource, &v3proto);
4691
    } else {
4692 4693 4694
        qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM2);
        ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen,
                              cookieout, cookieoutlen,
4695
                              flags, resource, NULL, NULL);
4696
    }
4697 4698
    if (ret < 0)
        goto endjob;
4699

4700 4701 4702 4703
    /*
     * In v3 protocol, the source VM is not killed off until the
     * confirm step.
     */
4704
    if (!v3proto) {
4705 4706
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED,
                        VIR_QEMU_PROCESS_STOP_MIGRATED);
4707
        virDomainAuditStop(vm, "migrated");
4708
        event = virDomainEventLifecycleNewFromObj(vm,
4709 4710
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
4711 4712
    }

4713
 endjob:
4714 4715 4716
    if (ret < 0)
        orig_err = virSaveLastError();

4717
    if (qemuMigrationRestoreDomainState(conn, vm)) {
4718
        event = virDomainEventLifecycleNewFromObj(vm,
4719 4720 4721
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
    }
4722

4723
    if (!qemuMigrationJobFinish(driver, vm)) {
4724 4725 4726 4727 4728
        vm = NULL;
    } else if (!virDomainObjIsActive(vm) &&
               (!vm->persistent ||
                (ret == 0 && (flags & VIR_MIGRATE_UNDEFINE_SOURCE)))) {
        if (flags & VIR_MIGRATE_UNDEFINE_SOURCE)
4729
            virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm);
4730
        qemuDomainRemoveInactive(driver, vm);
4731 4732 4733
        vm = NULL;
    }

4734 4735 4736 4737 4738
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }

4739
 cleanup:
4740
    if (vm)
4741
        virObjectUnlock(vm);
4742 4743
    if (event)
        qemuDomainEventQueue(driver, event);
4744
    virObjectUnref(cfg);
4745 4746 4747 4748 4749 4750 4751
    return ret;
}

/*
 * This implements perform phase of v3 migration protocol.
 */
static int
4752
qemuMigrationPerformPhase(virQEMUDriverPtr driver,
4753 4754 4755
                          virConnectPtr conn,
                          virDomainObjPtr vm,
                          const char *uri,
4756
                          const char *graphicsuri,
4757 4758 4759 4760 4761 4762 4763
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
                          unsigned long flags,
                          unsigned long resource)
{
4764
    virObjectEventPtr event = NULL;
4765
    int ret = -1;
4766
    bool hasrefs;
4767 4768 4769 4770 4771 4772 4773 4774 4775 4776

    /* If we didn't start the job in the begin phase, start it now. */
    if (!(flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            goto cleanup;
    } else if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT)) {
        goto cleanup;
    }

    qemuMigrationJobStartPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3);
4777 4778
    virCloseCallbacksUnset(driver->closeCallbacks, vm,
                           qemuMigrationCleanup);
4779 4780 4781

    ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen,
                          cookieout, cookieoutlen,
4782
                          flags, resource, NULL, graphicsuri);
4783

4784 4785 4786 4787 4788
    if (ret < 0) {
        if (qemuMigrationRestoreDomainState(conn, vm)) {
            event = virDomainEventLifecycleNewFromObj(vm,
                                                      VIR_DOMAIN_EVENT_RESUMED,
                                                      VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
4789
        }
4790
        goto endjob;
4791
    }
4792 4793 4794

    qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3_DONE);

4795 4796
    if (virCloseCallbacksSet(driver->closeCallbacks, vm, conn,
                             qemuMigrationCleanup) < 0)
4797 4798
        goto endjob;

4799
 endjob:
4800
    if (ret < 0)
4801
        hasrefs = qemuMigrationJobFinish(driver, vm);
4802
    else
4803 4804
        hasrefs = qemuMigrationJobContinue(vm);
    if (!hasrefs) {
4805 4806
        vm = NULL;
    } else if (!virDomainObjIsActive(vm) && !vm->persistent) {
4807
        qemuDomainRemoveInactive(driver, vm);
4808
        vm = NULL;
4809
    }
4810

4811
 cleanup:
4812
    if (vm)
4813
        virObjectUnlock(vm);
4814 4815 4816 4817 4818
    if (event)
        qemuDomainEventQueue(driver, event);
    return ret;
}

4819
int
4820
qemuMigrationPerform(virQEMUDriverPtr driver,
4821 4822 4823 4824 4825
                     virConnectPtr conn,
                     virDomainObjPtr vm,
                     const char *xmlin,
                     const char *dconnuri,
                     const char *uri,
4826
                     const char *graphicsuri,
4827
                     const char *listenAddress,
4828 4829 4830 4831 4832 4833 4834 4835 4836 4837
                     const char *cookiein,
                     int cookieinlen,
                     char **cookieout,
                     int *cookieoutlen,
                     unsigned long flags,
                     const char *dname,
                     unsigned long resource,
                     bool v3proto)
{
    VIR_DEBUG("driver=%p, conn=%p, vm=%p, xmlin=%s, dconnuri=%s, "
4838
              "uri=%s, graphicsuri=%s, listenAddress=%s"
4839 4840
              "cookiein=%s, cookieinlen=%d, cookieout=%p, cookieoutlen=%p, "
              "flags=%lx, dname=%s, resource=%lu, v3proto=%d",
4841
              driver, conn, vm, NULLSTR(xmlin), NULLSTR(dconnuri),
4842
              NULLSTR(uri), NULLSTR(graphicsuri), NULLSTR(listenAddress),
4843 4844
              NULLSTR(cookiein), cookieinlen, cookieout, cookieoutlen,
              flags, NULLSTR(dname), resource, v3proto);
4845 4846 4847

    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
        if (cookieinlen) {
4848 4849
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("received unexpected cookie with P2P migration"));
4850 4851 4852 4853
            return -1;
        }

        return qemuMigrationPerformJob(driver, conn, vm, xmlin, dconnuri, uri,
4854 4855
                                       graphicsuri, listenAddress,
                                       cookiein, cookieinlen,
4856 4857
                                       cookieout, cookieoutlen,
                                       flags, dname, resource, v3proto);
4858 4859
    } else {
        if (dconnuri) {
4860 4861
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Unexpected dconnuri parameter with non-peer2peer migration"));
4862 4863 4864 4865 4866
            return -1;
        }

        if (v3proto) {
            return qemuMigrationPerformPhase(driver, conn, vm, uri,
4867
                                             graphicsuri,
4868 4869
                                             cookiein, cookieinlen,
                                             cookieout, cookieoutlen,
4870
                                             flags, resource);
4871 4872
        } else {
            return qemuMigrationPerformJob(driver, conn, vm, xmlin, dconnuri,
4873
                                           uri, graphicsuri, listenAddress,
4874
                                           cookiein, cookieinlen,
4875 4876 4877 4878 4879
                                           cookieout, cookieoutlen, flags,
                                           dname, resource, v3proto);
        }
    }
}
4880

4881
static int
4882 4883
qemuMigrationVPAssociatePortProfiles(virDomainDefPtr def)
{
4884
    size_t i;
4885 4886 4887 4888 4889
    int last_good_net = -1;
    virDomainNetDefPtr net;

    for (i = 0; i < def->nnets; i++) {
        net = def->nets[i];
4890
        if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
4891
            if (virNetDevVPortProfileAssociate(net->ifname,
4892
                                               virDomainNetGetActualVirtPortProfile(net),
4893
                                               &net->mac,
4894
                                               virDomainNetGetActualDirectDev(net),
4895
                                               -1,
4896
                                               def->uuid,
4897 4898
                                               VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_FINISH,
                                               false) < 0) {
4899 4900 4901
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("Port profile Associate failed for %s"),
                               net->ifname);
4902
                goto err_exit;
4903 4904
            }
            VIR_DEBUG("Port profile Associate succeeded for %s", net->ifname);
4905

4906
            if (virNetDevMacVLanVPortProfileRegisterCallback(net->ifname, &net->mac,
4907 4908 4909 4910
                                                             virDomainNetGetActualDirectDev(net), def->uuid,
                                                             virDomainNetGetActualVirtPortProfile(net),
                                                             VIR_NETDEV_VPORT_PROFILE_OP_CREATE))
                goto err_exit;
4911 4912 4913 4914
        }
        last_good_net = i;
    }

4915
    return 0;
4916

4917
 err_exit:
4918
    for (i = 0; last_good_net != -1 && i < last_good_net; i++) {
4919
        net = def->nets[i];
4920
        if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
4921
            ignore_value(virNetDevVPortProfileDisassociate(net->ifname,
4922
                                                           virDomainNetGetActualVirtPortProfile(net),
4923
                                                           &net->mac,
4924
                                                           virDomainNetGetActualDirectDev(net),
4925
                                                           -1,
4926
                                                           VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_FINISH));
4927 4928
        }
    }
4929
    return -1;
4930 4931 4932 4933
}


virDomainPtr
4934
qemuMigrationFinish(virQEMUDriverPtr driver,
4935 4936
                    virConnectPtr dconn,
                    virDomainObjPtr vm,
4937 4938 4939 4940
                    const char *cookiein,
                    int cookieinlen,
                    char **cookieout,
                    int *cookieoutlen,
4941
                    unsigned long flags,
4942 4943
                    int retcode,
                    bool v3proto)
4944 4945
{
    virDomainPtr dom = NULL;
4946
    virObjectEventPtr event = NULL;
4947
    bool newVM = true;
4948
    qemuMigrationCookiePtr mig = NULL;
4949
    virErrorPtr orig_err = NULL;
4950
    int cookie_flags = 0;
J
Jiri Denemark 已提交
4951
    qemuDomainObjPrivatePtr priv = vm->privateData;
4952
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
4953
    virCapsPtr caps = NULL;
4954
    unsigned short port;
4955

4956
    VIR_DEBUG("driver=%p, dconn=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
4957
              "cookieout=%p, cookieoutlen=%p, flags=%lx, retcode=%d",
4958 4959
              driver, dconn, vm, NULLSTR(cookiein), cookieinlen,
              cookieout, cookieoutlen, flags, retcode);
4960

4961 4962 4963
    port = priv->migrationPort;
    priv->migrationPort = 0;

4964 4965 4966
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4967
    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN))
4968 4969
        goto cleanup;

4970 4971 4972
    qemuMigrationJobStartPhase(driver, vm,
                               v3proto ? QEMU_MIGRATION_PHASE_FINISH3
                                       : QEMU_MIGRATION_PHASE_FINISH2);
4973

4974
    qemuDomainCleanupRemove(vm, qemuMigrationPrepareCleanup);
4975
    VIR_FREE(priv->job.completed);
4976

4977
    cookie_flags = QEMU_MIGRATION_COOKIE_NETWORK |
4978 4979
                   QEMU_MIGRATION_COOKIE_STATS |
                   QEMU_MIGRATION_COOKIE_NBD;
4980 4981 4982 4983 4984
    if (flags & VIR_MIGRATE_PERSIST_DEST)
        cookie_flags |= QEMU_MIGRATION_COOKIE_PERSISTENT;

    if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein,
                                       cookieinlen, cookie_flags)))
4985
        goto endjob;
4986 4987 4988 4989 4990

    /* Did the migration go as planned?  If yes, return the domain
     * object, but if no, clean up the empty qemu process.
     */
    if (retcode == 0) {
L
liguang 已提交
4991
        if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
4992 4993
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
4994
            goto endjob;
4995 4996
        }

4997 4998 4999 5000 5001
        if (mig->jobInfo) {
            priv->job.completed = mig->jobInfo;
            mig->jobInfo = NULL;
        }

L
liguang 已提交
5002 5003 5004 5005 5006
        if (!(flags & VIR_MIGRATE_OFFLINE)) {
            if (qemuMigrationVPAssociatePortProfiles(vm->def) < 0) {
                qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED,
                                VIR_QEMU_PROCESS_STOP_MIGRATED);
                virDomainAuditStop(vm, "failed");
5007
                event = virDomainEventLifecycleNewFromObj(vm,
L
liguang 已提交
5008 5009 5010 5011 5012 5013 5014
                                                 VIR_DOMAIN_EVENT_STOPPED,
                                                 VIR_DOMAIN_EVENT_STOPPED_FAILED);
                goto endjob;
            }
            if (mig->network)
                if (qemuDomainMigrateOPDRelocate(driver, vm, mig) < 0)
                    VIR_WARN("unable to provide network data for relocation");
5015
        }
5016

5017 5018
        qemuMigrationStopNBDServer(driver, vm, mig);

5019
        if (flags & VIR_MIGRATE_PERSIST_DEST) {
5020
            virDomainDefPtr vmdef;
5021
            if (vm->persistent)
5022
                newVM = false;
5023
            vm->persistent = 1;
5024 5025 5026
            if (mig->persistent)
                vm->newDef = vmdef = mig->persistent;
            else
5027
                vmdef = virDomainObjGetPersistentDef(caps, driver->xmlopt, vm);
5028
            if (!vmdef || virDomainSaveConfig(cfg->configDir, vmdef) < 0) {
5029 5030 5031 5032 5033 5034 5035 5036 5037
                /* Hmpf.  Migration was successful, but making it persistent
                 * was not.  If we report successful, then when this domain
                 * shuts down, management tools are in for a surprise.  On the
                 * other hand, if we report failure, then the management tools
                 * might try to restart the domain on the source side, even
                 * though the domain is actually running on the destination.
                 * Return a NULL dom pointer, and hope that this is a rare
                 * situation and management tools are smart.
                 */
5038 5039

                /*
5040 5041
                 * However, in v3 protocol, the source VM is still available
                 * to restart during confirm() step, so we kill it off now.
5042 5043
                 */
                if (v3proto) {
L
liguang 已提交
5044 5045 5046 5047 5048
                    if (!(flags & VIR_MIGRATE_OFFLINE)) {
                        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED,
                                        VIR_QEMU_PROCESS_STOP_MIGRATED);
                        virDomainAuditStop(vm, "failed");
                    }
5049 5050
                    if (newVM)
                        vm->persistent = 0;
5051
                }
A
Alex Jia 已提交
5052
                if (!vmdef)
5053 5054
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("can't get vmdef"));
5055 5056 5057
                goto endjob;
            }

5058
            event = virDomainEventLifecycleNewFromObj(vm,
5059 5060 5061 5062 5063 5064 5065 5066 5067
                                             VIR_DOMAIN_EVENT_DEFINED,
                                             newVM ?
                                             VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                             VIR_DOMAIN_EVENT_DEFINED_UPDATED);
            if (event)
                qemuDomainEventQueue(driver, event);
            event = NULL;
        }

L
liguang 已提交
5068
        if (!(flags & VIR_MIGRATE_PAUSED) && !(flags & VIR_MIGRATE_OFFLINE)) {
5069 5070 5071 5072
            /* run 'cont' on the destination, which allows migration on qemu
             * >= 0.10.6 to work properly.  This isn't strictly necessary on
             * older qemu's, but it also doesn't hurt anything there
             */
J
Jiri Denemark 已提交
5073
            if (qemuProcessStartCPUs(driver, vm, dconn,
5074 5075
                                     VIR_DOMAIN_RUNNING_MIGRATED,
                                     QEMU_ASYNC_JOB_MIGRATION_IN) < 0) {
5076
                if (virGetLastError() == NULL)
5077 5078
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("resume operation failed"));
5079 5080 5081 5082 5083
                /* Need to save the current error, in case shutting
                 * down the process overwrites it
                 */
                orig_err = virSaveLastError();

5084 5085 5086 5087 5088 5089 5090 5091 5092
                /*
                 * In v3 protocol, the source VM is still available to
                 * restart during confirm() step, so we kill it off
                 * now.
                 * In v2 protocol, the source is dead, so we leave
                 * target in paused state, in case admin can fix
                 * things up
                 */
                if (v3proto) {
5093 5094
                    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED,
                                    VIR_QEMU_PROCESS_STOP_MIGRATED);
5095
                    virDomainAuditStop(vm, "failed");
5096
                    event = virDomainEventLifecycleNewFromObj(vm,
5097 5098 5099
                                                     VIR_DOMAIN_EVENT_STOPPED,
                                                     VIR_DOMAIN_EVENT_STOPPED_FAILED);
                }
5100 5101
                goto endjob;
            }
5102 5103 5104 5105
            if (priv->job.completed) {
                qemuDomainJobInfoUpdateTime(priv->job.completed);
                qemuDomainJobInfoUpdateDowntime(priv->job.completed);
            }
5106 5107
        }

5108
        dom = virGetDomain(dconn, vm->def->name, vm->def->uuid);
5109

L
liguang 已提交
5110
        if (!(flags & VIR_MIGRATE_OFFLINE)) {
5111
            event = virDomainEventLifecycleNewFromObj(vm,
L
liguang 已提交
5112 5113 5114 5115 5116 5117 5118
                                             VIR_DOMAIN_EVENT_RESUMED,
                                             VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
            if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
                virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                                     VIR_DOMAIN_PAUSED_USER);
                if (event)
                    qemuDomainEventQueue(driver, event);
5119
                event = virDomainEventLifecycleNewFromObj(vm,
L
liguang 已提交
5120 5121 5122
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
            }
5123
        }
L
liguang 已提交
5124 5125

        if (virDomainObjIsActive(vm) &&
5126
            virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
5127 5128 5129
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
            goto endjob;
        }
5130 5131 5132

        /* Guest is successfully running, so cancel previous auto destroy */
        qemuProcessAutoDestroyRemove(driver, vm);
L
liguang 已提交
5133
    } else if (!(flags & VIR_MIGRATE_OFFLINE)) {
5134 5135
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED,
                        VIR_QEMU_PROCESS_STOP_MIGRATED);
5136
        virDomainAuditStop(vm, "failed");
5137
        event = virDomainEventLifecycleNewFromObj(vm,
5138 5139 5140 5141
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
    }

5142 5143
    if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen,
                                QEMU_MIGRATION_COOKIE_STATS) < 0)
5144 5145
        VIR_WARN("Unable to encode migration cookie");

5146
 endjob:
E
Eric Blake 已提交
5147 5148 5149
    if (qemuMigrationJobFinish(driver, vm) == 0) {
        vm = NULL;
    } else if (!vm->persistent && !virDomainObjIsActive(vm)) {
5150
        qemuDomainRemoveInactive(driver, vm);
E
Eric Blake 已提交
5151
        vm = NULL;
5152
    }
5153

5154
 cleanup:
5155
    virPortAllocatorRelease(driver->migrationPorts, port);
J
Jiri Denemark 已提交
5156
    if (vm) {
5157 5158
        if (priv->mon)
            qemuMonitorSetDomainLog(priv->mon, -1);
J
Jiri Denemark 已提交
5159
        VIR_FREE(priv->origname);
5160
        virObjectUnlock(vm);
J
Jiri Denemark 已提交
5161
    }
5162 5163
    if (event)
        qemuDomainEventQueue(driver, event);
5164
    qemuMigrationCookieFree(mig);
5165 5166 5167 5168
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
5169
    virObjectUnref(caps);
5170
    virObjectUnref(cfg);
5171 5172
    return dom;
}
5173

5174

5175
/* Helper function called while vm is active.  */
5176
int
5177
qemuMigrationToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
5178 5179
                    int fd, off_t offset, const char *path,
                    const char *compressor,
E
Eric Blake 已提交
5180
                    bool bypassSecurityDriver,
5181
                    qemuDomainAsyncJob asyncJob)
5182 5183 5184
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int rc;
5185
    int ret = -1;
5186
    bool restoreLabel = false;
5187 5188
    virCommandPtr cmd = NULL;
    int pipeFD[2] = { -1, -1 };
5189
    unsigned long saveMigBandwidth = priv->migMaxBandwidth;
5190
    char *errbuf = NULL;
5191
    virErrorPtr orig_err = NULL;
5192 5193 5194 5195 5196

    /* Increase migration bandwidth to unlimited since target is a file.
     * Failure to change migration speed is not fatal. */
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
        qemuMonitorSetMigrationSpeed(priv->mon,
5197 5198
                                     QEMU_DOMAIN_MIG_BANDWIDTH_MAX);
        priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX;
5199
        qemuDomainObjExitMonitor(driver, vm);
5200
    }
5201

5202 5203 5204 5205 5206 5207 5208
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
        /* nothing to tear down */
        return -1;
    }

5209
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD) &&
5210
        (!compressor || pipe(pipeFD) == 0)) {
5211
        /* All right! We can use fd migration, which means that qemu
5212 5213 5214
         * doesn't have to open() the file, so while we still have to
         * grant SELinux access, we can do it on fd and avoid cleanup
         * later, as well as skip futzing with cgroup.  */
5215
        if (virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def,
5216
                                              compressor ? pipeFD[1] : fd) < 0)
5217
            goto cleanup;
5218 5219 5220
        bypassSecurityDriver = true;
    } else {
        /* Phooey - we have to fall back on exec migration, where qemu
E
Eric Blake 已提交
5221 5222
         * has to popen() the file by name, and block devices have to be
         * given cgroup ACL permission.  We might also stumble on
5223 5224
         * a race present in some qemu versions where it does a wait()
         * that botches pclose.  */
5225 5226
        if (virCgroupHasController(priv->cgroup,
                                   VIR_CGROUP_CONTROLLER_DEVICES)) {
5227 5228 5229 5230
            int rv = virCgroupAllowDevicePath(priv->cgroup, path,
                                              VIR_CGROUP_DEVICE_RW);
            virDomainAuditCgroupPath(vm, priv->cgroup, "allow", path, "rw", rv == 0);
            if (rv == 1) {
E
Eric Blake 已提交
5231
                /* path was not a device, no further need for cgroup */
5232
            } else if (rv < 0) {
5233 5234
                goto cleanup;
            }
5235
        }
5236 5237
        if ((!bypassSecurityDriver) &&
            virSecurityManagerSetSavedStateLabel(driver->securityManager,
5238
                                                 vm->def, path) < 0)
5239
            goto cleanup;
5240
        restoreLabel = true;
5241 5242
    }

5243
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
5244 5245
        goto cleanup;

5246 5247 5248
    if (!compressor) {
        const char *args[] = { "cat", NULL };

5249
        if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD) &&
5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265
            priv->monConfig->type == VIR_DOMAIN_CHR_TYPE_UNIX) {
            rc = qemuMonitorMigrateToFd(priv->mon,
                                        QEMU_MONITOR_MIGRATE_BACKGROUND,
                                        fd);
        } else {
            rc = qemuMonitorMigrateToFile(priv->mon,
                                          QEMU_MONITOR_MIGRATE_BACKGROUND,
                                          args, path, offset);
        }
    } else {
        const char *prog = compressor;
        const char *args[] = {
            prog,
            "-c",
            NULL
        };
5266 5267 5268 5269
        if (pipeFD[0] != -1) {
            cmd = virCommandNewArgs(args);
            virCommandSetInputFD(cmd, pipeFD[0]);
            virCommandSetOutputFD(cmd, &fd);
5270 5271
            virCommandSetErrorBuffer(cmd, &errbuf);
            virCommandDoAsyncIO(cmd);
5272 5273 5274
            if (virSetCloseExec(pipeFD[1]) < 0) {
                virReportSystemError(errno, "%s",
                                     _("Unable to set cloexec flag"));
5275
                qemuDomainObjExitMonitor(driver, vm);
5276 5277 5278
                goto cleanup;
            }
            if (virCommandRunAsync(cmd, NULL) < 0) {
5279
                qemuDomainObjExitMonitor(driver, vm);
5280 5281 5282 5283 5284 5285 5286
                goto cleanup;
            }
            rc = qemuMonitorMigrateToFd(priv->mon,
                                        QEMU_MONITOR_MIGRATE_BACKGROUND,
                                        pipeFD[1]);
            if (VIR_CLOSE(pipeFD[0]) < 0 ||
                VIR_CLOSE(pipeFD[1]) < 0)
5287
                VIR_WARN("failed to close intermediate pipe");
5288 5289 5290 5291 5292
        } else {
            rc = qemuMonitorMigrateToFile(priv->mon,
                                          QEMU_MONITOR_MIGRATE_BACKGROUND,
                                          args, path, offset);
        }
5293
    }
5294
    qemuDomainObjExitMonitor(driver, vm);
5295

5296 5297 5298 5299 5300 5301
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
        goto cleanup;
    }

5302 5303 5304
    if (rc < 0)
        goto cleanup;

5305
    rc = qemuMigrationWaitForCompletion(driver, vm, asyncJob, NULL, false);
5306

5307 5308 5309 5310
    if (rc < 0) {
        if (rc == -2) {
            orig_err = virSaveLastError();
            virCommandAbort(cmd);
5311 5312
            if (virDomainObjIsActive(vm) &&
                qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
5313 5314 5315 5316
                qemuMonitorMigrateCancel(priv->mon);
                qemuDomainObjExitMonitor(driver, vm);
            }
        }
5317
        goto cleanup;
5318
    }
5319

5320 5321 5322
    if (cmd && virCommandWait(cmd, NULL) < 0)
        goto cleanup;

5323 5324
    ret = 0;

5325
 cleanup:
5326 5327 5328
    if (ret < 0 && !orig_err)
        orig_err = virSaveLastError();

5329
    /* Restore max migration bandwidth */
5330 5331
    if (virDomainObjIsActive(vm) &&
        qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
5332 5333
        qemuMonitorSetMigrationSpeed(priv->mon, saveMigBandwidth);
        priv->migMaxBandwidth = saveMigBandwidth;
5334
        qemuDomainObjExitMonitor(driver, vm);
5335 5336
    }

5337 5338
    VIR_FORCE_CLOSE(pipeFD[0]);
    VIR_FORCE_CLOSE(pipeFD[1]);
5339 5340 5341 5342 5343
    if (cmd) {
        VIR_DEBUG("Compression binary stderr: %s", NULLSTR(errbuf));
        VIR_FREE(errbuf);
        virCommandFree(cmd);
    }
5344 5345
    if (restoreLabel && (!bypassSecurityDriver) &&
        virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
5346
                                                 vm->def, path) < 0)
5347 5348
        VIR_WARN("failed to restore save state label on %s", path);

5349 5350
    if (virCgroupHasController(priv->cgroup,
                               VIR_CGROUP_CONTROLLER_DEVICES)) {
5351 5352 5353
        int rv = virCgroupDenyDevicePath(priv->cgroup, path,
                                         VIR_CGROUP_DEVICE_RWM);
        virDomainAuditCgroupPath(vm, priv->cgroup, "deny", path, "rwm", rv == 0);
5354
    }
5355 5356 5357 5358 5359 5360

    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }

5361 5362
    return ret;
}
5363 5364

int
5365
qemuMigrationJobStart(virQEMUDriverPtr driver,
5366
                      virDomainObjPtr vm,
5367
                      qemuDomainAsyncJob job)
5368 5369 5370
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

5371
    if (qemuDomainObjBeginAsyncJob(driver, vm, job) < 0)
5372 5373
        return -1;

5374
    if (job == QEMU_ASYNC_JOB_MIGRATION_IN) {
5375
        qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_NONE);
5376
    } else {
5377 5378 5379
        qemuDomainObjSetAsyncJobMask(vm, (QEMU_JOB_DEFAULT_MASK |
                                          JOB_MASK(QEMU_JOB_SUSPEND) |
                                          JOB_MASK(QEMU_JOB_MIGRATION_OP)));
5380
    }
5381

J
Jiri Denemark 已提交
5382
    priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED;
5383 5384 5385 5386 5387

    return 0;
}

void
5388
qemuMigrationJobSetPhase(virQEMUDriverPtr driver,
5389
                         virDomainObjPtr vm,
5390
                         qemuMigrationJobPhase phase)
5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

    if (phase < priv->job.phase) {
        VIR_ERROR(_("migration protocol going backwards %s => %s"),
                  qemuMigrationJobPhaseTypeToString(priv->job.phase),
                  qemuMigrationJobPhaseTypeToString(phase));
        return;
    }

    qemuDomainObjSetJobPhase(driver, vm, phase);
}

void
5405
qemuMigrationJobStartPhase(virQEMUDriverPtr driver,
5406
                           virDomainObjPtr vm,
5407
                           qemuMigrationJobPhase phase)
5408
{
5409
    virObjectRef(vm);
5410 5411 5412
    qemuMigrationJobSetPhase(driver, vm, phase);
}

5413
bool
5414 5415
qemuMigrationJobContinue(virDomainObjPtr vm)
{
5416
    qemuDomainObjReleaseAsyncJob(vm);
5417
    return virObjectUnref(vm);
5418 5419 5420 5421
}

bool
qemuMigrationJobIsActive(virDomainObjPtr vm,
5422
                         qemuDomainAsyncJob job)
5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

    if (priv->job.asyncJob != job) {
        const char *msg;

        if (job == QEMU_ASYNC_JOB_MIGRATION_IN)
            msg = _("domain '%s' is not processing incoming migration");
        else
            msg = _("domain '%s' is not being migrated");

5434
        virReportError(VIR_ERR_OPERATION_INVALID, msg, vm->def->name);
5435 5436 5437 5438 5439
        return false;
    }
    return true;
}

5440
bool
5441
qemuMigrationJobFinish(virQEMUDriverPtr driver, virDomainObjPtr vm)
5442 5443 5444
{
    return qemuDomainObjEndAsyncJob(driver, vm);
}