--- src/qemu/qemu_driver.c | 302 ++++++++++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_migration.c | 162 ++++++++++++++++++------- src/qemu/qemu_migration.h | 9 ++ 3 files changed, 417 insertions(+), 56 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e2b85c0..cedec91 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1095,6 +1095,7 @@ qemuConnectSupportsFeature(virConnectPtr conn, int feature) case VIR_DRV_FEATURE_TYPED_PARAM_STRING: case VIR_DRV_FEATURE_XML_MIGRATABLE: case VIR_DRV_FEATURE_MIGRATION_OFFLINE: + case VIR_DRV_FEATURE_MIGRATION_PARAMS: return 1; default: return 0; @@ -10173,6 +10174,43 @@ qemuDomainMigrateBegin3(virDomainPtr domain, cookieout, cookieoutlen, flags); } +static char * +qemuDomainMigrateBegin3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + char **cookieout, + int *cookieoutlen, + unsigned int flags) +{ + const char *xmlin = NULL; + const char *dname = NULL; + virDomainObjPtr vm; + + virCheckFlags(QEMU_MIGRATION_FLAGS, NULL); + if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + return NULL; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &xmlin) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0) + return NULL; + + if (!(vm = qemuDomObjFromDomain(domain))) + return NULL; + + if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0) { + virObjectUnlock(vm); + return NULL; + } + + return qemuMigrationBegin(domain->conn, vm, xmlin, dname, + cookieout, cookieoutlen, flags); +} + + static int qemuDomainMigratePrepare3(virConnectPtr dconn, const char *cookiein, @@ -10219,6 +10257,66 @@ cleanup: return ret; } +static int +qemuDomainMigratePrepare3Params(virConnectPtr dconn, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout, + int *cookieoutlen, + char **uri_out, + unsigned int flags) +{ + virQEMUDriverPtr driver = dconn->privateData; + virDomainDefPtr def = NULL; + const char *dom_xml = NULL; + const char *dname = NULL; + const char *uri_in = NULL; + int ret = -1; + + virCheckFlags(QEMU_MIGRATION_FLAGS, -1); + if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + return -1; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &dom_xml) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, + &uri_in) < 0) + return -1; + + if (flags & VIR_MIGRATE_TUNNELLED) { + /* this is a logical error; we never should have gotten here with + * VIR_MIGRATE_TUNNELLED set + */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Tunnelled migration requested but invalid " + "RPC method called")); + goto cleanup; + } + + if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname))) + goto cleanup; + + if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0) + goto cleanup; + + ret = qemuMigrationPrepareDirect(driver, dconn, + cookiein, cookieinlen, + cookieout, cookieoutlen, + uri_in, uri_out, + &def, flags); + +cleanup: + virDomainDefFree(def); + return ret; +} + static int qemuDomainMigratePrepareTunnel3(virConnectPtr dconn, @@ -10260,6 +10358,57 @@ cleanup: return ret; } +static int +qemuDomainMigratePrepareTunnel3Params(virConnectPtr dconn, + virStreamPtr st, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout, + int *cookieoutlen, + unsigned int flags) +{ + virQEMUDriverPtr driver = dconn->privateData; + virDomainDefPtr def = NULL; + const char *dom_xml = NULL; + const char *dname = NULL; + int ret = -1; + + virCheckFlags(QEMU_MIGRATION_FLAGS, -1); + if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + return -1; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &dom_xml) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0) + return -1; + + if (!(flags & VIR_MIGRATE_TUNNELLED)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("PrepareTunnel called but no TUNNELLED flag set")); + goto cleanup; + } + + if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname))) + goto cleanup; + + if (virDomainMigratePrepareTunnel3ParamsEnsureACL(dconn, def) < 0) + goto cleanup; + + ret = qemuMigrationPrepareTunnel(driver, dconn, + cookiein, cookieinlen, + cookieout, cookieoutlen, + st, &def, flags); + +cleanup: + virDomainDefFree(def); + return ret; +} + static int qemuDomainMigratePerform3(virDomainPtr dom, @@ -10293,6 +10442,56 @@ qemuDomainMigratePerform3(virDomainPtr dom, flags, dname, resource, true); } +static int +qemuDomainMigratePerform3Params(virDomainPtr dom, + const char *dconnuri, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout, + int *cookieoutlen, + unsigned int flags) +{ + virQEMUDriverPtr driver = dom->conn->privateData; + virDomainObjPtr vm; + const char *dom_xml = NULL; + const char *dname = NULL; + const char *uri = NULL; + unsigned long long bandwidth = 0; + + virCheckFlags(QEMU_MIGRATION_FLAGS, -1); + if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + return -1; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &dom_xml) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, + &uri) < 0 || + virTypedParamsGetULLong(params, nparams, + VIR_MIGRATE_PARAM_BANDWIDTH, + &bandwidth) < 0) + return -1; + + if (!(vm = qemuDomObjFromDomain(dom))) + return -1; + + if (virDomainMigratePerform3ParamsEnsureACL(dom->conn, vm->def) < 0) { + virObjectUnlock(vm); + return -1; + } + + return qemuMigrationPerform(driver, dom->conn, vm, dom_xml, + dconnuri, uri, cookiein, cookieinlen, + cookieout, cookieoutlen, + flags, dname, bandwidth, true); +} + static virDomainPtr qemuDomainMigrateFinish3(virConnectPtr dconn, @@ -10308,29 +10507,72 @@ qemuDomainMigrateFinish3(virConnectPtr dconn, { virQEMUDriverPtr driver = dconn->privateData; virDomainObjPtr vm; - virDomainPtr dom = NULL; virCheckFlags(QEMU_MIGRATION_FLAGS, NULL); - vm = virDomainObjListFindByName(driver->domains, dname); - if (!vm) { + if (!dname || + !(vm = virDomainObjListFindByName(driver->domains, dname))) { virReportError(VIR_ERR_NO_DOMAIN, - _("no domain with matching name '%s'"), dname); - goto cleanup; + _("no domain with matching name '%s'"), + NULLSTR(dname)); + return NULL; } - if (virDomainMigrateFinish3EnsureACL(dconn, vm->def) < 0) - goto cleanup; + if (virDomainMigrateFinish3EnsureACL(dconn, vm->def) < 0) { + virObjectUnlock(vm); + return NULL; + } - dom = qemuMigrationFinish(driver, dconn, vm, - cookiein, cookieinlen, - cookieout, cookieoutlen, - flags, cancelled, true); + return qemuMigrationFinish(driver, dconn, vm, + cookiein, cookieinlen, + cookieout, cookieoutlen, + flags, cancelled, true); +} -cleanup: - return dom; +static virDomainPtr +qemuDomainMigrateFinish3Params(virConnectPtr dconn, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout, + int *cookieoutlen, + unsigned int flags, + int cancelled) +{ + virQEMUDriverPtr driver = dconn->privateData; + virDomainObjPtr vm; + const char *dname = NULL; + + virCheckFlags(QEMU_MIGRATION_FLAGS, NULL); + if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + return NULL; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0) + return NULL; + + if (!dname || + !(vm = virDomainObjListFindByName(driver->domains, dname))) { + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching name '%s'"), + NULLSTR(dname)); + return NULL; + } + + if (virDomainMigrateFinish3ParamsEnsureACL(dconn, vm->def) < 0) { + virObjectUnlock(vm); + return NULL; + } + + return qemuMigrationFinish(driver, dconn, vm, + cookiein, cookieinlen, + cookieout, cookieoutlen, + flags, cancelled, true); } + static int qemuDomainMigrateConfirm3(virDomainPtr domain, const char *cookiein, @@ -10354,6 +10596,34 @@ qemuDomainMigrateConfirm3(virDomainPtr domain, flags, cancelled); } +static int +qemuDomainMigrateConfirm3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + unsigned int flags, + int cancelled) +{ + virDomainObjPtr vm; + + virCheckFlags(QEMU_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0) + return -1; + + if (!(vm = qemuDomObjFromDomain(domain))) + return -1; + + if (virDomainMigrateConfirm3ParamsEnsureACL(domain->conn, vm->def) < 0) { + virObjectUnlock(vm); + return -1; + } + + return qemuMigrationConfirm(domain->conn, vm, cookiein, cookieinlen, + flags, cancelled); +} + static int qemuNodeDeviceGetPciInfo(virNodeDeviceDefPtr def, @@ -15776,6 +16046,12 @@ static virDriver qemuDriver = { .nodeGetCPUMap = qemuNodeGetCPUMap, /* 1.0.0 */ .domainFSTrim = qemuDomainFSTrim, /* 1.0.1 */ .domainOpenChannel = qemuDomainOpenChannel, /* 1.0.2 */ + .domainMigrateBegin3Params = qemuDomainMigrateBegin3Params, /* 1.1.0 */ + .domainMigratePrepare3Params = qemuDomainMigratePrepare3Params, /* 1.1.0 */ + .domainMigratePrepareTunnel3Params = qemuDomainMigratePrepareTunnel3Params, /* 1.1.0 */ + .domainMigratePerform3Params = qemuDomainMigratePerform3Params, /* 1.1.0 */ + .domainMigrateFinish3Params = qemuDomainMigrateFinish3Params, /* 1.1.0 */ + .domainMigrateConfirm3Params = qemuDomainMigrateConfirm3Params, /* 1.1.0 */ }; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 66d62fe..d4a169e 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -56,6 +56,7 @@ #include "viruri.h" #include "virhook.h" #include "virstring.h" +#include "virtypedparam.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -3564,16 +3565,18 @@ cleanup: * from libvirt.c, but running in source libvirtd context, * instead of client app context & also adding in tunnel * handling */ -static int doPeer2PeerMigrate3(virQEMUDriverPtr driver, - virConnectPtr sconn, - virConnectPtr dconn, - virDomainObjPtr vm, - const char *xmlin, - const char *dconnuri, - const char *uri, - unsigned long flags, - const char *dname, - unsigned long resource) +static int +doPeer2PeerMigrate3(virQEMUDriverPtr driver, + virConnectPtr sconn, + virConnectPtr dconn, + const char *dconnuri, + virDomainObjPtr vm, + const char *xmlin, + const char *dname, + const char *uri, + unsigned long long bandwidth, + bool useParams, + unsigned long flags) { virDomainPtr ddomain = NULL; char *uri_out = NULL; @@ -3584,15 +3587,18 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver, int cookieoutlen = 0; int ret = -1; virErrorPtr orig_err = NULL; - bool cancelled; + bool cancelled = true; virStreamPtr st = NULL; unsigned int destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; - VIR_DEBUG("driver=%p, sconn=%p, dconn=%p, vm=%p, xmlin=%s, " - "dconnuri=%s, uri=%s, flags=%lx, dname=%s, resource=%lu", - driver, sconn, dconn, vm, NULLSTR(xmlin), - NULLSTR(dconnuri), NULLSTR(uri), flags, - NULLSTR(dname), resource); + virTypedParameterPtr params = NULL; + int nparams = 0; + int maxparams = 0; + + VIR_DEBUG("driver=%p, sconn=%p, dconn=%p, dconnuri=%s, vm=%p, xmlin=%s, " + "dname=%s, uri=%s, bandwidth=%llu, useParams=%d, flags=%lx", + driver, sconn, dconn, NULLSTR(dconnuri), vm, NULLSTR(xmlin), + NULLSTR(dname), NULLSTR(uri), bandwidth, useParams, flags); /* Unlike the virDomainMigrateVersion3 counterpart, we don't need * to worry about auto-setting the VIR_MIGRATE_CHANGE_PROTECTION @@ -3604,6 +3610,28 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver, if (!dom_xml) goto cleanup; + if (useParams) { + if (virTypedParamsAddString(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_DEST_XML, dom_xml) < 0) + goto cleanup; + + if (dname && + virTypedParamsAddString(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_DEST_NAME, dname) < 0) + goto cleanup; + + if (uri && + virTypedParamsAddString(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_URI, uri) < 0) + goto cleanup; + + if (bandwidth && + virTypedParamsAddULLong(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_BANDWIDTH, + bandwidth) < 0) + goto cleanup; + } + if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; @@ -3617,16 +3645,27 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver, goto cleanup; qemuDomainObjEnterRemote(vm); - ret = dconn->driver->domainMigratePrepareTunnel3 - (dconn, st, cookiein, cookieinlen, - &cookieout, &cookieoutlen, - destflags, dname, resource, dom_xml); + 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); + } qemuDomainObjExitRemote(vm); } else { qemuDomainObjEnterRemote(vm); - ret = dconn->driver->domainMigratePrepare3 - (dconn, cookiein, cookieinlen, &cookieout, &cookieoutlen, - uri, &uri_out, destflags, dname, resource, dom_xml); + 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); + } qemuDomainObjExitRemote(vm); } VIR_FREE(dom_xml); @@ -3641,11 +3680,15 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver, goto finish; } - if (!(flags & VIR_MIGRATE_TUNNELLED) && - (uri_out == NULL)) { + if (uri_out) { + uri = uri_out; + if (useParams && + virTypedParamsReplaceString(¶ms, &nparams, + VIR_MIGRATE_PARAM_URI, uri_out) < 0) + goto finish; + } else if (!uri && !(flags & VIR_MIGRATE_TUNNELLED)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("domainMigratePrepare3 did not set uri")); - cancelled = true; goto finish; } @@ -3654,23 +3697,24 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver, * running, but in paused state until the destination can * confirm migration completion. */ - VIR_DEBUG("Perform3 %p uri=%s uri_out=%s", sconn, uri, uri_out); + VIR_DEBUG("Perform3 %p uri=%s", sconn, NULLSTR(uri)); qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3); VIR_FREE(cookiein); cookiein = cookieout; cookieinlen = cookieoutlen; cookieout = NULL; cookieoutlen = 0; - if (flags & VIR_MIGRATE_TUNNELLED) + if (flags & VIR_MIGRATE_TUNNELLED) { ret = doTunnelMigrate(driver, vm, st, cookiein, cookieinlen, &cookieout, &cookieoutlen, - flags, resource, dconn); - else - ret = doNativeMigrate(driver, vm, uri_out, + flags, bandwidth, dconn); + } else { + ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen, &cookieout, &cookieoutlen, - flags, resource, dconn); + flags, bandwidth, dconn); + } /* Perform failed. Make sure Finish doesn't overwrite the error */ if (ret < 0) { @@ -3698,12 +3742,29 @@ finish: cookieinlen = cookieoutlen; cookieout = NULL; cookieoutlen = 0; - dname = dname ? dname : vm->def->name; - qemuDomainObjEnterRemote(vm); - ddomain = dconn->driver->domainMigrateFinish3 - (dconn, dname, cookiein, cookieinlen, &cookieout, &cookieoutlen, - dconnuri, uri_out ? uri_out : uri, destflags, cancelled); - qemuDomainObjExitRemote(vm); + + if (useParams) { + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, NULL) <= 0 && + virTypedParamsReplaceString(¶ms, &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); + } /* If ddomain is NULL, then we were unable to start * the guest on the target, and must restart on the @@ -3759,7 +3820,7 @@ finish: VIR_FREE(uri_out); VIR_FREE(cookiein); VIR_FREE(cookieout); - + virTypedParamsFree(params, nparams); return ret; } @@ -3781,6 +3842,7 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, virErrorPtr orig_err = NULL; bool offline = false; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + bool useParams; VIR_DEBUG("driver=%p, sconn=%p, vm=%p, xmlin=%s, dconnuri=%s, " "uri=%s, flags=%lx, dname=%s, resource=%lu", @@ -3815,6 +3877,8 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, */ *v3proto = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, VIR_DRV_FEATURE_MIGRATION_V3); + useParams = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, + VIR_DRV_FEATURE_MIGRATION_PARAMS); if (flags & VIR_MIGRATE_OFFLINE) offline = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, VIR_DRV_FEATURE_MIGRATION_OFFLINE); @@ -3826,6 +3890,17 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, goto cleanup; } + /* Only xmlin, dname, uri, and bandwidth parameters can be used with + * old-style APIs. */ +#if 0 + if (!useParams && /* any new parameter */) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Migration APIs with extensible parameters are not " + "supported but extended parameters were passed")); + goto cleanup; + } +#endif + if (flags & VIR_MIGRATE_OFFLINE && !offline) { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", _("offline migration is not supported by " @@ -3847,12 +3922,13 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, * Therefore it is safe to clear the bit here. */ flags &= ~VIR_MIGRATE_CHANGE_PROTECTION; - if (*v3proto) - ret = doPeer2PeerMigrate3(driver, sconn, dconn, vm, xmlin, - dconnuri, uri, flags, dname, resource); - else + if (*v3proto) { + ret = doPeer2PeerMigrate3(driver, sconn, dconn, dconnuri, vm, xmlin, + dname, uri, resource, useParams, flags); + } else { ret = doPeer2PeerMigrate2(driver, sconn, dconn, vm, dconnuri, flags, dname, resource); + } cleanup: orig_err = virSaveLastError(); diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index dd1d0a1..469c948 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -41,6 +41,15 @@ VIR_MIGRATE_COMPRESSED | \ VIR_MIGRATE_ABORT_ON_ERROR) +/* All supported migration parameters and their types. */ +# define QEMU_MIGRATION_PARAMETERS \ + VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_BANDWIDTH, VIR_TYPED_PARAM_ULLONG, \ + NULL + + enum qemuMigrationJobPhase { QEMU_MIGRATION_PHASE_NONE = 0, QEMU_MIGRATION_PHASE_PERFORM2, -- 1.8.2.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list