Interface --------- The interface is now this: virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, unsigned long flags, const char *dname, const char *uri, unsigned long resource);The caller may set dname, uri and resource to 0/NULL and forget about them. Or else the caller may set, in particular, uri to allow for more complicated migration strategies (especially for qemu).
https://www.redhat.com/archives/libvir-list/2007-July/msg00249.html Driver support -------------- As outlined in the diagram in this email: https://www.redhat.com/archives/libvir-list/2007-July/msg00264.html migration happens in two stages.Firstly we send a "prepare" message to the destination host. The destination host may reply with a cookie. It may also suggest a URI (in the current Xen implementation it just returns gethostname). Secondly we send a "perform" message to the source host.
Correspondingly, there are two new driver API functions: 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); Remote support --------------To make this work in the remote case I have had to export two private functions from the API which only remote should call:
__virDomainMigratePrepare __virDomainMigratePerformThe reason for this is that libvirtd is just linked to the regular libvirt.so, so can only make calls into libvirt through exported symbols in the dynamic symbol table.
There are two corresponding wire messages (REMOTE_PROC_DOMAIN_MIGRATE_PREPARE and REMOTE_PROC_DOMAIN_MIGRATE_PERFORM) but they just do dumb argument shuffling, albeit rather complicated because of the number of arguments passed in and out.
The complete list of messages which go across the wire during a migration is:
client -- prepare --> destination host client <-- prepare reply -- destination host client -- perform --> source host client <-- perform reply -- source host client -- lookupbyname --> destination host client <-- lookupbyname reply -- destination host Xen URIs -------- Xen recognises the following forms of URI: hostname hostname:port tcp://hostname/ tcp://hostname:port/ Capabilities ------------ I have extended capabilities with <migration_features>. For Xen this is: <capabilities> <host> <migration_features> <live/> <uri_transports> <uri_transport>tcp</uri_transport> </uri_transports> </migration_features> Rich. -- Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/ Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 03798903
? migrate-remote.fig ? migrate-remote.png Index: include/libvirt/libvirt.h =================================================================== RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h,v retrieving revision 1.50 diff -u -p -r1.50 libvirt.h --- include/libvirt/libvirt.h 18 Jul 2007 10:11:10 -0000 1.50 +++ include/libvirt/libvirt.h 18 Jul 2007 19:00:07 -0000 @@ -197,6 +197,14 @@ int virDomainSetSchedulerParameters (vir virSchedParameterPtr params, int nparams); +/* Domain migration flags. */ +#define VIR_MIGRATE_LIVE 1 + +/* Domain migration. */ +virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, + unsigned long flags, const char *dname, + const char *uri, unsigned long resource); + /** * VIR_NODEINFO_MAXCPUS: * @nodeinfo: virNodeInfo instance Index: include/libvirt/libvirt.h.in =================================================================== RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h.in,v retrieving revision 1.31 diff -u -p -r1.31 libvirt.h.in --- include/libvirt/libvirt.h.in 18 Jul 2007 10:11:10 -0000 1.31 +++ include/libvirt/libvirt.h.in 18 Jul 2007 19:00:07 -0000 @@ -197,6 +197,14 @@ int virDomainSetSchedulerParameters (vir virSchedParameterPtr params, int nparams); +/* Domain migration flags. */ +#define VIR_MIGRATE_LIVE 1 + +/* Domain migration. */ +virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, + unsigned long flags, const char *dname, + const char *uri, unsigned long resource); + /** * VIR_NODEINFO_MAXCPUS: * @nodeinfo: virNodeInfo instance Index: qemud/remote.c =================================================================== RCS file: /data/cvs/libvirt/qemud/remote.c,v retrieving revision 1.5 diff -u -p -r1.5 remote.c --- qemud/remote.c 26 Jun 2007 23:48:47 -0000 1.5 +++ qemud/remote.c 18 Jul 2007 19:00:09 -0000 @@ -1004,6 +1004,72 @@ remoteDispatchDomainGetVcpus (struct qem } 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 remoteDispatchListDefinedDomains (struct qemud_client *client, remote_message_header *req, remote_list_defined_domains_args *args, Index: qemud/remote_dispatch_localvars.h =================================================================== RCS file: /data/cvs/libvirt/qemud/remote_dispatch_localvars.h,v retrieving revision 1.3 diff -u -p -r1.3 remote_dispatch_localvars.h --- qemud/remote_dispatch_localvars.h 26 Jun 2007 11:42:46 -0000 1.3 +++ qemud/remote_dispatch_localvars.h 18 Jul 2007 19:00:09 -0000 @@ -12,6 +12,8 @@ remote_domain_save_args lv_remote_domain 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; @@ -86,3 +88,4 @@ remote_domain_dump_xml_ret lv_remote_dom 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; Index: qemud/remote_dispatch_proc_switch.h =================================================================== RCS file: /data/cvs/libvirt/qemud/remote_dispatch_proc_switch.h,v retrieving revision 1.3 diff -u -p -r1.3 remote_dispatch_proc_switch.h --- qemud/remote_dispatch_proc_switch.h 26 Jun 2007 11:42:46 -0000 1.3 +++ qemud/remote_dispatch_proc_switch.h 18 Jul 2007 19:00:09 -0000 @@ -161,6 +161,21 @@ 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_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; Index: qemud/remote_dispatch_prototypes.h =================================================================== RCS file: /data/cvs/libvirt/qemud/remote_dispatch_prototypes.h,v retrieving revision 1.3 diff -u -p -r1.3 remote_dispatch_prototypes.h --- qemud/remote_dispatch_prototypes.h 26 Jun 2007 11:42:46 -0000 1.3 +++ qemud/remote_dispatch_prototypes.h 18 Jul 2007 19:00:09 -0000 @@ -22,6 +22,8 @@ static int remoteDispatchDomainGetVcpus 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 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); Index: qemud/remote_protocol.c =================================================================== RCS file: /data/cvs/libvirt/qemud/remote_protocol.c,v retrieving revision 1.3 diff -u -p -r1.3 remote_protocol.c --- qemud/remote_protocol.c 26 Jun 2007 11:42:46 -0000 1.3 +++ qemud/remote_protocol.c 18 Jul 2007 19:00:10 -0000 @@ -660,6 +660,53 @@ xdr_remote_domain_dump_xml_ret (XDR *xdr } 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_list_defined_domains_args (XDR *xdrs, remote_list_defined_domains_args *objp) { Index: qemud/remote_protocol.h =================================================================== RCS file: /data/cvs/libvirt/qemud/remote_protocol.h,v retrieving revision 1.3 diff -u -p -r1.3 remote_protocol.h --- qemud/remote_protocol.h 26 Jun 2007 11:42:46 -0000 1.3 +++ qemud/remote_protocol.h 18 Jul 2007 19:00:11 -0000 @@ -25,6 +25,7 @@ typedef remote_nonnull_string *remote_st #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 @@ -331,6 +332,36 @@ 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_list_defined_domains_args { int maxnames; }; @@ -632,6 +663,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS = 57, REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS = 58, REMOTE_PROC_GET_HOSTNAME = 59, + REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 60, + REMOTE_PROC_DOMAIN_MIGRATE_PREPARE = 61, }; typedef enum remote_procedure remote_procedure; @@ -714,6 +747,9 @@ extern bool_t xdr_remote_domain_restore 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_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*); @@ -815,6 +851,9 @@ extern bool_t xdr_remote_domain_restore_ 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_list_defined_domains_args (); extern bool_t xdr_remote_list_defined_domains_ret (); extern bool_t xdr_remote_num_of_defined_domains_ret (); Index: qemud/remote_protocol.x =================================================================== RCS file: /data/cvs/libvirt/qemud/remote_protocol.x,v retrieving revision 1.3 diff -u -p -r1.3 remote_protocol.x --- qemud/remote_protocol.x 26 Jun 2007 11:42:46 -0000 1.3 +++ qemud/remote_protocol.x 18 Jul 2007 19:00:11 -0000 @@ -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; @@ -257,7 +260,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; }; @@ -266,7 +268,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; }; @@ -275,7 +276,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; }; @@ -362,6 +362,27 @@ 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_list_defined_domains_args { int maxnames; }; @@ -474,7 +495,6 @@ struct remote_network_lookup_by_uuid_arg }; struct remote_network_lookup_by_uuid_ret { - /* XXX "Not found" semantic is ill-defined. */ remote_nonnull_network net; }; @@ -483,7 +503,6 @@ struct remote_network_lookup_by_name_arg }; struct remote_network_lookup_by_name_ret { - /* XXX "Not found" semantic is ill-defined. */ remote_nonnull_network net; }; @@ -610,7 +629,9 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_SCHEDULER_TYPE = 56, REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS = 57, REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS = 58, - REMOTE_PROC_GET_HOSTNAME = 59 + REMOTE_PROC_GET_HOSTNAME = 59, + REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 60, + REMOTE_PROC_DOMAIN_MIGRATE_PREPARE = 61 }; /* Custom RPC structure. */ Index: src/driver.h =================================================================== RCS file: /data/cvs/libvirt/src/driver.h,v retrieving revision 1.31 diff -u -p -r1.31 driver.h --- src/driver.h 17 Jul 2007 13:27:26 -0000 1.31 +++ src/driver.h 18 Jul 2007 19:00:11 -0000 @@ -181,6 +181,27 @@ 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 struct _virDriver virDriver; typedef virDriver *virDriverPtr; @@ -245,6 +266,8 @@ struct _virDriver { virDrvDomainGetSchedulerType domainGetSchedulerType; virDrvDomainGetSchedulerParameters domainGetSchedulerParameters; virDrvDomainSetSchedulerParameters domainSetSchedulerParameters; + virDrvDomainMigratePrepare domainMigratePrepare; + virDrvDomainMigratePerform domainMigratePerform; }; typedef int Index: src/internal.h =================================================================== RCS file: /data/cvs/libvirt/src/internal.h,v retrieving revision 1.46 diff -u -p -r1.46 internal.h --- src/internal.h 6 Jul 2007 15:02:09 -0000 1.46 +++ src/internal.h 18 Jul 2007 19:00:11 -0000 @@ -227,6 +227,9 @@ int __virStateActive(void); #define virStateReload() __virStateReload() #define virStateActive() __virStateActive() +int __virDomainMigratePrepare (virConnectPtr dconn, char **cookie, int *cookielen, const char *uri_in, char **uri_out, unsigned long flags, const char *dname, unsigned long resource); +int __virDomainMigratePerform (virDomainPtr domain, const char *cookie, int cookielen, const char *uri, unsigned long flags, const char *dname, unsigned long resource); + #ifdef __cplusplus } #endif /* __cplusplus */ Index: src/libvirt.c =================================================================== RCS file: /data/cvs/libvirt/src/libvirt.c,v retrieving revision 1.90 diff -u -p -r1.90 libvirt.c --- src/libvirt.c 17 Jul 2007 14:40:26 -0000 1.90 +++ src/libvirt.c 18 Jul 2007 19:00:13 -0000 @@ -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> @@ -1668,6 +1669,187 @@ virDomainGetXMLDesc(virDomainPtr domain, } /** + * 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 + * @resource: (optional) specify resource 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 resource parameter. If set to 0, + * libvirt will choose a suitable default. Some hypervisors do + * not support this feature and will return an error if resource + * 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. + */ +virDomainPtr +virDomainMigrate (virDomainPtr domain, + virConnectPtr dconn, + unsigned long flags, + const char *dname, + const char *uri, + unsigned long resource) +{ + virConnectPtr conn; + char *uri_out = NULL; + char *cookie = NULL; + int cookielen = 0, ret; + DEBUG("domain=%p, dconn=%p, flags=%lu, dname=%s, uri=%s, resource=%lu", + domain, dconn, flags, dname, uri, resource); + + 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. + * Note that in the remote case these functions always exist. + * But the remote driver will throw NO_SUPPORT errors later. + */ + if (!conn->driver->domainMigratePerform || + !dconn->driver->domainMigratePrepare) { + 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, resource); + if (ret == -1) return NULL; + if (uri == NULL && uri_out == NULL) { + virLibConnError (conn, VIR_ERR_INTERNAL_ERROR, + "domainMigratePrepare did not set uri"); + if (cookie) free (cookie); + return NULL; + } + 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, resource); + + if (uri_out) free (uri_out); + if (cookie) free (cookie); + + if (ret == -1) return NULL; + + /* Get the destination domain and return it or error. */ + return virDomainLookupByName (dconn, dname ? dname : domain->name); +} + +/* 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 resource) +{ + DEBUG("dconn=%p, cookie=%p, cookielen=%p, uri_in=%s, uri_out=%p, flags=%lu, dname=%s, resource=%lu", dconn, cookie, cookielen, uri_in, uri_out, flags, dname, resource); + + 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, resource); + + 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 resource) +{ + virConnectPtr conn; + DEBUG("domain=%p, cookie=%p, cookielen=%d, uri=%s, flags=%lu, dname=%s, resource=%lu", domain, cookie, cookielen, uri, flags, dname, resource); + + 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, resource); + + virLibDomainError (domain, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** * virNodeGetInfo: * @conn: pointer to the hypervisor connection * @info: pointer to a virNodeInfo structure allocated by the user Index: src/libvirt_sym.version =================================================================== RCS file: /data/cvs/libvirt/src/libvirt_sym.version,v retrieving revision 1.25 diff -u -p -r1.25 libvirt_sym.version --- src/libvirt_sym.version 26 Jun 2007 22:56:14 -0000 1.25 +++ src/libvirt_sym.version 18 Jul 2007 19:00:13 -0000 @@ -69,6 +69,8 @@ virDomainAttachDevice; virDomainDetachDevice; + virDomainMigrate; + virNetworkGetConnect; virConnectNumOfNetworks; virConnectListNetworks; @@ -116,5 +118,8 @@ __virStateReload; __virStateActive; + __virDomainMigratePrepare; + __virDomainMigratePerform; + local: *; }; Index: src/qemu_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/qemu_driver.c,v retrieving revision 1.8 diff -u -p -r1.8 qemu_driver.c --- src/qemu_driver.c 12 Jul 2007 15:09:01 -0000 1.8 +++ src/qemu_driver.c 18 Jul 2007 19:00:15 -0000 @@ -2507,6 +2507,8 @@ static virDriver qemuDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainMigratePrepare */ + NULL, /* domainMigratePerform */ }; static virNetworkDriver qemuNetworkDriver = { Index: src/remote_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/remote_internal.c,v retrieving revision 1.15 diff -u -p -r1.15 remote_internal.c --- src/remote_internal.c 12 Jul 2007 15:17:08 -0000 1.15 +++ src/remote_internal.c 18 Jul 2007 19:00:17 -0000 @@ -1831,6 +1831,66 @@ remoteDomainDumpXML (virDomainPtr domain } 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 int remoteListDefinedDomains (virConnectPtr conn, char **const names, int maxnames) { int i; @@ -2947,6 +3007,8 @@ static virDriver driver = { .domainGetSchedulerType = remoteDomainGetSchedulerType, .domainGetSchedulerParameters = remoteDomainGetSchedulerParameters, .domainSetSchedulerParameters = remoteDomainSetSchedulerParameters, + .domainMigratePrepare = remoteDomainMigratePrepare, + .domainMigratePerform = remoteDomainMigratePerform, }; static virNetworkDriver network_driver = { Index: src/test.c =================================================================== RCS file: /data/cvs/libvirt/src/test.c,v retrieving revision 1.42 diff -u -p -r1.42 test.c --- src/test.c 18 Jul 2007 10:11:09 -0000 1.42 +++ src/test.c 18 Jul 2007 19:00:18 -0000 @@ -144,6 +144,8 @@ static virDriver testDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainMigratePerform */ + NULL, /* domainMigratePrepare */ }; /* Per-connection private data. */ Index: src/xen_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xen_internal.c,v retrieving revision 1.85 diff -u -p -r1.85 xen_internal.c --- src/xen_internal.c 12 Jul 2007 08:57:52 -0000 1.85 +++ src/xen_internal.c 18 Jul 2007 19:00:20 -0000 @@ -2173,6 +2173,12 @@ xenHypervisorMakeCapabilitiesXML(virConn "\ </features>\n\ </cpu>\n\ + <migration_features>\n\ + <live/>\n\ + <uri_transports>\n\ + <uri_transport>tcp</uri_transport>\n\ + </uri_transports>\n\ + </migration_features>\n\ </host>\n", -1); if (r == -1) goto vir_buffer_failed; Index: src/xen_unified.c =================================================================== RCS file: /data/cvs/libvirt/src/xen_unified.c,v retrieving revision 1.17 diff -u -p -r1.17 xen_unified.c --- src/xen_unified.c 12 Jul 2007 08:34:51 -0000 1.17 +++ src/xen_unified.c 18 Jul 2007 19:00:20 -0000 @@ -792,6 +792,46 @@ xenUnifiedDomainDumpXML (virDomainPtr do } 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 int xenUnifiedListDefinedDomains (virConnectPtr conn, char **const names, int maxnames) { @@ -1002,6 +1042,8 @@ static virDriver xenUnifiedDriver = { .domainGetSchedulerType = xenUnifiedDomainGetSchedulerType, .domainGetSchedulerParameters = xenUnifiedDomainGetSchedulerParameters, .domainSetSchedulerParameters = xenUnifiedDomainSetSchedulerParameters, + .domainMigratePrepare = xenUnifiedDomainMigratePrepare, + .domainMigratePerform = xenUnifiedDomainMigratePerform, }; /** Index: src/xend_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.c,v retrieving revision 1.130 diff -u -p -r1.130 xend_internal.c --- src/xend_internal.c 16 Jul 2007 21:30:30 -0000 1.130 +++ src/xend_internal.c 18 Jul 2007 19:00:22 -0000 @@ -11,6 +11,8 @@ */ #ifdef WITH_XEN +#include "config.h" + #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> @@ -3131,6 +3133,169 @@ xenDaemonDetachDevice(virDomainPtr domai } +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 resource) +{ + /* 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 (resource) { + virXendError (conn, VIR_ERR_NO_SUPPORT, + "xenDaemonDomainMigrate: Xen does not support resource 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 "tcp://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, "tcp")) { + virXendError (conn, VIR_ERR_INVALID_ARG, + "xenDaemonDomainMigrate: only tcp:// 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; Index: src/xend_internal.h =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.h,v retrieving revision 1.31 diff -u -p -r1.31 xend_internal.h --- src/xend_internal.h 6 Jul 2007 15:11:22 -0000 1.31 +++ src/xend_internal.h 18 Jul 2007 19:00:23 -0000 @@ -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 }
Attachment:
smime.p7s
Description: S/MIME Cryptographic Signature
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list