Add flag to BaselineCPU API to return detailed CPU features

Currently the virConnectBaselineCPU API does not expose the CPU features
that are part of the CPU's model.  This patch adds a new flag,
VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, that causes the API to explicitly
list all features that are part of that model.

Signed-off-by: Don Dugger <donald.d.dugger@intel.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Don Dugger 2013-08-02 13:08:19 -06:00 committed by Eric Blake
parent 10ec64105b
commit d4952d36d0
15 changed files with 167 additions and 39 deletions

View File

@ -4007,6 +4007,15 @@ int virConnectCompareCPU(virConnectPtr conn,
unsigned int flags);
/**
* virConnectBaselineCPUFlags
*
* Flags when getting XML description of a computed CPU
*/
typedef enum {
VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES = (1 << 0), /* show all features */
} virConnectBaselineCPUFlags;
/**
* virConnectBaselineCPU:
*

View File

@ -167,7 +167,7 @@ cpuDecode(virCPUDefPtr cpu,
return -1;
}
return driver->decode(cpu, data, models, nmodels, preferred);
return driver->decode(cpu, data, models, nmodels, preferred, 0);
}
@ -276,7 +276,8 @@ char *
cpuBaselineXML(const char **xmlCPUs,
unsigned int ncpus,
const char **models,
unsigned int nmodels)
unsigned int nmodels,
unsigned int flags)
{
xmlDocPtr doc = NULL;
xmlXPathContextPtr ctxt = NULL;
@ -323,7 +324,7 @@ cpuBaselineXML(const char **xmlCPUs,
doc = NULL;
}
if (!(cpu = cpuBaseline(cpus, ncpus, models, nmodels)))
if (!(cpu = cpuBaseline(cpus, ncpus, models, nmodels, flags)))
goto error;
cpustr = virCPUDefFormat(cpu, 0);
@ -350,7 +351,8 @@ virCPUDefPtr
cpuBaseline(virCPUDefPtr *cpus,
unsigned int ncpus,
const char **models,
unsigned int nmodels)
unsigned int nmodels,
unsigned int flags)
{
struct cpuArchDriver *driver;
size_t i;
@ -392,7 +394,7 @@ cpuBaseline(virCPUDefPtr *cpus,
return NULL;
}
return driver->baseline(cpus, ncpus, models, nmodels);
return driver->baseline(cpus, ncpus, models, nmodels, flags);
}

View File

@ -53,7 +53,8 @@ typedef int
const virCPUDataPtr data,
const char **models,
unsigned int nmodels,
const char *preferred);
const char *preferred,
unsigned int flags);
typedef int
(*cpuArchEncode) (virArch arch,
@ -81,7 +82,8 @@ typedef virCPUDefPtr
(*cpuArchBaseline) (virCPUDefPtr *cpus,
unsigned int ncpus,
const char **models,
unsigned int nmodels);
unsigned int nmodels,
unsigned int flags);
typedef int
(*cpuArchUpdate) (virCPUDefPtr guest,
@ -149,13 +151,15 @@ extern char *
cpuBaselineXML(const char **xmlCPUs,
unsigned int ncpus,
const char **models,
unsigned int nmodels);
unsigned int nmodels,
unsigned int flags);
extern virCPUDefPtr
cpuBaseline (virCPUDefPtr *cpus,
unsigned int ncpus,
const char **models,
unsigned int nmodels);
unsigned int nmodels,
unsigned int flags);
extern int
cpuUpdate (virCPUDefPtr guest,

View File

@ -44,8 +44,12 @@ ArmDecode(virCPUDefPtr cpu ATTRIBUTE_UNUSED,
const virCPUDataPtr data ATTRIBUTE_UNUSED,
const char **models ATTRIBUTE_UNUSED,
unsigned int nmodels ATTRIBUTE_UNUSED,
const char *preferred ATTRIBUTE_UNUSED)
const char *preferred ATTRIBUTE_UNUSED,
unsigned int flags)
{
virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1);
return 0;
}

View File

@ -113,7 +113,8 @@ static virCPUDefPtr
genericBaseline(virCPUDefPtr *cpus,
unsigned int ncpus,
const char **models,
unsigned int nmodels)
unsigned int nmodels,
unsigned int flags)
{
virCPUDefPtr cpu = NULL;
virCPUFeatureDefPtr features = NULL;
@ -121,6 +122,8 @@ genericBaseline(virCPUDefPtr *cpus,
unsigned int count;
size_t i, j;
virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
if (!cpuModelIsAllowed(cpus[0]->model, models, nmodels)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("CPU model %s is not supported by hypervisor"),

View File

@ -304,12 +304,15 @@ ppcDecode(virCPUDefPtr cpu,
const virCPUDataPtr data,
const char **models,
unsigned int nmodels,
const char *preferred ATTRIBUTE_UNUSED)
const char *preferred ATTRIBUTE_UNUSED,
unsigned int flags)
{
int ret = -1;
struct ppc_map *map;
const struct ppc_model *model;
virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1);
if (data == NULL || (map = ppcLoadMap()) == NULL)
return -1;
@ -377,7 +380,8 @@ static virCPUDefPtr
ppcBaseline(virCPUDefPtr *cpus,
unsigned int ncpus,
const char **models,
unsigned int nmodels)
unsigned int nmodels,
unsigned int flags)
{
struct ppc_map *map = NULL;
const struct ppc_model *model;
@ -385,6 +389,8 @@ ppcBaseline(virCPUDefPtr *cpus,
virCPUDefPtr cpu = NULL;
size_t i;
virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
if (!(map = ppcLoadMap()))
goto error;

View File

@ -48,8 +48,12 @@ s390Decode(virCPUDefPtr cpu ATTRIBUTE_UNUSED,
const virCPUDataPtr data ATTRIBUTE_UNUSED,
const char **models ATTRIBUTE_UNUSED,
unsigned int nmodels ATTRIBUTE_UNUSED,
const char *preferred ATTRIBUTE_UNUSED)
const char *preferred ATTRIBUTE_UNUSED,
unsigned int flags)
{
virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1);
return 0;
}

View File

@ -1319,13 +1319,42 @@ x86GuestData(virCPUDefPtr host,
return x86Compute(host, guest, data, message);
}
static int
x86AddFeatures(virCPUDefPtr cpu,
struct x86_map *map)
{
const struct x86_model *candidate;
const struct x86_feature *feature = map->features;
candidate = map->models;
while (candidate != NULL) {
if (STREQ(cpu->model, candidate->name))
break;
candidate = candidate->next;
}
if (!candidate) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("%s not a known CPU model"), cpu->model);
return -1;
}
while (feature != NULL) {
if (x86DataIsSubset(candidate->data, feature->data) &&
virCPUDefAddFeature(cpu, feature->name,
VIR_CPU_FEATURE_REQUIRE) < 0)
return -1;
feature = feature->next;
}
return 0;
}
static int
x86Decode(virCPUDefPtr cpu,
const struct cpuX86Data *data,
const char **models,
unsigned int nmodels,
const char *preferred)
const char *preferred,
unsigned int flags)
{
int ret = -1;
struct x86_map *map;
@ -1334,6 +1363,8 @@ x86Decode(virCPUDefPtr cpu,
virCPUDefPtr cpuModel = NULL;
size_t i;
virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1);
if (data == NULL || (map = x86LoadMap()) == NULL)
return -1;
@ -1406,6 +1437,9 @@ x86Decode(virCPUDefPtr cpu,
goto out;
}
if (flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES &&
x86AddFeatures(cpuModel, map) < 0)
goto out;
cpu->model = cpuModel->model;
cpu->vendor = cpuModel->vendor;
cpu->nfeatures = cpuModel->nfeatures;
@ -1426,9 +1460,10 @@ x86DecodeCPUData(virCPUDefPtr cpu,
const virCPUDataPtr data,
const char **models,
unsigned int nmodels,
const char *preferred)
const char *preferred,
unsigned int flags)
{
return x86Decode(cpu, data->data.x86, models, nmodels, preferred);
return x86Decode(cpu, data->data.x86, models, nmodels, preferred, flags);
}
@ -1674,7 +1709,8 @@ static virCPUDefPtr
x86Baseline(virCPUDefPtr *cpus,
unsigned int ncpus,
const char **models,
unsigned int nmodels)
unsigned int nmodels,
unsigned int flags)
{
struct x86_map *map = NULL;
struct x86_model *base_model = NULL;
@ -1755,7 +1791,7 @@ x86Baseline(virCPUDefPtr *cpus,
if (vendor && x86DataAddCpuid(base_model->data, &vendor->cpuid) < 0)
goto error;
if (x86Decode(cpu, base_model->data, models, nmodels, NULL) < 0)
if (x86Decode(cpu, base_model->data, models, nmodels, NULL, flags) < 0)
goto error;
if (!outputVendor)

View File

@ -18524,11 +18524,16 @@ error:
* @conn: virConnect connection
* @xmlCPUs: array of XML descriptions of host CPUs
* @ncpus: number of CPUs in xmlCPUs
* @flags: extra flags; not used yet, so callers should always pass 0
* @flags: bitwise-OR of virConnectBaselineCPUFlags
*
* Computes the most feature-rich CPU which is compatible with all given
* host CPUs.
*
* If @flags includes VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES then libvirt
* will explicitly list all CPU features that are part of the host CPU,
* without this flag features that are part of the CPU model will not be
* listed.
*
* Returns XML description of the computed CPU or NULL on error.
*/
char *

