This is a repost of version 5 patch. Previous discussion of version 5: https://www.redhat.com/archives/libvir-list/2007-July/thread.html#00357 Previous discussion of version 4: https://www.redhat.com/archives/libvir-list/2007-July/thread.html#00304(This is separate from the feature patch, but in reality if the feature patch goes in, then I'd modify this patch slightly to make it use feature detection).
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
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 23 Jul 2007 15:22:00 -0000 @@ -197,6 +197,16 @@ int virDomainSetSchedulerParameters (vir 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 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 23 Jul 2007 15:22:01 -0000 @@ -197,6 +197,16 @@ int virDomainSetSchedulerParameters (vir 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 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 23 Jul 2007 15:22:02 -0000 @@ -1004,6 +1004,91 @@ 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 +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_list_defined_domains_args *args, 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 23 Jul 2007 15:22:03 -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,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; }; @@ -474,7 +506,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 +514,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 +640,10 @@ 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_PREPARE = 60, + REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 61, + REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 62 }; /* 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 23 Jul 2007 15:22:03 -0000 @@ -181,6 +181,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; @@ -245,6 +275,9 @@ struct _virDriver { virDrvDomainGetSchedulerType domainGetSchedulerType; virDrvDomainGetSchedulerParameters domainGetSchedulerParameters; virDrvDomainSetSchedulerParameters domainSetSchedulerParameters; + virDrvDomainMigratePrepare domainMigratePrepare; + virDrvDomainMigratePerform domainMigratePerform; + virDrvDomainMigrateFinish domainMigrateFinish; }; 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 23 Jul 2007 15:22:03 -0000 @@ -227,6 +227,10 @@ 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 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 */ 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 23 Jul 2007 15:22:05 -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,225 @@ 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 + * @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. + * 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, 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 * @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 23 Jul 2007 15:22:05 -0000 @@ -69,6 +69,8 @@ virDomainAttachDevice; virDomainDetachDevice; + virDomainMigrate; + virNetworkGetConnect; virConnectNumOfNetworks; virConnectListNetworks; @@ -116,5 +118,9 @@ __virStateReload; __virStateActive; + __virDomainMigratePrepare; + __virDomainMigratePerform; + __virDomainMigrateFinish; + local: *; }; Index: src/qemu_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/qemu_driver.c,v retrieving revision 1.9 diff -u -p -r1.9 qemu_driver.c --- src/qemu_driver.c 19 Jul 2007 16:22:40 -0000 1.9 +++ src/qemu_driver.c 23 Jul 2007 15:22:06 -0000 @@ -2423,6 +2423,9 @@ static virDriver qemuDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainMigratePrepare */ + NULL, /* domainMigratePerform */ + NULL, /* domainMigrateFinish */ }; 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 23 Jul 2007 15:22:08 -0000 @@ -1831,6 +1831,97 @@ 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 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) { int i; @@ -2947,6 +3038,9 @@ static virDriver driver = { .domainGetSchedulerType = remoteDomainGetSchedulerType, .domainGetSchedulerParameters = remoteDomainGetSchedulerParameters, .domainSetSchedulerParameters = remoteDomainSetSchedulerParameters, + .domainMigratePrepare = remoteDomainMigratePrepare, + .domainMigratePerform = remoteDomainMigratePerform, + .domainMigrateFinish = remoteDomainMigrateFinish, }; 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 23 Jul 2007 15:22:09 -0000 @@ -144,6 +144,9 @@ static virDriver testDriver = { NULL, /* domainGetSchedulerType */ NULL, /* domainGetSchedulerParameters */ NULL, /* domainSetSchedulerParameters */ + NULL, /* domainMigratePrepare */ + NULL, /* domainMigratePerform */ + NULL, /* domainMigrateFinish */ }; /* Per-connection private data. */ Index: src/virsh.c =================================================================== RCS file: /data/cvs/libvirt/src/virsh.c,v retrieving revision 1.92 diff -u -p -r1.92 virsh.c --- src/virsh.c 6 Jul 2007 15:05:19 -0000 1.92 +++ src/virsh.c 23 Jul 2007 15:22:10 -0000 @@ -2022,6 +2022,69 @@ cmdDomuuid(vshControl * ctl, vshCmd * cm } /* + * "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 */ static vshCmdInfo info_network_autostart[] = { @@ -3405,6 +3468,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}, Index: src/xen_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xen_internal.c,v retrieving revision 1.89 diff -u -p -r1.89 xen_internal.c --- src/xen_internal.c 20 Jul 2007 10:53:31 -0000 1.89 +++ src/xen_internal.c 23 Jul 2007 15:22:11 -0000 @@ -2198,6 +2198,12 @@ xenHypervisorMakeCapabilitiesXML(virConn "\ </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; 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 23 Jul 2007 15:22:12 -0000 @@ -792,6 +792,57 @@ 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 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) { @@ -1002,6 +1053,9 @@ static virDriver xenUnifiedDriver = { .domainGetSchedulerType = xenUnifiedDomainGetSchedulerType, .domainGetSchedulerParameters = xenUnifiedDomainGetSchedulerParameters, .domainSetSchedulerParameters = xenUnifiedDomainSetSchedulerParameters, + .domainMigratePrepare = xenUnifiedDomainMigratePrepare, + .domainMigratePerform = xenUnifiedDomainMigratePerform, + .domainMigrateFinish = xenUnifiedDomainMigrateFinish, }; /** Index: src/xend_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.c,v retrieving revision 1.131 diff -u -p -r1.131 xend_internal.c --- src/xend_internal.c 18 Jul 2007 21:08:22 -0000 1.131 +++ src/xend_internal.c 23 Jul 2007 15:22:13 -0000 @@ -11,6 +11,8 @@ */ #ifdef WITH_XEN +#include "config.h" + #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> @@ -3152,6 +3154,168 @@ 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 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; 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 23 Jul 2007 15:22:13 -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