QEMU already supports migration using a file descriptor that is passed to QEMU. As of now, libvirt, uses this path via the tunnelled migration approach, where libvirt creates a set of fds from a pipe, passes those fds to QEMU, and migrates the VM.
This patch introduces supports for fd based live migrations in libvirt, where the fds are opened and given to libvirt by the client. Clients are expected to pass the FDs on both source and destination libvirt, via the virDomainFDStore API, with the "fd" key being the domain UUID. If the URI of the migration has been set to "fd", libvirt will try to look for an FD passed to it via the client meant for migrating the VM, and will pass on that FD to QEMU and trigger the migration. Signed-off-by: Tejus GK <[email protected]> --- src/qemu/qemu_migration.c | 114 +++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 0cd417c15d..66e1236e6c 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -38,6 +38,7 @@ #include "qemu_security.h" #include "qemu_slirp.h" #include "qemu_block.h" +#include "qemu_fd.h" #include "qemu_tpm.h" #include "qemu_vhost_user.h" @@ -3137,6 +3138,8 @@ qemuMigrationDstPrepare(virQEMUDriver *driver, if (tunnel) { migrateFrom = g_strdup("stdio"); + } else if (g_strcmp0(protocol, "fd") == 0) { + migrateFrom = g_strdup("fd"); } else if (g_strcmp0(protocol, "unix") == 0) { migrateFrom = g_strdup_printf("%s:%s", protocol, listenAddress); } else { @@ -3301,6 +3304,8 @@ qemuMigrationDstPrepareActive(virQEMUDriver *driver, unsigned int startFlags; bool relabel = false; bool tunnel = !!st; + bool useDestFD = STREQ_NULLABLE(protocol, "fd"); + int destfd = -1; int ret = -1; int rv; @@ -3319,6 +3324,37 @@ qemuMigrationDstPrepareActive(virQEMUDriver *driver, virPipe(dataFD) < 0) goto error; + if (useDestFD) { + qemuFDTuple *fdtuple = NULL; + const char *fdName = vm->def->uuid; + + VIR_WITH_MUTEX_LOCK_GUARD(&driver->lock) { + fdtuple = g_hash_table_lookup(driver->domainFDs, fdName); + if (!fdtuple) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("no file descriptor stored for migration of domain '%1$s'"), + fdName); + goto error; + } + + if (fdtuple->nfds != 1) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("expected a single file descriptor for migration of domain '%1$s'"), + fdName); + goto error; + } + + if ((destfd = dup(fdtuple->fds[0])) < 0) { + virReportSystemError(errno, + _("failed to duplicate migration FD for domain '%1$s'"), + fdName); + goto error; + } + + g_hash_table_remove(driver->domainFDs, fdName); + } + } + startFlags = VIR_QEMU_PROCESS_START_AUTODESTROY; if (qemuProcessInit(driver, vm, mig->cpu, VIR_ASYNC_JOB_MIGRATION_IN, @@ -3328,7 +3364,7 @@ qemuMigrationDstPrepareActive(virQEMUDriver *driver, if (!(incoming = qemuMigrationDstPrepare(driver, vm, tunnel, protocol, listenAddress, port, - &dataFD[0]))) + useDestFD ? destfd : dataFD[0]))) goto error; qemuMigrationDstPrepareDiskSeclabels(vm, migrate_disks, flags); @@ -3437,6 +3473,7 @@ qemuMigrationDstPrepareActive(virQEMUDriver *driver, cleanup: qemuProcessIncomingDefFree(incoming); + VIR_FORCE_CLOSE(destfd); VIR_FORCE_CLOSE(dataFD[0]); VIR_FORCE_CLOSE(dataFD[1]); virObjectEventStateQueue(driver->domainEventState, event); @@ -3974,7 +4011,8 @@ qemuMigrationDstPrepareDirect(virQEMUDriver *driver, if (STRNEQ(uri->scheme, "tcp") && STRNEQ(uri->scheme, "rdma") && - STRNEQ(uri->scheme, "unix")) { + STRNEQ(uri->scheme, "unix") && + STRNEQ(uri->scheme, "fd")) { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, _("unsupported scheme %1$s in migration URI %2$s"), uri->scheme, uri_in); @@ -3984,6 +4022,9 @@ qemuMigrationDstPrepareDirect(virQEMUDriver *driver, if (STREQ(uri->scheme, "unix")) { autoPort = false; listenAddress = uri->path; + } else if (STREQ(uri->scheme, "fd")) { + autoPort = false; + listenAddress = NULL; } else { if (uri->server == NULL) { virReportError(VIR_ERR_INVALID_ARG, @@ -5411,6 +5452,75 @@ qemuMigrationSrcPerformNative(virQEMUDriver *driver, spec.destType = MIGRATION_DEST_CONNECT_SOCKET; spec.dest.socket.path = uribits->path; + } else if (STREQ(uribits->scheme, "fd")) { + + if (flags & VIR_MIGRATE_PARALLEL) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("FD-based migration is not supported with multi-fd migrations")); + return -1; + } + + if (flags & VIR_MIGRATE_POSTCOPY) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("FD-based migration is not supported with post-copy migration")); + return -1; + } + if (flags & VIR_MIGRATE_POSTCOPY_RESUME) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("FD-based migration is not supported with post-copy resume")); + return -1; + } + if (flags & VIR_MIGRATE_ZEROCOPY) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("FD-based migration is not supported with zero-copy migration")); + return -1; + } + + if (flags & VIR_MIGRATE_TLS) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("FD-based migration is not supported with TLS migration")); + return -1; + } + + qemuFDTuple *fdtuple = NULL; + const char *fdName = vm->def->uuid; + int srcfd = -1; + + VIR_WITH_MUTEX_LOCK_GUARD(&driver->lock) { + fdtuple = g_hash_table_lookup(driver->domainFDs, fdName); + if (!fdtuple) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("no file descriptor stored for migration of domain '%1$s'"), + fdName); + return -1; + } + + if (fdtuple->nfds != 1) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("expected a single file descriptor for migration of domain '%1$s'"), + fdName); + return -1; + } + + if ((srcfd = dup(fdtuple->fds[0])) < 0) { + virReportSystemError(errno, + _("failed to duplicate migration FD for domain '%1$s'"), + fdName); + return -1; + } + + g_hash_table_remove(driver->domainFDs, fdName); + } + + if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, srcfd) < 0) { + VIR_FORCE_CLOSE(srcfd); + return -1; + } + + spec.destType = MIGRATION_DEST_FD; + spec.dest.fd.qemu = srcfd; + spec.dest.fd.local = -1; + } else { /* RDMA, multi-fd, and postcopy-preempt migration require QEMU to * connect to the destination itself. -- 2.43.7
