mirror of https://gitee.com/openkylin/libvirt.git
XML definitions for guest NUMA and parsing routines
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@linux.vnet.ibm.com>
This commit is contained in:
parent
c74b97156f
commit
5f7b71b413
1
AUTHORS
1
AUTHORS
|
@ -205,6 +205,7 @@ Patches have also been contributed by:
|
||||||
Patrice LACHANCE <patlachance@gmail.com>
|
Patrice LACHANCE <patlachance@gmail.com>
|
||||||
Eli Qiao <taget@linux.vnet.ibm.com>
|
Eli Qiao <taget@linux.vnet.ibm.com>
|
||||||
Michael Wood <esiotrot@gmail.com>
|
Michael Wood <esiotrot@gmail.com>
|
||||||
|
Bharata B Rao <bharata@linux.vnet.ibm.com>
|
||||||
|
|
||||||
[....send patches to get your name here....]
|
[....send patches to get your name here....]
|
||||||
|
|
||||||
|
|
|
@ -628,6 +628,35 @@
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Guest NUMA topology can be specifed using the <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>
|
<h3><a name="elementsLifecycle">Lifecycle control</a></h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -2297,7 +2297,16 @@
|
||||||
<define name="cpu">
|
<define name="cpu">
|
||||||
<element name="cpu">
|
<element name="cpu">
|
||||||
<choice>
|
<choice>
|
||||||
<ref name="cpuTopology"/>
|
<group>
|
||||||
|
<interleave>
|
||||||
|
<optional>
|
||||||
|
<ref name="cpuTopology"/>
|
||||||
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<ref name="cpuNuma"/>
|
||||||
|
</optional>
|
||||||
|
</interleave>
|
||||||
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<ref name="cpuMatch"/>
|
<ref name="cpuMatch"/>
|
||||||
<interleave>
|
<interleave>
|
||||||
|
@ -2311,6 +2320,9 @@
|
||||||
<zeroOrMore>
|
<zeroOrMore>
|
||||||
<ref name="cpuFeature"/>
|
<ref name="cpuFeature"/>
|
||||||
</zeroOrMore>
|
</zeroOrMore>
|
||||||
|
<optional>
|
||||||
|
<ref name="cpuNuma"/>
|
||||||
|
</optional>
|
||||||
</interleave>
|
</interleave>
|
||||||
</group>
|
</group>
|
||||||
</choice>
|
</choice>
|
||||||
|
@ -2371,6 +2383,25 @@
|
||||||
</element>
|
</element>
|
||||||
</define>
|
</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:
|
System information specification:
|
||||||
Placeholder for system specific informations likes the ones
|
Placeholder for system specific informations likes the ones
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "buf.h"
|
#include "buf.h"
|
||||||
#include "cpu_conf.h"
|
#include "cpu_conf.h"
|
||||||
|
#include "domain_conf.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_CPU
|
#define VIR_FROM_THIS VIR_FROM_CPU
|
||||||
|
|
||||||
|
@ -67,6 +68,12 @@ virCPUDefFree(virCPUDefPtr def)
|
||||||
VIR_FREE(def->features[i].name);
|
VIR_FREE(def->features[i].name);
|
||||||
VIR_FREE(def->features);
|
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);
|
VIR_FREE(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +116,6 @@ no_memory:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virCPUDefPtr
|
virCPUDefPtr
|
||||||
virCPUDefParseXML(const xmlNodePtr node,
|
virCPUDefParseXML(const xmlNodePtr node,
|
||||||
xmlXPathContextPtr ctxt,
|
xmlXPathContextPtr ctxt,
|
||||||
|
@ -289,9 +295,75 @@ virCPUDefParseXML(const xmlNodePtr node,
|
||||||
def->features[i].policy = policy;
|
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:
|
cleanup:
|
||||||
VIR_FREE(nodes);
|
VIR_FREE(nodes);
|
||||||
|
|
||||||
return def;
|
return def;
|
||||||
|
|
||||||
no_memory:
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,15 @@ struct _virCPUFeatureDef {
|
||||||
int policy; /* enum virCPUFeaturePolicy */
|
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 struct _virCPUDef virCPUDef;
|
||||||
typedef virCPUDef *virCPUDefPtr;
|
typedef virCPUDef *virCPUDefPtr;
|
||||||
struct _virCPUDef {
|
struct _virCPUDef {
|
||||||
|
@ -81,6 +90,10 @@ struct _virCPUDef {
|
||||||
size_t nfeatures;
|
size_t nfeatures;
|
||||||
size_t nfeatures_max;
|
size_t nfeatures_max;
|
||||||
virCPUFeatureDefPtr features;
|
virCPUFeatureDefPtr features;
|
||||||
|
size_t ncells;
|
||||||
|
size_t ncells_max;
|
||||||
|
virCellDefPtr cells;
|
||||||
|
unsigned int cells_cpus;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7572,6 +7572,13 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
||||||
|
|
||||||
if (def->cpu == NULL)
|
if (def->cpu == NULL)
|
||||||
goto error;
|
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) {
|
if ((node = virXPathNode("./sysinfo[1]", ctxt)) != NULL) {
|
||||||
|
|
Loading…
Reference in New Issue