diff --git a/docs/schemas/capability.rng b/docs/schemas/capability.rng
index d2d9776e49448bb836b17176fe31f36870e73e38..0c95c05d6851174b63c0d3991b2ab36a8c393865 100644
--- a/docs/schemas/capability.rng
+++ b/docs/schemas/capability.rng
@@ -188,6 +188,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c
index cf474d72c6563acd2945de40d1330f4454c8a66d..408fab3f392c81347cc576475c233832a6977db6 100644
--- a/src/conf/capabilities.c
+++ b/src/conf/capabilities.c
@@ -107,6 +107,7 @@ virCapabilitiesFreeHostNUMACell(virCapsHostNUMACellPtr cell)
virCapabilitiesClearHostNUMACellCPUTopology(cell->cpus, cell->ncpus);
VIR_FREE(cell->cpus);
+ VIR_FREE(cell->siblings);
VIR_FREE(cell);
}
@@ -275,9 +276,11 @@ virCapabilitiesAddHostMigrateTransport(virCapsPtr caps,
* virCapabilitiesAddHostNUMACell:
* @caps: capabilities to extend
* @num: ID number of NUMA cell
- * @ncpus: number of CPUs in cell
* @mem: Total size of memory in the NUMA node (in KiB)
+ * @ncpus: number of CPUs in cell
* @cpus: array of CPU definition structures, the pointer is stolen
+ * @nsiblings: number of sibling NUMA nodes
+ * @siblings: info on sibling NUMA nodes
*
* Registers a new NUMA cell for a host, passing in a
* array of CPU IDs belonging to the cell
@@ -285,9 +288,11 @@ virCapabilitiesAddHostMigrateTransport(virCapsPtr caps,
int
virCapabilitiesAddHostNUMACell(virCapsPtr caps,
int num,
- int ncpus,
unsigned long long mem,
- virCapsHostNUMACellCPUPtr cpus)
+ int ncpus,
+ virCapsHostNUMACellCPUPtr cpus,
+ int nsiblings,
+ virCapsHostNUMACellSiblingInfoPtr siblings)
{
virCapsHostNUMACellPtr cell;
@@ -302,6 +307,8 @@ virCapabilitiesAddHostNUMACell(virCapsPtr caps,
cell->num = num;
cell->mem = mem;
cell->cpus = cpus;
+ cell->siblings = siblings;
+ cell->nsiblings = nsiblings;
caps->host.numaCell[caps->host.nnumaCell++] = cell;
@@ -766,6 +773,18 @@ virCapabilitiesFormatNUMATopology(virBufferPtr buf,
virBufferAsprintf(buf, "%llu\n",
cells[i]->mem);
+ if (cells[i]->nsiblings) {
+ virBufferAddLit(buf, "\n");
+ virBufferAdjustIndent(buf, 2);
+ for (j = 0; j < cells[i]->nsiblings; j++) {
+ virBufferAsprintf(buf, "\n",
+ cells[i]->siblings[j].node,
+ cells[i]->siblings[j].distance);
+ }
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "\n");
+ }
+
virBufferAsprintf(buf, "\n", cells[i]->ncpus);
virBufferAdjustIndent(buf, 2);
for (j = 0; j < cells[i]->ncpus; j++) {
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
index ba99e1a393c7d75f42c29e5c338c6c7a62234a15..53a83c9df740dd7600adf6c5dfc05225ca28ca56 100644
--- a/src/conf/capabilities.h
+++ b/src/conf/capabilities.h
@@ -95,6 +95,13 @@ struct _virCapsHostNUMACellCPU {
virBitmapPtr siblings;
};
+typedef struct _virCapsHostNUMACellSiblingInfo virCapsHostNUMACellSiblingInfo;
+typedef virCapsHostNUMACellSiblingInfo *virCapsHostNUMACellSiblingInfoPtr;
+struct _virCapsHostNUMACellSiblingInfo {
+ int node; /* foreign NUMA node */
+ unsigned int distance; /* distance to the node */
+};
+
typedef struct _virCapsHostNUMACell virCapsHostNUMACell;
typedef virCapsHostNUMACell *virCapsHostNUMACellPtr;
struct _virCapsHostNUMACell {
@@ -102,6 +109,8 @@ struct _virCapsHostNUMACell {
int ncpus;
unsigned long long mem; /* in kibibytes */
virCapsHostNUMACellCPUPtr cpus;
+ int nsiblings;
+ virCapsHostNUMACellSiblingInfoPtr siblings;
};
typedef struct _virCapsHostSecModelLabel virCapsHostSecModelLabel;
@@ -193,9 +202,11 @@ virCapabilitiesAddHostMigrateTransport(virCapsPtr caps,
extern int
virCapabilitiesAddHostNUMACell(virCapsPtr caps,
int num,
- int ncpus,
unsigned long long mem,
- virCapsHostNUMACellCPUPtr cpus);
+ int ncpus,
+ virCapsHostNUMACellCPUPtr cpus,
+ int nsiblings,
+ virCapsHostNUMACellSiblingInfoPtr siblings);
extern int
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
index 14742decde2f3b376cd4b2ec662efbe9c6b1d853..cec37d6991b734fd6dacca82eab82e207ecb7d65 100644
--- a/src/libxl/libxl_conf.c
+++ b/src/libxl/libxl_conf.c
@@ -207,9 +207,10 @@ libxlCapsInitNuma(libxl_ctx *ctx, virCapsPtr caps)
if (numa_info[i].size == LIBXL_NUMAINFO_INVALID_ENTRY)
continue;
- if (virCapabilitiesAddHostNUMACell(caps, i, nr_cpus_node[i],
+ if (virCapabilitiesAddHostNUMACell(caps, i,
numa_info[i].size / 1024,
- cpus[i]) < 0) {
+ nr_cpus_node[i], cpus[i],
+ 0, NULL) < 0) {
virCapabilitiesClearHostNUMACellCPUTopology(cpus[i],
nr_cpus_node[i]);
goto cleanup;
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index 56f2b02849b115fbf40cca0177c064afa4da7126..5eef42e20b2656acae0056e7600e2102a4ff9444 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -1644,9 +1644,9 @@ nodeCapsInitNUMAFake(virCapsPtr caps ATTRIBUTE_UNUSED)
}
if (virCapabilitiesAddHostNUMACell(caps, 0,
- ncpus,
nodeinfo.memory,
- cpus) < 0)
+ ncpus, cpus,
+ 0, NULL) < 0)
goto error;
return 0;
@@ -1748,6 +1748,53 @@ virNodeCapsFillCPUInfo(int cpu_id ATTRIBUTE_UNUSED,
#endif
}
+static int
+virNodeCapsGetSiblingInfo(int node,
+ virCapsHostNUMACellSiblingInfoPtr *siblings,
+ int *nsiblings)
+{
+ virCapsHostNUMACellSiblingInfoPtr tmp = NULL;
+ int tmp_size = 0;
+ int ret = -1;
+ int *distances = NULL;
+ int ndistances = 0;
+ size_t i;
+
+ if (virNumaGetDistances(node, &distances, &ndistances) < 0)
+ goto cleanup;
+
+ if (!distances) {
+ *siblings = NULL;
+ *nsiblings = 0;
+ return 0;
+ }
+
+ if (VIR_ALLOC_N(tmp, ndistances) < 0)
+ goto cleanup;
+
+ for (i = 0; i < ndistances; i++) {
+ if (!distances[i])
+ continue;
+
+ tmp[tmp_size].node = i;
+ tmp[tmp_size].distance = distances[i];
+ tmp_size++;
+ }
+
+ if (VIR_REALLOC_N(tmp, tmp_size) < 0)
+ goto cleanup;
+
+ *siblings = tmp;
+ *nsiblings = tmp_size;
+ tmp = NULL;
+ tmp_size = 0;
+ ret = 0;
+ cleanup:
+ VIR_FREE(distances);
+ VIR_FREE(tmp);
+ return ret;
+}
+
int
nodeCapsInitNUMA(virCapsPtr caps)
{
@@ -1755,6 +1802,8 @@ nodeCapsInitNUMA(virCapsPtr caps)
unsigned long long memory;
virCapsHostNUMACellCPUPtr cpus = NULL;
virBitmapPtr cpumap = NULL;
+ virCapsHostNUMACellSiblingInfoPtr siblings = NULL;
+ int nsiblings;
int ret = -1;
int ncpus = 0;
int cpu;
@@ -1794,14 +1843,20 @@ nodeCapsInitNUMA(virCapsPtr caps)
}
}
+ if (virNodeCapsGetSiblingInfo(n, &siblings, &nsiblings) < 0)
+ goto cleanup;
+
/* Detect the amount of memory in the numa cell in KiB */
virNumaGetNodeMemory(n, &memory, NULL);
memory >>= 10;
- if (virCapabilitiesAddHostNUMACell(caps, n, ncpus, memory, cpus) < 0)
+ if (virCapabilitiesAddHostNUMACell(caps, n, memory,
+ ncpus, cpus,
+ nsiblings, siblings) < 0)
goto cleanup;
cpus = NULL;
+ siblings = NULL;
}
ret = 0;
@@ -1812,6 +1867,7 @@ nodeCapsInitNUMA(virCapsPtr caps)
virBitmapFree(cpumap);
VIR_FREE(cpus);
+ VIR_FREE(siblings);
if (ret < 0)
VIR_FREE(cpus);
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 37756e7ebcff73b7d34fb42de87726ba8acc9b0e..f9e2b3dcc83ed29d7f5342fbde1082364c997c16 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -336,8 +336,9 @@ testBuildCapabilities(virConnectPtr conn)
sizeof(*cpu_cells) * privconn->cells[i].numCpus);
- if (virCapabilitiesAddHostNUMACell(caps, i, privconn->cells[i].numCpus,
- 0, cpu_cells) < 0)
+ if (virCapabilitiesAddHostNUMACell(caps, i, 0,
+ privconn->cells[i].numCpus,
+ cpu_cells, 0, NULL) < 0)
goto error;
}
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index c30b136ef22e643990658f5b96824e3b1d6c28e2..5ddf71acbc7aece405fb3fb4472f32e56ea5c34f 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -1100,7 +1100,9 @@ sexpr_to_xend_topology(const struct sexpr *root, virCapsPtr caps)
}
virBitmapFree(cpuset);
- if (virCapabilitiesAddHostNUMACell(caps, cell, nb_cpus, 0, cpuInfo) < 0)
+ if (virCapabilitiesAddHostNUMACell(caps, cell, 0,
+ nb_cpus, cpuInfo,
+ 0, NULL) < 0)
goto error;
cpuInfo = NULL;
}
diff --git a/tests/vircapstest.c b/tests/vircapstest.c
index 821a92bc5818c4cf6a555515a5bb10141d2c2770..3edebba5ef13562c553ae82c5b0a3d630476913c 100644
--- a/tests/vircapstest.c
+++ b/tests/vircapstest.c
@@ -64,9 +64,9 @@ buildNUMATopology(int seq)
id++;
if (virCapabilitiesAddHostNUMACell(caps, cell_id + seq,
- MAX_CPUS_IN_CELL,
MAX_MEM_IN_CELL,
- cell_cpus) < 0)
+ MAX_CPUS_IN_CELL, cell_cpus,
+ 0, NULL) < 0)
goto error;
cell_cpus = NULL;