View File

@ -11056,12 +11056,12 @@ qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
{
char *cpu = NULL;
virCheckFlags(0, NULL);
virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
if (virConnectBaselineCPUEnsureACL(conn) < 0)
goto cleanup;
cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0);
cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
cleanup:
return cpu;

View File

@ -75,6 +75,7 @@ struct data {
const char *modelsName;
unsigned int nmodels;
const char *preferred;
unsigned int flags;
int result;
};
@ -330,7 +331,7 @@ cpuTestBaseline(const void *arg)
if (!(cpus = cpuTestLoadMultiXML(data->arch, data->name, &ncpus)))
goto cleanup;
baseline = cpuBaseline(cpus, ncpus, NULL, 0);
baseline = cpuBaseline(cpus, ncpus, NULL, 0, data->flags);
if (data->result < 0) {
virResetLastError();
if (!baseline)
@ -510,12 +511,12 @@ mymain(void)
}
#define DO_TEST(arch, api, name, host, cpu, \
models, nmodels, preferred, result) \
models, nmodels, preferred, flags, result) \
do { \
static struct data data = { \
arch, api, host, cpu, models, \
models == NULL ? NULL : #models, \
nmodels, preferred, result \
nmodels, preferred, flags, result \
}; \
if (cpuTestRun(name, &data) < 0) \
ret = -1; \
@ -524,31 +525,31 @@ mymain(void)
#define DO_TEST_COMPARE(arch, host, cpu, result) \
DO_TEST(arch, API_COMPARE, \
host "/" cpu " (" #result ")", \
host, cpu, NULL, 0, NULL, result)
host, cpu, NULL, 0, NULL, 0, result)
#define DO_TEST_UPDATE(arch, host, cpu, result) \
do { \
DO_TEST(arch, API_UPDATE, \
cpu " on " host, \
host, cpu, NULL, 0, NULL, 0); \
host, cpu, NULL, 0, NULL, 0, 0); \
DO_TEST_COMPARE(arch, host, host "+" cpu, result); \
} while (0)
#define DO_TEST_BASELINE(arch, name, result) \
#define DO_TEST_BASELINE(arch, name, flags, result) \
DO_TEST(arch, API_BASELINE, name, NULL, "baseline-" name, \
NULL, 0, NULL, result)
NULL, 0, NULL, flags, result)
#define DO_TEST_HASFEATURE(arch, host, feature, result) \
DO_TEST(arch, API_HAS_FEATURE, \
host "/" feature " (" #result ")", \
host, feature, NULL, 0, NULL, result)
host, feature, NULL, 0, NULL, 0, result)
#define DO_TEST_GUESTDATA(arch, host, cpu, models, preferred, result) \
DO_TEST(arch, API_GUEST_DATA, \
host "/" cpu " (" #models ", pref=" #preferred ")", \
host, cpu, models, \
models == NULL ? 0 : sizeof(models) / sizeof(char *), \
preferred, result)
preferred, 0, result)
/* host to host comparison */
DO_TEST_COMPARE("x86", "host", "host", VIR_CPU_COMPARE_IDENTICAL);
@ -593,11 +594,12 @@ mymain(void)
DO_TEST_UPDATE("x86", "host", "host-passthrough", VIR_CPU_COMPARE_IDENTICAL);
/* computing baseline CPUs */
DO_TEST_BASELINE("x86", "incompatible-vendors", -1);
DO_TEST_BASELINE("x86", "no-vendor", 0);
DO_TEST_BASELINE("x86", "some-vendors", 0);
DO_TEST_BASELINE("x86", "1", 0);
DO_TEST_BASELINE("x86", "2", 0);
DO_TEST_BASELINE("x86", "incompatible-vendors", 0, -1);
DO_TEST_BASELINE("x86", "no-vendor", 0, 0);
DO_TEST_BASELINE("x86", "some-vendors", 0, 0);
DO_TEST_BASELINE("x86", "1", 0, 0);
DO_TEST_BASELINE("x86", "2", 0, 0);
DO_TEST_BASELINE("x86", "3", VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, 0);
/* CPU features */
DO_TEST_HASFEATURE("x86", "host", "vmx", YES);

