c1c534
From bc7971b29f6c152a9c20aa3cda9bd361dcb61f14 Mon Sep 17 00:00:00 2001
c1c534
Message-Id: <bc7971b29f6c152a9c20aa3cda9bd361dcb61f14@dist-git>
c1c534
From: Wim ten Have <wim.ten.have@oracle.com>
c1c534
Date: Mon, 4 Dec 2017 13:38:48 +0100
c1c534
Subject: [PATCH] xenconfig: add domxml conversions for xen-xl
c1c534
c1c534
https://bugzilla.redhat.com/show_bug.cgi?id=1454889
c1c534
c1c534
This patch converts NUMA configurations between the Xen libxl
c1c534
configuration file format and libvirt's XML format.
c1c534
c1c534
XML HVM domain on a 4 node (2 cores/socket) configuration:
c1c534
c1c534
  <cpu>
c1c534
    <numa>
c1c534
      <cell id='0' cpus='0-1' memory='2097152' unit='KiB'>
c1c534
        <distances>
c1c534
          <sibling id='0' value='10'/>
c1c534
          <sibling id='1' value='21'/>
c1c534
          <sibling id='2' value='31'/>
c1c534
          <sibling id='3' value='21'/>
c1c534
        </distances>
c1c534
      </cell>
c1c534
      <cell id='1' cpus='2-3' memory='2097152' unit='KiB'>
c1c534
        <distances>
c1c534
          <sibling id='0' value='21'/>
c1c534
          <sibling id='1' value='10'/>
c1c534
          <sibling id='2' value='21'/>
c1c534
          <sibling id='3' value='31'/>
c1c534
        </distances>
c1c534
      </cell>
c1c534
      <cell id='2' cpus='3-4' memory='2097152' unit='KiB'>
c1c534
        <distances>
c1c534
          <sibling id='0' value='31'/>
c1c534
          <sibling id='1' value='21'/>
c1c534
          <sibling id='2' value='10'/>
c1c534
          <sibling id='3' value='21'/>
c1c534
        </distances>
c1c534
      </cell>
c1c534
      <cell id='3' cpus='5-6' memory='2097152' unit='KiB'>
c1c534
        <distances>
c1c534
          <sibling id='0' value='21'/>
c1c534
          <sibling id='1' value='31'/>
c1c534
          <sibling id='2' value='21'/>
c1c534
          <sibling id='3' value='10'/>
c1c534
        </distances>
c1c534
      </cell>
c1c534
    </numa>
c1c534
  </cpu>
c1c534
c1c534
Xen xl.cfg domain configuration:
c1c534
c1c534
  vnuma = [["pnode=0","size=2048","vcpus=0-1","vdistances=10,21,31,21"],
c1c534
           ["pnode=1","size=2048","vcpus=2-3","vdistances=21,10,21,31"],
c1c534
           ["pnode=2","size=2048","vcpus=4-5","vdistances=31,21,10,21"],
c1c534
           ["pnode=3","size=2048","vcpus=6-7","vdistances=21,31,21,10"]]
c1c534
c1c534
If there is no XML <distances> description amongst the <cell> data the
c1c534
conversion schema from xml to native will generate 10 for local and 20
c1c534
for all remote instances.
c1c534
c1c534
Signed-off-by: Wim ten Have <wim.ten.have@oracle.com>
c1c534
Reviewed-by: Jim Fehlig <jfehlig@suse.com>
c1c534
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
c1c534
(cherry picked from commit 03d0959af3a72eb2aed47a1d2dcf8ccbb39d4b0e)
c1c534
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
c1c534
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c1c534
---
c1c534
 src/conf/numa_conf.c     | 137 +++++++++++++++++++
c1c534
 src/conf/numa_conf.h     |  25 ++++
c1c534
 src/libvirt_private.syms |   5 +
c1c534
 src/xenconfig/xen_xl.c   | 335 +++++++++++++++++++++++++++++++++++++++++++++++
c1c534
 4 files changed, 502 insertions(+)
