]> 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)
committerJiri Denemark <jdenemar@redhat.com>
Fri, 18 Oct 2013 14:34:09 +0000 (16:34 +0200)
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>
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 2e2acfb326ef2e9e06bdd89fbaa6c4cb395366e4..3277ba4a8e98f7ab956efbcf4192f49e3ad49c83 100644 (file)
@@ -51,6 +51,9 @@
 # define QEMU_WEBSOCKET_PORT_MIN  5700
 # define QEMU_WEBSOCKET_PORT_MAX  65535
 
+# define QEMU_MIGRATION_PORT_MIN 49152
+# define QEMU_MIGRATION_PORT_MAX 49215
+
 typedef struct _qemuBuildCommandLineCallbacks qemuBuildCommandLineCallbacks;
 typedef qemuBuildCommandLineCallbacks *qemuBuildCommandLineCallbacksPtr;
 struct _qemuBuildCommandLineCallbacks {
index d8304af93c35aaf5568fb3a8e889ebfc6af014d8..c6fbaa56edf841e8f9105ae96ef8fa2efa7dfba3 100644 (file)
@@ -227,6 +227,9 @@ struct _virQEMUDriver {
     /* Immutable pointer, self-locking APIs */
     virPortAllocatorPtr webSocketPorts;
 
+    /* Immutable pointer, self-locking APIs */
+    virPortAllocatorPtr migrationPorts;
+
     /* Immutable pointer, lockless APIs*/
     virSysinfoDefPtr hostsysinfo;
 
@@ -248,9 +251,6 @@ struct _qemuDomainCmdlineDef {
     char **env_value;
 };
 
-/* Port numbers used for KVM migration. */
-# define QEMUD_MIGRATION_FIRST_PORT 49152
-# define QEMUD_MIGRATION_NUM_PORTS 64
 
 
 void qemuDomainCmdlineDefFree(qemuDomainCmdlineDefPtr def);
index 5d9fab924b5212174e1cf3dbbe5855283e765a3e..77e0c20171ed5261751686997865c409f19722d9 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 746da261a324ee656eefa21a4ac8af7455494b2c..895681b60bc8eaf006fbf509b737ab11e1936e56 100644 (file)
@@ -687,6 +687,11 @@ qemuStateInitialize(bool privileged,
                              cfg->webSocketPortMax)) == 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;
 
@@ -993,6 +998,7 @@ qemuStateCleanup(void) {
     virObjectUnref(qemu_driver->domains);
     virObjectUnref(qemu_driver->remotePorts);
     virObjectUnref(qemu_driver->webSocketPorts);
+    virObjectUnref(qemu_driver->migrationPorts);
 
     virObjectUnref(qemu_driver->xmlopt);
 
index 38edadb9742dd787f1cc58008f45ae1da6c032ac..0439ba4323556978db624c04faf254a634d6dc14 100644 (file)
@@ -2141,6 +2141,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);
@@ -2156,7 +2159,8 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
                         virDomainDefPtr *def,
                         const char *origname,
                         virStreamPtr st,
-                        unsigned int port,
+                        unsigned short port,
+                        bool autoPort,
                         const char *listenAddress,
                         unsigned long flags)
 {
@@ -2436,6 +2440,8 @@ done:
         goto cleanup;
     }
 
+    if (autoPort)
+        priv->migrationPort = port;
     ret = 0;
 
 cleanup:
@@ -2503,7 +2509,7 @@ qemuMigrationPrepareTunnel(virQEMUDriverPtr driver,
 
     ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
                                   cookieout, cookieoutlen, def, origname,
-                                  st, 0, NULL, flags);
+                                  st, 0, false, NULL, flags);
     return ret;
 }
 
@@ -2522,8 +2528,8 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
                            const char *listenAddress,
                            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;
@@ -2550,10 +2556,15 @@ 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)
             goto cleanup;
 
@@ -2570,7 +2581,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)
             goto cleanup;
     } else {
         /* Check the URI starts with "tcp:".  We will escape the
@@ -2606,17 +2617,22 @@ 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)
                 goto cleanup;
 
         } else {
-            this_port = uri->port;
+            port = uri->port;
+            autoPort = false;
         }
     }
 
@@ -2625,12 +2641,15 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
 
     ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
                                   cookieout, cookieoutlen, def, origname,
-                                  NULL, this_port, listenAddress, flags);
+                                  NULL, port, autoPort, listenAddress, 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;
 }
 
@@ -4410,6 +4429,8 @@ qemuMigrationFinish(virQEMUDriverPtr driver,
         }
 
         qemuMigrationStopNBDServer(driver, vm, mig);
+        virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort);
+        priv->migrationPort = 0;
 
         if (flags & VIR_MIGRATE_PERSIST_DEST) {
             virDomainDefPtr vmdef;