---
 src/qemu/qemu_driver.c    | 302 ++++++++++++++++++++++++++++++++++++++++++++--
 src/qemu/qemu_migration.c | 162 ++++++++++++++++++-------
 src/qemu/qemu_migration.h |   9 ++
 3 files changed, 417 insertions(+), 56 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index e2b85c0..cedec91 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1095,6 +1095,7 @@ qemuConnectSupportsFeature(virConnectPtr conn, int 
feature)
     case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
     case VIR_DRV_FEATURE_XML_MIGRATABLE:
     case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
+    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
         return 1;
     default:
         return 0;
@@ -10173,6 +10174,43 @@ qemuDomainMigrateBegin3(virDomainPtr domain,
                               cookieout, cookieoutlen, flags);
 }
 
+static char *
+qemuDomainMigrateBegin3Params(virDomainPtr domain,
+                              virTypedParameterPtr params,
+                              int nparams,
+                              char **cookieout,
+                              int *cookieoutlen,
+                              unsigned int flags)
+{
+    const char *xmlin = NULL;
+    const char *dname = NULL;
+    virDomainObjPtr vm;
+
+    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
+    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
+        return NULL;
+
+    if (virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_XML,
+                                &xmlin) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_NAME,
+                                &dname) < 0)
+        return NULL;
+
+    if (!(vm = qemuDomObjFromDomain(domain)))
+        return NULL;
+
+    if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0) {
+        virObjectUnlock(vm);
+        return NULL;
+    }
+
+    return qemuMigrationBegin(domain->conn, vm, xmlin, dname,
+                              cookieout, cookieoutlen, flags);
+}
+
+
 static int
 qemuDomainMigratePrepare3(virConnectPtr dconn,
                           const char *cookiein,
@@ -10219,6 +10257,66 @@ cleanup:
     return ret;
 }
 
+static int
+qemuDomainMigratePrepare3Params(virConnectPtr dconn,
+                                virTypedParameterPtr params,
+                                int nparams,
+                                const char *cookiein,
+                                int cookieinlen,
+                                char **cookieout,
+                                int *cookieoutlen,
+                                char **uri_out,
+                                unsigned int flags)
+{
+    virQEMUDriverPtr driver = dconn->privateData;
+    virDomainDefPtr def = NULL;
+    const char *dom_xml = NULL;
+    const char *dname = NULL;
+    const char *uri_in = NULL;
+    int ret = -1;
+
+    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
+    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
+        return -1;
+
+    if (virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_XML,
+                                &dom_xml) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_NAME,
+                                &dname) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_URI,
+                                &uri_in) < 0)
+        return -1;
+
+    if (flags & VIR_MIGRATE_TUNNELLED) {
+        /* this is a logical error; we never should have gotten here with
+         * VIR_MIGRATE_TUNNELLED set
+         */
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Tunnelled migration requested but invalid "
+                         "RPC method called"));
+        goto cleanup;
+    }
+
+    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname)))
+        goto cleanup;
+
+    if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0)
+        goto cleanup;
+
+    ret = qemuMigrationPrepareDirect(driver, dconn,
+                                     cookiein, cookieinlen,
+                                     cookieout, cookieoutlen,
+                                     uri_in, uri_out,
+                                     &def, flags);
+
+cleanup:
+    virDomainDefFree(def);
+    return ret;
+}
+
 
 static int
 qemuDomainMigratePrepareTunnel3(virConnectPtr dconn,
@@ -10260,6 +10358,57 @@ cleanup:
     return ret;
 }
 
