[libvirt] [PATCH] Support a new peer-to-peer migration mode & public API

Daniel P. Berrange berrange at redhat.com
Thu Sep 17 17:25:01 UTC 2009


Introduces several new public API options for migration

 - VIR_MIGRATE_PEER2PEER: With this flag the client only
   invokes the virDomainMigratePerform method, expecting
   the source host driver to do whatever is required to
   complete the entire migration process.
 - VIR_MIGRATE_TUNNELLED: With this flag the actual data
   for migration will be tunnelled over the libvirtd RPC
   channel. This requires that VIR_MIGRATE_PEER2PEER is
   also set.
 - virDomainMigrateToURI: This is variant of the existing
   virDomainMigrate method which can be used when the
   VIR_MIGRATE_PEER2PEER flag is set. The benefit of this
   method is that no virConnectPtr object is required for
   the destination host, only a destination URI.

The URI for VIR_MIGRATE_TUNNELLED must be a valid libvirt
URI. For non-tunnelled migration a hypervisor specific
migration URI is used.

* include/libvirt/libvirt.h, include/libvirt/libvirt.h.in:
  Add VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_TUNNELLED and
  virDomainMigrateToURI.
* src/driver.h: Remove feature flags
* src/libvirt_internal.h: Add feature flags, and include
  new VIR_FEATURE_MIGRATE_P2P indicating support for the
  new VIR_MIGRATE_PEER2PEER mode.
* src/libvirt.c: Implement support for VIR_MIGRATE_PEER2PEER
  and virDomainMigrateToURI APIs.
* src/virsh.c: Add --p2p and --tunnelled args and use the
  new virDomainMigrateToURI method where possible.
* src/xen_unified.c: Advertise support for P2P migration
* src/xend_internal.c: Accept VIR_MIGRATE_PEER2PEER flag.
* src/libvirt_public.syms: Export virDomainMigrateToURI
  method
---
 include/libvirt/libvirt.h    |    8 ++-
 include/libvirt/libvirt.h.in |    8 ++-
 src/driver.h                 |   19 ----
 src/internal.h               |    2 +
 src/libvirt.c                |  224 +++++++++++++++++++++++++++++++++++++-----
 src/libvirt_internal.h       |   30 ++++++
 src/libvirt_public.syms      |    1 +
 src/virsh.c                  |   42 ++++++--
 src/xen_unified.c            |    7 +-
 src/xend_internal.c          |    6 +
 10 files changed, 286 insertions(+), 61 deletions(-)

diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h
index 10ec04a..1745396 100644
--- a/include/libvirt/libvirt.h
+++ b/include/libvirt/libvirt.h
@@ -336,7 +336,9 @@ typedef virDomainInterfaceStatsStruct *virDomainInterfaceStatsPtr;
 
 /* Domain migration flags. */
 typedef enum {
-  VIR_MIGRATE_LIVE              = 1, /* live migration */
+    VIR_MIGRATE_LIVE              = (1 << 0), /* live migration */
+    VIR_MIGRATE_PEER2PEER         = (1 << 1), /* direct source -> dest host control channel */
+    VIR_MIGRATE_TUNNELLED         = (1 << 2), /* tunnel migration data over libvirtd connection */
 } virDomainMigrateFlags;
 
 /* Domain migration. */
@@ -344,6 +346,10 @@ virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn,
                                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);
+
 /**
  * VIR_NODEINFO_MAXCPUS:
  * @nodeinfo: virNodeInfo instance
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 012d30e..5e1a500 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -336,7 +336,9 @@ typedef virDomainInterfaceStatsStruct *virDomainInterfaceStatsPtr;
 
 /* Domain migration flags. */
 typedef enum {
-  VIR_MIGRATE_LIVE              = 1, /* live migration */
+    VIR_MIGRATE_LIVE              = (1 << 0), /* live migration */
+    VIR_MIGRATE_PEER2PEER         = (1 << 1), /* direct source -> dest host control channel */
+    VIR_MIGRATE_TUNNELLED         = (1 << 2), /* tunnel migration data over libvirtd connection */
 } virDomainMigrateFlags;
 
 /* Domain migration. */
@@ -344,6 +346,10 @@ virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn,
                                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);
