]> xenbits.xensource.com Git - libvirt.git/commitdiff
Add new virDomainShutdownFlags API
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 5 Oct 2011 17:31:55 +0000 (18:31 +0100)
committerMichal Privoznik <mprivozn@redhat.com>
Tue, 24 Jan 2012 11:19:51 +0000 (12:19 +0100)
Add a new API virDomainShutdownFlags and define:

    VIR_DOMAIN_SHUTDOWN_DEFAULT        = 0,
    VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN = (1 << 0),
    VIR_DOMAIN_SHUTDOWN_GUEST_AGENT    = (1 << 1),

Also define some flags for the reboot API

    VIR_DOMAIN_REBOOT_DEFAULT        = 0,
    VIR_DOMAIN_REBOOT_ACPI_POWER_BTN = (1 << 0),
    VIR_DOMAIN_REBOOT_GUEST_AGENT    = (1 << 1),

Although these two APIs currently have the same flags, using
separate enums allows them to expand separately in the future.

Add stub impls of the new API for all existing drivers

16 files changed:
include/libvirt/libvirt.h.in
src/driver.h
src/esx/esx_driver.c
src/libvirt.c
src/libvirt_public.syms
src/libxl/libxl_driver.c
src/openvz/openvz_driver.c
src/remote/remote_driver.c
src/remote/remote_protocol.x
src/remote_protocol-structs
src/test/test_driver.c
src/uml/uml_driver.c
src/vbox/vbox_tmpl.c
src/vmware/vmware_driver.c
src/xen/xen_driver.c
src/xenapi/xenapi_driver.c

index 958e5a6b73527bd271f68e8f007386de7a4210de..5e6e488bc6e940a53ad8a2a0303a7ba82c477079 100644 (file)
@@ -1200,7 +1200,22 @@ virDomainPtr            virDomainLookupByUUID   (virConnectPtr conn,
 virDomainPtr            virDomainLookupByUUIDString     (virConnectPtr conn,
                                                         const char *uuid);
 
+typedef enum {
+    VIR_DOMAIN_SHUTDOWN_DEFAULT        = 0,        /* hypervisor choice */
+    VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN = (1 << 0), /* Send ACPI event */
+    VIR_DOMAIN_SHUTDOWN_GUEST_AGENT    = (1 << 1), /* Use guest agent */
+} virDomainShutdownFlagValues;
+
 int                     virDomainShutdown       (virDomainPtr domain);
+int                     virDomainShutdownFlags  (virDomainPtr domain,
+                                                 unsigned int flags);
+
+typedef enum {
+    VIR_DOMAIN_REBOOT_DEFAULT        = 0,        /* hypervisor choice */
+    VIR_DOMAIN_REBOOT_ACPI_POWER_BTN = (1 << 0), /* Send ACPI event */
+    VIR_DOMAIN_REBOOT_GUEST_AGENT    = (1 << 1), /* Use guest agent */
+} virDomainRebootFlagValues;
+
 int                     virDomainReboot         (virDomainPtr domain,
                                                  unsigned int flags);
 int                     virDomainReset          (virDomainPtr domain,
index 24636a43a21fba210a6aeede2f0c7f80e0706031..6222bed1669e497d4da98c8897def863489a4e6e 100644 (file)
@@ -793,6 +793,10 @@ typedef int
                                   virTypedParameterPtr params,
                                   int *nparams,
                                   unsigned int flags);
+typedef int
+    (*virDrvDomainShutdownFlags)(virDomainPtr domain,
+                                 unsigned int flags);
+
 
 /**
  * _virDriver:
@@ -829,6 +833,7 @@ struct _virDriver {
     virDrvDomainSuspend                domainSuspend;
     virDrvDomainResume         domainResume;
     virDrvDomainShutdown               domainShutdown;
+    virDrvDomainShutdownFlags   domainShutdownFlags;
     virDrvDomainReboot         domainReboot;
     virDrvDomainReset       domainReset;
     virDrvDomainDestroy                domainDestroy;
index 63cdba573c1849f823869f9452621cda54670b83..f5e1cc73d4ba644606a91c2408cb5c12c8f2724f 100644 (file)
@@ -1887,7 +1887,7 @@ esxDomainResume(virDomainPtr domain)
 
 
 static int
-esxDomainShutdown(virDomainPtr domain)
+esxDomainShutdownFlags(virDomainPtr domain, unsigned int flags)
 {
     int result = -1;
     esxPrivate *priv = domain->conn->privateData;
@@ -1895,6 +1895,8 @@ esxDomainShutdown(virDomainPtr domain)
     esxVI_String *propertyNameList = NULL;
     esxVI_VirtualMachinePowerState powerState;
 
+    virCheckFlags(0, -1);
+
     if (esxVI_EnsureSession(priv->primary) < 0) {
         return -1;
     }
@@ -1928,6 +1930,12 @@ esxDomainShutdown(virDomainPtr domain)
 }
 
 
+static int
+esxDomainShutdown(virDomainPtr domain)
+{
+    return esxDomainShutdownFlags(domain, 0);
+}
+
 
 static int
 esxDomainReboot(virDomainPtr domain, unsigned int flags)
@@ -4953,6 +4961,7 @@ static virDriver esxDriver = {
     .domainSuspend = esxDomainSuspend, /* 0.7.0 */
     .domainResume = esxDomainResume, /* 0.7.0 */
     .domainShutdown = esxDomainShutdown, /* 0.7.0 */
+    .domainShutdownFlags = esxDomainShutdownFlags, /* 0.9.10 */
     .domainReboot = esxDomainReboot, /* 0.7.0 */
     .domainDestroy = esxDomainDestroy, /* 0.7.0 */
     .domainDestroyFlags = esxDomainDestroyFlags, /* 0.9.4 */
index 7b8adf7f184b2f4a890d4e898ade43ba9337d180..96ad3d51dfa315e5635ba5c36bdbe2bc1178b089 100644 (file)
@@ -3105,15 +3105,88 @@ error:
     return -1;
 }
 
