XML definitions for guest NUMA and parsing routines.
From: Bharata B Rao <bharata(a)linux.vnet.ibm.com>
This patch adds XML definitions for guest NUMA specification and contains
routines to parse the same. The guest NUMA specification looks like this:
<cpu>
...
<topology sockets='2' cores='4' threads='2'/>
<numa>
<cell cpus='0-7' memory='512000'/>
<cell cpus='8-15' memory='512000'/>
</numa>
...
</cpu>
Signed-off-by: Bharata B Rao <bharata(a)linux.vnet.ibm.com>
---
docs/formatdomain.html.in | 29 ++++++++++++++
docs/schemas/domaincommon.rng | 31 ++++++++++++++-
src/conf/cpu_conf.c | 86 ++++++++++++++++++++++++++++++++++++++++-
src/conf/cpu_conf.h | 13 ++++++
src/conf/domain_conf.c | 7 +++
5 files changed, 163 insertions(+), 3 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index cbad196..28a4edc 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -628,6 +628,35 @@
</dd>
</dl>
+ <p>
+ Guest NUMA topology can be specifed using <code>numa</code> element.
+ <span class="since">Since 0.9.8</span>
+ </p>
+
+<pre>
+ ...
+ <cpu>
+ ...
+ <numa>
+ <cell cpus='0-3' memory='512000'/>
+ <cell cpus='4-7' memory='512000'/>
+ </numa>
+ ...
+ </cpu>
+ ...</pre>
+
+ <p>
+ Each <code>cell</code> element specifies a NUMA cell or a NUMA node.
+ <code>cpus</code> specifies the CPU or range of CPUs that are part of
+ the node. <code>memory</code> specifies the node memory in kilobytes
+ (i.e. blocks of 1024 bytes). Each cell or node is assigned cellid
+ or nodeid in the increasing order starting from 0.
+ </p>
+
+ <p>
+ This guest NUMA specification is currently available only for QEMU/KVM.
+ </p>
+
<h3><a name="elementsLifecycle">Lifecycle
control</a></h3>
<p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index b6f858e..afcaccc 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2297,7 +2297,14 @@
<define name="cpu">
<element name="cpu">
<choice>
- <ref name="cpuTopology"/>
+ <group>
+ <optional>
+ <ref name="cpuTopology"/>
+ </optional>
+ <optional>
+ <ref name="cpuNuma"/>
+ </optional>
+ </group>
<group>
<ref name="cpuMatch"/>
<interleave>
@@ -2311,6 +2318,9 @@
<zeroOrMore>
<ref name="cpuFeature"/>
</zeroOrMore>
+ <optional>
+ <ref name="cpuNuma"/>
+ </optional>
</interleave>
</group>
</choice>
@@ -2371,6 +2381,25 @@
</element>
</define>
+ <define name="cpuNuma">
+ <element name="numa">
+ <oneOrMore>
+ <ref name="numaCell"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="numaCell">
+ <element name="cell">
+ <attribute name="cpus">
+ <ref name="cpuset"/>
+ </attribute>
+ <attribute name="memory">
+ <ref name="memoryKB"/>
+ </attribute>
+ </element>
+ </define>
+
<!--
System information specification:
Placeholder for system specific informations likes the ones
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index 41e997e..4aabe98 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -28,6 +28,7 @@
#include "util.h"
#include "buf.h"
#include "cpu_conf.h"
+#include "domain_conf.h"
#define VIR_FROM_THIS VIR_FROM_CPU
@@ -67,6 +68,12 @@ virCPUDefFree(virCPUDefPtr def)
VIR_FREE(def->features[i].name);
VIR_FREE(def->features);
+ for (i = 0 ; i < def->ncells ; i++) {
+ VIR_FREE(def->cells[i].cpumask);
+ VIR_FREE(def->cells[i].cpustr);
+ }
+ VIR_FREE(def->cells);
+
VIR_FREE(def);
}
@@ -109,7 +116,6 @@ no_memory:
return NULL;
}
-
virCPUDefPtr
virCPUDefParseXML(const xmlNodePtr node,
xmlXPathContextPtr ctxt,
@@ -289,9 +295,75 @@ virCPUDefParseXML(const xmlNodePtr node,
def->features[i].policy = policy;
}
+ if (virXPathNode("./numa[1]", ctxt)) {
+ VIR_FREE(nodes);
+ n = virXPathNodeSet("./numa[1]/cell", ctxt, &nodes);
+ if (n <= 0) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("NUMA topology defined without NUMA
cells"));
+ goto error;
+ }
+
+ if (VIR_RESIZE_N(def->cells, def->ncells_max,
+ def->ncells, n) < 0)
+ goto no_memory;
+
+ def->ncells = n;
+
+ for (i = 0 ; i < n ; i++) {
+ char *cpus, *cpus_parse, *memory;
+ int cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
+ int ret, ncpus = 0;
+
+ def->cells[i].cellid = i;
+ cpus = cpus_parse = virXMLPropString(nodes[i], "cpus");
+ if (!cpus) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing 'cpus' attribute in NUMA
cell"));
+ goto error;
+ }
+
+ def->cells[i].cpustr = strdup(cpus);
+ if (!def->cells[i].cpustr) {
+ VIR_FREE(cpus);
+ goto no_memory;
+ }
+
+ if (VIR_ALLOC_N(def->cells[i].cpumask, cpumasklen) < 0) {
+ VIR_FREE(cpus);
+ goto no_memory;
+ }
+
+ ncpus = virDomainCpuSetParse((const char **)&cpus_parse,
+ 0, def->cells[i].cpumask, cpumasklen);
+ if (ncpus <= 0) {
+ VIR_FREE(cpus);
+ goto error;
+ }
+ def->cells_cpus += ncpus;
+
+ memory = virXMLPropString(nodes[i], "memory");
+ if (!memory) {
+ virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing 'memory' attribute in NUMA
cell"));
+ VIR_FREE(cpus);
+ goto error;
+ }
+
+ ret = virStrToLong_ui(memory, NULL, 10, &def->cells[i].mem);
+ if (ret == -1) {
+ VIR_FREE(cpus);
+ VIR_FREE(memory);
+ goto error;
+ }
+
+ VIR_FREE(cpus);
+ VIR_FREE(memory);
+ }
+ }
+
cleanup:
VIR_FREE(nodes);
-
return def;
no_memory:
@@ -414,6 +486,16 @@ virCPUDefFormatBuf(virBufferPtr buf,
}
}
+ if (def->ncells) {
+ virBufferAddLit(buf, "<numa>\n");
+ for (i = 0; i < def->ncells; i++) {
+ virBufferAddLit(buf, " <cell");
+ virBufferAsprintf(buf, " cpus='%s'",
def->cells[i].cpustr);
+ virBufferAsprintf(buf, " memory='%d'",
def->cells[i].mem);
+ virBufferAddLit(buf, "/>\n");
+ }
+ virBufferAddLit(buf, "</numa>\n");
+ }
return 0;
}
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index 4406cba..efff473 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -67,6 +67,15 @@ struct _virCPUFeatureDef {
int policy; /* enum virCPUFeaturePolicy */
};
+typedef struct _virCellDef virCellDef;
+typedef virCellDef *virCellDefPtr;
+struct _virCellDef {
+ int cellid;
+ char *cpumask; /* CPUs that are part of this node */
+ char *cpustr; /* CPUs stored in string form for dumpxml */
+ unsigned int mem; /* Node memory in kB */
+};
+
typedef struct _virCPUDef virCPUDef;
typedef virCPUDef *virCPUDefPtr;
struct _virCPUDef {
@@ -81,6 +90,10 @@ struct _virCPUDef {
size_t nfeatures;
size_t nfeatures_max;
virCPUFeatureDefPtr features;
+ size_t ncells;
+ size_t ncells_max;
+ virCellDefPtr cells;
+ unsigned int cells_cpus;
};
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index a85f837..1203119 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -7572,6 +7572,13 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
if (def->cpu == NULL)
goto error;
+
+ if (def->cpu->cells_cpus > def->maxvcpus) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Number of CPUs in <numa> exceeds
the"
+ " <vcpu> count"));
+ goto error;
+ }
}
if ((node = virXPathNode("./sysinfo[1]", ctxt)) != NULL) {