+
 /**
  * VIR_NODEINFO_MAXCPUS:
  * @nodeinfo: virNodeInfo instance
diff --git a/src/driver.h b/src/driver.h
index 6a3dcc2..893e98b 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -44,25 +44,6 @@ typedef enum {
     VIR_DRV_OPEN_ERROR = -2,
 } virDrvOpenStatus;
 
-/* Feature detection.  This is a libvirt-private interface for determining
- * what features are supported by the driver.
- *
- * The remote driver passes features through to the real driver at the
- * remote end unmodified, except if you query a VIR_DRV_FEATURE_REMOTE*
- * feature.
- */
-    /* Driver supports V1-style virDomainMigrate, ie. domainMigratePrepare/
-     * domainMigratePerform/domainMigrateFinish.
-     */
-#define VIR_DRV_FEATURE_MIGRATION_V1 1
-
-    /* Driver is not local. */
-#define VIR_DRV_FEATURE_REMOTE 2
-
-    /* Driver supports V2-style virDomainMigrate, ie. domainMigratePrepare2/
-     * domainMigratePerform/domainMigrateFinish2.
-     */
-#define VIR_DRV_FEATURE_MIGRATION_V2 3
 
 /* Internal feature-detection macro.  Don't call drv->supports_feature
  * directly, because it may be NULL, use this macro instead.
diff --git a/src/internal.h b/src/internal.h
index 8fa579c..bd1cfe6 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -24,6 +24,8 @@
 #include "libvirt/libvirt.h"
 #include "libvirt/virterror.h"
 
+#include "libvirt_internal.h"
+
 /* On architectures which lack these limits, define them (ie. Cygwin).
  * Note that the libvirt code should be robust enough to handle the
  * case where actual value is longer than these limits (eg. by setting
diff --git a/src/libvirt.c b/src/libvirt.c
index 124e5db..481afec 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -35,7 +35,6 @@
 #include "virterror_internal.h"
 #include "logging.h"
 #include "datatypes.h"
-#include "libvirt_internal.h"
 #include "driver.h"
 
 #include "uuid.h"
@@ -3059,6 +3058,38 @@ virDomainMigrateVersion2 (virDomainPtr domain,
     return ddomain;
 }
 
+
+ /*
+  * This is sort of a migration v3
+  *
+  * This performs a peer-2-peer migration where source host
+  * does all the communication with the destination host.
+  */
+static int
+virDomainMigrateP2P (virDomainPtr domain,
+                     unsigned long flags,
+                     const char *dname,
+                     const char *uri,
+                     unsigned long bandwidth)
+{
+    if (!domain->conn->driver->domainMigratePerform) {
+        virLibConnError (domain->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        return -1;
+    }
+
+    /* Perform the migration.  The driver isn't supposed to return
+     * until the migration is complete.
+     */
+    return domain->conn->driver->domainMigratePerform(domain,
+                                                      NULL, /* cookie */
+                                                      0,    /* cookielen */
+                                                      uri,
+                                                      flags,
+                                                      dname,
+                                                      bandwidth);
+}
+
+
 /**
  * virDomainMigrate:
  * @domain: a domain object
@@ -3072,22 +3103,34 @@ virDomainMigrateVersion2 (virDomainPtr domain,
  * 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_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_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.
  *
- * Since typically the two hypervisors connect directly to each
- * other in order to perform the migration, you may need to specify
- * a path from the source to the destination.  This is the purpose
- * of the uri parameter.  If uri is NULL, then libvirt will try to
- * find the best method.  Uri may specify the hostname or IP address
- * of the destination host as seen from the source.  Or uri may be
- * a URI giving transport, hostname, user, port, etc. in the usual
- * form.  Refer to driver documentation for the particular URIs
- * supported.
+ * If the VIR_MIGRATE_TUNNELLED 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_TUNNELED 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 neccessary 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,
@@ -3142,24 +3185,50 @@ virDomainMigrate (virDomainPtr domain,
         goto error;
     }
 
-    /* Check that migration is supported by both drivers. */
-    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))
-        ddomain = virDomainMigrateVersion1 (domain, dconn, 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))
-        ddomain = virDomainMigrateVersion2 (domain, dconn, flags, dname, uri, bandwidth);
-    else {
-        virLibConnError (domain->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-        goto error;
+    if (flags & VIR_MIGRATE_PEER2PEER) {
+        if (VIR_DRV_SUPPORTS_FEATURE (domain->conn->driver, domain->conn,
+                                      VIR_DRV_FEATURE_MIGRATION_P2P)) {
+            char *duri = NULL;
+            if (!uri)
+                duri = virConnectGetURI(dconn);
+
+            if (virDomainMigrateP2P (domain, flags, dname, uri ? uri : duri, bandwidth) < 0) {
+                VIR_FREE(duri);
+                goto error;
+            }
+            VIR_FREE(duri);
+
+            ddomain = virDomainLookupByName (dconn, dname ? dname : domain->name);
+        } else {
+            virLibConnError (domain->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+            goto error;
+        }
+    } else {
+        if (flags & VIR_MIGRATE_TUNNELLED) {
+            virLibConnError(domain->conn, 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_V1) &&
+            VIR_DRV_SUPPORTS_FEATURE (dconn->driver, dconn,
+                                      VIR_DRV_FEATURE_MIGRATION_V1))
+            ddomain = virDomainMigrateVersion1 (domain, dconn, 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))
+            ddomain = virDomainMigrateVersion2 (domain, dconn, flags, dname, uri, bandwidth);
+        else {
+            virLibConnError (domain->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+            goto error;
+        }
     }
 
-     if (ddomain == NULL)
-         goto error;
+    if (ddomain == NULL)
+        goto error;
 
     return ddomain;
 
@@ -3169,6 +3238,107 @@ error:
     return NULL;
 }
 
+
+/**
+ * virDomainMigrateToURI:
+ * @domain: a domain object
+ * @duri: libvirt connection URI for destination host
+ * @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. The duri is a libvirt connection URI that the
+ * source host will use to talk to the destination.
+ *
+ * The difference from the regular virDomainMigrate method is
+ * that the calling application does not need a direct connection
+ * to the destination host. The source libvirt driver makes a
+ * direct peer-to-peer connection to the destination libvirtd
+ * without the client appliction being involved.
+ *
+ * The VIR_MIGRATE_PEER2PEER flag is mandatory for this method.
+ * If an application wishes to run without this flag, then it
+ * may use the alternative virDomainMigrate method which requires
+ * an virConnectPtr object for the destination host
+ *
+ * The following additional flags may also be set
+ *   VIR_MIGRATE_LIVE      Do not pause the VM during migration
+ *   VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
+ *
+ * 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.
+ *
+ * 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
+virDomainMigrateToURI (virDomainPtr domain,
+                       const char *duri,
+                       unsigned long flags,
+                       const char *dname,
+                       unsigned long bandwidth)
+{
+    DEBUG("domain=%p, duri=%p, flags=%lu, dname=%s, bandwidth=%lu",
+          domain, NULLSTR(duri), flags, NULLSTR(dname), bandwidth);
+
+    virResetLastError();
+
+    /* First checkout the source */
+    if (!VIR_IS_CONNECTED_DOMAIN (domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        return -1;
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    if (duri == NULL) {
+        virLibConnError (domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto error;
+    }
+
+    /* XXX perhaps we should just automatically set this flag instead ? */
+    if (flags & VIR_MIGRATE_PEER2PEER) {
+        if (VIR_DRV_SUPPORTS_FEATURE (domain->conn->driver, domain->conn,
+                                      VIR_DRV_FEATURE_MIGRATION_P2P)) {
+            if (virDomainMigrateP2P (domain, flags, dname, duri, bandwidth) < 0)
+                goto error;
+        } else {
+            virLibConnError (domain->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+            goto error;
+        }
+    } else {
+        virLibConnError (domain->conn, VIR_ERR_OPERATION_INVALID,
+                         _("cannot migrate to a destination URI without peer2peer flag"));
+        goto error;
+    }
+
+    return 0;
+
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(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_internal.h b/src/libvirt_internal.h
index 5913798..5f1a7fe 100644
--- a/src/libvirt_internal.h
+++ b/src/libvirt_internal.h
@@ -17,6 +17,7 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
  *
+ * NB This file is (secret) ABI sensitive. Append only
  */
 
 #ifndef __LIBVIRT_H_
@@ -31,6 +32,35 @@ int virStateReload(void);
 int virStateActive(void);
 #endif
 
+/* Feature detection.  This is a libvirt-private interface for determining
+ * what features are supported by the driver.
+ *
+ * The remote driver passes features through to the real driver at the
+ * remote end unmodified, except if you query a VIR_DRV_FEATURE_REMOTE*
+ * feature.
+ *
+ */
+enum {
+    /* Driver supports V1-style virDomainMigrate, ie. domainMigratePrepare/
+     * domainMigratePerform/domainMigrateFinish.
+     */
+    VIR_DRV_FEATURE_MIGRATION_V1 = 1,
+
+    /* Driver is not local. */
+    VIR_DRV_FEATURE_REMOTE = 2,
+
+    /* Driver supports V2-style virDomainMigrate, ie. domainMigratePrepare2/
+     * domainMigratePerform/domainMigrateFinish2.
+     */
+    VIR_DRV_FEATURE_MIGRATION_V2 = 3,
+
+    /* Driver supports peer-2-peer virDomainMigrate ie soruce host
+     * do all the prepare/perform/finish steps directly
+     */
+    VIR_DRV_FEATURE_MIGRATION_P2P = 4,
+};
+
+
 int virDrvSupportsFeature (virConnectPtr conn, int feature);
 
 int virDomainMigratePrepare (virConnectPtr dconn,
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 888ea26..757e54c 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -323,6 +323,7 @@ LIBVIRT_0.7.1 {
 	virStreamFinish;
 	virStreamAbort;
 	virStreamFree;
+	virDomainMigrateToURI;
 } LIBVIRT_0.7.0;
 
 # .... define new API here using predicted next version number ....
diff --git a/src/virsh.c b/src/virsh.c
index 4825f1c..cabbd3d 100644
--- a/src/virsh.c
+++ b/src/virsh.c
@@ -2463,6 +2463,8 @@ static const vshCmdInfo info_migrate[] = {
 
 static const vshCmdOptDef opts_migrate[] = {
     {"live", VSH_OT_BOOL, 0, gettext_noop("live migration")},
+    {"p2p", VSH_OT_BOOL, 0, gettext_noop("peer-2-peer migration")},
+    {"tunnelled", VSH_OT_BOOL, 0, gettext_noop("tunnelled migration")},
     {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")},
     {"desturi", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("connection URI of the destination host")},
     {"migrateuri", VSH_OT_DATA, 0, gettext_noop("migration URI, usually can be omitted")},
@@ -2478,8 +2480,6 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd)
     const char *migrateuri;
     const char *dname;
     int flags = 0, found, ret = FALSE;
-    virConnectPtr dconn = NULL;
-    virDomainPtr ddom = NULL;
 
     if (!vshConnectionUsability (ctl, ctl->conn, TRUE))
         return FALSE;
@@ -2500,20 +2500,40 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd)
     if (vshCommandOptBool (cmd, "live"))
         flags |= VIR_MIGRATE_LIVE;
 
-    /* Temporarily connect to the destination host. */
-    dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0);
-    if (!dconn) goto done;
+    if (vshCommandOptBool (cmd, "p2p"))
+        flags |= VIR_MIGRATE_PEER2PEER;
 
-    /* Migrate. */
-    ddom = virDomainMigrate (dom, dconn, flags, dname, migrateuri, 0);
-    if (!ddom) goto done;
+    if (vshCommandOptBool (cmd, "tunnelled"))
+        flags |= VIR_MIGRATE_TUNNELLED;
 
-    ret = TRUE;
+    if ((flags & VIR_MIGRATE_PEER2PEER)) {
+        /* For peer2peer migration we only expect one URI, a libvirt URI */
+
+        if (migrateuri != NULL) {
+            vshError(ctl, FALSE, "%s", _("migrate: Unexpected migrateuri for peer2peer migration"));
+            goto done;
+        }
+
+        if (virDomainMigrateToURI (dom, desturi, flags, dname, 0) == 0)
+            ret = TRUE;
+    } else {
+        /* For regular live migration, connect to the destination host directly. */
+        virConnectPtr dconn = NULL;
+        virDomainPtr ddom = NULL;
+
+        dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0);
+        if (!dconn) goto done;
+
+        ddom = virDomainMigrate (dom, dconn, flags, dname, migrateuri, 0);
+        if (ddom) {
+            virDomainFree(ddom);
+            ret = TRUE;
+        }
+        virConnectClose (dconn);
+    }
 
  done:
     if (dom) virDomainFree (dom);
-    if (ddom) virDomainFree (ddom);
-    if (dconn) virConnectClose (dconn);
     return ret;
 }
 
diff --git a/src/xen_unified.c b/src/xen_unified.c
index dfa9ca5..954b187 100644
--- a/src/xen_unified.c
+++ b/src/xen_unified.c
@@ -455,8 +455,11 @@ static int
 xenUnifiedSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
 {
     switch (feature) {
-    case VIR_DRV_FEATURE_MIGRATION_V1: return 1;
-    default: return 0;
+    case VIR_DRV_FEATURE_MIGRATION_V1:
+    case VIR_DRV_FEATURE_MIGRATION_P2P:
+        return 1;
+    default:
+        return 0;
     }
 }
 
diff --git a/src/xend_internal.c b/src/xend_internal.c
index 7f55116..da5c039 100644
--- a/src/xend_internal.c
+++ b/src/xend_internal.c
@@ -4400,6 +4400,12 @@ xenDaemonDomainMigratePerform (virDomainPtr domain,
         strcpy (live, "1");
         flags &= ~VIR_MIGRATE_LIVE;
     }
+    /* Trivially support this in Xen, since XenD on dest is always
+     * ready to accept incoming migration */
+    if ((flags & VIR_MIGRATE_PEER2PEER)) {
+        flags &= ~VIR_MIGRATE_PEER2PEER;
+    }
+    /* XXX we could easily do tunnelled migration too if we want to */
     if (flags != 0) {
         virXendError (conn, VIR_ERR_NO_SUPPORT,
                       "%s", _("xenDaemonDomainMigrate: unsupported flag"));
-- 
1.6.2.5




More information about the libvir-list mailing list