Signed-off-by: Jiri Denemark <jdenemar@xxxxxxxxxx> --- include/libvirt/virterror.h | 1 + src/Makefile.am | 9 +- src/conf/capabilities.c | 31 ++++- src/conf/capabilities.h | 6 + src/conf/cpu_conf.c | 345 +++++++++++++++++++++++++++++++++++++++++++ src/conf/cpu_conf.h | 110 ++++++++++++++ src/conf/domain_conf.c | 15 ++ src/conf/domain_conf.h | 2 + src/libvirt_private.syms | 8 + src/util/virterror.c | 3 + 10 files changed, 527 insertions(+), 3 deletions(-) create mode 100644 src/conf/cpu_conf.c create mode 100644 src/conf/cpu_conf.h diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index fa5cac4..4f819b2 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -68,6 +68,7 @@ typedef enum { VIR_FROM_ESX, /* Error from ESX driver */ VIR_FROM_PHYP, /* Error from IBM power hypervisor */ VIR_FROM_SECRET, /* Error from secret storage */ + VIR_FROM_CPU, /* Error from CPU driver */ } virErrorDomain; diff --git a/src/Makefile.am b/src/Makefile.am index 8e27ea7..17ed03f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,6 +110,9 @@ NODE_DEVICE_CONF_SOURCES = \ ENCRYPTION_CONF_SOURCES = \ conf/storage_encryption_conf.c conf/storage_encryption_conf.h +CPU_CONF_SOURCES = \ + conf/cpu_conf.c conf/cpu_conf.h + CONF_SOURCES = \ $(DOMAIN_CONF_SOURCES) \ $(DOMAIN_EVENT_SOURCES) \ @@ -118,7 +121,8 @@ CONF_SOURCES = \ $(STORAGE_CONF_SOURCES) \ $(ENCRYPTION_CONF_SOURCES) \ $(INTERFACE_CONF_SOURCES) \ - $(SECRET_CONF_SOURCES) + $(SECRET_CONF_SOURCES) \ + $(CPU_CONF_SOURCES) # The remote RPC driver, covering domains, storage, networks, etc REMOTE_DRIVER_SOURCES = \ @@ -819,7 +823,8 @@ libvirt_lxc_SOURCES = \ $(UTIL_SOURCES) \ $(NODE_INFO_SOURCES) \ $(ENCRYPTION_CONF_SOURCES) \ - $(DOMAIN_CONF_SOURCES) + $(DOMAIN_CONF_SOURCES) \ + $(CPU_CONF_SOURCES) libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS) libvirt_lxc_LDADD = $(LIBXML_LIBS) $(NUMACTL_LIBS) ../gnulib/lib/libgnu.la libvirt_lxc_CFLAGS = \ diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 6ebddf5..98d7b0e 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -27,6 +27,7 @@ #include "buf.h" #include "memory.h" #include "util.h" +#include "cpu_conf.h" /** * virCapabilitiesNew: @@ -171,6 +172,8 @@ virCapabilitiesFree(virCapsPtr caps) { VIR_FREE(caps->host.arch); VIR_FREE(caps->host.secModel.model); VIR_FREE(caps->host.secModel.doi); + virCPUDefFree(caps->host.cpu); + VIR_FREE(caps); } @@ -263,6 +266,27 @@ virCapabilitiesAddHostNUMACell(virCapsPtr caps, return 0; } + +/** + * virCapabilitiesSetHostCPU: + * @caps: capabilities to extend + * @cpu: CPU definition + * + * Sets host CPU specification + */ +int +virCapabilitiesSetHostCPU(virCapsPtr caps, + virCPUDefPtr cpu) +{ + if (cpu == NULL) + return -1; + + caps->host.cpu = cpu; + + return 0; +} + + /** * virCapabilitiesAllocMachines: * @machines: machine variants for emulator ('pc', or 'isapc', etc) @@ -653,6 +677,10 @@ virCapabilitiesFormatXML(virCapsPtr caps) } virBufferAddLit(&xml, " </features>\n"); } + + virCPUDefFormatBuf(NULL, &xml, caps->host.cpu, " ", + VIR_CPU_FORMAT_EMBEDED); + virBufferAddLit(&xml, " </cpu>\n"); if (caps->host.offlineMigrate) { @@ -750,7 +778,8 @@ virCapabilitiesFormatXML(virCapsPtr caps) for (j = 0 ; j < caps->guests[i]->nfeatures ; j++) { if (STREQ(caps->guests[i]->features[j]->name, "pae") || STREQ(caps->guests[i]->features[j]->name, "nonpae") || - STREQ(caps->guests[i]->features[j]->name, "ia64_be")) { + STREQ(caps->guests[i]->features[j]->name, "ia64_be") || + STREQ(caps->guests[i]->features[j]->name, "cpu")) { virBufferVSprintf(&xml, " <%s/>\n", caps->guests[i]->features[j]->name); } else { diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index 2f24605..48e293c 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -26,6 +26,7 @@ #include "internal.h" #include "util.h" +#include "cpu_conf.h" typedef struct _virCapsGuestFeature virCapsGuestFeature; typedef virCapsGuestFeature *virCapsGuestFeaturePtr; @@ -105,6 +106,7 @@ struct _virCapsHost { int nnumaCell; virCapsHostNUMACellPtr *numaCell; virCapsHostSecModel secModel; + virCPUDefPtr cpu; }; typedef struct _virCaps virCaps; @@ -159,6 +161,10 @@ virCapabilitiesAddHostNUMACell(virCapsPtr caps, const int *cpus); +extern int +virCapabilitiesSetHostCPU(virCapsPtr caps, + virCPUDefPtr cpu); + extern virCapsGuestMachinePtr * virCapabilitiesAllocMachines(const char *const *names, diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c new file mode 100644 index 0000000..3c100ee --- /dev/null +++ b/src/conf/cpu_conf.c @@ -0,0 +1,345 @@ +/* + * cpu_conf.h: CPU XML handling + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Jiri Denemark <jdenemar@xxxxxxxxxx> + */ + +#include <config.h> + +#include "c-ctype.h" +#include "virterror_internal.h" +#include "memory.h" +#include "util.h" +#include "buf.h" +#include "cpu_conf.h" + +#define VIR_FROM_THIS VIR_FROM_CPU + +#define virCPUReportError(conn, code, fmt...) \ + virReportErrorHelper(conn, VIR_FROM_CPU, code, __FILE__, \ + __FUNCTION__, __LINE__, fmt) + +VIR_ENUM_IMPL(virCPUMatch, VIR_CPU_MATCH_LAST, + "minimum", + "exact", + "strict") + +VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST, + "force", + "require", + "optional", + "disable", + "forbid") + + +void +virCPUDefFree(virCPUDefPtr def) +{ + unsigned int i; + + if (!def) + return; + + VIR_FREE(def->model); + VIR_FREE(def->arch); + + for (i = 0 ; i < def->nfeatures ; i++) + VIR_FREE(def->features[i].name); + VIR_FREE(def->features); + + VIR_FREE(def); +} + + +virCPUDefPtr +virCPUDefParseXML(virConnectPtr conn, + const xmlNodePtr node, + xmlXPathContextPtr ctxt, + enum virCPUType mode) +{ + virCPUDefPtr def; + xmlNodePtr *nodes = NULL; + char *match; + int n; + unsigned int i; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(conn); + return NULL; + } + + match = virXMLPropString(node, "match"); + + if (mode == VIR_CPU_TYPE_AUTO) + def->type = (match == NULL) ? VIR_CPU_TYPE_HOST : VIR_CPU_TYPE_GUEST; + else + def->type = mode; + + if (def->type == VIR_CPU_TYPE_GUEST) { + if ((def->match = virCPUMatchTypeFromString(match)) < 0) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid match attribute for CPU specification")); + goto error; + } + } + + if (def->type == VIR_CPU_TYPE_HOST) { + def->arch = virXPathString(conn, "string(./arch[1])", ctxt); + if (!def->arch) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU architecture")); + goto error; + } + } + + if (!(def->model = virXPathString(conn, "string(./model[1])", ctxt))) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU model name")); + goto error; + } + + if (virXPathNode(conn, "./topology[1]", ctxt)) { + int ret; + unsigned long ul; + int all_zero; + + ret = virXPathULong(conn, "string(./topology[1]/@sockets)", + ctxt, &ul); + if (ret < 0) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing 'sockets' attribute in CPU topology")); + goto error; + } + def->sockets = (unsigned int) ul; + all_zero = !def->sockets; + + ret = virXPathULong(conn, "string(./topology[1]/@cores)", + ctxt, &ul); + if (ret < 0) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing 'cores' attribute in CPU topology")); + goto error; + } + def->cores = (unsigned int) ul; + all_zero &= !def->cores; + + ret = virXPathULong(conn, "string(./topology[1]/@threads)", + ctxt, &ul); + if (ret < 0) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing 'threads' attribute in CPU topology")); + goto error; + } + def->threads = (unsigned int) ul; + all_zero &= !def->threads; + + /* + * sockets, cores, and threads must all be either zero or nonzero; + * if all of them are zero, we don't care about topology + */ + if ((!def->sockets || !def->cores || !def->threads) && !all_zero) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid CPU topology")); + goto error; + } + } + + n = virXPathNodeSet(conn, "./feature", ctxt, &nodes); + if (n < 0) + goto error; + + if (n > 0) { + if (VIR_ALLOC_N(def->features, n) < 0) + goto no_memory; + def->nfeatures = n; + } + + for (i = 0 ; i < n ; i++) { + char *name; + int policy; /* enum virDomainCPUFeaturePolicy */ + unsigned int j; + unsigned int len; + + if (def->type == VIR_CPU_TYPE_GUEST) { + char *strpolicy; + + strpolicy = virXMLPropString(nodes[i], "policy"); + policy = virCPUFeaturePolicyTypeFromString(strpolicy); + VIR_FREE(strpolicy); + + if (policy < 0) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid CPU feature policy")); + goto error; + } + } + else + policy = -1; + + if (!(name = (char *) xmlNodeGetContent(nodes[i])) + || *name == 0) { + VIR_FREE(name); + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid CPU feature name")); + goto error; + } + + len = strlen(name); + for (j = 0 ; j < len ; j++) + name[j] = c_tolower(name[j]); + + for (j = 0 ; j < i ; j++) { + if (STREQ(name, def->features[j].name)) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("CPU feature `%s' specified more than once"), + name); + VIR_FREE(name); + goto error; + } + } + + def->features[i].name = name; + def->features[i].policy = policy; + } + +cleanup: + VIR_FREE(match); + VIR_FREE(nodes); + + return def; + +no_memory: + virReportOOMError(conn); + +error: + virCPUDefFree(def); + def = NULL; + goto cleanup; +} + + +char * +virCPUDefFormat(virConnectPtr conn, + virCPUDefPtr def, + const char *indent, + int flags) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *tmp; + + if (virCPUDefFormatBuf(conn, &buf, def, indent, flags) < 0) + goto cleanup; + + if (virBufferError(&buf)) + goto no_memory; + + return virBufferContentAndReset(&buf); + +no_memory: + virReportOOMError(conn); +cleanup: + tmp = virBufferContentAndReset(&buf); + VIR_FREE(tmp); + return NULL; +} + + +int +virCPUDefFormatBuf(virConnectPtr conn, + virBufferPtr buf, + virCPUDefPtr def, + const char *indent, + int flags) +{ + unsigned int i; + + if (!def) + return 0; + + if (indent == NULL) + indent = ""; + + if (!def->model) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU model")); + return -1; + } + + if (!(flags & VIR_CPU_FORMAT_EMBEDED)) { + if (def->type == VIR_CPU_TYPE_GUEST) { + const char *match; + if (!(match = virCPUMatchTypeToString(def->match))) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("Unexpected CPU match policy %d"), def->match); + return -1; + } + + virBufferVSprintf(buf, "%s<cpu match='%s'>\n", indent, match); + } + else + virBufferVSprintf(buf, "%s<cpu>\n", indent); + + if (def->arch) + virBufferVSprintf(buf, "%s <arch>%s</arch>\n", indent, def->arch); + } + + virBufferVSprintf(buf, "%s <model>%s</model>\n", indent, def->model); + + if (def->sockets && def->cores && def->threads) { + virBufferVSprintf(buf, "%s <topology", indent); + virBufferVSprintf(buf, " sockets='%u'", def->sockets); + virBufferVSprintf(buf, " cores='%u'", def->cores); + virBufferVSprintf(buf, " threads='%u'", def->threads); + virBufferAddLit(buf, "/>\n"); + } + + for (i = 0 ; i < def->nfeatures ; i++) { + virCPUFeatureDefPtr feature = def->features + i; + + if (!feature->name) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU feature name")); + return -1; + } + + if (def->type == VIR_CPU_TYPE_GUEST) { + const char *policy; + + policy = virCPUFeaturePolicyTypeToString(feature->policy); + if (!policy) { + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("Unexpected CPU feature policy %d"), feature->policy); + return -1; + } + virBufferVSprintf(buf, "%s <feature policy='%s'>%s</feature>\n", + indent, policy, feature->name); + } + else { + virBufferVSprintf(buf, "%s <feature>%s</feature>\n", + indent, feature->name); + } + } + + if (!(flags & VIR_CPU_FORMAT_EMBEDED)) + virBufferVSprintf(buf, "%s</cpu>\n", indent); + + return 0; +} + diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h new file mode 100644 index 0000000..3629d90 --- /dev/null +++ b/src/conf/cpu_conf.h @@ -0,0 +1,110 @@ +/* + * cpu_conf.h: CPU XML handling + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Jiri Denemark <jdenemar@xxxxxxxxxx> + */ + +#ifndef __VIR_CPU_CONF_H__ +#define __VIR_CPU_CONF_H__ + +#include "util.h" +#include "buf.h" +#include "xml.h" + + +enum virCPUType { + VIR_CPU_TYPE_HOST, + VIR_CPU_TYPE_GUEST, + VIR_CPU_TYPE_AUTO +}; + +enum virCPUMatch { + VIR_CPU_MATCH_MINIMUM, + VIR_CPU_MATCH_EXACT, + VIR_CPU_MATCH_STRICT, + + VIR_CPU_MATCH_LAST +}; + +VIR_ENUM_DECL(virCPUMatch) + +enum virCPUFeaturePolicy { + VIR_CPU_FEATURE_FORCE, + VIR_CPU_FEATURE_REQUIRE, + VIR_CPU_FEATURE_OPTIONAL, + VIR_CPU_FEATURE_DISABLE, + VIR_CPU_FEATURE_FORBID, + + VIR_CPU_FEATURE_LAST +}; + +VIR_ENUM_DECL(virCPUFeaturePolicy) + +typedef struct _virCPUFeatureDef virCPUFeatureDef; +typedef virCPUFeatureDef *virCPUFeatureDefPtr; +struct _virCPUFeatureDef { + char *name; + int policy; /* enum virCPUFeaturePolicy */ +}; + +typedef struct _virCPUDef virCPUDef; +typedef virCPUDef *virCPUDefPtr; +struct _virCPUDef { + int type; /* enum virCPUType */ + int match; /* enum virCPUMatch */ + char *arch; + char *model; + unsigned int sockets; + unsigned int cores; + unsigned int threads; + unsigned int nfeatures; + virCPUFeatureDefPtr features; +}; + + +void +virCPUDefFree(virCPUDefPtr def); + +virCPUDefPtr +virCPUDefParseXML(virConnectPtr conn, + const xmlNodePtr node, + xmlXPathContextPtr ctxt, + enum virCPUType mode); + +enum virCPUFormatFlags { + VIR_CPU_FORMAT_EMBEDED = (1 << 0) /* embed into existing <cpu/> element + * in host capabilities */ +}; + + +char * +virCPUDefFormat(virConnectPtr conn, + virCPUDefPtr def, + const char *indent, + int flags); + +int +virCPUDefFormatBuf(virConnectPtr conn, + virBufferPtr buf, + virCPUDefPtr def, + const char *indent, + int flags); + +#endif /* __VIR_CPU_CONF_H__ */ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index de07e13..5a62712 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -577,6 +577,8 @@ void virDomainDefFree(virDomainDefPtr def) virSecurityLabelDefFree(def); + virCPUDefFree(def->cpu); + VIR_FREE(def); } @@ -3160,6 +3162,16 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn, if (virSecurityLabelDefParseXML(conn, def, ctxt, flags) == -1) goto error; + if ((node = virXPathNode(conn, "./cpu[1]", ctxt)) != NULL) { + xmlNodePtr oldnode = ctxt->node; + ctxt->node = node; + def->cpu = virCPUDefParseXML(conn, node, ctxt, VIR_CPU_TYPE_GUEST); + ctxt->node = oldnode; + + if (def->cpu == NULL) + goto error; + } + return def; no_memory: @@ -4452,6 +4464,9 @@ char *virDomainDefFormat(virConnectPtr conn, virBufferAddLit(&buf, " </features>\n"); } + if (virCPUDefFormatBuf(conn, &buf, def->cpu, " ", 0) < 0) + goto cleanup; + virBufferVSprintf(&buf, " <clock offset='%s'/>\n", def->localtime ? "localtime" : "utc"); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 389e259..5ff4330 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -31,6 +31,7 @@ #include "internal.h" #include "capabilities.h" #include "storage_encryption_conf.h" +#include "cpu_conf.h" #include "util.h" #include "threads.h" #include "hash.h" @@ -614,6 +615,7 @@ struct _virDomainDef { virDomainChrDefPtr console; virSecurityLabelDef seclabel; virDomainWatchdogDefPtr watchdog; + virCPUDefPtr cpu; }; /* Guest VM runtime state */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3997704..e668d4b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -33,6 +33,7 @@ virCapabilitiesSetEmulatorRequired; virCapabilitiesIsEmulatorRequired; virCapabilitiesAllocMachines; virCapabilitiesFreeMachines; +virCapabilitiesSetHostCPU; # conf.h @@ -84,6 +85,13 @@ virGetStream; virUnrefStream; +# cpu_conf.h +virCPUDefFree; +virCPUDefParseXML; +virCPUDefFormat; +virCPUDefFormatBuf; + + # domain_conf.h virDiskNameToBusDeviceIndex; virDiskNameToIndex; diff --git a/src/util/virterror.c b/src/util/virterror.c index 10f979c..ff863ea 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -172,6 +172,9 @@ static const char *virErrorDomainName(virErrorDomain domain) { case VIR_FROM_SECRET: dom = "Secret Storage "; break; + case VIR_FROM_CPU: + dom = "CPU "; + break; } return(dom); } -- 1.6.5.2 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list