[libvirt] [PATCH 6/6] qemu: Use fd: protocol for migration

Jiri Denemark jdenemar at redhat.com
Mon Aug 15 07:58:16 UTC 2011


By opening a connection to remote qemu process ourselves and passing the
socket to qemu we get much better errors than just "migration failed"
when the connection is opened by qemu.
---
 src/qemu/qemu_migration.c |  128 ++++++++++++++++++++++++++++++++++-----------
 1 files changed, 98 insertions(+), 30 deletions(-)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index c29ea9e..537e57e 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1269,6 +1269,7 @@ cleanup:
 enum qemuMigrationDestinationType {
     MIGRATION_DEST_HOST,
     MIGRATION_DEST_UNIX,
+    MIGRATION_DEST_FD,
 };
 
 enum qemuMigrationForwardType {
@@ -1287,9 +1288,14 @@ struct _qemuMigrationSpec {
         } host;
 
         struct {
-            const char *file;
+            char *file;
             int sock;
         } unics; /* this sucks but "unix" is a macro defined to 1 */
+
+        struct {
+            int qemu;
+            int local;
+        } fd;
     } dest;
 
     enum qemuMigrationForwardType fwdType;
@@ -1472,6 +1478,14 @@ qemuMigrationRun(struct qemud_driver *driver,
             ret = qemuMonitorMigrateToCommand(priv->mon, migrate_flags, args);
         }
         break;
+
+    case MIGRATION_DEST_FD:
+        if (spec->fwdType != MIGRATION_FWD_DIRECT)
+            fd = spec->dest.fd.local;
+        ret = qemuMonitorMigrateToFd(priv->mon, migrate_flags,
+                                     spec->dest.fd.qemu);
+        VIR_FORCE_CLOSE(spec->dest.fd.qemu);
+        break;
     }
     qemuDomainObjExitMonitorWithDriver(driver, vm);
     if (ret < 0)
@@ -1568,9 +1582,11 @@ static int doNativeMigrate(struct qemud_driver *driver,
                            unsigned int flags,
                            unsigned long resource)
 {
+    qemuDomainObjPrivatePtr priv = vm->privateData;
     xmlURIPtr uribits = NULL;
-    int ret;
+    int ret = -1;
     qemuMigrationSpec spec;
+    char *tmp = NULL;
 
     VIR_DEBUG("driver=%p, vm=%p, uri=%s, cookiein=%s, cookieinlen=%d, "
               "cookieout=%p, cookieoutlen=%p, flags=%x, resource=%lu",
@@ -1579,13 +1595,12 @@ static int doNativeMigrate(struct qemud_driver *driver,
 
     if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) {
         /* HACK: source host generates bogus URIs, so fix them up */
-        char *tmpuri;
-        if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) {
+        if (virAsprintf(&tmp, "tcp://%s", uri + strlen("tcp:")) < 0) {
             virReportOOMError();
             return -1;
         }
-        uribits = xmlParseURI(tmpuri);
-        VIR_FREE(tmpuri);
+        uribits = xmlParseURI(tmp);
+        VIR_FREE(tmp);
     } else {
         uribits = xmlParseURI(uri);
     }
@@ -1595,13 +1610,38 @@ static int doNativeMigrate(struct qemud_driver *driver,
         return -1;
     }
 
-    spec.destType = MIGRATION_DEST_HOST;
-    spec.dest.host.name = uribits->server;
-    spec.dest.host.port = uribits->port;
     spec.fwdType = MIGRATION_FWD_DIRECT;
 
+    if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD)) {
+        virNetSocketPtr sock;
+
+        spec.destType = MIGRATION_DEST_FD;
+        spec.dest.fd.qemu = -1;
+
+        if (virAsprintf(&tmp, "%d", uribits->port) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+        if (virNetSocketNewConnectTCP(uribits->server, tmp, &sock) == 0) {
+            spec.dest.fd.qemu = virNetSocketDupFD(sock, true);
+            virNetSocketFree(sock);
+        }
+        if (spec.dest.fd.qemu == -1)
+            goto cleanup;
+    } else {
+        spec.destType = MIGRATION_DEST_HOST;
+        spec.dest.host.name = uribits->server;
+        spec.dest.host.port = uribits->port;
+    }
+
     ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout,
                            cookieoutlen, flags, resource, &spec);
