393 lines
13 KiB
Diff
393 lines
13 KiB
Diff
commit f9edcfa47396fdaab69ed72f0d5e0b751aa014fa
|
|
Author: Jim Fehlig <jfehlig@suse.com>
|
|
Date: Fri Apr 29 15:08:05 2016 -0600
|
|
|
|
libxl: support migration stream V2 in migration
|
|
|
|
Similar to "support Xen migration stream V2 in save/restore",
|
|
add support for indicating the migration stream version in
|
|
the migration code. To accomplish this, add a minimal migration
|
|
cookie in the libxl driver that is passed between source and
|
|
destination hosts. Initially, the cookie is only used in
|
|
the Begin and Prepare phases of migration to communicate the
|
|
version of the migration stream produced by the source.
|
|
|
|
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
|
|
|
|
Index: libvirt-1.3.4/src/libxl/libxl_driver.c
|
|
===================================================================
|
|
--- libvirt-1.3.4.orig/src/libxl/libxl_driver.c
|
|
+++ libvirt-1.3.4/src/libxl/libxl_driver.c
|
|
@@ -5151,8 +5151,8 @@ static char *
|
|
libxlDomainMigrateBegin3Params(virDomainPtr domain,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
- char **cookieout ATTRIBUTE_UNUSED,
|
|
- int *cookieoutlen ATTRIBUTE_UNUSED,
|
|
+ char **cookieout,
|
|
+ int *cookieoutlen,
|
|
unsigned int flags)
|
|
{
|
|
const char *xmlin = NULL;
|
|
@@ -5193,15 +5193,16 @@ libxlDomainMigrateBegin3Params(virDomain
|
|
return NULL;
|
|
}
|
|
|
|
- return libxlDomainMigrationBegin(domain->conn, vm, xmlin);
|
|
+ return libxlDomainMigrationBegin(domain->conn, vm, xmlin,
|
|
+ cookieout, cookieoutlen);
|
|
}
|
|
|
|
static int
|
|
libxlDomainMigratePrepare3Params(virConnectPtr dconn,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
- const char *cookiein ATTRIBUTE_UNUSED,
|
|
- int cookieinlen ATTRIBUTE_UNUSED,
|
|
+ const char *cookiein,
|
|
+ int cookieinlen,
|
|
char **cookieout ATTRIBUTE_UNUSED,
|
|
int *cookieoutlen ATTRIBUTE_UNUSED,
|
|
char **uri_out,
|
|
@@ -5240,7 +5241,8 @@ libxlDomainMigratePrepare3Params(virConn
|
|
if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0)
|
|
goto error;
|
|
|
|
- if (libxlDomainMigrationPrepare(dconn, &def, uri_in, uri_out, flags) < 0)
|
|
+ if (libxlDomainMigrationPrepare(dconn, &def, uri_in, uri_out,
|
|
+ cookiein, cookieinlen, flags) < 0)
|
|
goto error;
|
|
|
|
return 0;
|
|
Index: libvirt-1.3.4/src/libxl/libxl_migration.c
|
|
===================================================================
|
|
--- libvirt-1.3.4.orig/src/libxl/libxl_migration.c
|
|
+++ libvirt-1.3.4/src/libxl/libxl_migration.c
|
|
@@ -48,6 +48,18 @@
|
|
|
|
VIR_LOG_INIT("libxl.libxl_migration");
|
|
|
|
+typedef struct _libxlMigrationCookie libxlMigrationCookie;
|
|
+typedef libxlMigrationCookie *libxlMigrationCookiePtr;
|
|
+struct _libxlMigrationCookie {
|
|
+ /* Host properties */
|
|
+ char *srcHostname;
|
|
+ uint32_t xenMigStreamVer;
|
|
+
|
|
+ /* Guest properties */
|
|
+ unsigned char uuid[VIR_UUID_BUFLEN];
|
|
+ char *name;
|
|
+};
|
|
+
|
|
typedef struct _libxlMigrationDstArgs {
|
|
virObject parent;
|
|
|
|
@@ -55,6 +67,7 @@ typedef struct _libxlMigrationDstArgs {
|
|
virConnectPtr conn;
|
|
virDomainObjPtr vm;
|
|
unsigned int flags;
|
|
+ libxlMigrationCookiePtr migcookie;
|
|
|
|
/* for freeing listen sockets */
|
|
virNetSocketPtr *socks;
|
|
@@ -63,11 +76,166 @@ typedef struct _libxlMigrationDstArgs {
|
|
|
|
static virClassPtr libxlMigrationDstArgsClass;
|
|
|
|
+
|
|
+static void
|
|
+libxlMigrationCookieFree(libxlMigrationCookiePtr mig)
|
|
+{
|
|
+ if (!mig)
|
|
+ return;
|
|
+
|
|
+ VIR_FREE(mig->srcHostname);
|
|
+ VIR_FREE(mig->name);
|
|
+ VIR_FREE(mig);
|
|
+}
|
|
+
|
|
+static libxlMigrationCookiePtr
|
|
+libxlMigrationCookieNew(virDomainObjPtr dom)
|
|
+{
|
|
+ libxlMigrationCookiePtr mig = NULL;
|
|
+
|
|
+ if (VIR_ALLOC(mig) < 0)
|
|
+ goto error;
|
|
+
|
|
+ if (VIR_STRDUP(mig->name, dom->def->name) < 0)
|
|
+ goto error;
|
|
+
|
|
+ memcpy(mig->uuid, dom->def->uuid, VIR_UUID_BUFLEN);
|
|
+
|
|
+ if (!(mig->srcHostname = virGetHostname()))
|
|
+ goto error;
|
|
+
|
|
+ mig->xenMigStreamVer = LIBXL_SAVE_VERSION;
|
|
+
|
|
+ return mig;
|
|
+
|
|
+ error:
|
|
+ libxlMigrationCookieFree(mig);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+libxlMigrationBakeCookie(libxlMigrationCookiePtr mig,
|
|
+ char **cookieout,
|
|
+ int *cookieoutlen)
|
|
+{
|
|
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
+
|
|
+ if (!cookieout || !cookieoutlen)
|
|
+ return 0;
|
|
+
|
|
+ *cookieoutlen = 0;
|
|
+ virUUIDFormat(mig->uuid, uuidstr);
|
|
+
|
|
+ virBufferAddLit(&buf, "<libxl-migration>\n");
|
|
+ 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->srcHostname);
|
|
+ virBufferAsprintf(&buf, "<migration-stream-version>%u</migration-stream-version>\n", mig->xenMigStreamVer);
|
|
+ virBufferAdjustIndent(&buf, -2);
|
|
+ virBufferAddLit(&buf, "</libxl-migration>\n");
|
|
+
|
|
+ if (virBufferCheckError(&buf) < 0)
|
|
+ return -1;
|
|
+
|
|
+ *cookieout = virBufferContentAndReset(&buf);
|
|
+ *cookieoutlen = strlen(*cookieout) + 1;
|
|
+
|
|
+ VIR_DEBUG("cookielen=%d cookie=%s", *cookieoutlen, *cookieout);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+libxlMigrationEatCookie(const char *cookiein,
|
|
+ int cookieinlen,
|
|
+ libxlMigrationCookiePtr *migout)
|
|
+{
|
|
+ libxlMigrationCookiePtr mig = NULL;
|
|
+ xmlDocPtr doc = NULL;
|
|
+ xmlXPathContextPtr ctxt = NULL;
|
|
+ char *uuidstr = NULL;
|
|
+ int ret = -1;
|
|
+
|
|
+ /*
|
|
+ * Assume a legacy (V1) migration stream if request came from a
|
|
+ * source host without cookie support, and hence no way to
|
|
+ * specify a stream version.
|
|
+ */
|
|
+ if (!cookiein || !cookieinlen) {
|
|
+ if (VIR_ALLOC(mig) < 0)
|
|
+ return -1;
|
|
+
|
|
+ mig->xenMigStreamVer = 1;
|
|
+ *migout = mig;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (cookiein[cookieinlen-1] != '\0') {
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
+ _("Migration cookie was not NULL terminated"));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ VIR_DEBUG("cookielen=%d cookie='%s'", cookieinlen, NULLSTR(cookiein));
|
|
+
|
|
+ if (VIR_ALLOC(mig) < 0)
|
|
+ return -1;
|
|
+
|
|
+ if (!(doc = virXMLParseStringCtxt(cookiein,
|
|
+ _("(libxl_migration_cookie)"),
|
|
+ &ctxt)))
|
|
+ goto error;
|
|
+
|
|
+ /* Extract domain name */
|
|
+ if (!(mig->name = virXPathString("string(./name[1])", ctxt))) {
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
+ "%s", _("missing name element in migration data"));
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ /* Extract domain uuid */
|
|
+ uuidstr = virXPathString("string(./uuid[1])", ctxt);
|
|
+ if (!uuidstr) {
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
+ "%s", _("missing uuid element in migration data"));
|
|
+ goto error;
|
|
+ }
|
|
+ if (virUUIDParse(uuidstr, mig->uuid) < 0) {
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
+ "%s", _("malformed uuid element"));
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (virXPathUInt("string(./migration-stream-version[1])",
|
|
+ ctxt, &mig->xenMigStreamVer) < 0) {
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
+ _("missing Xen migration stream version"));
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ *migout = mig;
|
|
+ ret = 0;
|
|
+ goto cleanup;
|
|
+
|
|
+ error:
|
|
+ libxlMigrationCookieFree(mig);
|
|
+
|
|
+ cleanup:
|
|
+ VIR_FREE(uuidstr);
|
|
+ xmlXPathFreeContext(ctxt);
|
|
+ xmlFreeDoc(doc);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static void
|
|
libxlMigrationDstArgsDispose(void *obj)
|
|
{
|
|
libxlMigrationDstArgs *args = obj;
|
|
|
|
+ libxlMigrationCookieFree(args->migcookie);
|
|
VIR_FREE(args->socks);
|
|
}
|
|
|
|
@@ -106,7 +274,8 @@ libxlDoMigrateReceive(void *opaque)
|
|
* Always start the domain paused. If needed, unpause in the
|
|
* finish phase, after transfer of the domain is complete.
|
|
*/
|
|
- ret = libxlDomainStartRestore(driver, vm, true, recvfd, LIBXL_SAVE_VERSION);
|
|
+ ret = libxlDomainStartRestore(driver, vm, true, recvfd,
|
|
+ args->migcookie->xenMigStreamVer);
|
|
|
|
if (ret < 0 && !vm->persistent)
|
|
remove_dom = true;
|
|
@@ -227,10 +396,13 @@ libxlDomainMigrationIsAllowed(virDomainD
|
|
char *
|
|
libxlDomainMigrationBegin(virConnectPtr conn,
|
|
virDomainObjPtr vm,
|
|
- const char *xmlin)
|
|
+ const char *xmlin,
|
|
+ char **cookieout,
|
|
+ int *cookieoutlen)
|
|
{
|
|
libxlDriverPrivatePtr driver = conn->privateData;
|
|
libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
|
|
+ libxlMigrationCookiePtr mig;
|
|
virDomainDefPtr tmpdef = NULL;
|
|
virDomainDefPtr def;
|
|
char *xml = NULL;
|
|
@@ -238,6 +410,12 @@ libxlDomainMigrationBegin(virConnectPtr
|
|
if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
|
|
goto cleanup;
|
|
|
|
+ if (!(mig = libxlMigrationCookieNew(vm)))
|
|
+ goto endjob;
|
|
+
|
|
+ if (libxlMigrationBakeCookie(mig, cookieout, cookieoutlen) < 0)
|
|
+ goto endjob;
|
|
+
|
|
if (xmlin) {
|
|
if (!(tmpdef = virDomainDefParseString(xmlin, cfg->caps,
|
|
driver->xmlopt,
|
|
@@ -308,9 +486,12 @@ libxlDomainMigrationPrepare(virConnectPt
|
|
virDomainDefPtr *def,
|
|
const char *uri_in,
|
|
char **uri_out,
|
|
+ const char *cookiein,
|
|
+ int cookieinlen,
|
|
unsigned int flags)
|
|
{
|
|
libxlDriverPrivatePtr driver = dconn->privateData;
|
|
+ libxlMigrationCookiePtr mig = NULL;
|
|
virDomainObjPtr vm = NULL;
|
|
char *hostname = NULL;
|
|
unsigned short port;
|
|
@@ -323,6 +504,16 @@ libxlDomainMigrationPrepare(virConnectPt
|
|
size_t i;
|
|
int ret = -1;
|
|
|
|
+ if (libxlMigrationEatCookie(cookiein, cookieinlen, &mig) < 0)
|
|
+ goto error;
|
|
+
|
|
+ if (mig->xenMigStreamVer > LIBXL_SAVE_VERSION) {
|
|
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
|
|
+ _("Xen migration stream version '%d' is not supported on this host"),
|
|
+ mig->xenMigStreamVer);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
if (!(vm = virDomainObjListAdd(driver->domains, *def,
|
|
driver->xmlopt,
|
|
VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
|
|
@@ -409,6 +600,7 @@ libxlDomainMigrationPrepare(virConnectPt
|
|
args->flags = flags;
|
|
args->socks = socks;
|
|
args->nsocks = nsocks;
|
|
+ args->migcookie = mig;
|
|
|
|
for (i = 0; i < nsocks; i++) {
|
|
if (virNetSocketSetBlocking(socks[i], true) < 0)
|
|
@@ -479,11 +671,14 @@ libxlDoMigrateP2P(libxlDriverPrivatePtr
|
|
char *uri_out = NULL;
|
|
char *dom_xml = NULL;
|
|
unsigned long destflags;
|
|
+ char *cookieout = NULL;
|
|
+ int cookieoutlen;
|
|
bool cancelled = true;
|
|
virErrorPtr orig_err = NULL;
|
|
int ret = -1;
|
|
|
|
- dom_xml = libxlDomainMigrationBegin(sconn, vm, xmlin);
|
|
+ dom_xml = libxlDomainMigrationBegin(sconn, vm, xmlin,
|
|
+ &cookieout, &cookieoutlen);
|
|
if (!dom_xml)
|
|
goto cleanup;
|
|
|
|
@@ -509,7 +704,7 @@ libxlDoMigrateP2P(libxlDriverPrivatePtr
|
|
VIR_DEBUG("Prepare3");
|
|
virObjectUnlock(vm);
|
|
ret = dconn->driver->domainMigratePrepare3Params
|
|
- (dconn, params, nparams, NULL, 0, NULL, NULL, &uri_out, destflags);
|
|
+ (dconn, params, nparams, cookieout, cookieoutlen, NULL, NULL, &uri_out, destflags);
|
|
virObjectLock(vm);
|
|
|
|
if (ret == -1)
|
|
@@ -580,6 +775,7 @@ libxlDoMigrateP2P(libxlDriverPrivatePtr
|
|
virFreeError(orig_err);
|
|
}
|
|
|
|
+ VIR_FREE(cookieout);
|
|
VIR_FREE(dom_xml);
|
|
VIR_FREE(uri_out);
|
|
virTypedParamsFree(params, nparams);
|
|
Index: libvirt-1.3.4/src/libxl/libxl_migration.h
|
|
===================================================================
|
|
--- libvirt-1.3.4.orig/src/libxl/libxl_migration.h
|
|
+++ libvirt-1.3.4/src/libxl/libxl_migration.h
|
|
@@ -42,7 +42,9 @@
|
|
char *
|
|
libxlDomainMigrationBegin(virConnectPtr conn,
|
|
virDomainObjPtr vm,
|
|
- const char *xmlin);
|
|
+ const char *xmlin,
|
|
+ char **cookieout,
|
|
+ int *cookieoutlen);
|
|
|
|
virDomainDefPtr
|
|
libxlDomainMigrationPrepareDef(libxlDriverPrivatePtr driver,
|
|
@@ -54,6 +56,8 @@ libxlDomainMigrationPrepare(virConnectPt
|
|
virDomainDefPtr *def,
|
|
const char *uri_in,
|
|
char **uri_out,
|
|
+ const char *cookiein,
|
|
+ int cookieinlen,
|
|
unsigned int flags);
|
|
|
|
int
|