mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 11:35:19 +00:00
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.
This commit is contained in:
parent
4d8c013104
commit
81005437f4
14
ChangeLog
14
ChangeLog
@ -1,3 +1,17 @@
|
||||
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,
|
||||
|
@ -243,6 +243,12 @@ updated on <i>2007-08-20</i>.
|
||||
<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>
|
||||
|
@ -2996,6 +2996,14 @@ updated on <i>2007-08-20</i>.
|
||||
<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>
|
||||
|
@ -197,6 +197,16 @@ int virDomainSetSchedulerParameters (virDomainPtr domain,
|
||||
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
|
||||
|
@ -197,6 +197,16 @@ int virDomainSetSchedulerParameters (virDomainPtr domain,
|
||||
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
|
||||
|
@ -1058,6 +1058,91 @@ remoteDispatchDomainGetVcpus (struct qemud_client *client,
|
||||
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,
|
||||
|
@ -12,6 +12,8 @@ remote_domain_save_args lv_remote_domain_save_args;
|
||||
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;
|
||||
@ -79,6 +81,8 @@ remote_network_get_bridge_name_ret lv_remote_network_get_bridge_name_ret;
|
||||
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;
|
||||
@ -88,3 +92,4 @@ remote_domain_dump_xml_ret lv_remote_domain_dump_xml_ret;
|
||||
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;
|
||||
|
@ -161,6 +161,30 @@ case REMOTE_PROC_DOMAIN_LOOKUP_BY_UUID:
|
||||
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;
|
||||
|
@ -22,6 +22,9 @@ static int remoteDispatchDomainGetVcpus (struct qemud_client *client, remote_mes
|
||||
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);
|
||||
|
@ -677,6 +677,78 @@ xdr_remote_domain_dump_xml_ret (XDR *xdrs, remote_domain_dump_xml_ret *objp)
|
||||
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)
|
||||
{
|
||||
|
@ -25,6 +25,7 @@ typedef remote_nonnull_string *remote_string;
|
||||
#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
|
||||
|
||||
@ -341,6 +342,52 @@ struct remote_domain_dump_xml_ret {
|
||||
};
|
||||
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;
|
||||
};
|
||||
@ -643,6 +690,9 @@ enum remote_procedure {
|
||||
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;
|
||||
|
||||
@ -727,6 +777,11 @@ extern bool_t xdr_remote_domain_restore_args (XDR *, remote_domain_restore_args
|
||||
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*);
|
||||
@ -830,6 +885,11 @@ extern bool_t xdr_remote_domain_restore_args ();
|
||||
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 ();
|
||||
|
@ -72,6 +72,9 @@ const REMOTE_VCPUINFO_MAX = 2048;
|
||||
/* 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;
|
||||
|
||||
@ -265,7 +268,6 @@ struct remote_domain_lookup_by_id_args {
|
||||
};
|
||||
|
||||
struct remote_domain_lookup_by_id_ret {
|
||||
/* XXX "Not found" semantic is ill-defined. */
|
||||
remote_nonnull_domain dom;
|
||||
};
|
||||
|
||||
@ -274,7 +276,6 @@ struct remote_domain_lookup_by_uuid_args {
|
||||
};
|
||||
|
||||
struct remote_domain_lookup_by_uuid_ret {
|
||||
/* XXX "Not found" semantic is ill-defined. */
|
||||
remote_nonnull_domain dom;
|
||||
};
|
||||
|
||||
@ -283,7 +284,6 @@ struct remote_domain_lookup_by_name_args {
|
||||
};
|
||||
|
||||
struct remote_domain_lookup_by_name_ret {
|
||||
/* XXX "Not found" semantic is ill-defined. */
|
||||
remote_nonnull_domain dom;
|
||||
};
|
||||
|
||||
@ -370,6 +370,38 @@ struct remote_domain_dump_xml_ret {
|
||||
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;
|
||||
};
|
||||
@ -482,7 +514,6 @@ struct remote_network_lookup_by_uuid_args {
|
||||
};
|
||||
|
||||
struct remote_network_lookup_by_uuid_ret {
|
||||
/* XXX "Not found" semantic is ill-defined. */
|
||||
remote_nonnull_network net;
|
||||
};
|
||||
|
||||
@ -491,7 +522,6 @@ struct remote_network_lookup_by_name_args {
|
||||
};
|
||||
|
||||
struct remote_network_lookup_by_name_ret {
|
||||
/* XXX "Not found" semantic is ill-defined. */
|
||||
remote_nonnull_network net;
|
||||
};
|
||||
|
||||
@ -619,7 +649,10 @@ enum remote_procedure {
|
||||
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. */
|
||||
|
@ -13,7 +13,7 @@ INCLUDES = -I$(top_builddir)/include \
|
||||
$(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
|
||||
|
33
src/driver.h
33
src/driver.h
@ -211,6 +211,36 @@ typedef int
|
||||
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;
|
||||
|
||||
@ -276,6 +306,9 @@ struct _virDriver {
|
||||
virDrvDomainGetSchedulerType domainGetSchedulerType;
|
||||
virDrvDomainGetSchedulerParameters domainGetSchedulerParameters;
|
||||
virDrvDomainSetSchedulerParameters domainSetSchedulerParameters;
|
||||
virDrvDomainMigratePrepare domainMigratePrepare;
|
||||
virDrvDomainMigratePerform domainMigratePerform;
|
||||
virDrvDomainMigrateFinish domainMigrateFinish;
|
||||
};
|
||||
|
||||
typedef int
|
||||
|
@ -231,6 +231,10 @@ int __virStateActive(void);
|
||||
|
||||
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 */
|
||||
|
219
src/libvirt.c
219
src/libvirt.c
@ -18,6 +18,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/xpath.h>
|
||||
@ -1673,6 +1674,224 @@ virDomainGetXMLDesc(virDomainPtr domain, int flags)
|
||||
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
|
||||
|
@ -69,6 +69,8 @@
|
||||
virDomainAttachDevice;
|
||||
virDomainDetachDevice;
|
||||
|
||||
virDomainMigrate;
|
||||
|
||||
virNetworkGetConnect;
|
||||
virConnectNumOfNetworks;
|
||||
virConnectListNetworks;
|
||||
@ -118,5 +120,9 @@
|
||||
|
||||
__virDrvSupportsFeature;
|
||||
|
||||
__virDomainMigratePrepare;
|
||||
__virDomainMigratePerform;
|
||||
__virDomainMigrateFinish;
|
||||
|
||||
local: *;
|
||||
};
|
||||
|
@ -2662,6 +2662,9 @@ static virDriver qemuDriver = {
|
||||
NULL, /* domainGetSchedulerType */
|
||||
NULL, /* domainGetSchedulerParameters */
|
||||
NULL, /* domainSetSchedulerParameters */
|
||||
NULL, /* domainMigratePrepare */
|
||||
NULL, /* domainMigratePerform */
|
||||
NULL, /* domainMigrateFinish */
|
||||
};
|
||||
|
||||
static virNetworkDriver qemuNetworkDriver = {
|
||||
|
@ -1856,6 +1856,97 @@ remoteDomainDumpXML (virDomainPtr domain, int flags)
|
||||
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)
|
||||
{
|
||||
@ -2963,6 +3054,9 @@ static virDriver driver = {
|
||||
.domainGetSchedulerType = remoteDomainGetSchedulerType,
|
||||
.domainGetSchedulerParameters = remoteDomainGetSchedulerParameters,
|
||||
.domainSetSchedulerParameters = remoteDomainSetSchedulerParameters,
|
||||
.domainMigratePrepare = remoteDomainMigratePrepare,
|
||||
.domainMigratePerform = remoteDomainMigratePerform,
|
||||
.domainMigrateFinish = remoteDomainMigrateFinish,
|
||||
};
|
||||
|
||||
static virNetworkDriver network_driver = {
|
||||
|
@ -1964,6 +1964,9 @@ static virDriver testDriver = {
|
||||
testDomainGetSchedulerType, /* domainGetSchedulerType */
|
||||
testDomainGetSchedulerParams, /* domainGetSchedulerParameters */
|
||||
testDomainSetSchedulerParams, /* domainSetSchedulerParameters */
|
||||
NULL, /* domainMigratePrepare */
|
||||
NULL, /* domainMigratePerform */
|
||||
NULL, /* domainMigrateFinish */
|
||||
};
|
||||
|
||||
static virNetworkDriver testNetworkDriver = {
|
||||
|
64
src/virsh.c
64
src/virsh.c
@ -2022,6 +2022,69 @@ cmdDomuuid(vshControl * ctl, vshCmd * cmd)
|
||||
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
|
||||
*/
|
||||
@ -3469,6 +3532,7 @@ static vshCmdDef commands[] = {
|
||||
{"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},
|
||||
|
@ -2216,6 +2216,12 @@ xenHypervisorMakeCapabilitiesXML(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
"\
|
||||
</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;
|
||||
|
||||
|
@ -214,6 +214,16 @@ xenUnifiedType (virConnectPtr conn)
|
||||
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)
|
||||
{
|
||||
@ -805,6 +815,57 @@ xenUnifiedDomainDumpXML (virDomainPtr dom, int flags)
|
||||
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)
|
||||
@ -975,6 +1036,7 @@ static virDriver xenUnifiedDriver = {
|
||||
.ver = VERSION,
|
||||
.open = xenUnifiedOpen,
|
||||
.close = xenUnifiedClose,
|
||||
.supports_feature = xenUnifiedSupportsFeature,
|
||||
.type = xenUnifiedType,
|
||||
.version = xenUnifiedVersion,
|
||||
.getHostname = xenUnifiedGetHostname,
|
||||
@ -1016,6 +1078,9 @@ static virDriver xenUnifiedDriver = {
|
||||
.domainGetSchedulerType = xenUnifiedDomainGetSchedulerType,
|
||||
.domainGetSchedulerParameters = xenUnifiedDomainGetSchedulerParameters,
|
||||
.domainSetSchedulerParameters = xenUnifiedDomainSetSchedulerParameters,
|
||||
.domainMigratePrepare = xenUnifiedDomainMigratePrepare,
|
||||
.domainMigratePerform = xenUnifiedDomainMigratePerform,
|
||||
.domainMigrateFinish = xenUnifiedDomainMigrateFinish,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -11,6 +11,8 @@
|
||||
*/
|
||||
|
||||
#ifdef WITH_XEN
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
@ -3148,6 +3150,168 @@ xenDaemonDetachDevice(virDomainPtr domain, char *xml)
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -219,6 +219,8 @@ int xenDaemonInit (void);
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user