diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 319b4d000a..f573bd3eba 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1917,6 +1917,7 @@ qemuMigrationSrcBeginPhase(virQEMUDriverPtr driver, goto cleanup; if (qemuMigrationBakeCookie(mig, driver, vm, + QEMU_MIGRATION_SOURCE, cookieout, cookieoutlen, cookieFlags) < 0) goto cleanup; @@ -2429,8 +2430,9 @@ qemuMigrationDstPrepareAny(virQEMUDriverPtr driver, goto stopjob; done: - if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, - cookieoutlen, cookieFlags) < 0) { + if (qemuMigrationBakeCookie(mig, driver, vm, + QEMU_MIGRATION_DESTINATION, + cookieout, cookieoutlen, cookieFlags) < 0) { /* 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. @@ -3523,8 +3525,9 @@ qemuMigrationSrcRun(virQEMUDriverPtr driver, QEMU_MIGRATION_COOKIE_STATS; if (qemuMigrationCookieAddPersistent(mig, &persistDef) < 0 || - qemuMigrationBakeCookie(mig, driver, vm, cookieout, - cookieoutlen, cookieFlags) < 0) { + qemuMigrationBakeCookie(mig, driver, vm, + QEMU_MIGRATION_SOURCE, + cookieout, cookieoutlen, cookieFlags) < 0) { VIR_WARN("Unable to encode migration cookie"); } @@ -5019,7 +5022,9 @@ qemuMigrationDstFinish(virQEMUDriverPtr driver, priv->job.completed->status = QEMU_DOMAIN_JOB_STATUS_COMPLETED; } - if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen, + if (qemuMigrationBakeCookie(mig, driver, vm, + QEMU_MIGRATION_DESTINATION, + cookieout, cookieoutlen, QEMU_MIGRATION_COOKIE_STATS) < 0) VIR_WARN("Unable to encode migration cookie"); diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_cookie.c index 5a1e299ca2..eca1b74d63 100644 --- a/src/qemu/qemu_migration_cookie.c +++ b/src/qemu/qemu_migration_cookie.c @@ -33,6 +33,7 @@ #include "qemu_domain.h" #include "qemu_migration_cookie.h" +#include "qemu_migration_params.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -50,7 +51,8 @@ VIR_ENUM_IMPL(qemuMigrationCookieFlag, "memory-hotplug", "cpu-hotplug", "cpu", - "allowReboot"); + "allowReboot", + "capabilities"); static void @@ -94,6 +96,18 @@ qemuMigrationCookieNBDFree(qemuMigrationCookieNBDPtr nbd) } +static void +qemuMigrationCookieCapsFree(qemuMigrationCookieCapsPtr caps) +{ + if (!caps) + return; + + virBitmapFree(caps->supported); + virBitmapFree(caps->automatic); + VIR_FREE(caps); +} + + void qemuMigrationCookieFree(qemuMigrationCookiePtr mig) { @@ -112,6 +126,7 @@ qemuMigrationCookieFree(qemuMigrationCookiePtr mig) VIR_FREE(mig->lockDriver); VIR_FREE(mig->jobInfo); virCPUDefFree(mig->cpu); + qemuMigrationCookieCapsFree(mig->caps); VIR_FREE(mig); } @@ -550,6 +565,33 @@ qemuMigrationCookieAddAllowReboot(qemuMigrationCookiePtr mig, } +static int +qemuMigrationCookieAddCaps(qemuMigrationCookiePtr mig, + virDomainObjPtr vm, + qemuMigrationParty party) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + + qemuMigrationCookieCapsFree(mig->caps); + if (VIR_ALLOC(mig->caps) < 0) + return -1; + + if (priv->migrationCaps) + mig->caps->supported = virBitmapNewCopy(priv->migrationCaps); + else + mig->caps->supported = virBitmapNew(0); + + mig->caps->automatic = qemuMigrationParamsGetAlwaysOnCaps(party); + + if (!mig->caps->supported || !mig->caps->automatic) + return -1; + + mig->flags |= QEMU_MIGRATION_COOKIE_CAPS; + + return 0; +} + + static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf, qemuMigrationCookieGraphicsPtr grap) @@ -710,6 +752,33 @@ qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf, } +static void +qemuMigrationCookieCapsXMLFormat(virBufferPtr buf, + qemuMigrationCookieCapsPtr caps) +{ + qemuMigrationCapability cap; + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + + for (cap = 0; cap < QEMU_MIGRATION_CAP_LAST; cap++) { + bool supported = false; + bool automatic = false; + + ignore_value(virBitmapGetBit(caps->supported, cap, &supported)); + ignore_value(virBitmapGetBit(caps->automatic, cap, &automatic)); + if (supported) { + virBufferAsprintf(buf, "\n", + qemuMigrationCapabilityTypeToString(cap), + automatic ? "yes" : "no"); + } + } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); +} + + static int qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, virBufferPtr buf, @@ -793,6 +862,9 @@ qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, if (mig->flags & QEMU_MIGRATION_COOKIE_ALLOW_REBOOT) qemuDomainObjPrivateXMLFormatAllowReboot(buf, mig->allowReboot); + if (mig->flags & QEMU_MIGRATION_COOKIE_CAPS) + qemuMigrationCookieCapsXMLFormat(buf, mig->caps); + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "\n"); return 0; @@ -1067,6 +1139,59 @@ qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt) } +static qemuMigrationCookieCapsPtr +qemuMigrationCookieCapsXMLParse(xmlXPathContextPtr ctxt) +{ + qemuMigrationCookieCapsPtr caps = NULL; + xmlNodePtr *nodes = NULL; + qemuMigrationCookieCapsPtr ret = NULL; + char *name = NULL; + char *automatic = NULL; + int cap; + size_t i; + int n; + + if (VIR_ALLOC(caps) < 0) + return NULL; + + if (!(caps->supported = virBitmapNew(QEMU_MIGRATION_CAP_LAST)) || + !(caps->automatic = virBitmapNew(QEMU_MIGRATION_CAP_LAST))) + goto cleanup; + + if ((n = virXPathNodeSet("./capabilities[1]/cap", ctxt, &nodes)) < 0) + goto cleanup; + + for (i = 0; i < n; i++) { + if (!(name = virXMLPropString(nodes[i], "name"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing migration capability name")); + goto cleanup; + } + + if ((cap = qemuMigrationCapabilityTypeFromString(name)) < 0) + VIR_DEBUG("unknown migration capability '%s'", name); + else + ignore_value(virBitmapSetBit(caps->supported, cap)); + + if ((automatic = virXMLPropString(nodes[i], "auto")) && + STREQ(automatic, "yes")) + ignore_value(virBitmapSetBit(caps->automatic, cap)); + + VIR_FREE(name); + VIR_FREE(automatic); + } + + VIR_STEAL_PTR(ret, caps); + + cleanup: + qemuMigrationCookieCapsFree(caps); + VIR_FREE(nodes); + VIR_FREE(name); + VIR_FREE(automatic); + return ret; +} + + static int qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, virQEMUDriverPtr driver, @@ -1246,6 +1371,10 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, qemuDomainObjPrivateXMLParseAllowReboot(ctxt, &mig->allowReboot) < 0) goto error; + if (flags & QEMU_MIGRATION_COOKIE_CAPS && + !(mig->caps = qemuMigrationCookieCapsXMLParse(ctxt))) + goto error; + virObjectUnref(caps); return 0; @@ -1286,6 +1415,7 @@ int qemuMigrationBakeCookie(qemuMigrationCookiePtr mig, virQEMUDriverPtr driver, virDomainObjPtr dom, + qemuMigrationParty party, char **cookieout, int *cookieoutlen, unsigned int flags) @@ -1329,6 +1459,10 @@ qemuMigrationBakeCookie(qemuMigrationCookiePtr mig, if (flags & QEMU_MIGRATION_COOKIE_ALLOW_REBOOT) qemuMigrationCookieAddAllowReboot(mig, dom); + if (flags & QEMU_MIGRATION_COOKIE_CAPS && + qemuMigrationCookieAddCaps(mig, dom, party) < 0) + return -1; + if (!(*cookieout = qemuMigrationCookieXMLFormatStr(driver, mig))) return -1; diff --git a/src/qemu/qemu_migration_cookie.h b/src/qemu/qemu_migration_cookie.h index 4a25511a9a..08c5de8f06 100644 --- a/src/qemu/qemu_migration_cookie.h +++ b/src/qemu/qemu_migration_cookie.h @@ -19,6 +19,8 @@ #ifndef __QEMU_MIGRATION_COOKIE_H__ # define __QEMU_MIGRATION_COOKIE_H__ +# include "qemu_migration_params.h" + typedef enum { QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS, QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE, @@ -30,6 +32,7 @@ typedef enum { QEMU_MIGRATION_COOKIE_FLAG_CPU_HOTPLUG, QEMU_MIGRATION_COOKIE_FLAG_CPU, QEMU_MIGRATION_COOKIE_FLAG_ALLOW_REBOOT, + QEMU_MIGRATION_COOKIE_FLAG_CAPS, QEMU_MIGRATION_COOKIE_FLAG_LAST } qemuMigrationCookieFlags; @@ -47,6 +50,7 @@ typedef enum { QEMU_MIGRATION_COOKIE_CPU_HOTPLUG = (1 << QEMU_MIGRATION_COOKIE_FLAG_CPU_HOTPLUG), QEMU_MIGRATION_COOKIE_CPU = (1 << QEMU_MIGRATION_COOKIE_FLAG_CPU), QEMU_MIGRATION_COOKIE_ALLOW_REBOOT = (1 << QEMU_MIGRATION_COOKIE_FLAG_ALLOW_REBOOT), + QEMU_MIGRATION_COOKIE_CAPS = (1 << QEMU_MIGRATION_COOKIE_FLAG_CAPS), } qemuMigrationCookieFeatures; typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics; @@ -92,6 +96,13 @@ struct _qemuMigrationCookieNBD { } *disks; }; +typedef struct _qemuMigrationCookieCaps qemuMigrationCookieCaps; +typedef qemuMigrationCookieCaps *qemuMigrationCookieCapsPtr; +struct _qemuMigrationCookieCaps { + virBitmapPtr supported; + virBitmapPtr automatic; +}; + typedef struct _qemuMigrationCookie qemuMigrationCookie; typedef qemuMigrationCookie *qemuMigrationCookiePtr; struct _qemuMigrationCookie { @@ -132,6 +143,9 @@ struct _qemuMigrationCookie { /* If flags & QEMU_MIGRATION_COOKIE_ALLOW_REBOOT */ virTristateBool allowReboot; + + /* If flags & QEMU_MIGRATION_COOKIE_CAPS */ + qemuMigrationCookieCapsPtr caps; }; @@ -139,6 +153,7 @@ int qemuMigrationBakeCookie(qemuMigrationCookiePtr mig, virQEMUDriverPtr driver, virDomainObjPtr dom, + qemuMigrationParty party, char **cookieout, int *cookieoutlen, unsigned int flags); diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c index 2723288dfc..1b1e5829e8 100644 --- a/src/qemu/qemu_migration_params.c +++ b/src/qemu/qemu_migration_params.c @@ -153,6 +153,26 @@ static const qemuMigrationParamType qemuMigrationParamTypes[] = { verify(ARRAY_CARDINALITY(qemuMigrationParamTypes) == QEMU_MIGRATION_PARAM_LAST); +virBitmapPtr +qemuMigrationParamsGetAlwaysOnCaps(qemuMigrationParty party) +{ + virBitmapPtr caps = NULL; + size_t i; + + if (!(caps = virBitmapNew(QEMU_MIGRATION_CAP_LAST))) + return NULL; + + for (i = 0; i < ARRAY_CARDINALITY(qemuMigrationParamsAlwaysOn); i++) { + if (!(qemuMigrationParamsAlwaysOn[i].party & party)) + continue; + + ignore_value(virBitmapSetBit(caps, qemuMigrationParamsAlwaysOn[i].cap)); + } + + return caps; +} + + static qemuMigrationParamsPtr qemuMigrationParamsNew(void) { diff --git a/src/qemu/qemu_migration_params.h b/src/qemu/qemu_migration_params.h index ceba0eb68a..75a441e1e1 100644 --- a/src/qemu/qemu_migration_params.h +++ b/src/qemu/qemu_migration_params.h @@ -65,6 +65,9 @@ typedef enum { } qemuMigrationParty; +virBitmapPtr +qemuMigrationParamsGetAlwaysOnCaps(qemuMigrationParty party); + qemuMigrationParamsPtr qemuMigrationParamsFromFlags(virTypedParameterPtr params, int nparams,