[libvirt] [PATCH v6 0/5] vz: add migration support

Difference from v5 ================== 1. managed case is implemented 2. p2p follows managed migration flow now 3. 'vz: fix const correctness case' is needed to implement managed case. 4. misc options that are always on for vz (--live, --compressed) are not required to be set explicitly. 5. --offline is not supported anymore but migration of inactive domains is possible without this option set. Nikolay Shirokovskiy (5): vz: save session uuid on login vz: fix const correctness case vz: implement managed migration vz: implement p2p migration vz: cleanup: define vz format of uuids src/vz/vz_driver.c | 555 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 89 +++++++-- src/vz/vz_sdk.h | 6 + src/vz/vz_utils.c | 2 +- src/vz/vz_utils.h | 6 +- 5 files changed, 641 insertions(+), 17 deletions(-) -- 1.8.3.1

This session uuid acts as authN token for different multihost vz operations one of which is migration. Unfortunately we can't get it from server at any time thus we need to save it at login. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_sdk.c | 39 +++++++++++++++++++++++++++++---------- src/vz/vz_utils.h | 2 +- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index de73c31..8950b97 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -37,6 +37,9 @@ #define VIR_FROM_THIS VIR_FROM_PARALLELS #define JOB_INFINIT_WAIT_TIMEOUT UINT_MAX +static int +prlsdkUUIDParse(const char *uuidstr, unsigned char *uuid); + VIR_LOG_INIT("parallels.sdk"); /* @@ -228,24 +231,40 @@ prlsdkDeinit(void) int prlsdkConnect(vzConnPtr privconn) { - PRL_RESULT ret; + int ret = -1; + PRL_RESULT pret; PRL_HANDLE job = PRL_INVALID_HANDLE; + PRL_HANDLE result = PRL_INVALID_HANDLE; + PRL_HANDLE response = PRL_INVALID_HANDLE; + char session_uuid[VIR_UUID_STRING_BUFLEN + 2]; + PRL_UINT32 buflen = ARRAY_CARDINALITY(session_uuid); - ret = PrlSrv_Create(&privconn->server); - if (PRL_FAILED(ret)) { - logPrlError(ret); - return -1; - } + pret = PrlSrv_Create(&privconn->server); + prlsdkCheckRetGoto(pret, cleanup); job = PrlSrv_LoginLocalEx(privconn->server, NULL, 0, PSL_HIGH_SECURITY, PACF_NON_INTERACTIVE_MODE); + if (PRL_FAILED(getJobResult(job, &result))) + goto cleanup; - if (waitJob(job)) { + pret = PrlResult_GetParam(result, &response); + prlsdkCheckRetGoto(pret, cleanup); + + pret = PrlLoginResponse_GetSessionUuid(response, session_uuid, &buflen); + prlsdkCheckRetGoto(pret, cleanup); + + if (prlsdkUUIDParse(session_uuid, privconn->session_uuid) < 0) + goto cleanup; + + ret = 0; + + cleanup: + if (ret < 0) PrlHandle_Free(privconn->server); - return -1; - } + PrlHandle_Free(result); + PrlHandle_Free(response); - return 0; + return ret; } void diff --git a/src/vz/vz_utils.h b/src/vz/vz_utils.h index ed100ac..b685478 100644 --- a/src/vz/vz_utils.h +++ b/src/vz/vz_utils.h @@ -54,7 +54,7 @@ struct _vzConn { /* Immutable pointer, self-locking APIs */ virDomainObjListPtr domains; - + unsigned char session_uuid[VIR_UUID_BUFLEN]; PRL_HANDLE server; virCapsPtr caps; virDomainXMLOptionPtr xmlopt; -- 1.8.3.1

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_utils.c | 2 +- src/vz/vz_utils.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vz/vz_utils.c b/src/vz/vz_utils.c index a1ddad0..f56cbdf 100644 --- a/src/vz/vz_utils.c +++ b/src/vz/vz_utils.c @@ -137,7 +137,7 @@ vzGetOutput(const char *binary, ...) } virDomainObjPtr -vzNewDomain(vzConnPtr privconn, char *name, const unsigned char *uuid) +vzNewDomain(vzConnPtr privconn, const char *name, const unsigned char *uuid) { virDomainDefPtr def = NULL; virDomainObjPtr dom = NULL; diff --git a/src/vz/vz_utils.h b/src/vz/vz_utils.h index b685478..8fcedf3 100644 --- a/src/vz/vz_utils.h +++ b/src/vz/vz_utils.h @@ -95,7 +95,7 @@ void vzDriverLock(vzConnPtr driver); void vzDriverUnlock(vzConnPtr driver); virDomainObjPtr vzNewDomain(vzConnPtr privconn, - char *name, + const char *name, const unsigned char *uuid); # define PARALLELS_BLOCK_STATS_FOREACH(OP) \ -- 1.8.3.1

The newest version of migration protocol - version 3 with parameters is implemented. Supported flags is VIR_MIGRATE_PAUSED only. Supported parameters are VIR_MIGRATE_PARAM_URI and VIR_MIGRATE_PARAM_DEST_NAME. VIR_MIGRATE_PARAM_DEST_XML is in VZ_MIGRATION_PARAMETERS for technical onyl reasons. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 442 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 42 +++++ src/vz/vz_sdk.h | 6 + 3 files changed, 490 insertions(+) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index eb9b172..d542da2 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -146,6 +146,9 @@ vzBuildCapabilities(void) caps->host.cpu = cpu; + if (virCapabilitiesAddHostMigrateTransport(caps, "vzmigr") < 0) + goto error; + if (!(data = cpuNodeData(cpu->arch)) || cpuDecode(cpu, data, NULL, 0, NULL) < 0) { goto cleanup; @@ -1527,6 +1530,439 @@ vzConnectUnregisterCloseCallback(virConnectPtr conn, virConnectCloseFunc cb) return ret; } +typedef struct _vzMigrationCookie vzMigrationCookie; +typedef vzMigrationCookie *vzMigrationCookiePtr; +struct _vzMigrationCookie { + unsigned char session_uuid[VIR_UUID_BUFLEN]; + unsigned char uuid[VIR_UUID_BUFLEN]; + char *name; +}; + +static void +vzMigrationCookieFree(vzMigrationCookiePtr mig) +{ + if (!mig) + return; + VIR_FREE(mig->name); + VIR_FREE(mig); +} + +static int +vzBakeCookie(vzMigrationCookiePtr mig, char **cookieout, int *cookieoutlen) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (!cookieout || !cookieoutlen) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Migration cookie parameters are not provided.")); + return -1; + } + + *cookieout = NULL; + *cookieoutlen = 0; + + virBufferAddLit(&buf, "<vz-migration>\n"); + virBufferAdjustIndent(&buf, 2); + virUUIDFormat(mig->session_uuid, uuidstr); + virBufferAsprintf(&buf, "<session-uuid>%s</session-uuid>\n", uuidstr); + virUUIDFormat(mig->uuid, uuidstr); + virBufferAsprintf(&buf, "<uuid>%s</uuid>\n", uuidstr); + virBufferAsprintf(&buf, "<name>%s</name>\n", mig->name); + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</vz-migration>\n"); + + if (virBufferCheckError(&buf) < 0) + return -1; + + *cookieout = virBufferContentAndReset(&buf); + *cookieoutlen = strlen(*cookieout) + 1; + + return 0; +} + +static vzMigrationCookiePtr +vzEatCookie(const char *cookiein, int cookieinlen) +{ + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctx = NULL; + char *tmp = NULL; + vzMigrationCookiePtr mig = NULL; + + if (VIR_ALLOC(mig) < 0) + return NULL; + + if (!cookiein) + return mig; + + if (cookiein[cookieinlen - 1] != '\0') { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Migration cookie was not NULL terminated")); + goto error; + } + + if (!(doc = virXMLParseStringCtxt(cookiein, + _("(_migration_cookie)"), &ctx))) + goto error; + + if (!(tmp = virXPathString("string(./session-uuid[1])", ctx))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing session-uuid element in migration data")); + goto error; + } + if (virUUIDParse(tmp, mig->session_uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed session-uuid element in migration data")); + goto error; + } + + VIR_FREE(tmp); + if (!(tmp = virXPathString("string(./uuid[1])", ctx))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing uuid element in migration data")); + goto error; + } + if (virUUIDParse(tmp, mig->uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed uuid element in migration data")); + goto error; + } + + if (!(mig->name = virXPathString("string(./name[1])", ctx))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing name element in migration data")); + goto error; + } + + cleanup: + xmlXPathFreeContext(ctx); + xmlFreeDoc(doc); + VIR_FREE(tmp); + return mig; + + error: + vzMigrationCookieFree(mig); + mig = NULL; + goto cleanup; +} + +#define VZ_MIGRATION_FLAGS VIR_MIGRATE_PAUSED + +#define VZ_MIGRATION_PARAMETERS \ + VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \ + NULL + +static char * +vzDomainMigrateBegin3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + char **cookieout, + int *cookieoutlen, + unsigned int flags) +{ + char *xml = NULL; + virDomainObjPtr dom = NULL; + vzConnPtr privconn = domain->conn->privateData; + vzMigrationCookiePtr mig = NULL; + + virCheckFlags(VZ_MIGRATION_FLAGS, NULL); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + /* we can't do this check via VZ_MIGRATION_PARAMETERS as on preparation + * step domain xml will be passed via this parameter and it is a common + * style to use single allowed parameter list definition in all steps */ + if (virTypedParamsGet(params, nparams, VIR_MIGRATE_PARAM_DEST_XML)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("Changing destination XML is not supported")); + goto cleanup; + } + + if (!(dom = vzDomObjFromDomain(domain))) + goto cleanup; + + if (!(mig = vzEatCookie(NULL, 0))) + goto cleanup; + + if (VIR_STRDUP(mig->name, dom->def->name) < 0) + goto cleanup; + + memcpy(mig->uuid, dom->def->uuid, VIR_UUID_BUFLEN); + + if (vzBakeCookie(mig, cookieout, cookieoutlen) < 0) + goto cleanup; + + xml = virDomainDefFormat(dom->def, privconn->caps, + VIR_DOMAIN_XML_MIGRATABLE); + + cleanup: + + vzMigrationCookieFree(mig); + if (dom) + virObjectUnlock(dom); + return xml; +} + +static char* +vzMigrationCreateURI(void) +{ + char *hostname = NULL; + char *uri = NULL; + + if (!(hostname = virGetHostname())) + goto cleanup; + + if (STRPREFIX(hostname, "localhost")) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("hostname on destination resolved to localhost," + " but migration requires an FQDN")); + goto cleanup; + } + + if (virAsprintf(&uri, "vzmigr://%s", hostname) < 0) + goto cleanup; + + cleanup: + VIR_FREE(hostname); + return uri; +} + +static int +vzDomainMigratePrepare3Params(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout, + int *cookieoutlen, + char **uri_out, + unsigned int flags) +{ + vzConnPtr privconn = conn->privateData; + const char *miguri = NULL; + const char *dname = NULL; + virDomainObjPtr dom = NULL; + vzMigrationCookiePtr mig = NULL; + int ret = -1; + + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, &miguri) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0) + goto cleanup; + + /* We must set uri_out if miguri is not set. This is direct + * managmed migration requirement */ + if (!miguri && !(*uri_out = vzMigrationCreateURI())) + goto cleanup; + + if (!(mig = vzEatCookie(cookiein, cookieinlen))) + goto cleanup; + + memcpy(mig->session_uuid, privconn->session_uuid, VIR_UUID_BUFLEN); + + if (vzBakeCookie(mig, cookieout, cookieoutlen) < 0) + goto cleanup; + + if (!(dom = vzNewDomain(privconn, dname ? dname : mig->name, mig->uuid))) + goto cleanup; + + ret = 0; + + cleanup: + vzMigrationCookieFree(mig); + if (dom) + virObjectUnlock(dom); + return ret; +} + +static int +vzConnectSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_PARAMS: + return 1; + default: + return 0; + } +} + +static virURIPtr +vzParseVzURI(const char *uri_str) +{ + virURIPtr uri = NULL; + + if (!(uri = virURIParse(uri_str))) + goto error; + + if (!uri->scheme || !uri->server) { + virReportError(VIR_ERR_INVALID_ARG, + _("scheme and host are mandatory vz migration URI: %s"), + uri_str); + goto error; + } + + if (uri->user || uri->path || uri->query || uri->fragment) { + virReportError(VIR_ERR_INVALID_ARG, + _("only scheme, host and port are supported in " + "vz migration URI: %s"), uri_str); + goto error; + } + + if (STRNEQ(uri->scheme, "vzmigr")) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("unsupported scheme %s in migration URI %s"), + uri->scheme, uri_str); + goto error; + } + + return uri; + + error: + virURIFree(uri); + return NULL; +} + +static int +vzDomainMigratePerform3Params(virDomainPtr domain, + const char *dconnuri ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + int ret = -1; + virDomainObjPtr dom = NULL; + virURIPtr vzuri = NULL; + vzConnPtr privconn = domain->conn->privateData; + const char *miguri = NULL; + const char *dname = NULL; + vzMigrationCookiePtr mig = NULL; + + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, &miguri) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0) + goto cleanup; + + if (!miguri) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("migrate uri is not set")); + goto cleanup; + } + + if (!(mig = vzEatCookie(cookiein, cookieinlen))) + goto cleanup; + + if (!(dom = vzDomObjFromDomain(domain))) + goto cleanup; + + if (!(vzuri = vzParseVzURI(miguri))) + goto cleanup; + + if (prlsdkMigrate(dom, vzuri, mig->session_uuid, dname, flags) < 0) + goto cleanup; + + virDomainObjListRemove(privconn->domains, dom); + dom = NULL; + + ret = 0; + + cleanup: + if (dom) + virObjectUnlock(dom); + virURIFree(vzuri); + vzMigrationCookieFree(mig); + + return ret; +} + +static virDomainPtr +vzDomainMigrateFinish3Params(virConnectPtr dconn, + virTypedParameterPtr params, + int nparams, + const char *cookiein ATTRIBUTE_UNUSED, + int cookieinlen ATTRIBUTE_UNUSED, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags, + int cancelled) +{ + virDomainObjPtr dom = NULL; + virDomainPtr domain = NULL; + vzConnPtr privconn = dconn->privateData; + const char *name = NULL; + + virCheckFlags(VZ_MIGRATION_FLAGS, NULL); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, &name) < 0) + goto cleanup; + + if (!(dom = virDomainObjListFindByName(privconn->domains, name))) { + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching name '%s'"), name); + goto cleanup; + } + + if (cancelled) { + virDomainObjListRemove(privconn->domains, dom); + dom = NULL; + goto cleanup; + } + + if (prlsdkLoadDomain(privconn, dom)) + goto cleanup; + + domain = virGetDomain(dconn, dom->def->name, dom->def->uuid); + if (domain) + domain->id = dom->def->id; + + cleanup: + /* In this situation we have to restore domain on source. But the migration + * is already finished. */ + if (!cancelled && !domain) + VIR_WARN("Can't provide domain '%s' after successfull migration.", name); + virDomainObjEndAPI(&dom); + return domain; +} + +static int +vzDomainMigrateConfirm3Params(virDomainPtr domain ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + const char *cookiein ATTRIBUTE_UNUSED, + int cookieinlen ATTRIBUTE_UNUSED, + unsigned int flags, + int cancelled ATTRIBUTE_UNUSED) +{ + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + return -1; + + return 0; +} + static virHypervisorDriver vzDriver = { .name = "vz", .connectOpen = vzConnectOpen, /* 0.10.0 */ @@ -1591,6 +2027,12 @@ static virHypervisorDriver vzDriver = { .domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */ .connectRegisterCloseCallback = vzConnectRegisterCloseCallback, /* 1.3.2 */ .connectUnregisterCloseCallback = vzConnectUnregisterCloseCallback, /* 1.3.2 */ + .connectSupportsFeature = vzConnectSupportsFeature, /* 1.3.3 */ + .domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.3 */ + .domainMigratePrepare3Params = vzDomainMigratePrepare3Params, /* 1.3.3 */ + .domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.3 */ + .domainMigrateFinish3Params = vzDomainMigrateFinish3Params, /* 1.3.3 */ + .domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.3 */ }; static virConnectDriver vzConnectDriver = { diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index 8950b97..cc76243 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -4160,3 +4160,45 @@ prlsdkGetMemoryStats(virDomainObjPtr dom, return ret; } + +/* high security is default choice for 2 reasons: + * 1. as this is the highest set security we can't get + * reject from server with high security settings + * 2. this is on par with security level of driver + * connection to dispatcher + */ + +#define PRLSDK_MIGRATION_FLAGS (PSL_HIGH_SECURITY) + +int prlsdkMigrate(virDomainObjPtr dom, virURIPtr uri, + const unsigned char *session_uuid, + const char *dname, + unsigned int flags) +{ + int ret = -1; + vzDomObjPtr privdom = dom->privateData; + PRL_HANDLE job = PRL_INVALID_HANDLE; + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + PRL_UINT32 vzflags = PRLSDK_MIGRATION_FLAGS; + + if (flags & VIR_MIGRATE_PAUSED) + vzflags |= PVMT_DONT_RESUME_VM; + + prlsdkUUIDFormat(session_uuid, uuidstr); + job = PrlVm_MigrateWithRenameEx(privdom->sdkdom, uri->server, + uri->port, uuidstr, + dname == NULL ? "" : dname, + "", + vzflags, + 0, + PRL_TRUE + ); + + if (PRL_FAILED(waitJob(job))) + goto cleanup; + + ret = 0; + + cleanup: + return ret; +} diff --git a/src/vz/vz_sdk.h b/src/vz/vz_sdk.h index c2d9cb4..d2f1204 100644 --- a/src/vz/vz_sdk.h +++ b/src/vz/vz_sdk.h @@ -80,3 +80,9 @@ int prlsdkGetMemoryStats(virDomainObjPtr dom, virDomainMemoryStatPtr stats, unsigned int nr_stats); void prlsdkDomObjFreePrivate(void *p); +int +prlsdkMigrate(virDomainObjPtr dom, + virURIPtr uri, + const char unsigned *session_uuid, + const char *dname, + unsigned int flags); -- 1.8.3.1

