[libvirt] [RFC PATCH 3/8] Snapshot API framework.

Chris Lalancette clalance at redhat.com
Thu Apr 1 22:07:22 UTC 2010


Signed-off-by: Chris Lalancette <clalance at redhat.com>
---
 daemon/remote.c                     |  311 ++++++++++++++++++++++++
 daemon/remote_dispatch_args.h       |    9 +
 daemon/remote_dispatch_prototypes.h |   72 ++++++
 daemon/remote_dispatch_ret.h        |    7 +
 daemon/remote_dispatch_table.h      |   45 ++++
 include/libvirt/libvirt.h.in        |   61 +++++
 include/libvirt/virterror.h         |    5 +-
 src/datatypes.c                     |  122 ++++++++++
 src/datatypes.h                     |   25 ++
 src/driver.h                        |   47 ++++
 src/esx/esx_driver.c                |    9 +
 src/libvirt.c                       |  448 +++++++++++++++++++++++++++++++++++
 src/libvirt_private.syms            |    1 +
 src/libvirt_public.syms             |   10 +
 src/lxc/lxc_driver.c                |    9 +
 src/opennebula/one_driver.c         |    9 +
 src/openvz/openvz_driver.c          |    9 +
 src/phyp/phyp_driver.c              |    9 +
 src/qemu/qemu_driver.c              |    9 +
 src/remote/remote_driver.c          |  309 ++++++++++++++++++++++++
 src/remote/remote_protocol.c        |  181 ++++++++++++++
 src/remote/remote_protocol.h        |  145 +++++++++++
 src/remote/remote_protocol.x        |   97 ++++++++-
 src/test/test_driver.c              |    9 +
 src/uml/uml_driver.c                |    9 +
 src/util/virterror.c                |   15 ++
 src/vbox/vbox_tmpl.c                |    9 +
 src/xen/xen_driver.c                |    9 +
 src/xenapi/xenapi_driver.c          |    9 +
 29 files changed, 2007 insertions(+), 2 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index 67162d5..daedfd3 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -67,6 +67,7 @@ static virStoragePoolPtr get_nonnull_storage_pool (virConnectPtr conn, remote_no
 static virStorageVolPtr get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol);
 static virSecretPtr get_nonnull_secret (virConnectPtr conn, remote_nonnull_secret secret);
 static virNWFilterPtr get_nonnull_nwfilter (virConnectPtr conn, remote_nonnull_nwfilter nwfilter);
+static virDomainSnapshotPtr get_nonnull_domain_snapshot (virConnectPtr conn, remote_nonnull_domain_snapshot snapshot);
 static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src);
 static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src);
 static void make_nonnull_interface (remote_nonnull_interface *interface_dst, virInterfacePtr interface_src);
@@ -75,6 +76,7 @@ static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virSt
 static void make_nonnull_node_device (remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src);
 static void make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src);
 static void make_nonnull_nwfilter (remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src);
+static void make_nonnull_domain_snapshot (remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);
 
 
 #include "remote_dispatch_prototypes.h"
@@ -5766,6 +5768,298 @@ remoteDispatchDomainMigrateSetMaxDowntime(struct qemud_server *server ATTRIBUTE_
     return 0;
 }
 
