+Tue Aug 21 10:21:00 BST 2007 Richard W.M. Jones <rjones@redhat.com>
+
+ * src/libvirt.c (virDomainMigrate): Added virDomainMigrate
+ API call.
+ * src/xend_internal.c, src/xen_unified.c: Support for migration
+ of Xen domains.
+ * src/xen_internal.c: Xen capabilities indicates level of
+ support for migration.
+ * qemud/remote.c, qemud/remote_protocol.x, src/remote_internal.c:
+ Support for migration between remote hypervisors.
+ * src/virsh.c: Added 'virsh migrate' command.
+ * docs/libvir.html, docs/hvsupport.html: Updated hvsupport
+ documentation.
+
Tue Aug 21 09:56:00 BST 2007 Richard W.M. Jones <rjones@redhat.com>
* qemud/remote.c, qemud/remote_protocol.x, src/driver.h,
<td> ≥ 0.2.0 </td>
<td> ≥ 0.2.0 </td>
<td> ≥ 0.3.0 </td>
+</tr><tr><td> virDomainMigrate </td>
+ <td> 0.3.2 </td>
+ <td> ≥ 0.3.2 </td>
+ <td> x </td>
+ <td> x </td>
+ <td> 0.3.2 </td>
</tr><tr><td> virDomainPinVcpu </td>
<td> 0.1.4 </td>
<td> ≥ 0.1.4 </td>
<td> ≥ 0.2.0 </td>
<td> ≥ 0.3.0 </td>
</tr>
+<tr>
+ <td> virDomainMigrate </td>
+ <td> 0.3.2 </td>
+ <td> ≥ 0.3.2 </td>
+ <td> x </td>
+ <td> x </td>
+ <td> 0.3.2 </td>
+</tr>
<tr>
<td> virDomainPinVcpu </td>
<td> 0.1.4 </td>
virSchedParameterPtr params,
int nparams);
+/* Domain migration flags. */
+typedef enum {
+ VIR_MIGRATE_LIVE = 1, /* live migration */
+} virDomainMigrateFlags;
+
+/* Domain migration. */
+virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn,
+ unsigned long flags, const char *dname,
+ const char *uri, unsigned long bandwidth);
+
/**
* VIR_NODEINFO_MAXCPUS:
* @nodeinfo: virNodeInfo instance
virSchedParameterPtr params,
int nparams);
+/* Domain migration flags. */
+typedef enum {
+ VIR_MIGRATE_LIVE = 1, /* live migration */
+} virDomainMigrateFlags;
+
+/* Domain migration. */
+virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn,
+ unsigned long flags, const char *dname,
+ const char *uri, unsigned long bandwidth);
+
/**
* VIR_NODEINFO_MAXCPUS:
* @nodeinfo: virNodeInfo instance
return 0;
}
+static int
+remoteDispatchDomainMigratePrepare (struct qemud_client *client,
+ remote_message_header *req,
+ remote_domain_migrate_prepare_args *args,
+ remote_domain_migrate_prepare_ret *ret)
+{
+ int r;
+ char *cookie = NULL;
+ int cookielen = 0;
+ char *uri_in;
+ char **uri_out;
+ char *dname;
+ CHECK_CONN (client);
+
+ uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
+ dname = args->dname == NULL ? NULL : *args->dname;
+
+ /* Wacky world of XDR ... */
+ uri_out = calloc (1, sizeof (char *));
+
+ r = __virDomainMigratePrepare (client->conn, &cookie, &cookielen,
+ uri_in, uri_out,
+ args->flags, dname, args->resource);
+ if (r == -1) return -1;
+
+ /* remoteDispatchClientRequest will free cookie, uri_out and
+ * the string if there is one.
+ */
+ ret->cookie.cookie_len = cookielen;
+ ret->cookie.cookie_val = cookie;
+ ret->uri_out = *uri_out == NULL ? NULL : uri_out;
+
+ return 0;
+}
+
+static int
+remoteDispatchDomainMigratePerform (struct qemud_client *client,
+ remote_message_header *req,
+ remote_domain_migrate_perform_args *args,
+ void *ret ATTRIBUTE_UNUSED)
+{
+ int r;
+ virDomainPtr dom;
+ char *dname;
+ CHECK_CONN (client);
+
+ dom = get_nonnull_domain (client->conn, args->dom);
+ if (dom == NULL) {
+ remoteDispatchError (client, req, "domain not found");
+ return -2;
+ }
+
+ dname = args->dname == NULL ? NULL : *args->dname;
+
+ r = __virDomainMigratePerform (dom,
+ args->cookie.cookie_val,
+ args->cookie.cookie_len,
+ args->uri,
+ args->flags, dname, args->resource);
+ if (r == -1) return -1;
+
+ return 0;
+}
+
+static int
+remoteDispatchDomainMigrateFinish (struct qemud_client *client,
+ remote_message_header *req,
+ remote_domain_migrate_finish_args *args,
+ remote_domain_migrate_finish_ret *ret)
+{
+ virDomainPtr ddom;
+ CHECK_CONN (client);
+
+ ddom = __virDomainMigrateFinish (client->conn, args->dname,
+ args->cookie.cookie_val,
+ args->cookie.cookie_len,
+ args->uri,
+ args->flags);
+ if (ddom == NULL) return -1;
+
+ make_nonnull_domain (&ret->ddom, ddom);
+
+ return 0;
+}
+
static int
remoteDispatchListDefinedDomains (struct qemud_client *client,
remote_message_header *req,
remote_domain_shutdown_args lv_remote_domain_shutdown_args;
remote_list_defined_domains_args lv_remote_list_defined_domains_args;
remote_list_defined_domains_ret lv_remote_list_defined_domains_ret;
+remote_domain_migrate_prepare_args lv_remote_domain_migrate_prepare_args;
+remote_domain_migrate_prepare_ret lv_remote_domain_migrate_prepare_ret;
remote_get_capabilities_ret lv_remote_get_capabilities_ret;
remote_domain_set_max_memory_args lv_remote_domain_set_max_memory_args;
remote_domain_undefine_args lv_remote_domain_undefine_args;
remote_domain_destroy_args lv_remote_domain_destroy_args;
remote_domain_define_xml_args lv_remote_domain_define_xml_args;
remote_domain_define_xml_ret lv_remote_domain_define_xml_ret;
+remote_domain_migrate_finish_args lv_remote_domain_migrate_finish_args;
+remote_domain_migrate_finish_ret lv_remote_domain_migrate_finish_ret;
remote_domain_get_vcpus_args lv_remote_domain_get_vcpus_args;
remote_domain_get_vcpus_ret lv_remote_domain_get_vcpus_ret;
remote_domain_get_scheduler_parameters_args lv_remote_domain_get_scheduler_parameters_args;
remote_get_max_vcpus_args lv_remote_get_max_vcpus_args;
remote_get_max_vcpus_ret lv_remote_get_max_vcpus_ret;
remote_node_get_info_ret lv_remote_node_get_info_ret;
+remote_domain_migrate_perform_args lv_remote_domain_migrate_perform_args;
ret = (char *) &lv_remote_domain_lookup_by_uuid_ret;
memset (&lv_remote_domain_lookup_by_uuid_ret, 0, sizeof lv_remote_domain_lookup_by_uuid_ret);
break;
+case REMOTE_PROC_DOMAIN_MIGRATE_FINISH:
+ fn = (dispatch_fn) remoteDispatchDomainMigrateFinish;
+ args_filter = (xdrproc_t) xdr_remote_domain_migrate_finish_args;
+ args = (char *) &lv_remote_domain_migrate_finish_args;
+ memset (&lv_remote_domain_migrate_finish_args, 0, sizeof lv_remote_domain_migrate_finish_args);
+ ret_filter = (xdrproc_t) xdr_remote_domain_migrate_finish_ret;
+ ret = (char *) &lv_remote_domain_migrate_finish_ret;
+ memset (&lv_remote_domain_migrate_finish_ret, 0, sizeof lv_remote_domain_migrate_finish_ret);
+ break;
+case REMOTE_PROC_DOMAIN_MIGRATE_PERFORM:
+ fn = (dispatch_fn) remoteDispatchDomainMigratePerform;
+ args_filter = (xdrproc_t) xdr_remote_domain_migrate_perform_args;
+ args = (char *) &lv_remote_domain_migrate_perform_args;
+ memset (&lv_remote_domain_migrate_perform_args, 0, sizeof lv_remote_domain_migrate_perform_args);
+ break;
+case REMOTE_PROC_DOMAIN_MIGRATE_PREPARE:
+ fn = (dispatch_fn) remoteDispatchDomainMigratePrepare;
+ args_filter = (xdrproc_t) xdr_remote_domain_migrate_prepare_args;
+ args = (char *) &lv_remote_domain_migrate_prepare_args;
+ memset (&lv_remote_domain_migrate_prepare_args, 0, sizeof lv_remote_domain_migrate_prepare_args);
+ ret_filter = (xdrproc_t) xdr_remote_domain_migrate_prepare_ret;
+ ret = (char *) &lv_remote_domain_migrate_prepare_ret;
+ memset (&lv_remote_domain_migrate_prepare_ret, 0, sizeof lv_remote_domain_migrate_prepare_ret);
+ break;
case REMOTE_PROC_DOMAIN_PIN_VCPU:
fn = (dispatch_fn) remoteDispatchDomainPinVcpu;
args_filter = (xdrproc_t) xdr_remote_domain_pin_vcpu_args;
static int remoteDispatchDomainLookupById (struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_id_args *args, remote_domain_lookup_by_id_ret *ret);
static int remoteDispatchDomainLookupByName (struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_name_args *args, remote_domain_lookup_by_name_ret *ret);
static int remoteDispatchDomainLookupByUuid (struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_uuid_args *args, remote_domain_lookup_by_uuid_ret *ret);
+static int remoteDispatchDomainMigrateFinish (struct qemud_client *client, remote_message_header *req, remote_domain_migrate_finish_args *args, remote_domain_migrate_finish_ret *ret);
+static int remoteDispatchDomainMigratePerform (struct qemud_client *client, remote_message_header *req, remote_domain_migrate_perform_args *args, void *ret);
+static int remoteDispatchDomainMigratePrepare (struct qemud_client *client, remote_message_header *req, remote_domain_migrate_prepare_args *args, remote_domain_migrate_prepare_ret *ret);
static int remoteDispatchDomainPinVcpu (struct qemud_client *client, remote_message_header *req, remote_domain_pin_vcpu_args *args, void *ret);
static int remoteDispatchDomainReboot (struct qemud_client *client, remote_message_header *req, remote_domain_reboot_args *args, void *ret);
static int remoteDispatchDomainRestore (struct qemud_client *client, remote_message_header *req, remote_domain_restore_args *args, void *ret);
return TRUE;
}
+bool_t
+xdr_remote_domain_migrate_prepare_args (XDR *xdrs, remote_domain_migrate_prepare_args *objp)
+{
+
+ if (!xdr_remote_string (xdrs, &objp->uri_in))
+ return FALSE;
+ if (!xdr_u_quad_t (xdrs, &objp->flags))
+ return FALSE;
+ if (!xdr_remote_string (xdrs, &objp->dname))
+ return FALSE;
+ if (!xdr_u_quad_t (xdrs, &objp->resource))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_domain_migrate_prepare_ret (XDR *xdrs, remote_domain_migrate_prepare_ret *objp)
+{
+ char **objp_cpp0 = (char **) (void *) &objp->cookie.cookie_val;
+
+ if (!xdr_bytes (xdrs, objp_cpp0, (u_int *) &objp->cookie.cookie_len, REMOTE_MIGRATE_COOKIE_MAX))
+ return FALSE;
+ if (!xdr_remote_string (xdrs, &objp->uri_out))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_domain_migrate_perform_args (XDR *xdrs, remote_domain_migrate_perform_args *objp)
+{
+ char **objp_cpp0 = (char **) (void *) &objp->cookie.cookie_val;
+
+ if (!xdr_remote_nonnull_domain (xdrs, &objp->dom))
+ return FALSE;
+ if (!xdr_bytes (xdrs, objp_cpp0, (u_int *) &objp->cookie.cookie_len, REMOTE_MIGRATE_COOKIE_MAX))
+ return FALSE;
+ if (!xdr_remote_nonnull_string (xdrs, &objp->uri))
+ return FALSE;
+ if (!xdr_u_quad_t (xdrs, &objp->flags))
+ return FALSE;
+ if (!xdr_remote_string (xdrs, &objp->dname))
+ return FALSE;
+ if (!xdr_u_quad_t (xdrs, &objp->resource))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_domain_migrate_finish_args (XDR *xdrs, remote_domain_migrate_finish_args *objp)
+{
+ char **objp_cpp0 = (char **) (void *) &objp->cookie.cookie_val;
+
+ if (!xdr_remote_nonnull_string (xdrs, &objp->dname))
+ return FALSE;
+ if (!xdr_bytes (xdrs, objp_cpp0, (u_int *) &objp->cookie.cookie_len, REMOTE_MIGRATE_COOKIE_MAX))
+ return FALSE;
+ if (!xdr_remote_nonnull_string (xdrs, &objp->uri))
+ return FALSE;
+ if (!xdr_u_quad_t (xdrs, &objp->flags))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_domain_migrate_finish_ret (XDR *xdrs, remote_domain_migrate_finish_ret *objp)
+{
+
+ if (!xdr_remote_nonnull_domain (xdrs, &objp->ddom))
+ return FALSE;
+ return TRUE;
+}
+
bool_t
xdr_remote_list_defined_domains_args (XDR *xdrs, remote_list_defined_domains_args *objp)
{
#define REMOTE_CPUMAP_MAX 256
#define REMOTE_VCPUINFO_MAX 2048
#define REMOTE_CPUMAPS_MAX 16384
+#define REMOTE_MIGRATE_COOKIE_MAX 256
#define REMOTE_NETWORK_NAME_LIST_MAX 256
#define REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX 16
};
typedef struct remote_domain_dump_xml_ret remote_domain_dump_xml_ret;
+struct remote_domain_migrate_prepare_args {
+ remote_string uri_in;
+ u_quad_t flags;
+ remote_string dname;
+ u_quad_t resource;
+};
+typedef struct remote_domain_migrate_prepare_args remote_domain_migrate_prepare_args;
+
+struct remote_domain_migrate_prepare_ret {
+ struct {
+ u_int cookie_len;
+ char *cookie_val;
+ } cookie;
+ remote_string uri_out;
+};
+typedef struct remote_domain_migrate_prepare_ret remote_domain_migrate_prepare_ret;
+
+struct remote_domain_migrate_perform_args {
+ remote_nonnull_domain dom;
+ struct {
+ u_int cookie_len;
+ char *cookie_val;
+ } cookie;
+ remote_nonnull_string uri;
+ u_quad_t flags;
+ remote_string dname;
+ u_quad_t resource;
+};
+typedef struct remote_domain_migrate_perform_args remote_domain_migrate_perform_args;
+
+struct remote_domain_migrate_finish_args {
+ remote_nonnull_string dname;
+ struct {
+ u_int cookie_len;
+ char *cookie_val;
+ } cookie;
+ remote_nonnull_string uri;
+ u_quad_t flags;
+};
+typedef struct remote_domain_migrate_finish_args remote_domain_migrate_finish_args;
+
+struct remote_domain_migrate_finish_ret {
+ remote_nonnull_domain ddom;
+};
+typedef struct remote_domain_migrate_finish_ret remote_domain_migrate_finish_ret;
+
struct remote_list_defined_domains_args {
int maxnames;
};
REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS = 58,
REMOTE_PROC_GET_HOSTNAME = 59,
REMOTE_PROC_SUPPORTS_FEATURE = 60,
+ REMOTE_PROC_DOMAIN_MIGRATE_PREPARE = 61,
+ REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 62,
+ REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63,
};
typedef enum remote_procedure remote_procedure;
extern bool_t xdr_remote_domain_core_dump_args (XDR *, remote_domain_core_dump_args*);
extern bool_t xdr_remote_domain_dump_xml_args (XDR *, remote_domain_dump_xml_args*);
extern bool_t xdr_remote_domain_dump_xml_ret (XDR *, remote_domain_dump_xml_ret*);
+extern bool_t xdr_remote_domain_migrate_prepare_args (XDR *, remote_domain_migrate_prepare_args*);
+extern bool_t xdr_remote_domain_migrate_prepare_ret (XDR *, remote_domain_migrate_prepare_ret*);
+extern bool_t xdr_remote_domain_migrate_perform_args (XDR *, remote_domain_migrate_perform_args*);
+extern bool_t xdr_remote_domain_migrate_finish_args (XDR *, remote_domain_migrate_finish_args*);
+extern bool_t xdr_remote_domain_migrate_finish_ret (XDR *, remote_domain_migrate_finish_ret*);
extern bool_t xdr_remote_list_defined_domains_args (XDR *, remote_list_defined_domains_args*);
extern bool_t xdr_remote_list_defined_domains_ret (XDR *, remote_list_defined_domains_ret*);
extern bool_t xdr_remote_num_of_defined_domains_ret (XDR *, remote_num_of_defined_domains_ret*);
extern bool_t xdr_remote_domain_core_dump_args ();
extern bool_t xdr_remote_domain_dump_xml_args ();
extern bool_t xdr_remote_domain_dump_xml_ret ();
+extern bool_t xdr_remote_domain_migrate_prepare_args ();
+extern bool_t xdr_remote_domain_migrate_prepare_ret ();
+extern bool_t xdr_remote_domain_migrate_perform_args ();
+extern bool_t xdr_remote_domain_migrate_finish_args ();
+extern bool_t xdr_remote_domain_migrate_finish_ret ();
extern bool_t xdr_remote_list_defined_domains_args ();
extern bool_t xdr_remote_list_defined_domains_ret ();
extern bool_t xdr_remote_num_of_defined_domains_ret ();
/* Upper limit on cpumaps (bytes) passed to virDomainGetVcpus. */
const REMOTE_CPUMAPS_MAX = 16384;
+/* Upper limit on migrate cookie. */
+const REMOTE_MIGRATE_COOKIE_MAX = 256;
+
/* Upper limit on lists of network names. */
const REMOTE_NETWORK_NAME_LIST_MAX = 256;
};
struct remote_domain_lookup_by_id_ret {
- /* XXX "Not found" semantic is ill-defined. */
remote_nonnull_domain dom;
};
};
struct remote_domain_lookup_by_uuid_ret {
- /* XXX "Not found" semantic is ill-defined. */
remote_nonnull_domain dom;
};
};
struct remote_domain_lookup_by_name_ret {
- /* XXX "Not found" semantic is ill-defined. */
remote_nonnull_domain dom;
};
remote_nonnull_string xml;
};
+struct remote_domain_migrate_prepare_args {
+ remote_string uri_in;
+ unsigned hyper flags;
+ remote_string dname;
+ unsigned hyper resource;
+};
+
+struct remote_domain_migrate_prepare_ret {
+ opaque cookie<REMOTE_MIGRATE_COOKIE_MAX>;
+ remote_string uri_out;
+};
+
+struct remote_domain_migrate_perform_args {
+ remote_nonnull_domain dom;
+ opaque cookie<REMOTE_MIGRATE_COOKIE_MAX>;
+ remote_nonnull_string uri;
+ unsigned hyper flags;
+ remote_string dname;
+ unsigned hyper resource;
+};
+
+struct remote_domain_migrate_finish_args {
+ remote_nonnull_string dname;
+ opaque cookie<REMOTE_MIGRATE_COOKIE_MAX>;
+ remote_nonnull_string uri;
+ unsigned hyper flags;
+};
+
+struct remote_domain_migrate_finish_ret {
+ remote_nonnull_domain ddom;
+};
+
struct remote_list_defined_domains_args {
int maxnames;
};
};
struct remote_network_lookup_by_uuid_ret {
- /* XXX "Not found" semantic is ill-defined. */
remote_nonnull_network net;
};
};
struct remote_network_lookup_by_name_ret {
- /* XXX "Not found" semantic is ill-defined. */
remote_nonnull_network net;
};
REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS = 57,
REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS = 58,
REMOTE_PROC_GET_HOSTNAME = 59,
- REMOTE_PROC_SUPPORTS_FEATURE = 60
+ REMOTE_PROC_SUPPORTS_FEATURE = 60,
+ REMOTE_PROC_DOMAIN_MIGRATE_PREPARE = 61,
+ REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 62,
+ REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63
};
/* Custom RPC structure. */
$(WARN_CFLAGS) \
$(LIBVIRT_FEATURES)
DEPS = libvirt.la
-LDADDS = @STATIC_BINARIES@ libvirt.la
+LDADDS = @STATIC_BINARIES@ $(WARN_CFLAGS) libvirt.la
VIRSH_LIBS = @VIRSH_LIBS@
EXTRA_DIST = libvirt_sym.version
virSchedParameterPtr params,
int nparams);
+typedef int
+ (*virDrvDomainMigratePrepare)
+ (virConnectPtr dconn,
+ char **cookie,
+ int *cookielen,
+ const char *uri_in,
+ char **uri_out,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource);
+
+typedef int
+ (*virDrvDomainMigratePerform)
+ (virDomainPtr domain,
+ const char *cookie,
+ int cookielen,
+ const char *uri,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource);
+
+typedef virDomainPtr
+ (*virDrvDomainMigrateFinish)
+ (virConnectPtr dconn,
+ const char *dname,
+ const char *cookie,
+ int cookielen,
+ const char *uri,
+ unsigned long flags);
+
typedef struct _virDriver virDriver;
typedef virDriver *virDriverPtr;
virDrvDomainGetSchedulerType domainGetSchedulerType;
virDrvDomainGetSchedulerParameters domainGetSchedulerParameters;
virDrvDomainSetSchedulerParameters domainSetSchedulerParameters;
+ virDrvDomainMigratePrepare domainMigratePrepare;
+ virDrvDomainMigratePerform domainMigratePerform;
+ virDrvDomainMigrateFinish domainMigrateFinish;
};
typedef int
int __virDrvSupportsFeature (virConnectPtr conn, int feature);
+int __virDomainMigratePrepare (virConnectPtr dconn, char **cookie, int *cookielen, const char *uri_in, char **uri_out, unsigned long flags, const char *dname, unsigned long bandwidth);
+int __virDomainMigratePerform (virDomainPtr domain, const char *cookie, int cookielen, const char *uri, unsigned long flags, const char *dname, unsigned long bandwidth);
+virDomainPtr __virDomainMigrateFinish (virConnectPtr dconn, const char *dname, const char *cookie, int cookielen, const char *uri, unsigned long flags);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <assert.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
return NULL;
}
+/**
+ * virDomainMigrate:
+ * @domain: a domain object
+ * @dconn: destination host (a connection object)
+ * @flags: flags
+ * @dname: (optional) rename domain to this at destination
+ * @uri: (optional) dest hostname/URI as seen from the source host
+ * @bandwidth: (optional) specify migration bandwidth limit in Mbps
+ *
+ * Migrate the domain object from its current host to the destination
+ * host given by dconn (a connection to the destination host).
+ *
+ * Flags may be one of more of the following:
+ * VIR_MIGRATE_LIVE Attempt a live migration.
+ *
+ * If a hypervisor supports renaming domains during migration,
+ * then you may set the dname parameter to the new name (otherwise
+ * it keeps the same name). If this is not supported by the
+ * hypervisor, dname must be NULL or else you will get an error.
+ *
+ * Since typically the two hypervisors connect directly to each
+ * other in order to perform the migration, you may need to specify
+ * a path from the source to the destination. This is the purpose
+ * of the uri parameter. If uri is NULL, then libvirt will try to
+ * find the best method. Uri may specify the hostname or IP address
+ * of the destination host as seen from the source. Or uri may be
+ * a URI giving transport, hostname, user, port, etc. in the usual
+ * form. Refer to driver documentation for the particular URIs
+ * supported.
+ *
+ * The maximum bandwidth (in Mbps) that will be used to do migration
+ * can be specified with the bandwidth parameter. If set to 0,
+ * libvirt will choose a suitable default. Some hypervisors do
+ * not support this feature and will return an error if bandwidth
+ * is not 0.
+ *
+ * To see which features are supported by the current hypervisor,
+ * see virConnectGetCapabilities, /capabilities/host/migration_features.
+ *
+ * There are many limitations on migration imposed by the underlying
+ * technology - for example it may not be possible to migrate between
+ * different processors even with the same architecture, or between
+ * different types of hypervisor.
+ *
+ * Returns the new domain object if the migration was successful,
+ * or NULL in case of error. Note that the new domain object
+ * exists in the scope of the destination connection (dconn).
+ */
+virDomainPtr
+virDomainMigrate (virDomainPtr domain,
+ virConnectPtr dconn,
+ unsigned long flags,
+ const char *dname,
+ const char *uri,
+ unsigned long bandwidth)
+{
+ virConnectPtr conn;
+ virDomainPtr ddomain = NULL;
+ char *uri_out = NULL;
+ char *cookie = NULL;
+ int cookielen = 0, ret;
+ DEBUG("domain=%p, dconn=%p, flags=%lu, dname=%s, uri=%s, bandwidth=%lu",
+ domain, dconn, flags, dname, uri, bandwidth);
+
+ if (!VIR_IS_DOMAIN (domain)) {
+ virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ return NULL;
+ }
+ conn = domain->conn; /* Source connection. */
+ if (!VIR_IS_CONNECT (dconn)) {
+ virLibConnError (conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return NULL;
+ }
+
+ /* Check that migration is supported by both drivers. */
+ if (!VIR_DRV_SUPPORTS_FEATURE (conn->driver, conn,
+ VIR_DRV_FEATURE_MIGRATION_V1) ||
+ !VIR_DRV_SUPPORTS_FEATURE (dconn->driver, dconn,
+ VIR_DRV_FEATURE_MIGRATION_V1)) {
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return NULL;
+ }
+
+ /* Prepare the migration.
+ *
+ * The destination host may return a cookie, or leave cookie as
+ * NULL.
+ *
+ * The destination host MUST set uri_out if uri_in is NULL.
+ *
+ * If uri_in is non-NULL, then the destination host may modify
+ * the URI by setting uri_out. If it does not wish to modify
+ * the URI, it should leave uri_out as NULL.
+ */
+ ret = dconn->driver->domainMigratePrepare
+ (dconn, &cookie, &cookielen, uri, &uri_out, flags, dname, bandwidth);
+ if (ret == -1) goto done;
+ if (uri == NULL && uri_out == NULL) {
+ virLibConnError (conn, VIR_ERR_INTERNAL_ERROR,
+ "domainMigratePrepare did not set uri");
+ goto done;
+ }
+ if (uri_out) uri = uri_out; /* Did domainMigratePrepare change URI? */
+
+ assert (uri != NULL);
+
+ /* Perform the migration. The driver isn't supposed to return
+ * until the migration is complete.
+ */
+ ret = conn->driver->domainMigratePerform
+ (domain, cookie, cookielen, uri, flags, dname, bandwidth);
+
+ if (ret == -1) goto done;
+
+ /* Get the destination domain and return it or error.
+ * 'domain' no longer actually exists at this point (or so we hope), but
+ * we still use the object in memory in order to get the name.
+ */
+ dname = dname ? dname : domain->name;
+ if (dconn->driver->domainMigrateFinish)
+ ddomain = dconn->driver->domainMigrateFinish
+ (dconn, dname, cookie, cookielen, uri, flags);
+ else
+ ddomain = virDomainLookupByName (dconn, dname);
+
+ done:
+ if (uri_out) free (uri_out);
+ if (cookie) free (cookie);
+ return ddomain;
+}
+
+/* Not for public use. This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+__virDomainMigratePrepare (virConnectPtr dconn,
+ char **cookie,
+ int *cookielen,
+ const char *uri_in,
+ char **uri_out,
+ unsigned long flags,
+ const char *dname,
+ unsigned long bandwidth)
+{
+ DEBUG("dconn=%p, cookie=%p, cookielen=%p, uri_in=%s, uri_out=%p, flags=%lu, dname=%s, bandwidth=%lu", dconn, cookie, cookielen, uri_in, uri_out, flags, dname, bandwidth);
+
+ if (!VIR_IS_CONNECT (dconn)) {
+ virLibConnError (dconn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return -1;
+ }
+
+ if (dconn->driver->domainMigratePrepare)
+ return dconn->driver->domainMigratePrepare (dconn, cookie, cookielen,
+ uri_in, uri_out,
+ flags, dname, bandwidth);
+
+ virLibConnError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+/* Not for public use. This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+__virDomainMigratePerform (virDomainPtr domain,
+ const char *cookie,
+ int cookielen,
+ const char *uri,
+ unsigned long flags,
+ const char *dname,
+ unsigned long bandwidth)
+{
+ virConnectPtr conn;
+ DEBUG("domain=%p, cookie=%p, cookielen=%d, uri=%s, flags=%lu, dname=%s, bandwidth=%lu", domain, cookie, cookielen, uri, flags, dname, bandwidth);
+
+ if (!VIR_IS_DOMAIN (domain)) {
+ virLibDomainError (domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ return -1;
+ }
+ conn = domain->conn;
+
+ if (conn->driver->domainMigratePerform)
+ return conn->driver->domainMigratePerform (domain, cookie, cookielen,
+ uri,
+ flags, dname, bandwidth);
+
+ virLibDomainError (domain, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+/* Not for public use. This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+virDomainPtr
+__virDomainMigrateFinish (virConnectPtr dconn,
+ const char *dname,
+ const char *cookie,
+ int cookielen,
+ const char *uri,
+ unsigned long flags)
+{
+ DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, flags=%lu", dconn, dname, cookie, cookielen, uri, flags);
+
+ if (!VIR_IS_CONNECT (dconn)) {
+ virLibConnError (dconn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return NULL;
+ }
+
+ if (dconn->driver->domainMigrateFinish)
+ return dconn->driver->domainMigrateFinish (dconn, dname,
+ cookie, cookielen,
+ uri, flags);
+
+ virLibConnError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return NULL;
+}
+
+
/**
* virNodeGetInfo:
* @conn: pointer to the hypervisor connection
virDomainAttachDevice;
virDomainDetachDevice;
+ virDomainMigrate;
+
virNetworkGetConnect;
virConnectNumOfNetworks;
virConnectListNetworks;
__virDrvSupportsFeature;
+ __virDomainMigratePrepare;
+ __virDomainMigratePerform;
+ __virDomainMigrateFinish;
+
local: *;
};
NULL, /* domainGetSchedulerType */
NULL, /* domainGetSchedulerParameters */
NULL, /* domainSetSchedulerParameters */
+ NULL, /* domainMigratePrepare */
+ NULL, /* domainMigratePerform */
+ NULL, /* domainMigrateFinish */
};
static virNetworkDriver qemuNetworkDriver = {
return ret.xml;
}
+static int
+remoteDomainMigratePrepare (virConnectPtr dconn,
+ char **cookie, int *cookielen,
+ const char *uri_in, char **uri_out,
+ unsigned long flags, const char *dname,
+ unsigned long resource)
+{
+ remote_domain_migrate_prepare_args args;
+ remote_domain_migrate_prepare_ret ret;
+ GET_PRIVATE (dconn, -1);
+
+ args.uri_in = uri_in == NULL ? NULL : (char **) &uri_in;
+ args.flags = flags;
+ args.dname = dname == NULL ? NULL : (char **) &dname;
+ args.resource = resource;
+
+ memset (&ret, 0, sizeof ret);
+ if (call (dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_PREPARE,
+ (xdrproc_t) xdr_remote_domain_migrate_prepare_args, (char *) &args,
+ (xdrproc_t) xdr_remote_domain_migrate_prepare_ret, (char *) &ret) == -1)
+ return -1;
+
+ if (ret.cookie.cookie_len > 0) {
+ *cookie = ret.cookie.cookie_val; /* Caller frees. */
+ *cookielen = ret.cookie.cookie_len;
+ }
+ if (ret.uri_out)
+ *uri_out = *ret.uri_out; /* Caller frees. */
+
+ return 0;
+}
+
+static int
+remoteDomainMigratePerform (virDomainPtr domain,
+ const char *cookie,
+ int cookielen,
+ const char *uri,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource)
+{
+ remote_domain_migrate_perform_args args;
+ GET_PRIVATE (domain->conn, -1);
+
+ make_nonnull_domain (&args.dom, domain);
+ args.cookie.cookie_len = cookielen;
+ args.cookie.cookie_val = (char *) cookie;
+ args.uri = (char *) uri;
+ args.flags = flags;
+ args.dname = dname == NULL ? NULL : (char **) &dname;
+ args.resource = resource;
+
+ if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_PERFORM,
+ (xdrproc_t) xdr_remote_domain_migrate_perform_args, (char *) &args,
+ (xdrproc_t) xdr_void, (char *) NULL) == -1)
+ return -1;
+
+ return 0;
+}
+
+static virDomainPtr
+remoteDomainMigrateFinish (virConnectPtr dconn,
+ const char *dname,
+ const char *cookie,
+ int cookielen,
+ const char *uri,
+ unsigned long flags)
+{
+ virDomainPtr ddom;
+ remote_domain_migrate_finish_args args;
+ remote_domain_migrate_finish_ret ret;
+ GET_PRIVATE (dconn, NULL);
+
+ args.dname = (char *) dname;
+ args.cookie.cookie_len = cookielen;
+ args.cookie.cookie_val = (char *) cookie;
+ args.uri = (char *) uri;
+ args.flags = flags;
+
+ memset (&ret, 0, sizeof ret);
+ if (call (dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_FINISH,
+ (xdrproc_t) xdr_remote_domain_migrate_finish_args, (char *) &args,
+ (xdrproc_t) xdr_remote_domain_migrate_finish_ret, (char *) &ret) == -1)
+ return NULL;
+
+ ddom = get_nonnull_domain (dconn, ret.ddom);
+ xdr_free ((xdrproc_t) &xdr_remote_domain_migrate_finish_ret, (char *) &ret);
+
+ return ddom;
+}
+
static int
remoteListDefinedDomains (virConnectPtr conn, char **const names, int maxnames)
{
.domainGetSchedulerType = remoteDomainGetSchedulerType,
.domainGetSchedulerParameters = remoteDomainGetSchedulerParameters,
.domainSetSchedulerParameters = remoteDomainSetSchedulerParameters,
+ .domainMigratePrepare = remoteDomainMigratePrepare,
+ .domainMigratePerform = remoteDomainMigratePerform,
+ .domainMigrateFinish = remoteDomainMigrateFinish,
};
static virNetworkDriver network_driver = {
testDomainGetSchedulerType, /* domainGetSchedulerType */
testDomainGetSchedulerParams, /* domainGetSchedulerParameters */
testDomainSetSchedulerParams, /* domainSetSchedulerParameters */
+ NULL, /* domainMigratePrepare */
+ NULL, /* domainMigratePerform */
+ NULL, /* domainMigrateFinish */
};
static virNetworkDriver testNetworkDriver = {
return TRUE;
}
+/*
+ * "migrate" command
+ */
+static vshCmdInfo info_migrate[] = {
+ {"syntax", "migrate [--live] <domain> <desturi> [<migrateuri>]"},
+ {"help", gettext_noop("migrate domain to another host")},
+ {"desc", gettext_noop("Migrate domain to another host. Add --live for live migration.")},
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_migrate[] = {
+ {"live", VSH_OT_BOOL, 0, gettext_noop("live migration")},
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")},
+ {"desturi", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("connection URI of the destination host")},
+ {"migrateuri", VSH_OT_DATA, 0, gettext_noop("migration URI, usually can be omitted")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdMigrate (vshControl *ctl, vshCmd *cmd)
+{
+ virDomainPtr dom = NULL;
+ const char *desturi;
+ const char *migrateuri;
+ int flags = 0, found, ret = FALSE;
+ virConnectPtr dconn = NULL;
+ virDomainPtr ddom = NULL;
+
+ if (!vshConnectionUsability (ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if (!(dom = vshCommandOptDomain (ctl, cmd, "domain", NULL)))
+ return FALSE;
+
+ desturi = vshCommandOptString (cmd, "desturi", &found);
+ if (!found) {
+ vshError (ctl, FALSE, _("migrate: Missing desturi"));
+ goto done;
+ }
+
+ migrateuri = vshCommandOptString (cmd, "migrateuri", &found);
+ if (!found) migrateuri = NULL;
+
+ if (vshCommandOptBool (cmd, "live"))
+ flags |= VIR_MIGRATE_LIVE;
+
+ /* Temporarily connect to the destination host. */
+ dconn = virConnectOpen (desturi);
+ if (!dconn) goto done;
+
+ /* Migrate. */
+ ddom = virDomainMigrate (dom, dconn, flags, NULL, migrateuri, 0);
+ if (!ddom) goto done;
+
+ ret = TRUE;
+
+ done:
+ if (dom) virDomainFree (dom);
+ if (ddom) virDomainFree (ddom);
+ if (dconn) virConnectClose (dconn);
+ return ret;
+}
+
/*
* "net-autostart" command
*/
{"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
{"hostname", cmdHostname, NULL, info_hostname},
{"list", cmdList, opts_list, info_list},
+ {"migrate", cmdMigrate, opts_migrate, info_migrate},
{"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart},
{"net-create", cmdNetworkCreate, opts_network_create, info_network_create},
{"net-define", cmdNetworkDefine, opts_network_define, info_network_define},
"\
</features>\n\
</cpu>\n\
+ <migration_features>\n\
+ <live/>\n\
+ <uri_transports>\n\
+ <uri_transport>xenmigr</uri_transport>\n\
+ </uri_transports>\n\
+ </migration_features>\n\
</host>\n", -1);
if (r == -1) goto vir_buffer_failed;
return NULL;
}
+/* Which features are supported by this driver? */
+static int
+xenUnifiedSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
+{
+ switch (feature) {
+ case VIR_DRV_FEATURE_MIGRATION_V1: return 1;
+ default: return 0;
+ }
+}
+
static int
xenUnifiedVersion (virConnectPtr conn, unsigned long *hvVer)
{
return NULL;
}
+static int
+xenUnifiedDomainMigratePrepare (virConnectPtr dconn,
+ char **cookie,
+ int *cookielen,
+ const char *uri_in,
+ char **uri_out,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource)
+{
+ GET_PRIVATE(dconn);
+
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET])
+ return xenDaemonDomainMigratePrepare (dconn, cookie, cookielen,
+ uri_in, uri_out,
+ flags, dname, resource);
+
+ xenUnifiedError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+static int
+xenUnifiedDomainMigratePerform (virDomainPtr dom,
+ const char *cookie,
+ int cookielen,
+ const char *uri,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource)
+{
+ GET_PRIVATE(dom->conn);
+
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET])
+ return xenDaemonDomainMigratePerform (dom, cookie, cookielen, uri,
+ flags, dname, resource);
+
+ xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+static virDomainPtr
+xenUnifiedDomainMigrateFinish (virConnectPtr dconn,
+ const char *dname,
+ const char *cookie ATTRIBUTE_UNUSED,
+ int cookielen ATTRIBUTE_UNUSED,
+ const char *uri ATTRIBUTE_UNUSED,
+ unsigned long flags ATTRIBUTE_UNUSED)
+{
+ return xenUnifiedDomainLookupByName (dconn, dname);
+}
+
static int
xenUnifiedListDefinedDomains (virConnectPtr conn, char **const names,
int maxnames)
.ver = VERSION,
.open = xenUnifiedOpen,
.close = xenUnifiedClose,
+ .supports_feature = xenUnifiedSupportsFeature,
.type = xenUnifiedType,
.version = xenUnifiedVersion,
.getHostname = xenUnifiedGetHostname,
.domainGetSchedulerType = xenUnifiedDomainGetSchedulerType,
.domainGetSchedulerParameters = xenUnifiedDomainGetSchedulerParameters,
.domainSetSchedulerParameters = xenUnifiedDomainSetSchedulerParameters,
+ .domainMigratePrepare = xenUnifiedDomainMigratePrepare,
+ .domainMigratePerform = xenUnifiedDomainMigratePerform,
+ .domainMigrateFinish = xenUnifiedDomainMigrateFinish,
};
/**
*/
#ifdef WITH_XEN
+#include "config.h"
+
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
}
+int
+xenDaemonDomainMigratePrepare (virConnectPtr dconn,
+ char **cookie ATTRIBUTE_UNUSED,
+ int *cookielen ATTRIBUTE_UNUSED,
+ const char *uri_in,
+ char **uri_out,
+ unsigned long flags ATTRIBUTE_UNUSED,
+ const char *dname ATTRIBUTE_UNUSED,
+ unsigned long resource ATTRIBUTE_UNUSED)
+{
+ int r;
+ char hostname [HOST_NAME_MAX+1];
+
+ /* If uri_in is NULL, get the current hostname as a best guess
+ * of how the source host should connect to us. Note that caller
+ * deallocates this string.
+ */
+ if (uri_in == NULL) {
+ r = gethostname (hostname, HOST_NAME_MAX+1);
+ if (r == -1) {
+ virXendError (dconn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+ return -1;
+ }
+ *uri_out = strdup (hostname);
+ if (*uri_out == NULL) {
+ virXendError (dconn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+xenDaemonDomainMigratePerform (virDomainPtr domain,
+ const char *cookie ATTRIBUTE_UNUSED,
+ int cookielen ATTRIBUTE_UNUSED,
+ const char *uri,
+ unsigned long flags,
+ const char *dname,
+ unsigned long bandwidth)
+{
+ /* Upper layers have already checked domain. */
+ virConnectPtr conn = domain->conn;
+ /* NB: Passing port=0 to xend means it ignores
+ * the port. However this is somewhat specific to
+ * the internals of the xend Python code. (XXX).
+ */
+ char port[16] = "0";
+ char live[2] = "0";
+ int ret;
+ char *p, *hostname = NULL;
+
+ /* Xen doesn't support renaming domains during migration. */
+ if (dname) {
+ virXendError (conn, VIR_ERR_NO_SUPPORT,
+ "xenDaemonDomainMigrate: Xen does not support renaming domains during migration");
+ return -1;
+ }
+
+ /* Xen (at least up to 3.1.0) takes a resource parameter but
+ * ignores it.
+ */
+ if (bandwidth) {
+ virXendError (conn, VIR_ERR_NO_SUPPORT,
+ "xenDaemonDomainMigrate: Xen does not support bandwidth limits during migration");
+ return -1;
+ }
+
+ /* Check the flags. */
+ if ((flags & VIR_MIGRATE_LIVE)) {
+ strcpy (live, "1");
+ flags &= ~VIR_MIGRATE_LIVE;
+ }
+ if (flags != 0) {
+ virXendError (conn, VIR_ERR_NO_SUPPORT,
+ "xenDaemonDomainMigrate: unsupported flag");
+ return -1;
+ }
+
+ /* Set hostname and port.
+ *
+ * URI is non-NULL (guaranteed by caller). We expect either
+ * "hostname", "hostname:port" or "xenmigr://hostname[:port]/".
+ */
+ if (strstr (uri, "//")) { /* Full URI. */
+ xmlURIPtr uriptr = xmlParseURI (uri);
+ if (!uriptr) {
+ virXendError (conn, VIR_ERR_INVALID_ARG,
+ "xenDaemonDomainMigrate: invalid URI");
+ return -1;
+ }
+ if (uriptr->scheme && STRCASENEQ (uriptr->scheme, "xenmigr")) {
+ virXendError (conn, VIR_ERR_INVALID_ARG,
+ "xenDaemonDomainMigrate: only xenmigr:// migrations are supported by Xen");
+ xmlFreeURI (uriptr);
+ return -1;
+ }
+ if (!uriptr->server) {
+ virXendError (conn, VIR_ERR_INVALID_ARG,
+ "xenDaemonDomainMigrate: a hostname must be specified in the URI");
+ xmlFreeURI (uriptr);
+ return -1;
+ }
+ hostname = strdup (uriptr->server);
+ if (!hostname) {
+ virXendError (conn, VIR_ERR_NO_MEMORY, "strdup");
+ xmlFreeURI (uriptr);
+ return -1;
+ }
+ if (uriptr->port)
+ snprintf (port, sizeof port, "%d", uriptr->port);
+ xmlFreeURI (uriptr);
+ }
+ else if ((p = strrchr (uri, ':')) != NULL) { /* "hostname:port" */
+ int port_nr, n;
+
+ if (sscanf (p+1, "%d", &port_nr) != 1) {
+ virXendError (conn, VIR_ERR_INVALID_ARG,
+ "xenDaemonDomainMigrate: invalid port number");
+ return -1;
+ }
+ snprintf (port, sizeof port, "%d", port_nr);
+
+ /* Get the hostname. */
+ n = p - uri; /* n = Length of hostname in bytes. */
+ hostname = strdup (uri);
+ if (!hostname) {
+ virXendError (conn, VIR_ERR_NO_MEMORY, "strdup");
+ return -1;
+ }
+ hostname[n] = '\0';
+ }
+ else { /* "hostname" (or IP address) */
+ hostname = strdup (uri);
+ if (!hostname) {
+ virXendError (conn, VIR_ERR_NO_MEMORY, "strdup");
+ return -1;
+ }
+ }
+
+#ifdef ENABLE_DEBUG
+ fprintf (stderr, "hostname = %s, port = %s\n", hostname, port);
+#endif
+
+ /* Make the call. */
+ ret = xend_op (domain->conn, domain->name,
+ "op", "migrate",
+ "destination", hostname,
+ "live", live,
+ "port", port,
+ "resource", "0", /* required, xend ignores it */
+ NULL);
+ free (hostname);
+
+#ifdef ENABLE_DEBUG
+ fprintf (stderr, "migration done\n");
+#endif
+
+ return ret;
+}
+
virDomainPtr xenDaemonDomainDefineXML(virConnectPtr conn, const char *xmlDesc) {
int ret;
char *sexpr;
virDomainPtr xenDaemonLookupByID(virConnectPtr conn, int id);
virDomainPtr xenDaemonLookupByUUID(virConnectPtr conn, const unsigned char *uuid);
virDomainPtr xenDaemonLookupByName(virConnectPtr conn, const char *domname);
+int xenDaemonDomainMigratePrepare (virConnectPtr dconn, char **cookie, int *cookielen, const char *uri_in, char **uri_out, unsigned long flags, const char *dname, unsigned long resource);
+int xenDaemonDomainMigratePerform (virDomainPtr domain, const char *cookie, int cookielen, const char *uri, unsigned long flags, const char *dname, unsigned long resource);
#ifdef __cplusplus
}