]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Tue Aug 21 10:21:00 BST 2007 Richard W.M. Jones <rjones@redhat.com>
authorRichard W.M. Jones <rjones@redhat.com>
Tue, 21 Aug 2007 09:31:12 +0000 (09:31 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Tue, 21 Aug 2007 09:31:12 +0000 (09:31 +0000)
* 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.

25 files changed:
ChangeLog
docs/hvsupport.html
docs/libvir.html
include/libvirt/libvirt.h
include/libvirt/libvirt.h.in
qemud/remote.c
qemud/remote_dispatch_localvars.h
qemud/remote_dispatch_proc_switch.h
qemud/remote_dispatch_prototypes.h
qemud/remote_protocol.c
qemud/remote_protocol.h
qemud/remote_protocol.x
src/Makefile.am
src/driver.h
src/internal.h
src/libvirt.c
src/libvirt_sym.version
src/qemu_driver.c
src/remote_internal.c
src/test.c
src/virsh.c
src/xen_internal.c
src/xen_unified.c
src/xend_internal.c
src/xend_internal.h

index 558e3e40556679d6a97441c2b1b7e346dfed66bc..2ec5e6d72d1997a0e5076b794a7ad605d10846da 100644 (file)
--- a/ChangeLog
+++ b/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,
index f6b22b6b3a5ee1cf545969de16592fa65ec1d411..fe7f30faf3409891c4ec9a712362b2f1f32d09c7 100644 (file)
@@ -243,6 +243,12 @@ updated on <i>2007-08-20</i>.
   <td> &#8805; 0.2.0 </td>
   <td> &#8805; 0.2.0 </td>
   <td> &#8805; 0.3.0 </td>
+</tr><tr><td> virDomainMigrate </td>
+  <td> 0.3.2 </td>
+  <td> &#8805; 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> &#8805; 0.1.4 </td>
index c7e947ba1a4732aae9be7b3c1716b2de26238e2b..0e7539d8db0b34cbbd71ca7008cbeaa44f8485be 100644 (file)
@@ -2996,6 +2996,14 @@ updated on <i>2007-08-20</i>.
   <td> &ge; 0.2.0 </td>
   <td> &ge; 0.3.0 </td>
 </tr>
+<tr>
+  <td> virDomainMigrate </td>
+  <td> 0.3.2 </td>
+  <td> &ge; 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>
index 6125795797952c5943faab87b31f94ff16ac07cb..0ef4e2708012d1b1eb54e5742021c104a1373c52 100644 (file)
@@ -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
index 8d3128809302b473c5ac6a6a030f172842b001f3..255d11e2d0e221bc6523fee9df5f964b9b8fdf08 100644 (file)
@@ -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
index 62c353a53e6134811da991b7b8011628ac4dccb8..90ee1529d7a27d9962220486495ebb898be027b1 100644 (file)
@@ -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,
index 3f2fcbcd956a266828205c67756a554ea18d9269..07795d7c9e0b92f3f83ca1e24883a84199e43311 100644 (file)
@@ -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;
index 63511ec73065dd7154f34a616ca9fb55f877907e..e58d8e97fd5008c978c9116167162baf6932bf18 100644 (file)
@@ -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;
index 3fae468244f1f466c15a6b5fbc1ee0b88665dd9a..9ad9fb9b32daceedb78d6abde1c4c1e32240f6fa 100644 (file)
@@ -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);
index 309c35682f9d56c61a52a9e2536ae3d4fde770c6..e5dfb1c2cbe7cb3e35d0d9db58fe384ab8ca3f13 100644 (file)
@@ -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)
 {
index 4944296f149f9231990cdc15f7eff4e2b2bafaac..5a0310b561315e74b372af04791e25f5f3cee24c 100644 (file)
@@ -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 ();
index b7ca853c2974975a274e19826b901b77d0b60717..c9012ad8f3a8e36c4948264b133b4e4b6f25ccd1 100644 (file)
@@ -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. */
index 0a941697a2a814621973932738aafa59a91d6e24..2dd735450db64500e2017bd381c2bdf7cffd37a0 100644 (file)
@@ -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
index 60a75586b5efcfc1ea705035d741b40629176f5d..d73a940c7aa6abc7ae14516d4fda970128934155 100644 (file)
@@ -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
index 54bca2a43f88405a2a0d0f60fd7544a607a16c96..2181afe3deec07e2ec37aacc404b6e82a0a043e8 100644 (file)
@@ -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 */
index 57fbbf9ac28319b9694ad561a46a74131d19f19d..fa81ea868ce54f703c2ff8994627abb111ec40bd 100644 (file)
@@ -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
index b9cd55efdbb4fc0479b0c8631645a01dae28f8ed..b218ec0837b20b8d0ba6a05241fc77cf8831fff6 100644 (file)
@@ -69,6 +69,8 @@
        virDomainAttachDevice;
        virDomainDetachDevice;
 
+       virDomainMigrate;
+
        virNetworkGetConnect;
        virConnectNumOfNetworks;
        virConnectListNetworks;
 
        __virDrvSupportsFeature;
 
+       __virDomainMigratePrepare;
+       __virDomainMigratePerform;
+       __virDomainMigrateFinish;
+
     local: *;
 };
index 7da3ba4855a1a5a4e20be38029e8ccd92a12642a..e00d449df4e16de9e414e53dd31b233911a39951 100644 (file)
@@ -2662,6 +2662,9 @@ static virDriver qemuDriver = {
     NULL, /* domainGetSchedulerType */
     NULL, /* domainGetSchedulerParameters */
     NULL, /* domainSetSchedulerParameters */
+    NULL, /* domainMigratePrepare */
+    NULL, /* domainMigratePerform */
+    NULL, /* domainMigrateFinish */
 };
 
 static virNetworkDriver qemuNetworkDriver = {
index 69b944f8cfaee2713c294e4bd0771d5e3d8cb07a..d952374a5afd4ffcaec6599dbbb447b70364382c 100644 (file)
@@ -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 = {
index 4300d2af9e05ef4561369220629ddba229351045..82522410695fec80f169e1d76b5e254fbd17d287 100644 (file)
@@ -1964,6 +1964,9 @@ static virDriver testDriver = {
     testDomainGetSchedulerType, /* domainGetSchedulerType */
     testDomainGetSchedulerParams, /* domainGetSchedulerParameters */
     testDomainSetSchedulerParams, /* domainSetSchedulerParameters */
+    NULL, /* domainMigratePrepare */
+    NULL, /* domainMigratePerform */
+    NULL, /* domainMigrateFinish */
 };
 
 static virNetworkDriver testNetworkDriver = {
index 69dc559dfd7a5cf8ac21425701677a71787a0074..dc68a719ff9d866af7a03960b0199347b7106d61 100644 (file)
@@ -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},
index 638e340d45844b2280dee9efcf300937867a0c90..de7021b55d0edcdbc4c0779c62c9177f8f89bee5 100644 (file)
@@ -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;
 
index 5d9bb9418ec8ec021da3b11279053741d6f6e767..fafc24ca580a01e455f02ca24488cf26b09fb0f2 100644 (file)
@@ -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,
 };
 
 /**
index dfeab67c09ecaf57c195683831cacff414003686..5a1b09f2313c267509bca427bfe7e33a05e5c698 100644 (file)
@@ -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;
index 3facac1bb64c1ad7d2e88e1c362ab6f496f80c69..68833b0d755eff5f7ab69c8c6d75c6330bcd5cde 100644 (file)
@@ -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
 }