[libvirt] [RFC v3] Export KVM Host Power Management capabilities

Srivatsa S. Bhat srivatsa.bhat at linux.vnet.ibm.com
Mon Aug 8 15:18:48 UTC 2011


This patch exports KVM Host Power Management capabilities as XML so that
higher-level systems management software can make use of these features
available in the host.

The script "pm-is-supported" (from pm-utils package) is run to discover if
Suspend-to-RAM (S3) or Suspend-to-Disk (S4) is supported by the host.
If either of them are supported, then a new tag "<power_management>" is
introduced in the XML under the <host> tag.

Eg: When the host supports both S3 and S4, the XML looks like this:

<capabilities>

  <host>
    <uuid>dc699581-48a2-11cb-b8a8-9a0265a79bbe</uuid>
    <cpu>
      <arch>i686</arch>
      <model>coreduo</model>
      <vendor>Intel</vendor>
      <topology sockets='1' cores='2' threads='1'/>
      <feature name='xtpr'/>
      <feature name='tm2'/>
      <feature name='est'/>
      <feature name='vmx'/>
      <feature name='pbe'/>
      <feature name='tm'/>
      <feature name='ht'/>
      <feature name='ss'/>
      <feature name='acpi'/>
      <feature name='ds'/>
    </cpu>
    <power_management>         <<<=== New host power management features
      <S3/>
      <S4/>
    </power_management>
    <migration_features>
      <live/>
      <uri_transports>
        <uri_transport>tcp</uri_transport>
      </uri_transports>
    </migration_features>
  </host>
     .
     .
     .

However in case the query to check for power management features succeeded,
but the host does not support any such feature, then the XML will contain
an empty <power_management/> tag. In the event that the PM query itself
failed, the XML will not contain any "power_management" tag.


Open issues:
-----------
1. Design new APIs in libvirt to actually exploit the host power management
   features instead of relying on external programs. This was discussed in
   [4].
2. Decide on whether to include "pm-utils" package in the libvirt.spec
   file considering the fact that the package name (pm-utils) may differ
   from one Linux distribution to another.


Please let me know your comments and feedback.


Changelog:
---------
v1: The idea of exporting host power management capabilities through
    libvirt was discussed in [1]. The choice to name the new tag as
    "power_management" was discussed in [2].

v2: A working implementation was presented for review in [3].


References:
----------
[1] Exporting KVM host power saving capabilities through libvirt
    http://thread.gmane.org/gmane.comp.emulators.libvirt/40886

[2] http://article.gmane.org/gmane.comp.emulators.libvirt/41688

[3] http://www.redhat.com/archives/libvir-list/2011-August/msg00238.html

[4] http://www.redhat.com/archives/libvir-list/2011-August/msg00248.html

Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat at linux.vnet.ibm.com>
---

 docs/formatcaps.html.in      |   19 ++++++++++---
 docs/schemas/capability.rng  |   23 ++++++++++++++++
 include/libvirt/virterror.h  |    1 +
 src/conf/capabilities.c      |   50 ++++++++++++++++++++++++++++++++++
 src/conf/capabilities.h      |    8 ++++++
 src/libvirt_private.syms     |    2 +
 src/qemu/qemu_capabilities.c |   27 +++++++++++++++++++
 src/util/util.c              |   61 ++++++++++++++++++++++++++++++++++++++++++
 src/util/util.h              |   14 ++++++++++
 src/util/virterror.c         |    3 ++
 10 files changed, 203 insertions(+), 5 deletions(-)

diff --git a/docs/formatcaps.html.in b/docs/formatcaps.html.in
index a4297ce..ce6f9a6 100644
--- a/docs/formatcaps.html.in
+++ b/docs/formatcaps.html.in
@@ -28,6 +28,10 @@ BIOS you will see</p>
       <feature name='xtpr'/>
       ...
     </cpu>
+    <power_management>
+      <S3/>
+      <S4/>
+    <power_management/>
   </host></span>
 
   <!-- xen-3.0-x86_64 -->
