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

Daniel Veillard veillard at redhat.com
Mon Aug 15 10:04:07 UTC 2011


On Mon, Aug 15, 2011 at 09:58:16AM +0200, Jiri Denemark wrote:
> 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);

  Hum, I find dubious that we set up fd variable before
calling qemuMonitorMigrateToFd but don't use that variable, smells fishy
but I could be wrong since I don't get the full function context, so
to double check.

> +        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;
>  }

  Okay, I guess the best is to apply and run the verious test suites on
it ! Out of curiosity did you ran dan's migration suite with those
patches ?

  ACK,

Daniel

-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
daniel at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/




More information about the libvir-list mailing list