diff --git a/docs/libvirt-api.xml b/docs/libvirt-api.xml index 88dc246f60..a32c3976bc 100644 --- a/docs/libvirt-api.xml +++ b/docs/libvirt-api.xml @@ -47,6 +47,7 @@ + @@ -82,7 +83,7 @@ - + @@ -718,7 +719,8 @@ - + + @@ -1596,6 +1598,8 @@ host given by dconn (a connection to the destination host). Flags may be one of more of the following: VIR_MIGRATE_LIVE Attempt a live migration. + VIR_MIGRATE_TUNNELLED Attempt to do a migration tunnelled through the + libvirt RPC mechanism If a hypervisor supports renaming domains during migration, then you may set the dname parameter to the new name (otherwise diff --git a/docs/libvirt-refs.xml b/docs/libvirt-refs.xml index 08034e4b3b..0352e77354 100644 --- a/docs/libvirt-refs.xml +++ b/docs/libvirt-refs.xml @@ -154,6 +154,7 @@ + @@ -659,6 +660,7 @@ + @@ -1596,6 +1598,7 @@ + @@ -2654,6 +2657,9 @@ + + + @@ -2912,6 +2918,9 @@ + + + @@ -5604,6 +5613,9 @@ + + + @@ -7381,6 +7393,9 @@ + + + @@ -7443,6 +7458,9 @@ + + + diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ce37eb6339..81b1aa2360 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6470,7 +6470,9 @@ cleanup: static int doTunnelMigrate(virDomainPtr dom, + virConnectPtr dconn, virDomainObjPtr vm, + const char *dom_xml, const char *uri, unsigned long flags, const char *dname, @@ -6480,13 +6482,11 @@ static int doTunnelMigrate(virDomainPtr dom, int client_sock, qemu_sock; struct sockaddr_un sa_qemu, sa_client; socklen_t addrlen; - virConnectPtr dconn; virDomainPtr ddomain; int retval = -1; ssize_t bytes; char buffer[65536]; virStreamPtr st; - char *dom_xml = NULL; char *unixfile = NULL; int internalret; unsigned int qemuCmdFlags; @@ -6497,35 +6497,15 @@ static int doTunnelMigrate(virDomainPtr dom, * destination side is completely setup before we touch the source */ - dconn = virConnectOpen(uri); - if (dconn == NULL) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - _("Failed to connect to remote libvirt URI %s"), uri); - return -1; - } - if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, - VIR_DRV_FEATURE_MIGRATION_V2)) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s", - _("Destination libvirt does not support required migration protocol 2")); - goto close_dconn; - } - st = virStreamNew(dconn, 0); if (st == NULL) /* virStreamNew only fails on OOM, and it reports the error itself */ - goto close_dconn; - - dom_xml = virDomainDefFormat(dom->conn, vm->def, VIR_DOMAIN_XML_SECURE); - if (!dom_xml) { - qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - "%s", _("failed to get domain xml")); - goto close_stream; - } + goto cleanup; internalret = dconn->driver->domainMigratePrepareTunnel(dconn, st, flags, dname, resource, dom_xml); - VIR_FREE(dom_xml); + if (internalret < 0) /* domainMigratePrepareTunnel sets the error for us */ goto close_stream; @@ -6666,13 +6646,57 @@ close_stream: /* don't call virStreamFree(), because that resets any pending errors */ virUnrefStream(st); -close_dconn: +cleanup: + return retval; +} + + +static int doPeer2PeerMigrate(virDomainPtr dom, + virDomainObjPtr vm, + const char *uri, + unsigned long flags, + const char *dname, + unsigned long resource) +{ + int ret = -1; + virConnectPtr dconn = NULL; + char *dom_xml; + + /* the order of operations is important here; we make sure the + * destination side is completely setup before we touch the source + */ + + dconn = virConnectOpen(uri); + if (dconn == NULL) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + _("Failed to connect to remote libvirt URI %s"), uri); + return -1; + } + if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn, + VIR_DRV_FEATURE_MIGRATION_V2)) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s", + _("Destination libvirt does not support required migration protocol 2")); + goto cleanup; + } + + dom_xml = virDomainDefFormat(dom->conn, vm->def, VIR_DOMAIN_XML_SECURE); + if (!dom_xml) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("failed to get domain xml")); + goto cleanup; + } + + ret = doTunnelMigrate(dom, dconn, vm, dom_xml, uri, flags, dname, resource); + +cleanup: + VIR_FREE(dom_xml); /* don't call virConnectClose(), because that resets any pending errors */ virUnrefConnect(dconn); - return retval; + return ret; } + /* Perform is the second step, and it runs on the source host. */ static int qemudDomainMigratePerform (virDomainPtr dom, @@ -6720,7 +6744,7 @@ qemudDomainMigratePerform (virDomainPtr dom, } if ((flags & VIR_MIGRATE_TUNNELLED)) { - if (doTunnelMigrate(dom, vm, uri, flags, dname, resource) < 0) + if (doPeer2PeerMigrate(dom, vm, uri, flags, dname, resource) < 0) /* doTunnelMigrate already set the error, so just get out */ goto cleanup; } else {