diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 52ac95d722a31d38e5f13dbf59349db5a0e325db..a47e33cc73affc348ad08c488142b22a05af919d 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -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:
*
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index 4124354e79b3381871567655638fee6f4e2d1c11..023ce2652a16c9413ecaae6706de62babd866120 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -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);
}
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index 40034350ae2e38dec72157a634532fb51b63f58d..7f1d4bd027326d9cd751d51a5e98ae0a4b9df66d 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -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,
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
index 25e25ba361da2f0f81cb466933093a26f6c39c1a..d1b2a99b17479f35198f4a0965b17722dfd34cda 100644
--- a/src/cpu/cpu_arm.c
+++ b/src/cpu/cpu_arm.c
@@ -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;
}
diff --git a/src/cpu/cpu_generic.c b/src/cpu/cpu_generic.c
index 2fe792ff63ba5805207ee01e46f5b972719c57a2..1264da4981932b069fba82003af3a032063a8543 100644
--- a/src/cpu/cpu_generic.c
+++ b/src/cpu/cpu_generic.c
@@ -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"),
diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c
index 55a41534897d58a959f2391ab773df135a8e4063..647a8a11e21104b919fff7748d5822f2075a205a 100644
--- a/src/cpu/cpu_powerpc.c
+++ b/src/cpu/cpu_powerpc.c
@@ -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;
diff --git a/src/cpu/cpu_s390.c b/src/cpu/cpu_s390.c
index cbfae427950945da3ac291b99ae6012aec43208a..d997e06d9ab55474f9c7c8bc2550d05e6bd7bb28 100644
--- a/src/cpu/cpu_s390.c
+++ b/src/cpu/cpu_s390.c
@@ -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;
}
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index a388f0f2b8b8590cbe83fb95aead70627bb6d8a0..41ce21fa7659ba9216251b8206f94b779f127807 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -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)
diff --git a/src/libvirt.c b/src/libvirt.c
index 66e82485ae2d22f842cb0f5e967aec2a8561b886..07a3fd50224fc1dedabde7fc0a0ff7cc8a8e21d0 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -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 *
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 2daafa8d16810e8191974488b87887ff18d1b68f..2ad236e0e187af04b8c0c08ae1c27ae1cbdcdba8 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -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;
diff --git a/tests/cputest.c b/tests/cputest.c
index 2e5f0cdfb86053a24d3bc0129d9f00de57a906ff..959cb9fdc47cc1489d0b29daea221f67a954f92c 100644
--- a/tests/cputest.c
+++ b/tests/cputest.c
@@ -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);
diff --git a/tests/cputestdata/x86-baseline-3-result.xml b/tests/cputestdata/x86-baseline-3-result.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d196112b2723ccb0e6ad5b9ed444e6edc586a532
--- /dev/null
+++ b/tests/cputestdata/x86-baseline-3-result.xml
@@ -0,0 +1,35 @@
+
+ Westmere
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/cputestdata/x86-baseline-3.xml b/tests/cputestdata/x86-baseline-3.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7654a1d65d2b262663e08dac3074a379818ed86a
--- /dev/null
+++ b/tests/cputestdata/x86-baseline-3.xml
@@ -0,0 +1,7 @@
+
+
+ x86_64
+ Westmere
+
+
+
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 18fcb3eec3fe4cfd6cbbb76ddb5606de3afee053..13e30451a835907e23e9c45f656d5039ca8cd01e 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -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);
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 3ff6da14a810d9137db0d3b3c6f0d077e3a72363..0ae51780d5d64e041fec4042a225b464ee58f37e 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -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 I
+=item B I [I<--features>]
Compute baseline CPU which will be supported by all host CPUs given in .
The list of host CPUs is built by extracting all elements from the
. Thus, the can contain either a set of elements separated
by new lines or even a set of complete elements printed by
-B command.
+B 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 I