mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
libxl: add tunnelled migration support
Tunnelled migration doesn't require any extra network connections beside the libvirt daemon. It's capable of strong encryption and the default option of openstack-nova. This patch adds the tunnelled migration(Tunnel3params) support to libxl. On the source side, the data flow is: * libxlDoMigrateSend() -> pipe libxlTunnel3MigrationFunc() polls pipe * out and then write to dest stream. While on the destination side: * Stream -> pipe -> 'recvfd of libxlDomainStartRestore' The usage is the same as p2p migration, execpt adding one extra '--tunnelled' to the libvirt p2p migration command. Signed-off-by: Bob Liu <bob.liu@oracle.com> Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
This commit is contained in:
parent
d2100f2b4a
commit
6a95edf9ab
@ -5933,6 +5933,61 @@ libxlDomainMigrateBegin3Params(virDomainPtr domain,
|
|||||||
cookieout, cookieoutlen);
|
cookieout, cookieoutlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
libxlDomainMigratePrepareTunnel3Params(virConnectPtr dconn,
|
||||||
|
virStreamPtr st,
|
||||||
|
virTypedParameterPtr params,
|
||||||
|
int nparams,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
char **cookieout ATTRIBUTE_UNUSED,
|
||||||
|
int *cookieoutlen ATTRIBUTE_UNUSED,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
libxlDriverPrivatePtr driver = dconn->privateData;
|
||||||
|
virDomainDefPtr def = NULL;
|
||||||
|
const char *dom_xml = NULL;
|
||||||
|
const char *dname = NULL;
|
||||||
|
const char *uri_in = NULL;
|
||||||
|
|
||||||
|
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
|
||||||
|
virReportUnsupportedError();
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
|
||||||
|
if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (virTypedParamsGetString(params, nparams,
|
||||||
|
VIR_MIGRATE_PARAM_DEST_XML,
|
||||||
|
&dom_xml) < 0 ||
|
||||||
|
virTypedParamsGetString(params, nparams,
|
||||||
|
VIR_MIGRATE_PARAM_DEST_NAME,
|
||||||
|
&dname) < 0 ||
|
||||||
|
virTypedParamsGetString(params, nparams,
|
||||||
|
VIR_MIGRATE_PARAM_URI,
|
||||||
|
&uri_in) < 0)
|
||||||
|
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!(def = libxlDomainMigrationPrepareDef(driver, dom_xml, dname)))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (virDomainMigratePrepareTunnel3ParamsEnsureACL(dconn, def) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (libxlDomainMigrationPrepareTunnel3(dconn, st, &def, cookiein,
|
||||||
|
cookieinlen, flags) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
virDomainDefFree(def);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
libxlDomainMigratePrepare3Params(virConnectPtr dconn,
|
libxlDomainMigratePrepare3Params(virConnectPtr dconn,
|
||||||
virTypedParameterPtr params,
|
virTypedParameterPtr params,
|
||||||
@ -6033,7 +6088,7 @@ libxlDomainMigratePerform3Params(virDomainPtr dom,
|
|||||||
if (virDomainMigratePerform3ParamsEnsureACL(dom->conn, vm->def) < 0)
|
if (virDomainMigratePerform3ParamsEnsureACL(dom->conn, vm->def) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (flags & VIR_MIGRATE_PEER2PEER) {
|
if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
|
||||||
if (libxlDomainMigrationPerformP2P(driver, vm, dom->conn, dom_xml,
|
if (libxlDomainMigrationPerformP2P(driver, vm, dom->conn, dom_xml,
|
||||||
dconnuri, uri, dname, flags) < 0)
|
dconnuri, uri, dname, flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -6518,6 +6573,7 @@ static virHypervisorDriver libxlHypervisorDriver = {
|
|||||||
.nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.3 */
|
.nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.3 */
|
||||||
.domainMigrateBegin3Params = libxlDomainMigrateBegin3Params, /* 1.2.6 */
|
.domainMigrateBegin3Params = libxlDomainMigrateBegin3Params, /* 1.2.6 */
|
||||||
.domainMigratePrepare3Params = libxlDomainMigratePrepare3Params, /* 1.2.6 */
|
.domainMigratePrepare3Params = libxlDomainMigratePrepare3Params, /* 1.2.6 */
|
||||||
|
.domainMigratePrepareTunnel3Params = libxlDomainMigratePrepareTunnel3Params, /* 3.1.0 */
|
||||||
.domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.6 */
|
.domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.6 */
|
||||||
.domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.6 */
|
.domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.6 */
|
||||||
.domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */
|
.domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include "libxl_migration.h"
|
#include "libxl_migration.h"
|
||||||
#include "locking/domain_lock.h"
|
#include "locking/domain_lock.h"
|
||||||
#include "virtypedparam.h"
|
#include "virtypedparam.h"
|
||||||
|
#include "fdstream.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_LIBXL
|
#define VIR_FROM_THIS VIR_FROM_LIBXL
|
||||||
|
|
||||||
@ -553,6 +554,95 @@ libxlDomainMigrationPrepareAny(virConnectPtr dconn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
libxlDomainMigrationPrepareTunnel3(virConnectPtr dconn,
|
||||||
|
virStreamPtr st,
|
||||||
|
virDomainDefPtr *def,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
libxlMigrationCookiePtr mig = NULL;
|
||||||
|
libxlDriverPrivatePtr driver = dconn->privateData;
|
||||||
|
virDomainObjPtr vm = NULL;
|
||||||
|
libxlMigrationDstArgs *args = NULL;
|
||||||
|
virThread thread;
|
||||||
|
bool taint_hook = false;
|
||||||
|
libxlDomainObjPrivatePtr priv = NULL;
|
||||||
|
char *xmlout = NULL;
|
||||||
|
int dataFD[2] = { -1, -1 };
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (libxlDomainMigrationPrepareAny(dconn, def, cookiein, cookieinlen,
|
||||||
|
&mig, &xmlout, &taint_hook) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!(vm = virDomainObjListAdd(driver->domains, *def,
|
||||||
|
driver->xmlopt,
|
||||||
|
VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
|
||||||
|
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
|
||||||
|
NULL)))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
*def = NULL;
|
||||||
|
priv = vm->privateData;
|
||||||
|
|
||||||
|
if (taint_hook) {
|
||||||
|
/* Domain XML has been altered by a hook script. */
|
||||||
|
priv->hookRun = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The data flow of tunnel3 migration in the dest side:
|
||||||
|
* stream -> pipe -> recvfd of libxlDomainStartRestore
|
||||||
|
*/
|
||||||
|
if (pipe(dataFD) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Stream data will be written to pipeIn */
|
||||||
|
if (virFDStreamOpen(st, dataFD[1]) < 0)
|
||||||
|
goto error;
|
||||||
|
dataFD[1] = -1; /* 'st' owns the FD now & will close it */
|
||||||
|
|
||||||
|
if (libxlMigrationDstArgsInitialize() < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!(args = virObjectNew(libxlMigrationDstArgsClass)))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
args->conn = dconn;
|
||||||
|
args->vm = vm;
|
||||||
|
args->flags = flags;
|
||||||
|
args->migcookie = mig;
|
||||||
|
/* Receive from pipeOut */
|
||||||
|
args->recvfd = dataFD[0];
|
||||||
|
args->nsocks = 0;
|
||||||
|
if (virThreadCreate(&thread, false, libxlDoMigrateReceive, args) < 0) {
|
||||||
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||||
|
_("Failed to create thread for receiving migration data"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
error:
|
||||||
|
VIR_FORCE_CLOSE(dataFD[1]);
|
||||||
|
VIR_FORCE_CLOSE(dataFD[0]);
|
||||||
|
virObjectUnref(args);
|
||||||
|
/* Remove virDomainObj from domain list */
|
||||||
|
if (vm) {
|
||||||
|
virDomainObjListRemove(driver->domains, vm);
|
||||||
|
vm = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (vm)
|
||||||
|
virObjectUnlock(vm);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
libxlDomainMigrationPrepare(virConnectPtr dconn,
|
libxlDomainMigrationPrepare(virConnectPtr dconn,
|
||||||
virDomainDefPtr *def,
|
virDomainDefPtr *def,
|
||||||
@ -734,9 +824,143 @@ libxlDomainMigrationPrepare(virConnectPtr dconn,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is a simplification of virDomainMigrateVersion3Full
|
typedef struct _libxlTunnelMigrationThread libxlTunnelMigrationThread;
|
||||||
* excluding tunnel support and restricting it to migration v3
|
struct _libxlTunnelMigrationThread {
|
||||||
* with params since it was the first to be introduced in libxl.
|
virStreamPtr st;
|
||||||
|
int srcFD;
|
||||||
|
};
|
||||||
|
#define TUNNEL_SEND_BUF_SIZE 65536
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The data flow of tunnel3 migration in the src side:
|
||||||
|
* libxlDoMigrateSend() -> pipe
|
||||||
|
* libxlTunnel3MigrationFunc() polls pipe out and then write to dest stream.
|
||||||
|
*/
|
||||||
|
static void libxlTunnel3MigrationFunc(void *arg)
|
||||||
|
{
|
||||||
|
libxlTunnelMigrationThread *data = (libxlTunnelMigrationThread *)arg;
|
||||||
|
char *buffer = NULL;
|
||||||
|
struct pollfd fds[1];
|
||||||
|
int timeout = -1;
|
||||||
|
|
||||||
|
if (VIR_ALLOC_N(buffer, TUNNEL_SEND_BUF_SIZE) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fds[0].fd = data->srcFD;
|
||||||
|
for (;;) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
fds[0].events = POLLIN;
|
||||||
|
fds[0].revents = 0;
|
||||||
|
ret = poll(fds, ARRAY_CARDINALITY(fds), timeout);
|
||||||
|
if (ret < 0) {
|
||||||
|
if (errno == EAGAIN || errno == EINTR)
|
||||||
|
continue;
|
||||||
|
virReportError(errno, "%s",
|
||||||
|
_("poll failed in libxlTunnel3MigrationFunc"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
VIR_DEBUG("poll returned 0");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fds[0].revents & (POLLIN | POLLERR | POLLHUP)) {
|
||||||
|
int nbytes;
|
||||||
|
|
||||||
|
nbytes = read(data->srcFD, buffer, TUNNEL_SEND_BUF_SIZE);
|
||||||
|
if (nbytes > 0) {
|
||||||
|
/* Write to dest stream */
|
||||||
|
if (virStreamSend(data->st, buffer, nbytes) < 0) {
|
||||||
|
virStreamAbort(data->st);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else if (nbytes < 0) {
|
||||||
|
virReportError(errno, "%s",
|
||||||
|
_("tunnelled migration failed to read from xen side"));
|
||||||
|
virStreamAbort(data->st);
|
||||||
|
goto cleanup;
|
||||||
|
} else {
|
||||||
|
/* EOF; transferred all data */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ignore_value(virStreamFinish(data->st));
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(buffer);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct libxlTunnelControl {
|
||||||
|
libxlTunnelMigrationThread tmThread;
|
||||||
|
virThread thread;
|
||||||
|
int dataFD[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
libxlMigrationStartTunnel(libxlDriverPrivatePtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
unsigned long flags,
|
||||||
|
virStreamPtr st,
|
||||||
|
struct libxlTunnelControl *tc)
|
||||||
|
{
|
||||||
|
libxlTunnelMigrationThread *arg = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(tc) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
tc->dataFD[0] = -1;
|
||||||
|
tc->dataFD[1] = -1;
|
||||||
|
if (pipe(tc->dataFD) < 0) {
|
||||||
|
virReportError(errno, "%s", _("Unable to make pipes"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = &tc->tmThread;
|
||||||
|
/* Read from pipe */
|
||||||
|
arg->srcFD = tc->dataFD[0];
|
||||||
|
/* Write to dest stream */
|
||||||
|
arg->st = st;
|
||||||
|
if (virThreadCreate(&tc->thread, true,
|
||||||
|
libxlTunnel3MigrationFunc, arg) < 0) {
|
||||||
|
virReportError(errno, "%s",
|
||||||
|
_("Unable to create tunnel migration thread"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
virObjectUnlock(vm);
|
||||||
|
/* Send data to pipe */
|
||||||
|
ret = libxlDoMigrateSend(driver, vm, flags, tc->dataFD[1]);
|
||||||
|
virObjectLock(vm);
|
||||||
|
|
||||||
|
out:
|
||||||
|
/* libxlMigrationStopTunnel will be called in libxlDoMigrateP2P to free
|
||||||
|
* all resources for us. */
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void libxlMigrationStopTunnel(struct libxlTunnelControl *tc)
|
||||||
|
{
|
||||||
|
if (!tc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
virThreadCancel(&tc->thread);
|
||||||
|
virThreadJoin(&tc->thread);
|
||||||
|
|
||||||
|
VIR_FORCE_CLOSE(tc->dataFD[0]);
|
||||||
|
VIR_FORCE_CLOSE(tc->dataFD[1]);
|
||||||
|
VIR_FREE(tc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is a simplification of virDomainMigrateVersion3Full and
|
||||||
|
* restricting it to migration v3 with params since it was the first to be
|
||||||
|
* introduced in libxl.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
libxlDoMigrateP2P(libxlDriverPrivatePtr driver,
|
libxlDoMigrateP2P(libxlDriverPrivatePtr driver,
|
||||||
@ -761,6 +985,9 @@ libxlDoMigrateP2P(libxlDriverPrivatePtr driver,
|
|||||||
bool cancelled = true;
|
bool cancelled = true;
|
||||||
virErrorPtr orig_err = NULL;
|
virErrorPtr orig_err = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
/* For tunnel migration */
|
||||||
|
virStreamPtr st = NULL;
|
||||||
|
struct libxlTunnelControl *tc = NULL;
|
||||||
|
|
||||||
dom_xml = libxlDomainMigrationBegin(sconn, vm, xmlin,
|
dom_xml = libxlDomainMigrationBegin(sconn, vm, xmlin,
|
||||||
&cookieout, &cookieoutlen);
|
&cookieout, &cookieoutlen);
|
||||||
@ -788,29 +1015,40 @@ libxlDoMigrateP2P(libxlDriverPrivatePtr driver,
|
|||||||
|
|
||||||
VIR_DEBUG("Prepare3");
|
VIR_DEBUG("Prepare3");
|
||||||
virObjectUnlock(vm);
|
virObjectUnlock(vm);
|
||||||
ret = dconn->driver->domainMigratePrepare3Params
|
if (flags & VIR_MIGRATE_TUNNELLED) {
|
||||||
(dconn, params, nparams, cookieout, cookieoutlen, NULL, NULL, &uri_out, destflags);
|
if (!(st = virStreamNew(dconn, 0)))
|
||||||
|
goto cleanup;
|
||||||
|
ret = dconn->driver->domainMigratePrepareTunnel3Params
|
||||||
|
(dconn, st, params, nparams, cookieout, cookieoutlen, NULL, NULL, destflags);
|
||||||
|
} else {
|
||||||
|
ret = dconn->driver->domainMigratePrepare3Params
|
||||||
|
(dconn, params, nparams, cookieout, cookieoutlen, NULL, NULL, &uri_out, destflags);
|
||||||
|
}
|
||||||
virObjectLock(vm);
|
virObjectLock(vm);
|
||||||
|
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (uri_out) {
|
if (!(flags & VIR_MIGRATE_TUNNELLED)) {
|
||||||
if (virTypedParamsReplaceString(¶ms, &nparams,
|
if (uri_out) {
|
||||||
VIR_MIGRATE_PARAM_URI, uri_out) < 0) {
|
if (virTypedParamsReplaceString(¶ms, &nparams,
|
||||||
orig_err = virSaveLastError();
|
VIR_MIGRATE_PARAM_URI, uri_out) < 0) {
|
||||||
|
orig_err = virSaveLastError();
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("domainMigratePrepare3 did not set uri"));
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
||||||
_("domainMigratePrepare3 did not set uri"));
|
|
||||||
goto finish;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VIR_DEBUG("Perform3 uri=%s", NULLSTR(uri_out));
|
VIR_DEBUG("Perform3 uri=%s", NULLSTR(uri_out));
|
||||||
ret = libxlDomainMigrationPerform(driver, vm, NULL, NULL,
|
if (flags & VIR_MIGRATE_TUNNELLED)
|
||||||
uri_out, NULL, flags);
|
ret = libxlMigrationStartTunnel(driver, vm, flags, st, tc);
|
||||||
|
else
|
||||||
|
ret = libxlDomainMigrationPerform(driver, vm, NULL, NULL,
|
||||||
|
uri_out, NULL, flags);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
orig_err = virSaveLastError();
|
orig_err = virSaveLastError();
|
||||||
|
|
||||||
@ -848,6 +1086,11 @@ libxlDoMigrateP2P(libxlDriverPrivatePtr driver,
|
|||||||
vm->def->name);
|
vm->def->name);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
if (flags & VIR_MIGRATE_TUNNELLED) {
|
||||||
|
libxlMigrationStopTunnel(tc);
|
||||||
|
virObjectUnref(st);
|
||||||
|
}
|
||||||
|
|
||||||
if (ddomain) {
|
if (ddomain) {
|
||||||
virObjectUnref(ddomain);
|
virObjectUnref(ddomain);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
# define LIBXL_MIGRATION_FLAGS \
|
# define LIBXL_MIGRATION_FLAGS \
|
||||||
(VIR_MIGRATE_LIVE | \
|
(VIR_MIGRATE_LIVE | \
|
||||||
VIR_MIGRATE_PEER2PEER | \
|
VIR_MIGRATE_PEER2PEER | \
|
||||||
|
VIR_MIGRATE_TUNNELLED | \
|
||||||
VIR_MIGRATE_PERSIST_DEST | \
|
VIR_MIGRATE_PERSIST_DEST | \
|
||||||
VIR_MIGRATE_UNDEFINE_SOURCE | \
|
VIR_MIGRATE_UNDEFINE_SOURCE | \
|
||||||
VIR_MIGRATE_PAUSED)
|
VIR_MIGRATE_PAUSED)
|
||||||
@ -52,6 +53,14 @@ libxlDomainMigrationPrepareDef(libxlDriverPrivatePtr driver,
|
|||||||
const char *dom_xml,
|
const char *dom_xml,
|
||||||
const char *dname);
|
const char *dname);
|
||||||
|
|
||||||
|
int
|
||||||
|
libxlDomainMigrationPrepareTunnel3(virConnectPtr dconn,
|
||||||
|
virStreamPtr st,
|
||||||
|
virDomainDefPtr *def,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
unsigned int flags);
|
||||||
|
|
||||||
int
|
int
|
||||||
libxlDomainMigrationPrepare(virConnectPtr dconn,
|
libxlDomainMigrationPrepare(virConnectPtr dconn,
|
||||||
virDomainDefPtr *def,
|
virDomainDefPtr *def,
|
||||||
|
Loading…
Reference in New Issue
Block a user