[libvirt] [PATCH v2 0/2] CPU flags capabilities and domain configuration

Hi, These are two initial patches for CPU flags/masks support for libvirt. The first patch contains changes to schemas and describes semantics of new elements and attributes. The second patch introduces internal API functions for XML parsing and formating. Version 2 changes: - feature names moved to a 'name' attribute of 'feature' element - 'cpu' element in guest capabilities renamed as 'cpuselection' - topology attributes restricted to positiveInteger - move 'cpu' element above 'os' element in domain configuration schema - feature names restricted to [a-zA-Z0-9\-_]+ - feature names are not internally converted to lower case Jiri Denemark (2): XML schema for CPU flags XML parsing/formating code for CPU flags docs/schemas/capability.rng | 46 ++++++- docs/schemas/domain.rng | 62 ++++++++ include/libvirt/virterror.h | 1 + src/Makefile.am | 9 +- src/conf/capabilities.c | 31 ++++- src/conf/capabilities.h | 6 + src/conf/cpu_conf.c | 331 +++++++++++++++++++++++++++++++++++++++++++ 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 + 12 files changed, 620 insertions(+), 4 deletions(-) create mode 100644 src/conf/cpu_conf.c create mode 100644 src/conf/cpu_conf.h

Firstly, CPU topology and model with optional features have to be advertised in host capabilities: <host> <cpu> <arch>ARCHITECTURE</arch> <features> <!-- old-style features are here --> </features> <model>NAME</model> <topology sockets="S" cores="C" threads="T"/> <feature name="NAME"/> </cpu> ... </host> Secondly, drivers which support detailed CPU specification have to advertise it in guest capabilities: <guest> ... <features> <cpuselection/> </features> </guest> And finally, CPU may be configured in domain XML configuration: <domain> ... <cpu match="MATCH"> <model>NAME</model> <topology sockets="S" cores="C" threads="T"/> <feature policy="POLICY" name="NAME"/> </cpu> </domain> Where MATCH can be one of: - 'minimum' specified CPU is the minimum requested CPU - 'exact' disable all additional features provided by host CPU - 'strict' fail if host CPU doesn't exactly match POLICY can be one of: - 'force' turn on the feature, even if host doesn't have it - 'require' fail if host doesn't have the feature - 'optional' match host - 'disable' turn off the feature, even if host has it - 'forbid' fail if host has the feature 'force' and 'disable' policies turn on/off the feature regardless of its availability on host. 'force' is unlikely to be used but its there for completeness since Xen and VMWare allow it. 'require' and 'forbid' policies prevent a guest from being started on a host which doesn't/does have the feature. 'forbid' is for cases where you disable the feature but a guest may still try to access it anyway and you don't want it to succeed. 'optional' policy sets the feature according to its availability on host. When a guest is booted on a host that has the feature and then migrated to another host, the policy changes to 'require' as we can't take the feature away from a running guest. Default policy for features provided by host CPU but not specified in domain configuration is set using match attribute of cpu tag. If 'minimum' match is requested, additional features will be treated as if they were specified with 'optional' policy. 'exact' match implies 'disable' policy and 'strict' match stands for 'forbid' policy. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- docs/schemas/capability.rng | 46 +++++++++++++++++++++++++++++++- docs/schemas/domain.rng | 62 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletions(-) diff --git a/docs/schemas/capability.rng b/docs/schemas/capability.rng index 3e8944c..378652e 100644 --- a/docs/schemas/capability.rng +++ b/docs/schemas/capability.rng @@ -25,6 +25,9 @@ <optional> <ref name='cpufeatures'/> </optional> + <optional> + <ref name='cpuspec'/> + </optional> </element> <optional> <ref name='migration'/> @@ -67,6 +70,31 @@ </element> </define> + <define name='cpuspec'> + <element name='model'> + <text/> + </element> + <element name='topology'> + <attribute name='sockets'> + <ref name='positiveInteger'/> + </attribute> + <attribute name='cores'> + <ref name='positiveInteger'/> + </attribute> + <attribute name='threads'> + <ref name='positiveInteger'/> + </attribute> + </element> + <zeroOrMore> + <element name='feature'> + <attribute name='name'> + <ref name='featureName'/> + </attribute> + <empty/> + </element> + </zeroOrMore> + </define> + <define name='migration'> <element name='migration_features'> <optional> @@ -259,6 +287,11 @@ <empty/> </element> </optional> + <optional> + <element name='cpuselection'> + <empty/> + </element> + </optional> </element> </define> @@ -293,8 +326,14 @@ </define> + <define name='positiveInteger'> + <data type='positiveInteger'> + <param name="pattern">[0-9]+</param> + </data> + </define> + <define name='uint'> - <data type='string'> + <data type='unsignedInt'> <param name="pattern">[0-9]+</param> </data> </define> @@ -305,4 +344,9 @@ </data> </define> + <define name='featureName'> + <data type='string'> + <param name='pattern'>[a-zA-Z0-9\-_]+</param> + </data> + </define> </grammar> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index b75f17e..c004c52 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -27,6 +27,9 @@ <optional> <ref name="description"/> </optional> + <optional> + <ref name="cpu"/> + </optional> <ref name="os"/> <ref name="clock"/> <ref name="resources"/> @@ -1218,6 +1221,55 @@ </optional> </define> <!-- + CPU specification + --> + <define name="cpu"> + <element name="cpu"> + <attribute name="match"> + <choice> + <value>minimum</value> + <value>exact</value> + <value>strict</value> + </choice> + </attribute> + <interleave> + <element name="model"> + <text/> + </element> + <optional> + <element name="topology"> + <attribute name="sockets"> + <ref name="positiveInteger"/> + </attribute> + <attribute name="cores"> + <ref name="positiveInteger"/> + </attribute> + <attribute name="threads"> + <ref name="positiveInteger"/> + </attribute> + </element> + </optional> + <zeroOrMore> + <element name="feature"> + <attribute name="policy"> + <choice> + <value>force</value> + <value>require</value> + <value>optional</value> + <value>disable</value> + <value>forbid</value> + </choice> + </attribute> + <attribute name="name"> + <ref name="featureName"/> + </attribute> + <empty/> + </element> + </zeroOrMore> + </interleave> + </element> + </define> + <!-- Type library Our unsignedInt doesn't allow a leading '+' in its lexical form @@ -1230,6 +1282,11 @@ <param name="pattern">[0-9]+</param> </data> </define> + <define name='positiveInteger'> + <data type='positiveInteger'> + <param name="pattern">[0-9]+</param> + </data> + </define> <define name="countCPU"> <data type="unsignedShort"> <param name="pattern">[0-9]+</param> @@ -1337,4 +1394,9 @@ <param name="pattern">(0x)?[0-7]</param> </data> </define> + <define name="featureName"> + <data type="string"> + <param name='pattern'>[a-zA-Z0-9\-_]+</param> + </data> + </define> </grammar> -- 1.6.5.2

