qemu_migration.c 226.2 KB
Newer Older
1 2 3
/*
 * qemu_migration.c: QEMU migration handling
 *
4
 * Copyright (C) 2006-2015 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
#include "qemu_blockjob.h"
43

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

#define VIR_FROM_THIS VIR_FROM_QEMU

67 68
VIR_LOG_INIT("qemu.qemu_migration");

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

82 83 84 85 86
VIR_ENUM_IMPL(qemuMigrationCompressMethod, QEMU_MIGRATION_COMPRESS_LAST,
              "xbzrle",
              "mt",
);

87
enum qemuMigrationCookieFlags {
88
    QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS,
89
    QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE,
90
    QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT,
91
    QEMU_MIGRATION_COOKIE_FLAG_NETWORK,
92
    QEMU_MIGRATION_COOKIE_FLAG_NBD,
93
    QEMU_MIGRATION_COOKIE_FLAG_STATS,
94
    QEMU_MIGRATION_COOKIE_FLAG_MEMORY_HOTPLUG,
95 96 97 98 99 100 101

    QEMU_MIGRATION_COOKIE_FLAG_LAST
};

VIR_ENUM_DECL(qemuMigrationCookieFlag);
VIR_ENUM_IMPL(qemuMigrationCookieFlag,
              QEMU_MIGRATION_COOKIE_FLAG_LAST,
102 103 104 105
              "graphics",
              "lockstate",
              "persistent",
              "network",
106
              "nbd",
107 108
              "statistics",
              "memory-hotplug");
109 110 111

enum qemuMigrationCookieFeatures {
    QEMU_MIGRATION_COOKIE_GRAPHICS  = (1 << QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS),
112
    QEMU_MIGRATION_COOKIE_LOCKSTATE = (1 << QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE),
113
    QEMU_MIGRATION_COOKIE_PERSISTENT = (1 << QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT),
114
    QEMU_MIGRATION_COOKIE_NETWORK = (1 << QEMU_MIGRATION_COOKIE_FLAG_NETWORK),
115
    QEMU_MIGRATION_COOKIE_NBD = (1 << QEMU_MIGRATION_COOKIE_FLAG_NBD),
116
    QEMU_MIGRATION_COOKIE_STATS = (1 << QEMU_MIGRATION_COOKIE_FLAG_STATS),
117
    QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG = (1 << QEMU_MIGRATION_COOKIE_FLAG_MEMORY_HOTPLUG),
118 119 120 121 122 123 124 125 126 127 128 129
};

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

130 131 132 133 134 135
typedef struct _qemuMigrationCookieNetData qemuMigrationCookieNetData;
typedef qemuMigrationCookieNetData *qemuMigrationCookieNetDataPtr;
struct _qemuMigrationCookieNetData {
    int vporttype; /* enum virNetDevVPortProfile */

    /*
136
     * Array of pointers to saved data. Each VIF will have its own
137 138 139 140 141 142 143 144 145 146 147 148 149 150
     * 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;
};

151 152 153 154
typedef struct _qemuMigrationCookieNBD qemuMigrationCookieNBD;
typedef qemuMigrationCookieNBD *qemuMigrationCookieNBDPtr;
struct _qemuMigrationCookieNBD {
    int port; /* on which port does NBD server listen for incoming data */
155 156 157 158 159 160

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

163 164 165
typedef struct _qemuMigrationCookie qemuMigrationCookie;
typedef qemuMigrationCookie *qemuMigrationCookiePtr;
struct _qemuMigrationCookie {
E
Eric Blake 已提交
166 167
    unsigned int flags;
    unsigned int flagsMandatory;
168 169

    /* Host properties */
170 171 172 173
    unsigned char localHostuuid[VIR_UUID_BUFLEN];
    unsigned char remoteHostuuid[VIR_UUID_BUFLEN];
    char *localHostname;
    char *remoteHostname;
174 175 176 177

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

179 180 181 182
    /* If (flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) */
    char *lockState;
    char *lockDriver;

183 184
    /* If (flags & QEMU_MIGRATION_COOKIE_GRAPHICS) */
    qemuMigrationCookieGraphicsPtr graphics;
185 186 187

    /* If (flags & QEMU_MIGRATION_COOKIE_PERSISTENT) */
    virDomainDefPtr persistent;
188 189 190

    /* If (flags & QEMU_MIGRATION_COOKIE_NETWORK) */
    qemuMigrationCookieNetworkPtr network;
191 192 193

    /* If (flags & QEMU_MIGRATION_COOKIE_NBD) */
    qemuMigrationCookieNBDPtr nbd;
194 195 196

    /* If (flags & QEMU_MIGRATION_COOKIE_STATS) */
    qemuDomainJobInfoPtr jobInfo;
197 198
};

199 200 201 202 203 204 205 206 207
static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap)
{
    if (!grap)
        return;
    VIR_FREE(grap->listen);
    VIR_FREE(grap->tlsSubject);
    VIR_FREE(grap);
}

208

209 210 211
static void
qemuMigrationCookieNetworkFree(qemuMigrationCookieNetworkPtr network)
{
212
    size_t i;
213 214 215 216 217 218 219 220 221 222 223 224 225

    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);
}


226 227 228 229 230 231 232 233 234 235 236 237
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);
}


238 239 240 241 242
static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig)
{
    if (!mig)
        return;

243 244
    qemuMigrationCookieGraphicsFree(mig->graphics);
    qemuMigrationCookieNetworkFree(mig->network);
245
    qemuMigrationCookieNBDFree(mig->nbd);
246

247 248
    VIR_FREE(mig->localHostname);
    VIR_FREE(mig->remoteHostname);
249
    VIR_FREE(mig->name);
250 251
    VIR_FREE(mig->lockState);
    VIR_FREE(mig->lockDriver);
252
    VIR_FREE(mig->jobInfo);
253 254 255 256
    VIR_FREE(mig);
}


257
#ifdef WITH_GNUTLS
258 259 260 261 262 263 264 265 266 267 268 269
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)
270
        goto error;
271 272

    if (virFileReadAll(certfile, 8192, &pemdata) < 0) {
273 274
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unable to read server cert %s"), certfile);
275 276 277 278 279
        goto error;
    }

    ret = gnutls_x509_crt_init(&cert);
    if (ret < 0) {
280 281 282
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot initialize cert object: %s"),
                       gnutls_strerror(ret));
283 284 285 286 287 288 289 290
        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) {
291 292 293
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot load cert data from %s: %s"),
                       certfile, gnutls_strerror(ret));
294 295 296 297 298
        goto error;
    }

    subjectlen = 1024;
    if (VIR_ALLOC_N(subject, subjectlen+1) < 0)
299
        goto error;
300 301 302 303 304 305 306 307 308

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

    VIR_FREE(certfile);
    VIR_FREE(pemdata);

    return subject;

309
 error:
310 311 312 313
    VIR_FREE(certfile);
    VIR_FREE(pemdata);
    return NULL;
}
314
#endif
315 316

static qemuMigrationCookieGraphicsPtr
317
qemuMigrationCookieGraphicsSpiceAlloc(virQEMUDriverPtr driver,
318 319
                                      virDomainGraphicsDefPtr def,
                                      virDomainGraphicsListenDefPtr glisten)
320 321 322
{
    qemuMigrationCookieGraphicsPtr mig = NULL;
    const char *listenAddr;
323
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
324 325

    if (VIR_ALLOC(mig) < 0)
326
        goto error;
327

328
    mig->type = VIR_DOMAIN_GRAPHICS_TYPE_SPICE;
329 330 331 332 333
    mig->port = def->data.spice.port;
    if (cfg->spiceTLS)
        mig->tlsPort = def->data.spice.tlsPort;
    else
        mig->tlsPort = -1;
334

335
    if (!glisten || !(listenAddr = glisten->address))
336
        listenAddr = cfg->spiceListen;
337

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

346
    virObjectUnref(cfg);
347 348
    return mig;

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


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

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

    mig->nnets = def->nnets;

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

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

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

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

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

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

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

    return mig;

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


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

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

454
    for (i = 0; i < dom->def->ngraphics; i++) {
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
        if (dom->def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
            virDomainGraphicsListenDefPtr glisten =
                virDomainGraphicsGetListen(dom->def->graphics[i], 0);

            if (!glisten) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("missing listen element"));
                return -1;
            }

            switch (glisten->type) {
            case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
            case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
                /* Seamless migration is supported only for listen types
                 * 'address and 'network'. */
                if (!(mig->graphics =
                      qemuMigrationCookieGraphicsSpiceAlloc(driver,
                                                            dom->def->graphics[i],
                                                            glisten)))
                    return -1;
                mig->flags |= QEMU_MIGRATION_COOKIE_GRAPHICS;
                break;

            case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET:
            case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE:
            case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST:
                break;
            }

            /* Seamless migration is supported only for one graphics. */
            if (mig->graphics)
                break;
        }
488
    }
489 490 491 492 493

    return 0;
}


494 495
static int
qemuMigrationCookieAddLockstate(qemuMigrationCookiePtr mig,
496
                                virQEMUDriverPtr driver,
497 498 499 500 501
                                virDomainObjPtr dom)
{
    qemuDomainObjPrivatePtr priv = dom->privateData;

    if (mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) {
502 503
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Migration lockstate data already present"));
504 505 506 507
        return -1;
    }

    if (virDomainObjGetState(dom, NULL) == VIR_DOMAIN_PAUSED) {
508
        if (VIR_STRDUP(mig->lockState, priv->lockState) < 0)
509 510 511 512 513 514
            return -1;
    } else {
        if (virDomainLockProcessInquire(driver->lockManager, dom, &mig->lockState) < 0)
            return -1;
    }

515
    if (VIR_STRDUP(mig->lockDriver, virLockManagerPluginGetName(driver->lockManager)) < 0) {
516 517 518 519 520 521 522 523 524 525 526
        VIR_FREE(mig->lockState);
        return -1;
    }

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

    return 0;
}


527 528
static int
qemuMigrationCookieAddPersistent(qemuMigrationCookiePtr mig,
529
                                 virDomainDefPtr def)
530 531
{
    if (mig->flags & QEMU_MIGRATION_COOKIE_PERSISTENT) {
532 533
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Migration persistent data already present"));
534 535 536
        return -1;
    }

537
    if (!def)
538 539
        return 0;

540
    mig->persistent = def;
541 542 543 544 545 546
    mig->flags |= QEMU_MIGRATION_COOKIE_PERSISTENT;
    mig->flagsMandatory |= QEMU_MIGRATION_COOKIE_PERSISTENT;
    return 0;
}


547 548 549 550 551 552 553 554 555 556 557 558 559
static virDomainDefPtr
qemuMigrationCookieGetPersistent(qemuMigrationCookiePtr mig)
{
    virDomainDefPtr def = mig->persistent;

    mig->persistent = NULL;
    mig->flags &= ~QEMU_MIGRATION_COOKIE_PERSISTENT;
    mig->flagsMandatory &= ~QEMU_MIGRATION_COOKIE_PERSISTENT;

    return def;
}


560 561
static int
qemuMigrationCookieAddNetwork(qemuMigrationCookiePtr mig,
562
                              virQEMUDriverPtr driver,
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
                              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;
}

581

582 583
static int
qemuMigrationCookieAddNBD(qemuMigrationCookiePtr mig,
584
                          virQEMUDriverPtr driver,
585 586 587
                          virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
588 589
    virHashTablePtr stats = NULL;
    size_t i;
590
    int ret = -1, rc;
591 592

    /* It is not a bug if there already is a NBD data */
593 594 595
    qemuMigrationCookieNBDFree(mig->nbd);

    if (VIR_ALLOC(mig->nbd) < 0)
596 597
        return -1;

598 599 600 601 602 603 604 605 606 607 608 609 610
    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;

611 612 613
            if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                               priv->job.asyncJob) < 0)
                goto cleanup;
614 615
            rc = qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats, false);
            if (qemuDomainObjExitMonitor(driver, vm) < 0)
616
                goto cleanup;
617
            if (rc < 0)
618 619 620 621 622 623 624 625 626 627 628 629 630 631
                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++;
    }

632 633 634
    mig->nbd->port = priv->nbdPort;
    mig->flags |= QEMU_MIGRATION_COOKIE_NBD;

635 636 637 638
    ret = 0;
 cleanup:
    virHashFree(stats);
    return ret;
639 640 641
}


642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
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;
}


661 662 663
static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf,
                                                 qemuMigrationCookieGraphicsPtr grap)
{
664
    virBufferAsprintf(buf, "<graphics type='%s' port='%d' listen='%s'",
665 666 667 668 669 670
                      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");
671 672 673 674
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<cert info='subject' value='%s'/>\n", grap->tlsSubject);
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</graphics>\n");
675 676 677 678 679 680
    } else {
        virBufferAddLit(buf, "/>\n");
    }
}


681 682 683 684
static void
qemuMigrationCookieNetworkXMLFormat(virBufferPtr buf,
                                    qemuMigrationCookieNetworkPtr optr)
{
685
    size_t i;
686 687 688 689 690 691
    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) {
692 693
                virBufferAddLit(buf, "<network>\n");
                virBufferAdjustIndent(buf, 2);
694 695
                empty = false;
            }
696
            virBufferAsprintf(buf, "<interface index='%zu' vporttype='%s'",
697 698 699
                              i, virNetDevVPortTypeToString(optr->net[i].vporttype));
            if (optr->net[i].portdata) {
                virBufferAddLit(buf, ">\n");
700 701
                virBufferAdjustIndent(buf, 2);
                virBufferEscapeString(buf, "<portdata>%s</portdata>\n",
702
                                      optr->net[i].portdata);
703 704
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</interface>\n");
705 706 707 708 709
            } else {
                virBufferAddLit(buf, "/>\n");
            }
        }
    }
710 711 712 713
    if (!empty) {
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</network>\n");
    }
714 715 716
}


717 718 719 720
static void
qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf,
                                       qemuDomainJobInfoPtr jobInfo)
{
721
    qemuMonitorMigrationStats *stats = &jobInfo->stats;
722 723 724 725

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

726 727
    virBufferAsprintf(buf, "<started>%llu</started>\n", jobInfo->started);
    virBufferAsprintf(buf, "<stopped>%llu</stopped>\n", jobInfo->stopped);
728 729 730
    virBufferAsprintf(buf, "<sent>%llu</sent>\n", jobInfo->sent);
    if (jobInfo->timeDeltaSet)
        virBufferAsprintf(buf, "<delta>%lld</delta>\n", jobInfo->timeDelta);
731

732 733 734 735 736 737
    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);
738
    if (stats->downtime_set)
739 740
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_DOWNTIME,
741 742
                          stats->downtime);
    if (stats->setup_time_set)
743 744
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_SETUP_TIME,
745
                          stats->setup_time);
746 747 748

    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_MEMORY_TOTAL,
749
                      stats->ram_total);
750 751
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_MEMORY_PROCESSED,
752
                      stats->ram_transferred);
753 754
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_MEMORY_REMAINING,
755
                      stats->ram_remaining);
756 757
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_MEMORY_BPS,
758
                      stats->ram_bps);
759

760
    if (stats->ram_duplicate_set) {
761 762
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_MEMORY_CONSTANT,
763
                          stats->ram_duplicate);
764 765
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_MEMORY_NORMAL,
766
                          stats->ram_normal);
767 768
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES,
769
                          stats->ram_normal_bytes);
770 771
    }

772 773 774 775 776 777 778
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_MEMORY_DIRTY_RATE,
                      stats->ram_dirty_rate);
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_MEMORY_ITERATION,
                      stats->ram_iteration);

779 780
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_DISK_TOTAL,
781
                      stats->disk_total);
782 783
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_DISK_PROCESSED,
784
                      stats->disk_transferred);
785 786
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_DISK_REMAINING,
787
                      stats->disk_remaining);
788 789
    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                      VIR_DOMAIN_JOB_DISK_BPS,
790
                      stats->disk_bps);
791

792
    if (stats->xbzrle_set) {
793 794
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_COMPRESSION_CACHE,
795
                          stats->xbzrle_cache_size);
796 797
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_COMPRESSION_BYTES,
798
                          stats->xbzrle_bytes);
799 800
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_COMPRESSION_PAGES,
801
                          stats->xbzrle_pages);
802 803
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES,
804
                          stats->xbzrle_cache_miss);
805 806
        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
                          VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW,
807
                          stats->xbzrle_overflow);
808 809 810 811 812 813 814
    }

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


815
static int
816
qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver,
817
                             virBufferPtr buf,
818
                             qemuMigrationCookiePtr mig)
819 820 821
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    char hostuuidstr[VIR_UUID_STRING_BUFLEN];
822
    size_t i;
823 824

    virUUIDFormat(mig->uuid, uuidstr);
825
    virUUIDFormat(mig->localHostuuid, hostuuidstr);
826

827
    virBufferAddLit(buf, "<qemu-migration>\n");
828 829 830 831 832
    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);
833

834
    for (i = 0; i < QEMU_MIGRATION_COOKIE_FLAG_LAST; i++) {
835
        if (mig->flagsMandatory & (1 << i))
836
            virBufferAsprintf(buf, "<feature name='%s'/>\n",
837 838 839
                              qemuMigrationCookieFlagTypeToString(i));
    }

840 841
    if ((mig->flags & QEMU_MIGRATION_COOKIE_GRAPHICS) &&
        mig->graphics)
842 843
        qemuMigrationCookieGraphicsXMLFormat(buf, mig->graphics);

844 845
    if ((mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) &&
        mig->lockState) {
846
        virBufferAsprintf(buf, "<lockstate driver='%s'>\n",
847
                          mig->lockDriver);
848 849
        virBufferAdjustIndent(buf, 2);
        virBufferAsprintf(buf, "<leases>%s</leases>\n",
850
                          mig->lockState);
851 852
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</lockstate>\n");
853 854
    }

855 856
    if ((mig->flags & QEMU_MIGRATION_COOKIE_PERSISTENT) &&
        mig->persistent) {
857 858 859
        if (qemuDomainDefFormatBuf(driver,
                                   mig->persistent,
                                   VIR_DOMAIN_XML_INACTIVE |
860 861
                                   VIR_DOMAIN_XML_SECURE |
                                   VIR_DOMAIN_XML_MIGRATABLE,
862
                                   buf) < 0)
863
            return -1;
864 865
    }

866 867 868
    if ((mig->flags & QEMU_MIGRATION_COOKIE_NETWORK) && mig->network)
        qemuMigrationCookieNetworkXMLFormat(buf, mig->network);

869
    if ((mig->flags & QEMU_MIGRATION_COOKIE_NBD) && mig->nbd) {
870
        virBufferAddLit(buf, "<nbd");
871 872
        if (mig->nbd->port)
            virBufferAsprintf(buf, " port='%d'", mig->nbd->port);
873 874 875 876 877 878 879 880 881 882 883 884 885 886
        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");
        }
887 888
    }

889 890 891
    if (mig->flags & QEMU_MIGRATION_COOKIE_STATS && mig->jobInfo)
        qemuMigrationCookieStatisticsXMLFormat(buf, mig->jobInfo);

892
    virBufferAdjustIndent(buf, -2);
893
    virBufferAddLit(buf, "</qemu-migration>\n");
894
    return 0;
895 896 897
}


898
static char *qemuMigrationCookieXMLFormatStr(virQEMUDriverPtr driver,
899
                                             qemuMigrationCookiePtr mig)
900 901 902
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;

903
    if (qemuMigrationCookieXMLFormat(driver, &buf, mig) < 0) {
904 905 906
        virBufferFreeAndReset(&buf);
        return NULL;
    }
907

908
    if (virBufferCheckError(&buf) < 0)
909 910 911 912 913 914
        return NULL;

    return virBufferContentAndReset(&buf);
}


915 916 917 918 919 920 921
static qemuMigrationCookieGraphicsPtr
qemuMigrationCookieGraphicsXMLParse(xmlXPathContextPtr ctxt)
{
    qemuMigrationCookieGraphicsPtr grap;
    char *tmp;

    if (VIR_ALLOC(grap) < 0)
922
        goto error;
923 924

    if (!(tmp = virXPathString("string(./graphics/@type)", ctxt))) {
925 926
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing type attribute in migration data"));
927 928 929
        goto error;
    }
    if ((grap->type = virDomainGraphicsTypeFromString(tmp)) < 0) {
930 931
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown graphics type %s"), tmp);
932 933 934
        VIR_FREE(tmp);
        goto error;
    }
E
Eric Blake 已提交
935
    VIR_FREE(tmp);
936
    if (virXPathInt("string(./graphics/@port)", ctxt, &grap->port) < 0) {
937 938
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing port attribute in migration data"));
939 940 941 942
        goto error;
    }
    if (grap->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
        if (virXPathInt("string(./graphics/@tlsPort)", ctxt, &grap->tlsPort) < 0) {
943 944
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing tlsPort attribute in migration data"));
945 946 947 948
            goto error;
        }
    }
    if (!(grap->listen = virXPathString("string(./graphics/@listen)", ctxt))) {
949 950
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing listen attribute in migration data"));
951 952 953
        goto error;
    }
    /* Optional */
954
    grap->tlsSubject = virXPathString("string(./graphics/cert[@info='subject']/@value)", ctxt);
955 956 957

    return grap;

958
 error:
959 960 961 962 963
    qemuMigrationCookieGraphicsFree(grap);
    return NULL;
}


964 965 966 967
static qemuMigrationCookieNetworkPtr
qemuMigrationCookieNetworkXMLParse(xmlXPathContextPtr ctxt)
{
    qemuMigrationCookieNetworkPtr optr;
968
    size_t i;
969 970 971 972 973 974
    int n;
    xmlNodePtr *interfaces = NULL;
    char *vporttype;
    xmlNodePtr save_ctxt = ctxt->node;

    if (VIR_ALLOC(optr) < 0)
975
        goto error;
976 977 978 979 980 981 982 983

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

    optr->nnets = n;
984
    if (VIR_ALLOC_N(optr->net, optr->nnets) < 0)
985
        goto error;
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001

    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);

1002
 cleanup:
1003 1004 1005
    ctxt->node = save_ctxt;
    return optr;

1006
 error:
1007 1008 1009 1010 1011 1012 1013
    VIR_FREE(interfaces);
    qemuMigrationCookieNetworkFree(optr);
    optr = NULL;
    goto cleanup;
}


1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
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;
}


1078 1079 1080 1081
static qemuDomainJobInfoPtr
qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt)
{
    qemuDomainJobInfoPtr jobInfo = NULL;
1082
    qemuMonitorMigrationStats *stats;
1083 1084 1085 1086 1087 1088 1089 1090
    xmlNodePtr save_ctxt = ctxt->node;

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

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

1091
    stats = &jobInfo->stats;
1092 1093
    jobInfo->type = VIR_DOMAIN_JOB_COMPLETED;

1094 1095
    virXPathULongLong("string(./started[1])", ctxt, &jobInfo->started);
    virXPathULongLong("string(./stopped[1])", ctxt, &jobInfo->stopped);
1096 1097 1098
    virXPathULongLong("string(./sent[1])", ctxt, &jobInfo->sent);
    if (virXPathLongLong("string(./delta[1])", ctxt, &jobInfo->timeDelta) == 0)
        jobInfo->timeDeltaSet = true;
1099

1100 1101 1102 1103
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_TIME_ELAPSED "[1])",
                      ctxt, &jobInfo->timeElapsed);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_TIME_REMAINING "[1])",
                      ctxt, &jobInfo->timeRemaining);
1104

1105
    if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_DOWNTIME "[1])",
1106 1107
                          ctxt, &stats->downtime) == 0)
        stats->downtime_set = true;
1108
    if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_SETUP_TIME "[1])",
1109 1110
                          ctxt, &stats->setup_time) == 0)
        stats->setup_time_set = true;
1111 1112

    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_TOTAL "[1])",
1113
                      ctxt, &stats->ram_total);
1114
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_PROCESSED "[1])",
1115
                      ctxt, &stats->ram_transferred);
1116
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_REMAINING "[1])",
1117
                      ctxt, &stats->ram_remaining);
1118
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_BPS "[1])",
1119
                      ctxt, &stats->ram_bps);
1120 1121

    if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_CONSTANT "[1])",
1122 1123
                          ctxt, &stats->ram_duplicate) == 0)
        stats->ram_duplicate_set = true;
1124
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_NORMAL "[1])",
1125
                      ctxt, &stats->ram_normal);
1126
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES "[1])",
1127
                      ctxt, &stats->ram_normal_bytes);
1128

1129 1130 1131 1132 1133
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_DIRTY_RATE "[1])",
                      ctxt, &stats->ram_dirty_rate);
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_ITERATION "[1])",
                      ctxt, &stats->ram_iteration);

1134
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_TOTAL "[1])",
1135
                      ctxt, &stats->disk_total);
1136
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_PROCESSED "[1])",
1137
                      ctxt, &stats->disk_transferred);
1138
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_REMAINING "[1])",
1139
                      ctxt, &stats->disk_remaining);
1140
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_BPS "[1])",
1141
                      ctxt, &stats->disk_bps);
1142 1143

    if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE "[1])",
1144 1145
                          ctxt, &stats->xbzrle_cache_size) == 0)
        stats->xbzrle_set = true;
1146
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_BYTES "[1])",
1147
                      ctxt, &stats->xbzrle_bytes);
1148
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_PAGES "[1])",
1149
                      ctxt, &stats->xbzrle_pages);
1150
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES "[1])",
1151
                      ctxt, &stats->xbzrle_cache_miss);
1152
    virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW "[1])",
1153
                      ctxt, &stats->xbzrle_overflow);
1154 1155 1156 1157 1158 1159 1160

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


1161 1162
static int
qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig,
1163
                            virQEMUDriverPtr driver,
