mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-20 06:50:22 +03:00
qemu: Use fd: protocol for migration
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.
This commit is contained in:
parent
e8989ae4e2
commit
3261761794
@ -1269,6 +1269,7 @@ cleanup:
|
|||||||
enum qemuMigrationDestinationType {
|
enum qemuMigrationDestinationType {
|
||||||
MIGRATION_DEST_HOST,
|
MIGRATION_DEST_HOST,
|
||||||
MIGRATION_DEST_UNIX,
|
MIGRATION_DEST_UNIX,
|
||||||
|
MIGRATION_DEST_FD,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum qemuMigrationForwardType {
|
enum qemuMigrationForwardType {
|
||||||
@ -1287,9 +1288,14 @@ struct _qemuMigrationSpec {
|
|||||||
} host;
|
} host;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
const char *file;
|
char *file;
|
||||||
int sock;
|
int sock;
|
||||||
} unix_socket;
|
} unix_socket;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int qemu;
|
||||||
|
int local;
|
||||||
|
} fd;
|
||||||
} dest;
|
} dest;
|
||||||
|
|
||||||
enum qemuMigrationForwardType fwdType;
|
enum qemuMigrationForwardType fwdType;
|
||||||
@ -1481,6 +1487,14 @@ qemuMigrationRun(struct qemud_driver *driver,
|
|||||||
ret = qemuMonitorMigrateToCommand(priv->mon, migrate_flags, args);
|
ret = qemuMonitorMigrateToCommand(priv->mon, migrate_flags, args);
|
||||||
}
|
}
|
||||||
break;
|
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);
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -1577,9 +1591,11 @@ static int doNativeMigrate(struct qemud_driver *driver,
|
|||||||
unsigned long flags,
|
unsigned long flags,
|
||||||
unsigned long resource)
|
unsigned long resource)
|
||||||
{
|
{
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
xmlURIPtr uribits = NULL;
|
xmlURIPtr uribits = NULL;
|
||||||
int ret;
|
int ret = -1;
|
||||||
qemuMigrationSpec spec;
|
qemuMigrationSpec spec;
|
||||||
|
char *tmp = NULL;
|
||||||
|
|
||||||
VIR_DEBUG("driver=%p, vm=%p, uri=%s, cookiein=%s, cookieinlen=%d, "
|
VIR_DEBUG("driver=%p, vm=%p, uri=%s, cookiein=%s, cookieinlen=%d, "
|
||||||
"cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu",
|
"cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu",
|
||||||
@ -1588,13 +1604,12 @@ static int doNativeMigrate(struct qemud_driver *driver,
|
|||||||
|
|
||||||
if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) {
|
if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) {
|
||||||
/* HACK: source host generates bogus URIs, so fix them up */
|
/* HACK: source host generates bogus URIs, so fix them up */
|
||||||
char *tmpuri;
|
if (virAsprintf(&tmp, "tcp://%s", uri + strlen("tcp:")) < 0) {
|
||||||
if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) {
|
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
uribits = xmlParseURI(tmpuri);
|
uribits = xmlParseURI(tmp);
|
||||||
VIR_FREE(tmpuri);
|
VIR_FREE(tmp);
|
||||||
} else {
|
} else {
|
||||||
uribits = xmlParseURI(uri);
|
uribits = xmlParseURI(uri);
|
||||||
}
|
}
|
||||||
@ -1604,13 +1619,38 @@ static int doNativeMigrate(struct qemud_driver *driver,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
spec.destType = MIGRATION_DEST_HOST;
|
|
||||||
spec.dest.host.name = uribits->server;
|
|
||||||
spec.dest.host.port = uribits->port;
|
|
||||||
spec.fwdType = MIGRATION_FWD_DIRECT;
|
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,
|
ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout,
|
||||||
cookieoutlen, flags, resource, &spec);
|
cookieoutlen, flags, resource, &spec);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (spec.destType == MIGRATION_DEST_FD)
|
||||||
|
VIR_FORCE_CLOSE(spec.dest.fd.qemu);
|
||||||
|
|
||||||
|
VIR_FREE(tmp);
|
||||||
xmlFreeURI(uribits);
|
xmlFreeURI(uribits);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -1628,7 +1668,6 @@ static int doTunnelMigrate(struct qemud_driver *driver,
|
|||||||
unsigned long resource)
|
unsigned long resource)
|
||||||
{
|
{
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
char *unixfile = NULL;
|
|
||||||
virNetSocketPtr sock = NULL;
|
virNetSocketPtr sock = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
qemuMigrationSpec spec;
|
qemuMigrationSpec spec;
|
||||||
@ -1638,36 +1677,67 @@ static int doTunnelMigrate(struct qemud_driver *driver,
|
|||||||
driver, vm, st, NULLSTR(cookiein), cookieinlen,
|
driver, vm, st, NULLSTR(cookiein), cookieinlen,
|
||||||
cookieout, cookieoutlen, flags, resource);
|
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)) {
|
!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_EXEC)) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||||
"%s", _("Source qemu is too old to support tunnelled migration"));
|
_("Source qemu is too old to support tunnelled migration"));
|
||||||
goto cleanup;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.src.%s",
|
|
||||||
driver->libDir, vm->def->name) < 0) {
|
|
||||||
virReportOOMError();
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (virNetSocketNewListenUNIX(unixfile, 0700,
|
|
||||||
driver->user, driver->group, &sock) < 0 ||
|
|
||||||
virNetSocketListen(sock, 1) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
spec.destType = MIGRATION_DEST_UNIX;
|
|
||||||
spec.dest.unix_socket.file = unixfile;
|
|
||||||
spec.dest.unix_socket.sock = virNetSocketGetFD(sock);
|
|
||||||
spec.fwdType = MIGRATION_FWD_STREAM;
|
spec.fwdType = MIGRATION_FWD_STREAM;
|
||||||
spec.fwd.stream = st;
|
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.unix_socket.sock = -1;
|
||||||
|
spec.dest.unix_socket.file = NULL;
|
||||||
|
|
||||||
|
if (virAsprintf(&spec.dest.unix_socket.file,
|
||||||
|
"%s/qemu.tunnelmigrate.src.%s",
|
||||||
|
driver->libDir, vm->def->name) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virNetSocketNewListenUNIX(spec.dest.unix_socket.file, 0700,
|
||||||
|
driver->user, driver->group,
|
||||||
|
&sock) < 0 ||
|
||||||
|
virNetSocketListen(sock, 1) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
spec.dest.unix_socket.sock = virNetSocketGetFD(sock);
|
||||||
|
}
|
||||||
|
|
||||||
ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout,
|
ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout,
|
||||||
cookieoutlen, flags, resource, &spec);
|
cookieoutlen, flags, resource, &spec);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virNetSocketFree(sock);
|
if (spec.destType == MIGRATION_DEST_FD) {
|
||||||
VIR_FREE(unixfile);
|
VIR_FORCE_CLOSE(spec.dest.fd.qemu);
|
||||||
|
VIR_FORCE_CLOSE(spec.dest.fd.local);
|
||||||
|
} else {
|
||||||
|
virNetSocketFree(sock);
|
||||||
|
VIR_FREE(spec.dest.unix_socket.file);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user