+static int
+qemuDomainMigratePrepareTunnel3Params(virConnectPtr dconn,
+                                      virStreamPtr st,
+                                      virTypedParameterPtr params,
+                                      int nparams,
+                                      const char *cookiein,
+                                      int cookieinlen,
+                                      char **cookieout,
+                                      int *cookieoutlen,
+                                      unsigned int flags)
+{
+    virQEMUDriverPtr driver = dconn->privateData;
+    virDomainDefPtr def = NULL;
+    const char *dom_xml = NULL;
+    const char *dname = NULL;
+    int ret = -1;
+
+    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
+    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
+        return -1;
+
+    if (virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_XML,
+                                &dom_xml) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_NAME,
+                                &dname) < 0)
+        return -1;
+
+    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("PrepareTunnel called but no TUNNELLED flag set"));
+        goto cleanup;
+    }
+
+    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname)))
+        goto cleanup;
+
+    if (virDomainMigratePrepareTunnel3ParamsEnsureACL(dconn, def) < 0)
+        goto cleanup;
+
+    ret = qemuMigrationPrepareTunnel(driver, dconn,
+                                     cookiein, cookieinlen,
+                                     cookieout, cookieoutlen,
+                                     st, &def, flags);
+
+cleanup:
+    virDomainDefFree(def);
+    return ret;
+}
+
 
 static int
 qemuDomainMigratePerform3(virDomainPtr dom,
@@ -10293,6 +10442,56 @@ qemuDomainMigratePerform3(virDomainPtr dom,
                                 flags, dname, resource, true);
 }
 