+static int
+remoteDispatchDomainSnapshotCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                       struct qemud_client *client ATTRIBUTE_UNUSED,
+                                       virConnectPtr conn,
+                                       remote_message_header *hdr ATTRIBUTE_UNUSED,
+                                       remote_error *rerr,
+                                       remote_domain_snapshot_create_xml_args *args,
+                                       remote_domain_snapshot_create_xml_ret *ret)
+{
+    virDomainSnapshotPtr snapshot;
+    virDomainPtr domain;
+
+    domain = get_nonnull_domain(conn, args->domain);
+    if (domain == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    snapshot = virDomainSnapshotCreateXML(domain, args->xml_desc, args->flags);
+    if (snapshot == NULL) {
+        virDomainFree(domain);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    make_nonnull_domain_snapshot(&ret->snap, snapshot);
+
+    virDomainSnapshotFree(snapshot);
+    virDomainFree(domain);
+
+    return 0;
+}
+
+static int
+remoteDispatchDomainSnapshotDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                     struct qemud_client *client ATTRIBUTE_UNUSED,
+                                     virConnectPtr conn,
+                                     remote_message_header *hdr ATTRIBUTE_UNUSED,
+                                     remote_error *rerr,
+                                     remote_domain_snapshot_dump_xml_args *args,
+                                     remote_domain_snapshot_dump_xml_ret *ret)
+{
+    virDomainSnapshotPtr snapshot;
+
+    snapshot = get_nonnull_domain_snapshot(conn, args->snap);
+    if (snapshot == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    /* remoteDispatchClientRequest will free this. */
+    ret->xml = virDomainSnapshotGetXMLDesc(snapshot, args->flags);
+    if (!ret->xml) {
+        virDomainSnapshotFree(snapshot);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    virDomainSnapshotFree(snapshot);
+
+    return 0;
+}
+
+static int
+remoteDispatchDomainSnapshotNum (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                 struct qemud_client *client ATTRIBUTE_UNUSED,
+                                 virConnectPtr conn,
+                                 remote_message_header *hdr ATTRIBUTE_UNUSED,
+                                 remote_error *rerr,
+                                 remote_domain_snapshot_num_args *args,
+                                 remote_domain_snapshot_num_ret *ret)
+{
+    virDomainPtr domain;
+
+    domain = get_nonnull_domain(conn, args->domain);
+    if (domain == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    ret->num = virDomainSnapshotNum(domain, args->flags);
+    if (ret->num == -1) {
+        virDomainFree(domain);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    virDomainFree(domain);
+
+    return 0;
+}
+
+static int
+remoteDispatchDomainSnapshotListNames (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                       struct qemud_client *client ATTRIBUTE_UNUSED,
+                                       virConnectPtr conn,
+                                       remote_message_header *hdr ATTRIBUTE_UNUSED,
+                                       remote_error *rerr,
+                                       remote_domain_snapshot_list_names_args *args,
+                                       remote_domain_snapshot_list_names_ret *ret)
+{
+    virDomainPtr domain;
+
+    if (args->nameslen > REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX) {
+        remoteDispatchFormatError (rerr, "%s",
+                                   _("nameslen > REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX"));
+        return -1;
+    }
+
+    domain = get_nonnull_domain(conn, args->domain);
+    if (domain == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    /* Allocate return buffer. */
+    if (VIR_ALLOC_N(ret->names.names_val, args->nameslen) < 0) {
+        virDomainFree(domain);
+        remoteDispatchOOMError(rerr);
+        return -1;
+    }
+
+    ret->names.names_len = virDomainSnapshotListNames(domain,
+                                                      ret->names.names_val,
+                                                      args->nameslen,
+                                                      args->flags);
+    if (ret->names.names_len == -1) {
+        virDomainFree(domain);
+        VIR_FREE(ret->names.names_val);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    virDomainFree(domain);
+
+    return 0;
+}
+
+static int
+remoteDispatchDomainSnapshotLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                          struct qemud_client *client ATTRIBUTE_UNUSED,
+                                          virConnectPtr conn,
+                                          remote_message_header *hdr ATTRIBUTE_UNUSED,
+                                          remote_error *rerr,
+                                          remote_domain_snapshot_lookup_by_name_args *args,
+                                          remote_domain_snapshot_lookup_by_name_ret *ret)
+{
+    virDomainSnapshotPtr snapshot;
+    virDomainPtr domain;
+
+    domain = get_nonnull_domain(conn, args->domain);
+    if (domain == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    snapshot = virDomainSnapshotLookupByName(domain, args->name, args->flags);
+    if (snapshot == NULL) {
+        virDomainFree(domain);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    make_nonnull_domain_snapshot (&ret->snap, snapshot);
+
+    virDomainSnapshotFree(snapshot);
+    virDomainFree(domain);
+
+    return 0;
+}
+
+static int
+remoteDispatchDomainHasCurrentSnapshot(struct qemud_server *server ATTRIBUTE_UNUSED,
+                                       struct qemud_client *client ATTRIBUTE_UNUSED,
+                                       virConnectPtr conn,
+                                       remote_message_header *hdr ATTRIBUTE_UNUSED,
+                                       remote_error *rerr,
+                                       remote_domain_has_current_snapshot_args *args,
+                                       remote_domain_has_current_snapshot_ret *ret)
+{
+    virDomainPtr domain;
+    int result;
+
+    domain = get_nonnull_domain(conn, args->domain);
+    if (domain == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    result = virDomainHasCurrentSnapshot(domain, args->flags);
+    if (result < 0) {
+        virDomainFree(domain);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    ret->result = result;
+
+    virDomainFree(domain);
+
+    return 0;
+}
+
+static int
+remoteDispatchDomainSnapshotCurrent(struct qemud_server *server ATTRIBUTE_UNUSED,
+                                    struct qemud_client *client ATTRIBUTE_UNUSED,
+                                    virConnectPtr conn,
+                                    remote_message_header *hdr ATTRIBUTE_UNUSED,
+                                    remote_error *rerr,
+                                    remote_domain_snapshot_current_args *args,
+                                    remote_domain_snapshot_current_ret *ret)
+{
+    virDomainSnapshotPtr snapshot;
+    virDomainPtr domain;
+
+    domain = get_nonnull_domain(conn, args->domain);
+    if (domain == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    snapshot = virDomainSnapshotCurrent(domain, args->flags);
+    if (snapshot == NULL) {
+        virDomainFree(domain);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    make_nonnull_domain_snapshot(&ret->snap, snapshot);
+
+    virDomainSnapshotFree(snapshot);
+    virDomainFree(domain);
+
+    return 0;
+}
+
+static int
+remoteDispatchDomainCreateFromSnapshot (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                        struct qemud_client *client ATTRIBUTE_UNUSED,
+                                        virConnectPtr conn,
+                                        remote_message_header *hdr ATTRIBUTE_UNUSED,
+                                        remote_error *rerr,
+                                        remote_domain_create_from_snapshot_args *args,
+                                        void *ret ATTRIBUTE_UNUSED)
+{
+    virDomainSnapshotPtr snapshot;
+
+    snapshot = get_nonnull_domain_snapshot(conn, args->snap);
+    if (snapshot == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    if (virDomainCreateFromSnapshot(snapshot, args->flags) == -1) {
+        virDomainSnapshotFree(snapshot);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    virDomainSnapshotFree(snapshot);
+
+    return 0;
+}
+
+static int
+remoteDispatchDomainSnapshotDelete (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                    struct qemud_client *client ATTRIBUTE_UNUSED,
+                                    virConnectPtr conn,
+                                    remote_message_header *hdr ATTRIBUTE_UNUSED,
+                                    remote_error *rerr,
+                                    remote_domain_snapshot_delete_args *args,
+                                    void *ret ATTRIBUTE_UNUSED)
+{
+    virDomainSnapshotPtr snapshot;
+
+    snapshot = get_nonnull_domain_snapshot(conn, args->snap);
+    if (snapshot == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    if (virDomainSnapshotDelete(snapshot, args->flags) == -1) {
+        virDomainSnapshotFree(snapshot);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    virDomainSnapshotFree(snapshot);
+
+    return 0;
+}
+
 
 static int
 remoteDispatchDomainEventsRegisterAny (struct qemud_server *server ATTRIBUTE_UNUSED,
@@ -6076,6 +6370,16 @@ get_nonnull_nwfilter (virConnectPtr conn, remote_nonnull_nwfilter nwfilter)
     return virGetNWFilter (conn, nwfilter.name, BAD_CAST nwfilter.uuid);
 }
 
+static virDomainSnapshotPtr
+get_nonnull_domain_snapshot (virConnectPtr conn, remote_nonnull_domain_snapshot snapshot)
+{
+    virDomainPtr domain;
+    domain = get_nonnull_domain(conn, snapshot.domain);
+    if (domain == NULL)
+        return NULL;
+    return virGetDomainSnapshot(domain, snapshot.name);
+}
+
 /* Make remote_nonnull_domain and remote_nonnull_network. */
 static void
 make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src)
@@ -6135,3 +6439,10 @@ make_nonnull_nwfilter (remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwf
     nwfilter_dst->name = strdup (nwfilter_src->name);
     memcpy (nwfilter_dst->uuid, nwfilter_src->uuid, VIR_UUID_BUFLEN);
 }
+
+static void
+make_nonnull_domain_snapshot (remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src)
+{
+    snapshot_dst->name = strdup(snapshot_src->name);
+    make_nonnull_domain(&snapshot_dst->domain, snapshot_src->domain);
+}
diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h
index b188e6e..ae78e2e 100644
--- a/daemon/remote_dispatch_args.h
+++ b/daemon/remote_dispatch_args.h
@@ -151,3 +151,12 @@
     remote_list_nwfilters_args val_remote_list_nwfilters_args;
     remote_nwfilter_define_xml_args val_remote_nwfilter_define_xml_args;
     remote_nwfilter_undefine_args val_remote_nwfilter_undefine_args;
+    remote_domain_snapshot_create_xml_args val_remote_domain_snapshot_create_xml_args;
+    remote_domain_snapshot_dump_xml_args val_remote_domain_snapshot_dump_xml_args;
+    remote_domain_snapshot_num_args val_remote_domain_snapshot_num_args;
+    remote_domain_snapshot_list_names_args val_remote_domain_snapshot_list_names_args;
+    remote_domain_snapshot_lookup_by_name_args val_remote_domain_snapshot_lookup_by_name_args;
+    remote_domain_has_current_snapshot_args val_remote_domain_has_current_snapshot_args;
+    remote_domain_snapshot_current_args val_remote_domain_snapshot_current_args;
+    remote_domain_create_from_snapshot_args val_remote_domain_create_from_snapshot_args;
+    remote_domain_snapshot_delete_args val_remote_domain_snapshot_delete_args;
diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h
index e155c69..c91e8a3 100644
--- a/daemon/remote_dispatch_prototypes.h
+++ b/daemon/remote_dispatch_prototypes.h
@@ -122,6 +122,14 @@ static int remoteDispatchDomainCreate(
     remote_error *err,
     remote_domain_create_args *args,
     void *ret);
+static int remoteDispatchDomainCreateFromSnapshot(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_create_from_snapshot_args *args,
+    void *ret);
 static int remoteDispatchDomainCreateXml(
     struct qemud_server *server,
     struct qemud_client *client,
@@ -282,6 +290,14 @@ static int remoteDispatchDomainGetVcpus(
     remote_error *err,
     remote_domain_get_vcpus_args *args,
     remote_domain_get_vcpus_ret *ret);
+static int remoteDispatchDomainHasCurrentSnapshot(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_has_current_snapshot_args *args,
+    remote_domain_has_current_snapshot_ret *ret);
 static int remoteDispatchDomainInterfaceStats(
     struct qemud_server *server,
     struct qemud_client *client,
@@ -490,6 +506,62 @@ static int remoteDispatchDomainShutdown(
     remote_error *err,
     remote_domain_shutdown_args *args,
     void *ret);
+static int remoteDispatchDomainSnapshotCreateXml(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_snapshot_create_xml_args *args,
+    remote_domain_snapshot_create_xml_ret *ret);
+static int remoteDispatchDomainSnapshotCurrent(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_snapshot_current_args *args,
+    remote_domain_snapshot_current_ret *ret);
+static int remoteDispatchDomainSnapshotDelete(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_snapshot_delete_args *args,
+    void *ret);
+static int remoteDispatchDomainSnapshotDumpXml(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_snapshot_dump_xml_args *args,
+    remote_domain_snapshot_dump_xml_ret *ret);
+static int remoteDispatchDomainSnapshotListNames(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_snapshot_list_names_args *args,
+    remote_domain_snapshot_list_names_ret *ret);
+static int remoteDispatchDomainSnapshotLookupByName(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_snapshot_lookup_by_name_args *args,
+    remote_domain_snapshot_lookup_by_name_ret *ret);
+static int remoteDispatchDomainSnapshotNum(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_snapshot_num_args *args,
+    remote_domain_snapshot_num_ret *ret);
 static int remoteDispatchDomainSuspend(
     struct qemud_server *server,
     struct qemud_client *client,
diff --git a/daemon/remote_dispatch_ret.h b/daemon/remote_dispatch_ret.h
index b134f25..358bc58 100644
--- a/daemon/remote_dispatch_ret.h
+++ b/daemon/remote_dispatch_ret.h
@@ -125,3 +125,10 @@
     remote_num_of_nwfilters_ret val_remote_num_of_nwfilters_ret;
     remote_list_nwfilters_ret val_remote_list_nwfilters_ret;
     remote_nwfilter_define_xml_ret val_remote_nwfilter_define_xml_ret;
+    remote_domain_snapshot_create_xml_ret val_remote_domain_snapshot_create_xml_ret;
+    remote_domain_snapshot_dump_xml_ret val_remote_domain_snapshot_dump_xml_ret;
+    remote_domain_snapshot_num_ret val_remote_domain_snapshot_num_ret;
+    remote_domain_snapshot_list_names_ret val_remote_domain_snapshot_list_names_ret;
+    remote_domain_snapshot_lookup_by_name_ret val_remote_domain_snapshot_lookup_by_name_ret;
+    remote_domain_has_current_snapshot_ret val_remote_domain_has_current_snapshot_ret;
+    remote_domain_snapshot_current_ret val_remote_domain_snapshot_current_ret;
diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h
index 24756d7..ab317b5 100644
--- a/daemon/remote_dispatch_table.h
+++ b/daemon/remote_dispatch_table.h
@@ -912,3 +912,48 @@
     .args_filter = (xdrproc_t) xdr_remote_nwfilter_undefine_args,
     .ret_filter = (xdrproc_t) xdr_void,
 },
+{   /* DomainSnapshotCreateXml => 182 */
+    .fn = (dispatch_fn) remoteDispatchDomainSnapshotCreateXml,
+    .args_filter = (xdrproc_t) xdr_remote_domain_snapshot_create_xml_args,
+    .ret_filter = (xdrproc_t) xdr_remote_domain_snapshot_create_xml_ret,
+},
+{   /* DomainSnapshotDumpXml => 183 */
+    .fn = (dispatch_fn) remoteDispatchDomainSnapshotDumpXml,
+    .args_filter = (xdrproc_t) xdr_remote_domain_snapshot_dump_xml_args,
+    .ret_filter = (xdrproc_t) xdr_remote_domain_snapshot_dump_xml_ret,
+},
+{   /* DomainSnapshotNum => 184 */
+    .fn = (dispatch_fn) remoteDispatchDomainSnapshotNum,
+    .args_filter = (xdrproc_t) xdr_remote_domain_snapshot_num_args,
+    .ret_filter = (xdrproc_t) xdr_remote_domain_snapshot_num_ret,
+},
+{   /* DomainSnapshotListNames => 185 */
+    .fn = (dispatch_fn) remoteDispatchDomainSnapshotListNames,
+    .args_filter = (xdrproc_t) xdr_remote_domain_snapshot_list_names_args,
+    .ret_filter = (xdrproc_t) xdr_remote_domain_snapshot_list_names_ret,
+},
+{   /* DomainSnapshotLookupByName => 186 */
+    .fn = (dispatch_fn) remoteDispatchDomainSnapshotLookupByName,
+    .args_filter = (xdrproc_t) xdr_remote_domain_snapshot_lookup_by_name_args,
+    .ret_filter = (xdrproc_t) xdr_remote_domain_snapshot_lookup_by_name_ret,
+},
+{   /* DomainHasCurrentSnapshot => 187 */
+    .fn = (dispatch_fn) remoteDispatchDomainHasCurrentSnapshot,
+    .args_filter = (xdrproc_t) xdr_remote_domain_has_current_snapshot_args,
+    .ret_filter = (xdrproc_t) xdr_remote_domain_has_current_snapshot_ret,
+},
+{   /* DomainSnapshotCurrent => 188 */
+    .fn = (dispatch_fn) remoteDispatchDomainSnapshotCurrent,
+    .args_filter = (xdrproc_t) xdr_remote_domain_snapshot_current_args,
+    .ret_filter = (xdrproc_t) xdr_remote_domain_snapshot_current_ret,
+},
+{   /* DomainCreateFromSnapshot => 189 */
+    .fn = (dispatch_fn) remoteDispatchDomainCreateFromSnapshot,
+    .args_filter = (xdrproc_t) xdr_remote_domain_create_from_snapshot_args,
+    .ret_filter = (xdrproc_t) xdr_void,
+},
+{   /* DomainSnapshotDelete => 190 */
+    .fn = (dispatch_fn) remoteDispatchDomainSnapshotDelete,
+    .args_filter = (xdrproc_t) xdr_remote_domain_snapshot_delete_args,
+    .ret_filter = (xdrproc_t) xdr_void,
+},
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 7cb483e..a8a97e3 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1861,6 +1861,67 @@ int virDomainGetJobInfo(virDomainPtr dom,
                         virDomainJobInfoPtr info);
 int virDomainAbortJob(virDomainPtr dom);
 
+/**
+ * virDomainSnapshot:
+ *
+ * a virDomainSnapshot is a private structure representing a snapshot of
+ * a domain.
+ */
+typedef struct _virDomainSnapshot virDomainSnapshot;
+
+/**
+ * virDomainSnapshotPtr:
+ *
+ * a virDomainSnapshotPtr is pointer to a virDomainSnapshot private structure,
+ * and is the type used to reference a domain snapshot in the API.
+ */
+typedef virDomainSnapshot *virDomainSnapshotPtr;
+
+/* Take a snapshot of the current VM state */
+virDomainSnapshotPtr virDomainSnapshotCreateXML(virDomainPtr domain,
+                                                const char *xmlDesc,
+                                                unsigned int flags);
+
+/* Dump the XML of a snapshot */
+char *virDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
+                                  unsigned int flags);
+
+/* Return the number of snapshots for this domain */
+int virDomainSnapshotNum(virDomainPtr domain, unsigned int flags);
+
+/* Get the names of all snapshots for this domain */
+int virDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
+                               unsigned int flags);
+
+/* Get a handle to a named snapshot */
+virDomainSnapshotPtr virDomainSnapshotLookupByName(virDomainPtr domain,
+                                                   const char *name,
+                                                   unsigned int flags);
+
+/* Check whether a domain has a snapshot which is currently used */
+int virDomainHasCurrentSnapshot(virDomainPtr domain, unsigned flags);
+
+/* Get a handle to the current snapshot */
+virDomainSnapshotPtr virDomainSnapshotCurrent(virDomainPtr domain,
+                                              unsigned int flags);
+
+/* Set this snapshot as the current one for a domain, to be
+ * used next time domain is started */
+int virDomainCreateFromSnapshot(virDomainSnapshotPtr snapshot,
+				unsigned int flags);
+
+/* Deactivate a snapshot */
+typedef enum {
+    VIR_DOMAIN_SNAPSHOT_DELETE_MERGE = (1 << 0),
+    VIR_DOMAIN_SNAPSHOT_DELETE_MERGE_FORCE = (1 << 1),
+    VIR_DOMAIN_SNAPSHOT_DELETE_DISCARD = (1 << 2),
+    VIR_DOMAIN_SNAPSHOT_DELETE_DISCARD_FORCE = (1 << 3),
+} virDomainSnapshotDeleteFlags;
+
+int virDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
+			    unsigned int flags);
+
+int virDomainSnapshotFree(virDomainSnapshotPtr snapshot);
 
 /* A generic callback definition. Specific events usually have a customization
  * with extra parameters */
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index f69d07e..3bbb293 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -71,7 +71,8 @@ typedef enum {
     VIR_FROM_CPU,       /* Error from CPU driver */
     VIR_FROM_XENAPI,    /* Error from XenAPI */
     VIR_FROM_NWFILTER,  /* Error from network filter driver */
-    VIR_FROM_HOOK       /* Error from Synchronous hooks */
+    VIR_FROM_HOOK,      /* Error from Synchronous hooks */
+    VIR_FROM_DOMAIN_SNAPSHOT, /* Error from domain snapshot */
 } virErrorDomain;
 
 
@@ -183,6 +184,8 @@ typedef enum {
     VIR_ERR_MIGRATE_PERSIST_FAILED, /* a migration worked, but making the
                                        VM persist on the dest host failed */
     VIR_ERR_HOOK_SCRIPT_FAILED, /* a synchronous hook script failed */
+    VIR_ERR_INVALID_DOMAIN_SNAPSHOT, /* invalid domain snapshot */
+    VIR_ERR_NO_DOMAIN_SNAPSHOT, /* domain snapshot not found */
 } virErrorNumber;
 
 /**
diff --git a/src/datatypes.c b/src/datatypes.c
index a361da6..c514f41 100644
--- a/src/datatypes.c
+++ b/src/datatypes.c
@@ -129,6 +129,20 @@ virSecretFreeName(void *secret_, const char *name ATTRIBUTE_UNUSED)
 }
 
 /**
+ * virDomainSnapshotFreeName:
+ * @snapshot: a domain snapshotobject
+ *
+ * Destroy the domain snapshot object, this is just used by the domain hash callback.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+static int
+virDomainSnapshotFreeName(virDomainSnapshotPtr snapshot, const char *name ATTRIBUTE_UNUSED)
+{
+    return (virUnrefDomainSnapshot(snapshot));
+}
+
+/**
  * virGetConnect:
  *
  * Allocates a new hypervisor connection structure
@@ -337,6 +351,7 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) {
         ret->id = -1;
         if (uuid != NULL)
             memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN);
+        ret->snapshots = virHashCreate(20);
 
         if (virHashAddEntry(conn->domains, name, ret) < 0) {
             virMutexUnlock(&conn->lock);
@@ -389,6 +404,8 @@ virReleaseDomain(virDomainPtr domain) {
     domain->magic = -1;
     domain->id = -1;
     VIR_FREE(domain->name);
+    if (domain->snapshots != NULL)
+        virHashFree(domain->snapshots, (virHashDeallocator) virDomainSnapshotFreeName);
     VIR_FREE(domain);
 
     if (conn) {
@@ -1504,3 +1521,108 @@ virUnrefNWFilter(virNWFilterPtr pool) {
     virMutexUnlock(&pool->conn->lock);
     return (refs);
 }
+
+
+virDomainSnapshotPtr
+virGetDomainSnapshot(virDomainPtr domain, const char *name)
+{
+    virDomainSnapshotPtr ret = NULL;
+
+    if ((!VIR_IS_DOMAIN(domain)) || (name == NULL)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return(NULL);
+    }
+    virMutexLock(&domain->conn->lock);
+
+    ret = (virDomainSnapshotPtr) virHashLookup(domain->snapshots, name);
+    if (ret == NULL) {
+        if (VIR_ALLOC(ret) < 0) {
+            virMutexUnlock(&domain->conn->lock);
+            virReportOOMError();
+            goto error;
+        }
+        ret->name = strdup(name);
+        if (ret->name == NULL) {
+            virMutexUnlock(&domain->conn->lock);
+            virReportOOMError();
+            goto error;
+        }
+        ret->magic = VIR_SNAPSHOT_MAGIC;
+        ret->domain = domain;
+
+        if (virHashAddEntry(domain->snapshots, name, ret) < 0) {
+            virMutexUnlock(&domain->conn->lock);
+            virLibConnError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("failed to add snapshot to domain hash table"));
+            goto error;
+        }
+        domain->refs++;
+        DEBUG("New hash entry %p", ret);
+    } else {
+        DEBUG("Existing hash entry %p: refs now %d", ret, ret->refs+1);
+    }
+    ret->refs++;
+    virMutexUnlock(&domain->conn->lock);
+    return(ret);
+
+ error:
+    if (ret != NULL) {
+        VIR_FREE(ret->name);
+        VIR_FREE(ret);
+    }
+    return(NULL);
+}
+
+
+static void
+virReleaseDomainSnapshot(virDomainSnapshotPtr snapshot)
+{
+    virDomainPtr domain = snapshot->domain;
+    DEBUG("release snapshot %p %s", snapshot, snapshot->name);
+
+    if (virHashRemoveEntry(domain->snapshots, snapshot->name, NULL) < 0) {
+        virMutexUnlock(&domain->conn->lock);
+        virLibConnError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                        "%s", _("snapshot missing from domain hash table"));
+        domain = NULL;
+    }
+
+    snapshot->magic = -1;
+    VIR_FREE(snapshot->name);
+    VIR_FREE(snapshot);
+
+    if (domain) {
+        DEBUG("unref domain %p %d", domain, domain->refs);
+        domain->refs--;
+        if (domain->refs == 0) {
+            virReleaseDomain(domain);
+            /* Already unlocked mutex */
+            return;
+        }
+        virMutexUnlock(&domain->conn->lock);
+    }
+}
+
+int
+virUnrefDomainSnapshot(virDomainSnapshotPtr snapshot)
+{
+    int refs;
+
+    if (!VIR_IS_DOMAIN_SNAPSHOT(snapshot)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return(-1);
+    }
+
+    virMutexLock(&snapshot->domain->conn->lock);
+    DEBUG("unref snapshot %p %s %d", snapshot, snapshot->name, snapshot->refs);
+    snapshot->refs--;
+    refs = snapshot->refs;
+    if (refs == 0) {
+        virReleaseDomainSnapshot(snapshot);
+        /* Already unlocked mutex */
+        return (0);
+    }
+
+    virMutexUnlock(&snapshot->domain->conn->lock);
+    return (refs);
+}
diff --git a/src/datatypes.h b/src/datatypes.h
index 4663c9c..bbeb7cf 100644
--- a/src/datatypes.h
+++ b/src/datatypes.h
@@ -130,6 +130,15 @@
 # define VIR_IS_NWFILTER(obj)			((obj) && (obj)->magic==VIR_NWFILTER_MAGIC)
 # define VIR_IS_CONNECTED_NWFILTER(obj)		(VIR_IS_NWFILTER(obj) && VIR_IS_CONNECT((obj)->conn))
 
+/**
+ * VIR_SNAPSHOT_MAGIC:
+ *
+ * magic value used to protect the API when pointers to snapshot structures
+ * are passed down by the users.
+ */
+# define VIR_SNAPSHOT_MAGIC                0x6666DEAD
+# define VIR_IS_SNAPSHOT(obj)              ((obj) && (obj)->magic==VIR_SNAPSHOT_MAGIC)
+# define VIR_IS_DOMAIN_SNAPSHOT(obj)    (VIR_IS_SNAPSHOT(obj) && VIR_IS_DOMAIN((obj)->domain))
 
 /**
  * _virConnect:
@@ -202,6 +211,7 @@ struct _virDomain {
     char *name;                          /* the domain external name */
     int id;                              /* the domain ID */
     unsigned char uuid[VIR_UUID_BUFLEN]; /* the domain unique identifier */
+    virHashTablePtr snapshots; /* hash table for known snapshots */
 };
 
 /**
@@ -304,6 +314,17 @@ struct _virStream {
     void *privateData;
 };
 
+/**
+ * _virDomainSnapshot
+ *
+ * Internal structure associated with a domain snapshot
+ */
+struct _virDomainSnapshot {
+    unsigned int magic;
+    int refs;
+    char *name;
+    virDomainPtr domain;
+};
 
 /************************************************************************
  *									*
@@ -368,4 +389,8 @@ virNWFilterPtr virGetNWFilter(virConnectPtr conn,
                                   const unsigned char *uuid);
 int virUnrefNWFilter(virNWFilterPtr pool);
 
+virDomainSnapshotPtr virGetDomainSnapshot(virDomainPtr domain,
+                                          const char *name);
+int virUnrefDomainSnapshot(virDomainSnapshotPtr pool);
+
 #endif
diff --git a/src/driver.h b/src/driver.h
index 8f86463..1f257c0 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -402,6 +402,44 @@ typedef int
     (*virDrvDomainEventDeregisterAny)(virConnectPtr conn,
                                       int callbackID);
 
+typedef virDomainSnapshotPtr
+    (*virDrvDomainSnapshotCreateXML)(virDomainPtr domain,
+                                     const char *xmlDesc,
+                                     unsigned int flags);
+
+typedef char *
+    (*virDrvDomainSnapshotDumpXML)(virDomainSnapshotPtr snapshot,
+                                   unsigned int flags);
+
+typedef int
+    (*virDrvDomainSnapshotNum)(virDomainPtr domain, unsigned int flags);
+
+typedef int
+    (*virDrvDomainSnapshotListNames)(virDomainPtr domain, char **names,
+                                     int nameslen,
+                                     unsigned int flags);
+
+typedef virDomainSnapshotPtr
+    (*virDrvDomainSnapshotLookupByName)(virDomainPtr domain,
+                                        const char *name,
+                                        unsigned int flags);
+
+typedef int
+    (*virDrvDomainHasCurrentSnapshot)(virDomainPtr domain, unsigned int flags);
+
+typedef virDomainSnapshotPtr
+    (*virDrvDomainSnapshotCurrent)(virDomainPtr domain,
+                                   unsigned int flags);
+
+typedef int
+    (*virDrvDomainCreateFromSnapshot)(virDomainSnapshotPtr snapshot,
+                                      unsigned int flags);
+
+typedef int
+    (*virDrvDomainSnapshotDelete)(virDomainSnapshotPtr snapshot,
+                                  unsigned int flags);
+
+
 /**
  * _virDriver:
  *
@@ -499,6 +537,15 @@ struct _virDriver {
     virDrvDomainMigrateSetMaxDowntime  domainMigrateSetMaxDowntime;
     virDrvDomainEventRegisterAny domainEventRegisterAny;
     virDrvDomainEventDeregisterAny domainEventDeregisterAny;
+    virDrvDomainSnapshotCreateXML domainSnapshotCreateXML;
+    virDrvDomainSnapshotDumpXML domainSnapshotDumpXML;
+    virDrvDomainSnapshotNum domainSnapshotNum;
+    virDrvDomainSnapshotListNames domainSnapshotListNames;
+    virDrvDomainSnapshotLookupByName domainSnapshotLookupByName;
+    virDrvDomainHasCurrentSnapshot domainHasCurrentSnapshot;
+    virDrvDomainSnapshotCurrent domainSnapshotCurrent;
+    virDrvDomainCreateFromSnapshot domainCreateFromSnapshot;
+    virDrvDomainSnapshotDelete domainSnapshotDelete;
 };
 
 typedef int
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index 7a92c4d..38846c3 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -3389,6 +3389,15 @@ static virDriver esxDriver = {
     NULL, /* domainMigrateSetMaxDowntime */
     NULL, /* domainEventRegisterAny */
     NULL, /* domainEventDeregisterAny */
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 
diff --git a/src/libvirt.c b/src/libvirt.c
index 5247fe7..edb3084 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -683,6 +683,31 @@ virLibNWFilterError(virNWFilterPtr pool, virErrorNumber error,
 }
 
 /**
+ * virLibDomainSnapshotError:
+ * @snapshot: the snapshot if available
+ * @error: the error number
+ * @info: extra information string
+ *
+ * Handle an error at the secret level
+ */
+static void
+virLibDomainSnapshotError(virDomainSnapshotPtr snapshot, virErrorNumber error, const char *info)
+{
+    virConnectPtr conn = NULL;
+    const char *errmsg;
+
+    if (error == VIR_ERR_OK)
+        return;
+
+    errmsg = virErrorMsg(error, info);
+    if (error != VIR_ERR_INVALID_DOMAIN_SNAPSHOT)
+        conn = snapshot->domain->conn;
+
+    virRaiseError(conn, NULL, NULL, VIR_FROM_DOMAIN_SNAPSHOT, error, VIR_ERR_ERROR,
+                  errmsg, info, NULL, 0, 0, errmsg, info);
+}
+
+/**
  * virRegisterNetworkDriver:
  * @driver: pointer to a network driver block
  *
@@ -12136,3 +12161,426 @@ error:
     virDispatchError(conn);
     return -1;
 }
+
+/**
+ * virDomainSnapshotCreateXML:
+ * @domain: a domain object
+ * @xmlDesc: string containing an XML description of the domain
+ * @flags: unused flag parameters; callers should pass 0
+ *
+ * Creates a new snapshot of a domain based on the snapshot xml
+ * contained in xmlDesc.
+ *
+ * Returns an (opaque) virDomainSnapshotPtr on success, NULL on failure.
+ */
+virDomainSnapshotPtr
+virDomainSnapshotCreateXML(virDomainPtr domain,
+                           const char *xmlDesc,
+                           unsigned int flags)
+{
+    virConnectPtr conn;
+
+    DEBUG("domain=%p, xmlDesc=%s, flags=%u", domain, xmlDesc, flags);
+
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return NULL;
+    }
+
+    conn = domain->conn;
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainSnapshotCreateXML) {
+        virDomainSnapshotPtr ret;
+        ret = conn->driver->domainSnapshotCreateXML(domain, xmlDesc, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+/**
+ * virDomainSnapshotGetXMLDesc:
+ * @snapshot: a domain snapshot object
+ * @flags: unused flag parameters; callers should pass 0
+ *
+ * Provide an XML description of the domain snapshot.
+ *
+ * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
+ *         the caller must free() the returned value.
+ */
+char *
+virDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
+                            unsigned int flags)
+{
+    virConnectPtr conn;
+    DEBUG("snapshot=%p, flags=%d", snapshot, flags);
+
+    virResetLastError();
+
+    if (!VIR_IS_DOMAIN_SNAPSHOT(snapshot)) {
+        virLibDomainSnapshotError(NULL, VIR_ERR_INVALID_DOMAIN_SNAPSHOT, __FUNCTION__);
+        virDispatchError(NULL);
+        return (NULL);
+    }
+
+    conn = snapshot->domain->conn;
+
+    if ((conn->flags & VIR_CONNECT_RO) && (flags & VIR_DOMAIN_XML_SECURE)) {
+        virLibConnError(conn, VIR_ERR_OPERATION_DENIED,
+                        _("virDomainSnapshotGetXMLDesc with secure flag"));
+        goto error;
+    }
+
+    flags &= VIR_DOMAIN_XML_FLAGS_MASK;
+
+    if (conn->driver->domainSnapshotDumpXML) {
+        char *ret;
+        ret = conn->driver->domainSnapshotDumpXML(snapshot, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+/**
+ * virDomainSnapshotNum:
+ * @domain: a domain object
+ * @flags: unused flag parameters; callers should pass 0
+ *
+ * Provides the number of domain snapshots for this domain..
+ *
+ * Returns the number of domain snapshost found or -1 in case of error.
+ */
+int
+virDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+    DEBUG("domain=%p", domain);
+
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    conn = domain->conn;
+    if (conn->driver->domainSnapshotNum) {
+        int ret = conn->driver->domainSnapshotNum(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return -1;
+}
+
+/**
+ * virDomainSnapshotListNames:
+ * @domain: a domain object
+ * @names: array to collect the list of names of snapshots
+ * @nameslen: size of @names
+ * @flags: unused flag parameters; callers should pass 0
+ *
+ * Collect the list of domain snapshots for the given domain, and store
+ * their names in @names.
+ *
+ * Returns the number of domain snapshots found or -1 in case of error.
+ */
+int
+virDomainSnapshotListNames(virDomainPtr domain, char **names, int nameslen,
+                           unsigned int flags)
+{
+    virConnectPtr conn;
+
+    DEBUG("domain=%p, names=%p, nameslen=%d, flags=%u",
+          domain, names, nameslen, flags);
+
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    conn = domain->conn;
+
+    if ((names == NULL) || (nameslen < 0)) {
+        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainSnapshotListNames) {
+        int ret = conn->driver->domainSnapshotListNames(domain, names, nameslen,
+                                                        flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return -1;
+}
+
+/**
+ * virDomainSnapshotLookupByName:
+ * @domain: a domain object
+ * @name: name for the domain snapshot
+ * @flags: unused flag parameters; callers should pass 0
+ *
+ * Try to lookup a domain snapshot based on its name.
+ *
+ * Returns a domain snapshot object or NULL in case of failure.  If the
+ * domain snapshot cannot be found, then the VIR_ERR_NO_DOMAIN_SNAPSHOT
+ * error is raised.
+ */
+virDomainSnapshotPtr
+virDomainSnapshotLookupByName(virDomainPtr domain,
+                              const char *name,
+                              unsigned int flags)
+{
+    virConnectPtr conn;
+    DEBUG("domain=%p, name=%s, flags=%u", domain, name, flags);
+
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return (NULL);
+    }
+
+    conn = domain->conn;
+
+    if (name == NULL) {
+        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainSnapshotLookupByName) {
+        virDomainSnapshotPtr dom;
+        dom = conn->driver->domainSnapshotLookupByName(domain, name, flags);
+        if (!dom)
+            goto error;
+        return dom;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+/**
+ * virDomainHasCurrentSnapshot:
+ * @domain: pointer to the domain object
+ * @flags: unused flag parameters; callers should pass 0
+ *
+ * Determine if the domain has a current snapshot.
+ *
+ * Returns 1 if such snapshot exists, 0 if it doesn't, -1 on error.
+ */
+int
+virDomainHasCurrentSnapshot(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+    DEBUG("domain=%p, flags=%u", domain, flags);
+
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainHasCurrentSnapshot) {
+        int ret = conn->driver->domainHasCurrentSnapshot(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return -1;
+}
+
+/**
+ * virDomainSnapshotCurrent:
+ * @domain: a domain object
+ * @flags: unused flag parameters; callers should pass 0
+ *
+ * Get the current snapshot for a domain, if any.
+ *
+ * Returns a domain snapshot object or NULL in case of failure.  If the
+ * current domain snapshot cannot be found, then the VIR_ERR_NO_DOMAIN_SNAPSHOT
+ * error is raised.
+ */
+virDomainSnapshotPtr
+virDomainSnapshotCurrent(virDomainPtr domain,
+                         unsigned int flags)
+{
+    virConnectPtr conn;
+    DEBUG("domain=%p, flags=%u", domain, flags);
+
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return (NULL);
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainSnapshotCurrent) {
+        virDomainSnapshotPtr snap;
+        snap = conn->driver->domainSnapshotCurrent(domain, flags);
+        if (!snap)
+            goto error;
+        return snap;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+/**
+ * virDomainCreateFromSnapshot
+ * @snapshot: a domain snapshot object
+ * @flags: unused flag parameters; callers should pass 0
+ *
+ * Start the domain from the given snapshot.
+ *
+ * Returns 0 if the creation is successful, -1 on error.
+ */
+int
+virDomainCreateFromSnapshot(virDomainSnapshotPtr snapshot,
+                            unsigned int flags)
+{
+    virConnectPtr conn;
+
+    DEBUG("snapshot=%p, flags=%u", snapshot, flags);
+
+    virResetLastError();
+
+    if (!VIR_IS_DOMAIN_SNAPSHOT(snapshot)) {
+        virLibDomainSnapshotError(NULL, VIR_ERR_INVALID_DOMAIN_SNAPSHOT, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    conn = snapshot->domain->conn;
+
+    if (conn->driver->domainCreateFromSnapshot) {
+        int ret = conn->driver->domainCreateFromSnapshot(snapshot, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return -1;
+}
+
+/**
+ * virDomainCreateFromSnapshot
+ * @snapshot: a domain snapshot object
+ * @flags: flag parameters
+ *
+ * Delete the snapshot.
+ *
+ * Returns 0 if the snapshot was successfully deleted, -1 on error.
+ */
+int
+virDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
+                        unsigned int flags)
+{
+    virConnectPtr conn;
+
+    DEBUG("snapshot=%p, flags=%u", snapshot, flags);
+
+    /* FIXME: make sure only one of the flags is set */
+
+    virResetLastError();
+
+    if (!VIR_IS_DOMAIN_SNAPSHOT(snapshot)) {
+        virLibDomainSnapshotError(NULL, VIR_ERR_INVALID_DOMAIN_SNAPSHOT, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    conn = snapshot->domain->conn;
+
+    if (conn->driver->domainSnapshotDelete) {
+        int ret = conn->driver->domainSnapshotDelete(snapshot, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return -1;
+}
+
+/**
+ * virDomainFree:
+ * @snapshot: a domain snapshot object
+ *
+ * Free the domain snapshot object.  The snapshot itself is not modified.
+ * The data structure is freed and should not be used thereafter.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainSnapshotFree(virDomainSnapshotPtr snapshot)
+{
+    DEBUG("snapshot=%p", snapshot);
+
+    virResetLastError();
+
+    if (!VIR_IS_DOMAIN_SNAPSHOT(snapshot)) {
+        virLibDomainSnapshotError(NULL, VIR_ERR_INVALID_DOMAIN_SNAPSHOT, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+    if (virUnrefDomainSnapshot(snapshot) < 0) {
+        virDispatchError(NULL);
+        return -1;
+    }
+    return 0;
+}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index edb23c2..c402720 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -109,6 +109,7 @@ virGetStream;
 virUnrefStream;
 virGetNWFilter;
 virUnrefNWFilter;
+virGetDomainSnapshot;
 
 
 # domain_conf.h
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 2f812a1..5d33c31 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -378,6 +378,16 @@ LIBVIRT_0.7.8 {
 	virNWFilterRef;
 	virNWFilterDefineXML;
 	virNWFilterUndefine;
+        virDomainSnapshotCreateXML;
+        virDomainSnapshotGetXMLDesc;
+        virDomainSnapshotNum;
+        virDomainSnapshotListNames;
+        virDomainSnapshotLookupByName;
+        virDomainHasCurrentSnapshot;
+        virDomainSnapshotCurrent;
+        virDomainCreateFromSnapshot;
+        virDomainSnapshotDelete;
+        virDomainSnapshotFree;
 } LIBVIRT_0.7.7;
 
 
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 9caefa1..ba373f8 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -2538,6 +2538,15 @@ static virDriver lxcDriver = {
     NULL, /* domainMigrateSetMaxDowntime */
     lxcDomainEventRegisterAny, /* domainEventRegisterAny */
     lxcDomainEventDeregisterAny, /* domainEventDeregisterAny */
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 static virStateDriver lxcStateDriver = {
diff --git a/src/opennebula/one_driver.c b/src/opennebula/one_driver.c
index e901a03..85245d8 100644
--- a/src/opennebula/one_driver.c
+++ b/src/opennebula/one_driver.c
@@ -792,6 +792,15 @@ static virDriver oneDriver = {
     NULL, /* domainMigrateSetMaxDowntime */
     NULL, /* domainEventRegisterAny */
     NULL, /* domainEventDeregisterAny */
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 static virStateDriver oneStateDriver = {
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index 6176577..7458521 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -1544,6 +1544,15 @@ static virDriver openvzDriver = {
     NULL, /* domainMigrateSetMaxDowntime */
     NULL, /* domainEventRegisterAny */
     NULL, /* domainEventDeregisterAny */
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 int openvzRegister(void) {
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
index 4f7efdb..272a746 100644
--- a/src/phyp/phyp_driver.c
+++ b/src/phyp/phyp_driver.c
@@ -1651,6 +1651,15 @@ virDriver phypDriver = {
     NULL, /* domainMigrateSetMaxDowntime */
     NULL, /* domainEventRegisterAny */
     NULL, /* domainEventDeregisterAny */
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 int
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 4291bc7..695e5ba 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10307,6 +10307,15 @@ static virDriver qemuDriver = {
     qemuDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */
     qemuDomainEventRegisterAny, /* domainEventRegisterAny */
     qemuDomainEventDeregisterAny, /* domainEventDeregisterAny */
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 3b8be21..a8f48cf 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -254,6 +254,7 @@ static virStoragePoolPtr get_nonnull_storage_pool (virConnectPtr conn, remote_no
 static virStorageVolPtr get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol);
 static virNodeDevicePtr get_nonnull_node_device (virConnectPtr conn, remote_nonnull_node_device dev);
 static virSecretPtr get_nonnull_secret (virConnectPtr conn, remote_nonnull_secret secret);
+static virDomainSnapshotPtr get_nonnull_domain_snapshot (virDomainPtr domain, remote_nonnull_domain_snapshot snapshot);
 static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src);
 static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src);
 static void make_nonnull_interface (remote_nonnull_interface *interface_dst, virInterfacePtr interface_src);
@@ -261,6 +262,7 @@ static void make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, vi
 static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src);
 static void make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src);
 static void make_nonnull_nwfilter (remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src);
+static void make_nonnull_domain_snapshot (remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);
 void remoteDomainEventFired(int watch, int fd, int event, void *data);
 void remoteDomainEventQueueFlush(int timer, void *opaque);
 /*----------------------------------------------------------------------*/
@@ -8301,6 +8303,291 @@ done:
     return rv;
 }
 
+static virDomainSnapshotPtr
+remoteDomainSnapshotCreateXML(virDomainPtr domain,
+                              const char *xmlDesc,
+                              unsigned int flags)
+{
+    virDomainSnapshotPtr snapshot = NULL;
+    remote_domain_snapshot_create_xml_args args;
+    remote_domain_snapshot_create_xml_ret ret;
+    struct private_data *priv = domain->conn->privateData;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain (&args.domain, domain);
+    args.xml_desc = (char *) xmlDesc;
+    args.flags = flags;
+
+    memset (&ret, 0, sizeof ret);
+    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SNAPSHOT_CREATE_XML,
+              (xdrproc_t) xdr_remote_domain_snapshot_create_xml_args, (char *) &args,
+              (xdrproc_t) xdr_remote_domain_snapshot_create_xml_ret, (char *) &ret) == -1)
+        goto done;
+
+    snapshot = get_nonnull_domain_snapshot(domain, ret.snap);
+    xdr_free ((xdrproc_t) &xdr_remote_domain_snapshot_create_xml_ret, (char *) &ret);
+
+done:
+    remoteDriverUnlock(priv);
+    return snapshot;
+}
+
+
+static char *
+remoteDomainSnapshotDumpXML(virDomainSnapshotPtr snapshot, unsigned int flags)
+{
+    char *rv = NULL;
+    remote_domain_snapshot_dump_xml_args args;
+    remote_domain_snapshot_dump_xml_ret ret;
+    struct private_data *priv = snapshot->domain->conn->privateData;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain_snapshot(&args.snap, snapshot);
+    args.flags = flags;
+
+    memset (&ret, 0, sizeof ret);
+    if (call (snapshot->domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SNAPSHOT_DUMP_XML,
+              (xdrproc_t) xdr_remote_domain_snapshot_dump_xml_args, (char *) &args,
+              (xdrproc_t) xdr_remote_domain_snapshot_dump_xml_ret, (char *) &ret) == -1)
+        goto done;
+
+    /* Caller frees. */
+    rv = ret.xml;
+
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
+
+
+static int
+remoteDomainSnapshotNum (virDomainPtr domain, unsigned int flags)
+{
+    int rv = -1;
+    remote_domain_snapshot_num_args args;
+    remote_domain_snapshot_num_ret ret;
+    struct private_data *priv = domain->conn->privateData;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain (&args.domain, domain);
+    args.flags = flags;
+
+    memset (&ret, 0, sizeof ret);
+    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SNAPSHOT_NUM,
+              (xdrproc_t) xdr_remote_domain_snapshot_num_args, (char *) &args,
+              (xdrproc_t) xdr_remote_domain_snapshot_num_ret, (char *) &ret) == -1)
+        goto done;
+
+    rv = ret.num;
+
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
+
+
+static int
+remoteDomainSnapshotListNames (virDomainPtr domain, char **const names,
+                               int nameslen, unsigned int flags)
+{
+    int rv = -1;
+    int i;
+    remote_domain_snapshot_list_names_args args;
+    remote_domain_snapshot_list_names_ret ret;
+    struct private_data *priv = domain->conn->privateData;
+
+    remoteDriverLock(priv);
+
+    if (nameslen > REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX) {
+        errorf (domain->conn, VIR_ERR_RPC,
+                _("too many remote domain snapshot names: %d > %d"),
+                nameslen, REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX);
+        goto done;
+    }
+
+    make_nonnull_domain(&args.domain, domain);
+    args.nameslen = nameslen;
+    args.flags = flags;
+
+    memset (&ret, 0, sizeof ret);
+    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_NAMES,
+              (xdrproc_t) xdr_remote_domain_snapshot_list_names_args, (char *) &args,
+              (xdrproc_t) xdr_remote_domain_snapshot_list_names_ret, (char *) &ret) == -1)
+        goto done;
+
+    if (ret.names.names_len > nameslen) {
+        errorf (domain->conn, VIR_ERR_RPC,
+                _("too many remote domain snapshots: %d > %d"),
+                ret.names.names_len, nameslen);
+        goto cleanup;
+    }
+
+    /* This call is caller-frees (although that isn't clear from
+     * the documentation).  However xdr_free will free up both the
+     * names and the list of pointers, so we have to strdup the
+     * names here.
+     */
+    for (i = 0; i < ret.names.names_len; ++i) {
+        names[i] = strdup (ret.names.names_val[i]);
+
+        if (names[i] == NULL) {
+            for (--i; i >= 0; --i)
+                VIR_FREE(names[i]);
+
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
+    rv = ret.names.names_len;
+
+cleanup:
+    xdr_free ((xdrproc_t) xdr_remote_domain_snapshot_list_names_ret, (char *) &ret);
+
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
+
+
+static virDomainSnapshotPtr
+remoteDomainSnapshotLookupByName (virDomainPtr domain, const char *name,
+                                  unsigned int flags)
+{
+    virDomainSnapshotPtr snapshot = NULL;
+    remote_domain_snapshot_lookup_by_name_args args;
+    remote_domain_snapshot_lookup_by_name_ret ret;
+    struct private_data *priv = domain->conn->privateData;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain(&args.domain, domain);
+    args.name = (char *) name;
+    args.flags = flags;
+
+    memset (&ret, 0, sizeof ret);
+    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SNAPSHOT_LOOKUP_BY_NAME,
+              (xdrproc_t) xdr_remote_domain_snapshot_lookup_by_name_args, (char *) &args,
+              (xdrproc_t) xdr_remote_domain_snapshot_lookup_by_name_ret, (char *) &ret) == -1)
+        goto done;
+
+    snapshot = get_nonnull_domain_snapshot (domain, ret.snap);
+    xdr_free ((xdrproc_t) &xdr_remote_domain_snapshot_lookup_by_name_ret, (char *) &ret);
+
+done:
+    remoteDriverUnlock(priv);
+    return snapshot;
+}
+
+
+static int
+remoteDomainHasCurrentSnapshot(virDomainPtr domain, unsigned int flags)
+{
+    int rv = -1;
+    remote_domain_has_current_snapshot_args args;
+    remote_domain_has_current_snapshot_ret ret;
+    struct private_data *priv = domain->conn->privateData;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain(&args.domain, domain);
+    args.flags = flags;
+
+    if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_HAS_CURRENT_SNAPSHOT,
+             (xdrproc_t) xdr_remote_domain_has_current_snapshot_args, (char *) &args,
+             (xdrproc_t) xdr_remote_domain_has_current_snapshot_ret, (char *) &ret) == -1)
+        goto done;
+
+    rv = ret.result;
+
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
+
+
+static virDomainSnapshotPtr
+remoteDomainSnapshotCurrent(virDomainPtr domain,
+                            unsigned int flags)
+{
+    virDomainSnapshotPtr snapshot = NULL;
+    remote_domain_snapshot_current_args args;
+    remote_domain_snapshot_current_ret ret;
+    struct private_data *priv = domain->conn->privateData;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain(&args.domain, domain);
+    args.flags = flags;
+
+    memset(&ret, 0, sizeof ret);
+    if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SNAPSHOT_CURRENT,
+             (xdrproc_t) xdr_remote_domain_snapshot_current_args, (char *) &args,
+             (xdrproc_t) xdr_remote_domain_snapshot_current_ret, (char *) &ret) == -1)
+        goto done;
+
+    snapshot = get_nonnull_domain_snapshot(domain, ret.snap);
+    xdr_free((xdrproc_t) &xdr_remote_domain_snapshot_current_ret, (char *) &ret);
+
+done:
+    remoteDriverUnlock(priv);
+    return snapshot;
+}
+
+
+static int
+remoteDomainCreateFromSnapshot (virDomainSnapshotPtr snapshot,
+                                unsigned int flags)
+{
+    int rv = -1;
+    remote_domain_create_from_snapshot_args args;
+    struct private_data *priv = snapshot->domain->conn->privateData;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain_snapshot(&args.snap, snapshot);
+    args.flags = flags;
+
+    if (call (snapshot->domain->conn, priv, 0, REMOTE_PROC_DOMAIN_CREATE_FROM_SNAPSHOT,
+              (xdrproc_t) xdr_remote_domain_create_from_snapshot_args, (char *) &args,
+              (xdrproc_t) xdr_void, (char *) NULL) == -1)
+        goto done;
+
+    rv = 0;
+
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
+
+
+static int
+remoteDomainSnapshotDelete (virDomainSnapshotPtr snapshot,
+                            unsigned int flags)
+{
+    int rv = -1;
+    remote_domain_snapshot_delete_args args;
+    struct private_data *priv = snapshot->domain->conn->privateData;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain_snapshot(&args.snap, snapshot);
+    args.flags = flags;
+
+    if (call (snapshot->domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE,
+              (xdrproc_t) xdr_remote_domain_snapshot_delete_args, (char *) &args,
+              (xdrproc_t) xdr_void, (char *) NULL) == -1)
+        goto done;
+
+    rv = 0;
+
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
 
 static int remoteDomainEventRegisterAny(virConnectPtr conn,
                                         virDomainPtr dom,
@@ -9671,6 +9958,12 @@ get_nonnull_nwfilter (virConnectPtr conn, remote_nonnull_nwfilter nwfilter)
     return virGetNWFilter (conn, nwfilter.name, BAD_CAST nwfilter.uuid);
 }
 
+static virDomainSnapshotPtr
+get_nonnull_domain_snapshot (virDomainPtr domain, remote_nonnull_domain_snapshot snapshot)
+{
+    return virGetDomainSnapshot(domain, snapshot.name);
+}
+
 
 /* Make remote_nonnull_domain and remote_nonnull_network. */
 static void
@@ -9726,6 +10019,13 @@ make_nonnull_nwfilter (remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwf
     memcpy (nwfilter_dst->uuid, nwfilter_src->uuid, VIR_UUID_BUFLEN);
 }
 
+static void
+make_nonnull_domain_snapshot (remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src)
+{
+    snapshot_dst->name = snapshot_src->name;
+    make_nonnull_domain(&snapshot_dst->domain, snapshot_src->domain);
+}
+
 /*----------------------------------------------------------------------*/
 
 unsigned long remoteVersion(void)
@@ -9818,6 +10118,15 @@ static virDriver remote_driver = {
     remoteDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */
     remoteDomainEventRegisterAny, /* domainEventRegisterAny */
     remoteDomainEventDeregisterAny, /* domainEventDeregisterAny */
+    remoteDomainSnapshotCreateXML, /* domainSnapshotCreateXML */
+    remoteDomainSnapshotDumpXML, /* domainSnapshotDumpXML */
+    remoteDomainSnapshotNum, /* domainSnapshotNum */
+    remoteDomainSnapshotListNames, /* domainSnapshotListNames */
+    remoteDomainSnapshotLookupByName, /* domainSnapshotLookupByName */
+    remoteDomainHasCurrentSnapshot, /* domainHasCurrentSnapshot */
+    remoteDomainSnapshotCurrent, /* domainSnapshotCurrent */
+    remoteDomainCreateFromSnapshot, /* domainCreateFromSnapshot */
+    remoteDomainSnapshotDelete, /* domainSnapshotDelete */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c
index f252d85..f4c3eb5 100644
--- a/src/remote/remote_protocol.c
+++ b/src/remote/remote_protocol.c
@@ -128,6 +128,17 @@ xdr_remote_nonnull_secret (XDR *xdrs, remote_nonnull_secret *objp)
 }
 
 bool_t
+xdr_remote_nonnull_domain_snapshot (XDR *xdrs, remote_nonnull_domain_snapshot *objp)
+{
+
+         if (!xdr_remote_nonnull_string (xdrs, &objp->name))
+                 return FALSE;
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->domain))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
 xdr_remote_domain (XDR *xdrs, remote_domain *objp)
 {
 
@@ -3289,6 +3300,176 @@ xdr_remote_domain_event_graphics_msg (XDR *xdrs, remote_domain_event_graphics_ms
 }
 
 bool_t
+xdr_remote_domain_snapshot_create_xml_args (XDR *xdrs, remote_domain_snapshot_create_xml_args *objp)
+{
+
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->domain))
+                 return FALSE;
+         if (!xdr_remote_nonnull_string (xdrs, &objp->xml_desc))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->flags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_create_xml_ret (XDR *xdrs, remote_domain_snapshot_create_xml_ret *objp)
+{
+
+         if (!xdr_remote_nonnull_domain_snapshot (xdrs, &objp->snap))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_dump_xml_args (XDR *xdrs, remote_domain_snapshot_dump_xml_args *objp)
+{
+
+         if (!xdr_remote_nonnull_domain_snapshot (xdrs, &objp->snap))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->flags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_dump_xml_ret (XDR *xdrs, remote_domain_snapshot_dump_xml_ret *objp)
+{
+
+         if (!xdr_remote_nonnull_string (xdrs, &objp->xml))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_num_args (XDR *xdrs, remote_domain_snapshot_num_args *objp)
+{
+
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->domain))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->flags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_num_ret (XDR *xdrs, remote_domain_snapshot_num_ret *objp)
+{
+
+         if (!xdr_int (xdrs, &objp->num))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_list_names_args (XDR *xdrs, remote_domain_snapshot_list_names_args *objp)
+{
+
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->domain))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->nameslen))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->flags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_list_names_ret (XDR *xdrs, remote_domain_snapshot_list_names_ret *objp)
+{
+        char **objp_cpp0 = (char **) (void *) &objp->names.names_val;
+
+         if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->names.names_len, REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX,
+                sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_lookup_by_name_args (XDR *xdrs, remote_domain_snapshot_lookup_by_name_args *objp)
+{
+
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->domain))
+                 return FALSE;
+         if (!xdr_remote_nonnull_string (xdrs, &objp->name))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->flags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_lookup_by_name_ret (XDR *xdrs, remote_domain_snapshot_lookup_by_name_ret *objp)
+{
+
+         if (!xdr_remote_nonnull_domain_snapshot (xdrs, &objp->snap))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_has_current_snapshot_args (XDR *xdrs, remote_domain_has_current_snapshot_args *objp)
+{
+
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->domain))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->flags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_has_current_snapshot_ret (XDR *xdrs, remote_domain_has_current_snapshot_ret *objp)
+{
+
+         if (!xdr_int (xdrs, &objp->result))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_current_args (XDR *xdrs, remote_domain_snapshot_current_args *objp)
+{
+
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->domain))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->flags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_current_ret (XDR *xdrs, remote_domain_snapshot_current_ret *objp)
+{
+
+         if (!xdr_remote_nonnull_domain_snapshot (xdrs, &objp->snap))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_create_from_snapshot_args (XDR *xdrs, remote_domain_create_from_snapshot_args *objp)
+{
+
+         if (!xdr_remote_nonnull_domain_snapshot (xdrs, &objp->snap))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->flags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_snapshot_delete_args (XDR *xdrs, remote_domain_snapshot_delete_args *objp)
+{
+
+         if (!xdr_remote_nonnull_domain_snapshot (xdrs, &objp->snap))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->flags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
 xdr_remote_procedure (XDR *xdrs, remote_procedure *objp)
 {
 
diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h
index d898502..ae1c084 100644
--- a/src/remote/remote_protocol.h
+++ b/src/remote/remote_protocol.h
@@ -42,6 +42,7 @@ typedef remote_nonnull_string *remote_string;
 #define REMOTE_AUTH_SASL_DATA_MAX 65536
 #define REMOTE_AUTH_TYPE_LIST_MAX 20
 #define REMOTE_DOMAIN_MEMORY_STATS_MAX 1024
+#define REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX 1024
 #define REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX 65536
 #define REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX 65536
 #define REMOTE_SECURITY_MODEL_MAX VIR_SECURITY_MODEL_BUFLEN
@@ -103,6 +104,12 @@ struct remote_nonnull_secret {
 };
 typedef struct remote_nonnull_secret remote_nonnull_secret;
 
+struct remote_nonnull_domain_snapshot {
+        remote_nonnull_string name;
+        remote_nonnull_domain domain;
+};
+typedef struct remote_nonnull_domain_snapshot remote_nonnull_domain_snapshot;
+
 typedef remote_nonnull_domain *remote_domain;
 
 typedef remote_nonnull_network *remote_network;
@@ -1860,6 +1867,101 @@ struct remote_domain_event_graphics_msg {
         } subject;
 };
 typedef struct remote_domain_event_graphics_msg remote_domain_event_graphics_msg;
+
+struct remote_domain_snapshot_create_xml_args {
+        remote_nonnull_domain domain;
+        remote_nonnull_string xml_desc;
+        int flags;
+};
+typedef struct remote_domain_snapshot_create_xml_args remote_domain_snapshot_create_xml_args;
+
+struct remote_domain_snapshot_create_xml_ret {
+        remote_nonnull_domain_snapshot snap;
+};
+typedef struct remote_domain_snapshot_create_xml_ret remote_domain_snapshot_create_xml_ret;
+
+struct remote_domain_snapshot_dump_xml_args {
+        remote_nonnull_domain_snapshot snap;
+        int flags;
+};
+typedef struct remote_domain_snapshot_dump_xml_args remote_domain_snapshot_dump_xml_args;
+
+struct remote_domain_snapshot_dump_xml_ret {
+        remote_nonnull_string xml;
+};
+typedef struct remote_domain_snapshot_dump_xml_ret remote_domain_snapshot_dump_xml_ret;
+
+struct remote_domain_snapshot_num_args {
+        remote_nonnull_domain domain;
+        int flags;
+};
+typedef struct remote_domain_snapshot_num_args remote_domain_snapshot_num_args;
+
+struct remote_domain_snapshot_num_ret {
+        int num;
+};
+typedef struct remote_domain_snapshot_num_ret remote_domain_snapshot_num_ret;
+
+struct remote_domain_snapshot_list_names_args {
+        remote_nonnull_domain domain;
+        int nameslen;
+        int flags;
+};
+typedef struct remote_domain_snapshot_list_names_args remote_domain_snapshot_list_names_args;
+
+struct remote_domain_snapshot_list_names_ret {
+        struct {
+                u_int names_len;
+                remote_nonnull_string *names_val;
+        } names;
+};
+typedef struct remote_domain_snapshot_list_names_ret remote_domain_snapshot_list_names_ret;
+
+struct remote_domain_snapshot_lookup_by_name_args {
+        remote_nonnull_domain domain;
+        remote_nonnull_string name;
+        int flags;
+};
+typedef struct remote_domain_snapshot_lookup_by_name_args remote_domain_snapshot_lookup_by_name_args;
+
+struct remote_domain_snapshot_lookup_by_name_ret {
+        remote_nonnull_domain_snapshot snap;
+};
+typedef struct remote_domain_snapshot_lookup_by_name_ret remote_domain_snapshot_lookup_by_name_ret;
+
+struct remote_domain_has_current_snapshot_args {
+        remote_nonnull_domain domain;
+        int flags;
+};
+typedef struct remote_domain_has_current_snapshot_args remote_domain_has_current_snapshot_args;
+
+struct remote_domain_has_current_snapshot_ret {
+        int result;
+};
+typedef struct remote_domain_has_current_snapshot_ret remote_domain_has_current_snapshot_ret;
+
+struct remote_domain_snapshot_current_args {
+        remote_nonnull_domain domain;
+        int flags;
+};
+typedef struct remote_domain_snapshot_current_args remote_domain_snapshot_current_args;
+
+struct remote_domain_snapshot_current_ret {
+        remote_nonnull_domain_snapshot snap;
+};
+typedef struct remote_domain_snapshot_current_ret remote_domain_snapshot_current_ret;
+
+struct remote_domain_create_from_snapshot_args {
+        remote_nonnull_domain_snapshot snap;
+        int flags;
+};
+typedef struct remote_domain_create_from_snapshot_args remote_domain_create_from_snapshot_args;
+
+struct remote_domain_snapshot_delete_args {
+        remote_nonnull_domain_snapshot snap;
+        int flags;
+};
+typedef struct remote_domain_snapshot_delete_args remote_domain_snapshot_delete_args;
 #define REMOTE_PROGRAM 0x20008086
 #define REMOTE_PROTOCOL_VERSION 1
 
@@ -2045,6 +2147,15 @@ enum remote_procedure {
         REMOTE_PROC_LIST_NWFILTERS = 179,
         REMOTE_PROC_NWFILTER_DEFINE_XML = 180,
         REMOTE_PROC_NWFILTER_UNDEFINE = 181,
+        REMOTE_PROC_DOMAIN_SNAPSHOT_CREATE_XML = 182,
+        REMOTE_PROC_DOMAIN_SNAPSHOT_DUMP_XML = 183,
+        REMOTE_PROC_DOMAIN_SNAPSHOT_NUM = 184,
+        REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_NAMES = 185,
+        REMOTE_PROC_DOMAIN_SNAPSHOT_LOOKUP_BY_NAME = 186,
+        REMOTE_PROC_DOMAIN_HAS_CURRENT_SNAPSHOT = 187,
+        REMOTE_PROC_DOMAIN_SNAPSHOT_CURRENT = 188,
+        REMOTE_PROC_DOMAIN_CREATE_FROM_SNAPSHOT = 189,
+        REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE = 190,
 };
 typedef enum remote_procedure remote_procedure;
 
@@ -2088,6 +2199,7 @@ extern  bool_t xdr_remote_nonnull_storage_pool (XDR *, remote_nonnull_storage_po
 extern  bool_t xdr_remote_nonnull_storage_vol (XDR *, remote_nonnull_storage_vol*);
 extern  bool_t xdr_remote_nonnull_node_device (XDR *, remote_nonnull_node_device*);
 extern  bool_t xdr_remote_nonnull_secret (XDR *, remote_nonnull_secret*);
+extern  bool_t xdr_remote_nonnull_domain_snapshot (XDR *, remote_nonnull_domain_snapshot*);
 extern  bool_t xdr_remote_domain (XDR *, remote_domain*);
 extern  bool_t xdr_remote_network (XDR *, remote_network*);
 extern  bool_t xdr_remote_nwfilter (XDR *, remote_nwfilter*);
@@ -2380,6 +2492,22 @@ extern  bool_t xdr_remote_domain_event_io_error_msg (XDR *, remote_domain_event_
 extern  bool_t xdr_remote_domain_event_graphics_address (XDR *, remote_domain_event_graphics_address*);
 extern  bool_t xdr_remote_domain_event_graphics_identity (XDR *, remote_domain_event_graphics_identity*);
 extern  bool_t xdr_remote_domain_event_graphics_msg (XDR *, remote_domain_event_graphics_msg*);
+extern  bool_t xdr_remote_domain_snapshot_create_xml_args (XDR *, remote_domain_snapshot_create_xml_args*);
+extern  bool_t xdr_remote_domain_snapshot_create_xml_ret (XDR *, remote_domain_snapshot_create_xml_ret*);
+extern  bool_t xdr_remote_domain_snapshot_dump_xml_args (XDR *, remote_domain_snapshot_dump_xml_args*);
+extern  bool_t xdr_remote_domain_snapshot_dump_xml_ret (XDR *, remote_domain_snapshot_dump_xml_ret*);
+extern  bool_t xdr_remote_domain_snapshot_num_args (XDR *, remote_domain_snapshot_num_args*);
+extern  bool_t xdr_remote_domain_snapshot_num_ret (XDR *, remote_domain_snapshot_num_ret*);
+extern  bool_t xdr_remote_domain_snapshot_list_names_args (XDR *, remote_domain_snapshot_list_names_args*);
+extern  bool_t xdr_remote_domain_snapshot_list_names_ret (XDR *, remote_domain_snapshot_list_names_ret*);
+extern  bool_t xdr_remote_domain_snapshot_lookup_by_name_args (XDR *, remote_domain_snapshot_lookup_by_name_args*);
+extern  bool_t xdr_remote_domain_snapshot_lookup_by_name_ret (XDR *, remote_domain_snapshot_lookup_by_name_ret*);
+extern  bool_t xdr_remote_domain_has_current_snapshot_args (XDR *, remote_domain_has_current_snapshot_args*);
+extern  bool_t xdr_remote_domain_has_current_snapshot_ret (XDR *, remote_domain_has_current_snapshot_ret*);
+extern  bool_t xdr_remote_domain_snapshot_current_args (XDR *, remote_domain_snapshot_current_args*);
+extern  bool_t xdr_remote_domain_snapshot_current_ret (XDR *, remote_domain_snapshot_current_ret*);
+extern  bool_t xdr_remote_domain_create_from_snapshot_args (XDR *, remote_domain_create_from_snapshot_args*);
+extern  bool_t xdr_remote_domain_snapshot_delete_args (XDR *, remote_domain_snapshot_delete_args*);
 extern  bool_t xdr_remote_procedure (XDR *, remote_procedure*);
 extern  bool_t xdr_remote_message_type (XDR *, remote_message_type*);
 extern  bool_t xdr_remote_message_status (XDR *, remote_message_status*);
@@ -2397,6 +2525,7 @@ extern bool_t xdr_remote_nonnull_storage_pool ();
 extern bool_t xdr_remote_nonnull_storage_vol ();
 extern bool_t xdr_remote_nonnull_node_device ();
 extern bool_t xdr_remote_nonnull_secret ();
+extern bool_t xdr_remote_nonnull_domain_snapshot ();
 extern bool_t xdr_remote_domain ();
 extern bool_t xdr_remote_network ();
 extern bool_t xdr_remote_nwfilter ();
@@ -2689,6 +2818,22 @@ extern bool_t xdr_remote_domain_event_io_error_msg ();
 extern bool_t xdr_remote_domain_event_graphics_address ();
 extern bool_t xdr_remote_domain_event_graphics_identity ();
 extern bool_t xdr_remote_domain_event_graphics_msg ();
+extern bool_t xdr_remote_domain_snapshot_create_xml_args ();
+extern bool_t xdr_remote_domain_snapshot_create_xml_ret ();
+extern bool_t xdr_remote_domain_snapshot_dump_xml_args ();
+extern bool_t xdr_remote_domain_snapshot_dump_xml_ret ();
+extern bool_t xdr_remote_domain_snapshot_num_args ();
+extern bool_t xdr_remote_domain_snapshot_num_ret ();
+extern bool_t xdr_remote_domain_snapshot_list_names_args ();
+extern bool_t xdr_remote_domain_snapshot_list_names_ret ();
+extern bool_t xdr_remote_domain_snapshot_lookup_by_name_args ();
+extern bool_t xdr_remote_domain_snapshot_lookup_by_name_ret ();
+extern bool_t xdr_remote_domain_has_current_snapshot_args ();
+extern bool_t xdr_remote_domain_has_current_snapshot_ret ();
+extern bool_t xdr_remote_domain_snapshot_current_args ();
+extern bool_t xdr_remote_domain_snapshot_current_ret ();
+extern bool_t xdr_remote_domain_create_from_snapshot_args ();
+extern bool_t xdr_remote_domain_snapshot_delete_args ();
 extern bool_t xdr_remote_procedure ();
 extern bool_t xdr_remote_message_type ();
 extern bool_t xdr_remote_message_status ();
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index bf87c33..49ac935 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -121,6 +121,9 @@ const REMOTE_AUTH_TYPE_LIST_MAX = 20;
 /* Upper limit on list of memory stats */
 const REMOTE_DOMAIN_MEMORY_STATS_MAX = 1024;
 
+/* Upper limit on lists of domain snapshots. */
+const REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX = 1024;
+
 /* Maximum length of a block peek buffer message.
  * Note applications need to be aware of this limit and issue multiple
  * requests for large amounts of data.
@@ -216,6 +219,12 @@ struct remote_nonnull_secret {
     remote_nonnull_string usageID;
 };
 
+/* A snapshot which may not be NULL. */
+struct remote_nonnull_domain_snapshot {
+    remote_nonnull_string name;
+    remote_nonnull_domain domain;
+};
+
 /* A domain or network which may be NULL. */
 typedef remote_nonnull_domain *remote_domain;
 typedef remote_nonnull_network *remote_network;
@@ -1647,6 +1656,83 @@ struct remote_domain_event_graphics_msg {
     remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
 };
 
+struct remote_domain_snapshot_create_xml_args {
+    remote_nonnull_domain domain;
+    remote_nonnull_string xml_desc;
+    int flags;
+};
+
+struct remote_domain_snapshot_create_xml_ret {
+    remote_nonnull_domain_snapshot snap;
+};
+
+struct remote_domain_snapshot_dump_xml_args {
+    remote_nonnull_domain_snapshot snap;
+    int flags;
+};
+
+struct remote_domain_snapshot_dump_xml_ret {
+    remote_nonnull_string xml;
+};
+
+struct remote_domain_snapshot_num_args {
+    remote_nonnull_domain domain;
+    int flags;
+};
+
+struct remote_domain_snapshot_num_ret {
+    int num;
+};
+
+struct remote_domain_snapshot_list_names_args {
+    remote_nonnull_domain domain;
+    int nameslen;
+    int flags;
+};
+
+struct remote_domain_snapshot_list_names_ret {
+    remote_nonnull_string names<REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX>;
+};
+
+struct remote_domain_snapshot_lookup_by_name_args {
+    remote_nonnull_domain domain;
+    remote_nonnull_string name;
+    int flags;
+};
+
+struct remote_domain_snapshot_lookup_by_name_ret {
+    remote_nonnull_domain_snapshot snap;
+};
+
+struct remote_domain_has_current_snapshot_args {
+    remote_nonnull_domain domain;
+    int flags;
+};
+
+struct remote_domain_has_current_snapshot_ret {
+    int result;
+};
+
+struct remote_domain_snapshot_current_args {
+    remote_nonnull_domain domain;
+    int flags;
+};
+
+struct remote_domain_snapshot_current_ret {
+    remote_nonnull_domain_snapshot snap;
+};
+
+struct remote_domain_create_from_snapshot_args {
+    remote_nonnull_domain_snapshot snap;
+    int flags;
+};
+
+struct remote_domain_snapshot_delete_args {
+    remote_nonnull_domain_snapshot snap;
+    int flags;
+};
+
+
 /*----- Protocol. -----*/
 
 /* Define the program number, protocol version and procedure numbers here. */
@@ -1852,7 +1938,16 @@ enum remote_procedure {
     REMOTE_PROC_LIST_NWFILTERS = 179,
     REMOTE_PROC_NWFILTER_DEFINE_XML = 180,
 
-    REMOTE_PROC_NWFILTER_UNDEFINE = 181
+    REMOTE_PROC_NWFILTER_UNDEFINE = 181,
+    REMOTE_PROC_DOMAIN_SNAPSHOT_CREATE_XML = 182,
+    REMOTE_PROC_DOMAIN_SNAPSHOT_DUMP_XML = 183,
+    REMOTE_PROC_DOMAIN_SNAPSHOT_NUM = 184,
+    REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_NAMES = 185,
+    REMOTE_PROC_DOMAIN_SNAPSHOT_LOOKUP_BY_NAME = 186,
+    REMOTE_PROC_DOMAIN_HAS_CURRENT_SNAPSHOT = 187,
+    REMOTE_PROC_DOMAIN_SNAPSHOT_CURRENT = 188,
+    REMOTE_PROC_DOMAIN_CREATE_FROM_SNAPSHOT = 189,
+    REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE = 190
 
     /*
      * Notice how the entries are grouped in sets of 10 ?
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 646c7db..2a0e2b7 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -5306,6 +5306,15 @@ static virDriver testDriver = {
     NULL, /* domainMigrateSetMaxDowntime */
     testDomainEventRegisterAny, /* domainEventRegisterAny */
     testDomainEventDeregisterAny, /* domainEventDeregisterAny */
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 static virNetworkDriver testNetworkDriver = {
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index 08fbf93..4a1bd84 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -1937,6 +1937,15 @@ static virDriver umlDriver = {
     NULL, /* domainMigrateSetMaxDowntime */
     NULL, /* domainEventRegisterAny */
     NULL, /* domainEventDeregisterAny */
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 2537110..d29f95b 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -184,6 +184,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
         case VIR_FROM_HOOK:
             dom = "Sync Hook ";
             break;
+        case VIR_FROM_DOMAIN_SNAPSHOT:
+            dom = "Domain Snapshot ";
+            break;
     }
     return(dom);
 }
@@ -1153,6 +1156,18 @@ virErrorMsg(virErrorNumber error, const char *info)
             else
                 errmsg = _("Hook script execution failed: %s");
             break;
+        case VIR_ERR_INVALID_DOMAIN_SNAPSHOT:
+            if (info == NULL)
+                errmsg = _("Invalid snapshot");
+            else
+                errmsg = _("Invalid snapshot: %s");
+            break;
+        case VIR_ERR_NO_DOMAIN_SNAPSHOT:
+            if (info == NULL)
+                errmsg = _("Domain snapshot not found");
+            else
+                errmsg = _("Domain snapshot not found: %s");
+            break;
     }
     return (errmsg);
 }
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index 14fdcda..8163d22 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -7184,6 +7184,15 @@ virDriver NAME(Driver) = {
     vboxDomainEventRegisterAny, /* domainEventRegisterAny */
     vboxDomainEventDeregisterAny, /* domainEventDeregisterAny */
 #endif
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 virNetworkDriver NAME(NetworkDriver) = {
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
index ebdc600..c277ade 100644
--- a/src/xen/xen_driver.c
+++ b/src/xen/xen_driver.c
@@ -1980,6 +1980,15 @@ static virDriver xenUnifiedDriver = {
     NULL, /* domainMigrateSetMaxDowntime */
     xenUnifiedDomainEventRegisterAny, /* domainEventRegisterAny */
     xenUnifiedDomainEventDeregisterAny, /* domainEventDeregisterAny */
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 /**
diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c
index dcfdc1e..c0fd8ab 100644
--- a/src/xenapi/xenapi_driver.c
+++ b/src/xenapi/xenapi_driver.c
@@ -1783,6 +1783,15 @@ static virDriver xenapiDriver = {
     NULL, /* domainMigrateSetMaxDowntime */
     NULL, /* domainEventRegisterAny */
     NULL, /* domainEventDeregisterAny */
+    NULL, /* domainSnapshotCreateXML */
+    NULL, /* domainSnapshotDumpXML */
+    NULL, /* domainSnapshotNum */
+    NULL, /* domainSnapshotListNames */
+    NULL, /* domainSnapshotLookupByName */
+    NULL, /* domainHasCurrentSnapshot */
+    NULL, /* domainSnapshotCurrent */
+    NULL, /* domainCreateFromSnapshot */
+    NULL, /* domainSnapshotDelete */
 };
 
 /**
-- 
1.6.6.1




More information about the libvir-list mailing list