@@ -61,11 +65,16 @@ BIOS you will see</p>
   ...
 </capabilities></pre>
         <p>The first block (in red) indicates the host hardware capabilities, currently
-it is limited to the CPU properties but other information may be available,
-it shows the CPU architecture, topology, model name, and additional features
-which are not included in the model but the CPU provides them. Features of the
-chip are shown within the feature block (the block is similar to what you will
-find in a Xen fully virtualized domain description).</p>
+it is limited to the CPU properties and the power management features of
+the host platform, but other information may be available, it shows the CPU architecture,
+topology, model name, and additional features which are not included in the model but the
+CPU provides them. Features of the chip are shown within the feature block (the block is
+similar to what you will find in a Xen fully virtualized domain description). Further,
+the power management features supported by the host are shown, such as Suspend-to-RAM (S3)
+and Suspend-to-Disk (S4). In case the query for power management features succeeded but the
+host does not support any such feature, then an empty <power_management/>
+tag will be shown. Otherwise, if the query itself failed, no such tag will
+be displayed (i.e., there will not be any power_management block or empty tag in the XML).</p>
         <p>The second block (in blue) indicates the paravirtualization support of the
 Xen support, you will see the os_type of xen to indicate a paravirtual
 kernel, then architecture information and potential features.</p>
diff --git a/docs/schemas/capability.rng b/docs/schemas/capability.rng
index 99b4a9a..930374c 100644
--- a/docs/schemas/capability.rng
+++ b/docs/schemas/capability.rng
@@ -35,6 +35,9 @@
         </optional>
       </element>
       <optional>
+        <ref name='power_management'/>
+      </optional>
+      <optional>
         <ref name='migration'/>
       </optional>
       <optional>
@@ -105,6 +108,26 @@
     </zeroOrMore>
   </define>
 
+  <define name='power_management'>
+    <choice>
+      <element name='power_management'>
+        <optional>
+          <element name='S3'>
+            <empty/>
+          </element>
+        </optional>
+        <optional>
+          <element name='S4'>
+            <empty/>
+          </element>
+        </optional>
+      </element>
+      <element name='power_management'>
+        <empty/>
+      </element>
+    </choice>
+  </define>
+
   <define name='migration'>
     <element name='migration_features'>
       <optional>
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 9cac437..a831c73 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -82,6 +82,7 @@ typedef enum {
     VIR_FROM_EVENT = 40,       /* Error from event loop impl */
     VIR_FROM_LIBXL = 41,	/* Error from libxenlight driver */
     VIR_FROM_LOCKING = 42,      /* Error from lock manager */
+    VIR_FROM_CAPABILITIES = 43, /* Error from capabilities */
 } virErrorDomain;
 
 
diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c
index 2f243ae..d39a3f9 100644
--- a/src/conf/capabilities.c
+++ b/src/conf/capabilities.c
@@ -29,6 +29,13 @@
 #include "util.h"
 #include "uuid.h"
 #include "cpu_conf.h"