1164
                            xmlDocPtr doc,
1165
                            xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
1166
                            unsigned int flags)
1167 1168
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
1169
    char *tmp = NULL;
1170
    xmlNodePtr *nodes = NULL;
1171 1172
    size_t i;
    int n;
1173 1174 1175 1176
    virCapsPtr caps = NULL;

    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto error;
1177 1178 1179 1180 1181 1182 1183 1184

    /* 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))) {
1185 1186
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing name element in migration data"));
1187 1188 1189
        goto error;
    }
    if (STRNEQ(tmp, mig->name)) {
1190 1191 1192
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Incoming cookie data had unexpected name %s vs %s"),
                       tmp, mig->name);
1193 1194 1195 1196 1197 1198 1199
        goto error;
    }
    VIR_FREE(tmp);

    /* Extract domain uuid */
    tmp = virXPathString("string(./uuid[1])", ctxt);
    if (!tmp) {
1200 1201
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing uuid element in migration data"));
1202 1203 1204 1205
        goto error;
    }
    virUUIDFormat(mig->uuid, uuidstr);
    if (STRNEQ(tmp, uuidstr)) {
1206 1207 1208
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Incoming cookie data had unexpected UUID %s vs %s"),
                       tmp, uuidstr);
1209
        goto error;
1210 1211 1212 1213
    }
    VIR_FREE(tmp);

    /* Check & forbid "localhost" migration */
1214
    if (!(mig->remoteHostname = virXPathString("string(./hostname[1])", ctxt))) {
1215 1216
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing hostname element in migration data"));
1217 1218
        goto error;
    }
1219
    if (STREQ(mig->remoteHostname, mig->localHostname)) {
1220 1221 1222
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Attempt to migrate guest to the same host %s"),
                       mig->remoteHostname);
1223 1224 1225 1226
        goto error;
    }

    if (!(tmp = virXPathString("string(./hostuuid[1])", ctxt))) {
1227 1228 1229
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing hostuuid element in migration data"));
        goto error;
1230
    }
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
    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);
1243

1244 1245
    /* Check to ensure all mandatory features from XML are also
     * present in 'flags' */
1246
    if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0)
1247 1248
        goto error;

1249
    for (i = 0; i < n; i++) {
1250 1251 1252
        int val;
        char *str = virXMLPropString(nodes[i], "name");
        if (!str) {
1253 1254
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing feature name"));
1255 1256 1257 1258
            goto error;
        }

        if ((val = qemuMigrationCookieFlagTypeFromString(str)) < 0) {
1259 1260 1261
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown migration cookie feature %s"),
                           str);
1262 1263 1264 1265 1266
            VIR_FREE(str);
            goto error;
        }

        if ((flags & (1 << val)) == 0) {
1267 1268 1269
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unsupported migration cookie feature %s"),
                           str);
1270
            VIR_FREE(str);
1271
            goto error;
1272 1273 1274 1275 1276
        }
        VIR_FREE(str);
    }
    VIR_FREE(nodes);

1277 1278 1279 1280 1281
    if ((flags & QEMU_MIGRATION_COOKIE_GRAPHICS) &&
        virXPathBoolean("count(./graphics) > 0", ctxt) &&
        (!(mig->graphics = qemuMigrationCookieGraphicsXMLParse(ctxt))))
        goto error;

1282 1283 1284 1285
    if ((flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) &&
        virXPathBoolean("count(./lockstate) > 0", ctxt)) {
        mig->lockDriver = virXPathString("string(./lockstate[1]/@driver)", ctxt);
        if (!mig->lockDriver) {
1286 1287
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing lock driver name in migration cookie"));
1288 1289 1290 1291 1292 1293 1294
            goto error;
        }
        mig->lockState = virXPathString("string(./lockstate[1]/leases[1])", ctxt);
        if (mig->lockState && STREQ(mig->lockState, ""))
            VIR_FREE(mig->lockState);
    }

1295 1296 1297
    if ((flags & QEMU_MIGRATION_COOKIE_PERSISTENT) &&
        virXPathBoolean("count(./domain) > 0", ctxt)) {
        if ((n = virXPathNodeSet("./domain", ctxt, &nodes)) > 1) {
1298 1299 1300 1301
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Too many domain elements in "
                             "migration cookie: %d"),
                           n);
1302 1303
            goto error;
        }
1304 1305
        mig->persistent = virDomainDefParseNode(doc, nodes[0],
                                                caps, driver->xmlopt,
1306
                                                VIR_DOMAIN_DEF_PARSE_INACTIVE |
1307 1308
                                                VIR_DOMAIN_DEF_PARSE_ABI_UPDATE |
                                                VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
1309 1310 1311 1312 1313 1314 1315 1316
        if (!mig->persistent) {
            /* virDomainDefParseNode already reported
             * an error for us */
            goto error;
        }
        VIR_FREE(nodes);
    }

1317 1318 1319 1320 1321
    if ((flags & QEMU_MIGRATION_COOKIE_NETWORK) &&
        virXPathBoolean("count(./network) > 0", ctxt) &&
        (!(mig->network = qemuMigrationCookieNetworkXMLParse(ctxt))))
        goto error;

1322
    if (flags & QEMU_MIGRATION_COOKIE_NBD &&
1323 1324 1325
        virXPathBoolean("boolean(./nbd)", ctxt) &&
        (!(mig->nbd = qemuMigrationCookieNBDXMLParse(ctxt))))
        goto error;
1326

1327 1328 1329 1330 1331
    if (flags & QEMU_MIGRATION_COOKIE_STATS &&
        virXPathBoolean("boolean(./statistics)", ctxt) &&
        (!(mig->jobInfo = qemuMigrationCookieStatisticsXMLParse(ctxt))))
        goto error;

1332
    virObjectUnref(caps);
1333 1334
    return 0;

1335
 error:
1336
    VIR_FREE(tmp);
1337
    VIR_FREE(nodes);
1338
    virObjectUnref(caps);
1339 1340 1341 1342 1343 1344
    return -1;
}


static int
qemuMigrationCookieXMLParseStr(qemuMigrationCookiePtr mig,
1345
                               virQEMUDriverPtr driver,
1346
                               const char *xml,
E
Eric Blake 已提交
1347
                               unsigned int flags)
1348 1349 1350
{
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr ctxt = NULL;
1351
    int ret = -1;
1352 1353 1354

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

1355
    if (!(doc = virXMLParseStringCtxt(xml, _("(qemu_migration_cookie)"), &ctxt)))
1356 1357
        goto cleanup;

1358
    ret = qemuMigrationCookieXMLParse(mig, driver, doc, ctxt, flags);
1359

1360
 cleanup:
1361 1362 1363 1364 1365 1366 1367 1368 1369
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(doc);

    return ret;
}


static int
qemuMigrationBakeCookie(qemuMigrationCookiePtr mig,
1370
                        virQEMUDriverPtr driver,
1371
                        virDomainObjPtr dom,
1372 1373
                        char **cookieout,
                        int *cookieoutlen,
E
Eric Blake 已提交
1374
                        unsigned int flags)
1375
{
1376 1377
    if (!cookieout || !cookieoutlen)
        return 0;
1378 1379 1380

    *cookieoutlen = 0;

1381 1382 1383 1384
    if (flags & QEMU_MIGRATION_COOKIE_GRAPHICS &&
        qemuMigrationCookieAddGraphics(mig, driver, dom) < 0)
        return -1;

1385 1386 1387 1388
    if (flags & QEMU_MIGRATION_COOKIE_LOCKSTATE &&
        qemuMigrationCookieAddLockstate(mig, driver, dom) < 0)
        return -1;

1389 1390 1391 1392 1393
    if (flags & QEMU_MIGRATION_COOKIE_NETWORK &&
        qemuMigrationCookieAddNetwork(mig, driver, dom) < 0) {
        return -1;
    }

1394 1395 1396 1397
    if ((flags & QEMU_MIGRATION_COOKIE_NBD) &&
        qemuMigrationCookieAddNBD(mig, driver, dom) < 0)
        return -1;

1398 1399 1400 1401
    if (flags & QEMU_MIGRATION_COOKIE_STATS &&
        qemuMigrationCookieAddStatistics(mig, dom) < 0)
        return -1;

1402 1403 1404
    if (flags & QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG)
        mig->flagsMandatory |= QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG;

1405
    if (!(*cookieout = qemuMigrationCookieXMLFormatStr(driver, mig)))
1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
        return -1;

    *cookieoutlen = strlen(*cookieout) + 1;

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

    return 0;
}


static qemuMigrationCookiePtr
1417
qemuMigrationEatCookie(virQEMUDriverPtr driver,
1418
                       virDomainObjPtr dom,
1419 1420
                       const char *cookiein,
                       int cookieinlen,
E
Eric Blake 已提交
1421
                       unsigned int flags)
1422 1423 1424 1425 1426 1427
{
    qemuMigrationCookiePtr mig = NULL;

    /* Parse & validate incoming cookie (if any) */
    if (cookiein && cookieinlen &&
        cookiein[cookieinlen-1] != '\0') {
1428 1429
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Migration cookie was not NULL terminated"));
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
        goto error;
    }

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

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

    if (cookiein && cookieinlen &&
        qemuMigrationCookieXMLParseStr(mig,
1440
                                       driver,
1441 1442 1443 1444
                                       cookiein,
                                       flags) < 0)
        goto error;

1445 1446 1447 1448 1449 1450 1451 1452
    if (flags & QEMU_MIGRATION_COOKIE_PERSISTENT &&
        mig->persistent &&
        STRNEQ(dom->def->name, mig->persistent->name)) {
        VIR_FREE(mig->persistent->name);
        if (VIR_STRDUP(mig->persistent->name, dom->def->name) < 0)
            goto error;
    }

1453 1454 1455
    if (mig->flags & QEMU_MIGRATION_COOKIE_LOCKSTATE) {
        if (!mig->lockDriver) {
            if (virLockManagerPluginUsesState(driver->lockManager)) {
1456 1457 1458
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing %s lock state for migration cookie"),
                               virLockManagerPluginGetName(driver->lockManager));
1459 1460 1461 1462
                goto error;
            }
        } else if (STRNEQ(mig->lockDriver,
                          virLockManagerPluginGetName(driver->lockManager))) {
1463 1464 1465 1466
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Source host lock driver %s different from target %s"),
                           mig->lockDriver,
                           virLockManagerPluginGetName(driver->lockManager));
1467 1468 1469 1470
            goto error;
        }
    }

1471 1472
    return mig;

1473
 error:
1474 1475 1476
    qemuMigrationCookieFree(mig);
    return NULL;
}
1477

1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
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;
1494 1495
    int reason;
    virDomainState state = virDomainObjGetState(vm, &reason);
1496 1497
    bool ret = false;

1498 1499 1500 1501 1502
    VIR_DEBUG("driver=%p, vm=%p, pre-mig-state=%s, state=%s, reason=%s",
              driver, vm,
              virDomainStateTypeToString(priv->preMigrationState),
              virDomainStateTypeToString(state),
              virDomainStateReasonToString(state, reason));
1503

1504 1505 1506 1507 1508
    if (state != VIR_DOMAIN_PAUSED ||
        reason == VIR_DOMAIN_PAUSED_POSTCOPY_FAILED)
        goto cleanup;

    if (priv->preMigrationState == VIR_DOMAIN_RUNNING) {
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
        /* 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;
}

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 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585

static int
qemuMigrationPrecreateDisk(virConnectPtr conn,
                           virDomainDiskDefPtr disk,
                           unsigned long long capacity)
{
    int ret = -1;
    virStoragePoolPtr pool = NULL;
    virStorageVolPtr vol = NULL;
    char *volName = NULL, *basePath = NULL;
    char *volStr = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    const char *format = NULL;
    unsigned int flags = 0;

    VIR_DEBUG("Precreate disk type=%s", virStorageTypeToString(disk->src->type));

    switch ((virStorageType) disk->src->type) {
    case VIR_STORAGE_TYPE_FILE:
        if (!virDomainDiskGetSource(disk)) {
            VIR_DEBUG("Dropping sourceless disk '%s'",
                      disk->dst);
            return 0;
        }

        if (VIR_STRDUP(basePath, disk->src->path) < 0)
            goto cleanup;

        if (!(volName = strrchr(basePath, '/'))) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("malformed disk path: %s"),
                           disk->src->path);
            goto cleanup;
        }

        *volName = '\0';
        volName++;

        if (!(pool = storagePoolLookupByTargetPath(conn, basePath)))
            goto cleanup;
        format = virStorageFileFormatTypeToString(disk->src->format);
        if (disk->src->format == VIR_STORAGE_FILE_QCOW2)
            flags |= VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA;
        break;

    case VIR_STORAGE_TYPE_VOLUME:
        if (!(pool = virStoragePoolLookupByName(conn, disk->src->srcpool->pool)))
            goto cleanup;
        format = virStorageFileFormatTypeToString(disk->src->format);
        volName = disk->src->srcpool->volume;
        if (disk->src->format == VIR_STORAGE_FILE_QCOW2)
            flags |= VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA;
        break;

1586 1587 1588 1589 1590
    case VIR_STORAGE_TYPE_NETWORK:
        VIR_DEBUG("Skipping creation of network disk '%s'",
                  disk->dst);
        return 0;

1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
    case VIR_STORAGE_TYPE_BLOCK:
    case VIR_STORAGE_TYPE_DIR:
    case VIR_STORAGE_TYPE_NONE:
    case VIR_STORAGE_TYPE_LAST:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot precreate storage for disk type '%s'"),
                       virStorageTypeToString(disk->src->type));
        goto cleanup;
        break;
    }

    if ((vol = virStorageVolLookupByName(pool, volName))) {
        VIR_DEBUG("Skipping creation of already existing volume of name '%s'",
                  volName);
        ret = 0;
        goto cleanup;
    }

    virBufferAddLit(&buf, "<volume>\n");
    virBufferAdjustIndent(&buf, 2);
    virBufferEscapeString(&buf, "<name>%s</name>\n", volName);
    virBufferAsprintf(&buf, "<capacity>%llu</capacity>\n", capacity);
    virBufferAddLit(&buf, "<target>\n");
    virBufferAdjustIndent(&buf, 2);
    virBufferAsprintf(&buf, "<format type='%s'/>\n", format);
    virBufferAdjustIndent(&buf, -2);
    virBufferAddLit(&buf, "</target>\n");
    virBufferAdjustIndent(&buf, -2);
    virBufferAddLit(&buf, "</volume>\n");

    if (!(volStr = virBufferContentAndReset(&buf))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unable to create volume XML"));
        goto cleanup;
    }

    if (!(vol = virStorageVolCreateXML(pool, volStr, flags)))
        goto cleanup;

    ret = 0;
 cleanup:
    VIR_FREE(basePath);
    VIR_FREE(volStr);
    virObjectUnref(vol);
    virObjectUnref(pool);
    return ret;
}

1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
static bool
qemuMigrateDisk(virDomainDiskDef const *disk,
                size_t nmigrate_disks, const char **migrate_disks)
{
    size_t i;

    /* Check if the disk alias is in the list */
    if (nmigrate_disks) {
        for (i = 0; i < nmigrate_disks; i++) {
            if (STREQ(disk->dst, migrate_disks[i]))
                return true;
        }
        return false;
    }

    /* Default is to migrate only non-shared non-readonly disks
     * with source */
    return !disk->src->shared && !disk->src->readonly &&
           virDomainDiskGetSource(disk);
}

1660 1661 1662 1663 1664

static int
qemuMigrationPrecreateStorage(virConnectPtr conn,
                              virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
                              virDomainObjPtr vm,
1665 1666
                              qemuMigrationCookieNBDPtr nbd,
                              size_t nmigrate_disks,
1667 1668
                              const char **migrate_disks,
                              bool incremental)
1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679
{
    int ret = -1;
    size_t i = 0;

    if (!nbd || !nbd->ndisks)
        return 0;

    for (i = 0; i < nbd->ndisks; i++) {
        virDomainDiskDefPtr disk;
        const char *diskSrcPath;

1680
        VIR_DEBUG("Looking up disk target '%s' (capacity=%llu)",
1681 1682
                  nbd->disks[i].target, nbd->disks[i].capacity);

1683 1684
        if (!(disk = virDomainDiskByName(vm->def, nbd->disks[i].target,
                                         false))) {
1685 1686 1687 1688 1689 1690 1691 1692
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unable to find disk by target: %s"),
                           nbd->disks[i].target);
            goto cleanup;
        }

        diskSrcPath = virDomainDiskGetSource(disk);

1693 1694
        /* Skip disks we don't want to migrate and already existing disks. */
        if (!qemuMigrateDisk(disk, nmigrate_disks, migrate_disks) ||
1695 1696 1697 1698
            (diskSrcPath && virFileExists(diskSrcPath))) {
            continue;
        }

1699 1700 1701 1702 1703 1704 1705
        if (incremental) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("pre-creation of storage targets for incremental "
                             "storage migration is not supported"));
            goto cleanup;
        }

1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717
        VIR_DEBUG("Proceeding with disk source %s", NULLSTR(diskSrcPath));

        if (qemuMigrationPrecreateDisk(conn, disk, nbd->disks[i].capacity) < 0)
            goto cleanup;
    }

    ret = 0;
 cleanup:
    return ret;
}


1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
/**
 * 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 已提交
1732
                            virDomainObjPtr vm,
1733 1734
                            const char *listenAddr,
                            size_t nmigrate_disks,
1735 1736
                            const char **migrate_disks,
                            int nbdPort)
1737 1738 1739 1740 1741 1742 1743
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    unsigned short port = 0;
    char *diskAlias = NULL;
    size_t i;

1744 1745 1746 1747 1748 1749
    if (nbdPort < 0 || nbdPort > USHRT_MAX) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("nbd port must be in range 0-65535"));
        return -1;
    }

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

1753 1754
        /* check whether disk should be migrated */
        if (!qemuMigrateDisk(disk, nmigrate_disks, migrate_disks))
1755 1756 1757 1758
            continue;

        VIR_FREE(diskAlias);
        if (virAsprintf(&diskAlias, "%s%s",
1759
                        QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0)
1760 1761 1762 1763 1764 1765
            goto cleanup;

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

1766 1767 1768 1769 1770 1771 1772 1773
        if (port == 0) {
            if (nbdPort)
                port = nbdPort;
            else if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0)
                goto exit_monitor;

            if (qemuMonitorNBDServerStart(priv->mon, listenAddr, port) < 0)
                goto exit_monitor;
1774 1775
        }

1776 1777 1778
        if (qemuMonitorNBDServerAdd(priv->mon, diskAlias, true) < 0)
            goto exit_monitor;
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
1779 1780 1781 1782 1783 1784
            goto cleanup;
    }

    priv->nbdPort = port;
    ret = 0;

1785
 cleanup:
1786
    VIR_FREE(diskAlias);
1787
    if (ret < 0 && nbdPort == 0)
1788
        virPortAllocatorRelease(driver->migrationPorts, port);
1789
    return ret;
1790 1791 1792 1793

 exit_monitor:
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
    goto cleanup;
1794 1795
}

1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822

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

    if (!mig->nbd)
        return 0;

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

    if (qemuMonitorNBDServerStop(priv->mon) < 0)
        VIR_WARN("Unable to stop NBD server");
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        return -1;

    virPortAllocatorRelease(driver->migrationPorts, priv->nbdPort);
    priv->nbdPort = 0;
    return 0;
}


/**
1823
 * qemuMigrationDriveMirrorReady:
1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835
 * @driver: qemu driver
 * @vm: domain
 *
 * Check the status of all drive-mirrors started by
 * qemuMigrationDriveMirror. Any pending block job events
 * for the mirrored disks will be processed.
 *
 * Returns 1 if all mirrors are "ready",
 *         0 if some mirrors are still performing initial sync,
 *        -1 on error.
 */
static int
1836
qemuMigrationDriveMirrorReady(virQEMUDriverPtr driver,
1837 1838 1839
                              virDomainObjPtr vm)
{
    size_t i;
1840 1841
    size_t notReady = 0;
    int status;
1842 1843 1844

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

1847
        if (!diskPriv->migrating)
1848 1849
            continue;

1850 1851
        status = qemuBlockJobUpdate(driver, vm, disk);
        if (status == VIR_DOMAIN_BLOCK_JOB_FAILED) {
1852 1853 1854 1855 1856
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("migration of disk %s failed"),
                           disk->dst);
            return -1;
        }
1857 1858 1859

        if (disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_READY)
            notReady++;
1860 1861
    }

1862 1863 1864 1865 1866 1867 1868
    if (notReady) {
        VIR_DEBUG("Waiting for %zu disk mirrors to get ready", notReady);
        return 0;
    } else {
        VIR_DEBUG("All disk mirrors are ready");
        return 1;
    }
1869 1870 1871
}


1872 1873 1874 1875
/*
 * If @check is true, the function will report an error and return a different
 * code in case a block job fails. This way we can properly abort migration in
 * case some block jobs failed once all memory has already been transferred.
1876
 *
1877 1878 1879 1880
 * Returns 1 if all mirrors are gone,
 *         0 if some mirrors are still active,
 *         -1 some mirrors failed but some are still active,
 *         -2 all mirrors are gone but some of them failed.
1881 1882
 */
static int
1883
qemuMigrationDriveMirrorCancelled(virQEMUDriverPtr driver,
1884
                                  virDomainObjPtr vm,
1885
                                  bool check)
1886
{
1887 1888 1889 1890
    size_t i;
    size_t active = 0;
    int status;
    bool failed = false;
1891

1892 1893 1894
    for (i = 0; i < vm->def->ndisks; i++) {
        virDomainDiskDefPtr disk = vm->def->disks[i];
        qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
1895

1896 1897
        if (!diskPriv->migrating)
            continue;
1898

1899 1900 1901 1902
        status = qemuBlockJobUpdate(driver, vm, disk);
        switch (status) {
        case VIR_DOMAIN_BLOCK_JOB_FAILED:
            if (check) {
1903
                virReportError(VIR_ERR_OPERATION_FAILED,
1904
                               _("migration of disk %s failed"),
1905
                               disk->dst);
1906
                failed = true;
1907
            }
1908 1909 1910 1911 1912 1913
            /* fallthrough */
        case VIR_DOMAIN_BLOCK_JOB_CANCELED:
        case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
            qemuBlockJobSyncEnd(driver, vm, disk);
            diskPriv->migrating = false;
            break;
1914

1915 1916
        default:
            active++;
1917
        }
1918
    }
1919

1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935
    if (failed) {
        if (active) {
            VIR_DEBUG("Some disk mirrors failed; still waiting for %zu "
                      "disk mirrors to finish", active);
            return -1;
        } else {
            VIR_DEBUG("All disk mirrors are gone; some of them failed");
            return -2;
        }
    } else {
        if (active) {
            VIR_DEBUG("Waiting for %zu disk mirrors to finish", active);
            return 0;
        } else {
            VIR_DEBUG("All disk mirrors are gone");
            return 1;
1936
        }
1937
    }
1938
}
1939 1940


1941 1942 1943 1944 1945 1946 1947 1948 1949
/*
 * Returns 0 on success,
 *         1 when job is already completed or it failed and failNoJob is false,
 *         -1 on error or when job failed and failNoJob is true.
 */
static int
qemuMigrationCancelOneDriveMirror(virQEMUDriverPtr driver,
                                  virDomainObjPtr vm,
                                  virDomainDiskDefPtr disk,
1950 1951
                                  bool failNoJob,
                                  qemuDomainAsyncJob asyncJob)
1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *diskAlias = NULL;
    int ret = -1;
    int status;
    int rv;

    status = qemuBlockJobUpdate(driver, vm, disk);
    switch (status) {
    case VIR_DOMAIN_BLOCK_JOB_FAILED:
    case VIR_DOMAIN_BLOCK_JOB_CANCELED:
        if (failNoJob) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("migration of disk %s failed"),
                           disk->dst);
            return -1;
        }
        return 1;

    case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
        return 1;
    }

    if (virAsprintf(&diskAlias, "%s%s",
                    QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0)
        return -1;

1979
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
1980 1981 1982 1983 1984 1985 1986 1987
        goto cleanup;

    rv = qemuMonitorBlockJobCancel(priv->mon, diskAlias, true);

    if (qemuDomainObjExitMonitor(driver, vm) < 0 || rv < 0)
        goto cleanup;

    ret = 0;
1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998

 cleanup:
    VIR_FREE(diskAlias);
    return ret;
}


/**
 * qemuMigrationCancelDriveMirror:
 * @driver: qemu driver
 * @vm: domain
1999
 * @check: if true report an error when some of the mirrors fails
2000 2001 2002 2003 2004 2005 2006 2007 2008
 *
 * Cancel all drive-mirrors started by qemuMigrationDriveMirror.
 * Any pending block job events for the affected disks will be
 * processed.
 *
 * Returns 0 on success, -1 otherwise.
 */
static int
qemuMigrationCancelDriveMirror(virQEMUDriverPtr driver,
2009
                               virDomainObjPtr vm,
2010
                               bool check,
2011 2012
                               qemuDomainAsyncJob asyncJob,
                               virConnectPtr dconn)