View File

@ -0,0 +1,35 @@
<cpu mode='custom' match='exact'>
<model fallback='allow'>Westmere</model>
<feature policy='require' name='lahf_lm'/>
<feature policy='require' name='lm'/>
<feature policy='require' name='nx'/>
<feature policy='require' name='syscall'/>
<feature policy='require' name='aes'/>
<feature policy='require' name='popcnt'/>
<feature policy='require' name='sse4.2'/>
<feature policy='require' name='sse4.1'/>
<feature policy='require' name='cx16'/>
<feature policy='require' name='ssse3'/>
<feature policy='require' name='pni'/>
<feature policy='require' name='sse2'/>
<feature policy='require' name='sse'/>
<feature policy='require' name='fxsr'/>
<feature policy='require' name='mmx'/>
<feature policy='require' name='clflush'/>
<feature policy='require' name='pse36'/>
<feature policy='require' name='pat'/>
<feature policy='require' name='cmov'/>
<feature policy='require' name='mca'/>
<feature policy='require' name='pge'/>
<feature policy='require' name='mtrr'/>
<feature policy='require' name='sep'/>
<feature policy='require' name='apic'/>
<feature policy='require' name='cx8'/>
<feature policy='require' name='mce'/>
<feature policy='require' name='pae'/>
<feature policy='require' name='msr'/>
<feature policy='require' name='tsc'/>
<feature policy='require' name='pse'/>
<feature policy='require' name='de'/>
<feature policy='require' name='fpu'/>
</cpu>

