[virt-tools-list] [PATCH v2] CPU model capabilities vs domcapabilities

Charles Arnold carnold at suse.com
Mon Mar 26 21:08:59 UTC 2018


The issue is when the host has been updated with microcode for Spectre
but qemu has _not_ been updated. In this scenario (as an example),
'virsh capabilities' shows the host cpu model as IvyBridge-IBRS, which is
correct. However, 'virsh domcapabilities' shows IvyBridge as the host-model
and does not show any of the '-IBRS' flavors available under the custom model,
which is also correct since the qemu does not have Spectre patches.

Be default, virt-manager uses 'custom' for the cpu mode XML. For example,

  <cpu mode="custom" match="exact">
    <model>IvyBridge-IBRS</model>
  </cpu>

Starting an installation in the above scenario will fail because qemu
doesn't understand '-IBRS' until it has been updated to do so.

The patch below validates that the capabilities cpu is present in domcapabilities,
and if they differ, log a message and set the CPU model to None.

Signed-off-by: Charles Arnold <carnold at suse.com>

diff --git a/virtinst/domain/cpu.py b/virtinst/domain/cpu.py
index 3c1089c0..f3055dc7 100644
--- a/virtinst/domain/cpu.py
+++ b/virtinst/domain/cpu.py
@@ -6,6 +6,8 @@
 # See the COPYING file in the top-level directory.
 
 from ..xmlbuilder import XMLBuilder, XMLProperty, XMLChildProperty
+from .domcapabilities import DomainCapabilities
+import logging
 
 
 class _CPUCellSibling(XMLBuilder):
@@ -79,7 +81,7 @@ class DomainCpu(XMLBuilder):
     SPECIAL_MODES = [SPECIAL_MODE_HOST_MODEL_ONLY, SPECIAL_MODE_HV_DEFAULT,
                      SPECIAL_MODE_HOST_COPY, SPECIAL_MODE_HOST_MODEL,
                      SPECIAL_MODE_HOST_PASSTHROUGH, SPECIAL_MODE_CLEAR]
-    def set_special_mode(self, val):
+    def set_special_mode(self, val, guest=None):
         if (val == self.SPECIAL_MODE_HOST_MODEL or
             val == self.SPECIAL_MODE_HOST_PASSTHROUGH):
             self.model = None
@@ -97,6 +99,15 @@ class DomainCpu(XMLBuilder):
             if self.conn.caps.host.cpu.model:
                 self.clear()
                 self.model = self.conn.caps.host.cpu.model
+                if guest:
+                    domcaps = DomainCapabilities.build_from_guest(guest)
+                    domcaps_model = domcaps.cpu.get_mode("host-model").get_models()
+                    if (isinstance(domcaps_model, list) and len(domcaps_model) and
+                        domcaps_model[0] != self.conn.caps.host.cpu.model):
+                        logging.debug("Host capabilities CPU '%s' does not match "
+                              "domain capabilities CPU '%s'. Leaving CPU model unset.",
+                              self.conn.caps.host.cpu.model, domcaps_model[0])
+                        self.model = None
         else:
             raise RuntimeError("programming error: unknown "
                 "special cpu mode '%s'" % val)
diff --git a/virtinst/domcapabilities.py b/virtinst/domcapabilities.py
index f98c807b..8387838c 100644
--- a/virtinst/domcapabilities.py
+++ b/virtinst/domcapabilities.py
@@ -29,9 +29,27 @@ class _Enum(_HasValues):
     name = XMLProperty("./@name")
 
 
+class _Model(XMLBuilder):
+    _XML_ROOT_NAME = "model"
+    model = XMLProperty(".")
+
+
+class _HasModels(XMLBuilder):
+    models = XMLChildProperty(_Model)
+
+    def get_models(self):
+        return [m.model for m in self.models]
+
+
+class _CPUMode(_HasModels):
+    _XML_ROOT_NAME = "mode"
+    name = XMLProperty("./@name")
+
+
 class _CapsBlock(_HasValues):
     supported = XMLProperty("./@supported", is_yesno=True)
     enums = XMLChildProperty(_Enum)
+    modes = XMLChildProperty(_CPUMode)
 
     def enum_names(self):
         return [e.name for e in self.enums]
@@ -40,6 +58,12 @@ class _CapsBlock(_HasValues):
         d = dict((e.name, e) for e in self.enums)
         return d[name]
 
+    def mode_names(self):
+        return [m.name for m in self.modes]
+
+    def get_mode(self, name):
+        d = dict((m.name, m) for m in self.modes)
+        return d[name]
 
 def _make_capsblock(xml_root_name):
     class TmpClass(_CapsBlock):
@@ -53,6 +77,11 @@ class _OS(_CapsBlock):
     loader = XMLChildProperty(_make_capsblock("loader"), is_single=True)
 
 
+class _CPU(_CapsBlock):
+    _XML_ROOT_NAME = "cpu"
+    mode = XMLChildProperty(_make_capsblock("mode"), is_single=True)
+
+
 class _Devices(_CapsBlock):
     XML_NAME = "devices"
     hostdev = XMLChildProperty(_make_capsblock("hostdev"), is_single=True)
@@ -151,6 +180,7 @@ class DomainCapabilities(XMLBuilder):
 
     XML_NAME = "domainCapabilities"
     os = XMLChildProperty(_OS, is_single=True)
+    cpu = XMLChildProperty(_CPU, is_single=True)
     devices = XMLChildProperty(_Devices, is_single=True)
 
     arch = XMLProperty("./arch")
diff --git a/virtinst/guest.py b/virtinst/guest.py
index 5e7d8077..35d162c5 100644
--- a/virtinst/guest.py
+++ b/virtinst/guest.py
@@ -868,7 +868,7 @@ class Guest(XMLBuilder):
             if self.os.arch != self.conn.caps.host.cpu.arch:
                 return
 
-            self.cpu.set_special_mode(self.x86_cpu_default)
+            self.cpu.set_special_mode(self.x86_cpu_default, self)
             if self._os_object.broken_x2apic():
                 self.cpu.add_feature("x2apic", policy="disable")





More information about the virt-tools-list mailing list