[libvirt] [PATCH 0/3] Allow extra URI and target VM XML when migrating

This series takes advantage of the fact that we've not yet released the v3 migration protocol, to add support for some extra migration parameters.

This extends the v3 migration protocol such that the virDomainMigrateBegin3 and virDomainMigratePerform3 methods accept an application supplied XML config for the target VM. If the 'xmlin' parameter is NULL, then Begin3 uses the current guest XML as normal. A driver implementing the Begin3 method should either reject all non-NULL 'xmlin' parameters, or strictly validate that the app supplied XML does not change guest ABI. The Perform3 method also needed the xmlin parameter to cope with the Peer2Peer migration sequence. NB it is not yet possible to use this capability since neither of the public virDomainMigrate/virDomainMigrateToURI methods have a way to pass in XML. * daemon/remote.c, src/remote/remote_driver.c, src/remote/remote_protocol.x, src/remote_protocol-structs: Add 'remote_string xmlin' parameter to begin3/perform3 RPC messages * src/libvirt.c, src/driver.h, src/libvirt_internal.h: Add 'const char *xmlin' parameter to Begin3/Perform3 methods * src/qemu/qemu_driver.c, src/qemu/qemu_migration.c, src/qemu/qemu_migration.h: Pass xmlin parameter around migration methods --- .gnulib | 2 +- daemon/remote.c | 8 +++++- src/driver.h | 2 + src/libvirt.c | 49 ++++++++++++++++++++++++++++++----------- src/libvirt_internal.h | 2 + src/qemu/qemu_driver.c | 8 ++++-- src/qemu/qemu_migration.c | 17 ++++++++++++-- src/qemu/qemu_migration.h | 2 + src/remote/remote_driver.c | 4 +++ src/remote/remote_protocol.x | 2 + src/remote_protocol-structs | 2 + 11 files changed, 76 insertions(+), 22 deletions(-) diff --git a/.gnulib b/.gnulib index 2c25c9e..64a5e38 160000 --- a/.gnulib +++ b/.gnulib @@ -1 +1 @@ -Subproject commit 2c25c9ebe8db1415bfde25f0a451767332c8cf59 +Subproject commit 64a5e38bced6c8f5117efbed95cdfd8ca133ed54 diff --git a/daemon/remote.c b/daemon/remote.c index 42e1cb9..03f1a5e 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -3165,6 +3165,7 @@ remoteDispatchDomainMigrateBegin3(struct qemud_server *server ATTRIBUTE_UNUSED, char *xml = NULL; virDomainPtr dom = NULL; char *dname; + char *xmlin; char *cookieout = NULL; int cookieoutlen = 0; int rv = -1; @@ -3177,9 +3178,10 @@ remoteDispatchDomainMigrateBegin3(struct qemud_server *server ATTRIBUTE_UNUSED, if (!(dom = get_nonnull_domain(conn, args->dom))) goto cleanup; + xmlin = args->xmlin == NULL ? NULL : *args->xmlin; dname = args->dname == NULL ? NULL : *args->dname; - if (!(xml = virDomainMigrateBegin3(dom, + if (!(xml = virDomainMigrateBegin3(dom, xmlin, &cookieout, &cookieoutlen, args->flags, dname, args->resource))) goto cleanup; @@ -3325,6 +3327,7 @@ remoteDispatchDomainMigratePerform3(struct qemud_server *server ATTRIBUTE_UNUSED remote_domain_migrate_perform3_ret *ret) { virDomainPtr dom = NULL; + char *xmlin; char *dname; char *cookieout = NULL; int cookieoutlen = 0; @@ -3338,9 +3341,10 @@ remoteDispatchDomainMigratePerform3(struct qemud_server *server ATTRIBUTE_UNUSED if (!(dom = get_nonnull_domain(conn, args->dom))) goto cleanup; + xmlin = args->xmlin == NULL ? NULL : *args->xmlin; dname = args->dname == NULL ? NULL : *args->dname; - if (virDomainMigratePerform3(dom, + if (virDomainMigratePerform3(dom, xmlin, args->cookie_in.cookie_in_val, args->cookie_in.cookie_in_len, &cookieout, &cookieoutlen, diff --git a/src/driver.h b/src/driver.h index 450dd53..a1468e8 100644 --- a/src/driver.h +++ b/src/driver.h @@ -538,6 +538,7 @@ typedef int typedef char * (*virDrvDomainMigrateBegin3) (virDomainPtr domain, + const char *xmlin, char **cookieout, int *cookieoutlen, unsigned long flags, @@ -575,6 +576,7 @@ typedef int typedef int (*virDrvDomainMigratePerform3) (virDomainPtr dom, + const char *xmlin, const char *cookiein, int cookieinlen, char **cookieout, diff --git a/src/libvirt.c b/src/libvirt.c index ff16c48..7b7323e 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3719,6 +3719,7 @@ finish: static virDomainPtr virDomainMigrateVersion3(virDomainPtr domain, virConnectPtr dconn, + const char *xmlin, unsigned long flags, const char *dname, const char *uri, @@ -3748,8 +3749,8 @@ virDomainMigrateVersion3(virDomainPtr domain, VIR_DEBUG("Begin3 %p", domain->conn); dom_xml = domain->conn->driver->domainMigrateBegin3 - (domain, &cookieout, &cookieoutlen, flags, dname, - bandwidth); + (domain, xmlin, &cookieout, &cookieoutlen, + flags, dname, bandwidth); if (!dom_xml) goto done; @@ -3792,7 +3793,8 @@ virDomainMigrateVersion3(virDomainPtr domain, cookieout = NULL; cookieoutlen = 0; ret = domain->conn->driver->domainMigratePerform3 - (domain, cookiein, cookieinlen, &cookieout, &cookieoutlen, + (domain, NULL, cookiein, cookieinlen, + &cookieout, &cookieoutlen, uri, flags, dname, bandwidth); /* Perform failed. Make sure Finish doesn't overwrite the error */ @@ -3872,6 +3874,7 @@ finish: */ static int virDomainMigratePeer2Peer (virDomainPtr domain, + const char *xmlin, unsigned long flags, const char *dname, const char *uri, @@ -3907,6 +3910,7 @@ virDomainMigratePeer2Peer (virDomainPtr domain, VIR_DRV_FEATURE_MIGRATION_V3)) { VIR_DEBUG("Using migration protocol 3"); return domain->conn->driver->domainMigratePerform3(domain, + xmlin, NULL, /* cookiein */ 0, /* cookieinlen */ NULL, /* cookieoutlen */ @@ -3917,6 +3921,11 @@ virDomainMigratePeer2Peer (virDomainPtr domain, bandwidth); } else { VIR_DEBUG("Using migration protocol 2"); + if (xmlin) { + virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to change target guest XML during migration")); + return -1; + } return domain->conn->driver->domainMigratePerform(domain, NULL, /* cookie */ 0, /* cookielen */ @@ -3941,6 +3950,7 @@ virDomainMigratePeer2Peer (virDomainPtr domain, */ static int virDomainMigrateDirect (virDomainPtr domain, + const char *xmlin, unsigned long flags, const char *dname, const char *uri, @@ -3959,6 +3969,7 @@ virDomainMigrateDirect (virDomainPtr domain, VIR_DRV_FEATURE_MIGRATION_V3)) { VIR_DEBUG("Using migration protocol 3"); return domain->conn->driver->domainMigratePerform3(domain, + xmlin, NULL, /* cookiein */ 0, /* cookieinlen */ NULL, /* cookieoutlen */ @@ -3969,6 +3980,11 @@ virDomainMigrateDirect (virDomainPtr domain, bandwidth); } else { VIR_DEBUG("Using migration protocol 2"); + if (xmlin) { + virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to change target guest XML during migration")); + return -1; + } return domain->conn->driver->domainMigratePerform(domain, NULL, /* cookie */ 0, /* cookielen */ @@ -4093,7 +4109,8 @@ virDomainMigrate (virDomainPtr domain, } VIR_DEBUG("Using peer2peer migration"); - if (virDomainMigratePeer2Peer(domain, flags, dname, uri ? uri : dstURI, bandwidth) < 0) { + if (virDomainMigratePeer2Peer(domain, NULL, flags, dname, + uri ? uri : dstURI, bandwidth) < 0) { VIR_FREE(dstURI); goto error; } @@ -4118,7 +4135,7 @@ virDomainMigrate (virDomainPtr domain, VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, VIR_DRV_FEATURE_MIGRATION_V3)) { VIR_DEBUG("Using migration protocol 3"); - ddomain = virDomainMigrateVersion3(domain, dconn, flags, dname, uri, bandwidth); + ddomain = virDomainMigrateVersion3(domain, dconn, NULL, flags, dname, uri, bandwidth); } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn, VIR_DRV_FEATURE_MIGRATION_V2) && VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, @@ -4238,7 +4255,8 @@ virDomainMigrateToURI (virDomainPtr domain, if (VIR_DRV_SUPPORTS_FEATURE (domain->conn->driver, domain->conn, VIR_DRV_FEATURE_MIGRATION_P2P)) { VIR_DEBUG("Using peer2peer migration"); - if (virDomainMigratePeer2Peer (domain, flags, dname, duri, bandwidth) < 0) + if (virDomainMigratePeer2Peer(domain, NULL, flags, + dname, duri, bandwidth) < 0) goto error; } else { /* No peer to peer migration supported */ @@ -4249,7 +4267,8 @@ virDomainMigrateToURI (virDomainPtr domain, if (VIR_DRV_SUPPORTS_FEATURE (domain->conn->driver, domain->conn, VIR_DRV_FEATURE_MIGRATION_DIRECT)) { VIR_DEBUG("Using direct migration"); - if (virDomainMigrateDirect (domain, flags, dname, duri, bandwidth) < 0) + if (virDomainMigrateDirect(domain, NULL, flags, + dname, duri, bandwidth) < 0) goto error; } else { /* Cannot do a migration with only the perform step */ @@ -4567,6 +4586,7 @@ error: */ char * virDomainMigrateBegin3(virDomainPtr domain, + const char *xmlin, char **cookieout, int *cookieoutlen, unsigned long flags, @@ -4575,9 +4595,9 @@ virDomainMigrateBegin3(virDomainPtr domain, { virConnectPtr conn; - VIR_DOMAIN_DEBUG(domain, "cookieout=%p, cookieoutlen=%p, " + VIR_DOMAIN_DEBUG(domain, "xmlin=%s cookieout=%p, cookieoutlen=%p, " "flags=%lu, dname=%s, bandwidth=%lu", - cookieout, cookieoutlen, flags, + NULLSTR(xmlin), cookieout, cookieoutlen, flags, NULLSTR(dname), bandwidth); virResetLastError(); @@ -4596,7 +4616,7 @@ virDomainMigrateBegin3(virDomainPtr domain, if (conn->driver->domainMigrateBegin3) { char *xml; - xml = conn->driver->domainMigrateBegin3(domain, + xml = conn->driver->domainMigrateBegin3(domain, xmlin, cookieout, cookieoutlen, flags, dname, bandwidth); VIR_DEBUG("xml %s", NULLSTR(xml)); @@ -4733,6 +4753,7 @@ error: */ int virDomainMigratePerform3(virDomainPtr domain, + const char *xmlin, const char *cookiein, int cookieinlen, char **cookieout, @@ -4744,9 +4765,11 @@ virDomainMigratePerform3(virDomainPtr domain, { virConnectPtr conn; - VIR_DOMAIN_DEBUG(domain, "cookiein=%p, cookieinlen=%d, cookieout=%p, cookieoutlen=%p," + VIR_DOMAIN_DEBUG(domain, "xmlin=%s cookiein=%p, cookieinlen=%d, " + "cookieout=%p, cookieoutlen=%p, " "uri=%s, flags=%lu, dname=%s, bandwidth=%lu", - cookiein, cookieinlen, cookieout, cookieoutlen, + NULLSTR(xmlin), cookiein, cookieinlen, + cookieout, cookieoutlen, uri, flags, NULLSTR(dname), bandwidth); virResetLastError(); @@ -4765,7 +4788,7 @@ virDomainMigratePerform3(virDomainPtr domain, if (conn->driver->domainMigratePerform3) { int ret; - ret = conn->driver->domainMigratePerform3(domain, + ret = conn->driver->domainMigratePerform3(domain, xmlin, cookiein, cookieinlen, cookieout, cookieoutlen, uri, diff --git a/src/libvirt_internal.h b/src/libvirt_internal.h index 81d0c56..c7c1932 100644 --- a/src/libvirt_internal.h +++ b/src/libvirt_internal.h @@ -124,6 +124,7 @@ int virDomainMigratePrepareTunnel(virConnectPtr dconn, char *virDomainMigrateBegin3(virDomainPtr domain, + const char *xmlin, char **cookieout, int *cookieoutlen, unsigned long flags, @@ -155,6 +156,7 @@ int virDomainMigratePrepareTunnel3(virConnectPtr dconn, int virDomainMigratePerform3(virDomainPtr dom, + const char *xmlin, const char *cookiein, int cookieinlen, char **cookieout, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 44acc6a..2f454f7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5961,7 +5961,7 @@ qemudDomainMigratePerform (virDomainPtr dom, * Consume any cookie we were able to decode though */ ret = qemuMigrationPerform(driver, dom->conn, vm, - uri, cookie, cookielen, + NULL, uri, cookie, cookielen, NULL, NULL, /* No output cookies in v2 */ flags, dname, resource, true); @@ -6030,6 +6030,7 @@ cleanup: static char * qemuDomainMigrateBegin3(virDomainPtr domain, + const char *xmlin, char **cookieout, int *cookieoutlen, unsigned long flags, @@ -6059,7 +6060,7 @@ qemuDomainMigrateBegin3(virDomainPtr domain, goto cleanup; } - xml = qemuMigrationBegin(driver, vm, + xml = qemuMigrationBegin(driver, vm, xmlin, cookieout, cookieoutlen); cleanup: @@ -6176,6 +6177,7 @@ cleanup: static int qemuDomainMigratePerform3(virDomainPtr dom, + const char *xmlin, const char *cookiein, int cookieinlen, char **cookieout, @@ -6208,7 +6210,7 @@ qemuDomainMigratePerform3(virDomainPtr dom, goto cleanup; } - ret = qemuMigrationPerform(driver, dom->conn, vm, + ret = qemuMigrationPerform(driver, dom->conn, vm, xmlin, uri, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, false); diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 4d7bc38..077a1b1 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -809,12 +809,19 @@ qemuDomainMigrateGraphicsRelocate(struct qemud_driver *driver, char *qemuMigrationBegin(struct qemud_driver *driver, virDomainObjPtr vm, + const char *xmlin, char **cookieout, int *cookieoutlen) { char *rv = NULL; qemuMigrationCookiePtr mig = NULL; + if (xmlin) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Passing XML for the target VM is not yet supported")); + goto cleanup; + } + if (!virDomainObjIsActive(vm)) { qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", _("domain is not running")); @@ -1725,6 +1732,7 @@ static int doPeer2PeerMigrate3(struct qemud_driver *driver, virConnectPtr sconn, virConnectPtr dconn, virDomainObjPtr vm, + const char *xmlin, const char *uri, unsigned long flags, const char *dname, @@ -1743,7 +1751,7 @@ static int doPeer2PeerMigrate3(struct qemud_driver *driver, virStreamPtr st = NULL; VIR_DEBUG("Begin3 %p", sconn); - dom_xml = qemuMigrationBegin(driver, vm, + dom_xml = qemuMigrationBegin(driver, vm, xmlin, &cookieout, &cookieoutlen); if (!dom_xml) goto cleanup; @@ -1889,6 +1897,7 @@ finish: static int doPeer2PeerMigrate(struct qemud_driver *driver, virConnectPtr sconn, virDomainObjPtr vm, + const char *xmlin, const char *uri, unsigned long flags, const char *dname, @@ -1933,7 +1942,7 @@ static int doPeer2PeerMigrate(struct qemud_driver *driver, } if (v3) - ret = doPeer2PeerMigrate3(driver, sconn, dconn, vm, + ret = doPeer2PeerMigrate3(driver, sconn, dconn, vm, xmlin, uri, flags, dname, resource); else ret = doPeer2PeerMigrate2(driver, sconn, dconn, vm, @@ -1952,6 +1961,7 @@ cleanup: int qemuMigrationPerform(struct qemud_driver *driver, virConnectPtr conn, virDomainObjPtr vm, + const char *xmlin, const char *uri, const char *cookiein, int cookieinlen, @@ -1994,7 +2004,8 @@ int qemuMigrationPerform(struct qemud_driver *driver, goto endjob; } - if (doPeer2PeerMigrate(driver, conn, vm, uri, flags, dname, resource) < 0) + if (doPeer2PeerMigrate(driver, conn, vm, xmlin, + uri, flags, dname, resource) < 0) /* doPeer2PeerMigrate already set the error, so just get out */ goto endjob; } else { diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index f96a0b8..a24b3a8 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -34,6 +34,7 @@ int qemuMigrationWaitForCompletion(struct qemud_driver *driver, virDomainObjPtr char *qemuMigrationBegin(struct qemud_driver *driver, virDomainObjPtr vm, + const char *xmlin, char **cookieout, int *cookieoutlen); @@ -61,6 +62,7 @@ int qemuMigrationPrepareDirect(struct qemud_driver *driver, int qemuMigrationPerform(struct qemud_driver *driver, virConnectPtr conn, virDomainObjPtr vm, + const char *xmlin, const char *uri, const char *cookiein, int cookieinlen, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 8c69743..77bd474 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -4982,6 +4982,7 @@ done: static char * remoteDomainMigrateBegin3(virDomainPtr domain, + const char *xmlin, char **cookieout, int *cookieoutlen, unsigned long flags, @@ -4999,6 +5000,7 @@ remoteDomainMigrateBegin3(virDomainPtr domain, memset(&ret, 0, sizeof(ret)); make_nonnull_domain (&args.dom, domain); + args.xmlin = xmlin == NULL ? NULL : (char **) &xmlin; args.flags = flags; args.dname = dname == NULL ? NULL : (char **) &dname; args.resource = resource; @@ -5167,6 +5169,7 @@ error: static int remoteDomainMigratePerform3(virDomainPtr dom, + const char *xmlin, const char *cookiein, int cookieinlen, char **cookieout, @@ -5188,6 +5191,7 @@ remoteDomainMigratePerform3(virDomainPtr dom, make_nonnull_domain(&args.dom, dom); + args.xmlin = xmlin == NULL ? NULL : (char **) &xmlin; args.cookie_in.cookie_in_val = (char *)cookiein; args.cookie_in.cookie_in_len = cookieinlen; args.uri = (char *) uri; diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 5932b2c..37b5a3f 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1973,6 +1973,7 @@ struct remote_domain_get_state_ret { struct remote_domain_migrate_begin3_args { remote_nonnull_domain dom; + remote_string xmlin; unsigned hyper flags; remote_string dname; unsigned hyper resource; @@ -2011,6 +2012,7 @@ struct remote_domain_migrate_prepare_tunnel3_ret { struct remote_domain_migrate_perform3_args { remote_nonnull_domain dom; + remote_string xmlin; opaque cookie_in<REMOTE_MIGRATE_COOKIE_MAX>; remote_nonnull_string uri; unsigned hyper flags; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 5b43cb4..616a44b 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1457,6 +1457,7 @@ struct remote_domain_get_state_ret { }; struct remote_domain_migrate_begin3_args { remote_nonnull_domain dom; + remote_string xmlin; uint64_t flags; remote_string dname; uint64_t resource; @@ -1504,6 +1505,7 @@ struct remote_domain_migrate_prepare_tunnel3_ret { }; struct remote_domain_migrate_perform3_args { remote_nonnull_domain dom; + remote_string xmlin; struct { u_int cookie_in_len; char * cookie_in_val; -- 1.7.4.4

The virDomainMigratePerform3 currently has a single URI parameter whose meaning varies. It is either - A QEMU migration URI (normal migration) - A libvirtd connection URI (peer2peer migration) Unfortunately when using peer2peer migration, without also using tunnelled migration, it is possible that both URIs are required. This adds a second URI parameter to the virDomainMigratePerform3 method, to cope with this scenario. Each parameter how has a fixed meaning. NB, there is no way to actually take advantage of this yet, since virDomainMigrate/virDomainMigrateToURI do not have any way to provide the 2 separate URIs * daemon/remote.c, src/remote/remote_driver.c, src/remote/remote_protocol.x, src/remote_protocol-structs: Add the second URI parameter to perform3 message * src/driver.h, src/libvirt.c, src/libvirt_internal.h: Add the second URI parameter to Perform3 method * src/libvirt_internal.h, src/qemu/qemu_migration.c, src/qemu/qemu_migration.h: Update to handle URIs correctly --- daemon/remote.c | 4 +++- src/driver.h | 1 + src/libvirt.c | 26 +++++++++++++++++++------- src/libvirt_internal.h | 3 ++- src/qemu/qemu_driver.c | 5 +++-- src/qemu/qemu_migration.c | 15 +++++++++++---- src/qemu/qemu_migration.h | 1 + src/remote/remote_driver.c | 2 ++ src/remote/remote_protocol.x | 1 + src/remote_protocol-structs | 1 + 10 files changed, 44 insertions(+), 15 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 03f1a5e..270ca30 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -3329,6 +3329,7 @@ remoteDispatchDomainMigratePerform3(struct qemud_server *server ATTRIBUTE_UNUSED virDomainPtr dom = NULL; char *xmlin; char *dname; + char *dconnuri; char *cookieout = NULL; int cookieoutlen = 0; int rv = -1; @@ -3343,12 +3344,13 @@ remoteDispatchDomainMigratePerform3(struct qemud_server *server ATTRIBUTE_UNUSED xmlin = args->xmlin == NULL ? NULL : *args->xmlin; dname = args->dname == NULL ? NULL : *args->dname; + dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri; if (virDomainMigratePerform3(dom, xmlin, args->cookie_in.cookie_in_val, args->cookie_in.cookie_in_len, &cookieout, &cookieoutlen, - args->uri, + dconnuri, args->uri, args->flags, dname, args->resource) < 0) goto cleanup; diff --git a/src/driver.h b/src/driver.h index a1468e8..035e42d 100644 --- a/src/driver.h +++ b/src/driver.h @@ -581,6 +581,7 @@ typedef int int cookieinlen, char **cookieout, int *cookieoutlen, + const char *dconnuri, const char *uri, unsigned long flags, const char *dname, diff --git a/src/libvirt.c b/src/libvirt.c index 7b7323e..c85f7bf 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3792,9 +3792,10 @@ virDomainMigrateVersion3(virDomainPtr domain, cookieinlen = cookieoutlen; cookieout = NULL; cookieoutlen = 0; + /* dconnuri not relevant in non-P2P modes, so left NULL here */ ret = domain->conn->driver->domainMigratePerform3 (domain, NULL, cookiein, cookieinlen, - &cookieout, &cookieoutlen, + &cookieout, &cookieoutlen, NULL, uri, flags, dname, bandwidth); /* Perform failed. Make sure Finish doesn't overwrite the error */ @@ -3877,6 +3878,7 @@ virDomainMigratePeer2Peer (virDomainPtr domain, const char *xmlin, unsigned long flags, const char *dname, + const char *dconnuri, const char *uri, unsigned long bandwidth) { @@ -3915,6 +3917,7 @@ virDomainMigratePeer2Peer (virDomainPtr domain, 0, /* cookieinlen */ NULL, /* cookieoutlen */ NULL, /* cookieoutlen */ + dconnuri, uri, flags, dname, @@ -3926,10 +3929,15 @@ virDomainMigratePeer2Peer (virDomainPtr domain, _("Unable to change target guest XML during migration")); return -1; } + if (uri) { + virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to override peer2peer migration URI")); + return -1; + } return domain->conn->driver->domainMigratePerform(domain, NULL, /* cookie */ 0, /* cookielen */ - uri, + dconnuri, flags, dname, bandwidth); @@ -3968,12 +3976,15 @@ virDomainMigrateDirect (virDomainPtr domain, if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn, VIR_DRV_FEATURE_MIGRATION_V3)) { VIR_DEBUG("Using migration protocol 3"); + /* dconn URI not relevant in direct migration, since no + * target libvirtd is involved */ return domain->conn->driver->domainMigratePerform3(domain, xmlin, NULL, /* cookiein */ 0, /* cookieinlen */ NULL, /* cookieoutlen */ NULL, /* cookieoutlen */ + NULL, /* dconnuri */ uri, flags, dname, @@ -4110,7 +4121,7 @@ virDomainMigrate (virDomainPtr domain, VIR_DEBUG("Using peer2peer migration"); if (virDomainMigratePeer2Peer(domain, NULL, flags, dname, - uri ? uri : dstURI, bandwidth) < 0) { + uri ? uri : dstURI, NULL, bandwidth) < 0) { VIR_FREE(dstURI); goto error; } @@ -4256,7 +4267,7 @@ virDomainMigrateToURI (virDomainPtr domain, VIR_DRV_FEATURE_MIGRATION_P2P)) { VIR_DEBUG("Using peer2peer migration"); if (virDomainMigratePeer2Peer(domain, NULL, flags, - dname, duri, bandwidth) < 0) + dname, duri, NULL, bandwidth) < 0) goto error; } else { /* No peer to peer migration supported */ @@ -4758,6 +4769,7 @@ virDomainMigratePerform3(virDomainPtr domain, int cookieinlen, char **cookieout, int *cookieoutlen, + const char *dconnuri, const char *uri, unsigned long flags, const char *dname, @@ -4766,10 +4778,10 @@ virDomainMigratePerform3(virDomainPtr domain, virConnectPtr conn; VIR_DOMAIN_DEBUG(domain, "xmlin=%s cookiein=%p, cookieinlen=%d, " - "cookieout=%p, cookieoutlen=%p, " + "cookieout=%p, cookieoutlen=%p, dconnuri=%s, " "uri=%s, flags=%lu, dname=%s, bandwidth=%lu", NULLSTR(xmlin), cookiein, cookieinlen, - cookieout, cookieoutlen, + cookieout, cookieoutlen, NULLSTR(dconnuri), uri, flags, NULLSTR(dname), bandwidth); virResetLastError(); @@ -4791,7 +4803,7 @@ virDomainMigratePerform3(virDomainPtr domain, ret = conn->driver->domainMigratePerform3(domain, xmlin, cookiein, cookieinlen, cookieout, cookieoutlen, - uri, + dconnuri, uri, flags, dname, bandwidth); if (ret < 0) goto error; diff --git a/src/libvirt_internal.h b/src/libvirt_internal.h index c7c1932..68c140b 100644 --- a/src/libvirt_internal.h +++ b/src/libvirt_internal.h @@ -161,7 +161,8 @@ int virDomainMigratePerform3(virDomainPtr dom, int cookieinlen, char **cookieout, int *cookieoutlen, - const char *uri, + const char *dconnuri, /* libvirtd URI if Peer2Peer, NULL otherwise */ + const char *uri, /* VM Migration URI */ unsigned long flags, const char *dname, unsigned long resource); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2f454f7..f836d79 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5961,7 +5961,7 @@ qemudDomainMigratePerform (virDomainPtr dom, * Consume any cookie we were able to decode though */ ret = qemuMigrationPerform(driver, dom->conn, vm, - NULL, uri, cookie, cookielen, + NULL, NULL, uri, cookie, cookielen, NULL, NULL, /* No output cookies in v2 */ flags, dname, resource, true); @@ -6182,6 +6182,7 @@ qemuDomainMigratePerform3(virDomainPtr dom, int cookieinlen, char **cookieout, int *cookieoutlen, + const char *dconnuri, const char *uri, unsigned long flags, const char *dname, @@ -6211,7 +6212,7 @@ qemuDomainMigratePerform3(virDomainPtr dom, } ret = qemuMigrationPerform(driver, dom->conn, vm, xmlin, - uri, cookiein, cookieinlen, + dconnuri, uri, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, false); diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 077a1b1..7817f37 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1778,7 +1778,7 @@ static int doPeer2PeerMigrate3(struct qemud_driver *driver, qemuDomainObjEnterRemoteWithDriver(driver, vm); ret = dconn->driver->domainMigratePrepare3 (dconn, cookiein, cookieinlen, &cookieout, &cookieoutlen, - NULL, &uri_out, flags, dname, resource, dom_xml); + uri, &uri_out, flags, dname, resource, dom_xml); qemuDomainObjExitRemoteWithDriver(driver, vm); } VIR_FREE(dom_xml); @@ -1798,7 +1798,7 @@ static int doPeer2PeerMigrate3(struct qemud_driver *driver, * running, but in paused state until the destination can * confirm migration completion. */ - VIR_DEBUG("Perform3 %p uri=%s", sconn, uri_out); + VIR_DEBUG("Perform3 %p uri=%s uri_out=%s", sconn, uri, uri_out); VIR_FREE(cookiein); cookiein = cookieout; cookieinlen = cookieoutlen; @@ -1898,6 +1898,7 @@ static int doPeer2PeerMigrate(struct qemud_driver *driver, virConnectPtr sconn, virDomainObjPtr vm, const char *xmlin, + const char *dconnuri, const char *uri, unsigned long flags, const char *dname, @@ -1913,7 +1914,7 @@ static int doPeer2PeerMigrate(struct qemud_driver *driver, */ qemuDomainObjEnterRemoteWithDriver(driver, vm); - dconn = virConnectOpen(uri); + dconn = virConnectOpen(dconnuri); qemuDomainObjExitRemoteWithDriver(driver, vm); if (dconn == NULL) { qemuReportError(VIR_ERR_OPERATION_FAILED, @@ -1962,6 +1963,7 @@ int qemuMigrationPerform(struct qemud_driver *driver, virConnectPtr conn, virDomainObjPtr vm, const char *xmlin, + const char *dconnuri, const char *uri, const char *cookiein, int cookieinlen, @@ -2005,10 +2007,15 @@ int qemuMigrationPerform(struct qemud_driver *driver, } if (doPeer2PeerMigrate(driver, conn, vm, xmlin, - uri, flags, dname, resource) < 0) + dconnuri, uri, flags, dname, resource) < 0) /* doPeer2PeerMigrate already set the error, so just get out */ goto endjob; } else { + if (dconnuri) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Unexpected dconnuri parameter with non-peer2peer migration")); + goto endjob; + } if (doNativeMigrate(driver, vm, uri, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource) < 0) diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index a24b3a8..a350579 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -63,6 +63,7 @@ int qemuMigrationPerform(struct qemud_driver *driver, virConnectPtr conn, virDomainObjPtr vm, const char *xmlin, + const char *dconnuri, const char *uri, const char *cookiein, int cookieinlen, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 77bd474..668edfe 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -5174,6 +5174,7 @@ remoteDomainMigratePerform3(virDomainPtr dom, int cookieinlen, char **cookieout, int *cookieoutlen, + const char *dconnuri, const char *uri, unsigned long flags, const char *dname, @@ -5197,6 +5198,7 @@ remoteDomainMigratePerform3(virDomainPtr dom, args.uri = (char *) uri; args.flags = flags; args.dname = dname == NULL ? NULL : (char **) &dname; + args.dconnuri = dconnuri == NULL ? NULL : (char **) &dconnuri; args.resource = resource; if (call (dom->conn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3, diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 37b5a3f..214a052 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2014,6 +2014,7 @@ struct remote_domain_migrate_perform3_args { remote_nonnull_domain dom; remote_string xmlin; opaque cookie_in<REMOTE_MIGRATE_COOKIE_MAX>; + remote_string dconnuri; remote_nonnull_string uri; unsigned hyper flags; remote_string dname; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 616a44b..7285006 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1510,6 +1510,7 @@ struct remote_domain_migrate_perform3_args { u_int cookie_in_len; char * cookie_in_val; } cookie_in; + remote_string dconnuri; remote_nonnull_string uri; uint64_t flags; remote_string dname; -- 1.7.4.4

There are two pieces of information which are desirable for migration, which cannot be supplied by applications - The explicit QEMU migration URI, while using Peer2Peer migration - An override for the target VM XML This introduces two new public APIs to support these extra parameters. There is no need for extra wire protocool changes, since this is supported by the v3 migration enhancements * include/libvirt/libvirt.h.in, src/libvirt.c, src/libvirt_public.syms: Add virDomainMigrate2 and virDomainMigrateToURI2 --- include/libvirt/libvirt.h.in | 12 ++ src/libvirt.c | 321 +++++++++++++++++++++++++++++++++++++++++- src/libvirt_public.syms | 2 + 3 files changed, 332 insertions(+), 3 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 7cd6e13..a3c771a 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -532,11 +532,23 @@ typedef enum { virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, unsigned long flags, const char *dname, const char *uri, unsigned long bandwidth); +virDomainPtr virDomainMigrate2(virDomainPtr domain, virConnectPtr dconn, + const char *dxml, + unsigned long flags, const char *dname, + const char *uri, unsigned long bandwidth); int virDomainMigrateToURI (virDomainPtr domain, const char *duri, unsigned long flags, const char *dname, unsigned long bandwidth); +int virDomainMigrateToURI2(virDomainPtr domain, + const char *dconnuri, + const char *miguri, + const char *dxml, + unsigned long flags, + const char *dname, + unsigned long bandwidth); + int virDomainMigrateSetMaxDowntime (virDomainPtr domain, unsigned long long downtime, unsigned int flags); diff --git a/src/libvirt.c b/src/libvirt.c index c85f7bf..4eb854e 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -4146,19 +4146,204 @@ virDomainMigrate (virDomainPtr domain, VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, VIR_DRV_FEATURE_MIGRATION_V3)) { VIR_DEBUG("Using migration protocol 3"); - ddomain = virDomainMigrateVersion3(domain, dconn, NULL, flags, dname, uri, bandwidth); + ddomain = virDomainMigrateVersion3(domain, dconn, NULL, + flags, dname, uri, bandwidth); } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn, VIR_DRV_FEATURE_MIGRATION_V2) && VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, VIR_DRV_FEATURE_MIGRATION_V2)) { VIR_DEBUG("Using migration protocol 2"); - ddomain = virDomainMigrateVersion2(domain, dconn, flags, dname, uri, bandwidth); + ddomain = virDomainMigrateVersion2(domain, dconn, flags, + dname, uri, bandwidth); } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn, VIR_DRV_FEATURE_MIGRATION_V1) && VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, VIR_DRV_FEATURE_MIGRATION_V1)) { VIR_DEBUG("Using migration protocol 1"); - ddomain = virDomainMigrateVersion1(domain, dconn, flags, dname, uri, bandwidth); + ddomain = virDomainMigrateVersion1(domain, dconn, flags, + dname, uri, bandwidth); + } else { + /* This driver does not support any migration method */ + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + goto error; + } + } + + if (ddomain == NULL) + goto error; + + return ddomain; + +error: + virDispatchError(domain->conn); + return NULL; +} + + +/** + * virDomainMigrate2: + * @domain: a domain object + * @dconn: destination host (a connection object) + * @flags: flags + * @dxml: optional XML config for launching guest on target + * @dname: (optional) rename domain to this at destination + * @uri: (optional) dest hostname/URI as seen from the source host + * @bandwidth: (optional) specify migration bandwidth limit in Mbps + * + * Migrate the domain object from its current host to the destination + * host given by dconn (a connection to the destination host). + * + * Flags may be one of more of the following: + * VIR_MIGRATE_LIVE Do not pause the VM during migration + * VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts + * VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel + * VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain + * on the destination host. + * VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the + * domain on the source host. + * VIR_MIGRATE_PAUSED Leave the domain suspended on the remote side. + * + * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set. + * Applications using the VIR_MIGRATE_PEER2PEER flag will probably + * prefer to invoke virDomainMigrateToURI, avoiding the need to + * open connection to the destination host themselves. + * + * If a hypervisor supports renaming domains during migration, + * then you may set the dname parameter to the new name (otherwise + * it keeps the same name). If this is not supported by the + * hypervisor, dname must be NULL or else you will get an error. + * + * If the VIR_MIGRATE_PEER2PEER flag is set, the uri parameter + * must be a valid libvirt connection URI, by which the source + * libvirt driver can connect to the destination libvirt. If + * omitted, the dconn connection object will be queried for its + * current URI. + * + * If the VIR_MIGRATE_PEER2PEER flag is NOT set, the URI parameter + * takes a hypervisor specific format. The hypervisor capabilities + * XML includes details of the support URI schemes. If omitted + * the dconn will be asked for a default URI. + * + * In either case it is typically only necessary to specify a + * URI if the destination host has multiple interfaces and a + * specific interface is required to transmit migration data. + * + * The maximum bandwidth (in Mbps) that will be used to do migration + * can be specified with the bandwidth parameter. If set to 0, + * libvirt will choose a suitable default. Some hypervisors do + * not support this feature and will return an error if bandwidth + * is not 0. + * + * To see which features are supported by the current hypervisor, + * see virConnectGetCapabilities, /capabilities/host/migration_features. + * + * There are many limitations on migration imposed by the underlying + * technology - for example it may not be possible to migrate between + * different processors even with the same architecture, or between + * different types of hypervisor. + * + * Returns the new domain object if the migration was successful, + * or NULL in case of error. Note that the new domain object + * exists in the scope of the destination connection (dconn). + */ +virDomainPtr +virDomainMigrate2(virDomainPtr domain, + virConnectPtr dconn, + const char *dxml, + unsigned long flags, + const char *dname, + const char *uri, + unsigned long bandwidth) +{ + virDomainPtr ddomain = NULL; + + VIR_DOMAIN_DEBUG(domain, "dconn=%p, flags=%lu, dname=%s, uri=%s, bandwidth=%lu", + dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth); + + virResetLastError(); + + /* First checkout the source */ + if (!VIR_IS_CONNECTED_DOMAIN (domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return NULL; + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + /* Now checkout the destination */ + if (!VIR_IS_CONNECT(dconn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + goto error; + } + if (dconn->flags & VIR_CONNECT_RO) { + /* NB, deliberately report error against source object, not dest */ + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if (flags & VIR_MIGRATE_PEER2PEER) { + if (VIR_DRV_SUPPORTS_FEATURE (domain->conn->driver, domain->conn, + VIR_DRV_FEATURE_MIGRATION_P2P)) { + char *dstURI = virConnectGetURI(dconn); + if (!dstURI) + return NULL; + + VIR_DEBUG("Using peer2peer migration"); + if (virDomainMigratePeer2Peer(domain, dxml, flags, dname, + dstURI, uri, bandwidth) < 0) { + VIR_FREE(dstURI); + goto error; + } + VIR_FREE(dstURI); + + ddomain = virDomainLookupByName (dconn, dname ? dname : domain->name); + } else { + /* This driver does not support peer to peer migration */ + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + goto error; + } + } else { + if (flags & VIR_MIGRATE_TUNNELLED) { + virLibConnError(VIR_ERR_OPERATION_INVALID, + _("cannot perform tunnelled migration without using peer2peer flag")); + goto error; + } + + /* Check that migration is supported by both drivers. */ + if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn, + VIR_DRV_FEATURE_MIGRATION_V3) && + VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, + VIR_DRV_FEATURE_MIGRATION_V3)) { + VIR_DEBUG("Using migration protocol 3"); + ddomain = virDomainMigrateVersion3(domain, dconn, dxml, + flags, dname, uri, bandwidth); + } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn, + VIR_DRV_FEATURE_MIGRATION_V2) && + VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, + VIR_DRV_FEATURE_MIGRATION_V2)) { + VIR_DEBUG("Using migration protocol 2"); + if (dxml) { + virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to change target guest XML during migration")); + goto error; + } + ddomain = virDomainMigrateVersion2(domain, dconn, flags, + dname, uri, bandwidth); + } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn, + VIR_DRV_FEATURE_MIGRATION_V1) && + VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, + VIR_DRV_FEATURE_MIGRATION_V1)) { + VIR_DEBUG("Using migration protocol 1"); + if (dxml) { + virLibConnError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to change target guest XML during migration")); + goto error; + } + ddomain = virDomainMigrateVersion1(domain, dconn, flags, + dname, uri, bandwidth); } else { /* This driver does not support any migration method */ virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); @@ -4296,6 +4481,136 @@ error: } +/** + * virDomainMigrateToURI2: + * @domain: a domain object + * @dconnuri: optional URI for target libvirtd if @flags includes VIR_MIGRATE_PEER2PEER + * @miguri: optional URI for invoking the migration, not if @flags includs VIR_MIGRATE_TUNNELLED + * @dxml: optional XML config for launching guest on target + * @flags: flags + * @dname: (optional) rename domain to this at destination + * @bandwidth: (optional) specify migration bandwidth limit in Mbps + * + * Migrate the domain object from its current host to the destination + * host given by duri. + * + * Flags may be one of more of the following: + * VIR_MIGRATE_LIVE Do not pause the VM during migration + * VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts + * VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel + * VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain + * on the destination host. + * VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the + * domain on the source host. + * + * The operation of this API hinges on the VIR_MIGRATE_PEER2PEER flag. + * + * If the VIR_MIGRATE_PEER2PEER flag is set, the @dconnuri parameter + * must be a valid libvirt connection URI, by which the source + * libvirt driver can connect to the destination libvirt. If the + * VIR_MIGRATE_PEER2PEER flag is NOT set, then @dconnuri must be + * NULL. + * + * If the VIR_MIGRATE_TUNNELLED flag is NOT set, then the @miguri + * parameter allows specification of a URI to use to initiate the + * VM migration. It takes a hypervisor specific format. The uri_transports + * element of the hypervisor capabilities XML includes details of the + * supported URI schemes. + * + * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set. + * + * If a hypervisor supports changing the configuration of the guest + * during migration, the @dxml parameter specifies the new config + * for the guest. The configuration must include an identical set + * of virtual devices, to ensure a stable guest ABI across migration. + * Only parameters related to host side configuration can be + * changed in the XML. Hypervisors will validate this and refuse to + * allow migration if the provided XML would cause a change in the + * guest ABI, + * + * If a hypervisor supports renaming domains during migration, + * the dname parameter specifies the new name for the domain. + * Setting dname to NULL keeps the domain name the same. If domain + * renaming is not supported by the hypervisor, dname must be NULL or + * else an error will be returned. + * + * The maximum bandwidth (in Mbps) that will be used to do migration + * can be specified with the bandwidth parameter. If set to 0, + * libvirt will choose a suitable default. Some hypervisors do + * not support this feature and will return an error if bandwidth + * is not 0. + * + * To see which features are supported by the current hypervisor, + * see virConnectGetCapabilities, /capabilities/host/migration_features. + * + * There are many limitations on migration imposed by the underlying + * technology - for example it may not be possible to migrate between + * different processors even with the same architecture, or between + * different types of hypervisor. + * + * Returns 0 if the migration succeeded, -1 upon error. + */ +int +virDomainMigrateToURI2(virDomainPtr domain, + const char *dconnuri, + const char *miguri, + const char *dxml, + unsigned long flags, + const char *dname, + unsigned long bandwidth) +{ + VIR_DOMAIN_DEBUG(domain, "dconnuri=%s, miguri=%s, dxml=%s, " + "flags=%lu, dname=%s, bandwidth=%lu", + NULLSTR(dconnuri), NULLSTR(miguri), NULLSTR(dxml), + flags, NULLSTR(dname), bandwidth); + + virResetLastError(); + + /* First checkout the source */ + if (!VIR_IS_CONNECTED_DOMAIN (domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if (flags & VIR_MIGRATE_PEER2PEER) { + if (VIR_DRV_SUPPORTS_FEATURE (domain->conn->driver, domain->conn, + VIR_DRV_FEATURE_MIGRATION_P2P)) { + VIR_DEBUG("Using peer2peer migration"); + if (virDomainMigratePeer2Peer(domain, dxml, flags, + dname, dconnuri, miguri, bandwidth) < 0) + goto error; + } else { + /* No peer to peer migration supported */ + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + goto error; + } + } else { + if (VIR_DRV_SUPPORTS_FEATURE (domain->conn->driver, domain->conn, + VIR_DRV_FEATURE_MIGRATION_DIRECT)) { + VIR_DEBUG("Using direct migration"); + if (virDomainMigrateDirect(domain, dxml, flags, + dname, miguri, bandwidth) < 0) + goto error; + } else { + /* Cannot do a migration with only the perform step */ + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + goto error; + } + } + + return 0; + +error: + virDispatchError(domain->conn); + return -1; +} + + /* * Not for public use. This function is part of the internal * implementation of migration in the remote case. diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 0590535..cd23f69 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -442,6 +442,8 @@ LIBVIRT_0.9.2 { virDomainInjectNMI; virDomainScreenshot; virDomainSetSchedulerParametersFlags; + virDomainMigrate2; + virDomainMigrateToURI2; } LIBVIRT_0.9.0; # .... define new API here using predicted next version number .... -- 1.7.4.4

On Wed, May 18, 2011 at 01:23:22PM -0400, Daniel P. Berrange wrote:
This series takes advantage of the fact that we've not yet released the v3 migration protocol, to add support for some extra migration parameters.
Looked at the patches, looks fine, I didn't spot anything. ACK It's fairly important to push this before the freeze, so if you don't push this by sunday, I will do this. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (2)
-
Daniel P. Berrange
-
Daniel Veillard