43fe83
From ac2a6bb565013f8fce9f36d3eac1ffa7d9523e9a Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <ac2a6bb565013f8fce9f36d3eac1ffa7d9523e9a.1382534061.git.jdenemar@redhat.com>
43fe83
From: Wang Yufei <james.wangyufei@huawei.com>
43fe83
Date: Tue, 22 Oct 2013 16:24:46 +0100
43fe83
Subject: [PATCH] qemu: Avoid assigning unavailable migration ports
43fe83
43fe83
https://bugzilla.redhat.com/show_bug.cgi?id=1019237
43fe83
43fe83
When we migrate vms concurrently, there's a chance that libvirtd on
43fe83
destination assigns the same port for different migrations, which will
43fe83
lead to migration failure during prepare phase on destination. So we use
43fe83
virPortAllocator here to solve the problem.
43fe83
43fe83
Signed-off-by: Wang Yufei <james.wangyufei@huawei.com>
43fe83
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
43fe83
(cherry picked from commit 0196845d3abd0d914cf11f7ad6c19df8b47c32ed)
43fe83
---
43fe83
 src/qemu/qemu_command.h   |  3 +++
43fe83
 src/qemu/qemu_conf.h      |  6 +++---
43fe83
 src/qemu/qemu_domain.h    |  1 +
43fe83
 src/qemu/qemu_driver.c    |  6 ++++++
43fe83
 src/qemu/qemu_migration.c | 53 +++++++++++++++++++++++++++++++++--------------
43fe83
 5 files changed, 50 insertions(+), 19 deletions(-)
43fe83
43fe83
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
43fe83
index 47022e6..decc940 100644
43fe83
--- a/src/qemu/qemu_command.h
43fe83
+++ b/src/qemu/qemu_command.h
43fe83
@@ -51,6 +51,9 @@
43fe83
 # define QEMU_WEBSOCKET_PORT_MIN  5700
43fe83
 # define QEMU_WEBSOCKET_PORT_MAX  65535
43fe83
 
43fe83
+# define QEMU_MIGRATION_PORT_MIN 49152
43fe83
+# define QEMU_MIGRATION_PORT_MAX 49215
43fe83
+
43fe83
 typedef struct _qemuBuildCommandLineCallbacks qemuBuildCommandLineCallbacks;
43fe83
 typedef qemuBuildCommandLineCallbacks *qemuBuildCommandLineCallbacksPtr;
43fe83
 struct _qemuBuildCommandLineCallbacks {
43fe83
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
43fe83
index 356e501..4acc67b 100644
43fe83
--- a/src/qemu/qemu_conf.h
43fe83
+++ b/src/qemu/qemu_conf.h
43fe83
@@ -224,6 +224,9 @@ struct _virQEMUDriver {
43fe83
     /* Immutable pointer, self-locking APIs */
43fe83
     virPortAllocatorPtr webSocketPorts;
43fe83
 
43fe83
+    /* Immutable pointer, self-locking APIs */
43fe83
+    virPortAllocatorPtr migrationPorts;
43fe83
+
43fe83
     /* Immutable pointer, lockless APIs*/
43fe83
     virSysinfoDefPtr hostsysinfo;
43fe83
 
43fe83
@@ -245,9 +248,6 @@ struct _qemuDomainCmdlineDef {
43fe83
     char **env_value;
43fe83
 };
43fe83
 
43fe83
-/* Port numbers used for KVM migration. */
43fe83
-# define QEMUD_MIGRATION_FIRST_PORT 49152
43fe83
-# define QEMUD_MIGRATION_NUM_PORTS 64
43fe83
 
43fe83
 
43fe83
 virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged);
43fe83
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
43fe83
index 21f116c..04f08a3 100644
43fe83
--- a/src/qemu/qemu_domain.h
43fe83
+++ b/src/qemu/qemu_domain.h
43fe83
@@ -160,6 +160,7 @@ struct _qemuDomainObjPrivate {
43fe83
     unsigned long migMaxBandwidth;
43fe83
     char *origname;
43fe83
     int nbdPort; /* Port used for migration with NBD */
43fe83
+    unsigned short migrationPort;
43fe83
 
43fe83
     virChrdevsPtr devs;
43fe83
 
43fe83
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
43fe83
index c2445d9..4a4880c 100644
43fe83
--- a/src/qemu/qemu_driver.c
43fe83
+++ b/src/qemu/qemu_driver.c
43fe83
@@ -687,6 +687,11 @@ qemuStateInitialize(bool privileged,
43fe83
                              cfg->webSocketPortMax)) == NULL)
43fe83
         goto error;
43fe83
 
43fe83
+    if ((qemu_driver->migrationPorts =
43fe83
+         virPortAllocatorNew(QEMU_MIGRATION_PORT_MIN,
43fe83
+                             QEMU_MIGRATION_PORT_MAX)) == NULL)
43fe83
+        goto error;
43fe83
+
43fe83
     if (qemuSecurityInit(qemu_driver) < 0)
43fe83
         goto error;
43fe83
 
43fe83
@@ -993,6 +998,7 @@ qemuStateCleanup(void) {
43fe83
     virObjectUnref(qemu_driver->domains);
43fe83
     virObjectUnref(qemu_driver->remotePorts);
43fe83
     virObjectUnref(qemu_driver->webSocketPorts);
43fe83
+    virObjectUnref(qemu_driver->migrationPorts);
43fe83
 
43fe83
     virObjectUnref(qemu_driver->xmlopt);
43fe83
 
43fe83
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
43fe83
index 047fad9..4222a10 100644
43fe83
--- a/src/qemu/qemu_migration.c
43fe83
+++ b/src/qemu/qemu_migration.c
43fe83
@@ -2145,6 +2145,9 @@ qemuMigrationPrepareCleanup(virQEMUDriverPtr driver,
43fe83
               qemuDomainJobTypeToString(priv->job.active),
43fe83
               qemuDomainAsyncJobTypeToString(priv->job.asyncJob));
43fe83
 
43fe83
+    virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort);
43fe83
+    priv->migrationPort = 0;
43fe83
+
43fe83
     if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN))