2013
{
2014
    virErrorPtr err = NULL;
2015
    int ret = -1;
2016
    size_t i;
2017 2018 2019 2020
    int rv;
    bool failed = false;

    VIR_DEBUG("Cancelling drive mirrors for domain %s", vm->def->name);
2021 2022 2023

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

2026
        if (!diskPriv->migrating)
2027 2028
            continue;

2029 2030
        rv = qemuMigrationCancelOneDriveMirror(driver, vm, disk,
                                               check, asyncJob);
2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042
        if (rv != 0) {
            if (rv < 0) {
                if (!err)
                    err = virSaveLastError();
                failed = true;
            }
            qemuBlockJobSyncEnd(driver, vm, disk);
            diskPriv->migrating = false;
        }
    }

    while ((rv = qemuMigrationDriveMirrorCancelled(driver, vm, check)) != 1) {
2043 2044 2045 2046 2047 2048 2049
        if (check && !failed &&
            dconn && virConnectIsAlive(dconn) <= 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Lost connection to destination host"));
            failed = true;
        }

2050 2051 2052 2053
        if (rv < 0) {
            failed = true;
            if (rv == -2)
                break;
2054
        }
2055

2056 2057 2058 2059 2060
        if (failed && !err)
            err = virSaveLastError();

        if (virDomainObjWait(vm) < 0)
            goto cleanup;
2061 2062
    }

2063 2064 2065
    ret = failed ? -1 : 0;

 cleanup:
2066 2067 2068 2069 2070
    if (err) {
        virSetError(err);
        virFreeError(err);
    }
    return ret;
2071 2072 2073
}


2074 2075 2076 2077 2078 2079
/**
 * qemuMigrationDriveMirror:
 * @driver: qemu driver
 * @vm: domain
 * @mig: migration cookie
 * @host: where are we migrating to
2080
 * @speed: bandwidth limit in MiB/s
2081 2082 2083 2084
 * @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
2085 2086 2087 2088 2089
 * simultaneously to both source and destination. On success,
 * update @migrate_flags so we don't tell 'migrate' command
 * to do the very same operation. On failure, the caller is
 * expected to call qemuMigrationCancelDriveMirror to stop all
 * running mirrors.
2090 2091 2092 2093 2094 2095 2096 2097 2098 2099
 *
 * Returns 0 on success (@migrate_flags updated),
 *        -1 otherwise.
 */
static int
qemuMigrationDriveMirror(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         qemuMigrationCookiePtr mig,
                         const char *host,
                         unsigned long speed,
2100 2101
                         unsigned int *migrate_flags,
                         size_t nmigrate_disks,
2102 2103
                         const char **migrate_disks,
                         virConnectPtr dconn)
2104 2105 2106 2107
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
    int port;
2108
    size_t i;
2109 2110
    char *diskAlias = NULL;
    char *nbd_dest = NULL;
2111
    char *hoststr = NULL;
2112
    unsigned long long mirror_speed = speed;
2113
    unsigned int mirror_flags = VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT;
2114
    int rv;
2115
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
2116 2117

    VIR_DEBUG("Starting drive mirrors for domain %s", vm->def->name);
2118

2119 2120 2121 2122 2123 2124 2125 2126
    if (mirror_speed > LLONG_MAX >> 20) {
        virReportError(VIR_ERR_OVERFLOW,
                       _("bandwidth must be less than %llu"),
                       LLONG_MAX >> 20);
        goto cleanup;
    }
    mirror_speed <<= 20;

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

2131 2132
    /* escape literal IPv6 address */
    if (strchr(host, ':')) {
2133
        if (virAsprintf(&hoststr, "[%s]", host) < 0)
2134
            goto cleanup;
2135
    } else if (VIR_STRDUP(hoststr, host) < 0) {
2136
        goto cleanup;
2137 2138
    }

2139 2140 2141 2142 2143
    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];
2144
        qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
2145
        int mon_ret;
2146

2147 2148
        /* check whether disk should be migrated */
        if (!qemuMigrateDisk(disk, nmigrate_disks, migrate_disks))
2149 2150 2151 2152 2153
            continue;

        if ((virAsprintf(&diskAlias, "%s%s",
                         QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0) ||
            (virAsprintf(&nbd_dest, "nbd:%s:%d:exportname=%s",
2154
                         hoststr, port, diskAlias) < 0))
2155 2156
            goto cleanup;

2157
        if (qemuDomainObjEnterMonitorAsync(driver, vm,
2158
                                           QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
2159 2160
            goto cleanup;

2161
        qemuBlockJobSyncBegin(disk);
2162
        /* Force "raw" format for NBD export */
2163
        mon_ret = qemuMonitorDriveMirror(priv->mon, diskAlias, nbd_dest,
2164
                                         "raw", mirror_speed, 0, 0, mirror_flags);
2165 2166
        VIR_FREE(diskAlias);
        VIR_FREE(nbd_dest);
2167

2168
        if (qemuDomainObjExitMonitor(driver, vm) < 0 || mon_ret < 0) {
2169
            qemuBlockJobSyncEnd(driver, vm, disk);
2170 2171
            goto cleanup;
        }
2172
        diskPriv->migrating = true;
2173

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

2180 2181 2182
    while ((rv = qemuMigrationDriveMirrorReady(driver, vm)) != 1) {
        if (rv < 0)
            goto cleanup;
2183

2184
        if (priv->job.abortJob) {
2185 2186 2187 2188 2189
            priv->job.current->type = VIR_DOMAIN_JOB_CANCELLED;
            virReportError(VIR_ERR_OPERATION_ABORTED, _("%s: %s"),
                           qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
                           _("canceled by client"));
            goto cleanup;
2190
        }
2191

2192 2193 2194 2195 2196 2197
        if (dconn && virConnectIsAlive(dconn) <= 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Lost connection to destination host"));
            goto cleanup;
        }

2198
        if (virDomainObjWait(vm) < 0)
2199
            goto cleanup;
2200 2201
    }

2202
    /* Okay, all disks are ready. Modify migrate_flags */
2203 2204 2205 2206
    *migrate_flags &= ~(QEMU_MONITOR_MIGRATE_NON_SHARED_DISK |
                        QEMU_MONITOR_MIGRATE_NON_SHARED_INC);
    ret = 0;

2207
 cleanup:
2208
    virObjectUnref(cfg);
2209 2210
    VIR_FREE(diskAlias);
    VIR_FREE(nbd_dest);
2211
    VIR_FREE(hoststr);
2212 2213
    return ret;
}
2214

2215

2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243
/**
 * qemuMigrationIsAllowedHostdev:
 * @def: domain definition
 *
 * Checks that @def does not contain any host devices unsupported accross
 * migrations. Returns true if the vm is allowed to migrate.
 */
static bool
qemuMigrationIsAllowedHostdev(const virDomainDef *def)
{
    size_t i;

    /* Migration with USB host devices is allowed, all other devices are
     * forbidden. */
    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) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("domain has assigned non-USB host devices"));
            return false;
        }
    }

    return true;
}


2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257
/**
 * qemuMigrationIsAllowed:
 * @driver: qemu driver struct
 * @vm: domain object
 * @remote: migration is remote
 * @flags: migration flags (see struct virDomainMigrateFlags)
 *
 * Validates that the configuration of @vm can be migrated in various
 * situations. If @remote is true, the migration happens to remote host. @flags
 * is used to check various special migration types according to the request.
 *
 * Returns true if migration is supported. Reports libvirt error and returns
 * false otherwise.
 */
2258
bool
2259 2260 2261
qemuMigrationIsAllowed(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       bool remote,
2262
                       unsigned int flags)
2263
{
2264
    int nsnapshots;
2265
    int pauseReason;
2266
    size_t i;
2267

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

2274 2275 2276 2277 2278
        if (nsnapshots > 0) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("cannot migrate domain with %d snapshots"),
                           nsnapshots);
            return false;
2279
        }
2280

2281
        /* cancel migration if disk I/O error is emitted while migrating */
2282
        if (flags & VIR_MIGRATE_ABORT_ON_ERROR &&
2283
            !(flags & VIR_MIGRATE_OFFLINE) &&
2284 2285
            virDomainObjGetState(vm, &pauseReason) == VIR_DOMAIN_PAUSED &&
            pauseReason == VIR_DOMAIN_PAUSED_IOERROR) {
E
Eric Blake 已提交
2286
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2287
                           _("cannot migrate domain with I/O error"));
E
Eric Blake 已提交
2288 2289
            return false;
        }
2290 2291

    }
2292

2293 2294 2295 2296 2297 2298 2299
    /* following checks don't make sense for offline migration */
    if (!(flags & VIR_MIGRATE_OFFLINE)) {
        if (qemuProcessAutoDestroyActive(driver, vm)) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is marked for auto destroy"));
            return false;
        }
2300

2301

2302 2303
        if (qemuDomainHasBlockjob(vm, false)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2304
                           _("domain has active block job"));
2305 2306 2307 2308 2309 2310 2311 2312 2313
            return false;
        }

        if (!qemuMigrationIsAllowedHostdev(vm->def))
            return false;

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

2315 2316
                if (feature->policy != VIR_CPU_FEATURE_REQUIRE)
                    continue;
J
Ján Tomko 已提交
2317

2318 2319 2320 2321 2322 2323 2324
                /* 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;
                }
2325
            }
J
Ján Tomko 已提交
2326 2327
        }

2328 2329 2330
        /* Verify that memory device config can be transferred reliably */
        for (i = 0; i < vm->def->nmems; i++) {
            virDomainMemoryDefPtr mem = vm->def->mems[i];
2331

2332 2333 2334 2335 2336
            if (mem->model == VIR_DOMAIN_MEMORY_MODEL_DIMM &&
                mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM) {
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("domain's dimm info lacks slot ID "
                                 "or base address"));
2337

2338 2339
                return false;
            }
2340 2341 2342
        }
    }

2343 2344 2345
    return true;
}

2346
static bool
2347 2348 2349
qemuMigrationIsSafe(virDomainDefPtr def,
                    size_t nmigrate_disks,
                    const char **migrate_disks)
2350
{
2351
    size_t i;
2352

2353
    for (i = 0; i < def->ndisks; i++) {
2354
        virDomainDiskDefPtr disk = def->disks[i];
2355
        const char *src = virDomainDiskGetSource(disk);
2356

2357 2358
        /* Our code elsewhere guarantees shared disks are either readonly (in
         * which case cache mode doesn't matter) or used with cache=none */
2359
        if (qemuMigrateDisk(disk, nmigrate_disks, migrate_disks) &&
2360
            disk->cachemode != VIR_DOMAIN_DISK_CACHE_DISABLE) {
2361
            int rc;
2362

E
Eric Blake 已提交
2363
            if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_FILE) {
2364
                if ((rc = virFileIsSharedFS(src)) < 0)
2365 2366
                    return false;
                else if (rc == 0)
2367
                    continue;
2368
                if ((rc = virStorageFileIsClusterFS(src)) < 0)
2369
                    return false;
2370 2371
                else if (rc == 1)
                    continue;
2372 2373
            } else if (disk->src->type == VIR_STORAGE_TYPE_NETWORK &&
                       disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD) {
2374
                continue;
2375
            }
2376

2377 2378 2379
            virReportError(VIR_ERR_MIGRATE_UNSAFE, "%s",
                           _("Migration may lead to data corruption if disks"
                             " use cache != none"));
2380 2381 2382 2383 2384 2385 2386
            return false;
        }
    }

    return true;
}

2387 2388 2389 2390
/** qemuMigrationSetOffline
 * Pause domain for non-live migration.
 */
int
2391
qemuMigrationSetOffline(virQEMUDriverPtr driver,
2392 2393 2394
                        virDomainObjPtr vm)
{
    int ret;
2395
    VIR_DEBUG("driver=%p vm=%p", driver, vm);
2396 2397
    ret = qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_MIGRATION,
                              QEMU_ASYNC_JOB_MIGRATION_OUT);
2398
    if (ret == 0) {
2399
        virObjectEventPtr event;
2400

2401
        event = virDomainEventLifecycleNewFromObj(vm,
2402 2403
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
2404
        qemuDomainEventQueue(driver, event);
2405 2406 2407 2408 2409
    }

    return ret;
}

2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451

void
qemuMigrationPostcopyFailed(virQEMUDriverPtr driver,
                            virDomainObjPtr vm)
{
    virDomainState state;
    int reason;

    state = virDomainObjGetState(vm, &reason);

    if (state != VIR_DOMAIN_PAUSED &&
        state != VIR_DOMAIN_RUNNING)
        return;

    if (state == VIR_DOMAIN_PAUSED &&
        reason == VIR_DOMAIN_PAUSED_POSTCOPY_FAILED)
        return;

    VIR_WARN("Migration of domain %s failed during post-copy; "
             "leaving the domain paused", vm->def->name);

    if (state == VIR_DOMAIN_RUNNING) {
        virObjectEventPtr event;

        if (qemuProcessStopCPUs(driver, vm,
                                VIR_DOMAIN_PAUSED_POSTCOPY_FAILED,
                                QEMU_ASYNC_JOB_MIGRATION_IN) < 0) {
            VIR_WARN("Unable to pause guest CPUs for %s", vm->def->name);
            return;
        }

        event = virDomainEventLifecycleNewFromObj(vm,
                                VIR_DOMAIN_EVENT_SUSPENDED,
                                VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED);
        qemuDomainEventQueue(driver, event);
    } else {
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                             VIR_DOMAIN_PAUSED_POSTCOPY_FAILED);
    }
}


2452
static int
2453
qemuMigrationSetOption(virQEMUDriverPtr driver,
2454
                       virDomainObjPtr vm,
2455
                       qemuMonitorMigrationCaps capability,
2456
                       bool state,
2457 2458 2459 2460 2461 2462 2463 2464
                       qemuDomainAsyncJob job)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret;

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

2465
    ret = qemuMonitorGetMigrationCapability(priv->mon, capability);
2466 2467 2468

    if (ret < 0) {
        goto cleanup;
2469 2470 2471
    } else if (ret == 0 && !state) {
        /* Unsupported but we want it off anyway */
        goto cleanup;
2472 2473
    } else if (ret == 0) {
        if (job == QEMU_ASYNC_JOB_MIGRATION_IN) {
2474 2475 2476 2477
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                           _("Migration option '%s' is not supported by "
                             "target QEMU binary"),
                           qemuMonitorMigrationCapsTypeToString(capability));
2478
        } else {
2479 2480 2481 2482
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                           _("Migration option '%s' is not supported by "
                             "source QEMU binary"),
                           qemuMonitorMigrationCapsTypeToString(capability));
2483 2484 2485 2486 2487
        }
        ret = -1;
        goto cleanup;
    }

2488
    ret = qemuMonitorSetMigrationCapability(priv->mon, capability, state);
2489 2490

 cleanup:
2491 2492
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        ret = -1;
2493 2494 2495
    return ret;
}

2496 2497 2498 2499 2500 2501 2502

static int
qemuMigrationSetPostCopy(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         bool state,
                         qemuDomainAsyncJob job)
{
2503 2504
    qemuDomainObjPrivatePtr priv = vm->privateData;

2505 2506 2507 2508 2509
    if (qemuMigrationSetOption(driver, vm,
                               QEMU_MONITOR_MIGRATION_CAPS_POSTCOPY,
                               state, job) < 0)
        return -1;

2510
    priv->job.postcopyEnabled = state;
2511 2512 2513 2514
    return 0;
}


2515
static int
2516
qemuMigrationWaitForSpice(virDomainObjPtr vm)
2517 2518 2519
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    bool wait_for_spice = false;
2520
    size_t i = 0;
2521

2522 2523
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_SEAMLESS_MIGRATION) ||
        !priv->job.spiceMigration)
2524 2525 2526 2527 2528 2529
        return 0;

    for (i = 0; i < vm->def->ngraphics; i++) {
        if (vm->def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
            wait_for_spice = true;
            break;
2530 2531
        }
    }
2532 2533 2534 2535

    if (!wait_for_spice)
        return 0;

2536
    VIR_DEBUG("Waiting for SPICE to finish migration");
2537 2538
    while (!priv->job.spiceMigrated && !priv->job.abortJob) {
        if (virDomainObjWait(vm) < 0)
2539 2540 2541 2542
            return -1;
    }
    return 0;
}
2543

2544 2545 2546 2547

static void
qemuMigrationUpdateJobType(qemuDomainJobInfoPtr jobInfo)
{
2548
    switch ((qemuMonitorMigrationStatus) jobInfo->stats.status) {
2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566
    case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED:
        jobInfo->type = VIR_DOMAIN_JOB_COMPLETED;
        break;

    case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
        jobInfo->type = VIR_DOMAIN_JOB_NONE;
        break;

    case QEMU_MONITOR_MIGRATION_STATUS_ERROR:
        jobInfo->type = VIR_DOMAIN_JOB_FAILED;
        break;

    case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED:
        jobInfo->type = VIR_DOMAIN_JOB_CANCELLED;
        break;

    case QEMU_MONITOR_MIGRATION_STATUS_SETUP:
    case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE:
2567
    case QEMU_MONITOR_MIGRATION_STATUS_POSTCOPY:
2568
    case QEMU_MONITOR_MIGRATION_STATUS_CANCELLING:
2569
    case QEMU_MONITOR_MIGRATION_STATUS_LAST:
2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586
        break;
    }
}


int
qemuMigrationFetchJobStatus(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            qemuDomainAsyncJob asyncJob,
                            qemuDomainJobInfoPtr jobInfo)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int rv;

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

2587 2588
    memset(&jobInfo->stats, 0, sizeof(jobInfo->stats));
    rv = qemuMonitorGetMigrationStats(priv->mon, &jobInfo->stats);
2589 2590 2591 2592 2593 2594 2595 2596 2597

    if (qemuDomainObjExitMonitor(driver, vm) < 0 || rv < 0)
        return -1;

    qemuMigrationUpdateJobType(jobInfo);
    return qemuDomainJobInfoUpdateTime(jobInfo);
}


2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615
static const char *
qemuMigrationJobName(virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

    switch (priv->job.asyncJob) {
    case QEMU_ASYNC_JOB_MIGRATION_OUT:
        return _("migration job");
    case QEMU_ASYNC_JOB_SAVE:
        return _("domain save job");
    case QEMU_ASYNC_JOB_DUMP:
        return _("domain core dump job");
    default:
        return _("job");
    }
}


2616
static int
2617
qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
2618
                             virDomainObjPtr vm,
2619
                             qemuDomainAsyncJob asyncJob)
2620
{
2621
    qemuDomainObjPrivatePtr priv = vm->privateData;
2622 2623
    qemuDomainJobInfoPtr jobInfo = priv->job.current;
    qemuDomainJobInfo newInfo = *jobInfo;
2624

2625 2626
    if (qemuMigrationFetchJobStatus(driver, vm, asyncJob, &newInfo) < 0)
        return -1;
2627

2628 2629 2630
    *jobInfo = newInfo;
    return 0;
}
2631

2632

2633 2634 2635
static int
qemuMigrationCheckJobStatus(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
2636 2637
                            qemuDomainAsyncJob asyncJob,
                            bool updateJobStats)
2638 2639 2640
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    qemuDomainJobInfoPtr jobInfo = priv->job.current;
2641

2642 2643 2644 2645 2646
    bool events = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_EVENT);

    if (events)
        qemuMigrationUpdateJobType(jobInfo);
    else if (qemuMigrationUpdateJobStatus(driver, vm, asyncJob) < 0)
2647
        return -1;
2648

2649 2650
    switch (jobInfo->type) {
    case VIR_DOMAIN_JOB_NONE:
2651 2652
        virReportError(VIR_ERR_OPERATION_FAILED, _("%s: %s"),
                       qemuMigrationJobName(vm), _("is not active"));
2653
        return -1;
2654

2655
    case VIR_DOMAIN_JOB_FAILED:
2656 2657
        virReportError(VIR_ERR_OPERATION_FAILED, _("%s: %s"),
                       qemuMigrationJobName(vm), _("unexpectedly failed"));
2658
        return -1;
2659

2660
    case VIR_DOMAIN_JOB_CANCELLED:
2661 2662
        virReportError(VIR_ERR_OPERATION_ABORTED, _("%s: %s"),
                       qemuMigrationJobName(vm), _("canceled by client"));
2663 2664
        return -1;

2665 2666
    case VIR_DOMAIN_JOB_COMPLETED:
        /* Fetch statistics of a completed migration */
2667
        if (events && updateJobStats &&
2668 2669 2670 2671
            qemuMigrationUpdateJobStatus(driver, vm, asyncJob) < 0)
            return -1;
        break;

2672 2673 2674
    case VIR_DOMAIN_JOB_BOUNDED:
    case VIR_DOMAIN_JOB_UNBOUNDED:
    case VIR_DOMAIN_JOB_LAST:
2675 2676
        break;
    }
2677
    return 0;
2678 2679 2680
}


2681 2682 2683
enum qemuMigrationCompletedFlags {
    QEMU_MIGRATION_COMPLETED_ABORT_ON_ERROR = (1 << 0),
    QEMU_MIGRATION_COMPLETED_CHECK_STORAGE  = (1 << 1),
2684
    QEMU_MIGRATION_COMPLETED_UPDATE_STATS   = (1 << 2),
2685
    QEMU_MIGRATION_COMPLETED_POSTCOPY       = (1 << 3),
2686 2687
};

2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698
/**
 * Returns 1 if migration completed successfully,
 *         0 if the domain is still being migrated,
 *         -1 migration failed,
 *         -2 something else failed, we need to cancel migration.
 */
static int
qemuMigrationCompleted(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       qemuDomainAsyncJob asyncJob,
                       virConnectPtr dconn,
2699
                       unsigned int flags)
2700 2701 2702 2703
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    qemuDomainJobInfoPtr jobInfo = priv->job.current;
    int pauseReason;
2704
    bool updateStats = !!(flags & QEMU_MIGRATION_COMPLETED_UPDATE_STATS);
2705

2706
    if (qemuMigrationCheckJobStatus(driver, vm, asyncJob, updateStats) < 0)
2707 2708
        goto error;

2709 2710
    if (flags & QEMU_MIGRATION_COMPLETED_CHECK_STORAGE &&
        qemuMigrationDriveMirrorReady(driver, vm) < 0)
2711 2712
        goto error;

2713
    if (flags & QEMU_MIGRATION_COMPLETED_ABORT_ON_ERROR &&
2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726
        virDomainObjGetState(vm, &pauseReason) == VIR_DOMAIN_PAUSED &&
        pauseReason == VIR_DOMAIN_PAUSED_IOERROR) {
        virReportError(VIR_ERR_OPERATION_FAILED, _("%s: %s"),
                       qemuMigrationJobName(vm), _("failed due to I/O error"));
        goto error;
    }

    if (dconn && virConnectIsAlive(dconn) <= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Lost connection to destination host"));
        goto error;
    }

2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740
    /* In case of postcopy the source considers migration completed at the
     * moment it switched from active to postcopy-active state. The destination
     * will continue waiting until the migrate state changes to completed.
     */
    if (flags & QEMU_MIGRATION_COMPLETED_POSTCOPY &&
        jobInfo->type == VIR_DOMAIN_JOB_UNBOUNDED &&
        jobInfo->stats.status == QEMU_MONITOR_MIGRATION_STATUS_POSTCOPY) {
        VIR_DEBUG("Migration switched to post-copy");
        if (updateStats &&
            qemuMigrationUpdateJobStatus(driver, vm, asyncJob) < 0)
            goto error;
        return 1;
    }

2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759
    if (jobInfo->type == VIR_DOMAIN_JOB_COMPLETED)
        return 1;
    else
        return 0;

 error:
    if (jobInfo->type == VIR_DOMAIN_JOB_UNBOUNDED) {
        /* The migration was aborted by us rather than QEMU itself. */
        jobInfo->type = VIR_DOMAIN_JOB_FAILED;
        return -2;
    } else if (jobInfo->type == VIR_DOMAIN_JOB_COMPLETED) {
        jobInfo->type = VIR_DOMAIN_JOB_FAILED;
        return -1;
    } else {
        return -1;
    }
}


2760 2761 2762
/* Returns 0 on success, -2 when migration needs to be cancelled, or -1 when
 * QEMU reports failed migration.
 */
2763
static int
J
Jiri Denemark 已提交
2764 2765
qemuMigrationWaitForCompletion(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
2766
                               qemuDomainAsyncJob asyncJob,
J
Jiri Denemark 已提交
2767
                               virConnectPtr dconn,
2768
                               unsigned int flags)
2769
{
2770
    qemuDomainObjPrivatePtr priv = vm->privateData;
J
Jiri Denemark 已提交
2771
    qemuDomainJobInfoPtr jobInfo = priv->job.current;
2772
    bool events = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_EVENT);
2773
    int rv;
2774

2775
    flags |= QEMU_MIGRATION_COMPLETED_UPDATE_STATS;
2776

J
Jiri Denemark 已提交
2777
    jobInfo->type = VIR_DOMAIN_JOB_UNBOUNDED;
2778 2779
    while ((rv = qemuMigrationCompleted(driver, vm, asyncJob,
                                        dconn, flags)) != 1) {
2780 2781
        if (rv < 0)
            return rv;
2782

2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795
        if (events) {
            if (virDomainObjWait(vm) < 0) {
                jobInfo->type = VIR_DOMAIN_JOB_FAILED;
                return -2;
            }
        } else {
            /* Poll every 50ms for progress & to allow cancellation */
            struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };

            virObjectUnlock(vm);
            nanosleep(&ts, NULL);
            virObjectLock(vm);
        }
2796 2797
    }

2798 2799 2800 2801 2802
    qemuDomainJobInfoUpdateDowntime(jobInfo);
    VIR_FREE(priv->job.completed);
    if (VIR_ALLOC(priv->job.completed) == 0)
        *priv->job.completed = *jobInfo;

2803
    return 0;
2804 2805 2806
}


2807 2808 2809
static int
qemuMigrationWaitForDestCompletion(virQEMUDriverPtr driver,
                                   virDomainObjPtr vm,
2810 2811
                                   qemuDomainAsyncJob asyncJob,
                                   bool postcopy)
2812 2813
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
2814
    unsigned int flags = 0;
2815 2816 2817 2818 2819 2820 2821
    int rv;

    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_EVENT))
        return 0;

    VIR_DEBUG("Waiting for incoming migration to complete");