+/**
+ * virDomainShutdownFlags:
+ * @domain: a domain object
+ * @flags: bitwise-OR of virDomainShutdownFlagValues
+ *
+ * Shutdown a domain, the domain object is still usable thereafter but
+ * the domain OS is being stopped. Note that the guest OS may ignore the
+ * request.  For guests that react to a shutdown request, the differences
+ * from virDomainDestroy() are that the guest's disk storage will be in a
+ * stable state rather than having the (virtual) power cord pulled, and
+ * this command returns as soon as the shutdown request is issued rather
+ * than blocking until the guest is no longer running.
+ *
+ * If the domain is transient and has any snapshot metadata (see
+ * virDomainSnapshotNum()), then that metadata will automatically
+ * be deleted when the domain quits.
+ *
+ * If @flags is set to zero, then the hypervisor will choose the
+ * method of shutdown it considers best. To have greater control
+ * pass exactly one of the virDomainShutdownFlagValues.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainShutdownFlags(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    /* At most one of these two flags should be set.  */
+    if ((flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) &&
+        (flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT)) {
+        virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto error;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainShutdownFlags) {
+        int ret;
+        ret = conn->driver->domainShutdownFlags(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
 /**
  * virDomainReboot:
  * @domain: a domain object
- * @flags: extra flags; not used yet, so callers should always pass 0
+ * @flags: bitwise-OR of virDomainRebootFlagValues
  *
  * Reboot a domain, the domain object is still usable there after but
  * the domain OS is being stopped for a restart.
  * Note that the guest OS may ignore the request.
  *
+ * If @flags is set to zero, then the hypervisor will choose the
+ * method of shutdown it considers best. To have greater control
+ * pass exactly one of the virDomainRebootFlagValues.
+ *
+ * To use guest agent (VIR_DOMAIN_REBOOT_GUEST_AGENT) the domain XML
+ * must have <channel> configured.
+ *
  * Returns 0 in case of success and -1 in case of failure.
  */
 int
@@ -3135,6 +3208,13 @@ virDomainReboot(virDomainPtr domain, unsigned int flags)
         goto error;
     }
 
+    /* At most one of these two flags should be set.  */
+    if ((flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) &&
+        (flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT)) {
+        virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto error;
+    }
+
     conn = domain->conn;
 
     if (conn->driver->domainReboot) {
index 4ca72165736fefa621bcef7e048778dd4a4042ce..e0cbdb448d4696d6531b7faa65b1562aded9426c 100644 (file)
@@ -516,4 +516,8 @@ LIBVIRT_0.9.9 {
         virDomainSetNumaParameters;
 } LIBVIRT_0.9.8;
 
+LIBVIRT_0.9.10 {
+    global:
+        virDomainShutdownFlags;
+} LIBVIRT_0.9.9;
 # .... define new API here using predicted next version number ....
index f7f45c70b74299613961ff33f8f6ccd0723d652c..41366e464304385b94ad12d8f61eaa9072d680b2 100644 (file)
@@ -1412,13 +1412,15 @@ cleanup:
 }
 
 static int
-libxlDomainShutdown(virDomainPtr dom)
+libxlDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
 {
     libxlDriverPrivatePtr driver = dom->conn->privateData;
     virDomainObjPtr vm;
     int ret = -1;
     libxlDomainObjPrivatePtr priv;
 
+    virCheckFlags(0, -1);
+
     libxlDriverLock(driver);
     vm = virDomainFindByUUID(&driver->domains, dom->uuid);
     if (!vm) {
@@ -1455,6 +1457,13 @@ cleanup:
     return ret;
 }
 
+static int
+libxlDomainShutdown(virDomainPtr dom)
+{
+    return libxlDomainShutdownFlags(dom, 0);
+}
+
+
 static int
 libxlDomainReboot(virDomainPtr dom, unsigned int flags)
 {
@@ -3857,6 +3866,7 @@ static virDriver libxlDriver = {
     .domainSuspend = libxlDomainSuspend, /* 0.9.0 */
     .domainResume = libxlDomainResume, /* 0.9.0 */
     .domainShutdown = libxlDomainShutdown, /* 0.9.0 */
+    .domainShutdownFlags = libxlDomainShutdownFlags, /* 0.9.10 */
     .domainReboot = libxlDomainReboot, /* 0.9.0 */
     .domainDestroy = libxlDomainDestroy, /* 0.9.0 */
     .domainDestroyFlags = libxlDomainDestroyFlags, /* 0.9.4 */
index 03bf21a903dbfa171a74cafb48633bd4f77fdb1c..b848a888a9cdb2285a9ce59bf1d13cdf28dc41bc 100644 (file)
@@ -1693,6 +1693,7 @@ static virDriver openvzDriver = {
     .domainSuspend = openvzDomainSuspend, /* 0.8.3 */
     .domainResume = openvzDomainResume, /* 0.8.3 */
     .domainShutdown = openvzDomainShutdown, /* 0.3.1 */
+    .domainShutdownFlags = openvzDomainShutdownFlags, /* 0.9.10 */
     .domainReboot = openvzDomainReboot, /* 0.3.1 */
     .domainDestroy = openvzDomainShutdown, /* 0.3.1 */
     .domainDestroyFlags = openvzDomainShutdownFlags, /* 0.9.4 */
index e28840b9816dcfb02f56cd32d29974c23710614b..f45a8feb4047a20665535811c5e0ceb5f305ab2f 100644 (file)
@@ -4617,6 +4617,7 @@ static virDriver remote_driver = {
     .domainSuspend = remoteDomainSuspend, /* 0.3.0 */
     .domainResume = remoteDomainResume, /* 0.3.0 */
     .domainShutdown = remoteDomainShutdown, /* 0.3.0 */
+    .domainShutdownFlags = remoteDomainShutdownFlags, /* 0.9.10 */
     .domainReboot = remoteDomainReboot, /* 0.3.0 */
     .domainReset = remoteDomainReset, /* 0.9.7 */
     .domainDestroy = remoteDomainDestroy, /* 0.3.0 */
index 514b0cc08c8c4913ff8c47dca5df20614c4d1301..6a20ae81d645430bf24499e7dccf56b691c8db26 100644 (file)
@@ -2349,6 +2349,11 @@ struct remote_node_suspend_for_duration_args {
     unsigned int flags;
 };
 
+struct remote_domain_shutdown_flags_args {
+    remote_nonnull_domain dom;
+    unsigned int flags;
+};
+
 
 /*----- Protocol. -----*/
 
@@ -2654,7 +2659,8 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_SET_NUMA_PARAMETERS = 254, /* autogen autogen */
     REMOTE_PROC_DOMAIN_GET_NUMA_PARAMETERS = 255, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_SET_INTERFACE_PARAMETERS = 256, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS = 257 /* skipgen skipgen */
+    REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS = 257, /* skipgen skipgen */
+    REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS = 258 /* autogen autogen */
 
     /*
      * Notice how the entries are grouped in sets of 10 ?
index 275831556daf3074d8447a0f082c3b43e2dd4bbb..430d8e4a6caffd73417708515b9a06b4e8914421 100644 (file)
@@ -1832,6 +1832,10 @@ struct remote_node_suspend_for_duration_args {
         uint64_t                   duration;
         u_int                      flags;
 };
+struct remote_domain_shutdown_flags_args {
+        remote_nonnull_domain      dom;
+        u_int                      flags;
+};
 enum remote_procedure {
         REMOTE_PROC_OPEN = 1,
         REMOTE_PROC_CLOSE = 2,
@@ -2090,4 +2094,5 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_GET_NUMA_PARAMETERS = 255,
         REMOTE_PROC_DOMAIN_SET_INTERFACE_PARAMETERS = 256,
         REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS = 257,
+        REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS = 258,
 };
index c0b2ca668db094cba2f012dd31a8d857076567bc..55b889b148002db3f8f287f4f69f791190a5f57a 100644 (file)
@@ -1542,13 +1542,16 @@ cleanup:
     return ret;
 }
 
-static int testShutdownDomain (virDomainPtr domain)
+static int testShutdownDomainFlags(virDomainPtr domain,
+                                   unsigned int flags)
 {
     testConnPtr privconn = domain->conn->privateData;
     virDomainObjPtr privdom;
     virDomainEventPtr event = NULL;
     int ret = -1;
 
+    virCheckFlags(0, -1);
+
     testDriverLock(privconn);
     privdom = virDomainFindByName(&privconn->domains,
                                   domain->name);
@@ -1585,6 +1588,11 @@ cleanup:
     return ret;
 }
 
+static int testShutdownDomain (virDomainPtr domain)
+{
+    return testShutdownDomainFlags(domain, 0);
+}
+
 /* Similar behaviour as shutdown */
 static int testRebootDomain (virDomainPtr domain,
                              unsigned int action ATTRIBUTE_UNUSED)
@@ -5523,6 +5531,7 @@ static virDriver testDriver = {
     .domainSuspend = testPauseDomain, /* 0.1.1 */
     .domainResume = testResumeDomain, /* 0.1.1 */
     .domainShutdown = testShutdownDomain, /* 0.1.1 */
+    .domainShutdownFlags = testShutdownDomainFlags, /* 0.9.10 */
     .domainReboot = testRebootDomain, /* 0.1.1 */
     .domainDestroy = testDestroyDomain, /* 0.1.1 */
     .domainGetOSType = testGetOSType, /* 0.1.9 */
index 671216e15ce8601034c77b8929dff3eb5bcc6f75..a4cf9452a7aead6971bd9fe359f5129516e283b0 100644 (file)
@@ -1513,12 +1513,15 @@ cleanup:
 }
 
 
-static int umlDomainShutdown(virDomainPtr dom) {
+static int umlDomainShutdownFlags(virDomainPtr dom,
+                                  unsigned int flags) {
     struct uml_driver *driver = dom->conn->privateData;
     virDomainObjPtr vm;
     char *info = NULL;
     int ret = -1;
 
+    virCheckFlags(0, -1);
+
     umlDriverLock(driver);
     vm = virDomainFindByID(&driver->domains, dom->id);
     umlDriverUnlock(driver);
@@ -1544,6 +1547,11 @@ cleanup:
     return ret;
 }
 
+static int
+umlDomainShutdown(virDomainPtr dom)
+{
+    return umlDomainShutdownFlags(dom, 0);
+}
 
 static int
 umlDomainDestroyFlags(virDomainPtr dom,
@@ -2533,6 +2541,7 @@ static virDriver umlDriver = {
     .domainLookupByUUID = umlDomainLookupByUUID, /* 0.5.0 */
     .domainLookupByName = umlDomainLookupByName, /* 0.5.0 */
     .domainShutdown = umlDomainShutdown, /* 0.5.0 */
+    .domainShutdownFlags = umlDomainShutdownFlags, /* 0.9.10 */
     .domainDestroy = umlDomainDestroy, /* 0.5.0 */
     .domainDestroyFlags = umlDomainDestroyFlags, /* 0.9.4 */
     .domainGetOSType = umlDomainGetOSType, /* 0.5.0 */
index 22712d578b3951818f6c379839af973868e573b2..d72043274b863b7923f500920bbc7003502e61e3 100644 (file)
@@ -1606,7 +1606,8 @@ cleanup:
     return ret;
 }
 
-static int vboxDomainShutdown(virDomainPtr dom) {
+static int vboxDomainShutdownFlags(virDomainPtr dom,
+                                   unsigned int flags) {
     VBOX_OBJECT_CHECK(dom->conn, int, -1);
     IMachine *machine    = NULL;
     vboxIID iid = VBOX_IID_INITIALIZER;
@@ -1615,6 +1616,8 @@ static int vboxDomainShutdown(virDomainPtr dom) {
     PRBool isAccessible  = PR_FALSE;
     nsresult rc;
 
+    virCheckFlags(0, -1);
+
     vboxIIDFromUUID(&iid, dom->uuid);
     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
     if (NS_FAILED(rc)) {
@@ -1656,6 +1659,11 @@ cleanup:
     return ret;
 }
 
+static int vboxDomainShutdown(virDomainPtr dom) {
+    return vboxDomainShutdownFlags(dom, 0);
+}
+
+
 static int vboxDomainReboot(virDomainPtr dom, unsigned int flags)
 {
     VBOX_OBJECT_CHECK(dom->conn, int, -1);
@@ -9112,6 +9120,7 @@ virDriver NAME(Driver) = {
     .domainSuspend = vboxDomainSuspend, /* 0.6.3 */
     .domainResume = vboxDomainResume, /* 0.6.3 */
     .domainShutdown = vboxDomainShutdown, /* 0.6.3 */
+    .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
     .domainReboot = vboxDomainReboot, /* 0.6.3 */
     .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
     .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
index a9873ba1a7190b90d181b419ac6d4a13e831b0bc..56e9d2d704f88d1c8cecec7483ff9b841c86a9af 100644 (file)
@@ -980,6 +980,7 @@ static virDriver vmwareDriver = {
     .domainSuspend = vmwareDomainSuspend, /* 0.8.7 */
     .domainResume = vmwareDomainResume, /* 0.8.7 */
     .domainShutdown = vmwareDomainShutdown, /* 0.8.7 */
+    .domainShutdownFlags = vmwareDomainShutdownFlags, /* 0.9.10 */
     .domainReboot = vmwareDomainReboot, /* 0.8.7 */
     .domainDestroy = vmwareDomainShutdown, /* 0.8.7 */
     .domainDestroyFlags = vmwareDomainShutdownFlags, /* 0.9.4 */
index 520ec03a846e6e3cc74b24759b86c3b343934ab2..12d7eb0655e1c0f13126bfb8a9c9292889f35108 100644 (file)
@@ -851,20 +851,29 @@ xenUnifiedDomainResume (virDomainPtr dom)
 }
 
 static int
-xenUnifiedDomainShutdown (virDomainPtr dom)
+xenUnifiedDomainShutdownFlags(virDomainPtr dom,
+                              unsigned int flags)
 {
     GET_PRIVATE(dom->conn);
     int i;
 
+    virCheckFlags(0, -1);
+
     for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
         if (priv->opened[i] &&
             drivers[i]->xenDomainShutdown &&
-            drivers[i]->xenDomainShutdown (dom) == 0)
+            drivers[i]->xenDomainShutdown(dom) == 0)
             return 0;
 
     return -1;
 }
 
+static int
+xenUnifiedDomainShutdown(virDomainPtr dom)
+{
+    return xenUnifiedDomainShutdownFlags(dom, 0);
+}
+
 static int
 xenUnifiedDomainReboot (virDomainPtr dom, unsigned int flags)
 {
@@ -2187,6 +2196,7 @@ static virDriver xenUnifiedDriver = {
     .domainSuspend = xenUnifiedDomainSuspend, /* 0.0.3 */
     .domainResume = xenUnifiedDomainResume, /* 0.0.3 */
     .domainShutdown = xenUnifiedDomainShutdown, /* 0.0.3 */
+    .domainShutdownFlags = xenUnifiedDomainShutdownFlags, /* 0.9.10 */
     .domainReboot = xenUnifiedDomainReboot, /* 0.1.0 */
     .domainDestroy = xenUnifiedDomainDestroy, /* 0.0.3 */
     .domainDestroyFlags = xenUnifiedDomainDestroyFlags, /* 0.9.4 */
index 78137d48a074ace8b85db3be61ed7b854808941e..68017bcae9c4e0077fd17a70b968537b6ffbd694 100644 (file)
@@ -783,12 +783,15 @@ xenapiDomainResume (virDomainPtr dom)
  * Returns 0 on success or -1 in case of error
  */
 static int
-xenapiDomainShutdown (virDomainPtr dom)
+xenapiDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
 {
     /* vm.clean_shutdown */
     xen_vm vm;
     xen_vm_set *vms;
     xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session;
+
+    virCheckFlags(0, -1);
+
     if (xen_vm_get_by_name_label(session, &vms, dom->name) && vms->size > 0) {
         if (vms->size != 1) {
             xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,
@@ -811,6 +814,12 @@ xenapiDomainShutdown (virDomainPtr dom)
     return -1;
 }
 
+static int
+xenapiDomainShutdown(virDomainPtr dom)
+{
+    return xenapiDomainShutdownFlags(dom, 0);
+}
+
 /*
  * xenapiDomainReboot
  *
@@ -1928,6 +1937,7 @@ static virDriver xenapiDriver = {
     .domainSuspend = xenapiDomainSuspend, /* 0.8.0 */
     .domainResume = xenapiDomainResume, /* 0.8.0 */
     .domainShutdown = xenapiDomainShutdown, /* 0.8.0 */
+    .domainShutdownFlags = xenapiDomainShutdownFlags, /* 0.9.10 */
     .domainReboot = xenapiDomainReboot, /* 0.8.0 */
     .domainDestroy = xenapiDomainDestroy, /* 0.8.0 */
     .domainDestroyFlags = xenapiDomainDestroyFlags, /* 0.9.4 */