+
+cleanup:
+    if (spec.destType == MIGRATION_DEST_FD)
+        VIR_FORCE_CLOSE(spec.dest.fd.qemu);
+
+    VIR_FREE(tmp);
     xmlFreeURI(uribits);
 
     return ret;
@@ -1619,7 +1659,6 @@ static int doTunnelMigrate(struct qemud_driver *driver,
                            unsigned long resource)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
-    char *unixfile = NULL;
     virNetSocketPtr sock = NULL;
     int ret = -1;
     qemuMigrationSpec spec;
@@ -1629,36 +1668,65 @@ static int doTunnelMigrate(struct qemud_driver *driver,
               driver, vm, st, NULLSTR(cookiein), cookieinlen,
               cookieout, cookieoutlen, flags, resource);
 
-    if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_UNIX) &&
+    if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD) &&
+        !qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_UNIX) &&
         !qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_EXEC)) {
-        qemuReportError(VIR_ERR_OPERATION_FAILED,
-                        "%s", _("Source qemu is too old to support tunnelled migration"));
-        goto cleanup;
-    }
-
-    if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.src.%s",
-                    driver->libDir, vm->def->name) < 0) {
-        virReportOOMError();
-        goto cleanup;
+        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                        _("Source qemu is too old to support tunnelled migration"));
+        return -1;
     }
 
-    if (virNetSocketNewListenUNIX(unixfile, 0700,
-                                  driver->user, driver->group, &sock) < 0 ||
-        virNetSocketListen(sock, 1) < 0)
-        goto cleanup;
-
-    spec.destType = MIGRATION_DEST_UNIX;
-    spec.dest.unics.file = unixfile;
-    spec.dest.unics.sock = virNetSocketGetFD(sock);
     spec.fwdType = MIGRATION_FWD_STREAM;
     spec.fwd.stream = st;
 
+    if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD)) {
+        int fds[2];
+
+        spec.destType = MIGRATION_DEST_FD;
+        spec.dest.fd.qemu = -1;
+        spec.dest.fd.local = -1;
+
+        if (pipe(fds) == 0) {
+            spec.dest.fd.qemu = fds[1];
+            spec.dest.fd.local = fds[0];
+        }
+        if (spec.dest.fd.qemu == -1 ||
+            virSetCloseExec(spec.dest.fd.qemu) < 0 ||
+            virSetCloseExec(spec.dest.fd.local) < 0) {
+            virReportSystemError(errno, "%s",
+                        _("cannot create pipe for tunnelled migration"));
+            goto cleanup;
+        }
+    } else {
+        spec.destType = MIGRATION_DEST_UNIX;
+        spec.dest.unics.sock = -1;
+        spec.dest.unics.file = NULL;
+
+        if (virAsprintf(&spec.dest.unics.file, "%s/qemu.tunnelmigrate.src.%s",
+                        driver->libDir, vm->def->name) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (virNetSocketNewListenUNIX(spec.dest.unics.file, 0700, driver->user,
+                                      driver->group, &sock) < 0 ||
+            virNetSocketListen(sock, 1) < 0)
+            goto cleanup;
+
+        spec.dest.unics.sock = virNetSocketGetFD(sock);
+    }
+
     ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout,
                            cookieoutlen, flags, resource, &spec);
 
 cleanup:
-    virNetSocketFree(sock);
-    VIR_FREE(unixfile);
+    if (spec.destType == MIGRATION_DEST_FD) {
+        VIR_FORCE_CLOSE(spec.dest.fd.qemu);
+        VIR_FORCE_CLOSE(spec.dest.fd.local);
+    } else {
+        virNetSocketFree(sock);
+        VIR_FREE(spec.dest.unics.file);
+    }
 
     return ret;
 }
-- 
1.7.6




More information about the libvir-list mailing list