c1c534
c1c534
diff --git a/src/conf/numa_conf.c b/src/conf/numa_conf.c
c1c534
index 5fbcc72041..7bba4120bd 100644
c1c534
--- a/src/conf/numa_conf.c
c1c534
+++ b/src/conf/numa_conf.c
c1c534
@@ -1114,6 +1114,132 @@ virDomainNumaGetNodeCount(virDomainNumaPtr numa)
c1c534
 }
c1c534
 
c1c534
 
c1c534
+size_t
c1c534
+virDomainNumaSetNodeCount(virDomainNumaPtr numa, size_t nmem_nodes)
c1c534
+{
c1c534
+    if (!nmem_nodes) {
c1c534
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
c1c534
+                       _("Cannot set an empty mem_nodes set"));
c1c534
+        return 0;
c1c534
+    }
c1c534
+
c1c534
+    if (numa->mem_nodes) {
c1c534
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
c1c534
+                       _("Cannot alter an existing mem_nodes set"));
c1c534
+        return 0;
c1c534
+    }
c1c534
+
c1c534
+    if (VIR_ALLOC_N(numa->mem_nodes, nmem_nodes) < 0)
c1c534
+        return 0;
c1c534
+
c1c534
+    numa->nmem_nodes = nmem_nodes;
c1c534
+
c1c534
+    return numa->nmem_nodes;
c1c534
+}
c1c534
+
c1c534
+size_t
c1c534
+virDomainNumaGetNodeDistance(virDomainNumaPtr numa,
c1c534
+                             size_t node,
c1c534
+                             size_t cellid)
c1c534
+{
c1c534
+    virDomainNumaDistancePtr distances = NULL;
c1c534
+
c1c534
+    if (node < numa->nmem_nodes)
c1c534
+        distances = numa->mem_nodes[node].distances;
c1c534
+
c1c534
+    /*
c1c534
+     * Present the configured distance value. If
c1c534
+     * out of range or not available set the platform
c1c534
+     * defined default for local and remote nodes.
c1c534
+     */
c1c534
+    if (!distances ||
c1c534
+        !distances[cellid].value ||
c1c534
+        !numa->mem_nodes[node].ndistances)
c1c534
+        return (node == cellid) ? LOCAL_DISTANCE : REMOTE_DISTANCE;
c1c534
+
c1c534
+    return distances[cellid].value;
c1c534
+}
c1c534
+
c1c534
+
c1c534
+int
c1c534
+virDomainNumaSetNodeDistance(virDomainNumaPtr numa,
c1c534
+                             size_t node,
c1c534
+                             size_t cellid,
c1c534
+                             unsigned int value)
c1c534
+{
c1c534
+    virDomainNumaDistancePtr distances;
c1c534
+
c1c534
+    if (node >= numa->nmem_nodes) {
c1c534
+        virReportError(VIR_ERR_INTERNAL_ERROR,
c1c534
+                       _("Argument 'node' %zu outranges "
c1c534
+                         "defined number of NUMA nodes"),
c1c534
+                       node);
c1c534
+        return -1;
c1c534
+    }
c1c534
+
c1c534
+    distances = numa->mem_nodes[node].distances;
c1c534
+    if (!distances ||
c1c534
+        cellid >= numa->mem_nodes[node].ndistances) {
c1c534
+        virReportError(VIR_ERR_XML_ERROR, "%s",
c1c534
+                       _("Arguments under memnode element do not "
c1c534
+                         "correspond with existing guest's NUMA cell"));
c1c534
+        return -1;
c1c534
+    }
c1c534
+
c1c534
+    /*
c1c534
+     * Advanced Configuration and Power Interface
c1c534
+     * Specification version 6.1. Chapter 5.2.17
c1c534
+     * System Locality Distance Information Table
c1c534
+     * ... Distance values of 0-9 are reserved.
c1c534
+     */
c1c534
+    if (value < LOCAL_DISTANCE ||
c1c534
+        value > UNREACHABLE) {
c1c534
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
c1c534
+                       _("Distance value of %d is not in valid range"),
c1c534
+                       value);
c1c534
+        return -1;
c1c534
+    }
c1c534
+
c1c534
+    if (value == LOCAL_DISTANCE && node != cellid) {
c1c534
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
c1c534
+                       _("Distance value %d under node %zu is "
c1c534
+                         "LOCAL_DISTANCE and should be set to 10"),
c1c534
+                       value, node);
c1c534
+        return -1;
c1c534
+    }
c1c534
+
c1c534
+    distances[cellid].cellid = cellid;
c1c534
+    distances[cellid].value = value;
c1c534
+
c1c534
+    return distances[cellid].value;
c1c534
+}
c1c534
+
c1c534
+
c1c534
+size_t
c1c534
+virDomainNumaSetNodeDistanceCount(virDomainNumaPtr numa,
c1c534
+                                  size_t node,
c1c534
+                                  size_t ndistances)
c1c534
+{
c1c534
+    virDomainNumaDistancePtr distances;
c1c534
+
c1c534
+    distances = numa->mem_nodes[node].distances;
c1c534
+    if (distances) {
c1c534
+        virReportError(VIR_ERR_INTERNAL_ERROR,
c1c534
+                       _("Cannot alter an existing nmem_nodes distances set for node: %zu"),
c1c534
+                       node);
c1c534
+        return 0;
c1c534
+    }
c1c534
+
c1c534
+    if (VIR_ALLOC_N(distances, ndistances) < 0)
c1c534
+        return 0;
c1c534
+
c1c534
+    numa->mem_nodes[node].distances = distances;
c1c534
+    numa->mem_nodes[node].ndistances = ndistances;
c1c534
+
c1c534
+    return numa->mem_nodes[node].ndistances;
c1c534
+}
c1c534
+
c1c534
+
c1c534
 virBitmapPtr