2822 2823 2824 2825 2826
    if (postcopy)
        flags = QEMU_MIGRATION_COMPLETED_POSTCOPY;

    while ((rv = qemuMigrationCompleted(driver, vm, asyncJob,
                                        NULL, flags)) != 1) {
2827 2828 2829 2830 2831 2832 2833 2834
        if (rv < 0 || virDomainObjWait(vm) < 0)
            return -1;
    }

    return 0;
}


2835
static int
2836
qemuDomainMigrateGraphicsRelocate(virQEMUDriverPtr driver,
2837
                                  virDomainObjPtr vm,
2838 2839
                                  qemuMigrationCookiePtr cookie,
                                  const char *graphicsuri)
2840 2841
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
2842 2843
    int ret = -1;
    const char *listenAddress = NULL;
2844
    virSocketAddr addr;
2845 2846 2847 2848 2849
    virURIPtr uri = NULL;
    int type = -1;
    int port = -1;
    int tlsPort = -1;
    const char *tlsSubject = NULL;
2850

2851
    if (!cookie || (!cookie->graphics && !graphicsuri))
2852 2853
        return 0;

2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872
    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) {
2873
        size_t i;
2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900

        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;
            }
        }
    }
2901 2902 2903 2904

    /* QEMU doesn't support VNC relocation yet, so
     * skip it to avoid generating an error
     */
2905 2906 2907 2908
    if (type != VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
        ret = 0;
        goto cleanup;
    }
2909

2910 2911 2912 2913
    if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                       QEMU_ASYNC_JOB_MIGRATION_OUT) == 0) {
        ret = qemuMonitorGraphicsRelocate(priv->mon, type, listenAddress,
                                          port, tlsPort, tlsSubject);
2914
        priv->job.spiceMigration = !ret;
2915 2916
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            ret = -1;
2917
    }
2918

2919
 cleanup:
2920
    virURIFree(uri);
2921 2922 2923 2924
    return ret;
}


2925
static int
2926
qemuDomainMigrateOPDRelocate(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
2927 2928 2929
                             virDomainObjPtr vm,
                             qemuMigrationCookiePtr cookie)
{
2930 2931
    virDomainNetDefPtr netptr;
    int ret = -1;
2932
    size_t i;
2933 2934 2935 2936 2937 2938 2939 2940

    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:
2941
           break;
2942
        case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
2943 2944
            if (virNetDevOpenvswitchSetMigrateData(cookie->network->net[i].portdata,
                                                   netptr->ifname) != 0) {
J
Jiri Denemark 已提交
2945 2946 2947
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to run command to set OVS port data for "
                                 "interface %s"), netptr->ifname);
2948 2949 2950
                goto cleanup;
            }
            break;
2951 2952 2953 2954 2955
        default:
            break;
        }
    }

2956
    ret = 0;
2957
 cleanup:
2958 2959 2960 2961
    return ret;
}


2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001
int
qemuMigrationCheckIncoming(virQEMUCapsPtr qemuCaps,
                           const char *migrateFrom)
{
    if (STRPREFIX(migrateFrom, "rdma")) {
        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MIGRATE_RDMA)) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("incoming RDMA migration is not supported "
                             "with this QEMU binary"));
            return -1;
        }
    } else if (!STRPREFIX(migrateFrom, "tcp") &&
               !STRPREFIX(migrateFrom, "exec") &&
               !STRPREFIX(migrateFrom, "fd") &&
               !STRPREFIX(migrateFrom, "unix") &&
               STRNEQ(migrateFrom, "stdio")) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("unknown migration protocol"));
        return -1;
    }

    return 0;
}


char *
qemuMigrationIncomingURI(const char *migrateFrom,
                         int migrateFd)
{
    char *uri = NULL;

    if (STREQ(migrateFrom, "stdio"))
        ignore_value(virAsprintf(&uri, "fd:%d", migrateFd));
    else
        ignore_value(VIR_STRDUP(uri, migrateFrom));

    return uri;
}


3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027
int
qemuMigrationRunIncoming(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         const char *uri,
                         qemuDomainAsyncJob asyncJob)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
    int rv;

    VIR_DEBUG("Setting up incoming migration with URI %s", uri);

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

    rv = qemuMonitorMigrateIncoming(priv->mon, uri);

    if (qemuDomainObjExitMonitor(driver, vm) < 0 || rv < 0)
        goto cleanup;

    if (asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
        /* qemuMigrationWaitForDestCompletion is called from the Finish phase */
        ret = 0;
        goto cleanup;
    }

3028
    if (qemuMigrationWaitForDestCompletion(driver, vm, asyncJob, false) < 0)
3029 3030 3031 3032 3033 3034 3035 3036 3037
        goto cleanup;

    ret = 0;

 cleanup:
    return ret;
}


3038 3039 3040 3041 3042 3043
/* 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.
 */
3044 3045 3046 3047
static virDomainObjPtr
qemuMigrationCleanup(virDomainObjPtr vm,
                     virConnectPtr conn,
                     void *opaque)
3048
{
3049
    virQEMUDriverPtr driver = opaque;
3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064
    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);

3065
    switch ((qemuMigrationJobPhase) priv->job.phase) {
3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095
    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 */
        ;
    }

3096
 cleanup:
3097 3098 3099
    return vm;
}

3100

3101
/* The caller is supposed to lock the vm and start a migration job. */
3102 3103 3104 3105 3106 3107 3108
static char *
qemuMigrationBeginPhase(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
                        const char *xmlin,
                        const char *dname,
                        char **cookieout,
                        int *cookieoutlen,
3109 3110
                        size_t nmigrate_disks,
                        const char **migrate_disks,
3111
                        unsigned long flags)
3112 3113 3114
{
    char *rv = NULL;
    qemuMigrationCookiePtr mig = NULL;
3115
    virDomainDefPtr def = NULL;
3116
    qemuDomainObjPrivatePtr priv = vm->privateData;
3117
    virCapsPtr caps = NULL;
3118
    unsigned int cookieFlags = QEMU_MIGRATION_COOKIE_LOCKSTATE;
3119

3120
    VIR_DEBUG("driver=%p, vm=%p, xmlin=%s, dname=%s,"
3121 3122
              " cookieout=%p, cookieoutlen=%p,"
              " nmigrate_disks=%zu, migrate_disks=%p, flags=%lx",
3123
              driver, vm, NULLSTR(xmlin), NULLSTR(dname),
3124 3125
              cookieout, cookieoutlen, nmigrate_disks,
              migrate_disks, flags);
3126

3127 3128 3129
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

3130 3131 3132 3133 3134 3135
    /* 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);
3136

3137
    if (!qemuMigrationIsAllowed(driver, vm, true, flags))
3138 3139
        goto cleanup;

3140 3141
    if (!(flags & VIR_MIGRATE_UNSAFE) &&
        !qemuMigrationIsSafe(vm->def, nmigrate_disks, migrate_disks))
3142 3143
        goto cleanup;

3144 3145 3146 3147 3148 3149 3150 3151 3152
    if (flags & VIR_MIGRATE_POSTCOPY &&
        (!(flags & VIR_MIGRATE_LIVE) ||
         flags & VIR_MIGRATE_PAUSED)) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("post-copy migration is not supported with non-live "
                         "or paused migration"));
        goto cleanup;
    }

3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195
    if (flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC)) {
        bool has_drive_mirror =  virQEMUCapsGet(priv->qemuCaps,
                                                QEMU_CAPS_DRIVE_MIRROR);

        if (nmigrate_disks) {
            if (has_drive_mirror) {
                size_t i, j;
                /* Check user requested only known disk targets. */
                for (i = 0; i < nmigrate_disks; i++) {
                    for (j = 0; j < vm->def->ndisks; j++) {
                        if (STREQ(vm->def->disks[j]->dst, migrate_disks[i]))
                            break;
                    }

                    if (j == vm->def->ndisks) {
                        virReportError(VIR_ERR_INVALID_ARG,
                                       _("disk target %s not found"),
                                       migrate_disks[i]);
                        goto cleanup;
                    }
                }

                if (flags & VIR_MIGRATE_TUNNELLED) {
                    virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                                   _("Selecting disks to migrate is not "
                                     "implemented for tunnelled migration"));
                    goto cleanup;
                }
            } else {
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                               _("qemu does not support drive-mirror command"));
                goto cleanup;
            }
        }

        if (has_drive_mirror) {
            /* TODO support NBD for TUNNELLED migration */
            if (flags & VIR_MIGRATE_TUNNELLED) {
                VIR_WARN("NBD in tunnelled migration is currently not supported");
            } else {
                cookieFlags |= QEMU_MIGRATION_COOKIE_NBD;
                priv->nbdPort = 0;
            }
3196 3197 3198
        }
    }

3199
    if (virDomainDefHasMemoryHotplug(vm->def) ||
3200
        ((flags & VIR_MIGRATE_PERSIST_DEST) &&
3201
         vm->newDef && virDomainDefHasMemoryHotplug(vm->newDef)))
3202 3203
        cookieFlags |= QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG;

3204
    if (!(mig = qemuMigrationEatCookie(driver, vm, NULL, 0, 0)))
3205 3206 3207 3208
        goto cleanup;

    if (qemuMigrationBakeCookie(mig, driver, vm,
                                cookieout, cookieoutlen,
3209
                                cookieFlags) < 0)
3210 3211
        goto cleanup;

L
liguang 已提交
3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233
    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;
        }
    }

3234
    if (xmlin) {
3235
        if (!(def = virDomainDefParseString(xmlin, caps, driver->xmlopt,
3236 3237
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                            VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
3238 3239
            goto cleanup;

3240
        if (!qemuDomainDefCheckABIStability(driver, vm->def, def))
3241 3242
            goto cleanup;

3243
        rv = qemuDomainDefFormatLive(driver, def, false, true);
3244
    } else {
3245
        rv = qemuDomainDefFormatLive(driver, vm->def, false, true);
3246
    }
3247

3248
 cleanup:
3249
    qemuMigrationCookieFree(mig);
3250
    virObjectUnref(caps);
3251
    virDomainDefFree(def);
3252 3253 3254
    return rv;
}

3255 3256 3257 3258 3259 3260 3261
char *
qemuMigrationBegin(virConnectPtr conn,
                   virDomainObjPtr vm,
                   const char *xmlin,
                   const char *dname,
                   char **cookieout,
                   int *cookieoutlen,
3262 3263
                   size_t nmigrate_disks,
                   const char **migrate_disks,
3264 3265 3266 3267
                   unsigned long flags)
{
    virQEMUDriverPtr driver = conn->privateData;
    char *xml = NULL;
3268
    qemuDomainAsyncJob asyncJob;
3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279

    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;
    }

3280 3281
    qemuMigrationStoreDomainState(vm);

3282 3283 3284 3285 3286 3287 3288 3289 3290 3291
    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) &&
3292
        qemuProcessRefreshDisks(driver, vm, asyncJob) < 0)
3293 3294 3295 3296
        goto endjob;

    if (!(xml = qemuMigrationBeginPhase(driver, vm, xmlin, dname,
                                        cookieout, cookieoutlen,
3297
                                        nmigrate_disks, migrate_disks, flags)))
3298 3299 3300 3301 3302 3303 3304
        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.
         */
3305
        if (virCloseCallbacksSet(driver->closeCallbacks, vm, conn,
3306 3307
                                 qemuMigrationCleanup) < 0) {
            VIR_FREE(xml);
3308
            goto endjob;
3309
        }
3310
        qemuMigrationJobContinue(vm);
3311 3312 3313 3314
    } else {
        goto endjob;
    }

3315
 cleanup:
M
Michal Privoznik 已提交
3316
    virDomainObjEndAPI(&vm);
3317 3318
    return xml;

3319
 endjob:
3320 3321 3322 3323
    if (flags & VIR_MIGRATE_CHANGE_PROTECTION)
        qemuMigrationJobFinish(driver, vm);
    else
        qemuDomainObjEndJob(driver, vm);
3324 3325 3326
    goto cleanup;
}

3327

3328 3329
/* Prepare is the first step, and it runs on the destination host.
 */
3330

3331
static void
3332
qemuMigrationPrepareCleanup(virQEMUDriverPtr driver,
3333 3334 3335 3336 3337 3338 3339 3340 3341 3342
                            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));

3343 3344 3345
    virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort);
    priv->migrationPort = 0;

3346 3347 3348 3349 3350
    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN))
        return;
    qemuDomainObjDiscardAsyncJob(driver, vm);
}

3351
static qemuProcessIncomingDefPtr
3352 3353 3354 3355
qemuMigrationPrepareIncoming(virDomainObjPtr vm,
                             bool tunnel,
                             const char *protocol,
                             const char *listenAddress,
3356 3357
                             unsigned short port,
                             int fd)
3358 3359
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3360
    qemuProcessIncomingDefPtr inc = NULL;
3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422
    char *migrateFrom = NULL;

    if (tunnel) {
        if (VIR_STRDUP(migrateFrom, "stdio") < 0)
            goto cleanup;
    } else {
        bool encloseAddress = false;
        bool hostIPv6Capable = false;
        bool qemuIPv6Capable = false;
        struct addrinfo *info = NULL;
        struct addrinfo hints = { .ai_flags = AI_ADDRCONFIG,
                                  .ai_socktype = SOCK_STREAM };
        const char *incFormat;

        if (getaddrinfo("::", NULL, &hints, &info) == 0) {
            freeaddrinfo(info);
            hostIPv6Capable = true;
        }
        qemuIPv6Capable = virQEMUCapsGet(priv->qemuCaps,
                                         QEMU_CAPS_IPV6_MIGRATION);

        if (listenAddress) {
            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"));
                    goto cleanup;
                }
                /* IPv6 address must be escaped in brackets on the cmd line */
                encloseAddress = true;
            } else {
                /* listenAddress is a hostname or IPv4 */
            }
        } else if (qemuIPv6Capable && hostIPv6Capable) {
            /* Listen on :: instead of 0.0.0.0 if QEMU understands it
             * and there is at least one IPv6 address configured
             */
            listenAddress = "::";
            encloseAddress = true;
        } else {
            listenAddress = "0.0.0.0";
        }

        /* QEMU will be started with
         *   -incoming protocol:[<IPv6 addr>]:port,
         *   -incoming protocol:<IPv4 addr>:port, or
         *   -incoming protocol:<hostname>:port
         */
        if (encloseAddress)
            incFormat = "%s:[%s]:%d";
        else
            incFormat = "%s:%s:%d";
        if (virAsprintf(&migrateFrom, incFormat,
                        protocol, listenAddress, port) < 0)
            goto cleanup;
    }

3423 3424
    inc = qemuProcessIncomingDefNew(priv->qemuCaps, listenAddress,
                                    migrateFrom, fd, NULL);
3425

3426
 cleanup:
3427 3428
    VIR_FREE(migrateFrom);
    return inc;
3429 3430
}

3431 3432 3433 3434
static int
qemuMigrationSetCompression(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            qemuDomainAsyncJob job,
3435 3436
                            qemuMigrationCompressionPtr compression,
                            qemuMonitorMigrationParamsPtr migParams)
3437
{
3438 3439 3440
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;

3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454
    if (qemuMigrationSetOption(driver, vm,
                               QEMU_MONITOR_MIGRATION_CAPS_XBZRLE,
                               compression->methods &
                                   (1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE),
                               job) < 0)
        return -1;

    if (qemuMigrationSetOption(driver, vm,
                               QEMU_MONITOR_MIGRATION_CAPS_COMPRESS,
                               compression->methods &
                                   (1ULL << QEMU_MIGRATION_COMPRESS_MT),
                               job) < 0)
        return -1;

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

3458 3459
    migParams->compressLevel_set = compression->level_set;
    migParams->compressLevel = compression->level;
3460

3461 3462
    migParams->compressThreads_set = compression->threads_set;
    migParams->compressThreads = compression->threads;
3463

3464 3465
    migParams->decompressThreads_set = compression->dthreads_set;
    migParams->decompressThreads = compression->dthreads;
3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478

    if (compression->xbzrle_cache_set &&
        qemuMonitorSetMigrationCacheSize(priv->mon,
                                         compression->xbzrle_cache) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        ret = -1;

    return ret;
3479 3480
}

3481

3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527
qemuMonitorMigrationParamsPtr
qemuMigrationParams(virTypedParameterPtr params,
                    int nparams,
                    unsigned long flags)
{
    qemuMonitorMigrationParamsPtr migParams;

    if (VIR_ALLOC(migParams) < 0)
        return NULL;

    if (!params)
        return migParams;

#define GET(PARAM, VAR)                                                     \
    do {                                                                    \
        int rc;                                                             \
        if ((rc = virTypedParamsGetInt(params, nparams,                     \
                                       VIR_MIGRATE_PARAM_ ## PARAM,         \
                                       &migParams->VAR)) < 0)               \
            goto error;                                                     \
                                                                            \
        if (rc == 1)                                                        \
            migParams->VAR ## _set = true;                                  \
    } while (0)

    GET(AUTO_CONVERGE_INITIAL, cpuThrottleInitial);
    GET(AUTO_CONVERGE_INCREMENT, cpuThrottleIncrement);

#undef GET

    if ((migParams->cpuThrottleInitial_set ||
         migParams->cpuThrottleIncrement_set) &&
        !(flags & VIR_MIGRATE_AUTO_CONVERGE)) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Turn auto convergence on to tune it"));
        goto error;
    }

    return migParams;

 error:
    VIR_FREE(migParams);
    return NULL;
}


3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552
static int
qemuMigrationSetParams(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       qemuDomainAsyncJob job,
                       qemuMonitorMigrationParamsPtr migParams)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;

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

    if (qemuMonitorSetMigrationParams(priv->mon, migParams) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        ret = -1;

    return ret;
}


3553
static int
3554
qemuMigrationPrepareAny(virQEMUDriverPtr driver,
3555 3556 3557 3558 3559
                        virConnectPtr dconn,
                        const char *cookiein,
                        int cookieinlen,
                        char **cookieout,
                        int *cookieoutlen,
3560
                        virDomainDefPtr *def,
3561
                        const char *origname,
L
liguang 已提交
3562
                        virStreamPtr st,
3563
                        const char *protocol,
3564 3565
                        unsigned short port,
                        bool autoPort,
3566
                        const char *listenAddress,
3567 3568
                        size_t nmigrate_disks,
                        const char **migrate_disks,
3569
                        int nbdPort,
3570
                        qemuMigrationCompressionPtr compression,
L
liguang 已提交
3571
                        unsigned long flags)
3572 3573
{
    virDomainObjPtr vm = NULL;
3574
    virObjectEventPtr event = NULL;
3575
    int ret = -1;
3576
    int dataFD[2] = { -1, -1 };
3577
    qemuDomainObjPrivatePtr priv = NULL;
3578
    qemuMigrationCookiePtr mig = NULL;
3579
    bool tunnel = !!st;
J
Jiri Denemark 已提交
3580
    char *xmlout = NULL;
L
liguang 已提交
3581
    unsigned int cookieFlags;
3582
    virCapsPtr caps = NULL;
3583
    qemuProcessIncomingDefPtr incoming = NULL;
3584
    bool taint_hook = false;
3585 3586 3587
    bool stopProcess = false;
    bool relabel = false;
    int rv;
3588
    qemuMonitorMigrationParams migParams = { 0 };
3589

3590 3591
    virNWFilterReadLockFilterUpdates();

L
liguang 已提交
3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611
    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;
        }
3612 3613 3614
        cookieFlags = 0;
    } else {
        cookieFlags = QEMU_MIGRATION_COOKIE_GRAPHICS;
L
liguang 已提交
3615 3616
    }

3617 3618 3619 3620 3621 3622 3623 3624 3625
    if (flags & VIR_MIGRATE_POSTCOPY &&
        (!(flags & VIR_MIGRATE_LIVE) ||
         flags & VIR_MIGRATE_PAUSED)) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("post-copy migration is not supported with non-live "
                         "or paused migration"));
        goto cleanup;
    }

3626 3627 3628
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

3629
    if (!qemuMigrationIsAllowedHostdev(*def))
3630 3631
        goto cleanup;

J
Jiri Denemark 已提交
3632 3633 3634 3635 3636
    /* Let migration hook filter domain XML */
    if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
        char *xml;
        int hookret;

3637
        if (!(xml = qemuDomainDefFormatXML(driver, *def,
3638 3639
                                           VIR_DOMAIN_XML_SECURE |
                                           VIR_DOMAIN_XML_MIGRATABLE)))
J
Jiri Denemark 已提交
3640 3641
            goto cleanup;

3642
        hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, (*def)->name,
J
Jiri Denemark 已提交
3643 3644 3645 3646 3647 3648 3649
                              VIR_HOOK_QEMU_OP_MIGRATE, VIR_HOOK_SUBOP_BEGIN,
                              NULL, xml, &xmlout);
        VIR_FREE(xml);

        if (hookret < 0) {
            goto cleanup;
        } else if (hookret == 0) {
3650
            if (virStringIsEmpty(xmlout)) {
J
Jiri Denemark 已提交
3651 3652 3653 3654 3655 3656
                VIR_DEBUG("Migrate hook filter returned nothing; using the"
                          " original XML");
            } else {
                virDomainDefPtr newdef;

                VIR_DEBUG("Using hook-filtered domain XML: %s", xmlout);
3657
                newdef = virDomainDefParseString(xmlout, caps, driver->xmlopt,
3658 3659
                                                 VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                                 VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
J
Jiri Denemark 已提交
3660 3661 3662
                if (!newdef)
                    goto cleanup;

3663
                if (!qemuDomainDefCheckABIStability(driver, *def, newdef)) {
J
Jiri Denemark 已提交
3664 3665 3666 3667
                    virDomainDefFree(newdef);
                    goto cleanup;
                }

3668 3669
                virDomainDefFree(*def);
                *def = newdef;
3670 3671 3672 3673
                /* 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 已提交
3674 3675 3676 3677
            }
        }
    }

3678
    if (!(vm = virDomainObjListAdd(driver->domains, *def,
3679
                                   driver->xmlopt,
3680 3681 3682
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
3683
        goto cleanup;
3684

3685
    virObjectRef(vm);
3686
    *def = NULL;
3687
    priv = vm->privateData;
3688 3689
    if (VIR_STRDUP(priv->origname, origname) < 0)
        goto cleanup;
3690

3691 3692 3693 3694 3695
    if (taint_hook) {
        /* Domain XML has been altered by a hook script. */
        priv->hookRun = true;
    }

3696
    if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen,
3697
                                       QEMU_MIGRATION_COOKIE_LOCKSTATE |
3698 3699
                                       QEMU_MIGRATION_COOKIE_NBD |
                                       QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG)))
3700 3701
        goto cleanup;

3702 3703
    if (STREQ_NULLABLE(protocol, "rdma") &&
        !virMemoryLimitIsSet(vm->def->mem.hard_limit)) {
M
Michael R. Hines 已提交
3704 3705 3706 3707 3708 3709
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot start RDMA migration with no memory hard "
                         "limit set"));
        goto cleanup;
    }

3710
    if (qemuMigrationPrecreateStorage(dconn, driver, vm, mig->nbd,
3711 3712
                                      nmigrate_disks, migrate_disks,
                                      !!(flags & VIR_MIGRATE_NON_SHARED_INC)) < 0)
3713 3714
        goto cleanup;

3715
    if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
3716
        goto cleanup;
3717
    qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PREPARE);
3718 3719 3720 3721

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

L
liguang 已提交
3722 3723 3724
    if (flags & VIR_MIGRATE_OFFLINE)
        goto done;

3725 3726
    if (tunnel &&
        (pipe(dataFD) < 0 || virSetCloseExec(dataFD[1]) < 0)) {
3727 3728
        virReportSystemError(errno, "%s",
                             _("cannot create pipe for tunnelled migration"));
3729
        goto stopjob;
3730 3731
    }

3732
    if (qemuProcessInit(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN,
3733
                        true, VIR_QEMU_PROCESS_START_AUTODESTROY) < 0)
3734
        goto stopjob;
3735
    stopProcess = true;
3736

3737 3738 3739
    if (!(incoming = qemuMigrationPrepareIncoming(vm, tunnel, protocol,
                                                  listenAddress, port,
                                                  dataFD[0])))
3740
        goto stopjob;
3741 3742
    dataFD[0] = -1; /* the FD is now owned by incoming */

3743 3744 3745 3746
    if (qemuProcessPrepareDomain(dconn, driver, vm,
                                 VIR_QEMU_PROCESS_START_AUTODESTROY) < 0)
        goto stopjob;

3747 3748 3749
    if (qemuProcessPrepareHost(driver, vm, !!incoming) < 0)
        goto stopjob;

3750 3751 3752 3753 3754 3755 3756
    rv = qemuProcessLaunch(dconn, driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN,
                           incoming, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START,
                           VIR_QEMU_PROCESS_START_AUTODESTROY);
    if (rv < 0) {
        if (rv == -2)
            relabel = true;
3757
        goto stopjob;
3758
    }
3759
    relabel = true;
3760

3761 3762 3763 3764
    if (tunnel) {
        if (virFDStreamOpen(st, dataFD[1]) < 0) {
            virReportSystemError(errno, "%s",
                                 _("cannot pass pipe for tunnelled migration"));
3765
            goto stopjob;
3766
        }
3767
        dataFD[1] = -1; /* 'st' owns the FD now & will close it */
3768 3769
    }

3770
    if (qemuMigrationSetCompression(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN,
3771
                                    compression, &migParams) < 0)
3772
        goto stopjob;
3773

3774
    if (STREQ_NULLABLE(protocol, "rdma") &&
M
Michael R. Hines 已提交
3775
        virProcessSetMaxMemLock(vm->pid, vm->def->mem.hard_limit << 10) < 0) {
3776
        goto stopjob;
M
Michael R. Hines 已提交
3777 3778
    }