+static int
+qemuDomainMigratePerform3Params(virDomainPtr dom,
+                                const char *dconnuri,
+                                virTypedParameterPtr params,
+                                int nparams,
+                                const char *cookiein,
+                                int cookieinlen,
+                                char **cookieout,
+                                int *cookieoutlen,
+                                unsigned int flags)
+{
+    virQEMUDriverPtr driver = dom->conn->privateData;
+    virDomainObjPtr vm;
+    const char *dom_xml = NULL;
+    const char *dname = NULL;
+    const char *uri = NULL;
+    unsigned long long bandwidth = 0;
+
+    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
+    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
+        return -1;
+
+    if (virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_XML,
+                                &dom_xml) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_NAME,
+                                &dname) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_URI,
+                                &uri) < 0 ||
+        virTypedParamsGetULLong(params, nparams,
+                                VIR_MIGRATE_PARAM_BANDWIDTH,
+                                &bandwidth) < 0)
+        return -1;
+
+    if (!(vm = qemuDomObjFromDomain(dom)))
+        return -1;
+
+    if (virDomainMigratePerform3ParamsEnsureACL(dom->conn, vm->def) < 0) {
+        virObjectUnlock(vm);
+        return -1;
+    }
+
+    return qemuMigrationPerform(driver, dom->conn, vm, dom_xml,
+                                dconnuri, uri, cookiein, cookieinlen,
+                                cookieout, cookieoutlen,
+                                flags, dname, bandwidth, true);
+}
+
 
 static virDomainPtr
 qemuDomainMigrateFinish3(virConnectPtr dconn,
@@ -10308,29 +10507,72 @@ qemuDomainMigrateFinish3(virConnectPtr dconn,
 {
     virQEMUDriverPtr driver = dconn->privateData;
     virDomainObjPtr vm;
-    virDomainPtr dom = NULL;
 
     virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
 
-    vm = virDomainObjListFindByName(driver->domains, dname);
-    if (!vm) {
+    if (!dname ||
+        !(vm = virDomainObjListFindByName(driver->domains, dname))) {
         virReportError(VIR_ERR_NO_DOMAIN,
-                       _("no domain with matching name '%s'"), dname);
-        goto cleanup;
+                       _("no domain with matching name '%s'"),
+                       NULLSTR(dname));
+        return NULL;
     }
 
-    if (virDomainMigrateFinish3EnsureACL(dconn, vm->def) < 0)
-        goto cleanup;
+    if (virDomainMigrateFinish3EnsureACL(dconn, vm->def) < 0) {
+        virObjectUnlock(vm);
+        return NULL;
+    }
 
-    dom = qemuMigrationFinish(driver, dconn, vm,
-                              cookiein, cookieinlen,
-                              cookieout, cookieoutlen,
-                              flags, cancelled, true);
+    return qemuMigrationFinish(driver, dconn, vm,
+                               cookiein, cookieinlen,
+                               cookieout, cookieoutlen,
+                               flags, cancelled, true);
+}
 
-cleanup:
-    return dom;
+static virDomainPtr
+qemuDomainMigrateFinish3Params(virConnectPtr dconn,
+                               virTypedParameterPtr params,
+                               int nparams,
+                               const char *cookiein,
+                               int cookieinlen,
+                               char **cookieout,
+                               int *cookieoutlen,
+                               unsigned int flags,
+                               int cancelled)
+{
+    virQEMUDriverPtr driver = dconn->privateData;
+    virDomainObjPtr vm;
+    const char *dname = NULL;
+
+    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
+    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
+        return NULL;
+
+    if (virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_NAME,
+                                &dname) < 0)
+        return NULL;
+
+    if (!dname ||
+        !(vm = virDomainObjListFindByName(driver->domains, dname))) {
+        virReportError(VIR_ERR_NO_DOMAIN,
+                       _("no domain with matching name '%s'"),
+                       NULLSTR(dname));
+        return NULL;
+    }
+
+    if (virDomainMigrateFinish3ParamsEnsureACL(dconn, vm->def) < 0) {
+        virObjectUnlock(vm);
+        return NULL;
+    }
+
+    return qemuMigrationFinish(driver, dconn, vm,
+                               cookiein, cookieinlen,
+                               cookieout, cookieoutlen,
+                               flags, cancelled, true);
 }
 
+
 static int
 qemuDomainMigrateConfirm3(virDomainPtr domain,
                           const char *cookiein,
@@ -10354,6 +10596,34 @@ qemuDomainMigrateConfirm3(virDomainPtr domain,
                                 flags, cancelled);
 }
 
+static int
+qemuDomainMigrateConfirm3Params(virDomainPtr domain,
+                                virTypedParameterPtr params,
+                                int nparams,
+                                const char *cookiein,
+                                int cookieinlen,
+                                unsigned int flags,
+                                int cancelled)
+{
+    virDomainObjPtr vm;
+
+    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
+
+    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
+        return -1;
+
+    if (!(vm = qemuDomObjFromDomain(domain)))
+        return -1;
+
+    if (virDomainMigrateConfirm3ParamsEnsureACL(domain->conn, vm->def) < 0) {
+        virObjectUnlock(vm);
+        return -1;
+    }
+
+    return qemuMigrationConfirm(domain->conn, vm, cookiein, cookieinlen,
+                                flags, cancelled);
+}
+
 
 static int
 qemuNodeDeviceGetPciInfo(virNodeDeviceDefPtr def,
@@ -15776,6 +16046,12 @@ static virDriver qemuDriver = {
     .nodeGetCPUMap = qemuNodeGetCPUMap, /* 1.0.0 */
     .domainFSTrim = qemuDomainFSTrim, /* 1.0.1 */
     .domainOpenChannel = qemuDomainOpenChannel, /* 1.0.2 */
+    .domainMigrateBegin3Params = qemuDomainMigrateBegin3Params, /* 1.1.0 */
+    .domainMigratePrepare3Params = qemuDomainMigratePrepare3Params, /* 1.1.0 */
+    .domainMigratePrepareTunnel3Params = 
qemuDomainMigratePrepareTunnel3Params, /* 1.1.0 */
+    .domainMigratePerform3Params = qemuDomainMigratePerform3Params, /* 1.1.0 */
+    .domainMigrateFinish3Params = qemuDomainMigrateFinish3Params, /* 1.1.0 */
+    .domainMigrateConfirm3Params = qemuDomainMigrateConfirm3Params, /* 1.1.0 */
 };
 
 
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 66d62fe..d4a169e 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -56,6 +56,7 @@
 #include "viruri.h"
 #include "virhook.h"
 #include "virstring.h"
+#include "virtypedparam.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -3564,16 +3565,18 @@ cleanup:
  * from libvirt.c, but running in source libvirtd context,
  * instead of client app context & also adding in tunnel
  * handling */
-static int doPeer2PeerMigrate3(virQEMUDriverPtr driver,
-                               virConnectPtr sconn,
-                               virConnectPtr dconn,
-                               virDomainObjPtr vm,
-                               const char *xmlin,
-                               const char *dconnuri,
-                               const char *uri,
-                               unsigned long flags,
-                               const char *dname,
-                               unsigned long resource)
+static int
+doPeer2PeerMigrate3(virQEMUDriverPtr driver,
+                    virConnectPtr sconn,
+                    virConnectPtr dconn,
+                    const char *dconnuri,
+                    virDomainObjPtr vm,
+                    const char *xmlin,
+                    const char *dname,
+                    const char *uri,
+                    unsigned long long bandwidth,
+                    bool useParams,
+                    unsigned long flags)
 {
     virDomainPtr ddomain = NULL;
     char *uri_out = NULL;
@@ -3584,15 +3587,18 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver,
     int cookieoutlen = 0;
     int ret = -1;
     virErrorPtr orig_err = NULL;
-    bool cancelled;
+    bool cancelled = true;
     virStreamPtr st = NULL;
     unsigned int destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR;
 
-    VIR_DEBUG("driver=%p, sconn=%p, dconn=%p, vm=%p, xmlin=%s, "
-              "dconnuri=%s, uri=%s, flags=%lx, dname=%s, resource=%lu",
-              driver, sconn, dconn, vm, NULLSTR(xmlin),
-              NULLSTR(dconnuri), NULLSTR(uri), flags,
-              NULLSTR(dname), resource);
+    virTypedParameterPtr params = NULL;
+    int nparams = 0;
+    int maxparams = 0;
+
+    VIR_DEBUG("driver=%p, sconn=%p, dconn=%p, dconnuri=%s, vm=%p, xmlin=%s, "
+              "dname=%s, uri=%s, bandwidth=%llu, useParams=%d, flags=%lx",
+              driver, sconn, dconn, NULLSTR(dconnuri), vm, NULLSTR(xmlin),
+              NULLSTR(dname), NULLSTR(uri), bandwidth, useParams, flags);
 
     /* Unlike the virDomainMigrateVersion3 counterpart, we don't need
      * to worry about auto-setting the VIR_MIGRATE_CHANGE_PROTECTION
@@ -3604,6 +3610,28 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver,
     if (!dom_xml)
         goto cleanup;
 
+    if (useParams) {
+        if (virTypedParamsAddString(&params, &nparams, &maxparams,
+                                    VIR_MIGRATE_PARAM_DEST_XML, dom_xml) < 0)
+            goto cleanup;
+
+        if (dname &&
+            virTypedParamsAddString(&params, &nparams, &maxparams,
+                                    VIR_MIGRATE_PARAM_DEST_NAME, dname) < 0)
+            goto cleanup;
+
+        if (uri &&
+            virTypedParamsAddString(&params, &nparams, &maxparams,
+                                    VIR_MIGRATE_PARAM_URI, uri) < 0)
+            goto cleanup;
+
+        if (bandwidth &&
+            virTypedParamsAddULLong(&params, &nparams, &maxparams,
+                                    VIR_MIGRATE_PARAM_BANDWIDTH,
+                                    bandwidth) < 0)
+            goto cleanup;
+    }
+
     if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED)
         flags |= VIR_MIGRATE_PAUSED;
 
@@ -3617,16 +3645,27 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver,
             goto cleanup;
 
         qemuDomainObjEnterRemote(vm);
-        ret = dconn->driver->domainMigratePrepareTunnel3
-            (dconn, st, cookiein, cookieinlen,
-             &cookieout, &cookieoutlen,
-             destflags, dname, resource, dom_xml);
+        if (useParams) {
+            ret = dconn->driver->domainMigratePrepareTunnel3Params
+                (dconn, st, params, nparams, cookiein, cookieinlen,
+                 &cookieout, &cookieoutlen, destflags);
+        } else {
+            ret = dconn->driver->domainMigratePrepareTunnel3
+                (dconn, st, cookiein, cookieinlen, &cookieout, &cookieoutlen,
+                 destflags, dname, bandwidth, dom_xml);
+        }
         qemuDomainObjExitRemote(vm);
     } else {
         qemuDomainObjEnterRemote(vm);
-        ret = dconn->driver->domainMigratePrepare3
-            (dconn, cookiein, cookieinlen, &cookieout, &cookieoutlen,
-             uri, &uri_out, destflags, dname, resource, dom_xml);
+        if (useParams) {
+            ret = dconn->driver->domainMigratePrepare3Params
+                (dconn, params, nparams, cookiein, cookieinlen,
+                 &cookieout, &cookieoutlen, &uri_out, destflags);
+        } else {
+            ret = dconn->driver->domainMigratePrepare3
+                (dconn, cookiein, cookieinlen, &cookieout, &cookieoutlen,
+                 uri, &uri_out, destflags, dname, bandwidth, dom_xml);
+        }
         qemuDomainObjExitRemote(vm);
     }
     VIR_FREE(dom_xml);
@@ -3641,11 +3680,15 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver,
         goto finish;
     }
 
-    if (!(flags & VIR_MIGRATE_TUNNELLED) &&
-        (uri_out == NULL)) {
+    if (uri_out) {
+        uri = uri_out;
+        if (useParams &&
+            virTypedParamsReplaceString(&params, &nparams,
+                                        VIR_MIGRATE_PARAM_URI, uri_out) < 0)
+            goto finish;
+    } else if (!uri && !(flags & VIR_MIGRATE_TUNNELLED)) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("domainMigratePrepare3 did not set uri"));
-        cancelled = true;
         goto finish;
     }
 
@@ -3654,23 +3697,24 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver,
      * running, but in paused state until the destination can
      * confirm migration completion.
      */
-    VIR_DEBUG("Perform3 %p uri=%s uri_out=%s", sconn, uri, uri_out);
+    VIR_DEBUG("Perform3 %p uri=%s", sconn, NULLSTR(uri));
     qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3);
     VIR_FREE(cookiein);
     cookiein = cookieout;
     cookieinlen = cookieoutlen;
     cookieout = NULL;
     cookieoutlen = 0;
-    if (flags & VIR_MIGRATE_TUNNELLED)
+    if (flags & VIR_MIGRATE_TUNNELLED) {
         ret = doTunnelMigrate(driver, vm, st,
                               cookiein, cookieinlen,
                               &cookieout, &cookieoutlen,
-                              flags, resource, dconn);
-    else
-        ret = doNativeMigrate(driver, vm, uri_out,
+                              flags, bandwidth, dconn);
+    } else {
+        ret = doNativeMigrate(driver, vm, uri,
                               cookiein, cookieinlen,
                               &cookieout, &cookieoutlen,
-                              flags, resource, dconn);
+                              flags, bandwidth, dconn);
+    }
 
     /* Perform failed. Make sure Finish doesn't overwrite the error */
     if (ret < 0) {
@@ -3698,12 +3742,29 @@ finish:
     cookieinlen = cookieoutlen;
     cookieout = NULL;
     cookieoutlen = 0;
-    dname = dname ? dname : vm->def->name;
-    qemuDomainObjEnterRemote(vm);
-    ddomain = dconn->driver->domainMigrateFinish3
-        (dconn, dname, cookiein, cookieinlen, &cookieout, &cookieoutlen,
-         dconnuri, uri_out ? uri_out : uri, destflags, cancelled);
-    qemuDomainObjExitRemote(vm);
+
+    if (useParams) {
+        if (virTypedParamsGetString(params, nparams,
+                                    VIR_MIGRATE_PARAM_DEST_NAME, NULL) <= 0 &&
+            virTypedParamsReplaceString(&params, &nparams,
+                                        VIR_MIGRATE_PARAM_DEST_NAME,
+                                        vm->def->name) < 0) {
+            ddomain = NULL;
+        } else {
+            qemuDomainObjEnterRemote(vm);
+            ddomain = dconn->driver->domainMigrateFinish3Params
+                (dconn, params, nparams, cookiein, cookieinlen,
+                 &cookieout, &cookieoutlen, destflags, cancelled);
+            qemuDomainObjExitRemote(vm);
+        }
+    } else {
+        dname = dname ? dname : vm->def->name;
+        qemuDomainObjEnterRemote(vm);
+        ddomain = dconn->driver->domainMigrateFinish3
+            (dconn, dname, cookiein, cookieinlen, &cookieout, &cookieoutlen,
+             dconnuri, uri, destflags, cancelled);
+        qemuDomainObjExitRemote(vm);
+    }
 
     /* If ddomain is NULL, then we were unable to start
      * the guest on the target, and must restart on the
@@ -3759,7 +3820,7 @@ finish:
     VIR_FREE(uri_out);
     VIR_FREE(cookiein);
     VIR_FREE(cookieout);
-
+    virTypedParamsFree(params, nparams);
     return ret;
 }
 
@@ -3781,6 +3842,7 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver,
     virErrorPtr orig_err = NULL;
     bool offline = false;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    bool useParams;
 
     VIR_DEBUG("driver=%p, sconn=%p, vm=%p, xmlin=%s, dconnuri=%s, "
               "uri=%s, flags=%lx, dname=%s, resource=%lu",
@@ -3815,6 +3877,8 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver,
          */
     *v3proto = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
                                         VIR_DRV_FEATURE_MIGRATION_V3);
+    useParams = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                         VIR_DRV_FEATURE_MIGRATION_PARAMS);
     if (flags & VIR_MIGRATE_OFFLINE)
         offline = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
                                            VIR_DRV_FEATURE_MIGRATION_OFFLINE);
@@ -3826,6 +3890,17 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver,
         goto cleanup;
     }
 
+    /* Only xmlin, dname, uri, and bandwidth parameters can be used with
+     * old-style APIs. */
+#if 0
+    if (!useParams && /* any new parameter */) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("Migration APIs with extensible parameters are not "
+                         "supported but extended parameters were passed"));
+        goto cleanup;
+    }
+#endif
+
     if (flags & VIR_MIGRATE_OFFLINE && !offline) {
         virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                        _("offline migration is not supported by "
@@ -3847,12 +3922,13 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver,
      * Therefore it is safe to clear the bit here.  */
     flags &= ~VIR_MIGRATE_CHANGE_PROTECTION;
 
-    if (*v3proto)
-        ret = doPeer2PeerMigrate3(driver, sconn, dconn, vm, xmlin,
-                                  dconnuri, uri, flags, dname, resource);
-    else
+    if (*v3proto) {
+        ret = doPeer2PeerMigrate3(driver, sconn, dconn, dconnuri, vm, xmlin,
+                                  dname, uri, resource, useParams, flags);
+    } else {
         ret = doPeer2PeerMigrate2(driver, sconn, dconn, vm,
                                   dconnuri, flags, dname, resource);
+    }
 
 cleanup:
     orig_err = virSaveLastError();
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index dd1d0a1..469c948 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -41,6 +41,15 @@
      VIR_MIGRATE_COMPRESSED |                   \
      VIR_MIGRATE_ABORT_ON_ERROR)
 
+/* All supported migration parameters and their types. */
+# define QEMU_MIGRATION_PARAMETERS                              \
+    VIR_MIGRATE_PARAM_URI,          VIR_TYPED_PARAM_STRING,     \
+    VIR_MIGRATE_PARAM_DEST_NAME,    VIR_TYPED_PARAM_STRING,     \
+    VIR_MIGRATE_PARAM_DEST_XML,     VIR_TYPED_PARAM_STRING,     \
+    VIR_MIGRATE_PARAM_BANDWIDTH,    VIR_TYPED_PARAM_ULLONG,     \
+    NULL
+
+
 enum qemuMigrationJobPhase {
     QEMU_MIGRATION_PHASE_NONE = 0,
     QEMU_MIGRATION_PHASE_PERFORM2,
-- 
1.8.2.1

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to