View File

@ -0,0 +1,7 @@
<cpuTest>
<cpu>
<arch>x86_64</arch>
<model>Westmere</model>
<topology sockets='1' cores='2' threads='1'/>
</cpu>
</cpuTest>

View File

@ -6157,6 +6157,10 @@ static const vshCmdOptDef opts_cpu_baseline[] = {
.flags = VSH_OFLAG_REQ,
.help = N_("file containing XML CPU descriptions")
},
{.name = "features",
.type = VSH_OT_BOOL,
.help = N_("Show features that are part of the CPU model type")
},
{.name = NULL}
};
@ -6168,6 +6172,7 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd)
char *buffer;
char *result = NULL;
const char **list = NULL;
unsigned int flags = 0;
int count = 0;
xmlDocPtr xml = NULL;
@ -6177,6 +6182,9 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd)
virBuffer buf = VIR_BUFFER_INITIALIZER;
size_t i;
if (vshCommandOptBool(cmd, "features"))
flags |= VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES;
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
return false;
@ -6220,7 +6228,7 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd)
list[i] = vshStrdup(ctl, (const char *)xmlBufferContent(xml_buf));
}
result = virConnectBaselineCPU(ctl->conn, list, count, 0);
result = virConnectBaselineCPU(ctl->conn, list, count, flags);
if (result) {
vshPrint(ctl, "%s", result);

View File

@ -485,13 +485,16 @@ cell and the total free memory on the machine. Finally, with a
numeric argument or with --cellno plus a cell number it will display
the free memory for the specified cell only.
=item B<cpu-baseline> I<FILE>
=item B<cpu-baseline> I<FILE> [I<--features>]
Compute baseline CPU which will be supported by all host CPUs given in <file>.
The list of host CPUs is built by extracting all <cpu> elements from the
<file>. Thus, the <file> can contain either a set of <cpu> elements separated
by new lines or even a set of complete <capabilities> elements printed by
B<capabilities> command.
B<capabilities> command. If I<--features> is specified then the
resulting XML description will explicitly include all features that make
up the CPU, without this option features that are part of the CPU model
will not be listed in the XML description.
=item B<cpu-compare> I<FILE>