c1c534
 virDomainNumaGetNodeCpumask(virDomainNumaPtr numa,
c1c534
                             size_t node)
c1c534
@@ -1122,6 +1248,17 @@ virDomainNumaGetNodeCpumask(virDomainNumaPtr numa,
c1c534
 }
c1c534
 
c1c534
 
c1c534
+virBitmapPtr
c1c534
+virDomainNumaSetNodeCpumask(virDomainNumaPtr numa,
c1c534
+                            size_t node,
c1c534
+                            virBitmapPtr cpumask)
c1c534
+{
c1c534
+    numa->mem_nodes[node].cpumask = cpumask;
c1c534
+
c1c534
+    return numa->mem_nodes[node].cpumask;
c1c534
+}
c1c534
+
c1c534
+
c1c534
 virDomainMemoryAccess
c1c534
 virDomainNumaGetNodeMemoryAccessMode(virDomainNumaPtr numa,
c1c534
                                      size_t node)
c1c534
diff --git a/src/conf/numa_conf.h b/src/conf/numa_conf.h
c1c534
index 378b772e4b..4655de3aa7 100644
c1c534
--- a/src/conf/numa_conf.h
c1c534
+++ b/src/conf/numa_conf.h
c1c534
@@ -87,6 +87,11 @@ int virDomainNumatuneMaybeGetNodeset(virDomainNumaPtr numatune,
c1c534
 
c1c534
 size_t virDomainNumaGetNodeCount(virDomainNumaPtr numa);
c1c534
 
c1c534
+size_t virDomainNumaGetNodeDistance(virDomainNumaPtr numa,
c1c534
+                                    size_t node,
c1c534
+                                    size_t sibling)
c1c534
+    ATTRIBUTE_NONNULL(1);
c1c534
+
c1c534
 virBitmapPtr virDomainNumaGetNodeCpumask(virDomainNumaPtr numa,
c1c534
                                          size_t node)
c1c534
     ATTRIBUTE_NONNULL(1);
c1c534
@@ -124,11 +129,31 @@ int virDomainNumatuneSet(virDomainNumaPtr numa,
c1c534
                          virBitmapPtr nodeset)
c1c534
     ATTRIBUTE_NONNULL(1);
c1c534
 
c1c534
+size_t virDomainNumaSetNodeCount(virDomainNumaPtr numa,
c1c534
+                                 size_t nmem_nodes)
c1c534
+    ATTRIBUTE_NONNULL(1);
c1c534
+
c1c534
 void virDomainNumaSetNodeMemorySize(virDomainNumaPtr numa,
c1c534
                                     size_t node,
c1c534
                                     unsigned long long size)
c1c534
     ATTRIBUTE_NONNULL(1);
c1c534
 
c1c534
+int virDomainNumaSetNodeDistance(virDomainNumaPtr numa,
c1c534
+                                 size_t node,
c1c534
+                                 size_t sibling,
c1c534
+                                 unsigned int value)
c1c534
+    ATTRIBUTE_NONNULL(1);
c1c534
+
c1c534
+size_t virDomainNumaSetNodeDistanceCount(virDomainNumaPtr numa,
c1c534
+                                         size_t node,
c1c534
+                                         size_t ndistances)
c1c534
+    ATTRIBUTE_NONNULL(1);
c1c534
+
c1c534
+virBitmapPtr virDomainNumaSetNodeCpumask(virDomainNumaPtr numa,
c1c534
+                                         size_t node,
c1c534
+                                         virBitmapPtr cpumask)
c1c534
+    ATTRIBUTE_NONNULL(1);
c1c534
+
c1c534
 /*
c1c534
  * Other accessors
c1c534
  */
c1c534
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
c1c534
index ecf7036dff..19543e06ae 100644
c1c534
--- a/src/libvirt_private.syms
c1c534
+++ b/src/libvirt_private.syms
c1c534
@@ -723,9 +723,14 @@ virDomainNumaGetMaxCPUID;
c1c534
 virDomainNumaGetMemorySize;
c1c534
 virDomainNumaGetNodeCount;
c1c534
 virDomainNumaGetNodeCpumask;
c1c534
+virDomainNumaGetNodeDistance;
c1c534
 virDomainNumaGetNodeMemoryAccessMode;
c1c534
 virDomainNumaGetNodeMemorySize;
c1c534
 virDomainNumaNew;
c1c534
+virDomainNumaSetNodeCount;
c1c534
+virDomainNumaSetNodeCpumask;
c1c534
+virDomainNumaSetNodeDistance;
c1c534
+virDomainNumaSetNodeDistanceCount;
c1c534
 virDomainNumaSetNodeMemorySize;
c1c534
 virDomainNumatuneFormatNodeset;
c1c534
 virDomainNumatuneFormatXML;
c1c534
diff --git a/src/xenconfig/xen_xl.c b/src/xenconfig/xen_xl.c
c1c534
index 8acbfe3f69..81e780586f 100644
c1c534
--- a/src/xenconfig/xen_xl.c
c1c534
+++ b/src/xenconfig/xen_xl.c
c1c534
@@ -309,6 +309,203 @@ xenParseXLSpice(virConfPtr conf, virDomainDefPtr def)
c1c534
     return -1;
c1c534
 }