+#include "virterror_internal.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_CAPABILITIES
+
+VIR_ENUM_IMPL(virHostPMCapability, VIR_HOST_PM_LAST,
+              "S3", "S4")
 
 /**
  * virCapabilitiesNew:
@@ -166,6 +173,8 @@ virCapabilitiesFree(virCapsPtr caps) {
 
     virCapabilitiesFreeNUMAInfo(caps);
 
+    VIR_FREE(caps->host.powerMgmt);
+
     for (i = 0 ; i < caps->host.nmigrateTrans ; i++)
         VIR_FREE(caps->host.migrateTrans[i]);
     VIR_FREE(caps->host.migrateTrans);
@@ -201,6 +210,28 @@ virCapabilitiesAddHostFeature(virCapsPtr caps,
     return 0;
 }
 
+/**
+ * virCapabilitiesAddHostPowerManagement:
+ * @caps: capabilities to extend
+ * @feature: the power management feature to be added
+ *
+ * Registers a new host power management feature, eg: 'S3' or 'S4'
+ */
+int
+virCapabilitiesAddHostPowerManagement(virCapsPtr caps,
+                                      int feature)
+{
+    if(VIR_RESIZE_N(caps->host.powerMgmt, caps->host.npowerMgmt_max,
+                   caps->host.npowerMgmt, 1) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    caps->host.powerMgmt[caps->host.npowerMgmt] = feature;
+    caps->host.npowerMgmt++;
+
+    return 0;
+}
 
 /**
  * virCapabilitiesAddHostMigrateTransport:
@@ -686,6 +717,25 @@ virCapabilitiesFormatXML(virCapsPtr caps)
 
     virBufferAddLit(&xml, "    </cpu>\n");
 
+    if(caps->host.isPMQuerySuccess) {
+        if(caps->host.npowerMgmt) {
+            /* The PM Query was successful and the host supports
+             * some PM features.
+             */
+            virBufferAddLit(&xml, "    <power_management>\n");
+            for (i = 0; i < caps->host.npowerMgmt ; i++) {
+                virBufferAsprintf(&xml, "      <%s/>\n",
+                    virHostPMCapabilityTypeToString(caps->host.powerMgmt[i]));
+            }
+            virBufferAddLit(&xml, "    </power_management>\n");
+        } else {
+            /* The PM Query was successful but the host does not
+             * support any PM feature.
+             */
+            virBufferAddLit(&xml, "    <power_management/>\n");
+        }
+    }
+
     if (caps->host.offlineMigrate) {
         virBufferAddLit(&xml, "    <migration_features>\n");
         if (caps->host.liveMigrate)
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
index e2fa1d6..afbf732 100644
--- a/src/conf/capabilities.h
+++ b/src/conf/capabilities.h
@@ -105,6 +105,10 @@ struct _virCapsHost {
     size_t nfeatures;
     size_t nfeatures_max;
     char **features;
+    bool isPMQuerySuccess;
+    size_t npowerMgmt;
+    size_t npowerMgmt_max;
+    int *powerMgmt;    /* enum virHostPMCapability */
     int offlineMigrate;
     int liveMigrate;
     size_t nmigrateTrans;
@@ -186,6 +190,10 @@ virCapabilitiesAddHostFeature(virCapsPtr caps,
                               const char *name);
 
 extern int
+virCapabilitiesAddHostPowerManagement(virCapsPtr caps,
+                                      int feature);
+
+extern int
 virCapabilitiesAddHostMigrateTransport(virCapsPtr caps,
                                        const char *name);
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 830222b..5754fdd 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -41,6 +41,7 @@ virCapabilitiesAddGuestFeature;
 virCapabilitiesAddHostFeature;
 virCapabilitiesAddHostMigrateTransport;
 virCapabilitiesAddHostNUMACell;
+virCapabilitiesAddHostPowerManagement;
 virCapabilitiesAllocMachines;
 virCapabilitiesDefaultGuestArch;
 virCapabilitiesDefaultGuestEmulator;
@@ -1025,6 +1026,7 @@ safezero;
 virArgvToString;
 virAsprintf;
 virBuildPathInternal;
+virCheckPMCapability;
 virDirCreate;
 virEmitXMLWarning;
 virEnumFromString;
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 3f36212..f3d0c0a 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -794,6 +794,7 @@ virCapsPtr qemuCapsInit(virCapsPtr old_caps)
     struct utsname utsname;
     virCapsPtr caps;
     int i;
+    int status = -1;
     char *xenner = NULL;
 
     /* Really, this never fails - look at the man-page. */
@@ -824,6 +825,32 @@ virCapsPtr qemuCapsInit(virCapsPtr old_caps)
         old_caps->host.cpu = NULL;
     }
 
+    /* Add the power management features of the host */
+
+    /* Check for Suspend-to-RAM support (S3) */
+    status = virCheckPMCapability(VIR_HOST_PM_S3);
+    if(status < 0) {
+        caps->host.isPMQuerySuccess = false;
+        VIR_WARN("Failed to get host power management features");
+    } else {
+        /* The PM Query succeeded */
+        caps->host.isPMQuerySuccess = true;
+        if(status == 1)    /* S3 is supported */
+            virCapabilitiesAddHostPowerManagement(caps, VIR_HOST_PM_S3);
+    }
+
+    /* Check for Suspend-to-Disk support (S4) */
+    status = virCheckPMCapability(VIR_HOST_PM_S4);
+    if(status < 0) {
+        caps->host.isPMQuerySuccess = false;
+        VIR_WARN("Failed to get host power management features");
+    } else {
+        /* The PM Query succeeded */
+        caps->host.isPMQuerySuccess = true;
+        if(status == 1)    /* S4 is supported */
+            virCapabilitiesAddHostPowerManagement(caps, VIR_HOST_PM_S4);
+    }
+
     virCapabilitiesAddHostMigrateTransport(caps,
                                            "tcp");
 
diff --git a/src/util/util.c b/src/util/util.c
index 03a9e1a..489c4d6 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -2641,3 +2641,64 @@ or other application using the libvirt API.\n\
 
     return 0;
 }
