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 host does not support any power management feature,
then the XML will not contain the <power_management> tag.
The initial discussion about this patch was done in [1]. And the choice
to name the new tag as "power_management" was discussed in [2].
Please let me know your comments and feedback.
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
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat(a)linux.vnet.ibm.com>
---
src/conf/capabilities.c | 34 +++++++++++++++++++++++++++
src/conf/capabilities.h | 7 ++++++
src/libvirt_private.syms | 2 ++
src/qemu/qemu_capabilities.c | 10 ++++++++
src/util/util.c | 52 ++++++++++++++++++++++++++++++++++++++++++
src/util/util.h | 7 ++++++
6 files changed, 112 insertions(+), 0 deletions(-)
diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c
index 2f243ae..94423dc 100644
--- a/src/conf/capabilities.c
+++ b/src/conf/capabilities.c
@@ -166,6 +166,10 @@ virCapabilitiesFree(virCapsPtr caps) {
virCapabilitiesFreeNUMAInfo(caps);
+ for(i = 0; i < caps->host.npowerMgmt ; i++)
+ VIR_FREE(caps->host.powerMgmt[i]);
+ 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 +205,27 @@ virCapabilitiesAddHostFeature(virCapsPtr caps,
return 0;
}
+/**
+ * virCapabilitiesAddHostPowerManagement:
+ * @caps: capabilities to extend
+ * @name: name of power management feature
+ *
+ * Registers a new host power management feature, eg: 'S3' or 'S4'
+ */
+int
+virCapabilitiesAddHostPowerManagement(virCapsPtr caps,
+ const char *name)
+{
+ if(VIR_RESIZE_N(caps->host.powerMgmt, caps->host.npowerMgmt_max,
+ caps->host.npowerMgmt, 1) < 0)
+ return -1;
+
+ if((caps->host.powerMgmt[caps->host.npowerMgmt] = strdup(name)) == NULL)
+ return -1;
+ caps->host.npowerMgmt++;
+
+ return 0;
+}
/**
* virCapabilitiesAddHostMigrateTransport:
@@ -686,6 +711,15 @@ virCapabilitiesFormatXML(virCapsPtr caps)
virBufferAddLit(&xml, " </cpu>\n");
+ if(caps->host.npowerMgmt) {
+ virBufferAddLit(&xml, " <power_management>\n");
+ for (i = 0; i < caps->host.npowerMgmt ; i++) {
+ virBufferAsprintf(&xml, " <%s/>\n",
+ caps->host.powerMgmt[i]);
+ }
+ 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..eb6e561 100644
--- a/src/conf/capabilities.h
+++ b/src/conf/capabilities.h
@@ -105,6 +105,9 @@ struct _virCapsHost {
size_t nfeatures;
size_t nfeatures_max;
char **features;
+ size_t npowerMgmt;
+ size_t npowerMgmt_max;
+ char **powerMgmt;
int offlineMigrate;
int liveMigrate;
size_t nmigrateTrans;
@@ -186,6 +189,10 @@ virCapabilitiesAddHostFeature(virCapsPtr caps,
const char *name);
extern int
+virCapabilitiesAddHostPowerManagement(virCapsPtr caps,
+ const char *name);
+
+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..6e969a7 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -824,6 +824,16 @@ 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) */
+ if(virCheckPMCapability(HOST_PM_S3) == 0)
+ virCapabilitiesAddHostPowerManagement(caps, "S3");
+
+ /* Check for Suspend-to-Disk support (S4) */
+ if(virCheckPMCapability(HOST_PM_S4) == 0)
+ virCapabilitiesAddHostPowerManagement(caps, "S4");
+
virCapabilitiesAddHostMigrateTransport(caps,
"tcp");
diff --git a/src/util/util.c b/src/util/util.c
index 03a9e1a..9893597 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -2641,3 +2641,55 @@ 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
+ * HOST_PM_S3: Check for Suspend-to-RAM support
+ * HOST_PM_S4: Check for Suspend-to-Disk support
+ *
+ * Returns 0 if supported, -1 if not supported.
+ */
+int
+virCheckPMCapability(int capability)
+{
+
+ char *path = NULL;
+ int status = -1, ret = -1;
+ virCommandPtr cmd;
+
+ if((path = virFindFileInPath("pm-is-supported")) == NULL)
+ return -1;
+
+ cmd = virCommandNew(path);
+ switch(capability) {
+ case HOST_PM_S3:
+ /* Check support for suspend (S3) */
+ virCommandAddArg(cmd, "--suspend");
+ break;
+
+ case 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 */
+ if(status == 0)
+ ret = 0;
+
+cleanup:
+ virCommandFree(cmd);
+ VIR_FREE(path);
+ return ret;
+}
+
diff --git a/src/util/util.h b/src/util/util.h
index af8b15d..c428eb4 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -272,4 +272,11 @@ 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 */
+# define HOST_PM_S3 1 /* Suspend-to-RAM */
+# define HOST_PM_S4 2 /* Suspend-to-Disk */
+
+int virCheckPMCapability(int capability);
+
#endif /* __VIR_UTIL_H__ */