c1c534
 
c1c534
+#ifdef LIBXL_HAVE_VNUMA
c1c534
+static int
c1c534
+xenParseXLVnuma(virConfPtr conf,
c1c534
+                virDomainDefPtr def)
c1c534
+{
c1c534
+    int ret = -1;
c1c534
+    char *tmp = NULL;
c1c534
+    char **token = NULL;
c1c534
+    size_t vcpus = 0;
c1c534
+    size_t nr_nodes = 0;
c1c534
+    size_t vnodeCnt = 0;
c1c534
+    virCPUDefPtr cpu = NULL;
c1c534
+    virConfValuePtr list;
c1c534
+    virConfValuePtr vnode;
c1c534
+    virDomainNumaPtr numa;
c1c534
+
c1c534
+    numa = def->numa;
c1c534
+    if (numa == NULL)
c1c534
+        return -1;
c1c534
+
c1c534
+    list = virConfGetValue(conf, "vnuma");
c1c534
+    if (!list || list->type != VIR_CONF_LIST)
c1c534
+        return 0;
c1c534
+
c1c534
+    vnode = list->list;
c1c534
+    while (vnode && vnode->type == VIR_CONF_LIST) {
c1c534
+        vnode = vnode->next;
c1c534
+        nr_nodes++;
c1c534
+    }
c1c534
+
c1c534
+    if (!virDomainNumaSetNodeCount(numa, nr_nodes))
c1c534
+        goto cleanup;
c1c534
+
c1c534
+    if (VIR_ALLOC(cpu) < 0)
c1c534
+        goto cleanup;
c1c534
+
c1c534
+    list = list->list;
c1c534
+    while (list) {
c1c534
+        int pnode = -1;
c1c534
+        virBitmapPtr cpumask = NULL;
c1c534
+        unsigned long long kbsize = 0;
c1c534
+
c1c534
+        /* Is there a sublist (vnode)? */
c1c534
+        if (list && list->type == VIR_CONF_LIST) {
c1c534
+            vnode = list->list;
c1c534
+
c1c534
+            while (vnode && vnode->type == VIR_CONF_STRING) {
c1c534
+                const char *data;
c1c534
+                const char *str = vnode->str;
c1c534
+
c1c534
+                if (!str ||
c1c534
+                   !(data = strrchr(str, '='))) {
c1c534
+                    virReportError(VIR_ERR_INTERNAL_ERROR,
c1c534
+                                   _("vnuma vnode invalid format '%s'"),
c1c534
+                                   str);
c1c534
+                    goto cleanup;
c1c534
+                }
c1c534
+                data++;
c1c534
+
c1c534
+                if (*data) {
c1c534
+                    size_t len;
c1c534
+                    char vtoken[64];
c1c534
+
c1c534
+                    if (STRPREFIX(str, "pnode")) {
c1c534
+                        unsigned int cellid;
c1c534
+
c1c534
+                        len = strlen(data);
c1c534
+                        if (!virStrncpy(vtoken, data,
c1c534
+                                        len, sizeof(vtoken))) {
c1c534
+                            virReportError(VIR_ERR_INTERNAL_ERROR,
c1c534
+                                           _("vnuma vnode %zu pnode '%s' too long for destination"),
c1c534
+                                           vnodeCnt, data);
c1c534
+                            goto cleanup;
c1c534
+                        }
c1c534
+
c1c534
+                        if ((virStrToLong_ui(vtoken, NULL, 10, &cellid) < 0) ||
c1c534
+                            (cellid >= nr_nodes)) {
c1c534
+                            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
c1c534
+                                           _("vnuma vnode %zu contains invalid pnode value '%s'"),
c1c534
+                                           vnodeCnt, data);
c1c534
+                            goto cleanup;
c1c534
+                        }
c1c534
+                        pnode = cellid;
c1c534
+                    } else if (STRPREFIX(str, "size")) {
c1c534
+                        len = strlen(data);
c1c534
+                        if (!virStrncpy(vtoken, data,
c1c534
+                                        len, sizeof(vtoken))) {
c1c534
+                            virReportError(VIR_ERR_INTERNAL_ERROR,
c1c534
+                                           _("vnuma vnode %zu size '%s' too long for destination"),
c1c534
+                                           vnodeCnt, data);
c1c534
+                            goto cleanup;
c1c534
+                        }
c1c534
+
c1c534
+                        if (virStrToLong_ull(vtoken, NULL, 10, &kbsize) < 0)
c1c534
+                            goto cleanup;
c1c534
+
c1c534
+                        virDomainNumaSetNodeMemorySize(numa, vnodeCnt, (kbsize * 1024));
c1c534
+
c1c534
+                    } else if (STRPREFIX(str, "vcpus")) {
c1c534
+                        len = strlen(data);
c1c534
+                        if (!virStrncpy(vtoken, data,
c1c534
+                                        len, sizeof(vtoken))) {
c1c534
+                            virReportError(VIR_ERR_INTERNAL_ERROR,
c1c534
+                                           _("vnuma vnode %zu vcpus '%s' too long for destination"),
c1c534
+                                           vnodeCnt, data);
c1c534
+                            goto cleanup;
c1c534
+                        }
c1c534
+
c1c534
+                        if ((virBitmapParse(vtoken, &cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) ||
c1c534
+                            (virDomainNumaSetNodeCpumask(numa, vnodeCnt, cpumask) == NULL))
c1c534
+                            goto cleanup;
c1c534
+
c1c534
+                        vcpus += virBitmapCountBits(cpumask);
c1c534
+
c1c534
+                    } else if (STRPREFIX(str, "vdistances")) {
c1c534
+                        size_t i, ndistances;
c1c534
+                        unsigned int value;
c1c534
+
c1c534
+                        len = strlen(data);
c1c534
+                        if (!virStrncpy(vtoken, data,
c1c534
+                                        len, sizeof(vtoken))) {
c1c534
+                            virReportError(VIR_ERR_INTERNAL_ERROR,
c1c534
+                                           _("vnuma vnode %zu vdistances '%s' too long for destination"),
c1c534
+                                           vnodeCnt, data);
c1c534
+                            goto cleanup;
c1c534
+                        }
c1c534
+
c1c534
+                        if (VIR_STRDUP(tmp, vtoken) < 0)
c1c534
+                            goto cleanup;
c1c534
+
c1c534
+                        if (!(token = virStringSplitCount(tmp, ",", 0, &ndistances)))
c1c534
+                            goto cleanup;
c1c534
+
c1c534
+                        if (ndistances != nr_nodes) {
c1c534
+                            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
c1c534
+                                       _("vnuma pnode %d configured '%s' (count %zu) doesn't fit the number of specified vnodes %zu"),
c1c534
+                                       pnode, str, ndistances, nr_nodes);
c1c534
+                            goto cleanup;
c1c534
+                        }
c1c534
+
c1c534
+                        if (virDomainNumaSetNodeDistanceCount(numa, vnodeCnt, ndistances) != ndistances)
c1c534
+                            goto cleanup;
c1c534
+
c1c534
+                        for (i = 0; i < ndistances; i++) {
c1c534
+                            if ((virStrToLong_ui(token[i], NULL, 10, &value) < 0) ||
c1c534
+                                (virDomainNumaSetNodeDistance(numa, vnodeCnt, i, value) != value))
c1c534
+                                goto cleanup;
c1c534
+                        }
c1c534
+
c1c534
+                    } else {
c1c534
+                        virReportError(VIR_ERR_CONF_SYNTAX,
c1c534
+                                       _("Invalid vnuma configuration for vnode %zu"),
c1c534
+                                       vnodeCnt);
c1c534
+                        goto cleanup;
c1c534
+                    }
c1c534
+                }
c1c534
+                vnode = vnode->next;
c1c534
+            }
c1c534
+        }
c1c534
+
c1c534
+        if ((pnode < 0) ||
c1c534
+            (cpumask == NULL) ||
c1c534
+            (kbsize == 0)) {
c1c534
+            virReportError(VIR_ERR_CONF_SYNTAX,
c1c534
+                           _("Incomplete vnuma configuration for vnode %zu"),
c1c534
+                           vnodeCnt);
c1c534
+            goto cleanup;
c1c534
+        }
c1c534
+
c1c534
+        list = list->next;
c1c534
+        vnodeCnt++;
c1c534
+    }
c1c534
+
c1c534
+    if (def->maxvcpus == 0)
c1c534
+        def->maxvcpus = vcpus;
c1c534
+
c1c534
+    if (def->maxvcpus < vcpus) {
c1c534
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
c1c534
+                       _("vnuma configuration contains %zu vcpus, which is greater than %zu maxvcpus"),
c1c534
+                       vcpus, def->maxvcpus);
c1c534
+        goto cleanup;
c1c534
+    }
c1c534
+
c1c534
+    cpu->type = VIR_CPU_TYPE_GUEST;
c1c534
+    def->cpu = cpu;
c1c534
+
c1c534
+    ret = 0;
c1c534
+
c1c534
+ cleanup:
c1c534
+    if (ret)
c1c534
+        VIR_FREE(cpu);
c1c534
+    virStringListFree(token);
c1c534
+    VIR_FREE(tmp);
c1c534
+
c1c534
+    return ret;
c1c534
+}
c1c534
+#endif
c1c534
 