3779 3780
    if (qemuMigrationSetOption(driver, vm,
                               QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL,
3781 3782
                               flags & VIR_MIGRATE_RDMA_PIN_ALL,
                               QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
3783
        goto stopjob;
3784

3785 3786 3787 3788 3789
    if (qemuMigrationSetPostCopy(driver, vm,
                                 flags & VIR_MIGRATE_POSTCOPY,
                                 QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
        goto stopjob;

3790 3791 3792 3793
    if (qemuMigrationSetParams(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN,
                               &migParams) < 0)
        goto stopjob;

3794 3795 3796
    if (mig->nbd &&
        flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC) &&
        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NBD_SERVER)) {
3797
        if (qemuMigrationStartNBDServer(driver, vm, incoming->address,
3798 3799
                                        nmigrate_disks, migrate_disks,
                                        nbdPort) < 0) {
3800
            goto stopjob;
3801
        }
3802
        cookieFlags |= QEMU_MIGRATION_COOKIE_NBD;
3803 3804
    }

3805 3806 3807 3808 3809 3810 3811 3812 3813
    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");
    }

3814 3815 3816 3817 3818 3819 3820 3821 3822
    if (incoming->deferredURI &&
        qemuMigrationRunIncoming(driver, vm, incoming->deferredURI,
                                 QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
        goto stopjob;

    if (qemuProcessFinishStartup(dconn, driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN,
                                 false, VIR_DOMAIN_PAUSED_MIGRATION) < 0)
        goto stopjob;

3823
 done:
3824 3825
    if (qemuMigrationBakeCookie(mig, driver, vm, cookieout,
                                cookieoutlen, cookieFlags) < 0) {
3826 3827 3828 3829 3830 3831 3832
        /* 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");
    }

3833
    if (qemuDomainCleanupAdd(vm, qemuMigrationPrepareCleanup) < 0)
3834
        goto stopjob;
3835

L
liguang 已提交
3836 3837
    if (!(flags & VIR_MIGRATE_OFFLINE)) {
        virDomainAuditStart(vm, "migrated", true);
3838
        event = virDomainEventLifecycleNewFromObj(vm,
L
liguang 已提交
3839 3840 3841
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_MIGRATED);
    }
3842

3843 3844 3845 3846
    /* 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.
     */
3847
    qemuMigrationJobContinue(vm);
3848

3849 3850
    if (autoPort)
        priv->migrationPort = port;
3851 3852 3853 3854 3855
    /* in this case port is not auto selected and we don't need to manage it
     * anymore after cookie is baked
     */
    if (nbdPort != 0)
        priv->nbdPort = 0;
3856
    ret = 0;
3857

3858
 cleanup:
3859
    qemuProcessIncomingDefFree(incoming);
J
Jiri Denemark 已提交
3860
    VIR_FREE(xmlout);
3861 3862
    VIR_FORCE_CLOSE(dataFD[0]);
    VIR_FORCE_CLOSE(dataFD[1]);
3863 3864 3865
    if (ret < 0 && priv) {
        /* priv is set right after vm is added to the list of domains
         * and there is no 'goto cleanup;' in the middle of those */
3866
        VIR_FREE(priv->origname);
3867 3868 3869 3870 3871
        /* release if port is auto selected which is not the case if
         * it is given in parameters
         */
        if (nbdPort == 0)
            virPortAllocatorRelease(driver->migrationPorts, priv->nbdPort);
3872
        priv->nbdPort = 0;
3873
        qemuDomainRemoveInactive(driver, vm);
3874
    }
M
Michal Privoznik 已提交
3875
    virDomainObjEndAPI(&vm);
3876
    qemuDomainEventQueue(driver, event);
3877
    qemuMigrationCookieFree(mig);
3878
    virObjectUnref(caps);
3879
    virNWFilterUnlockFilterUpdates();
3880
    return ret;
3881

3882
 stopjob:
3883 3884 3885 3886
    if (stopProcess) {
        unsigned int stopFlags = VIR_QEMU_PROCESS_STOP_MIGRATED;
        if (!relabel)
            stopFlags |= VIR_QEMU_PROCESS_STOP_NO_RELABEL;
3887
        virDomainAuditStart(vm, "migrated", false);
3888 3889
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED,
                        QEMU_ASYNC_JOB_MIGRATION_IN, stopFlags);
3890
    }
3891

3892
    qemuMigrationJobFinish(driver, vm);
3893
    goto cleanup;
3894 3895 3896
}


3897 3898 3899 3900 3901
/*
 * This version starts an empty VM listening on a localhost TCP port, and
 * sets up the corresponding virStream to handle the incoming data.
 */
int
3902
qemuMigrationPrepareTunnel(virQEMUDriverPtr driver,
3903 3904 3905 3906 3907 3908
                           virConnectPtr dconn,
                           const char *cookiein,
                           int cookieinlen,
                           char **cookieout,
                           int *cookieoutlen,
                           virStreamPtr st,
3909
                           virDomainDefPtr *def,
3910
                           const char *origname,
L
liguang 已提交
3911
                           unsigned long flags)
3912
{
3913
    qemuMigrationCompressionPtr compression = NULL;
3914 3915 3916
    int ret;

    VIR_DEBUG("driver=%p, dconn=%p, cookiein=%s, cookieinlen=%d, "
3917
              "cookieout=%p, cookieoutlen=%p, st=%p, def=%p, "
3918
              "origname=%s, flags=%lx",
3919
              driver, dconn, NULLSTR(cookiein), cookieinlen,
3920
              cookieout, cookieoutlen, st, *def, origname, flags);
3921

3922 3923 3924 3925 3926 3927
    if (st == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("tunnelled migration requested but NULL stream passed"));
        return -1;
    }

3928 3929 3930
    if (!(compression = qemuMigrationCompressionParse(NULL, 0, flags)))
        return -1;

3931
    ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
3932
                                  cookieout, cookieoutlen, def, origname,
3933 3934 3935
                                  st, NULL, 0, false, NULL, 0, NULL, 0,
                                  compression, flags);
    VIR_FREE(compression);
3936 3937 3938 3939
    return ret;
}


3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962
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;
}


3963
int
3964
qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
3965
                           virConnectPtr dconn,
3966 3967 3968 3969
                           const char *cookiein,
                           int cookieinlen,
                           char **cookieout,
                           int *cookieoutlen,
3970 3971
                           const char *uri_in,
                           char **uri_out,
3972
                           virDomainDefPtr *def,
3973
                           const char *origname,
3974
                           const char *listenAddress,
3975 3976
                           size_t nmigrate_disks,
                           const char **migrate_disks,
3977
                           int nbdPort,
3978
                           qemuMigrationCompressionPtr compression,
L
liguang 已提交
3979
                           unsigned long flags)
3980
{
3981 3982
    unsigned short port = 0;
    bool autoPort = true;
3983 3984
    char *hostname = NULL;
    int ret = -1;
3985
    virURIPtr uri = NULL;
3986 3987
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    const char *migrateHost = cfg->migrateHost;
J
Jiri Denemark 已提交
3988

3989 3990
    VIR_DEBUG("driver=%p, dconn=%p, cookiein=%s, cookieinlen=%d, "
              "cookieout=%p, cookieoutlen=%p, uri_in=%s, uri_out=%p, "
3991
              "def=%p, origname=%s, listenAddress=%s, "
3992
              "nmigrate_disks=%zu, migrate_disks=%p, nbdPort=%d, flags=%lx",
3993 3994
              driver, dconn, NULLSTR(cookiein), cookieinlen,
              cookieout, cookieoutlen, NULLSTR(uri_in), uri_out,
3995
              *def, origname, NULLSTR(listenAddress),
3996
              nmigrate_disks, migrate_disks, nbdPort, flags);
3997

3998 3999
    *uri_out = NULL;

4000 4001 4002
    /* 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
4003 4004 4005
     * 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".
4006 4007 4008 4009 4010 4011
     *
     * 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) {
4012 4013 4014
        bool encloseAddress = false;
        const char *incFormat;

4015
        if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0)
4016
            goto cleanup;
4017

4018
        if (migrateHost != NULL) {
4019 4020
            if (virSocketAddrNumericFamily(migrateHost) == AF_INET6)
                encloseAddress = true;
4021

4022
            if (VIR_STRDUP(hostname, migrateHost) < 0)
4023 4024 4025 4026 4027
                goto cleanup;
        } else {
            if ((hostname = virGetHostname()) == NULL)
                goto cleanup;
        }
4028 4029

        if (STRPREFIX(hostname, "localhost")) {
4030 4031 4032
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("hostname on destination resolved to localhost,"
                             " but migration requires an FQDN"));
4033 4034 4035 4036 4037
            goto cleanup;
        }

        /* XXX this really should have been a properly well-formed
         * URI, but we can't add in tcp:// now without breaking
4038
         * compatibility with old targets. We at least make the
4039 4040
         * new targets accept both syntaxes though.
         */
4041 4042 4043 4044 4045 4046
        if (encloseAddress)
            incFormat = "%s:[%s]:%d";
        else
            incFormat = "%s:%s:%d";

        if (virAsprintf(uri_out, incFormat, "tcp", hostname, port) < 0)
4047 4048
            goto cleanup;
    } else {
4049
        bool well_formed_uri;
J
Ján Tomko 已提交
4050

4051 4052
        if (!(uri = qemuMigrationParseURI(uri_in, &well_formed_uri)))
            goto cleanup;
J
Ján Tomko 已提交
4053

4054 4055 4056 4057 4058 4059 4060
        if (uri->scheme == NULL) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("missing scheme in migration URI: %s"),
                           uri_in);
            goto cleanup;
        }

M
Michael R. Hines 已提交
4061 4062
        if (STRNEQ(uri->scheme, "tcp") &&
            STRNEQ(uri->scheme, "rdma")) {
4063 4064 4065
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                           _("unsupported scheme %s in migration URI %s"),
                           uri->scheme, uri_in);
J
Ján Tomko 已提交
4066 4067 4068 4069 4070 4071 4072 4073 4074 4075
            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) {
4076
            if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0)
4077
                goto cleanup;
4078

4079
            /* Send well-formed URI only if uri_in was well-formed */
4080 4081 4082 4083 4084 4085 4086 4087
            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;
            }
4088
        } else {
4089 4090
            port = uri->port;
            autoPort = false;
4091 4092 4093 4094 4095 4096
        }
    }

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

4097
    ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
4098
                                  cookieout, cookieoutlen, def, origname,
4099
                                  NULL, uri ? uri->scheme : "tcp",
4100
                                  port, autoPort, listenAddress,
4101 4102
                                  nmigrate_disks, migrate_disks, nbdPort,
                                  compression, flags);
4103
 cleanup:
4104
    virURIFree(uri);
4105
    VIR_FREE(hostname);
4106
    virObjectUnref(cfg);
4107
    if (ret != 0) {
4108
        VIR_FREE(*uri_out);
4109 4110 4111
        if (autoPort)
            virPortAllocatorRelease(driver->migrationPorts, port);
    }
4112 4113 4114 4115
    return ret;
}


4116 4117 4118
virDomainDefPtr
qemuMigrationPrepareDef(virQEMUDriverPtr driver,
                        const char *dom_xml,
4119 4120
                        const char *dname,
                        char **origname)
4121 4122 4123
{
    virCapsPtr caps = NULL;
    virDomainDefPtr def;
4124
    char *name = NULL;
4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135

    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,
4136 4137
                                        VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                        VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
4138 4139 4140
        goto cleanup;

    if (dname) {
4141
        name = def->name;
4142 4143 4144 4145 4146 4147
        if (VIR_STRDUP(def->name, dname) < 0) {
            virDomainDefFree(def);
            def = NULL;
        }
    }

4148
 cleanup:
4149
    virObjectUnref(caps);
4150 4151 4152 4153
    if (def && origname)
        *origname = name;
    else
        VIR_FREE(name);
4154 4155 4156 4157
    return def;
}


4158 4159 4160 4161 4162 4163 4164 4165 4166 4167
static int
qemuMigrationConfirmPhase(virQEMUDriverPtr driver,
                          virConnectPtr conn,
                          virDomainObjPtr vm,
                          const char *cookiein,
                          int cookieinlen,
                          unsigned int flags,
                          int retcode)
{
    qemuMigrationCookiePtr mig;
4168
    virObjectEventPtr event;
4169 4170
    int rv = -1;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
4171 4172
    qemuDomainObjPrivatePtr priv = vm->privateData;
    qemuDomainJobInfoPtr jobInfo = NULL;
4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185

    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);

4186 4187
    if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen,
                                       QEMU_MIGRATION_COOKIE_STATS)))
4188 4189
        goto cleanup;

4190 4191 4192
    if (retcode == 0)
        jobInfo = priv->job.completed;
    else
4193
        VIR_FREE(priv->job.completed);
4194 4195 4196

    /* Update times with the values sent by the destination daemon */
    if (mig->jobInfo && jobInfo) {
4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209
        int reason;

        /* We need to refresh migration statistics after a completed post-copy
         * migration since priv->job.completed contains obsolete data from the
         * time we switched to post-copy mode.
         */
        if (virDomainObjGetState(vm, &reason) == VIR_DOMAIN_PAUSED &&
            reason == VIR_DOMAIN_PAUSED_POSTCOPY &&
            qemuMigrationFetchJobStatus(driver, vm,
                                        QEMU_ASYNC_JOB_MIGRATION_OUT,
                                        jobInfo) < 0)
            VIR_WARN("Could not refresh migration statistics");

4210 4211 4212 4213 4214
        qemuDomainJobInfoUpdateTime(jobInfo);
        jobInfo->timeDeltaSet = mig->jobInfo->timeDeltaSet;
        jobInfo->timeDelta = mig->jobInfo->timeDelta;
        jobInfo->stats.downtime_set = mig->jobInfo->stats.downtime_set;
        jobInfo->stats.downtime = mig->jobInfo->stats.downtime;
4215 4216
    }

4217 4218 4219
    if (flags & VIR_MIGRATE_OFFLINE)
        goto done;

4220 4221
    /* Did the migration go as planned?  If yes, kill off the domain object.
     * If something failed, resume CPUs, but only if we didn't use post-copy.
4222 4223 4224 4225
     */
    if (retcode == 0) {
        /* If guest uses SPICE and supports seamless migration we have to hold
         * up domain shutdown until SPICE server transfers its data */
4226
        qemuMigrationWaitForSpice(vm);
4227 4228

        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED,
4229
                        QEMU_ASYNC_JOB_MIGRATION_OUT,
4230 4231 4232
                        VIR_QEMU_PROCESS_STOP_MIGRATED);
        virDomainAuditStop(vm, "migrated");

4233
        event = virDomainEventLifecycleNewFromObj(vm,
4234 4235
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
4236 4237
        qemuDomainEventQueue(driver, event);
        qemuDomainEventEmitJobCompleted(driver, vm);
4238
    } else {
4239
        virErrorPtr orig_err = virSaveLastError();
4240
        int reason;
4241 4242

        /* cancel any outstanding NBD jobs */
4243
        qemuMigrationCancelDriveMirror(driver, vm, false,
4244
                                       QEMU_ASYNC_JOB_MIGRATION_OUT, NULL);
4245 4246 4247

        virSetError(orig_err);
        virFreeError(orig_err);
4248

4249 4250 4251 4252
        if (virDomainObjGetState(vm, &reason) == VIR_DOMAIN_PAUSED &&
            reason == VIR_DOMAIN_PAUSED_POSTCOPY) {
            qemuMigrationPostcopyFailed(driver, vm);
        } else if (qemuMigrationRestoreDomainState(conn, vm)) {
4253 4254 4255
            event = virDomainEventLifecycleNewFromObj(vm,
                                                      VIR_DOMAIN_EVENT_RESUMED,
                                                      VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
4256
            qemuDomainEventQueue(driver, event);
4257 4258
        }

4259
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
4260 4261 4262
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
    }

4263
 done:
4264 4265 4266
    qemuMigrationCookieFree(mig);
    rv = 0;

4267
 cleanup:
4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280
    virObjectUnref(cfg);
    return rv;
}

int
qemuMigrationConfirm(virConnectPtr conn,
                     virDomainObjPtr vm,
                     const char *cookiein,
                     int cookieinlen,
                     unsigned int flags,
                     int cancelled)
{
    virQEMUDriverPtr driver = conn->privateData;
4281
    qemuMigrationJobPhase phase;
4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295
    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);
4296 4297
    virCloseCallbacksUnset(driver->closeCallbacks, vm,
                           qemuMigrationCleanup);
4298 4299 4300 4301 4302

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

4303
    qemuMigrationJobFinish(driver, vm);
4304
    if (!virDomainObjIsActive(vm)) {
4305
        if (flags & VIR_MIGRATE_UNDEFINE_SOURCE) {
4306
            virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm);
4307 4308
            vm->persistent = 0;
        }
4309 4310 4311
        qemuDomainRemoveInactive(driver, vm);
    }

4312
 cleanup:
M
Michal Privoznik 已提交
4313
    virDomainObjEndAPI(&vm);
4314 4315 4316 4317 4318
    virObjectUnref(cfg);
    return ret;
}


4319 4320
enum qemuMigrationDestinationType {
    MIGRATION_DEST_HOST,
4321
    MIGRATION_DEST_CONNECT_HOST,
4322
    MIGRATION_DEST_UNIX,
4323
    MIGRATION_DEST_FD,
4324
};
4325

4326 4327 4328 4329
enum qemuMigrationForwardType {
    MIGRATION_FWD_DIRECT,
    MIGRATION_FWD_STREAM,
};
4330

4331 4332 4333 4334 4335 4336
typedef struct _qemuMigrationSpec qemuMigrationSpec;
typedef qemuMigrationSpec *qemuMigrationSpecPtr;
struct _qemuMigrationSpec {
    enum qemuMigrationDestinationType destType;
    union {
        struct {
4337
            const char *protocol;
4338 4339 4340 4341 4342
            const char *name;
            int port;
        } host;

        struct {
4343
            char *file;
4344 4345
            int sock;
        } unix_socket;
4346 4347 4348 4349 4350

        struct {
            int qemu;
            int local;
        } fd;
4351 4352 4353 4354 4355 4356 4357
    } dest;

    enum qemuMigrationForwardType fwdType;
    union {
        virStreamPtr stream;
    } fwd;
};
4358 4359 4360

#define TUNNEL_SEND_BUF_SIZE 65536

4361 4362 4363 4364 4365 4366 4367
typedef struct _qemuMigrationIOThread qemuMigrationIOThread;
typedef qemuMigrationIOThread *qemuMigrationIOThreadPtr;
struct _qemuMigrationIOThread {
    virThread thread;
    virStreamPtr st;
    int sock;
    virError err;
4368 4369
    int wakeupRecvFD;
    int wakeupSendFD;
4370 4371 4372
};

static void qemuMigrationIOFunc(void *arg)
4373
{
4374
    qemuMigrationIOThreadPtr data = arg;
4375 4376 4377 4378 4379 4380 4381
    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);
4382

4383
    if (VIR_ALLOC_N(buffer, TUNNEL_SEND_BUF_SIZE) < 0)
4384
        goto abrt;
4385

4386 4387 4388
    fds[0].fd = data->sock;
    fds[1].fd = data->wakeupRecvFD;

4389
    for (;;) {
4390 4391 4392 4393 4394 4395 4396 4397 4398 4399
        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;
4400
            virReportSystemError(errno, "%s",
4401 4402
                                 _("poll failed in migration tunnel"));
            goto abrt;
4403
        }
4404 4405 4406 4407 4408 4409 4410

        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");
4411
            break;
4412
        }
4413

4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429
        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;
            }
4430 4431
        }

4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448
        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;
            }
        }
    }
4449

4450 4451
    if (virStreamFinish(data->st) < 0)
        goto error;
4452

4453
    VIR_FORCE_CLOSE(data->sock);
4454 4455
    VIR_FREE(buffer);

4456 4457
    return;

4458
 abrt:
4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469
    err = virSaveLastError();
    if (err && err->code == VIR_ERR_OK) {
        virFreeError(err);
        err = NULL;
    }
    virStreamAbort(data->st);
    if (err) {
        virSetError(err);
        virFreeError(err);
    }

4470
 error:
4471 4472 4473 4474 4475
    /* Let the source qemu know that the transfer cant continue anymore.
     * Don't copy the error for EPIPE as destination has the actual error. */
    VIR_FORCE_CLOSE(data->sock);
    if (!virLastErrorIsSystemErrno(EPIPE))
        virCopyLastError(&data->err);
4476
    virResetLastError();
4477
    VIR_FREE(buffer);
4478 4479 4480 4481 4482 4483 4484
}


static qemuMigrationIOThreadPtr
qemuMigrationStartTunnel(virStreamPtr st,
                         int sock)
{
4485 4486
    qemuMigrationIOThreadPtr io = NULL;
    int wakeupFD[2] = { -1, -1 };
4487

4488 4489 4490 4491
    if (pipe2(wakeupFD, O_CLOEXEC) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to make pipe"));
        goto error;
4492 4493
    }

4494
    if (VIR_ALLOC(io) < 0)
4495
        goto error;
4496

4497 4498
    io->st = st;
    io->sock = sock;
4499 4500
    io->wakeupRecvFD = wakeupFD[0];
    io->wakeupSendFD = wakeupFD[1];
4501 4502 4503 4504 4505 4506

    if (virThreadCreate(&io->thread, true,
                        qemuMigrationIOFunc,
                        io) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to create migration thread"));
4507
        goto error;
4508 4509 4510
    }

    return io;
4511

4512
 error:
4513 4514 4515 4516
    VIR_FORCE_CLOSE(wakeupFD[0]);
    VIR_FORCE_CLOSE(wakeupFD[1]);
    VIR_FREE(io);
    return NULL;
4517 4518 4519
}

static int
4520
qemuMigrationStopTunnel(qemuMigrationIOThreadPtr io, bool error)
4521 4522
{
    int rv = -1;
4523 4524 4525 4526 4527 4528 4529 4530 4531
    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;
    }

4532 4533 4534 4535
    virThreadJoin(&io->thread);

    /* Forward error from the IO thread, to this thread */
    if (io->err.code != VIR_ERR_OK) {
4536 4537 4538 4539
        if (error)
            rv = 0;
        else
            virSetError(&io->err);
4540 4541 4542 4543 4544 4545
        virResetError(&io->err);
        goto cleanup;
    }

    rv = 0;

4546
 cleanup:
4547 4548
    VIR_FORCE_CLOSE(io->wakeupSendFD);
    VIR_FORCE_CLOSE(io->wakeupRecvFD);
4549 4550
    VIR_FREE(io);
    return rv;
4551 4552
}

4553
static int
4554
qemuMigrationConnect(virQEMUDriverPtr driver,
4555 4556 4557 4558 4559 4560 4561 4562 4563
                     virDomainObjPtr vm,
                     qemuMigrationSpecPtr spec)
{
    virNetSocketPtr sock;
    const char *host;
    char *port = NULL;
    int ret = -1;

    host = spec->dest.host.name;
4564
    if (virAsprintf(&port, "%d", spec->dest.host.port) < 0)
4565 4566 4567 4568 4569 4570 4571
        return -1;

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

    if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0)
        goto cleanup;
4572 4573 4574
    if (virNetSocketNewConnectTCP(host, port,
                                  AF_UNSPEC,
                                  &sock) == 0) {
4575
        spec->dest.fd.qemu = virNetSocketDupFD(sock, true);
4576
        virObjectUnref(sock);
4577 4578 4579 4580 4581
    }
    if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0 ||
        spec->dest.fd.qemu == -1)
        goto cleanup;

