Outgoing migration still has to use a Unix socket and or exec netcat,
since there is no way to pass a migration fd into qemu via monitor
commands, but incoming migration need not suffer from the complexity.
* src/qemu/qemu_driver.c (qemudDomainMigratePrepareTunnel):
Replace Unix socket with simpler pipe.
Suggested by Paolo Bonzini.
---
I've since been corrected; qemu_monitor.c has qemuMonitorIOWriteWithFD
that looks like it can be used to avoid exec: on outgoing migrations
by instead passing an open fd over a unix socket, although I have not
tested that yet. However, this patch does not need to be held up by
waiting for the followup patch that optimizes outgoing migrations.
src/qemu/qemu_driver.c | 49 +++++++++++++++--------------------------------
1 files changed, 16 insertions(+), 33 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a82392e..8cb05b7 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7925,11 +7925,10 @@ qemudDomainMigratePrepareTunnel(virConnectPtr dconn,
struct qemud_driver *driver = dconn->privateData;
virDomainDefPtr def = NULL;
virDomainObjPtr vm = NULL;
- char *migrateFrom;
virDomainEventPtr event = NULL;
int ret = -1;
int internalret;
- char *unixfile = NULL;
+ int dataFD[2] = { -1, -1 };
unsigned long long qemuCmdFlags;
qemuDomainObjPrivatePtr priv = NULL;
struct timeval now;
@@ -7995,39 +7994,27 @@ qemudDomainMigratePrepareTunnel(virConnectPtr dconn,
/* Domain starts inactive, even if the domain XML had an id field. */
vm->def->id = -1;
- if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.dest.%s",
- driver->libDir, vm->def->name) < 0) {
- virReportOOMError();
+ if (pipe(dataFD) < 0) {
+ virReportSystemError(errno, "%s",
+ _("cannot create pipe for tunnelled migration"));
goto endjob;
}
- unlink(unixfile);
/* check that this qemu version supports the interactive exec */
- if (qemuCapsExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) <
0) {
+ if (qemuCapsExtractVersionInfo(vm->def->emulator, NULL,
+ &qemuCmdFlags) < 0) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("Cannot determine QEMU argv syntax %s"),
vm->def->emulator);
goto endjob;
}
- if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX)
- internalret = virAsprintf(&migrateFrom, "unix:%s", unixfile);
- else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)
- internalret = virAsprintf(&migrateFrom, "exec:nc -U -l %s",
unixfile);
- else {
- qemuReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("Destination qemu is too old to support
tunnelled migration"));
- goto endjob;
- }
- if (internalret < 0) {
- virReportOOMError();
- goto endjob;
- }
+
/* Start the QEMU daemon, with the same command-line arguments plus
- * -incoming unix:/path/to/file or exec:nc -U /path/to/file
+ * -incoming stdin (which qemu_command might convert to exec:cat or fd:n)
*/
- internalret = qemudStartVMDaemon(dconn, driver, vm, migrateFrom, true,
- -1, NULL, VIR_VM_OP_MIGRATE_IN_START);
- VIR_FREE(migrateFrom);
+ internalret = qemudStartVMDaemon(dconn, driver, vm, "stdin", true,
+ dataFD[1], NULL,
+ VIR_VM_OP_MIGRATE_IN_START);
if (internalret < 0) {
qemuDomainStartAudit(vm, "migrated", false);
/* Note that we don't set an error here because qemudStartVMDaemon
@@ -8040,9 +8027,7 @@ qemudDomainMigratePrepareTunnel(virConnectPtr dconn,
goto endjob;
}
- if (virFDStreamConnectUNIX(st,
- unixfile,
- false) < 0) {
+ if (virFDStreamOpen(st, dataFD[0]) < 0) {
qemuDomainStartAudit(vm, "migrated", false);
qemudShutdownVMDaemon(driver, vm, 0);
if (!vm->persistent) {
@@ -8050,9 +8035,8 @@ qemudDomainMigratePrepareTunnel(virConnectPtr dconn,
virDomainRemoveInactive(&driver->domains, vm);
vm = NULL;
}
- virReportSystemError(errno,
- _("cannot open unix socket '%s' for tunnelled
migration"),
- unixfile);
+ virReportSystemError(errno, "%s",
+ _("cannot pass pipe for tunnelled migration"));
goto endjob;
}
@@ -8082,9 +8066,8 @@ endjob:
cleanup:
virDomainDefFree(def);
- if (unixfile)
- unlink(unixfile);
- VIR_FREE(unixfile);
+ VIR_FORCE_CLOSE(dataFD[0]);
+ VIR_FORCE_CLOSE(dataFD[1]);
if (vm)
virDomainObjUnlock(vm);
if (event)
--
1.7.3.4