[libvirt] [PATCH v2 1/2] XML definitions for guest NUMA and parsing routines

Bharata B Rao bharata at linux.vnet.ibm.com
Fri Nov 11 12:51:45 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' memory='512000'/>
                <cell cpus='8-15' memory='512000'/>
        </numa>
        ...
</cpu>

Signed-off-by: Bharata B Rao <bharata at 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) {




More information about the libvir-list mailing list