As opposed to the existing virCPUCompare{,XML} this function does not
use CPU model definitions from CPU map. It relies on CPU model usability
info from a hypervisor with a list of blockers that make the selected
CPU model unusable. Explicitly requested features are checked against
the hypervisor's view of a host CPU.
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
src/cpu/cpu.c | 73 ++++++++++++++++++++++++++++++++++++++++
src/cpu/cpu.h | 7 ++++
src/libvirt_private.syms | 1 +
3 files changed, 81 insertions(+)
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index 1734561215..2b0d641e78 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -167,6 +167,79 @@ virCPUCompare(virArch arch,
}
+/** virCPUCompareUnusable:
+ * @arch: CPU architecture
+ * @host: host CPU reported by the hypervisor
+ * @cpu: CPU to be compared with @host
+ * @blockers: NULL terminated list of features blocking usability of the CPU model from
@cpu
+ * @failIncompatible: return an error instead of VIR_CPU_COMPARE_INCOMPATIBLE
+ *
+ * Check if @cpu can be run on @host when we know model used by @cpu is
+ * considered unusable by the hypervisor because it requires some features
+ * that cannot be provided on the host (the list of them is passed as
+ * @blockers) and/or @cpu requests additional features. The @cpu definition
+ * can still be compatible with @host if all @blockers are explicitly disabled
+ * and all explicitly requested features are supported by @host.
+ *
+ * Returns VIR_CPU_COMPARE_ERROR on error, VIR_CPU_COMPARE_INCOMPATIBLE when
+ * the @cpu cannot be created on @host, or VIR_CPU_COMPARE_SUPERSET when the
+ * @cpu is compatible with @host CPU. If @failIncompatible is true, the
+ * function will return VIR_CPU_COMPARE_ERROR (and set VIR_ERR_CPU_INCOMPATIBLE
+ * error) when the two CPUs are incompatible.
+ */
+int
+virCPUCompareUnusable(virArch arch,
+ const virCPUDef *host,
+ const virCPUDef *cpu,
+ char **blockers,
+ bool failIncompatible)
+{
+ g_autoptr(virCPUDef) expanded = NULL;
+ g_auto(virBuffer) features = VIR_BUFFER_INITIALIZER;
+ g_autofree char *str = NULL;
+ virCPUFeatureDef *feat;
+ char **blocker;
+ size_t i;
+
+ for (blocker = blockers; *blocker; blocker++) {
+ if (!(feat = virCPUDefFindFeature(cpu, *blocker)) ||
+ feat->policy != VIR_CPU_FEATURE_DISABLE) {
+ virBufferAddStr(&features, *blocker);
+ virBufferAddLit(&features, ", ");
+ }
+ }
+
+ expanded = virCPUDefCopy(host);
+ if (virCPUExpandFeatures(arch, expanded) < 0)
+ return VIR_CPU_COMPARE_ERROR;
+
+ for (i = 0; i < cpu->nfeatures; i++) {
+ if (cpu->features[i].policy != VIR_CPU_FEATURE_REQUIRE)
+ continue;
+
+ if (!(feat = virCPUDefFindFeature(expanded, cpu->features[i].name)) ||
+ feat->policy != VIR_CPU_FEATURE_REQUIRE) {
+ virBufferAddStr(&features, cpu->features[i].name);
+ virBufferAddLit(&features, ", ");
+ }
+ }
+ virBufferTrim(&features, ", ");
+
+ if ((str = virBufferContentAndReset(&features))) {
+ if (failIncompatible) {
+ virReportError(VIR_ERR_CPU_INCOMPATIBLE,
+ _("Host CPU does not provide required features:
%1$s"),
+ str);
+ return VIR_CPU_COMPARE_ERROR;
+ }
+
+ return VIR_CPU_COMPARE_INCOMPATIBLE;
+ }
+
+ return VIR_CPU_COMPARE_SUPERSET;
+}
+
+
/**
* cpuDecode:
*
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index ceb6eb0944..ff68c5da2d 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -185,6 +185,13 @@ virCPUCompare(virArch arch,
bool failIncompatible)
ATTRIBUTE_NONNULL(3);
+int
+virCPUCompareUnusable(virArch arch,
+ const virCPUDef *host,
+ const virCPUDef *cpu,
+ char **blockers,
+ bool failIncompatible);
+
int
cpuDecode (virCPUDef *cpu,
const virCPUData *data,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 551cea989b..c1542847f4 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1524,6 +1524,7 @@ virCPUBaseline;
virCPUCheckFeature;
virCPUCheckForbiddenFeatures;
virCPUCompare;
+virCPUCompareUnusable;
virCPUCompareXML;
virCPUConvertLegacy;
virCPUCopyMigratable;
--
2.47.0