]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: Avoid assigning unavailable migration ports
authorWang Yufei <james.wangyufei@huawei.com>
Fri, 11 Oct 2013 03:27:13 +0000 (11:27 +0800)
committerJán Tomko <jtomko@redhat.com>
Thu, 9 Jan 2014 13:25:35 +0000 (14:25 +0100)
https://bugzilla.redhat.com/show_bug.cgi?id=1019053

When we migrate vms concurrently, there's a chance that libvirtd on
destination assigns the same port for different migrations, which will
lead to migration failure during prepare phase on destination. So we use
virPortAllocator here to solve the problem.

Signed-off-by: Wang Yufei <james.wangyufei@huawei.com>
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
(cherry picked from commit 0196845d3abd0d914cf11f7ad6c19df8b47c32ed)

Conflicts:
  missing support for WebSockets and listen address
  virAsprintf doesn't report OOM

src/qemu/qemu_command.h
src/qemu/qemu_conf.h
src/qemu/qemu_driver.c
src/qemu/qemu_migration.c

src/qemu/qemu_command.h
src/qemu/qemu_conf.h
src/qemu/qemu_domain.h
src/qemu/qemu_driver.c
src/qemu/qemu_migration.c

index e690dee0513aeee33037bd8d912d65c58f150d08..6c5a6bc7557095a2f52e61c6b43d4ead00e261c0 100644 (file)
@@ -48,6 +48,8 @@
 # define QEMU_REMOTE_PORT_MIN  5900
 # define QEMU_REMOTE_PORT_MAX  65535
 
+# define QEMU_MIGRATION_PORT_MIN 49152
+# define QEMU_MIGRATION_PORT_MAX 49215
 
 virCommandPtr qemuBuildCommandLine(virConnectPtr conn,
                                    virQEMUDriverPtr driver,
index 77d3d2f34936a173588d47c680849c36f67511e1..47fbef8f42192c440ce5c39189935ef29ac57b5c 100644 (file)
@@ -210,6 +210,9 @@ struct _virQEMUDriver {
     /* Immutable pointer, self-locking APIs */
     virPortAllocatorPtr remotePorts;
 
+    /* Immutable pointer, self-locking APIs */
+    virPortAllocatorPtr migrationPorts;
+
     /* Immutable pointer, lockless APIs*/
     virSysinfoDefPtr hostsysinfo;
 
@@ -231,9 +234,6 @@ struct _qemuDomainCmdlineDef {
     char **env_value;
 };
 
-/* Port numbers used for KVM migration. */
-# define QEMUD_MIGRATION_FIRST_PORT 49152
-# define QEMUD_MIGRATION_NUM_PORTS 64
 
 
 virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged);
index d0ae6494068e591c7acf7ed21ab96d1a89cde0b0..7a982edb2a5141c2b26bf85fc28d225c8cce7e52 100644 (file)
@@ -160,6 +160,7 @@ struct _qemuDomainObjPrivate {
     unsigned long migMaxBandwidth;
     char *origname;
     int nbdPort; /* Port used for migration with NBD */
+    unsigned short migrationPort;
 
     virChrdevsPtr devs;
 
index 10e2b86d4cf0fa939c3dd8ad8bca3fc696e794a4..777c6be3b9b0faba3e6d480339243ef8885dcfb2 100644 (file)
@@ -662,6 +662,11 @@ qemuStateInitialize(bool privileged,
                              cfg->remotePortMax)) == NULL)
         goto error;
 
+    if ((qemu_driver->migrationPorts =
+         virPortAllocatorNew(QEMU_MIGRATION_PORT_MIN,
+                             QEMU_MIGRATION_PORT_MAX)) == NULL)
+        goto error;
+
     if (qemuSecurityInit(qemu_driver) < 0)
         goto error;
 
