File libvirt-qemu-Allow-migration-over-IPv6.patch of Package libvirt

From 0b439ce200a50d1a9664c4f724c6b52d12962412 Mon Sep 17 00:00:00 2001
Message-Id: <0b439ce200a50d1a9664c4f724c6b52d12962412.1373271640.git.jdenemar@redhat.com>
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
Date: Wed, 10 Apr 2013 18:09:17 +0200
Subject: [PATCH] qemu: Allow migration over IPv6

https://bugzilla.redhat.com/show_bug.cgi?id=846013

Allow migration over IPv6 by listening on [::] instead of 0.0.0.0
when QEMU supports it (QEMU_CAPS_IPV6_MIGRATION) and there is
at least one v6 address configured on the system.

Use virURIParse in qemuMigrationPrepareDirect to allow parsing
IPv6 addresses, which would cause an 'incorrect :port' error
message before.

Move setting of migrateFrom from qemuMigrationPrepare{Direct,Tunnel}
after domain XML parsing, since we need the QEMU binary path from it
to get its capabilities.

(cherry picked from commit f03dcc5df141370c09da93135ad2f921c0af55b9)

Conflicts:
	src/qemu/qemu_capabilities.c [1][2]
	src/qemu/qemu_capabilities.h [1]
	src/qemu/qemu_migration.c [2][3]
	tests/qemuhelptest.c [1]

[1] different QEMU_CAPS set upstream and on RHEL
[2] qemuCaps -> virQEMUCaps change
[3] upstream has NBD support
---
 src/qemu/qemu_capabilities.c |   4 ++
 src/qemu/qemu_capabilities.h |   1 +
 src/qemu/qemu_migration.c    | 100 +++++++++++++++++++++++++++++++++----------
 tests/qemuhelptest.c         |   6 ++-
 4 files changed, 87 insertions(+), 24 deletions(-)

diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 65ce0a3..66795a7 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -197,6 +197,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
               "cirrus-vga",
               "vmware-svga",
               "device-video-primary",
+              "ipv6-migration",
     );
 
 struct _qemuCaps {
@@ -1141,6 +1142,9 @@ qemuCapsComputeCmdFlags(const char *help,
     if (version >= 11000)
         qemuCapsSet(caps, QEMU_CAPS_CPU_HOST);
 
+    if (version >= 1001000)
+        qemuCapsSet(caps, QEMU_CAPS_IPV6_MIGRATION);
+
     if (version >= 1002000)
         qemuCapsSet(caps, QEMU_CAPS_DEVICE_VIDEO_PRIMARY);
     return 0;
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index be53b26..2451a09 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -164,6 +164,7 @@ enum qemuCapsFlags {
     QEMU_CAPS_DEVICE_VMWARE_SVGA,       /* -device vmware-svga */
     QEMU_CAPS_DEVICE_VIDEO_PRIMARY,     /* safe to use -device XXX
                                            for primary video device */
+    QEMU_CAPS_IPV6_MIGRATION,           /* -incoming [::] */
 
     QEMU_CAPS_LAST,                   /* this must always be the last item */
 };
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index beeea3e..938c222 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -21,6 +21,8 @@
 
 #include <config.h>
 
+#include <netdb.h>
+#include <sys/socket.h>
 #include <sys/time.h>
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
@@ -1246,8 +1248,8 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
                         int *cookieoutlen,
                         const char *dname,
                         const char *dom_xml,
-                        const char *migrateFrom,
-                        virStreamPtr st)
+                        virStreamPtr st,
+                        unsigned int port)
 {
     virDomainDefPtr def = NULL;
     virDomainObjPtr vm = NULL;
@@ -1260,6 +1262,8 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
     bool tunnel = !!st;
     char *origname = NULL;
     char *xmlout = NULL;
+    const char *listenAddr = NULL;
+    char *migrateFrom = NULL;
 
     if (virTimeMillisNow(&now) < 0)
         return -1;
@@ -1322,6 +1326,45 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
         }
     }
 
+    if (tunnel) {
+        /* QEMU will be started with -incoming stdio
+         * (which qemu_command might convert to exec:cat or fd:n)
+         */
+        if (!(migrateFrom = strdup("stdio"))) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    } else {
+        qemuCapsPtr caps = NULL;
+        struct addrinfo *info = NULL;
+        struct addrinfo hints = { .ai_flags = AI_ADDRCONFIG,
+                                  .ai_socktype = SOCK_STREAM };
+
+        if (!(caps = qemuCapsCacheLookupCopy(driver->capsCache,
+                                             def->emulator)))
+            goto cleanup;
+
+        /* Listen on :: instead of 0.0.0.0 if QEMU understands it
+         * and there is at least one IPv6 address configured
+         */
+        if (qemuCapsGet(caps, QEMU_CAPS_IPV6_MIGRATION) &&
+            getaddrinfo("::", NULL, &hints, &info) == 0) {
+            freeaddrinfo(info);
+            listenAddr = "[::]";
+        } else {
+            listenAddr = "0.0.0.0";
+        }
+        virObjectUnref(caps);
+
+        /* QEMU will be started with -incoming [::]:port
+         * or -incoming 0.0.0.0:port
+         */
+        if (virAsprintf(&migrateFrom, "tcp:%s:%d", listenAddr, port) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
     if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
         goto cleanup;
 
@@ -1419,6 +1462,7 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
     ret = 0;
 
 cleanup:
+    VIR_FREE(migrateFrom);
     VIR_FREE(origname);
     VIR_FREE(xmlout);
     virDomainDefFree(def);
@@ -1465,12 +1509,9 @@ qemuMigrationPrepareTunnel(struct qemud_driver *driver,
               driver, dconn, NULLSTR(cookiein), cookieinlen,
               cookieout, cookieoutlen, st, NULLSTR(dname), dom_xml);
 
-    /* QEMU will be started with -incoming stdio (which qemu_command might
-     * convert to exec:cat or fd:n)
-     */
     ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
                                   cookieout, cookieoutlen, dname, dom_xml,
-                                  "stdio", st);
+                                  st, 0);
     return ret;
 }
 