4582 4583 4584 4585 4586 4587 4588
    /* 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;
    }

4589 4590
    ret = 0;

4591
 cleanup:
4592 4593 4594 4595 4596 4597
    VIR_FREE(port);
    if (ret < 0)
        VIR_FORCE_CLOSE(spec->dest.fd.qemu);
    return ret;
}

4598
static int
4599
qemuMigrationRun(virQEMUDriverPtr driver,
4600
                 virDomainObjPtr vm,
4601
                 const char *persist_xml,
4602 4603 4604 4605 4606 4607
                 const char *cookiein,
                 int cookieinlen,
                 char **cookieout,
                 int *cookieoutlen,
                 unsigned long flags,
                 unsigned long resource,
4608
                 qemuMigrationSpecPtr spec,
4609
                 virConnectPtr dconn,
4610 4611
                 const char *graphicsuri,
                 size_t nmigrate_disks,
4612
                 const char **migrate_disks,
4613 4614
                 qemuMigrationCompressionPtr compression,
                 qemuMonitorMigrationParamsPtr migParams)
4615
{
4616
    int ret = -1;
4617 4618
    unsigned int migrate_flags = QEMU_MONITOR_MIGRATE_BACKGROUND;
    qemuDomainObjPrivatePtr priv = vm->privateData;
4619
    qemuMigrationCookiePtr mig = NULL;
4620
    qemuMigrationIOThreadPtr iothread = NULL;
4621
    int fd = -1;
4622
    unsigned long migrate_speed = resource ? resource : priv->migMaxBandwidth;
4623
    virErrorPtr orig_err = NULL;
4624
    unsigned int cookieFlags = 0;
4625
    bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
4626
    bool events = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_EVENT);
4627
    bool inPostCopy = false;
4628
    unsigned int waitFlags;
4629
    virDomainDefPtr persistDef = NULL;
4630
    char *timestamp;
4631
    int rc;
4632 4633 4634

    VIR_DEBUG("driver=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
              "cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu, "
4635 4636
              "spec=%p (dest=%d, fwd=%d), dconn=%p, graphicsuri=%s, "
              "nmigrate_disks=%zu, migrate_disks=%p",
4637 4638
              driver, vm, NULLSTR(cookiein), cookieinlen,
              cookieout, cookieoutlen, flags, resource,
4639
              spec, spec->destType, spec->fwdType, dconn,
4640
              NULLSTR(graphicsuri), nmigrate_disks, migrate_disks);
4641

4642 4643 4644 4645 4646 4647 4648 4649 4650 4651
    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;
    }

4652 4653
    if (virLockManagerPluginUsesState(driver->lockManager) &&
        !cookieout) {
4654 4655 4656 4657
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Migration with lock driver %s requires"
                         " cookie support"),
                       virLockManagerPluginGetName(driver->lockManager));
4658 4659 4660
        return -1;
    }

4661 4662 4663
    if (events)
        priv->signalIOError = abort_on_error;

4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674
    if (flags & VIR_MIGRATE_PERSIST_DEST) {
        if (persist_xml) {
            persistDef = qemuMigrationPrepareDef(driver, persist_xml,
                                                 NULL, NULL);
            if (!persistDef)
                goto cleanup;
        } else {
            persistDef = vm->newDef;
        }
    }

4675 4676 4677
    mig = qemuMigrationEatCookie(driver, vm, cookiein, cookieinlen,
                                 cookieFlags | QEMU_MIGRATION_COOKIE_GRAPHICS);
    if (!mig)
4678 4679
        goto cleanup;

4680
    if (qemuDomainMigrateGraphicsRelocate(driver, vm, mig, graphicsuri) < 0)
4681 4682
        VIR_WARN("unable to provide data for graphics client relocation");

4683 4684 4685 4686 4687 4688 4689
    if (migrate_flags & (QEMU_MONITOR_MIGRATE_NON_SHARED_DISK |
                         QEMU_MONITOR_MIGRATE_NON_SHARED_INC)) {
        if (mig->nbd) {
            /* This will update migrate_flags on success */
            if (qemuMigrationDriveMirror(driver, vm, mig,
                                         spec->dest.host.name,
                                         migrate_speed,
4690 4691
                                         &migrate_flags,
                                         nmigrate_disks,
4692 4693
                                         migrate_disks,
                                         dconn) < 0) {
4694 4695 4696 4697 4698 4699 4700 4701
                goto cleanup;
            }
        } else {
            /* Destination doesn't support NBD server.
             * Fall back to previous implementation. */
            VIR_DEBUG("Destination doesn't support NBD server "
                      "Falling back to previous implementation.");
        }
4702 4703
    }

4704
    /* Before EnterMonitor, since qemuMigrationSetOffline already does that */
4705 4706 4707 4708 4709 4710
    if (!(flags & VIR_MIGRATE_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
        if (qemuMigrationSetOffline(driver, vm) < 0)
            goto cleanup;
    }

4711
    if (qemuMigrationSetCompression(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
4712
                                    compression, migParams) < 0)
4713 4714
        goto cleanup;

4715 4716 4717 4718
    if (qemuMigrationSetOption(driver, vm,
                               QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE,
                               flags & VIR_MIGRATE_AUTO_CONVERGE,
                               QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
4719 4720
        goto cleanup;

4721 4722
    if (qemuMigrationSetOption(driver, vm,
                               QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL,
4723
                               flags & VIR_MIGRATE_RDMA_PIN_ALL,
4724 4725 4726
                               QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
        goto cleanup;

4727 4728 4729 4730 4731
    if (qemuMigrationSetPostCopy(driver, vm,
                                 flags & VIR_MIGRATE_POSTCOPY,
                                 QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
        goto cleanup;

4732
    if (qemuMigrationSetParams(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
4733
                               migParams) < 0)
4734 4735
        goto cleanup;

4736 4737
    if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                       QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
4738 4739
        goto cleanup;

4740
    if (priv->job.abortJob) {
4741 4742
        /* explicitly do this *after* we entered the monitor,
         * as this is a critical section so we are guaranteed
4743
         * priv->job.abortJob will not change */
4744
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
4745
        priv->job.current->type = VIR_DOMAIN_JOB_CANCELLED;
4746 4747 4748 4749 4750 4751
        virReportError(VIR_ERR_OPERATION_ABORTED, _("%s: %s"),
                       qemuDomainAsyncJobTypeToString(priv->job.asyncJob),
                       _("canceled by client"));
        goto cleanup;
    }

4752 4753
    if (qemuMonitorSetMigrationSpeed(priv->mon, migrate_speed) < 0)
        goto exit_monitor;
4754

4755 4756
    /* connect to the destination qemu if needed */
    if (spec->destType == MIGRATION_DEST_CONNECT_HOST &&
4757
        qemuMigrationConnect(driver, vm, spec) < 0) {
4758
        goto exit_monitor;
4759
    }
4760

4761 4762 4763 4764 4765 4766
    /* log start of migration */
    if ((timestamp = virTimeStringNow()) != NULL) {
        qemuDomainLogAppendMessage(driver, vm, "%s: initiating migration\n", timestamp);
        VIR_FREE(timestamp);
    }

4767 4768
    switch (spec->destType) {
    case MIGRATION_DEST_HOST:
M
Michael R. Hines 已提交
4769 4770
        if (STREQ(spec->dest.host.protocol, "rdma") &&
            virProcessSetMaxMemLock(vm->pid, vm->def->mem.hard_limit << 10) < 0) {
4771
            goto exit_monitor;
M
Michael R. Hines 已提交
4772
        }
4773
        ret = qemuMonitorMigrateToHost(priv->mon, migrate_flags,
4774
                                       spec->dest.host.protocol,
4775 4776 4777 4778
                                       spec->dest.host.name,
                                       spec->dest.host.port);
        break;

4779 4780 4781 4782
    case MIGRATION_DEST_CONNECT_HOST:
        /* handled above and transformed into MIGRATION_DEST_FD */
        break;

4783
    case MIGRATION_DEST_UNIX:
4784 4785
        ret = qemuMonitorMigrateToUnix(priv->mon, migrate_flags,
                                       spec->dest.unix_socket.file);
4786
        break;
4787 4788

    case MIGRATION_DEST_FD:
4789
        if (spec->fwdType != MIGRATION_FWD_DIRECT) {
4790
            fd = spec->dest.fd.local;
4791 4792
            spec->dest.fd.local = -1;
        }
4793 4794 4795 4796
        ret = qemuMonitorMigrateToFd(priv->mon, migrate_flags,
                                     spec->dest.fd.qemu);
        VIR_FORCE_CLOSE(spec->dest.fd.qemu);
        break;
4797
    }
4798 4799
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        ret = -1;
4800
    if (ret < 0)
4801 4802
        goto cleanup;
    ret = -1;
4803 4804 4805 4806

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

4807 4808 4809 4810 4811
    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.
         */
4812
        if (qemuMigrationCheckJobStatus(driver, vm,
4813 4814
                                        QEMU_ASYNC_JOB_MIGRATION_OUT,
                                        false) < 0)
4815
            goto cancel;
4816

4817 4818 4819 4820 4821 4822 4823
        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;
        }
4824 4825
    }

4826 4827 4828 4829 4830 4831 4832 4833
    if (spec->fwdType != MIGRATION_FWD_DIRECT) {
        if (!(iothread = qemuMigrationStartTunnel(spec->fwd.stream, fd)))
            goto cancel;
        /* If we've created a tunnel, then the 'fd' will be closed in the
         * qemuMigrationIOFunc as data->sock.
         */
        fd = -1;
    }
4834

4835 4836 4837 4838 4839 4840 4841 4842
    waitFlags = 0;
    if (abort_on_error)
        waitFlags |= QEMU_MIGRATION_COMPLETED_ABORT_ON_ERROR;
    if (mig->nbd)
        waitFlags |= QEMU_MIGRATION_COMPLETED_CHECK_STORAGE;
    if (flags & VIR_MIGRATE_POSTCOPY)
        waitFlags |= QEMU_MIGRATION_COMPLETED_POSTCOPY;

4843 4844
    rc = qemuMigrationWaitForCompletion(driver, vm,
                                        QEMU_ASYNC_JOB_MIGRATION_OUT,
4845
                                        dconn, waitFlags);
4846 4847 4848
    if (rc == -2)
        goto cancel;
    else if (rc == -1)
4849
        goto cleanup;
4850

4851 4852 4853
    if (priv->job.current->stats.status == QEMU_MONITOR_MIGRATION_STATUS_POSTCOPY)
        inPostCopy = true;

4854 4855 4856
    /* When migration completed, QEMU will have paused the CPUs for us.
     * Wait for the STOP event to be processed or explicitly stop CPUs
     * (for old QEMU which does not send events) to release the lock state.
4857
     */
4858 4859 4860 4861 4862
    if (priv->monJSON) {
        while (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
            priv->signalStop = true;
            rc = virDomainObjWait(vm);
            priv->signalStop = false;
4863 4864
            if (rc < 0)
                goto cancelPostCopy;
4865
        }
4866 4867
    } else if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING &&
               qemuMigrationSetOffline(driver, vm) < 0) {
4868
        goto cancelPostCopy;
4869
    }
4870 4871
    if (priv->job.completed)
        priv->job.completed->stopped = priv->job.current->stopped;
4872

4873
    ret = 0;
4874

4875
 cleanup:
4876 4877 4878
    if (ret < 0 && !orig_err)
        orig_err = virSaveLastError();

4879
    /* cancel any outstanding NBD jobs */
4880
    if (mig && mig->nbd) {
4881
        if (qemuMigrationCancelDriveMirror(driver, vm, ret == 0,
4882 4883
                                           QEMU_ASYNC_JOB_MIGRATION_OUT,
                                           dconn) < 0)
4884 4885
            ret = -1;
    }
4886

4887
    if (spec->fwdType != MIGRATION_FWD_DIRECT) {
4888
        if (iothread && qemuMigrationStopTunnel(iothread, ret < 0) < 0)
4889 4890
            ret = -1;
    }
4891
    VIR_FORCE_CLOSE(fd);
4892

4893
    if (priv->job.completed) {
4894
        qemuDomainJobInfoUpdateTime(priv->job.completed);
4895
        qemuDomainJobInfoUpdateDowntime(priv->job.completed);
4896
        ignore_value(virTimeMillisNow(&priv->job.completed->sent));
4897
    }
4898

4899
    if (priv->job.current->type == VIR_DOMAIN_JOB_UNBOUNDED && !inPostCopy)
4900 4901
        priv->job.current->type = VIR_DOMAIN_JOB_FAILED;

4902 4903
    cookieFlags |= QEMU_MIGRATION_COOKIE_NETWORK |
                   QEMU_MIGRATION_COOKIE_STATS;
4904

4905
    if (ret == 0 &&
4906 4907 4908
        (qemuMigrationCookieAddPersistent(mig, persistDef) < 0 ||
         qemuMigrationBakeCookie(mig, driver, vm, cookieout,
                                 cookieoutlen, cookieFlags) < 0)) {
4909
        VIR_WARN("Unable to encode migration cookie");
4910
    }
4911

4912 4913
    if (persistDef != vm->newDef)
        virDomainDefFree(persistDef);
4914 4915
    qemuMigrationCookieFree(mig);

4916 4917 4918
    if (events)
        priv->signalIOError = false;

4919 4920 4921 4922 4923
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }

4924 4925
    return ret;

4926 4927 4928 4929
 exit_monitor:
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
    goto cleanup;

4930
 cancel:
4931 4932
    orig_err = virSaveLastError();

4933
    if (virDomainObjIsActive(vm)) {
4934 4935
        if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                           QEMU_ASYNC_JOB_MIGRATION_OUT) == 0) {
4936
            qemuMonitorMigrateCancel(priv->mon);
4937
            ignore_value(qemuDomainObjExitMonitor(driver, vm));
4938
        }
4939
    }
4940
    goto cleanup;
4941 4942 4943 4944 4945 4946 4947

 cancelPostCopy:
    priv->job.current->type = VIR_DOMAIN_JOB_FAILED;
    if (inPostCopy)
        goto cancel;
    else
        goto cleanup;
4948 4949
}

4950
/* Perform migration using QEMU's native migrate support,
4951 4952
 * not encrypted obviously
 */
4953
static int doNativeMigrate(virQEMUDriverPtr driver,
4954
                           virDomainObjPtr vm,
4955
                           const char *persist_xml,
4956 4957 4958 4959 4960 4961
                           const char *uri,
                           const char *cookiein,
                           int cookieinlen,
                           char **cookieout,
                           int *cookieoutlen,
                           unsigned long flags,
4962
                           unsigned long resource,
4963
                           virConnectPtr dconn,
4964 4965
                           const char *graphicsuri,
                           size_t nmigrate_disks,
4966
                           const char **migrate_disks,
4967 4968
                           qemuMigrationCompressionPtr compression,
                           qemuMonitorMigrationParamsPtr migParams)
4969
{
4970
    qemuDomainObjPrivatePtr priv = vm->privateData;
M
Martin Kletzander 已提交
4971
    virURIPtr uribits = NULL;
4972
    int ret = -1;
4973 4974 4975
    qemuMigrationSpec spec;

    VIR_DEBUG("driver=%p, vm=%p, uri=%s, cookiein=%s, cookieinlen=%d, "
4976
              "cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu, "
4977
              "graphicsuri=%s, nmigrate_disks=%zu migrate_disks=%p",
4978
              driver, vm, uri, NULLSTR(cookiein), cookieinlen,
4979
              cookieout, cookieoutlen, flags, resource,
4980
              NULLSTR(graphicsuri), nmigrate_disks, migrate_disks);
4981

4982
    if (!(uribits = qemuMigrationParseURI(uri, NULL)))
4983 4984
        return -1;

4985 4986 4987 4988 4989 4990 4991
    if (uribits->scheme == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing scheme in migration URI: %s"),
                       uri);
        goto cleanup;
    }

M
Michael R. Hines 已提交
4992 4993 4994 4995 4996
    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"));
4997
            goto cleanup;
M
Michael R. Hines 已提交
4998
        }
4999
        if (!virMemoryLimitIsSet(vm->def->mem.hard_limit)) {
M
Michael R. Hines 已提交
5000 5001 5002
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot start RDMA migration with no memory hard "
                             "limit set"));
5003
            goto cleanup;
M
Michael R. Hines 已提交
5004 5005 5006
        }
    }

5007
    if (STRNEQ(uribits->scheme, "rdma"))
5008 5009
        spec.destType = MIGRATION_DEST_CONNECT_HOST;
    else
5010
        spec.destType = MIGRATION_DEST_HOST;
5011
    spec.dest.host.protocol = uribits->scheme;
5012 5013 5014
    spec.dest.host.name = uribits->server;
    spec.dest.host.port = uribits->port;
    spec.fwdType = MIGRATION_FWD_DIRECT;
5015

5016
    ret = qemuMigrationRun(driver, vm, persist_xml, cookiein, cookieinlen, cookieout,
5017
                           cookieoutlen, flags, resource, &spec, dconn,
5018
                           graphicsuri, nmigrate_disks, migrate_disks,
5019
                           compression, migParams);
5020 5021 5022 5023

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

5024
 cleanup:
5025
    virURIFree(uribits);
5026 5027 5028 5029 5030

    return ret;
}


5031
static int doTunnelMigrate(virQEMUDriverPtr driver,
5032 5033
                           virDomainObjPtr vm,
                           virStreamPtr st,
5034
                           const char *persist_xml,
5035 5036 5037 5038 5039
                           const char *cookiein,
                           int cookieinlen,
                           char **cookieout,
                           int *cookieoutlen,
                           unsigned long flags,
5040
                           unsigned long resource,
5041
                           virConnectPtr dconn,
5042 5043
                           const char *graphicsuri,
                           size_t nmigrate_disks,
5044
                           const char **migrate_disks,
5045 5046
                           qemuMigrationCompressionPtr compression,
                           qemuMonitorMigrationParamsPtr migParams)
5047
{
5048
    virNetSocketPtr sock = NULL;
5049 5050
    int ret = -1;
    qemuMigrationSpec spec;
5051
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
5052
    int fds[2] = { -1, -1 };
5053 5054

    VIR_DEBUG("driver=%p, vm=%p, st=%p, cookiein=%s, cookieinlen=%d, "
5055
              "cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu, "
5056
              "graphicsuri=%s, nmigrate_disks=%zu, migrate_disks=%p",
5057
              driver, vm, st, NULLSTR(cookiein), cookieinlen,
5058
              cookieout, cookieoutlen, flags, resource,
5059
              NULLSTR(graphicsuri), nmigrate_disks, migrate_disks);
5060 5061 5062 5063

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

5064

5065 5066 5067
    spec.destType = MIGRATION_DEST_FD;
    spec.dest.fd.qemu = -1;
    spec.dest.fd.local = -1;
5068

5069 5070 5071 5072 5073 5074 5075 5076 5077 5078
    if (pipe2(fds, O_CLOEXEC) == 0) {
        spec.dest.fd.qemu = fds[1];
        spec.dest.fd.local = fds[0];
    }
    if (spec.dest.fd.qemu == -1 ||
        virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def,
                                          spec.dest.fd.qemu) < 0) {
        virReportSystemError(errno, "%s",
                             _("cannot create pipe for tunnelled migration"));
        goto cleanup;
5079 5080
    }

5081 5082 5083
    ret = qemuMigrationRun(driver, vm, persist_xml, cookiein, cookieinlen,
                           cookieout, cookieoutlen, flags, resource, &spec,
                           dconn, graphicsuri, nmigrate_disks, migrate_disks,
5084
                           compression, migParams);
5085

5086
 cleanup:
5087 5088 5089 5090
    if (spec.destType == MIGRATION_DEST_FD) {
        VIR_FORCE_CLOSE(spec.dest.fd.qemu);
        VIR_FORCE_CLOSE(spec.dest.fd.local);
    } else {
5091
        virObjectUnref(sock);
5092 5093
        VIR_FREE(spec.dest.unix_socket.file);
    }
5094

5095
    virObjectUnref(cfg);
5096 5097 5098 5099
    return ret;
}


5100 5101 5102 5103
/* 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 */
5104
static int doPeer2PeerMigrate2(virQEMUDriverPtr driver,
5105
                               virConnectPtr sconn ATTRIBUTE_UNUSED,
5106 5107
                               virConnectPtr dconn,
                               virDomainObjPtr vm,
5108
                               const char *dconnuri,
5109 5110 5111
                               unsigned long flags,
                               const char *dname,
                               unsigned long resource)
5112 5113 5114
{
    virDomainPtr ddomain = NULL;
    char *uri_out = NULL;
5115
    char *cookie = NULL;
5116 5117 5118
    char *dom_xml = NULL;
    int cookielen = 0, ret;
    virErrorPtr orig_err = NULL;
5119
    bool cancelled;
5120
    virStreamPtr st = NULL;
5121
    unsigned long destflags;
5122
    qemuMigrationCompressionPtr compression = NULL;
5123
    qemuMonitorMigrationParams migParams = { 0 };
5124

5125
    VIR_DEBUG("driver=%p, sconn=%p, dconn=%p, vm=%p, dconnuri=%s, "
5126
              "flags=%lx, dname=%s, resource=%lu",
5127 5128
              driver, sconn, dconn, vm, NULLSTR(dconnuri),
              flags, NULLSTR(dname), resource);
5129

5130 5131 5132 5133 5134
    /* 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,
5135 5136
                                        QEMU_DOMAIN_FORMAT_LIVE_FLAGS |
                                        VIR_DOMAIN_XML_MIGRATABLE)))
5137 5138 5139 5140 5141
        return -1;

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

5142 5143
    destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
                          VIR_MIGRATE_AUTO_CONVERGE);
5144

5145 5146 5147
    if (!(compression = qemuMigrationCompressionParse(NULL, 0, flags)))
        goto cleanup;

5148 5149 5150 5151 5152 5153 5154 5155 5156 5157
    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;

5158
        qemuDomainObjEnterRemote(vm);
5159
        ret = dconn->driver->domainMigratePrepareTunnel
5160
            (dconn, st, destflags, dname, resource, dom_xml);
5161
        qemuDomainObjExitRemote(vm);
5162
    } else {
5163
        qemuDomainObjEnterRemote(vm);
5164 5165
        ret = dconn->driver->domainMigratePrepare2
            (dconn, &cookie, &cookielen, NULL, &uri_out,
5166
             destflags, dname, resource, dom_xml);
5167
        qemuDomainObjExitRemote(vm);
5168 5169 5170
    }
    VIR_FREE(dom_xml);
    if (ret == -1)
5171 5172 5173
        goto cleanup;

    /* the domain may have shutdown or crashed while we had the locks dropped
5174
     * in qemuDomainObjEnterRemote, so check again
5175 5176
     */
    if (!virDomainObjIsActive(vm)) {
5177 5178
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
5179 5180 5181
        goto cleanup;
    }

5182 5183
    if (!(flags & VIR_MIGRATE_TUNNELLED) &&
        (uri_out == NULL)) {
5184 5185
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domainMigratePrepare2 did not set uri"));
5186
        cancelled = true;
5187
        orig_err = virSaveLastError();
5188
        goto finish;
5189 5190
    }

5191 5192 5193 5194
    /* Perform the migration.  The driver isn't supposed to return
     * until the migration is complete.
     */
    VIR_DEBUG("Perform %p", sconn);
5195
    qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM2);
5196
    if (flags & VIR_MIGRATE_TUNNELLED)
5197
        ret = doTunnelMigrate(driver, vm, st, NULL,
5198
                              NULL, 0, NULL, NULL,
5199
                              flags, resource, dconn,
5200
                              NULL, 0, NULL, compression, &migParams);
5201
    else
5202
        ret = doNativeMigrate(driver, vm, NULL, uri_out,
5203 5204
                              cookie, cookielen,
                              NULL, NULL, /* No out cookie with v2 migration */
5205 5206
                              flags, resource, dconn, NULL, 0, NULL,
                              compression, &migParams);
5207 5208 5209 5210

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

5212 5213 5214
    /* If Perform returns < 0, then we need to cancel the VM
     * startup on the destination
     */
5215
    cancelled = ret < 0;
5216

5217
 finish:
5218 5219 5220 5221
    /* 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.
     */
5222
    dname = dname ? dname : vm->def->name;
5223
    VIR_DEBUG("Finish2 %p ret=%d", dconn, ret);
5224
    qemuDomainObjEnterRemote(vm);
5225
    ddomain = dconn->driver->domainMigrateFinish2
5226
        (dconn, dname, cookie, cookielen,
5227
         uri_out ? uri_out : dconnuri, destflags, cancelled);
5228
    qemuDomainObjExitRemote(vm);
5229 5230
    if (cancelled && ddomain)
        VIR_ERROR(_("finish step ignored that migration was cancelled"));
5231

5232
 cleanup:
5233
    if (ddomain) {
5234
        virObjectUnref(ddomain);
5235 5236 5237 5238
        ret = 0;
    } else {
        ret = -1;
    }
5239

5240
    virObjectUnref(st);
5241 5242 5243 5244 5245 5246

    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
    VIR_FREE(uri_out);
5247
    VIR_FREE(cookie);
5248
    VIR_FREE(compression);
5249 5250

    return ret;
5251 5252 5253
}


5254 5255 5256 5257
/* 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 */
5258 5259 5260 5261 5262 5263 5264
static int
doPeer2PeerMigrate3(virQEMUDriverPtr driver,
                    virConnectPtr sconn,
                    virConnectPtr dconn,
                    const char *dconnuri,
                    virDomainObjPtr vm,
                    const char *xmlin,
5265
                    const char *persist_xml,
5266 5267
                    const char *dname,
                    const char *uri,
5268
                    const char *graphicsuri,
5269
                    const char *listenAddress,
5270 5271
                    size_t nmigrate_disks,
                    const char **migrate_disks,
5272
                    int nbdPort,
5273
                    qemuMigrationCompressionPtr compression,
5274
                    qemuMonitorMigrationParamsPtr migParams,
5275 5276 5277
                    unsigned long long bandwidth,
                    bool useParams,
                    unsigned long flags)
5278 5279 5280 5281 5282 5283 5284 5285 5286 5287
{
    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;
5288
    bool cancelled = true;
5289
    virStreamPtr st = NULL;
5290
    unsigned long destflags;
5291 5292 5293
    virTypedParameterPtr params = NULL;
    int nparams = 0;
    int maxparams = 0;
5294
    size_t i;
5295 5296

    VIR_DEBUG("driver=%p, sconn=%p, dconn=%p, dconnuri=%s, vm=%p, xmlin=%s, "
5297
              "dname=%s, uri=%s, graphicsuri=%s, listenAddress=%s, "
5298 5299
              "nmigrate_disks=%zu, migrate_disks=%p, nbdPort=%d, "
              "bandwidth=%llu, useParams=%d, flags=%lx",
5300
              driver, sconn, dconn, NULLSTR(dconnuri), vm, NULLSTR(xmlin),
5301
              NULLSTR(dname), NULLSTR(uri), NULLSTR(graphicsuri),
5302
              NULLSTR(listenAddress), nmigrate_disks, migrate_disks, nbdPort,
5303
              bandwidth, useParams, flags);
5304

5305 5306 5307 5308 5309
    /* 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.  */

5310
    dom_xml = qemuMigrationBeginPhase(driver, vm, xmlin, dname,
5311 5312
                                      &cookieout, &cookieoutlen,
                                      nmigrate_disks, migrate_disks, flags);
5313 5314 5315
    if (!dom_xml)
        goto cleanup;

5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335
    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;
5336 5337 5338 5339 5340 5341

        if (graphicsuri &&
            virTypedParamsAddString(&params, &nparams, &maxparams,
                                    VIR_MIGRATE_PARAM_GRAPHICS_URI,
                                    graphicsuri) < 0)
            goto cleanup;
5342 5343 5344 5345 5346
        if (listenAddress &&
            virTypedParamsAddString(&params, &nparams, &maxparams,
                                    VIR_MIGRATE_PARAM_LISTEN_ADDRESS,
                                    listenAddress) < 0)
            goto cleanup;
5347 5348 5349 5350 5351
        for (i = 0; i < nmigrate_disks; i++)
            if (virTypedParamsAddString(&params, &nparams, &maxparams,
                                        VIR_MIGRATE_PARAM_MIGRATE_DISKS,
                                        migrate_disks[i]) < 0)
                goto cleanup;
5352 5353 5354 5355 5356
        if (nbdPort &&
            virTypedParamsAddInt(&params, &nparams, &maxparams,
                                 VIR_MIGRATE_PARAM_DISKS_PORT,
                                 nbdPort) < 0)
            goto cleanup;
5357 5358 5359 5360

        if (qemuMigrationCompressionDump(compression, &params, &nparams,
                                         &maxparams, &flags) < 0)
            goto cleanup;
5361 5362
    }

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