c1c534
 static int
c1c534
 xenParseXLDiskSrc(virDomainDiskDefPtr disk, char *srcstr)
c1c534
@@ -863,6 +1060,11 @@ xenParseXL(virConfPtr conf,
c1c534
     if (xenParseXLOS(conf, def, caps) < 0)
c1c534
         goto cleanup;
c1c534
 
c1c534
+#ifdef LIBXL_HAVE_VNUMA
c1c534
+    if (xenParseXLVnuma(conf, def) < 0)
c1c534
+        goto cleanup;
c1c534
+#endif
c1c534
+
c1c534
     if (xenParseXLDisk(conf, def) < 0)
c1c534
         goto cleanup;
c1c534
 
c1c534
@@ -1005,6 +1207,134 @@ xenFormatXLOS(virConfPtr conf, virDomainDefPtr def)
c1c534
     return 0;
c1c534
 }
c1c534
 
c1c534
+#ifdef LIBXL_HAVE_VNUMA
c1c534
+static int
c1c534
+xenFormatXLVnode(virConfValuePtr list,
c1c534
+                 virBufferPtr buf)
c1c534
+{
c1c534
+    int ret = -1;
c1c534
+    virConfValuePtr numaPnode, tmp;
c1c534
+
c1c534
+    if (virBufferCheckError(buf) < 0)
c1c534
+        goto cleanup;
c1c534
+
c1c534
+    if (VIR_ALLOC(numaPnode) < 0)
c1c534
+        goto cleanup;
c1c534
+
c1c534
+    /* Place VNODE directive */
c1c534
+    numaPnode->type = VIR_CONF_STRING;
c1c534
+    numaPnode->str = virBufferContentAndReset(buf);
c1c534
+
c1c534
+    tmp = list->list;
c1c534
+    while (tmp && tmp->next)
c1c534
+        tmp = tmp->next;
c1c534
+    if (tmp)
c1c534
+        tmp->next = numaPnode;
c1c534
+    else
c1c534
+        list->list = numaPnode;
c1c534
+    ret = 0;
c1c534
+
c1c534
+ cleanup:
c1c534
+    virBufferFreeAndReset(buf);
c1c534
+    return ret;
c1c534
+}
c1c534
+
c1c534
+static int
c1c534
+xenFormatXLVnuma(virConfValuePtr list,
c1c534
+                 virDomainNumaPtr numa,
c1c534
+                 size_t node,
c1c534
+                 size_t nr_nodes)
c1c534
+{
c1c534
+    int ret = -1;
c1c534
+    size_t i;
c1c534
+
c1c534
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
c1c534
+    virConfValuePtr numaVnode, tmp;
c1c534
+
c1c534
+    size_t nodeSize = virDomainNumaGetNodeMemorySize(numa, node) / 1024;
c1c534
+    char *nodeVcpus = virBitmapFormat(virDomainNumaGetNodeCpumask(numa, node));
c1c534
+
c1c534
+    if (VIR_ALLOC(numaVnode) < 0)
c1c534
+        goto cleanup;
c1c534
+
c1c534
+    numaVnode->type = VIR_CONF_LIST;
c1c534
+    numaVnode->list = NULL;
c1c534
+
c1c534
+    /* pnode */
c1c534
+    virBufferAsprintf(&buf, "pnode=%ld", node);
c1c534
+    xenFormatXLVnode(numaVnode, &buf;;
c1c534
+
c1c534
+    /* size */
c1c534
+    virBufferAsprintf(&buf, "size=%ld", nodeSize);
c1c534
+    xenFormatXLVnode(numaVnode, &buf;;
c1c534
+
c1c534
+    /* vcpus */
c1c534
+    virBufferAsprintf(&buf, "vcpus=%s", nodeVcpus);
c1c534
+    xenFormatXLVnode(numaVnode, &buf;;
c1c534
+
c1c534
+    /* distances */
c1c534
+    virBufferAddLit(&buf, "vdistances=");
c1c534
+    for (i = 0; i < nr_nodes; i++) {
c1c534
+        virBufferAsprintf(&buf, "%zu",
c1c534
+            virDomainNumaGetNodeDistance(numa, node, i));
c1c534
+        if ((nr_nodes - i) > 1)
c1c534
+            virBufferAddLit(&buf, ",");
c1c534
+    }
c1c534
+    xenFormatXLVnode(numaVnode, &buf;;
c1c534
+
c1c534
+    tmp = list->list;
c1c534
+    while (tmp && tmp->next)
c1c534
+        tmp = tmp->next;
c1c534
+    if (tmp)
c1c534
+        tmp->next = numaVnode;
c1c534
+    else
c1c534
+        list->list = numaVnode;
c1c534
+    ret = 0;
c1c534
+
c1c534
+ cleanup:
c1c534
+    VIR_FREE(nodeVcpus);
c1c534
+    return ret;
c1c534
+}
c1c534
+
c1c534
+static int
c1c534
+xenFormatXLDomainVnuma(virConfPtr conf,
c1c534
+                       virDomainDefPtr def)
c1c534
+{
c1c534
+    virDomainNumaPtr numa = def->numa;
c1c534
+    virConfValuePtr vnumaVal;
c1c534
+    size_t i;
c1c534
+    size_t nr_nodes;
c1c534
+
c1c534
+    if (numa == NULL)
c1c534
+        return -1;
c1c534
+
c1c534
+    if (VIR_ALLOC(vnumaVal) < 0)
c1c534
+        return -1;
c1c534
+
c1c534
+    vnumaVal->type = VIR_CONF_LIST;
c1c534
+    vnumaVal->list = NULL;
c1c534
+
c1c534
+    nr_nodes = virDomainNumaGetNodeCount(numa);
c1c534
+    for (i = 0; i < nr_nodes; i++) {
c1c534
+        if (xenFormatXLVnuma(vnumaVal, numa, i, nr_nodes) < 0)
c1c534
+            goto cleanup;
c1c534
+    }
c1c534
+
c1c534
+    if (vnumaVal->list != NULL) {
c1c534
+        int ret = virConfSetValue(conf, "vnuma", vnumaVal);
c1c534
+            vnumaVal = NULL;
c1c534
+            if (ret < 0)
c1c534
+                return -1;
c1c534
+    }
c1c534
+    VIR_FREE(vnumaVal);
c1c534
+
c1c534
+    return 0;
c1c534
+
c1c534
+ cleanup:
c1c534
+    virConfFreeValue(vnumaVal);
c1c534
+    return -1;
c1c534
+}
c1c534
+#endif
c1c534
 
c1c534
 static char *
c1c534
 xenFormatXLDiskSrcNet(virStorageSourcePtr src)
c1c534
@@ -1642,6 +1972,11 @@ xenFormatXL(virDomainDefPtr def, virConnectPtr conn)
c1c534
     if (xenFormatXLOS(conf, def) < 0)
c1c534
         goto cleanup;
c1c534
 
c1c534
+#ifdef LIBXL_HAVE_VNUMA
c1c534
+    if (xenFormatXLDomainVnuma(conf, def) < 0)
c1c534
+        goto cleanup;
c1c534
+#endif
c1c534
+
c1c534
     if (xenFormatXLDomainDisks(conf, def) < 0)
c1c534
         goto cleanup;
c1c534
 
c1c534
-- 
c1c534
2.15.1
c1c534