+
+/**
+ * Check the Power Management Capabilities of the host system.
+ * The script 'pm-is-supported' (from the pm-utils package) is run
+ * to find out if the capability is supported by the host.
+ *
+ * @capability: capability to check for
+ * VIR_HOST_PM_S3: Check for Suspend-to-RAM support
+ * VIR_HOST_PM_S4: Check for Suspend-to-Disk support
+ *
+ * Return values:
+ * 1 if the capability is supported.
+ * 0 if the query was successful but the capability is
+ *   not supported by the host.
+ * -1 on error like 'pm-is-supported' is not found.
+ */
+int
+virCheckPMCapability(int capability)
+{
+
+    char *path = NULL;
+    int status = -1;
+    int ret = -1;
+    virCommandPtr cmd;
+
+    if((path = virFindFileInPath("pm-is-supported")) == NULL) {
+        virUtilError(VIR_ERR_INTERNAL_ERROR,
+                     "%s", _("Failed to get the path of pm-is-supported"));
+        return -1;
+    }
+
+    cmd = virCommandNew(path);
+    switch(capability) {
+    case VIR_HOST_PM_S3:
+        /* Check support for suspend (S3) */
+        virCommandAddArg(cmd, "--suspend");
+        break;
+
+    case VIR_HOST_PM_S4:
+        /* Check support for hibernation (S4) */
+        virCommandAddArg(cmd, "--hibernate");
+        break;
+
+    default:
+        goto cleanup;
+    }
+
+    if(virCommandRun(cmd, &status) < 0)
+        goto cleanup;
+
+    /* Check return code of command == 0 for success
+     * (i.e., the PM capability is supported)
+     */
+    ret = (status == 0) ? 1 : 0;
+
+cleanup:
+    virCommandFree(cmd);
+    VIR_FREE(path);
+    return ret;
+}
+
diff --git a/src/util/util.h b/src/util/util.h
index af8b15d..dfb8c1a 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -272,4 +272,18 @@ bool virIsDevMapperDevice(const char *devname) ATTRIBUTE_NONNULL(1);
 int virEmitXMLWarning(int fd,
                       const char *name,
                       const char *cmd) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+
+/* Power Management Capabilities of the host system */
+
+enum virHostPMCapability {
+    VIR_HOST_PM_S3,  /* Suspend-to-RAM */
+    VIR_HOST_PM_S4,  /* Suspend-to-Disk */
+
+    VIR_HOST_PM_LAST
+};
+
+VIR_ENUM_DECL(virHostPMCapability)
+
+int virCheckPMCapability(int capability);
+
 #endif /* __VIR_UTIL_H__ */
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 9a27feb..26d6011 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -148,6 +148,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
         case VIR_FROM_CPU:
             dom = "CPU ";
             break;
+        case VIR_FROM_CAPABILITIES:
+            dom = "Capabilities ";
+            break;
         case VIR_FROM_NWFILTER:
             dom = "Network Filter ";
             break;




More information about the libvir-list mailing list