5366 5367
    destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
                          VIR_MIGRATE_AUTO_CONVERGE);
5368

5369 5370 5371 5372 5373 5374 5375 5376 5377
    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;

5378
        qemuDomainObjEnterRemote(vm);
5379 5380 5381 5382 5383 5384 5385 5386 5387
        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);
        }
5388
        qemuDomainObjExitRemote(vm);
5389
    } else {
5390
        qemuDomainObjEnterRemote(vm);
5391 5392 5393 5394 5395 5396 5397 5398 5399
        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);
        }
5400
        qemuDomainObjExitRemote(vm);
5401 5402 5403 5404 5405
    }
    VIR_FREE(dom_xml);
    if (ret == -1)
        goto cleanup;

L
liguang 已提交
5406 5407 5408 5409
    if (flags & VIR_MIGRATE_OFFLINE) {
        VIR_DEBUG("Offline migration, skipping Perform phase");
        VIR_FREE(cookieout);
        cookieoutlen = 0;
5410
        cancelled = false;
L
liguang 已提交
5411 5412 5413
        goto finish;
    }

5414 5415 5416 5417
    if (uri_out) {
        uri = uri_out;
        if (useParams &&
            virTypedParamsReplaceString(&params, &nparams,
5418 5419
                                        VIR_MIGRATE_PARAM_URI, uri_out) < 0) {
            orig_err = virSaveLastError();
5420
            goto finish;
5421
        }
5422
    } else if (!uri && !(flags & VIR_MIGRATE_TUNNELLED)) {
5423 5424
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("domainMigratePrepare3 did not set uri"));
5425
        orig_err = virSaveLastError();
5426 5427 5428 5429 5430 5431 5432 5433
        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.
     */
5434
    VIR_DEBUG("Perform3 %p uri=%s", sconn, NULLSTR(uri));
5435
    qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3);
5436 5437 5438 5439 5440
    VIR_FREE(cookiein);
    cookiein = cookieout;
    cookieinlen = cookieoutlen;
    cookieout = NULL;
    cookieoutlen = 0;
5441
    if (flags & VIR_MIGRATE_TUNNELLED) {
5442
        ret = doTunnelMigrate(driver, vm, st, persist_xml,
5443 5444
                              cookiein, cookieinlen,
                              &cookieout, &cookieoutlen,
5445
                              flags, bandwidth, dconn, graphicsuri,
5446 5447
                              nmigrate_disks, migrate_disks, compression,
                              migParams);
5448
    } else {
5449
        ret = doNativeMigrate(driver, vm, persist_xml, uri,
5450 5451
                              cookiein, cookieinlen,
                              &cookieout, &cookieoutlen,
5452
                              flags, bandwidth, dconn, graphicsuri,
5453 5454
                              nmigrate_disks, migrate_disks, compression,
                              migParams);
5455
    }
5456 5457

    /* Perform failed. Make sure Finish doesn't overwrite the error */
5458
    if (ret < 0) {
5459
        orig_err = virSaveLastError();
5460 5461 5462 5463
    } else {
        qemuMigrationJobSetPhase(driver, vm,
                                 QEMU_MIGRATION_PHASE_PERFORM3_DONE);
    }
5464 5465 5466 5467

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

5470
 finish:
5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482
    /*
     * 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;
5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505

    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);
    }
5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525

    if (cancelled) {
        if (ddomain) {
            VIR_ERROR(_("finish step ignored that migration was cancelled"));
        } else {
            /* If Finish reported a useful error, use it instead of the
             * original "migration unexpectedly failed" error.
             *
             * This is ugly but we can't do better with the APIs we have. We
             * only replace the error if Finish was called with cancelled == 1
             * and reported a real error (old libvirt would report an error
             * from RPC instead of MIGRATE_FINISH_OK), which only happens when
             * the domain died on destination. To further reduce a possibility
             * of false positives we also check that Perform returned
             * VIR_ERR_OPERATION_FAILED.
             */
            if (orig_err &&
                orig_err->domain == VIR_FROM_QEMU &&
                orig_err->code == VIR_ERR_OPERATION_FAILED) {
                virErrorPtr err = virGetLastError();
5526 5527
                if (err &&
                    err->domain == VIR_FROM_QEMU &&
5528 5529 5530 5531 5532 5533 5534
                    err->code != VIR_ERR_MIGRATE_FINISH_OK) {
                    virFreeError(orig_err);
                    orig_err = NULL;
                }
            }
        }
    }
5535

5536 5537 5538 5539 5540 5541 5542
    /* 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.
5543
     */
5544
    cancelled = ddomain == NULL;
5545

5546 5547 5548 5549 5550 5551
    /* 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();

5552 5553 5554 5555
    /*
     * If cancelled, then src VM will be restarted, else
     * it will be killed
     */
5556
    VIR_DEBUG("Confirm3 %p cancelled=%d vm=%p", sconn, cancelled, vm);
5557 5558 5559 5560 5561
    VIR_FREE(cookiein);
    cookiein = cookieout;
    cookieinlen = cookieoutlen;
    cookieout = NULL;
    cookieoutlen = 0;
5562 5563 5564
    ret = qemuMigrationConfirmPhase(driver, sconn, vm,
                                    cookiein, cookieinlen,
                                    flags, cancelled);
5565 5566 5567 5568
    /* 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.
     */
5569 5570 5571
    if (ret < 0)
        VIR_WARN("Guest %s probably left in 'paused' state on source",
                 vm->def->name);
5572 5573 5574

 cleanup:
    if (ddomain) {
5575
        virObjectUnref(ddomain);
5576 5577 5578 5579 5580
        ret = 0;
    } else {
        ret = -1;
    }

5581
    virObjectUnref(st);
5582 5583 5584 5585 5586 5587 5588 5589

    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
    VIR_FREE(uri_out);
    VIR_FREE(cookiein);
    VIR_FREE(cookieout);
5590
    virTypedParamsFree(params, nparams);
5591 5592 5593 5594
    return ret;
}


5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606
static void
qemuMigrationConnectionClosed(virConnectPtr conn,
                              int reason,
                              void *opaque)
{
    virDomainObjPtr vm = opaque;

    VIR_DEBUG("conn=%p, reason=%d, vm=%s", conn, reason, vm->def->name);
    virDomainObjBroadcast(vm);
}


5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618
static int virConnectCredType[] = {
    VIR_CRED_AUTHNAME,
    VIR_CRED_PASSPHRASE,
};


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


5619
static int doPeer2PeerMigrate(virQEMUDriverPtr driver,
5620
                              virConnectPtr sconn,
5621
                              virDomainObjPtr vm,
5622
                              const char *xmlin,
5623
                              const char *persist_xml,
5624
                              const char *dconnuri,
5625
                              const char *uri,
5626
                              const char *graphicsuri,
5627
                              const char *listenAddress,
5628 5629
                              size_t nmigrate_disks,
                              const char **migrate_disks,
5630
                              int nbdPort,
5631
                              qemuMigrationCompressionPtr compression,
5632
                              qemuMonitorMigrationParamsPtr migParams,
5633 5634
                              unsigned long flags,
                              const char *dname,
5635 5636
                              unsigned long resource,
                              bool *v3proto)
5637 5638 5639 5640
{
    int ret = -1;
    virConnectPtr dconn = NULL;
    bool p2p;
5641
    virErrorPtr orig_err = NULL;
5642
    bool offline = false;
5643
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
5644
    bool useParams;
5645

5646 5647
    VIR_DEBUG("driver=%p, sconn=%p, vm=%p, xmlin=%s, dconnuri=%s, uri=%s, "
              "graphicsuri=%s, listenAddress=%s, nmigrate_disks=%zu, "
5648 5649
              "migrate_disks=%p, nbdPort=%d, flags=%lx, dname=%s, "
              "resource=%lu",
5650
              driver, sconn, vm, NULLSTR(xmlin), NULLSTR(dconnuri),
5651
              NULLSTR(uri), NULLSTR(graphicsuri), NULLSTR(listenAddress),
5652 5653
              nmigrate_disks, migrate_disks, nbdPort, flags, NULLSTR(dname),
              resource);
5654

5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668
    if (flags & VIR_MIGRATE_TUNNELLED && uri) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("migration URI is not supported by tunnelled "
                         "migration"));
        goto cleanup;
    }

    if (flags & VIR_MIGRATE_TUNNELLED && listenAddress) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("listen address is not supported by tunnelled "
                         "migration"));
        goto cleanup;
    }

5669 5670 5671 5672 5673 5674 5675
    if (flags & VIR_MIGRATE_TUNNELLED && nbdPort) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("disk port address is not supported by tunnelled "
                         "migration"));
        goto cleanup;
    }

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

5680
    qemuDomainObjEnterRemote(vm);
5681
    dconn = virConnectOpenAuth(dconnuri, &virConnectAuthConfig, 0);
5682
    qemuDomainObjExitRemote(vm);
5683
    if (dconn == NULL) {
5684
        virReportError(VIR_ERR_OPERATION_FAILED,
5685 5686
                       _("Failed to connect to remote libvirt URI %s: %s"),
                       dconnuri, virGetLastErrorMessage());
5687
        virObjectUnref(cfg);
5688 5689 5690
        return -1;
    }

5691 5692
    if (virConnectSetKeepAlive(dconn, cfg->keepAliveInterval,
                               cfg->keepAliveCount) < 0)
5693 5694
        goto cleanup;

5695 5696 5697 5698 5699
    if (virConnectRegisterCloseCallback(dconn, qemuMigrationConnectionClosed,
                                        vm, NULL) < 0) {
        goto cleanup;
    }

5700
    qemuDomainObjEnterRemote(vm);
5701 5702
    p2p = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
                                   VIR_DRV_FEATURE_MIGRATION_P2P);
5703
        /* v3proto reflects whether the caller used Perform3, but with
5704
         * p2p migrate, regardless of whether Perform2 or Perform3
5705 5706 5707 5708
         * were used, we decide protocol based on what target supports
         */
    *v3proto = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
                                        VIR_DRV_FEATURE_MIGRATION_V3);
5709 5710
    useParams = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
                                         VIR_DRV_FEATURE_MIGRATION_PARAMS);
L
liguang 已提交
5711 5712 5713
    if (flags & VIR_MIGRATE_OFFLINE)
        offline = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
                                           VIR_DRV_FEATURE_MIGRATION_OFFLINE);
5714
    qemuDomainObjExitRemote(vm);
5715

5716
    if (!p2p) {
5717 5718
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Destination libvirt does not support peer-to-peer migration protocol"));
5719 5720 5721
        goto cleanup;
    }

5722 5723
    /* Only xmlin, dname, uri, and bandwidth parameters can be used with
     * old-style APIs. */
5724
    if (!useParams && (graphicsuri || listenAddress || nmigrate_disks)) {
5725 5726 5727 5728 5729 5730
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Migration APIs with extensible parameters are not "
                         "supported but extended parameters were passed"));
        goto cleanup;
    }

L
liguang 已提交
5731 5732 5733 5734 5735 5736 5737
    if (flags & VIR_MIGRATE_OFFLINE && !offline) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("offline migration is not supported by "
                         "the destination host"));
        goto cleanup;
    }

5738
    /* domain may have been stopped while we were talking to remote daemon */
L
liguang 已提交
5739
    if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
5740 5741
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
5742 5743 5744
        goto cleanup;
    }

5745 5746 5747 5748 5749 5750 5751
    /* 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;

5752 5753
    if (*v3proto) {
        ret = doPeer2PeerMigrate3(driver, sconn, dconn, dconnuri, vm, xmlin,
5754 5755
                                  persist_xml, dname, uri, graphicsuri,
                                  listenAddress, nmigrate_disks, migrate_disks,
5756 5757
                                  nbdPort, compression, migParams, resource,
                                  useParams, flags);
5758
    } else {
5759
        ret = doPeer2PeerMigrate2(driver, sconn, dconn, vm,
5760
                                  dconnuri, flags, dname, resource);
5761
    }
5762

5763
 cleanup:
5764
    orig_err = virSaveLastError();
5765
    qemuDomainObjEnterRemote(vm);
5766
    virConnectUnregisterCloseCallback(dconn, qemuMigrationConnectionClosed);
5767
    virObjectUnref(dconn);
5768
    qemuDomainObjExitRemote(vm);
5769 5770 5771 5772
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
5773
    virObjectUnref(cfg);
5774 5775 5776 5777
    return ret;
}


5778 5779 5780 5781 5782 5783
/*
 * 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
5784
qemuMigrationPerformJob(virQEMUDriverPtr driver,
5785 5786 5787
                        virConnectPtr conn,
                        virDomainObjPtr vm,
                        const char *xmlin,
5788
                        const char *persist_xml,
5789 5790
                        const char *dconnuri,
                        const char *uri,
5791
                        const char *graphicsuri,
5792
                        const char *listenAddress,
5793 5794
                        size_t nmigrate_disks,
                        const char **migrate_disks,
5795
                        int nbdPort,
5796
                        qemuMigrationCompressionPtr compression,
5797
                        qemuMonitorMigrationParamsPtr migParams,
5798
                        const char *cookiein,
5799 5800 5801 5802 5803 5804 5805
                        int cookieinlen,
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
                        const char *dname,
                        unsigned long resource,
                        bool v3proto)
5806
{
5807
    virObjectEventPtr event = NULL;
5808
    int ret = -1;
5809
    virErrorPtr orig_err = NULL;
5810
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
5811

5812
    if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
5813 5814
        goto cleanup;

L
liguang 已提交
5815
    if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
5816 5817
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
5818 5819 5820
        goto endjob;
    }

5821
    if (!qemuMigrationIsAllowed(driver, vm, true, flags))
5822
        goto endjob;
5823

5824 5825
    if (!(flags & VIR_MIGRATE_UNSAFE) &&
        !qemuMigrationIsSafe(vm->def, nmigrate_disks, migrate_disks))
5826
        goto endjob;
5827

5828
    qemuMigrationStoreDomainState(vm);
5829 5830

    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
5831
        ret = doPeer2PeerMigrate(driver, conn, vm, xmlin, persist_xml,
5832
                                 dconnuri, uri, graphicsuri, listenAddress,
5833
                                 nmigrate_disks, migrate_disks, nbdPort,
5834 5835
                                 compression, migParams, flags, dname, resource,
                                 &v3proto);
5836
    } else {
5837
        qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM2);
5838
        ret = doNativeMigrate(driver, vm, persist_xml, uri, cookiein, cookieinlen,
5839
                              cookieout, cookieoutlen,
5840
                              flags, resource, NULL, NULL, 0, NULL,
5841
                              compression, migParams);
5842
    }
5843 5844
    if (ret < 0)
        goto endjob;
5845

5846 5847 5848 5849
    /*
     * In v3 protocol, the source VM is not killed off until the
     * confirm step.
     */
5850
    if (!v3proto) {
5851
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED,
5852
                        QEMU_ASYNC_JOB_MIGRATION_OUT,
5853
                        VIR_QEMU_PROCESS_STOP_MIGRATED);
5854
        virDomainAuditStop(vm, "migrated");
5855
        event = virDomainEventLifecycleNewFromObj(vm,
5856 5857
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
5858 5859
    }

5860
 endjob:
5861 5862 5863
    if (ret < 0)
        orig_err = virSaveLastError();

5864
    if (qemuMigrationRestoreDomainState(conn, vm)) {
5865
        event = virDomainEventLifecycleNewFromObj(vm,
5866 5867 5868
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
    }
5869

5870
    qemuMigrationJobFinish(driver, vm);
5871
    if (!virDomainObjIsActive(vm) && ret == 0) {
5872
        if (flags & VIR_MIGRATE_UNDEFINE_SOURCE) {
5873
            virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm);
5874 5875
            vm->persistent = 0;
        }
5876
        qemuDomainRemoveInactive(driver, vm);
5877 5878
    }

5879 5880 5881 5882 5883
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }

5884
 cleanup:
M
Michal Privoznik 已提交
5885
    virDomainObjEndAPI(&vm);
5886
    qemuDomainEventQueue(driver, event);
5887
    virObjectUnref(cfg);
5888 5889 5890 5891 5892 5893 5894
    return ret;
}

/*
 * This implements perform phase of v3 migration protocol.
 */
static int
5895
qemuMigrationPerformPhase(virQEMUDriverPtr driver,
5896 5897
                          virConnectPtr conn,
                          virDomainObjPtr vm,
5898
                          const char *persist_xml,
5899
                          const char *uri,
5900
                          const char *graphicsuri,
5901 5902
                          size_t nmigrate_disks,
                          const char **migrate_disks,
5903
                          qemuMigrationCompressionPtr compression,
5904
                          qemuMonitorMigrationParamsPtr migParams,
5905 5906 5907 5908 5909 5910 5911
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
                          unsigned long flags,
                          unsigned long resource)
{
5912
    virObjectEventPtr event = NULL;
5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923
    int ret = -1;

    /* 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);
5924 5925
    virCloseCallbacksUnset(driver->closeCallbacks, vm,
                           qemuMigrationCleanup);
5926

5927
    ret = doNativeMigrate(driver, vm, persist_xml, uri, cookiein, cookieinlen,
5928
                          cookieout, cookieoutlen,
5929
                          flags, resource, NULL, graphicsuri,
5930
                          nmigrate_disks, migrate_disks, compression, migParams);
5931

5932 5933 5934 5935 5936
    if (ret < 0) {
        if (qemuMigrationRestoreDomainState(conn, vm)) {
            event = virDomainEventLifecycleNewFromObj(vm,
                                                      VIR_DOMAIN_EVENT_RESUMED,
                                                      VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
5937
        }
5938
        goto endjob;
5939
    }
5940 5941 5942

    qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3_DONE);

5943 5944
    if (virCloseCallbacksSet(driver->closeCallbacks, vm, conn,
                             qemuMigrationCleanup) < 0)
5945 5946
        goto endjob;

5947
 endjob:
5948
    if (ret < 0)
5949
        qemuMigrationJobFinish(driver, vm);
5950
    else
5951
        qemuMigrationJobContinue(vm);
5952
    if (!virDomainObjIsActive(vm))
5953
        qemuDomainRemoveInactive(driver, vm);
5954

5955
 cleanup:
M
Michal Privoznik 已提交
5956
    virDomainObjEndAPI(&vm);
5957
    qemuDomainEventQueue(driver, event);
5958 5959 5960
    return ret;
}

5961
int
5962
qemuMigrationPerform(virQEMUDriverPtr driver,
5963 5964 5965
                     virConnectPtr conn,
                     virDomainObjPtr vm,
                     const char *xmlin,
5966
                     const char *persist_xml,
5967 5968
                     const char *dconnuri,
                     const char *uri,
5969
                     const char *graphicsuri,
5970
                     const char *listenAddress,
5971 5972
                     size_t nmigrate_disks,
                     const char **migrate_disks,
5973
                     int nbdPort,
5974
                     qemuMigrationCompressionPtr compression,
5975
                     qemuMonitorMigrationParamsPtr migParams,
5976 5977 5978 5979 5980 5981 5982 5983 5984 5985
                     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, "
5986
              "uri=%s, graphicsuri=%s, listenAddress=%s, "
5987
              "nmigrate_disks=%zu, migrate_disks=%p, nbdPort=%d, "
5988 5989
              "cookiein=%s, cookieinlen=%d, cookieout=%p, cookieoutlen=%p, "
              "flags=%lx, dname=%s, resource=%lu, v3proto=%d",
5990
              driver, conn, vm, NULLSTR(xmlin), NULLSTR(dconnuri),
5991
              NULLSTR(uri), NULLSTR(graphicsuri), NULLSTR(listenAddress),
5992 5993 5994
              nmigrate_disks, migrate_disks, nbdPort,
              NULLSTR(cookiein), cookieinlen, cookieout, cookieoutlen,
              flags, NULLSTR(dname), resource, v3proto);
5995 5996 5997

    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
        if (cookieinlen) {
5998 5999
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("received unexpected cookie with P2P migration"));
6000 6001 6002
            return -1;
        }

6003
        return qemuMigrationPerformJob(driver, conn, vm, xmlin, persist_xml, dconnuri, uri,
6004
                                       graphicsuri, listenAddress,
6005
                                       nmigrate_disks, migrate_disks, nbdPort,
6006 6007
                                       compression, migParams,
                                       cookiein, cookieinlen,
6008 6009
                                       cookieout, cookieoutlen,
                                       flags, dname, resource, v3proto);
6010 6011
    } else {
        if (dconnuri) {
6012 6013
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Unexpected dconnuri parameter with non-peer2peer migration"));
6014 6015 6016 6017
            return -1;
        }

        if (v3proto) {
6018
            return qemuMigrationPerformPhase(driver, conn, vm, persist_xml, uri,
6019
                                             graphicsuri,
6020
                                             nmigrate_disks, migrate_disks,
6021 6022
                                             compression, migParams,
                                             cookiein, cookieinlen,
6023
                                             cookieout, cookieoutlen,
6024
                                             flags, resource);
6025
        } else {
6026
            return qemuMigrationPerformJob(driver, conn, vm, xmlin, persist_xml, NULL,
6027
                                           uri, graphicsuri, listenAddress,
6028
                                           nmigrate_disks, migrate_disks, nbdPort,
6029 6030
                                           compression, migParams,
                                           cookiein, cookieinlen,
6031 6032 6033 6034 6035
                                           cookieout, cookieoutlen, flags,
                                           dname, resource, v3proto);
        }
    }
}
6036

6037
static int
6038 6039
qemuMigrationVPAssociatePortProfiles(virDomainDefPtr def)
{
6040
    size_t i;
6041 6042 6043 6044 6045
    int last_good_net = -1;
    virDomainNetDefPtr net;

    for (i = 0; i < def->nnets; i++) {
        net = def->nets[i];
6046
        if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
6047
            if (virNetDevVPortProfileAssociate(net->ifname,
6048
                                               virDomainNetGetActualVirtPortProfile(net),
6049
                                               &net->mac,
6050
                                               virDomainNetGetActualDirectDev(net),
6051
                                               -1,
6052
                                               def->uuid,
6053 6054
                                               VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_FINISH,
                                               false) < 0) {
6055 6056 6057
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("Port profile Associate failed for %s"),
                               net->ifname);
6058
                goto err_exit;
6059
            }
6060
            last_good_net = i;
6061
            VIR_DEBUG("Port profile Associate succeeded for %s", net->ifname);
6062

6063
            if (virNetDevMacVLanVPortProfileRegisterCallback(net->ifname, &net->mac,
6064 6065 6066 6067
                                                             virDomainNetGetActualDirectDev(net), def->uuid,
                                                             virDomainNetGetActualVirtPortProfile(net),
                                                             VIR_NETDEV_VPORT_PROFILE_OP_CREATE))
                goto err_exit;
6068 6069 6070
        }
    }

6071
    return 0;
6072

6073
 err_exit:
6074
    for (i = 0; last_good_net != -1 && i <= last_good_net; i++) {
6075
        net = def->nets[i];
6076
        if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
6077
            ignore_value(virNetDevVPortProfileDisassociate(net->ifname,
6078
                                                           virDomainNetGetActualVirtPortProfile(net),
6079
                                                           &net->mac,
6080
                                                           virDomainNetGetActualDirectDev(net),
6081
                                                           -1,
6082
                                                           VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_FINISH));
6083 6084
        }
    }
6085
    return -1;
6086 6087 6088
}


J
Jiri Denemark 已提交
6089 6090 6091
static int
qemuMigrationPersist(virQEMUDriverPtr driver,
                     virDomainObjPtr vm,
6092 6093
                     qemuMigrationCookiePtr mig,
                     bool ignoreSaveError)
J
Jiri Denemark 已提交
6094 6095 6096 6097
{
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    virCapsPtr caps = NULL;
    virDomainDefPtr vmdef;
6098 6099
    virDomainDefPtr oldDef = NULL;
    unsigned int oldPersist = vm->persistent;
J
Jiri Denemark 已提交
6100 6101 6102 6103 6104 6105 6106
    virObjectEventPtr event;
    int ret = -1;

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

    vm->persistent = 1;
6107 6108
    oldDef = vm->newDef;
    vm->newDef = qemuMigrationCookieGetPersistent(mig);
J
Jiri Denemark 已提交
6109

6110 6111
    if (!(vmdef = virDomainObjGetPersistentDef(caps, driver->xmlopt, vm)))
        goto error;
J
Jiri Denemark 已提交
6112

6113 6114
    if (virDomainSaveConfig(cfg->configDir, driver->caps, vmdef) < 0 &&
        !ignoreSaveError)
6115
        goto error;
J
Jiri Denemark 已提交
6116 6117 6118

    event = virDomainEventLifecycleNewFromObj(vm,
                                              VIR_DOMAIN_EVENT_DEFINED,
6119 6120 6121
                                              oldPersist ?
                                              VIR_DOMAIN_EVENT_DEFINED_UPDATED :
                                              VIR_DOMAIN_EVENT_DEFINED_ADDED);
6122
    qemuDomainEventQueue(driver, event);
J
Jiri Denemark 已提交
6123 6124 6125 6126

    ret = 0;

 cleanup:
6127
    virDomainDefFree(oldDef);
J
Jiri Denemark 已提交
6128 6129 6130
    virObjectUnref(caps);
    virObjectUnref(cfg);
    return ret;
6131 6132 6133 6134 6135 6136 6137

 error:
    virDomainDefFree(vm->newDef);
    vm->persistent = oldPersist;
    vm->newDef = oldDef;
    oldDef = NULL;
    goto cleanup;
J
Jiri Denemark 已提交
6138 6139 6140
}


6141
virDomainPtr
6142
qemuMigrationFinish(virQEMUDriverPtr driver,
6143 6144
                    virConnectPtr dconn,
                    virDomainObjPtr vm,
6145 6146 6147 6148
                    const char *cookiein,
                    int cookieinlen,
                    char **cookieout,
                    int *cookieoutlen,
6149
                    unsigned long flags,
6150 6151
                    int retcode,
                    bool v3proto)
6152 6153
{
    virDomainPtr dom = NULL;
6154
    qemuMigrationCookiePtr mig = NULL;
6155
    virErrorPtr orig_err = NULL;
6156
    int cookie_flags = 0;
J
Jiri Denemark 已提交
6157
    qemuDomainObjPrivatePtr priv = vm->privateData;
6158
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
6159
    unsigned short port;
6160 6161
    unsigned long long timeReceived = 0;
    virObjectEventPtr event;
6162
    int rc;
6163
    qemuDomainJobInfoPtr jobInfo = NULL;
6164
    bool inPostCopy = false;
6165
    bool doKill = true;
6166

6167
    VIR_DEBUG("driver=%p, dconn=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
6168
              "cookieout=%p, cookieoutlen=%p, flags=%lx, retcode=%d",
6169 6170
              driver, dconn, vm, NULLSTR(cookiein), cookieinlen,
              cookieout, cookieoutlen, flags, retcode);
6171

6172 6173 6174
    port = priv->migrationPort;
    priv->migrationPort = 0;

6175 6176
    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN)) {
        qemuMigrationErrorReport(driver, vm->def->name);
6177
        goto cleanup;
6178
    }
6179

6180 6181
    ignore_value(virTimeMillisNow(&timeReceived));

6182 6183 6184
    qemuMigrationJobStartPhase(driver, vm,
                               v3proto ? QEMU_MIGRATION_PHASE_FINISH3
                                       : QEMU_MIGRATION_PHASE_FINISH2);
6185

6186
    qemuDomainCleanupRemove(vm, qemuMigrationPrepareCleanup);
6187
    VIR_FREE(priv->job.completed);
6188

6189
    cookie_flags = QEMU_MIGRATION_COOKIE_NETWORK |
6190 6191
                   QEMU_MIGRATION_COOKIE_STATS |
                   QEMU_MIGRATION_COOKIE_NBD;
6192 6193 6194 6195 6196
    if (flags & VIR_MIGRATE_PERSIST_DEST)
        cookie_flags |= QEMU_MIGRATION_COOKIE_PERSISTENT;

    if (!(mig = qemuMigrationEatCookie(driver, vm, cookiein,
                                       cookieinlen, cookie_flags)))
6197
        goto endjob;
6198

6199
    if (flags & VIR_MIGRATE_OFFLINE) {
6200 6201 6202 6203 6204
        if (retcode == 0 &&
            qemuMigrationPersist(driver, vm, mig, false) == 0)
            dom = virGetDomain(dconn, vm->def->name, vm->def->uuid);
        goto endjob;
    }
6205

6206 6207
    if (retcode != 0) {
        qemuDomainJobInfo info;
6208

6209 6210 6211 6212 6213 6214 6215 6216
        /* Check for a possible error on the monitor in case Finish was called
         * earlier than monitor EOF handler got a chance to process the error
         */
        qemuMigrationFetchJobStatus(driver, vm,
                                    QEMU_ASYNC_JOB_MIGRATION_IN,
                                    &info);
        goto endjob;
    }