On 11/05/2009 05:04 PM, Jiri Denemark wrote:
Firstly, CPU topology and model with optional features have to be advertised in host capabilities:
<host> <cpu> <arch>ARCHITECTURE</arch> <features> <!-- old-style features are here --> </features> <model>NAME</model> <topology sockets="S" cores="C" threads="T"/> <feature name="NAME"/> </cpu> ... </host>
Secondly, drivers which support detailed CPU specification have to advertise it in guest capabilities:
<guest> ... <features> <cpuselection/> </features> </guest>
And finally, CPU may be configured in domain XML configuration:
<domain> ... <cpu match="MATCH"> <model>NAME</model>
Note that for qemu/kvm we plan of using the model only. The features (flags) below will be a function of the model used. Model is one of core2duo/Nehalem/Merom/...
<topology sockets="S" cores="C" threads="T"/> <feature policy="POLICY" name="NAME"/> </cpu> </domain>

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- include/libvirt/virterror.h | 1 + src/Makefile.am | 9 +- src/conf/capabilities.c | 31 ++++- src/conf/capabilities.h | 6 + src/conf/cpu_conf.c | 331 +++++++++++++++++++++++++++++++++++++++++++ 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, 513 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 70def38..1c981a7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -112,6 +112,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) \ @@ -120,7 +123,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 = \ @@ -823,7 +827,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..8f50009 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, "cpuselection")) { virBufferVSprintf(&xml, " <%s/>\n", caps->guests[i]->features[j]->name); } else { diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index 7234cf4..5e37032 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; @@ -161,6 +163,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..8fed691 --- /dev/null +++ b/src/conf/cpu_conf.c @@ -0,0 +1,331 @@ +/* + * 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@redhat.com> + */ + +#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; + + 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; + + 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; + + 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; + + if (!def->sockets || !def->cores || !def->threads) { + 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; + + 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 = virXMLPropString(nodes[i], "name")) || *name == 0) { + VIR_FREE(name); + virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid CPU feature name")); + goto error; + } + + 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' name='%s'/>\n", + indent, policy, feature->name); + } + else { + virBufferVSprintf(buf, "%s <feature name='%s'/>\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@redhat.com> + */ + +#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 94bce1e..830ff2b 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -597,6 +597,8 @@ void virDomainDefFree(virDomainDefPtr def) virSecurityLabelDefFree(def); + virCPUDefFree(def->cpu); + VIR_FREE(def); } @@ -3321,6 +3323,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: @@ -4662,6 +4674,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 e826cc7..049fb8a 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" @@ -633,6 +634,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 215addb..9ce1312 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
participants (2)
-
Dor Laor
-
Jiri Denemark