@@ -951,6 +956,7 @@ qemuStateCleanup(void) {
 
     virObjectUnref(qemu_driver->domains);
     virObjectUnref(qemu_driver->remotePorts);
+    virObjectUnref(qemu_driver->migrationPorts);
 
     virObjectUnref(qemu_driver->xmlopt);
 
index f89aa90e7599bc37dc35552a1dbcb5d8f98af544..7d96d17f91ed88fe94c7c930ed4826a11582c9e9 100644 (file)
@@ -1998,6 +1998,9 @@ qemuMigrationPrepareCleanup(virQEMUDriverPtr driver,
               qemuDomainJobTypeToString(priv->job.active),
               qemuDomainAsyncJobTypeToString(priv->job.asyncJob));
 
+    virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort);
+    priv->migrationPort = 0;
+
     if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN))
         return;
     qemuDomainObjDiscardAsyncJob(driver, vm);
@@ -2013,7 +2016,8 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
                         const char *dname,
                         const char *dom_xml,
                         virStreamPtr st,
-                        unsigned int port,
+                        unsigned short port,
+                        bool autoPort,
                         unsigned long flags)
 {
     virDomainDefPtr def = NULL;
@@ -2277,6 +2281,8 @@ done:
         goto cleanup;
     }
 
+    if (autoPort)
+        priv->migrationPort = port;
     ret = 0;
 
 cleanup:
@@ -2340,7 +2346,7 @@ qemuMigrationPrepareTunnel(virQEMUDriverPtr driver,
 
     ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
                                   cookieout, cookieoutlen, dname, dom_xml,
-                                  st, 0, flags);
+                                  st, 0, false, flags);
     return ret;
 }
 
@@ -2358,8 +2364,8 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
                            const char *dom_xml,
                            unsigned long flags)
 {
-    static int port = 0;
-    int this_port;
+    unsigned short port = 0;
+    bool autoPort = true;
     char *hostname = NULL;
     const char *p;
     char *uri_str = NULL;
@@ -2384,8 +2390,14 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
      * to be a correct hostname which refers to the target machine).
      */
     if (uri_in == NULL) {
-        this_port = QEMUD_MIGRATION_FIRST_PORT + port++;
-        if (port == QEMUD_MIGRATION_NUM_PORTS) port = 0;
+        if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) {
+            goto cleanup;
+        } else if (!port) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("No migration port available within the "
+                             "configured range"));
+            goto cleanup;
+        }
 
         /* Get hostname */
         if ((hostname = virGetHostname(NULL)) == NULL)
@@ -2404,7 +2416,7 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
          * new targets accept both syntaxes though.
          */
         /* Caller frees */
-        if (virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port) < 0) {
+        if (virAsprintf(uri_out, "tcp:%s:%d", hostname, port) < 0) {
             virReportOOMError();
             goto cleanup;
         }
@@ -2444,19 +2456,24 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
         }
 
         if (uri->port == 0) {
-            /* Generate a port */
-            this_port = QEMUD_MIGRATION_FIRST_PORT + port++;
-            if (port == QEMUD_MIGRATION_NUM_PORTS)
-                port = 0;
+            if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) {
+                goto cleanup;
+            } else if (!port) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("No migration port available within the "
+                                 "configured range"));
+                goto cleanup;
+            }
 
             /* Caller frees */
-            if (virAsprintf(uri_out, "%s:%d", uri_in, this_port) < 0) {
+            if (virAsprintf(uri_out, "%s:%d", uri_in, port) < 0) {
                 virReportOOMError();
                 goto cleanup;
             }
 
         } else {
-            this_port = uri->port;
+            port = uri->port;
+            autoPort = false;
         }
     }
 
@@ -2465,12 +2482,15 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
 
     ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
                                   cookieout, cookieoutlen, dname, dom_xml,
-                                  NULL, this_port, flags);
+                                  NULL, port, autoPort, flags);
 cleanup:
     virURIFree(uri);
     VIR_FREE(hostname);
-    if (ret != 0)
+    if (ret != 0) {
         VIR_FREE(*uri_out);
+        if (autoPort)
+            virPortAllocatorRelease(driver->migrationPorts, port);
+    }
     return ret;
 }
 
@@ -3962,6 +3982,8 @@ qemuMigrationFinish(virQEMUDriverPtr driver,
         }
 
         qemuMigrationStopNBDServer(driver, vm, mig);
+        virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort);
+        priv->migrationPort = 0;
 
         if (flags & VIR_MIGRATE_PERSIST_DEST) {
             virDomainDefPtr vmdef;