On Tue, Sep 08, 2015 at 09:26:11AM +0100, Joao Martins wrote: > Introduce support for VIR_MIGRATE_PEER2PEER in libvirt migration. > Most of the changes occur at the source and no modifications > at the receiver. > > In P2P mode there is only the Perform phase so we must handle > the connection with the destination and actually perform the > migration. libxlDomainPerformP2P implements the connection to > the destination and let libxlDoMigrateP2P implements the actual > migration logic with virConnectPtr. In this function we take > of doing all phases of migration in the destination similar to > virDomainMigrateVersion3Full. We appropriately save the last > error reported in each of the phases to provide proper > reporting. We don't yet support VIR_MIGRATE_TUNNELED yet and > we always use V3 with extensible params, thus it also makes the > implementation simpler. > > It is worth noting that the receiver didn't have any changes, > and since it's still the v3 sequence thus it is possible to > migrate from a P2P to non-P2P host. > > Signed-off-by: Joao Martins <joao.m.martins@xxxxxxxxxx> > --- > src/libxl/libxl_driver.c | 13 ++- > src/libxl/libxl_migration.c | 220 ++++++++++++++++++++++++++++++++++++++++++++ > src/libxl/libxl_migration.h | 11 +++ > 3 files changed, 241 insertions(+), 3 deletions(-) > > diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c > index 5f69b49..4d6821f 100644 > --- a/src/libxl/libxl_driver.c > +++ b/src/libxl/libxl_driver.c > @@ -4710,6 +4710,7 @@ libxlConnectSupportsFeature(virConnectPtr conn, int feature) > switch (feature) { > case VIR_DRV_FEATURE_TYPED_PARAM_STRING: > case VIR_DRV_FEATURE_MIGRATION_PARAMS: > + case VIR_DRV_FEATURE_MIGRATION_P2P: > return 1; > default: > return 0; > @@ -5036,9 +5037,15 @@ libxlDomainMigratePerform3Params(virDomainPtr dom, > if (virDomainMigratePerform3ParamsEnsureACL(dom->conn, vm->def) < 0) > goto cleanup; > > - if (libxlDomainMigrationPerform(driver, vm, dom_xml, dconnuri, > - uri, dname, flags) < 0) > - goto cleanup; > + if (flags & VIR_MIGRATE_PEER2PEER) { > + if (libxlDomainMigrationPerformP2P(driver, vm, dom->conn, dom_xml, > + dconnuri, uri, dname, flags) < 0) > + goto cleanup; > + } else { > + if (libxlDomainMigrationPerform(driver, vm, dom_xml, dconnuri, > + uri, dname, flags) < 0) > + goto cleanup; > + } > > ret = 0; > > diff --git a/src/libxl/libxl_migration.c b/src/libxl/libxl_migration.c > index 0d23e5f..659f4d8 100644 > --- a/src/libxl/libxl_migration.c > +++ b/src/libxl/libxl_migration.c > @@ -42,6 +42,7 @@ > #include "libxl_conf.h" > #include "libxl_migration.h" > #include "locking/domain_lock.h" > +#include "virtypedparam.h" > > #define VIR_FROM_THIS VIR_FROM_LIBXL > > @@ -456,6 +457,225 @@ libxlDomainMigrationPrepare(virConnectPtr dconn, > return ret; > } > > +/* This function is a simplification of virDomainMigrateVersion3Full > + * excluding tunnel support and restricting it to migration v3 > + * with params since it was the first to be introduced in libxl. > + */ > +static int > +libxlDoMigrateP2P(libxlDriverPrivatePtr driver, > + virDomainObjPtr vm, > + const char *dom_xml, > + virConnectPtr dconn, > + const char *dconnuri ATTRIBUTE_UNUSED, > + const char *dname, > + const char *uri, > + unsigned int flags) > +{ > + virDomainPtr ddomain = NULL; > + virTypedParameterPtr params = NULL; > + int nparams = 0; > + int maxparams = 0; > + char *uri_out = NULL; > + unsigned long destflags; > + bool cancelled = true; > + virErrorPtr orig_err = NULL; > + int ret = -1; > + > + 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; > + > + /* We don't require the destination to have P2P support > + * as it looks to be normal migration from the receiver perpective. > + */ > + destflags = flags & ~(VIR_MIGRATE_PEER2PEER); > + > + VIR_DEBUG("Prepare3"); > + virObjectUnlock(vm); > + ret = dconn->driver->domainMigratePrepare3Params > + (dconn, params, nparams, NULL, 0, NULL, NULL, &uri_out, destflags); > + virObjectLock(vm); > + > + if (ret == -1) > + goto cleanup; > + > + if (uri_out) { > + if (virTypedParamsReplaceString(¶ms, &nparams, > + VIR_MIGRATE_PARAM_URI, uri_out) < 0) { > + orig_err = virSaveLastError(); > + goto finish; > + } > + } else { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("domainMigratePrepare3 did not set uri")); > + goto finish; > + } > + > + VIR_DEBUG("Perform3 uri=%s", NULLSTR(uri_out)); > + ret = libxlDomainMigrationPerform(driver, vm, NULL, NULL, > + uri_out, NULL, flags); > + > + if (ret < 0) > + orig_err = virSaveLastError(); > + > + cancelled = (ret < 0); > + > + finish: > + VIR_DEBUG("Finish3 ret=%d", ret); > + 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 { > + virObjectUnlock(vm); > + ddomain = dconn->driver->domainMigrateFinish3Params > + (dconn, params, nparams, NULL, 0, NULL, NULL, > + destflags, cancelled); > + virObjectLock(vm); > + } > + > + cancelled = (ddomain == NULL); > + > + /* If Finish3Params 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(); > + > + VIR_DEBUG("Confirm3 cancelled=%d vm=%p", cancelled, vm); > + ret = libxlDomainMigrationConfirm(driver, vm, flags, cancelled); > + > + if (ret < 0) > + VIR_WARN("Guest %s probably left in 'paused' state on source", > + vm->def->name); > + > + cleanup: > + if (ddomain) { > + virObjectUnref(ddomain); > + ret = 0; > + } else { > + ret = -1; > + } > + > + if (orig_err) { > + virSetError(orig_err); > + virFreeError(orig_err); > + } > + > + VIR_FREE(uri_out); > + virTypedParamsFree(params, nparams); > + return ret; > +} > + > +static int virConnectCredType[] = { > + VIR_CRED_AUTHNAME, > + VIR_CRED_PASSPHRASE, > +}; > + > + > +static virConnectAuth virConnectAuthConfig = { > + .credtype = virConnectCredType, > + .ncredtype = ARRAY_CARDINALITY(virConnectCredType), > +}; > + > +static void > +libxlMigrationConnectionClosed(virConnectPtr conn, > + int reason, > + void *opaque) > +{ > + virDomainObjPtr vm = opaque; > + > + VIR_DEBUG("conn=%p, reason=%d, vm=%s", conn, reason, vm->def->name); > + virDomainObjBroadcast(vm); > +} > + > +/* On P2P mode there is only the Perform3 phase and we need to handle > + * the connection with the destination libvirtd and perform the migration. > + * Here we first tackle the first part of it, and libxlDoMigrationP2P handles > + * the migration process with an established virConnectPtr to the destination. > + */ > +int > +libxlDomainMigrationPerformP2P(libxlDriverPrivatePtr driver, > + virDomainObjPtr vm, > + virConnectPtr sconn, > + const char *xmlin, > + const char *dconnuri, > + const char *uri_str ATTRIBUTE_UNUSED, > + const char *dname, > + unsigned int flags) > +{ > + char *dom_xml; > + int ret = -1; > + int keepAliveInterval = 5; > + int keepAliveCount = 5; > + bool useParams; > + virConnectPtr dconn = NULL; > + virErrorPtr orig_err = NULL; > + > + virObjectUnlock(vm); > + dconn = virConnectOpenAuth(dconnuri, &virConnectAuthConfig, 0); > + virObjectLock(vm); > + > + if (dconn == NULL) { > + virReportError(VIR_ERR_OPERATION_FAILED, > + _("Failed to connect to remote libvirt URI %s: %s"), > + dconnuri, virGetLastErrorMessage()); > + return ret; > + } > + > + if (virConnectSetKeepAlive(dconn, keepAliveInterval, > + keepAliveCount) < 0) > + goto cleanup; > + > + if (virConnectRegisterCloseCallback(dconn, libxlMigrationConnectionClosed, > + vm, NULL) < 0) { > + goto cleanup; > + } > + > + virObjectUnlock(vm); > + useParams = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, > + VIR_DRV_FEATURE_MIGRATION_PARAMS); > + virObjectLock(vm); > + > + if (!useParams) { > + virReportError(VIR_ERR_OPERATION_FAILED, "%s", > + _("Destination libvirt does not support migration with extensible parameters")); > + goto cleanup; > + } > + > + dom_xml = libxlDomainMigrationBegin(sconn, vm, xmlin); > + if (!dom_xml) > + goto cleanup; Since you have the other 4 steps of the V3 protocol invoked in libxlDoMigrateP2P, I'd rather expect the Begin step to be in that method too. > + > + ret = libxlDoMigrateP2P(driver, vm, dom_xml, dconn, dconnuri, > + dname, uri_str, flags); > + > + VIR_FREE(dom_xml); > + cleanup: > + orig_err = virSaveLastError(); > + virObjectUnlock(vm); > + virConnectUnregisterCloseCallback(dconn, libxlMigrationConnectionClosed); > + virObjectUnref(dconn); > + virObjectLock(vm); > + if (orig_err) { > + virSetError(orig_err); > + virFreeError(orig_err); > + } > + return ret; > +} Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list