+Wed Oct 31 10:36:00 CET 2007 Daniel Veillard <veillard@redhat.com>
+
+ * proxy/libvirt_proxy.c src/proxy_internal.[ch] src/xen_internal.c
+ src/xen_unified.[ch] src/xend_internal.[ch] src/xml.[ch]: last
+ patch for the library NUMA support, allow to serialize CPU pinning
+ to domain configs (but won't work though proxy access), includes
+ many patches from Saori Fukuta.
+
Fri Oct 26 21:20:44 EST 2007 Daniel P. Berrange <berrange@redhat.com>
* src/libvirt.c: Don't call state driver API if callback is NULL.
if (req->len != sizeof(virProxyPacket))
goto comm_error;
- xml = xenDaemonDomainDumpXMLByID(conn, request.data.arg, 0);
+ /*
+ * Ideally we should get the CPUs used by the domain
+ * but that information is really node specific and it
+ * rather hard to get from that code path. So proxy
+ * users won't see CPU pinning (last NULL arg)
+ */
+ xml = xenDaemonDomainDumpXMLByID(conn, request.data.arg, 0, NULL);
if (!xml) {
req->data.arg = -1;
req->len = sizeof(virProxyPacket);
static int xenProxyNumOfDomains(virConnectPtr conn);
static unsigned long xenProxyDomainGetMaxMemory(virDomainPtr domain);
static int xenProxyDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info);
-static char *xenProxyDomainDumpXML(virDomainPtr domain, int flags);
static char *xenProxyDomainGetOSType(virDomainPtr domain);
struct xenUnifiedDriver xenProxyDriver = {
NULL, /* domainPinVcpu */
NULL, /* domainGetVcpus */
NULL, /* domainGetMaxVcpus */
- xenProxyDomainDumpXML, /* domainDumpXML */
NULL, /* listDefinedDomains */
NULL, /* numOfDefinedDomains */
NULL, /* domainCreate */
*
* Returns the XML document on success, NULL otherwise.
*/
-static char *
+char *
xenProxyDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
{
virProxyPacket req;
extern virDomainPtr xenProxyLookupByName(virConnectPtr conn,
const char *domname);
+extern char * xenProxyDomainDumpXML(virDomainPtr domain,
+ int flags);
#ifdef __cplusplus
}
#endif /* __cplusplus */
xenHypervisorPinVcpu, /* domainPinVcpu */
xenHypervisorGetVcpus, /* domainGetVcpus */
xenHypervisorGetVcpuMax, /* domainGetMaxVcpus */
- NULL, /* domainDumpXML */
NULL, /* listDefinedDomains */
NULL, /* numOfDefinedDomains */
NULL, /* domainCreate */
#include "xend_internal.h"
#include "xs_internal.h"
#include "xm_internal.h"
+#include "xml.h"
static int
xenUnifiedNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info);
+static int
+xenUnifiedDomainGetMaxVcpus (virDomainPtr dom);
+static int
+xenUnifiedDomainGetVcpus (virDomainPtr dom,
+ virVcpuInfoPtr info, int maxinfo,
+ unsigned char *cpumaps, int maplen);
/* The five Xen drivers below us. */
static struct xenUnifiedDriver *drivers[XEN_UNIFIED_NR_DRIVERS] = {
* xenNbCpus:
* @conn: pointer to the hypervisor connection
*
- * Number of NUMa cells present in the actual Node
+ * Number of CPUs present in the actual Node
*
- * Returns the number of NUMA cells available on that Node
+ * Returns the number of CPUs available on that Node
*/
int xenNbCpus(virConnectPtr conn) {
if (nbNodeCpus < 0)
return(nbNodeCpus);
}
+/**
+ * xenDomainUsedCpus:
+ * @dom: the domain
+ *
+ * Analyze which set of CPUs are used by the domain and
+ * return a string providing the ranges.
+ *
+ * Returns the string which needs to be freed by the caller or
+ * NULL if the domain uses all CPU or in case of error.
+ */
+char *
+xenDomainUsedCpus(virDomainPtr dom)
+{
+ char *res = NULL;
+ int nb_cpu, ncpus;
+ int nb_vcpu;
+ char *cpulist = NULL;
+ unsigned char *cpumap = NULL;
+ size_t cpumaplen;
+ int nb = 0;
+ int n, m;
+ virVcpuInfoPtr cpuinfo = NULL;
+ virNodeInfo nodeinfo;
+
+ if (!VIR_IS_CONNECTED_DOMAIN(dom))
+ return (NULL);
+
+ nb_cpu = xenNbCpus(dom->conn);
+ if (nb_cpu <= 0)
+ return(NULL);
+ nb_vcpu = xenUnifiedDomainGetMaxVcpus(dom);
+ if (nb_vcpu <= 0)
+ return(NULL);
+ if (xenUnifiedNodeGetInfo(dom->conn, &nodeinfo) < 0)
+ return(NULL);
+
+ cpulist = (char *) calloc(nb_cpu, sizeof(char));
+ if (cpulist == NULL)
+ goto done;
+ cpuinfo = malloc(sizeof(virVcpuInfo) * nb_vcpu);
+ if (cpuinfo == NULL)
+ goto done;
+ cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
+ cpumap = (unsigned char *) calloc(nb_vcpu, cpumaplen);
+ if (cpumap == NULL)
+ goto done;
+
+ if ((ncpus = xenUnifiedDomainGetVcpus(dom, cpuinfo, nb_vcpu,
+ cpumap, cpumaplen)) >= 0) {
+ for (n = 0 ; n < ncpus ; n++) {
+ for (m = 0 ; m < nb_cpu; m++) {
+ if ((cpulist[m] == 0) &&
+ (VIR_CPU_USABLE(cpumap, cpumaplen, n, m))) {
+ cpulist[m] = 1;
+ nb++;
+ /* if all CPU are used just return NULL */
+ if (nb == nb_cpu)
+ goto done;
+
+ }
+ }
+ }
+ res = virSaveCpuSet(dom->conn, cpulist, nb_cpu);
+ }
+
+done:
+ if (cpulist != NULL)
+ free(cpulist);
+ if (cpumap != NULL)
+ free(cpumap);
+ if (cpuinfo != NULL)
+ free(cpuinfo);
+ return(res);
+}
+
/*----- Dispatch functions. -----*/
/* These dispatch functions follow the model used historically
xenUnifiedDomainDumpXML (virDomainPtr dom, int flags)
{
GET_PRIVATE(dom->conn);
- int i;
- char *ret;
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainDumpXML) {
- ret = drivers[i]->domainDumpXML (dom, flags);
- if (ret) return ret;
+ if (dom->id == -1 && priv->xendConfigVersion < 3 ) {
+ if (priv->opened[XEN_UNIFIED_XM_OFFSET])
+ return xenXMDomainDumpXML(dom, flags);
+ } else {
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+ char *cpus, *res;
+ cpus = xenDomainUsedCpus(dom);
+ res = xenDaemonDomainDumpXML(dom, flags, cpus);
+ if (cpus != NULL)
+ free(cpus);
+ return(res);
}
+ if (priv->opened[XEN_UNIFIED_PROXY_OFFSET])
+ return xenProxyDomainDumpXML(dom, flags);
+ }
- /* XXX May need to return an error here if sub-drivers didn't
- * set one. We really should change these to direct calls to
- * the sub-drivers at a later date.
- */
+ xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
return NULL;
}
virDrvDomainPinVcpu domainPinVcpu;
virDrvDomainGetVcpus domainGetVcpus;
virDrvDomainGetMaxVcpus domainGetMaxVcpus;
- virDrvDomainDumpXML domainDumpXML;
virDrvListDefinedDomains listDefinedDomains;
virDrvNumOfDefinedDomains numOfDefinedDomains;
virDrvDomainCreate domainCreate;
int xenNbCells(virConnectPtr conn);
int xenNbCpus(virConnectPtr conn);
+char *xenDomainUsedCpus(virDomainPtr dom);
#ifdef __cplusplus
}
#endif
xenDaemonDomainPinVcpu, /* domainPinVcpu */
xenDaemonDomainGetVcpus, /* domainGetVcpus */
NULL, /* domainGetMaxVcpus */
- xenDaemonDomainDumpXML, /* domainDumpXML */
xenDaemonListDefinedDomains, /* listDefinedDomains */
xenDaemonNumOfDefinedDomains, /* numOfDefinedDomains */
xenDaemonDomainCreate, /* domainCreate */
* @root: the root of the parsed S-Expression
* @xendConfigVersion: version of xend
* @flags: a combination of virDomainXMLFlags
+ * @cpus: set of cpus the domain may be pinned to
*
* Parse the xend sexp description and turn it into the XML format similar
* to the one unsed for creation.
*/
static char *
xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root,
- int xendConfigVersion, int flags)
+ int xendConfigVersion, int flags, const char *cpus)
{
struct sexpr *cur, *node;
const char *tmp;
if ((cur_mem >= MIN_XEN_GUEST_SIZE) && (cur_mem != max_mem))
virBufferVSprintf(&buf, " <currentMemory>%d</currentMemory>\n",
cur_mem);
- virBufferVSprintf(&buf, " <vcpu>%d</vcpu>\n",
+
+ virBufferVSprintf(&buf, " <vcpu");
+ if (cpus != NULL) {
+ virBufferVSprintf(&buf, " cpuset='%s'", cpus);
+ }
+ virBufferVSprintf(&buf, ">%d</vcpu>\n",
sexpr_int(root, "domain/vcpus"));
+ /* TODO if need to output the cpus values,
+ * - parse the cpus values if xend exports
+ * or
+ * - analyze the cpus values extracted by xenDaemonDomainGetVcpus
+ */
tmp = sexpr_node(root, "domain/on_poweroff");
if (tmp != NULL)
virBufferVSprintf(&buf, " <on_poweroff>%s</on_poweroff>\n", tmp);
if (!root)
return NULL;
- data = xend_parse_sexp_desc(conn, root, xendConfigVersion, 0);
+ data = xend_parse_sexp_desc(conn, root, xendConfigVersion, 0, NULL);
sexpr_free(root);
dumpxml will work over proxy for inactive domains
and this can be removed */
char *
-xenDaemonDomainDumpXMLByID(virConnectPtr conn, int domid, int flags)
+xenDaemonDomainDumpXMLByID(virConnectPtr conn, int domid, int flags,
+ const char *cpus)
{
char *ret = NULL;
struct sexpr *root;
priv = (xenUnifiedPrivatePtr) conn->privateData;
- ret = xend_parse_sexp_desc(conn, root, priv->xendConfigVersion, flags);
+ ret = xend_parse_sexp_desc(conn, root, priv->xendConfigVersion,
+ flags, cpus);
sexpr_free(root);
return (ret);
}
char *
-xenDaemonDomainDumpXMLByName(virConnectPtr conn, const char *name, int flags)
+xenDaemonDomainDumpXMLByName(virConnectPtr conn, const char *name, int flags,
+ const char *cpus)
{
char *ret = NULL;
struct sexpr *root;
priv = (xenUnifiedPrivatePtr) conn->privateData;
- ret = xend_parse_sexp_desc(conn, root, priv->xendConfigVersion, flags);
+ ret = xend_parse_sexp_desc(conn, root, priv->xendConfigVersion,
+ flags, cpus);
sexpr_free(root);
return (ret);
/**
* xenDaemonDomainDumpXML:
* @domain: a domain object
+ * @flags: potential dump flags
+ * @cpus: list of cpu the domain is pinned to.
*
* Provide an XML description of the domain.
*
* the caller must free() the returned value.
*/
char *
-xenDaemonDomainDumpXML(virDomainPtr domain, int flags)
+xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus)
{
xenUnifiedPrivatePtr priv;
}
if (domain->id < 0)
- return xenDaemonDomainDumpXMLByName(domain->conn, domain->name, flags);
+ return xenDaemonDomainDumpXMLByName(domain->conn, domain->name, flags,
+ cpus);
else
- return xenDaemonDomainDumpXMLByID(domain->conn, domain->id, flags);
+ return xenDaemonDomainDumpXMLByID(domain->conn, domain->id, flags,
+ cpus);
}
#endif /* !PROXY */
char *xenDaemonDomainDumpXMLByID(virConnectPtr xend,
int domid,
- int flags);
+ int flags,
+ const char *cpus);
char *xenDaemonDomainDumpXMLByName(virConnectPtr xend,
const char *name,
- int flags);
+ int flags,
+ const char *cpus);
/**
* \brief Lookup information about the host machine
int xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory);
int xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);
int xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info);
-char *xenDaemonDomainDumpXML(virDomainPtr domain, int flags);
+char *xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus);
unsigned long xenDaemonDomainGetMaxMemory(virDomainPtr domain);
char **xenDaemonListDomainsOld(virConnectPtr xend);
NULL, /* domainPinVcpu */
NULL, /* domainGetVcpus */
NULL, /* domainGetMaxVcpus */
- xenXMDomainDumpXML, /* domainDumpXML */
xenXMListDefinedDomains, /* listDefinedDomains */
xenXMNumOfDefinedDomains, /* numOfDefinedDomains */
xenXMDomainCreate, /* domainCreate */
val = MIN_XEN_GUEST_SIZE * 2;
virBufferVSprintf(buf, " <memory>%ld</memory>\n", val * 1024);
+ virBufferVSprintf(buf, " <vcpu"); /* DV */
+ if (xenXMConfigGetString(conf, "cpus", &str) == 0) {
+ char *ranges;
+ ranges = virConvertCpuSet(conn, str, 0);
+ if (ranges != NULL) {
+ virBufferVSprintf(buf, " cpuset='%s'", ranges);
+ free(ranges);
+ } else
+ virBufferVSprintf(buf, " cpuset='%s'", str);
+ }
if (xenXMConfigGetInt(conf, "vcpus", &val) < 0)
val = 1;
- virBufferVSprintf(buf, " <vcpu>%ld</vcpu>\n", val);
-
+ virBufferVSprintf(buf, ">%ld</vcpu>\n", val);
if (xenXMConfigGetString(conf, "on_poweroff", &str) < 0)
str = "destroy";
virConfPtr conf = NULL;
int hvm = 0, i;
xenUnifiedPrivatePtr priv;
+ char *cpus;
doc = xmlReadDoc((const xmlChar *) xml, "domain.xml", NULL,
XML_PARSE_NOENT | XML_PARSE_NONET |
"cannot set vcpus config parameter") < 0)
goto error;
+ cpus = virXPathString("string(/domain/vcpu/@cpuset)", ctxt);
+ if (cpus != NULL) {
+ char *ranges;
+
+ ranges = virConvertCpuSet(conn, cpus, 0);
+ if (ranges != NULL) {
+ free(cpus);
+ if (xenXMConfigSetString(conf, "cpus", ranges) < 0) {
+ free(ranges);
+ goto error;
+ }
+ free(ranges);
+ } else {
+ if (xenXMConfigSetString(conf, "cpus", cpus) < 0) {
+ free(cpus);
+ goto error;
+ }
+ free(cpus);
+ }
+ }
+
+ if (xenXMConfigSetStringFromXPath(conn, conf, ctxt, "cpus", /* DV */
+ "string(/domain/vcpu/@cpuset)", 1,
+ "cannot set the cpuset parameter") < 0)
+ goto error;
+
obj = xmlXPathEval(BAD_CAST "string(/domain/os/type)", ctxt);
if ((obj != NULL) && (obj->type == XPATH_STRING) &&
(obj->stringval != NULL) && !strcmp((char*)obj->stringval, "hvm"))
}
/**
- * saveCpuSet:
+ * virSaveCpuSet:
* @conn: connection
* @cpuset: pointer to a char array for the CPU set
* @maxcpu: number of elements available in @cpuset
* Returns the new string NULL in case of error. The string need to be
* freed by the caller.
*/
-static char *
-saveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu)
+char *
+virSaveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu)
{
virBufferPtr buf;
char *ret;
first = 0;
if (cur == start + 1)
virBufferVSprintf(buf, "%d", start);
- else if (cur == start + 2)
- virBufferVSprintf(buf, "%d,%d", start, cur - 1);
else
virBufferVSprintf(buf, "%d-%d", start, cur - 1);
start = -1;
virBufferAdd(buf, ",", -1);
if (maxcpu == start + 1)
virBufferVSprintf(buf, "%d", start);
- else if (maxcpu == start + 2)
- virBufferVSprintf(buf, "%d,%d", start, maxcpu - 1);
else
virBufferVSprintf(buf, "%d-%d", start, maxcpu - 1);
}
/**
* virParseCpuSet:
+ * @conn: connection
* @str: pointer to a CPU set string pointer
* @sep: potential character used to mark the end of string if not 0
* @cpuset: pointer to a char array for the CPU set
/**
* virParseXenCpuTopology:
+ * @conn: connection
* @xml: XML output buffer
* @str: the topology string
* @maxcpu: number of elements available in @cpuset
{
char *dump;
- dump = saveCpuSet(conn, cpuset, maxcpu);
+ dump = virSaveCpuSet(conn, cpuset, maxcpu);
if (dump != NULL) {
virBufferVSprintf(xml, " <dump>%s</dump>\n",
dump);
return (-1);
}
+/**
+ * virConvertCpuSet:
+ * @conn: connection
+ * @str: pointer to a Xen or user provided CPU set string pointer
+ * @maxcpu: number of CPUs on the node, if 0 4096 will be used
+ *
+ * Parse the given CPU set string and convert it to a range based
+ * string.
+ *
+ * Returns a new string which must be freed by the caller or NULL in
+ * case of error.
+ */
+char *
+virConvertCpuSet(virConnectPtr conn, const char *str, int maxcpu) {
+ int ret;
+ char *res, *cpuset;
+ const char *cur = str;
+
+ if (str == NULL)
+ return(NULL);
+
+ if (maxcpu <= 0)
+ maxcpu = 4096;
+
+ cpuset = calloc(maxcpu, sizeof(char));
+ if (cpuset == NULL) {
+ virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 0);
+ return(NULL);
+ }
+
+ ret = virParseCpuSet(conn, &cur, 0, cpuset, maxcpu);
+ if (ret < 0) {
+ free(cpuset);
+ return(NULL);
+ }
+ res = virSaveCpuSet(conn, cpuset, maxcpu);
+ free(cpuset);
+ return (res);
+}
#ifndef PROXY
/************************************************************************
if (cpuset != NULL) {
res = virParseCpuSet(conn, &cur, 0, cpuset, maxcpu);
if (res > 0) {
- ranges = saveCpuSet(conn, cpuset, maxcpu);
+ ranges = virSaveCpuSet(conn, cpuset, maxcpu);
if (ranges != NULL) {
virBufferVSprintf(&buf, "(cpus '%s')", ranges);
free(ranges);
char sep,
char *cpuset,
int maxcpu);
+char * virSaveCpuSet (virConnectPtr conn,
+ char *cpuset,
+ int maxcpu);
+char * virConvertCpuSet(virConnectPtr conn,
+ const char *str,
+ int maxcpu);
char * virDomainParseXMLDesc(virConnectPtr conn,
const char *xmldesc,
char **name,