43fe83
         return;
43fe83
     qemuDomainObjDiscardAsyncJob(driver, vm);
43fe83
@@ -2160,7 +2163,8 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
43fe83
                         virDomainDefPtr *def,
43fe83
                         const char *origname,
43fe83
                         virStreamPtr st,
43fe83
-                        unsigned int port,
43fe83
+                        unsigned short port,
43fe83
+                        bool autoPort,
43fe83
                         const char *listenAddress,
43fe83
                         unsigned long flags)
43fe83
 {
43fe83
@@ -2440,6 +2444,8 @@ done:
43fe83
         goto cleanup;
43fe83
     }
43fe83
 
43fe83
+    if (autoPort)
43fe83
+        priv->migrationPort = port;
43fe83
     ret = 0;
43fe83
 
43fe83
 cleanup:
43fe83
@@ -2507,7 +2513,7 @@ qemuMigrationPrepareTunnel(virQEMUDriverPtr driver,
43fe83
 
43fe83
     ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
43fe83
                                   cookieout, cookieoutlen, def, origname,
43fe83
-                                  st, 0, NULL, flags);
43fe83
+                                  st, 0, false, NULL, flags);
43fe83
     return ret;
43fe83
 }
43fe83
 
43fe83
@@ -2526,8 +2532,8 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
43fe83
                            const char *listenAddress,
43fe83
                            unsigned long flags)
43fe83
 {
43fe83
-    static int port = 0;
43fe83
-    int this_port;
43fe83
+    unsigned short port = 0;
43fe83
+    bool autoPort = true;
43fe83
     char *hostname = NULL;
43fe83
     const char *p;
43fe83
     char *uri_str = NULL;
43fe83
@@ -2554,10 +2560,15 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
43fe83
      * to be a correct hostname which refers to the target machine).
43fe83
      */
43fe83
     if (uri_in == NULL) {
43fe83
-        this_port = QEMUD_MIGRATION_FIRST_PORT + port++;
43fe83
-        if (port == QEMUD_MIGRATION_NUM_PORTS) port = 0;
43fe83
+        if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) {
43fe83
+            goto cleanup;
43fe83
+        } else if (!port) {
43fe83
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
43fe83
+                           _("No migration port available within the "
43fe83
+                             "configured range"));
43fe83
+            goto cleanup;
43fe83
+        }
43fe83
 
43fe83
-        /* Get hostname */
43fe83
         if ((hostname = virGetHostname()) == NULL)
43fe83
             goto cleanup;
43fe83
 
43fe83
@@ -2574,7 +2585,7 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
43fe83
          * new targets accept both syntaxes though.
43fe83
          */
43fe83
         /* Caller frees */
43fe83
-        if (virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port) < 0)
43fe83
+        if (virAsprintf(uri_out, "tcp:%s:%d", hostname, port) < 0)
43fe83
             goto cleanup;
43fe83
     } else {
43fe83
         /* Check the URI starts with "tcp:".  We will escape the
43fe83
@@ -2610,17 +2621,22 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
43fe83
         }
43fe83
 
43fe83
         if (uri->port == 0) {
43fe83
-            /* Generate a port */
43fe83
-            this_port = QEMUD_MIGRATION_FIRST_PORT + port++;
43fe83
-            if (port == QEMUD_MIGRATION_NUM_PORTS)
43fe83
-                port = 0;
43fe83
+            if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) {
43fe83
+                goto cleanup;
43fe83
+            } else if (!port) {
43fe83
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
43fe83
+                               _("No migration port available within the "
43fe83
+                                 "configured range"));
43fe83
+                goto cleanup;
43fe83
+            }
43fe83
 
43fe83
             /* Caller frees */
43fe83
-            if (virAsprintf(uri_out, "%s:%d", uri_in, this_port) < 0)
43fe83
+            if (virAsprintf(uri_out, "%s:%d", uri_in, port) < 0)
43fe83
                 goto cleanup;
43fe83
 
43fe83
         } else {
43fe83
-            this_port = uri->port;
43fe83
+            port = uri->port;
43fe83
+            autoPort = false;
43fe83
         }
43fe83
     }
43fe83
 
43fe83
@@ -2629,12 +2645,15 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
43fe83
 
43fe83
     ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
43fe83
                                   cookieout, cookieoutlen, def, origname,
43fe83
-                                  NULL, this_port, listenAddress, flags);
43fe83
+                                  NULL, port, autoPort, listenAddress, flags);
43fe83
 cleanup:
43fe83
     virURIFree(uri);
43fe83
     VIR_FREE(hostname);
43fe83
-    if (ret != 0)
43fe83
+    if (ret != 0) {
43fe83
         VIR_FREE(*uri_out);
43fe83
+        if (autoPort)
43fe83
+            virPortAllocatorRelease(driver->migrationPorts, port);
43fe83
+    }
43fe83
     return ret;
43fe83
 }
43fe83
 
43fe83
@@ -4414,6 +4433,8 @@ qemuMigrationFinish(virQEMUDriverPtr driver,
43fe83
         }
43fe83
 
43fe83
         qemuMigrationStopNBDServer(driver, vm, mig);
43fe83
+        virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort);
43fe83
+        priv->migrationPort = 0;
43fe83
 
43fe83
         if (flags & VIR_MIGRATE_PERSIST_DEST) {
43fe83
             virDomainDefPtr vmdef;
43fe83
-- 
43fe83
1.8.4
43fe83