Peer to peer migration is implemented just as in managed case. Basically it is copy paste from managed case but with all the branches that are not applied to vz removed. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 126 insertions(+), 13 deletions(-) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index d542da2..2fce025 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -1646,7 +1646,8 @@ vzEatCookie(const char *cookiein, int cookieinlen) goto cleanup; } -#define VZ_MIGRATION_FLAGS VIR_MIGRATE_PAUSED +#define VZ_MIGRATION_FLAGS (VIR_MIGRATE_PAUSED | \ + VIR_MIGRATE_PEER2PEER) #define VZ_MIGRATION_PARAMETERS \ VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ @@ -1750,9 +1751,6 @@ vzDomainMigratePrepare3Params(virConnectPtr conn, virCheckFlags(VZ_MIGRATION_FLAGS, -1); - if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) - goto cleanup; - if (virTypedParamsGetString(params, nparams, VIR_MIGRATE_PARAM_URI, &miguri) < 0 || virTypedParamsGetString(params, nparams, @@ -1789,6 +1787,7 @@ vzConnectSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature) { switch (feature) { case VIR_DRV_FEATURE_MIGRATION_PARAMS: + case VIR_DRV_FEATURE_MIGRATION_P2P: return 1; default: return 0; @@ -1832,15 +1831,12 @@ vzParseVzURI(const char *uri_str) } static int -vzDomainMigratePerform3Params(virDomainPtr domain, - const char *dconnuri ATTRIBUTE_UNUSED, - virTypedParameterPtr params, - int nparams, - const char *cookiein, - int cookieinlen, - char **cookieout ATTRIBUTE_UNUSED, - int *cookieoutlen ATTRIBUTE_UNUSED, - unsigned int flags) +vzDomainMigratePerformStep(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + unsigned int flags) { int ret = -1; virDomainObjPtr dom = NULL; @@ -1893,6 +1889,123 @@ vzDomainMigratePerform3Params(virDomainPtr domain, return ret; } +static int +vzDomainMigratePerformP2P(virDomainPtr domain, + const char *dconnuri, + virTypedParameterPtr orig_params, + int nparams, + unsigned int flags) +{ + virDomainPtr ddomain = NULL; + char *uri = NULL; + char *cookiein = NULL; + char *cookieout = NULL; + char *dom_xml = NULL; + int cookieinlen = 0; + int cookieoutlen = 0; + virErrorPtr orig_err = NULL; + int cancelled = 1; + virConnectPtr dconn = NULL; + virTypedParameterPtr params = NULL; + int ret = -1; + + if (virTypedParamsCopy(¶ms, orig_params, nparams) < 0) + return -1; + + if (!(dconn = virConnectOpen(dconnuri))) + goto done; + + if (!(dom_xml = vzDomainMigrateBegin3Params(domain, params, nparams, + &cookieout, &cookieoutlen, + flags))) + goto done; + + cookiein = cookieout; + cookieinlen = cookieoutlen; + cookieout = NULL; + cookieoutlen = 0; + if (dconn->driver->domainMigratePrepare3Params + (dconn, params, nparams, cookiein, cookieinlen, + &cookieout, &cookieoutlen, &uri, flags) < 0) + goto done; + + /* preparation step was successful, thus on any error we must perform + * finish step to finalize migration on target + */ + if (uri && virTypedParamsReplaceString(¶ms, &nparams, + VIR_MIGRATE_PARAM_URI, uri) < 0) { + orig_err = virSaveLastError(); + goto finish; + } + + VIR_FREE(cookiein); + cookiein = cookieout; + cookieinlen = cookieoutlen; + cookieout = NULL; + cookieoutlen = 0; + if (vzDomainMigratePerformStep(domain, params, nparams, cookiein, + cookieinlen, flags) < 0) { + orig_err = virSaveLastError(); + goto finish; + } + + cancelled = 0; + + finish: + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, NULL) <= 0 && + virTypedParamsReplaceString(¶ms, &nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + domain->name) < 0) + goto done; + + ddomain = dconn->driver->domainMigrateFinish3Params(dconn, params, nparams, + NULL, 0, NULL, NULL, + flags, cancelled); + if (ddomain) + ret = 0; + virObjectUnref(ddomain); + + /* confirm step is NOOP thus no need to call it */ + + done: + if (orig_err) { + virSetError(orig_err); + virFreeError(orig_err); + } + VIR_FREE(dom_xml); + VIR_FREE(uri); + VIR_FREE(cookiein); + VIR_FREE(cookieout); + virTypedParamsFree(params, nparams); + virObjectUnref(dconn); + return ret; +} + +static int +vzDomainMigratePerform3Params(virDomainPtr domain, + const char *dconnuri, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + return -1; + + if (flags & VIR_MIGRATE_PEER2PEER) + return vzDomainMigratePerformP2P(domain, dconnuri, params, nparams, flags); + else + return vzDomainMigratePerformStep(domain, params, nparams, + cookiein, cookieinlen, flags); + +} + static virDomainPtr vzDomainMigrateFinish3Params(virConnectPtr dconn, virTypedParameterPtr params, -- 1.8.3.1

