[libvirt] [PATCH 1/3] XML definitions for guest NUMA

Bharata B Rao bharata at linux.vnet.ibm.com
Sun Nov 6 13:57:22 UTC 2011


XML definitions for guest NUMA and parsing routines.

From: Bharata B Rao <bharata at 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' mems='512000'/>
                <cell cpus='8-15' mems='512000'/>
        </numa>
        ...
</cpu>

Signed-off-by: Bharata B Rao <bharata at linux.vnet.ibm.com>
---

 docs/formatdomain.html.in     |   32 +++++++++++++++++++++
 docs/schemas/domaincommon.rng |   32 +++++++++++++++++++++
 src/conf/cpu_conf.c           |   62 +++++++++++++++++++++++++++++++++++++++++
 src/conf/cpu_conf.h           |   12 ++++++++
 src/conf/domain_conf.c        |    7 +++++
 5 files changed, 145 insertions(+), 0 deletions(-)


diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index c3e7752..8d070ca 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -628,6 +628,38 @@
       </dd>
     </dl>
 
+    <p>
+      Guest NUMA topology can be specifed using  <code>numa</code> element.
+      <span class="since">Since X.X.X</span>
+    </p>
+
+<pre>
+  ...
+  <cpu>
+    ...
+    <numa>
+      <cell cpus='0-3' mems='512000'/>
+      <cell cpus='4-7' mems='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>mems</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 translates to <code>-numa</code> command
+      line option for QEMU/KVM. For the above example, the following QEMU
+      command line option is generated:
+      <code>-numa node,nodeid=0,cpus=0-3,mems=512000 -numa node,nodeid=1,cpus=4-7,mems=512000</code>
+    </p>
+
     <h3><a name="elementsLifecycle">Lifecycle control</a></h3>
 
     <p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index b6f858e..b09060a 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2311,6 +2311,9 @@
             <zeroOrMore>
               <ref name="cpuFeature"/>
             </zeroOrMore>
+            <optional>
+              <ref name="cpuNuma"/>
+            </optional>
           </interleave>
         </group>
       </choice>
@@ -2371,6 +2374,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="Cellcpus"/>
+      </attribute>
+      <attribute name="mems">
+        <ref name="Cellmems"/>
+      </attribute>
+    </element>
+  </define>
+
   <!--
       System information specification:
        Placeholder for system specific informations likes the ones
@@ -2745,4 +2767,14 @@
       <param name="pattern">[a-zA-Z0-9_\.:]+</param>
     </data>
   </define>
+  <define name="Cellcpus">
+    <data type="string">
+      <param name="pattern">([0-9]+(-[0-9]+)?|\^[0-9]+)(,([0-9]+(-[0-9]+)?|\^[0-9]+))*</param>
+    </data>
+  </define>
+  <define name="Cellmems">
+    <data type="unsignedInt">
+      <param name="pattern">[0-9]+</param>
+    </data>
+  </define>
 </grammar>
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index 41e997e..e55897f 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,10 @@ 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);
+
     VIR_FREE(def);
 }
 
@@ -109,6 +114,19 @@ no_memory:
     return NULL;
 }
 
+static int
+virCPUDefNumaCPUs(virCPUDefPtr def)
+{
+    int i, j, ncpus = 0;
+
+    for (i = 0; i < def->ncells; i++) {
+        for (j = 0; j < VIR_DOMAIN_CPUMASK_LEN; j++) {
+            if (def->cells[i].cpumask[j])
+                ncpus++;
+        }
+    }
+    return ncpus;
+}
 
 virCPUDefPtr
 virCPUDefParseXML(const xmlNodePtr node,
@@ -289,6 +307,50 @@ 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 || 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;
+            int cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
+            unsigned long ul;
+            int ret;
+
+            def->cells[i].cellid = i;
+            cpus = virXMLPropString(nodes[i], "cpus");
+
+            if (VIR_ALLOC_N(def->cells[i].cpumask, cpumasklen) < 0)
+                goto no_memory;
+
+            if (virDomainCpuSetParse((const char **)&cpus,
+                                 0, def->cells[i].cpumask,
+                                 cpumasklen) < 0)
+                goto error;
+
+            ret = virXPathULong("string(./numa[1]/cell/@mems)",
+                            ctxt, &ul);
+            if (ret < 0) {
+                virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+                    "%s", _("Missing 'mems' attribute in NUMA topology"));
+                goto error;
+            }
+            def->cells[i].mem = (unsigned int) ul;
+        }
+        def->cells_cpus = virCPUDefNumaCPUs(def);
+    }
+
 cleanup:
     VIR_FREE(nodes);
 
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index 4406cba..bf4270a 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -67,6 +67,14 @@ 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 */
+   unsigned int mem;	/* Node memory */
+};
+
 typedef struct _virCPUDef virCPUDef;
 typedef virCPUDef *virCPUDefPtr;
 struct _virCPUDef {
@@ -81,6 +89,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 6e2d421..02fc1e7 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -7511,6 +7511,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) {




More information about the libvir-list mailing list