@@ -1490,9 +1531,10 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver,
     static int port = 0;
     int this_port;
     char *hostname = NULL;
-    char migrateFrom [64];
     const char *p;
+    char *uri_str = NULL;
     int ret = -1;
+    virURIPtr uri;
 
     VIR_DEBUG("driver=%p, dconn=%p, cookiein=%s, cookieinlen=%d, "
               "cookieout=%p, cookieoutlen=%p, uri_in=%s, uri_out=%p, "
@@ -1541,16 +1583,39 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver,
          * URI when passing it to the qemu monitor, so bad
          * characters in hostname part don't matter.
          */
-        if (!STRPREFIX (uri_in, "tcp:")) {
+        if (!(p = STRSKIP(uri_in, "tcp:"))) {
             virReportError(VIR_ERR_INVALID_ARG, "%s",
                            _("only tcp URIs are supported for KVM/QEMU"
                              " migrations"));
             goto cleanup;
         }
 
-        /* Get the port number. */
-        p = strrchr (uri_in, ':');
-        if (p == strchr(uri_in, ':')) {
+        /* Convert uri_in to well-formed URI with // after tcp: */
+        if (!(STRPREFIX(uri_in, "tcp://"))) {
+            if (virAsprintf(&uri_str, "tcp://%s", p) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+        }
+
+        uri = virURIParse(uri_str ? uri_str : uri_in);
+        VIR_FREE(uri_str);
+
+        if (uri == NULL) {
+            virReportError(VIR_ERR_INVALID_ARG, _("unable to parse URI: %s"),
+                           uri_in);
+            goto cleanup;
+        }
+
+        if (uri->server == NULL) {
+            virReportError(VIR_ERR_INVALID_ARG, _("missing host in migration"
+                                                  " URI: %s"), uri_in);
+            goto cleanup;
+        } else {
+            hostname = uri->server;
+        }
+
+        if (uri->port == 0) {
             /* Generate a port */
             this_port = QEMUD_MIGRATION_FIRST_PORT + port++;
             if (port == QEMUD_MIGRATION_NUM_PORTS)
@@ -1563,25 +1628,16 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver,
             }
 
         } else {
-            p++; /* definitely has a ':' in it, see above */
-            this_port = virParseNumber (&p);
-            if (this_port == -1 || p-uri_in != strlen (uri_in)) {
-                virReportError(VIR_ERR_INVALID_ARG,
-                               "%s", _("URI ended with incorrect ':port'"));
-                goto cleanup;
-            }
+            this_port = uri->port;
         }
     }
 
     if (*uri_out)
         VIR_DEBUG("Generated uri_out=%s", *uri_out);
 
-    /* QEMU will be started with -incoming tcp:0.0.0.0:port */
-    snprintf(migrateFrom, sizeof(migrateFrom), "tcp:0.0.0.0:%d", this_port);
-
     ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen,
                                   cookieout, cookieoutlen, dname, dom_xml,
-                                  migrateFrom, NULL);
+                                  NULL, this_port);
 cleanup:
     VIR_FREE(hostname);
     if (ret != 0)
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
index 270ed16..0724a05 100644
--- a/tests/qemuhelptest.c
+++ b/tests/qemuhelptest.c
@@ -789,7 +789,8 @@ mymain(void)
             QEMU_CAPS_DEVICE_QXL,
             QEMU_CAPS_DEVICE_VGA,
             QEMU_CAPS_DEVICE_CIRRUS_VGA,
-            QEMU_CAPS_DEVICE_VMWARE_SVGA);
+            QEMU_CAPS_DEVICE_VMWARE_SVGA,
+            QEMU_CAPS_IPV6_MIGRATION);
     DO_TEST("qemu-1.2.0", 1002000, 0, 0,
             QEMU_CAPS_VNC_COLON,
             QEMU_CAPS_NO_REBOOT,
@@ -877,7 +878,8 @@ mymain(void)
             QEMU_CAPS_DEVICE_VGA,
             QEMU_CAPS_DEVICE_CIRRUS_VGA,
             QEMU_CAPS_DEVICE_VMWARE_SVGA,
-            QEMU_CAPS_DEVICE_VIDEO_PRIMARY);
+            QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
+            QEMU_CAPS_IPV6_MIGRATION);
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
-- 
1.8.2.1

openSUSE Build Service is sponsored by