vz puts uuids into curly braces. Simply introduce new contstant to reflect this and get rid of magic +2 in code. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_sdk.c | 12 ++++++------ src/vz/vz_utils.h | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index cc76243..814c781 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -236,7 +236,7 @@ prlsdkConnect(vzConnPtr privconn) PRL_HANDLE job = PRL_INVALID_HANDLE; PRL_HANDLE result = PRL_INVALID_HANDLE; PRL_HANDLE response = PRL_INVALID_HANDLE; - char session_uuid[VIR_UUID_STRING_BUFLEN + 2]; + char session_uuid[VZ_UUID_STRING_BUFLEN]; PRL_UINT32 buflen = ARRAY_CARDINALITY(session_uuid); pret = PrlSrv_Create(&privconn->server); @@ -316,7 +316,7 @@ prlsdkUUIDFormat(const unsigned char *uuid, char *uuidstr) static PRL_HANDLE prlsdkSdkDomainLookupByUUID(vzConnPtr privconn, const unsigned char *uuid) { - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VZ_UUID_STRING_BUFLEN]; PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; prlsdkUUIDFormat(uuid, uuidstr); @@ -361,7 +361,7 @@ prlsdkGetDomainIds(PRL_HANDLE sdkdom, char **name, unsigned char *uuid) { - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VZ_UUID_STRING_BUFLEN]; PRL_UINT32 len; PRL_RESULT pret; @@ -1683,7 +1683,7 @@ prlsdkEventsHandler(PRL_HANDLE prlEvent, PRL_VOID_PTR opaque) vzConnPtr privconn = opaque; PRL_RESULT pret = PRL_ERR_FAILURE; PRL_HANDLE_TYPE handleType; - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VZ_UUID_STRING_BUFLEN]; unsigned char uuid[VIR_UUID_BUFLEN]; PRL_UINT32 bufsize = ARRAY_CARDINALITY(uuidstr); PRL_EVENT_TYPE prlEventType; @@ -3456,7 +3456,7 @@ prlsdkDoApplyConfig(virConnectPtr conn, { PRL_RESULT pret; size_t i; - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VZ_UUID_STRING_BUFLEN]; bool needBoot = true; char *mask = NULL; @@ -4178,7 +4178,7 @@ int prlsdkMigrate(virDomainObjPtr dom, virURIPtr uri, int ret = -1; vzDomObjPtr privdom = dom->privateData; PRL_HANDLE job = PRL_INVALID_HANDLE; - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VZ_UUID_STRING_BUFLEN]; PRL_UINT32 vzflags = PRLSDK_MIGRATION_FLAGS; if (flags & VIR_MIGRATE_PAUSED) diff --git a/src/vz/vz_utils.h b/src/vz/vz_utils.h index 8fcedf3..cef2dca 100644 --- a/src/vz/vz_utils.h +++ b/src/vz/vz_utils.h @@ -49,6 +49,8 @@ # define PARALLELS_DOMAIN_ROUTED_NETWORK_NAME "Routed" # define PARALLELS_DOMAIN_BRIDGED_NETWORK_NAME "Bridged" +# define VZ_UUID_STRING_BUFLEN (VIR_UUID_STRING_BUFLEN + 2) + struct _vzConn { virMutex lock; -- 1.8.3.1

ping On 02.03.2016 13:55, Nikolay Shirokovskiy wrote:
Difference from v5 ==================
1. managed case is implemented 2. p2p follows managed migration flow now 3. 'vz: fix const correctness case' is needed to implement managed case. 4. misc options that are always on for vz (--live, --compressed) are not required to be set explicitly. 5. --offline is not supported anymore but migration of inactive domains is possible without this option set.
Nikolay Shirokovskiy (5): vz: save session uuid on login vz: fix const correctness case vz: implement managed migration vz: implement p2p migration vz: cleanup: define vz format of uuids
src/vz/vz_driver.c | 555 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 89 +++++++-- src/vz/vz_sdk.h | 6 + src/vz/vz_utils.c | 2 +- src/vz/vz_utils.h | 6 +- 5 files changed, 641 insertions(+), 17 deletions(-)

02.03.2016 13:55, Nikolay Shirokovskiy пишет:
Difference from v5 ==================
1. managed case is implemented 2. p2p follows managed migration flow now 3. 'vz: fix const correctness case' is needed to implement managed case. 4. misc options that are always on for vz (--live, --compressed) are not required to be set explicitly. 5. --offline is not supported anymore but migration of inactive domains is possible without this option set.
Nikolay Shirokovskiy (5): vz: save session uuid on login vz: fix const correctness case vz: implement managed migration vz: implement p2p migration vz: cleanup: define vz format of uuids
src/vz/vz_driver.c | 555 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 89 +++++++-- src/vz/vz_sdk.h | 6 + src/vz/vz_utils.c | 2 +- src/vz/vz_utils.h | 6 +- 5 files changed, 641 insertions(+), 17 deletions(-)
Sorry for the long delay. Since the code moved forward a lot could you please rebase the series? Maxim
participants (2)
-
Maxim Nestratov
-
Nikolay Shirokovskiy