XML parsing/formating code for CPU flags

* include/libvirt/virterror.h src/util/virterror.c: add new domain
  VIR_FROM_CPU for errors
* src/conf/cpu_conf.c src/conf/cpu_conf.h: new parsing module
* src/Makefile.am proxy/Makefile.am: include new files
* src/conf/capabilities.[ch] src/conf/domain_conf.[ch]: reference
  new code
* src/libvirt_private.syms: private export of new entry points
This commit is contained in:
Jiri Denemark 2009-12-18 14:44:55 +01:00 committed by Daniel Veillard
parent 6df8b363f7
commit 6695818c03
11 changed files with 561 additions and 3 deletions

View File

@ -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;

View File

@ -25,6 +25,7 @@ libvirt_proxy_SOURCES = libvirt_proxy.c \
@top_srcdir@/src/conf/capabilities.c \
@top_srcdir@/src/conf/storage_encryption_conf.c \
@top_srcdir@/src/conf/domain_conf.c \
@top_srcdir@/src/conf/cpu_conf.c \
@top_srcdir@/src/xen/xend_internal.c \
@top_srcdir@/src/xen/xen_hypervisor.c \
@top_srcdir@/src/xen/sexpr.c \

View File

@ -114,6 +114,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) \
@ -122,7 +125,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 = \
@ -831,7 +835,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) $(YAJL_LIBS)
libvirt_lxc_LDADD = $(LIBXML_LIBS) $(NUMACTL_LIBS) ../gnulib/lib/libgnu.la
libvirt_lxc_CFLAGS = \

View File

@ -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 {

View File

@ -27,6 +27,7 @@
#include "internal.h"
#include "util.h"
#include "buf.h"
#include "cpu_conf.h"
#include <libxml/xpath.h>
@ -108,6 +109,7 @@ struct _virCapsHost {
int nnumaCell;
virCapsHostNUMACellPtr *numaCell;
virCapsHostSecModel secModel;
virCPUDefPtr cpu;
};
typedef struct _virCaps virCaps;
@ -166,6 +168,10 @@ virCapabilitiesAddHostNUMACell(virCapsPtr caps,
const int *cpus);
extern int
virCapabilitiesSetHostCPU(virCapsPtr caps,
virCPUDefPtr cpu);
extern virCapsGuestMachinePtr *
virCapabilitiesAllocMachines(const char *const *names,

368
src/conf/cpu_conf.c Normal file
View File

@ -0,0 +1,368 @@
/*
* 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);
}
#ifndef PROXY
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;
}
#endif
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;
}
int
virCPUDefAddFeature(virConnectPtr conn,
virCPUDefPtr def,
const char *name,
int policy)
{
int i;
for (i = 0 ; i < def->nfeatures ; i++) {
if (STREQ(name, def->features[i].name)) {
virCPUReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("CPU feature `%s' specified more than once"), name);
return -1;
}
}
if (VIR_REALLOC_N(def->features, def->nfeatures + 1) < 0)
goto no_memory;
if (def->type == VIR_CPU_TYPE_HOST)
policy = -1;
if (!(def->features[def->nfeatures].name = strdup(name)))
goto no_memory;
def->features[def->nfeatures].policy = policy;
def->nfeatures++;
return 0;
no_memory:
virReportOOMError(conn);
return -1;
}

119
src/conf/cpu_conf.h Normal file
View File

@ -0,0 +1,119 @@
/*
* 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"
#ifndef PROXY
#include "xml.h"
#endif
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);
#ifndef PROXY
virCPUDefPtr
virCPUDefParseXML(virConnectPtr conn,
const xmlNodePtr node,
xmlXPathContextPtr ctxt,
enum virCPUType mode);
#endif
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);
int
virCPUDefAddFeature(virConnectPtr conn,
virCPUDefPtr cpu,
const char *name,
int policy);
#endif /* __VIR_CPU_CONF_H__ */

View File

@ -601,6 +601,8 @@ void virDomainDefFree(virDomainDefPtr def)
virSecurityLabelDefFree(def);
virCPUDefFree(def->cpu);
VIR_FREE(def);
}
@ -3360,6 +3362,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:
@ -4660,6 +4672,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");

View File

@ -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"
@ -635,6 +636,7 @@ struct _virDomainDef {
virDomainChrDefPtr console;
virSecurityLabelDef seclabel;
virDomainWatchdogDefPtr watchdog;
virCPUDefPtr cpu;
};
/* Guest VM runtime state */

View File

@ -35,6 +35,7 @@ virCapabilitiesSetEmulatorRequired;
virCapabilitiesIsEmulatorRequired;
virCapabilitiesAllocMachines;
virCapabilitiesFreeMachines;
virCapabilitiesSetHostCPU;
# conf.h
@ -70,6 +71,14 @@ virCgroupGetFreezerState;
virCgroupSetFreezerState;
# cpu_conf.h
virCPUDefFree;
virCPUDefParseXML;
virCPUDefFormat;
virCPUDefFormatBuf;
virCPUDefAddFeature;
# datatypes.h
virGetDomain;
virGetInterface;

View File

@ -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);
}