6217

6218 6219 6220 6221 6222 6223
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
        qemuMigrationErrorReport(driver, vm->def->name);
        goto endjob;
    }
6224

6225 6226
    if (qemuMigrationVPAssociatePortProfiles(vm->def) < 0)
        goto endjob;
6227

6228 6229
    if (mig->network && qemuDomainMigrateOPDRelocate(driver, vm, mig) < 0)
        VIR_WARN("unable to provide network data for relocation");
6230

6231 6232
    if (qemuMigrationStopNBDServer(driver, vm, mig) < 0)
        goto endjob;
6233

6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247
    if (qemuRefreshVirtioChannelState(driver, vm) < 0)
        goto endjob;

    if ((rc = qemuConnectAgent(driver, vm)) < 0) {
        if (rc == -2)
            goto endjob;

        VIR_WARN("Cannot connect to QEMU guest agent for %s",
                 vm->def->name);
        virResetLastError();
        priv->agentError = true;
    }


6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260
    if (flags & VIR_MIGRATE_PERSIST_DEST) {
        if (qemuMigrationPersist(driver, vm, mig, !v3proto) < 0) {
            /* 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.
             * Pretend success and hope that this is a rare situation and
             * management tools are smart.
             *
             * However, in v3 protocol, the source VM is still available
             * to restart during confirm() step, so we kill it off now.
6261 6262 6263
             */
            if (v3proto)
                goto endjob;
6264
        }
6265
    }
6266

6267 6268 6269 6270
    /* We need to wait for QEMU to process all data sent by the source
     * before starting guest CPUs.
     */
    if (qemuMigrationWaitForDestCompletion(driver, vm,
6271 6272
                                           QEMU_ASYNC_JOB_MIGRATION_IN,
                                           !!(flags & VIR_MIGRATE_POSTCOPY)) < 0) {
6273 6274 6275 6276 6277 6278
        /* There's not much we can do for v2 protocol since the
         * original domain on the source host is already gone.
         */
        if (v3proto)
            goto endjob;
    }
6279

6280 6281 6282
    if (priv->job.current->stats.status == QEMU_MONITOR_MIGRATION_STATUS_POSTCOPY)
        inPostCopy = true;

6283 6284 6285 6286 6287 6288
    if (!(flags & VIR_MIGRATE_PAUSED)) {
        /* 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
         */
        if (qemuProcessStartCPUs(driver, vm, dconn,
6289 6290
                                 inPostCopy ? VIR_DOMAIN_RUNNING_POSTCOPY
                                            : VIR_DOMAIN_RUNNING_MIGRATED,
6291 6292 6293 6294 6295 6296 6297 6298
                                 QEMU_ASYNC_JOB_MIGRATION_IN) < 0) {
            if (virGetLastError() == NULL)
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("resume operation failed"));
            /* Need to save the current error, in case shutting
             * down the process overwrites it
             */
            orig_err = virSaveLastError();
6299

6300 6301 6302 6303 6304 6305 6306 6307 6308 6309
            /*
             * 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)
                goto endjob;
6310
        }
6311 6312

        if (inPostCopy) {
6313
            doKill = false;
6314 6315 6316 6317 6318
            event = virDomainEventLifecycleNewFromObj(vm,
                                        VIR_DOMAIN_EVENT_RESUMED,
                                        VIR_DOMAIN_EVENT_RESUMED_POSTCOPY);
            qemuDomainEventQueue(driver, event);
        }
6319
    }
6320

6321
    if (mig->jobInfo) {
6322
        jobInfo = mig->jobInfo;
6323 6324 6325 6326 6327 6328
        mig->jobInfo = NULL;

        if (jobInfo->sent && timeReceived) {
            jobInfo->timeDelta = timeReceived - jobInfo->sent;
            jobInfo->received = timeReceived;
            jobInfo->timeDeltaSet = true;
6329
        }
6330 6331
        qemuDomainJobInfoUpdateTime(jobInfo);
        qemuDomainJobInfoUpdateDowntime(jobInfo);
6332
    }
L
liguang 已提交
6333

6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346
    if (inPostCopy) {
        if (qemuMigrationWaitForDestCompletion(driver, vm,
                                               QEMU_ASYNC_JOB_MIGRATION_IN,
                                               false) < 0) {
            goto endjob;
        }
        if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
            virDomainObjSetState(vm,
                                 VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_MIGRATED);
        }
    }

6347
    dom = virGetDomain(dconn, vm->def->name, vm->def->uuid);
6348

6349 6350 6351 6352
    event = virDomainEventLifecycleNewFromObj(vm,
                                              VIR_DOMAIN_EVENT_RESUMED,
                                              VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
    qemuDomainEventQueue(driver, event);
6353

6354 6355 6356 6357 6358 6359
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
        event = virDomainEventLifecycleNewFromObj(vm,
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
        qemuDomainEventQueue(driver, event);
6360
    }
6361

6362
    if (virDomainObjIsActive(vm) &&
6363
        virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
6364 6365 6366 6367 6368
        VIR_WARN("Failed to save status on vm %s", vm->def->name);

    /* Guest is successfully running, so cancel previous auto destroy */
    qemuProcessAutoDestroyRemove(driver, vm);

6369
 endjob:
6370
    if (!dom &&
6371 6372
        !(flags & VIR_MIGRATE_OFFLINE) &&
        virDomainObjIsActive(vm)) {
6373
        if (doKill) {
6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED,
                            QEMU_ASYNC_JOB_MIGRATION_IN,
                            VIR_QEMU_PROCESS_STOP_MIGRATED);
            virDomainAuditStop(vm, "failed");
            event = virDomainEventLifecycleNewFromObj(vm,
                                VIR_DOMAIN_EVENT_STOPPED,
                                VIR_DOMAIN_EVENT_STOPPED_FAILED);
            qemuDomainEventQueue(driver, event);
        } else {
            qemuMigrationPostcopyFailed(driver, vm);
        }
6385 6386
    }

6387 6388 6389 6390 6391 6392
    if (dom) {
        priv->job.completed = jobInfo;
        jobInfo = NULL;
        if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen,
                                    QEMU_MIGRATION_COOKIE_STATS) < 0)
            VIR_WARN("Unable to encode migration cookie");
6393 6394 6395 6396 6397 6398

        /* Remove completed stats for post-copy, everything but timing fields
         * is obsolete anyway.
         */
        if (inPostCopy)
            VIR_FREE(priv->job.completed);
6399
    }
6400

6401
    qemuMigrationJobFinish(driver, vm);
6402
    if (!virDomainObjIsActive(vm))
6403
        qemuDomainRemoveInactive(driver, vm);
6404

6405
 cleanup:
6406
    VIR_FREE(jobInfo);
6407
    virPortAllocatorRelease(driver->migrationPorts, port);
6408
    if (priv->mon)
6409
        qemuMonitorSetDomainLog(priv->mon, NULL, NULL, NULL);
6410
    VIR_FREE(priv->origname);
M
Michal Privoznik 已提交
6411
    virDomainObjEndAPI(&vm);
6412 6413 6414 6415
    if (mig) {
        virDomainDefFree(qemuMigrationCookieGetPersistent(mig));
        qemuMigrationCookieFree(mig);
    }
6416 6417 6418 6419
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
6420
    virObjectUnref(cfg);
6421 6422 6423 6424 6425 6426

    /* Set a special error if Finish is expected to return NULL as a result of
     * successful call with retcode != 0
     */
    if (retcode != 0 && !dom && !virGetLastError())
        virReportError(VIR_ERR_MIGRATE_FINISH_OK, NULL);
6427 6428
    return dom;
}
6429

6430

6431
/* Helper function called while vm is active.  */
6432
int
6433
qemuMigrationToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
6434
                    int fd,
6435
                    const char *compressor,
6436
                    qemuDomainAsyncJob asyncJob)
6437 6438 6439
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int rc;
6440
    int ret = -1;
6441 6442
    virCommandPtr cmd = NULL;
    int pipeFD[2] = { -1, -1 };
6443
    unsigned long saveMigBandwidth = priv->migMaxBandwidth;
6444
    char *errbuf = NULL;
6445
    virErrorPtr orig_err = NULL;
6446 6447 6448 6449 6450

    /* 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,
6451 6452
                                     QEMU_DOMAIN_MIG_BANDWIDTH_MAX);
        priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX;
6453 6454
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            return -1;
6455
    }
6456

6457 6458 6459 6460 6461 6462 6463
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
        /* nothing to tear down */
        return -1;
    }

6464 6465 6466 6467
    if (compressor && pipe(pipeFD) < 0) {
        virReportSystemError(errno, "%s",
                             _("Failed to create pipe for migration"));
        return -1;
6468 6469
    }

6470 6471 6472 6473 6474 6475 6476 6477
    /* All right! We can use fd migration, which means that qemu
     * 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.  */
    if (virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def,
                                          compressor ? pipeFD[1] : fd) < 0)
        goto cleanup;

6478
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
6479 6480
        goto cleanup;

6481
    if (!compressor) {
6482 6483 6484
        rc = qemuMonitorMigrateToFd(priv->mon,
                                    QEMU_MONITOR_MIGRATE_BACKGROUND,
                                    fd);
6485 6486 6487 6488 6489 6490 6491
    } else {
        const char *prog = compressor;
        const char *args[] = {
            prog,
            "-c",
            NULL
        };
6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502

        cmd = virCommandNewArgs(args);
        virCommandSetInputFD(cmd, pipeFD[0]);
        virCommandSetOutputFD(cmd, &fd);
        virCommandSetErrorBuffer(cmd, &errbuf);
        virCommandDoAsyncIO(cmd);
        if (virSetCloseExec(pipeFD[1]) < 0) {
            virReportSystemError(errno, "%s",
                                 _("Unable to set cloexec flag"));
            ignore_value(qemuDomainObjExitMonitor(driver, vm));
            goto cleanup;
6503
        }
6504 6505 6506 6507 6508 6509 6510 6511 6512 6513
        if (virCommandRunAsync(cmd, NULL) < 0) {
            ignore_value(qemuDomainObjExitMonitor(driver, vm));
            goto cleanup;
        }
        rc = qemuMonitorMigrateToFd(priv->mon,
                                    QEMU_MONITOR_MIGRATE_BACKGROUND,
                                    pipeFD[1]);
        if (VIR_CLOSE(pipeFD[0]) < 0 ||
            VIR_CLOSE(pipeFD[1]) < 0)
            VIR_WARN("failed to close intermediate pipe");
6514
    }
6515
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
6516
        goto cleanup;
6517 6518 6519
    if (rc < 0)
        goto cleanup;

6520
    rc = qemuMigrationWaitForCompletion(driver, vm, asyncJob, NULL, 0);
6521

6522 6523 6524 6525
    if (rc < 0) {
        if (rc == -2) {
            orig_err = virSaveLastError();
            virCommandAbort(cmd);
6526 6527
            if (virDomainObjIsActive(vm) &&
                qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
6528
                qemuMonitorMigrateCancel(priv->mon);
6529
                ignore_value(qemuDomainObjExitMonitor(driver, vm));
6530 6531
            }
        }
6532
        goto cleanup;
6533
    }
6534

6535 6536 6537
    if (cmd && virCommandWait(cmd, NULL) < 0)
        goto cleanup;

6538
    qemuDomainEventEmitJobCompleted(driver, vm);
6539 6540
    ret = 0;

6541
 cleanup:
6542 6543 6544
    if (ret < 0 && !orig_err)
        orig_err = virSaveLastError();

6545
    /* Restore max migration bandwidth */
6546 6547
    if (virDomainObjIsActive(vm) &&
        qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
6548 6549
        qemuMonitorSetMigrationSpeed(priv->mon, saveMigBandwidth);
        priv->migMaxBandwidth = saveMigBandwidth;
6550
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
6551 6552
    }

6553 6554
    VIR_FORCE_CLOSE(pipeFD[0]);
    VIR_FORCE_CLOSE(pipeFD[1]);
6555 6556 6557 6558 6559
    if (cmd) {
        VIR_DEBUG("Compression binary stderr: %s", NULLSTR(errbuf));
        VIR_FREE(errbuf);
        virCommandFree(cmd);
    }
6560 6561 6562 6563 6564 6565

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

6566 6567
    return ret;
}
6568

6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621

int
qemuMigrationCancel(virQEMUDriverPtr driver,
                    virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virHashTablePtr blockJobs = NULL;
    bool storage = false;
    size_t i;
    int ret = -1;

    VIR_DEBUG("Canceling unfinished outgoing migration of domain %s",
              vm->def->name);

    for (i = 0; i < vm->def->ndisks; i++) {
        virDomainDiskDefPtr disk = vm->def->disks[i];
        if (QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating) {
            qemuBlockJobSyncBegin(disk);
            storage = true;
        }
    }

    qemuDomainObjEnterMonitor(driver, vm);

    ignore_value(qemuMonitorMigrateCancel(priv->mon));
    if (storage)
        blockJobs = qemuMonitorGetAllBlockJobInfo(priv->mon);

    if (qemuDomainObjExitMonitor(driver, vm) < 0 || (storage && !blockJobs))
        goto endsyncjob;

    if (!storage) {
        ret = 0;
        goto cleanup;
    }

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

        if (!diskPriv->migrating)
            continue;

        if (virHashLookup(blockJobs, disk->info.alias)) {
            VIR_DEBUG("Drive mirror on disk %s is still running", disk->dst);
        } else {
            VIR_DEBUG("Drive mirror on disk %s is gone", disk->dst);
            qemuBlockJobSyncEnd(driver, vm, disk);
            diskPriv->migrating = false;
        }
    }

    if (qemuMigrationCancelDriveMirror(driver, vm, false,
6622
                                       QEMU_ASYNC_JOB_NONE, NULL) < 0)
6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646
        goto endsyncjob;

    ret = 0;

 cleanup:
    virHashFree(blockJobs);
    return ret;

 endsyncjob:
    if (storage) {
        for (i = 0; i < vm->def->ndisks; i++) {
            virDomainDiskDefPtr disk = vm->def->disks[i];
            qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);

            if (diskPriv->migrating) {
                qemuBlockJobSyncEnd(driver, vm, disk);
                diskPriv->migrating = false;
            }
        }
    }
    goto cleanup;
}


6647
int
6648
qemuMigrationJobStart(virQEMUDriverPtr driver,
6649
                      virDomainObjPtr vm,
6650
                      qemuDomainAsyncJob job)
6651 6652 6653
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

6654
    if (qemuDomainObjBeginAsyncJob(driver, vm, job) < 0)
6655 6656
        return -1;

6657
    if (job == QEMU_ASYNC_JOB_MIGRATION_IN) {
6658
        qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_NONE);
6659
    } else {
6660 6661 6662
        qemuDomainObjSetAsyncJobMask(vm, (QEMU_JOB_DEFAULT_MASK |
                                          JOB_MASK(QEMU_JOB_SUSPEND) |
                                          JOB_MASK(QEMU_JOB_MIGRATION_OP)));
6663
    }
6664

J
Jiri Denemark 已提交
6665
    priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED;
6666 6667 6668 6669 6670

    return 0;
}

void
6671
qemuMigrationJobSetPhase(virQEMUDriverPtr driver,
6672
                         virDomainObjPtr vm,
6673
                         qemuMigrationJobPhase phase)
6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687
{
    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
6688
qemuMigrationJobStartPhase(virQEMUDriverPtr driver,
6689
                           virDomainObjPtr vm,
6690
                           qemuMigrationJobPhase phase)
6691 6692 6693 6694
{
    qemuMigrationJobSetPhase(driver, vm, phase);
}

6695
void
6696 6697
qemuMigrationJobContinue(virDomainObjPtr vm)
{
6698
    qemuDomainObjReleaseAsyncJob(vm);
6699 6700 6701 6702
}

bool
qemuMigrationJobIsActive(virDomainObjPtr vm,
6703
                         qemuDomainAsyncJob job)
6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714
{
    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");

6715
        virReportError(VIR_ERR_OPERATION_INVALID, msg, vm->def->name);
6716 6717 6718 6719 6720
        return false;
    }
    return true;
}

6721
void
6722
qemuMigrationJobFinish(virQEMUDriverPtr driver, virDomainObjPtr vm)
6723
{
6724
    qemuDomainObjEndAsyncJob(driver, vm);
6725
}
6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779


static void
qemuMigrationErrorFree(void *data,
                       const void *name ATTRIBUTE_UNUSED)
{
    virErrorPtr err = data;
    virFreeError(err);
}

int
qemuMigrationErrorInit(virQEMUDriverPtr driver)
{
    driver->migrationErrors = virHashAtomicNew(64, qemuMigrationErrorFree);
    if (driver->migrationErrors)
        return 0;
    else
        return -1;
}

/**
 * This function consumes @err; the caller should consider the @err pointer
 * invalid after calling this function.
 */
void
qemuMigrationErrorSave(virQEMUDriverPtr driver,
                       const char *name,
                       virErrorPtr err)
{
    if (!err)
        return;

    VIR_DEBUG("Saving incoming migration error for domain %s: %s",
              name, err->message);
    if (virHashAtomicUpdate(driver->migrationErrors, name, err) < 0) {
        VIR_WARN("Failed to save migration error for domain '%s'", name);
        virFreeError(err);
    }
}

void
qemuMigrationErrorReport(virQEMUDriverPtr driver,
                         const char *name)
{
    virErrorPtr err;

    if (!(err = virHashAtomicSteal(driver->migrationErrors, name)))
        return;

    VIR_DEBUG("Restoring saved incoming migration error for domain %s: %s",
              name, err->message);
    virSetError(err);
    virFreeError(err);
}
6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817


/* don't ever pass NULL params with non zero nparams */
qemuMigrationCompressionPtr
qemuMigrationCompressionParse(virTypedParameterPtr params,
                              int nparams,
                              unsigned long flags)
{
    size_t i;
    qemuMigrationCompressionPtr compression = NULL;

    if (VIR_ALLOC(compression) < 0)
        return NULL;

    for (i = 0; i < nparams; i++) {
        int method;

        if (STRNEQ(params[i].field, VIR_MIGRATE_PARAM_COMPRESSION))
            continue;

        method = qemuMigrationCompressMethodTypeFromString(params[i].value.s);
        if (method < 0) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Unsupported compression method '%s'"),
                           params[i].value.s);
            goto error;
        }

        if (compression->methods & (1ULL << method)) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Compression method '%s' is specified twice"),
                           params[i].value.s);
            goto error;
        }

        compression->methods |= 1ULL << method;
    }

6818
#define GET_PARAM(PARAM, TYPE, VALUE)                                       \
6819 6820
    do {                                                                    \
        int rc;                                                             \
6821
        const char *par = VIR_MIGRATE_PARAM_COMPRESSION_ ## PARAM;          \
6822 6823
                                                                            \
        if ((rc = virTypedParamsGet ## TYPE(params, nparams,                \
6824
                                            par, &compression->VALUE)) < 0) \
6825 6826 6827
            goto error;                                                     \
                                                                            \
        if (rc == 1)                                                        \
6828
            compression->VALUE ## _set = true;                              \
6829 6830 6831
    } while (0)

    if (params) {
6832 6833 6834 6835
        GET_PARAM(MT_LEVEL, Int, level);
        GET_PARAM(MT_THREADS, Int, threads);
        GET_PARAM(MT_DTHREADS, Int, dthreads);
        GET_PARAM(XBZRLE_CACHE, ULLong, xbzrle_cache);
6836 6837 6838 6839
    }

#undef GET_PARAM

6840 6841 6842
    if ((compression->level_set ||
         compression->threads_set ||
         compression->dthreads_set) &&
6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855
        !(compression->methods & (1ULL << QEMU_MIGRATION_COMPRESS_MT))) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Turn multithread compression on to tune it"));
        goto error;
    }

    if (compression->xbzrle_cache_set &&
        !(compression->methods & (1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE))) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Turn xbzrle compression on to tune it"));
        goto error;
    }

6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874
    if (!compression->methods && (flags & VIR_MIGRATE_COMPRESSED))
        compression->methods = 1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE;

    return compression;

 error:
    VIR_FREE(compression);
    return NULL;
}

int
qemuMigrationCompressionDump(qemuMigrationCompressionPtr compression,
                             virTypedParameterPtr *params,
                             int *nparams,
                             int *maxparams,
                             unsigned long *flags)
{
    size_t i;

6875 6876
    if (compression->methods == 1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE &&
        !compression->xbzrle_cache_set) {
6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888
        *flags |= VIR_MIGRATE_COMPRESSED;
        return 0;
    }

    for (i = 0; i < QEMU_MIGRATION_COMPRESS_LAST; ++i) {
        if ((compression->methods & (1ULL << i)) &&
            virTypedParamsAddString(params, nparams, maxparams,
                                    VIR_MIGRATE_PARAM_COMPRESSION,
                                    qemuMigrationCompressMethodTypeToString(i)) < 0)
            return -1;
    }

6889
    if (compression->level_set &&
6890 6891
        virTypedParamsAddInt(params, nparams, maxparams,
                             VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL,
6892
                             compression->level) < 0)
6893 6894
        return -1;

6895
    if (compression->threads_set &&
6896 6897
        virTypedParamsAddInt(params, nparams, maxparams,
                             VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS,
6898
                             compression->threads) < 0)
6899 6900
        return -1;

6901
    if (compression->dthreads_set &&
6902 6903
        virTypedParamsAddInt(params, nparams, maxparams,
                             VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS,
6904
                             compression->dthreads) < 0)
6905 6906 6907 6908 6909 6910 6911 6912
        return -1;

    if (compression->xbzrle_cache_set &&
        virTypedParamsAddULLong(params, nparams, maxparams,
                                VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE,
                                compression->xbzrle_cache) < 0)
        return -1;

6913 6914
    return 0;
}