[libvirt] [RFC PATCH 2/2] Routines to parse <numa> ... </numa>

Bharata B Rao bharata at linux.vnet.ibm.com
Mon Oct 3 10:01:35 UTC 2011


Routines to parse <numa> ... </numa>

From: Bharata B Rao <bharata at linux.vnet.ibm.com>

This patch adds routines to parse guest numa
XML configuration for qemu.

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

 src/conf/cpu_conf.c     |   48 ++++++++++++++++++++++++
 src/conf/cpu_conf.h     |   11 ++++++
 src/qemu/qemu_command.c |   94 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 153 insertions(+), 0 deletions(-)


diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index 5cecda2..c520025 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->nnodes ; i++)
+        VIR_FREE(def->nodes[i].cpumask);
+    VIR_FREE(def->nodes);
+
     VIR_FREE(def);
 }
 
@@ -289,6 +294,49 @@ virCPUDefParseXML(const xmlNodePtr node,
         def->features[i].policy = policy;
     }
 
+    if (virXPathNode("./numa[1]", ctxt)) {
+        VIR_FREE(nodes);
+        n = virXPathNodeSet("./numa[1]/node", ctxt, &nodes);
+        if (n < 0 || n == 0) {
+            virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+                    "%s", _("NUMA topology defined without NUMA nodes"));
+            goto error;
+        }
+
+        if (VIR_RESIZE_N(def->nodes, def->nnodes_max,
+                         def->nnodes, n) < 0)
+            goto no_memory;
+
+        def->nnodes = n;
+
+        for (i = 0 ; i < n ; i++) {
+            char *cpus;
+            int cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
+            unsigned long ul;
+            int ret;
+
+            def->nodes[i].nodeid = i;
+            cpus = virXMLPropString(nodes[i], "cpus");
+
+            if (VIR_ALLOC_N(def->nodes[i].cpumask, cpumasklen) < 0)
+                goto no_memory;
+
+            if (virDomainCpuSetParse((const char **)&cpus,
+                                 0, def->nodes[i].cpumask,
+                                 cpumasklen) < 0)
+                goto error;
+
+            ret = virXPathULong("string(./numa[1]/node/@mems)",
+                            ctxt, &ul);
+            if (ret < 0) {
+                virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+                    "%s", _("Missing 'mems' attribute in NUMA topology"));
+                goto error;
+            }
+            def->nodes[i].mem = (unsigned int) ul;
+        }
+    }
+
 cleanup:
     VIR_FREE(nodes);
 
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index 57b85e1..266ec81 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 _virNodeDef virNodeDef;
+typedef virNodeDef *virNodeDefPtr;
+struct _virNodeDef {
+   int nodeid;
+   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,9 @@ struct _virCPUDef {
     size_t nfeatures;
     size_t nfeatures_max;
     virCPUFeatureDefPtr features;
+    size_t nnodes;
+    size_t nnodes_max;
+    virNodeDefPtr nodes;
 };
 
 
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index a13ba71..5b4345e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3153,6 +3153,97 @@ qemuBuildSmpArgStr(const virDomainDefPtr def,
     return virBufferContentAndReset(&buf);
 }
 
+static char *
+virParseNodeCPUs(char *cpumask)
+{
+    int i, first, last, ret;
+    char *cpus, *ptr;
+    int cpuSet = 0;
+    int remaining = 128;
+
+    if (VIR_ALLOC_N(cpus, remaining) < 0)
+        return NULL;
+
+    ptr = cpus;
+
+    for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) {
+        if (cpumask[i]) {
+            if (cpuSet)
+                last = i;
+            else {
+                first = last = i;
+                cpuSet = 1;
+            }
+        } else {
+            if (!cpuSet)
+                continue;
+            if (first == last)
+                ret = snprintf(ptr, remaining, "%d,", first);
+            else
+                ret = snprintf(ptr, remaining, "%d-%d,", first, last);
+            if (ret > remaining)
+                goto error;
+            ptr += ret;
+            remaining -= ret;
+            cpuSet = 0;
+	}
+    }
+
+    if (cpuSet) {
+        if (first == last)
+            ret = snprintf(ptr, remaining, "%d,", first);
+        else
+            ret = snprintf(ptr, remaining, "%d-%d,", first, last);
+        if (ret > remaining)
+            goto error;
+    }
+
+    /* Remove the trailing comma */
+    *(--ptr) = '\0';
+    return cpus;
+
+error:
+    VIR_FREE(cpus);
+    return NULL;
+}
+
+static int
+qemuBuildNumaArgStr(const virDomainDefPtr def, virCommandPtr cmd)
+{
+    int i;
+    char *cpus, *node;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    for (i = 0; i < def->cpu->nnodes; i++) {
+        virCommandAddArg(cmd, "-numa");
+        virBufferAsprintf(&buf, "%s", "node");
+        virBufferAsprintf(&buf, ",nodeid=%d", def->cpu->nodes[i].nodeid);
+
+        cpus = virParseNodeCPUs(def->cpu->nodes[i].cpumask);
+        if (!cpus)
+            goto error;
+
+        virBufferAsprintf(&buf, ",cpus=%s", cpus);
+        virBufferAsprintf(&buf, ",mems=%d", def->cpu->nodes[i].mem);
+
+        if (virBufferError(&buf)) {
+            VIR_FREE(cpus);
+            goto error;
+        }
+
+        node = virBufferContentAndReset(&buf);
+        virCommandAddArg(cmd, node);
+
+        VIR_FREE(cpus);
+        VIR_FREE(node);
+    }
+    return 0;
+
+error:
+    virBufferFreeAndReset(&buf);
+    virReportOOMError();
+    return -1;
+}
 
 /*
  * Constructs a argv suitable for launching qemu with config defined
@@ -3319,6 +3410,9 @@ qemuBuildCommandLine(virConnectPtr conn,
     virCommandAddArg(cmd, smp);
     VIR_FREE(smp);
 
+    if (def->cpu->nnodes && qemuBuildNumaArgStr(def, cmd))
+        goto error;
+
     if (qemuCapsGet(qemuCaps, QEMU_CAPS_NAME)) {
         virCommandAddArg(cmd, "-name");
         if (driver->setProcessName &&




More information about the libvir-list mailing list