Although, having it depending on Xen >= 4.3 (by using the proper
libxl feature flag).
Xen currently implements a NUMA placement policy which is basically
the same as the 'interleaved' policy of `numactl', although it can
be applied on a subset of the available nodes. We therefore hardcode
"interleave" as 'numa_mode', and we use the newly introduced libxl
interface to figure out what nodes a domain spans ('numa_nodeset').
With this change, it is now possible to query the NUMA node
affinity of a running domain:
[raistlin@Zhaman ~]$ sudo virsh --connect xen:/// list
Id Name State
----------------------------------------------------
23 F18_x64 running
[raistlin@Zhaman ~]$ sudo virsh --connect xen:/// numatune 23
numa_mode : interleave
numa_nodeset : 1
Signed-off-by: Dario Faggioli <dario.faggioli(a)citrix.com>
---
Changes from v1:
* fixed coding style, as requested during review;
* VIR_TYPED_PARAM_STRING_OKAY handled more properly;
---
src/libxl/libxl_driver.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 141 insertions(+)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 7555bc6..4ed231a 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -28,6 +28,7 @@
#include <math.h>
#include <libxl.h>
+#include <libxl_utils.h>
#include <fcntl.h>
#include <regex.h>
@@ -4521,6 +4522,143 @@ libxlDomainSetSchedulerParameters(virDomainPtr dom,
virTypedParameterPtr params,
return libxlDomainSetSchedulerParametersFlags(dom, params, nparams, 0);
}
+/* NUMA node affinity information is available through libxl
+ * starting from Xen 4.3. */
+#ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY
+
+/* Number of Xen NUMA parameters */
+# define LIBXL_NUMA_NPARAM 2
+
+static int
+libxlDomainGetNumaParameters(virDomainPtr dom,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ libxlDomainObjPrivatePtr priv;
+ virDomainObjPtr vm;
+ libxl_bitmap nodemap;
+ virBitmapPtr nodes = NULL;
+ char *nodeset = NULL;
+ int rc, ret = -1;
+ int i, j;
+
+ /* In Xen 4.3, it is possible to query the NUMA node affinity of a domain
+ * via libxl, but not to change it. We therefore only allow AFFECT_LIVE. */
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_TYPED_PARAM_STRING_OKAY, -1);
+
+ /* We blindly return a string, and let libvirt.c and remote_driver.c do
+ * the filtering on behalf of older clients that can't parse it. */
+ flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
+
+ libxlDriverLock(driver);
+ vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ virReportError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ if (virDomainGetNumaParametersEnsureACL(dom->conn, vm->def) < 0)
+ goto cleanup;
+
+ if (!virDomainObjIsActive(vm)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Domain is not running"));
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+
+ libxl_bitmap_init(&nodemap);
+
+ if ((*nparams) == 0) {
+ *nparams = LIBXL_NUMA_NPARAM;
+ ret = 0;
+ goto cleanup;
+ }
+
+ for (i = 0; i < LIBXL_NUMA_NPARAM && i < *nparams; i++) {
+ virMemoryParameterPtr param = ¶ms[i];
+
+ switch (i) {
+ case 0:
+ /* NUMA mode */
+
+ /* Xen implements something that is is really close to numactl's
+ * 'interleave' policy (see `man 8 numactl' for details). */
+ if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
+ VIR_TYPED_PARAM_INT,
+ VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE) < 0)
+ goto cleanup;
+
+ break;
+
+ case 1:
+ /* Node affinity */
+
+ /* Let's allocate both libxl and libvirt bitmaps */
+ if (libxl_node_bitmap_alloc(priv->ctx, &nodemap, 0) ||
+ !(nodes = virBitmapNew(libxl_get_max_nodes(priv->ctx)))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ rc = libxl_domain_get_nodeaffinity(priv->ctx,
+ vm->def->id,
+ &nodemap);
+ if (rc != 0) {
+ virReportSystemError(-rc, "%s",
+ _("unable to get numa affinity"));
+ goto cleanup;
+ }
+
+ /* First, we convert libxl_bitmap into virBitmap. After that,
+ * we format virBitmap as a string that can be returned. */
+ virBitmapClearAll(nodes);
+ libxl_for_each_set_bit(j, nodemap) {
+ if (virBitmapSetBit(nodes, j)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Node %d out of range"), j);
+ goto cleanup;
+ }
+ }
+
+ nodeset = virBitmapFormat(nodes);
+ if (!nodeset && VIR_STRDUP(nodeset, "") < 0)
+ goto cleanup;
+
+ if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
+ VIR_TYPED_PARAM_STRING, nodeset) < 0)
+ goto cleanup;
+
+ nodeset = NULL;
+
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (*nparams > LIBXL_NUMA_NPARAM)
+ *nparams = LIBXL_NUMA_NPARAM;
+ ret = 0;
+
+cleanup:
+ VIR_FREE(nodeset);
+ virBitmapFree(nodes);
+ libxl_bitmap_dispose(&nodemap);
+ if (vm)
+ virObjectUnlock(vm);
+ return ret;
+}
+#endif
+
static int
libxlDomainIsActive(virDomainPtr dom)
{
@@ -4749,6 +4887,9 @@ static virDriver libxlDriver = {
.domainGetSchedulerParametersFlags = libxlDomainGetSchedulerParametersFlags, /* 0.9.2
*/
.domainSetSchedulerParameters = libxlDomainSetSchedulerParameters, /* 0.9.0 */
.domainSetSchedulerParametersFlags = libxlDomainSetSchedulerParametersFlags, /* 0.9.2
*/
+#ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY
+ .domainGetNumaParameters = libxlDomainGetNumaParameters, /* 1.1.1 */
+#endif
.nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
.nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
.connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */