cli: --cpu: code cleanup & reordering
Shuffling bits of code around, adding comments and grouping CLI options to make the code easier to read and understand at a glance. Brings the ordering of XML options in line with libvirt's own output as implemented in `src/conf/cpu_conf.c` and `src/conf/numa_conf.c`.
This commit is contained in:
parent
6a2bc142eb
commit
cb97f6001b
|
@ -131,6 +131,7 @@
|
||||||
<cpu mode="custom" match="strict" check="partial">
|
<cpu mode="custom" match="strict" check="partial">
|
||||||
<model>foobar</model>
|
<model>foobar</model>
|
||||||
<vendor>meee</vendor>
|
<vendor>meee</vendor>
|
||||||
|
<cache level="3" mode="emulate"/>
|
||||||
<feature policy="force" name="x2apic"/>
|
<feature policy="force" name="x2apic"/>
|
||||||
<feature policy="force" name="x2apicagain"/>
|
<feature policy="force" name="x2apicagain"/>
|
||||||
<feature policy="require" name="reqtest"/>
|
<feature policy="require" name="reqtest"/>
|
||||||
|
@ -140,12 +141,6 @@
|
||||||
<feature policy="forbid" name="foo"/>
|
<feature policy="forbid" name="foo"/>
|
||||||
<feature policy="forbid" name="bar"/>
|
<feature policy="forbid" name="bar"/>
|
||||||
<numa>
|
<numa>
|
||||||
<interconnects>
|
|
||||||
<bandwidth initiator="0" target="0" type="access" value="204800"/>
|
|
||||||
<bandwidth initiator="0" target="2" cache="1" type="access" value="409600" unit="KiB"/>
|
|
||||||
<latency initiator="0" target="0" type="access" value="5"/>
|
|
||||||
<latency initiator="0" target="2" cache="1" type="access" value="10" unit="ns"/>
|
|
||||||
</interconnects>
|
|
||||||
<cell id="0" cpus="1,2,3" memory="1024">
|
<cell id="0" cpus="1,2,3" memory="1024">
|
||||||
<distances>
|
<distances>
|
||||||
<sibling id="0" value="10"/>
|
<sibling id="0" value="10"/>
|
||||||
|
@ -158,14 +153,19 @@
|
||||||
<sibling id="1" value="10"/>
|
<sibling id="1" value="10"/>
|
||||||
</distances>
|
</distances>
|
||||||
</cell>
|
</cell>
|
||||||
<cell id="2" cpus="4" memory="256" memAccess="shared" discard="no" unit="KiB">
|
<cell id="2" cpus="4" memory="256" unit="KiB" memAccess="shared" discard="no">
|
||||||
<cache level="1" associativity="direct" policy="writeback">
|
<cache level="1" associativity="direct" policy="writeback">
|
||||||
<size value="256" unit="KiB"/>
|
<size value="256" unit="KiB"/>
|
||||||
<line value="256" unit="KiB"/>
|
<line value="256" unit="KiB"/>
|
||||||
</cache>
|
</cache>
|
||||||
</cell>
|
</cell>
|
||||||
|
<interconnects>
|
||||||
|
<latency initiator="0" target="0" type="access" value="5"/>
|
||||||
|
<latency initiator="0" target="2" cache="1" type="access" value="10" unit="ns"/>
|
||||||
|
<bandwidth initiator="0" target="0" type="access" value="204800"/>
|
||||||
|
<bandwidth initiator="0" target="2" cache="1" type="access" value="409600" unit="KiB"/>
|
||||||
|
</interconnects>
|
||||||
</numa>
|
</numa>
|
||||||
<cache mode="emulate" level="3"/>
|
|
||||||
</cpu>
|
</cpu>
|
||||||
<clock offset="utc">
|
<clock offset="utc">
|
||||||
<timer name="rtc" tickpolicy="merge"/>
|
<timer name="rtc" tickpolicy="merge"/>
|
||||||
|
@ -415,6 +415,7 @@
|
||||||
<cpu mode="custom" match="strict" check="partial">
|
<cpu mode="custom" match="strict" check="partial">
|
||||||
<model>foobar</model>
|
<model>foobar</model>
|
||||||
<vendor>meee</vendor>
|
<vendor>meee</vendor>
|
||||||
|
<cache level="3" mode="emulate"/>
|
||||||
<feature policy="force" name="x2apic"/>
|
<feature policy="force" name="x2apic"/>
|
||||||
<feature policy="force" name="x2apicagain"/>
|
<feature policy="force" name="x2apicagain"/>
|
||||||
<feature policy="require" name="reqtest"/>
|
<feature policy="require" name="reqtest"/>
|
||||||
|
@ -424,12 +425,6 @@
|
||||||
<feature policy="forbid" name="foo"/>
|
<feature policy="forbid" name="foo"/>
|
||||||
<feature policy="forbid" name="bar"/>
|
<feature policy="forbid" name="bar"/>
|
||||||
<numa>
|
<numa>
|
||||||
<interconnects>
|
|
||||||
<bandwidth initiator="0" target="0" type="access" value="204800"/>
|
|
||||||
<bandwidth initiator="0" target="2" cache="1" type="access" value="409600" unit="KiB"/>
|
|
||||||
<latency initiator="0" target="0" type="access" value="5"/>
|
|
||||||
<latency initiator="0" target="2" cache="1" type="access" value="10" unit="ns"/>
|
|
||||||
</interconnects>
|
|
||||||
<cell id="0" cpus="1,2,3" memory="1024">
|
<cell id="0" cpus="1,2,3" memory="1024">
|
||||||
<distances>
|
<distances>
|
||||||
<sibling id="0" value="10"/>
|
<sibling id="0" value="10"/>
|
||||||
|
@ -442,14 +437,19 @@
|
||||||
<sibling id="1" value="10"/>
|
<sibling id="1" value="10"/>
|
||||||
</distances>
|
</distances>
|
||||||
</cell>
|
</cell>
|
||||||
<cell id="2" cpus="4" memory="256" memAccess="shared" discard="no" unit="KiB">
|
<cell id="2" cpus="4" memory="256" unit="KiB" memAccess="shared" discard="no">
|
||||||
<cache level="1" associativity="direct" policy="writeback">
|
<cache level="1" associativity="direct" policy="writeback">
|
||||||
<size value="256" unit="KiB"/>
|
<size value="256" unit="KiB"/>
|
||||||
<line value="256" unit="KiB"/>
|
<line value="256" unit="KiB"/>
|
||||||
</cache>
|
</cache>
|
||||||
</cell>
|
</cell>
|
||||||
|
<interconnects>
|
||||||
|
<latency initiator="0" target="0" type="access" value="5"/>
|
||||||
|
<latency initiator="0" target="2" cache="1" type="access" value="10" unit="ns"/>
|
||||||
|
<bandwidth initiator="0" target="0" type="access" value="204800"/>
|
||||||
|
<bandwidth initiator="0" target="2" cache="1" type="access" value="409600" unit="KiB"/>
|
||||||
|
</interconnects>
|
||||||
</numa>
|
</numa>
|
||||||
<cache mode="emulate" level="3"/>
|
|
||||||
</cpu>
|
</cpu>
|
||||||
<clock offset="utc">
|
<clock offset="utc">
|
||||||
<timer name="rtc" tickpolicy="merge"/>
|
<timer name="rtc" tickpolicy="merge"/>
|
||||||
|
|
|
@ -2221,6 +2221,11 @@ class ParserCPU(VirtCLIParser):
|
||||||
"numa.cell[0-9]*.memory": "cell[0-9]*.memory",
|
"numa.cell[0-9]*.memory": "cell[0-9]*.memory",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Special parsing #
|
||||||
|
###################
|
||||||
|
|
||||||
def _convert_old_feature_options(self):
|
def _convert_old_feature_options(self):
|
||||||
# For old CLI compat, --cpu force=foo,force=bar should force
|
# For old CLI compat, --cpu force=foo,force=bar should force
|
||||||
# enable 'foo' and 'bar' features, but that doesn't fit with the
|
# enable 'foo' and 'bar' features, but that doesn't fit with the
|
||||||
|
@ -2254,9 +2259,9 @@ class ParserCPU(VirtCLIParser):
|
||||||
return super()._parse(inst)
|
return super()._parse(inst)
|
||||||
|
|
||||||
|
|
||||||
###################
|
#################################
|
||||||
# Option handling #
|
# Option multi-instance finders #
|
||||||
###################
|
#################################
|
||||||
|
|
||||||
def cell_find_inst_cb(self, *args, **kwargs):
|
def cell_find_inst_cb(self, *args, **kwargs):
|
||||||
cliarg = "cell" # cell[0-9]*
|
cliarg = "cell" # cell[0-9]*
|
||||||
|
@ -2294,6 +2299,11 @@ class ParserCPU(VirtCLIParser):
|
||||||
cb = self._make_find_inst_cb(cliarg, list_propname)
|
cb = self._make_find_inst_cb(cliarg, list_propname)
|
||||||
return cb(*args, **kwargs)
|
return cb(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
#############################
|
||||||
|
# Option handling callbacks #
|
||||||
|
#############################
|
||||||
|
|
||||||
def set_model_cb(self, inst, val, virtarg):
|
def set_model_cb(self, inst, val, virtarg):
|
||||||
if val == "host":
|
if val == "host":
|
||||||
val = inst.SPECIAL_MODE_HOST_MODEL
|
val = inst.SPECIAL_MODE_HOST_MODEL
|
||||||
|
@ -2330,16 +2340,21 @@ class ParserCPU(VirtCLIParser):
|
||||||
# overridden
|
# overridden
|
||||||
cls.add_arg("model.fallback", "model_fallback")
|
cls.add_arg("model.fallback", "model_fallback")
|
||||||
cls.add_arg("model.vendor_id", "model_vendor_id")
|
cls.add_arg("model.vendor_id", "model_vendor_id")
|
||||||
|
cls.add_arg("vendor", "vendor")
|
||||||
|
|
||||||
cls.add_arg("mode", "mode")
|
cls.add_arg("mode", "mode")
|
||||||
cls.add_arg("match", "match")
|
cls.add_arg("match", "match")
|
||||||
cls.add_arg("check", "check")
|
cls.add_arg("check", "check")
|
||||||
cls.add_arg("migratable", "migratable", is_onoff=True)
|
cls.add_arg("migratable", "migratable", is_onoff=True)
|
||||||
|
|
||||||
cls.add_arg("vendor", "vendor")
|
cls.add_arg("topology.sockets", "topology.sockets")
|
||||||
cls.add_arg("cache.mode", "cache.mode")
|
cls.add_arg("topology.dies", "topology.dies")
|
||||||
|
cls.add_arg("topology.cores", "topology.cores")
|
||||||
|
cls.add_arg("topology.threads", "topology.threads")
|
||||||
cls.add_arg("cache.level", "cache.level")
|
cls.add_arg("cache.level", "cache.level")
|
||||||
|
cls.add_arg("cache.mode", "cache.mode")
|
||||||
|
|
||||||
|
# CPU features
|
||||||
# These are handled specially in _parse
|
# These are handled specially in _parse
|
||||||
cls.add_arg("force", None, lookup_cb=None, cb=cls.set_feature_cb)
|
cls.add_arg("force", None, lookup_cb=None, cb=cls.set_feature_cb)
|
||||||
cls.add_arg("require", None, lookup_cb=None, cb=cls.set_feature_cb)
|
cls.add_arg("require", None, lookup_cb=None, cb=cls.set_feature_cb)
|
||||||
|
@ -2347,30 +2362,24 @@ class ParserCPU(VirtCLIParser):
|
||||||
cls.add_arg("disable", None, lookup_cb=None, cb=cls.set_feature_cb)
|
cls.add_arg("disable", None, lookup_cb=None, cb=cls.set_feature_cb)
|
||||||
cls.add_arg("forbid", None, lookup_cb=None, cb=cls.set_feature_cb)
|
cls.add_arg("forbid", None, lookup_cb=None, cb=cls.set_feature_cb)
|
||||||
|
|
||||||
cls.add_arg("topology.sockets", "topology.sockets")
|
# NUMA cells
|
||||||
cls.add_arg("topology.dies", "topology.dies")
|
|
||||||
cls.add_arg("topology.cores", "topology.cores")
|
|
||||||
cls.add_arg("topology.threads", "topology.threads")
|
|
||||||
|
|
||||||
# Options for CPU.cells config
|
|
||||||
cls.add_arg("numa.cell[0-9]*.id", "id",
|
cls.add_arg("numa.cell[0-9]*.id", "id",
|
||||||
find_inst_cb=cls.cell_find_inst_cb)
|
find_inst_cb=cls.cell_find_inst_cb)
|
||||||
cls.add_arg("numa.cell[0-9]*.cpus", "cpus", can_comma=True,
|
cls.add_arg("numa.cell[0-9]*.cpus", "cpus", can_comma=True,
|
||||||
find_inst_cb=cls.cell_find_inst_cb)
|
find_inst_cb=cls.cell_find_inst_cb)
|
||||||
|
cls.add_arg("numa.cell[0-9]*.memory", "memory",
|
||||||
|
find_inst_cb=cls.cell_find_inst_cb)
|
||||||
|
cls.add_arg("numa.cell[0-9]*.unit", "unit",
|
||||||
|
find_inst_cb=cls.cell_find_inst_cb)
|
||||||
cls.add_arg("numa.cell[0-9]*.memAccess", "memAccess",
|
cls.add_arg("numa.cell[0-9]*.memAccess", "memAccess",
|
||||||
find_inst_cb=cls.cell_find_inst_cb)
|
find_inst_cb=cls.cell_find_inst_cb)
|
||||||
cls.add_arg("numa.cell[0-9]*.discard", "discard",
|
cls.add_arg("numa.cell[0-9]*.discard", "discard",
|
||||||
find_inst_cb=cls.cell_find_inst_cb, is_onoff=True)
|
find_inst_cb=cls.cell_find_inst_cb, is_onoff=True)
|
||||||
cls.add_arg("numa.cell[0-9]*.memory", "memory",
|
|
||||||
find_inst_cb=cls.cell_find_inst_cb)
|
|
||||||
cls.add_arg("numa.cell[0-9]*.unit", "unit",
|
|
||||||
find_inst_cb=cls.cell_find_inst_cb)
|
|
||||||
|
|
||||||
cls.add_arg("numa.cell[0-9]*.distances.sibling[0-9]*.id", "id",
|
cls.add_arg("numa.cell[0-9]*.distances.sibling[0-9]*.id", "id",
|
||||||
find_inst_cb=cls.cell_sibling_find_inst_cb)
|
find_inst_cb=cls.cell_sibling_find_inst_cb)
|
||||||
cls.add_arg("numa.cell[0-9]*.distances.sibling[0-9]*.value", "value",
|
cls.add_arg("numa.cell[0-9]*.distances.sibling[0-9]*.value", "value",
|
||||||
find_inst_cb=cls.cell_sibling_find_inst_cb)
|
find_inst_cb=cls.cell_sibling_find_inst_cb)
|
||||||
|
# NUMA cell caches
|
||||||
cls.add_arg("numa.cell[0-9]*.cache[0-9]*.level", "level",
|
cls.add_arg("numa.cell[0-9]*.cache[0-9]*.level", "level",
|
||||||
find_inst_cb=cls.cell_cache_find_inst_cb)
|
find_inst_cb=cls.cell_cache_find_inst_cb)
|
||||||
cls.add_arg("numa.cell[0-9]*.cache[0-9]*.associativity", "associativity",
|
cls.add_arg("numa.cell[0-9]*.cache[0-9]*.associativity", "associativity",
|
||||||
|
@ -2386,6 +2395,7 @@ class ParserCPU(VirtCLIParser):
|
||||||
cls.add_arg("numa.cell[0-9]*.cache[0-9]*.line.unit", "line_unit",
|
cls.add_arg("numa.cell[0-9]*.cache[0-9]*.line.unit", "line_unit",
|
||||||
find_inst_cb=cls.cell_cache_find_inst_cb)
|
find_inst_cb=cls.cell_cache_find_inst_cb)
|
||||||
|
|
||||||
|
# Interconnections between NUMA cells
|
||||||
cls.add_arg("numa.interconnects.latency[0-9]*.initiator", "initiator",
|
cls.add_arg("numa.interconnects.latency[0-9]*.initiator", "initiator",
|
||||||
find_inst_cb=cls.latency_find_inst_cb)
|
find_inst_cb=cls.latency_find_inst_cb)
|
||||||
cls.add_arg("numa.interconnects.latency[0-9]*.target", "target",
|
cls.add_arg("numa.interconnects.latency[0-9]*.target", "target",
|
||||||
|
@ -2398,7 +2408,6 @@ class ParserCPU(VirtCLIParser):
|
||||||
find_inst_cb=cls.latency_find_inst_cb)
|
find_inst_cb=cls.latency_find_inst_cb)
|
||||||
cls.add_arg("numa.interconnects.latency[0-9]*.unit", "unit",
|
cls.add_arg("numa.interconnects.latency[0-9]*.unit", "unit",
|
||||||
find_inst_cb=cls.latency_find_inst_cb)
|
find_inst_cb=cls.latency_find_inst_cb)
|
||||||
|
|
||||||
cls.add_arg("numa.interconnects.bandwidth[0-9]*.initiator", "initiator",
|
cls.add_arg("numa.interconnects.bandwidth[0-9]*.initiator", "initiator",
|
||||||
find_inst_cb=cls.bandwidth_find_inst_cb)
|
find_inst_cb=cls.bandwidth_find_inst_cb)
|
||||||
cls.add_arg("numa.interconnects.bandwidth[0-9]*.target", "target",
|
cls.add_arg("numa.interconnects.bandwidth[0-9]*.target", "target",
|
||||||
|
|
|
@ -10,118 +10,13 @@ from ..xmlbuilder import XMLBuilder, XMLProperty, XMLChildProperty
|
||||||
from .. import xmlutil
|
from .. import xmlutil
|
||||||
|
|
||||||
|
|
||||||
class _NUMACellSibling(XMLBuilder):
|
###################################
|
||||||
"""
|
# Misc child nodes for CPU domain #
|
||||||
Class for generating <cpu><numa><cell><distances> child nodes <sibling>,
|
###################################
|
||||||
describing the distances to other NUMA cells.
|
|
||||||
"""
|
|
||||||
XML_NAME = "sibling"
|
|
||||||
_XML_PROP_ORDER = ["id", "value"]
|
|
||||||
|
|
||||||
id = XMLProperty("./@id", is_int=True)
|
|
||||||
value = XMLProperty("./@value", is_int=True)
|
|
||||||
|
|
||||||
|
|
||||||
class _NUMACellCache(XMLBuilder):
|
|
||||||
"""
|
|
||||||
Class for generating <cpu><numa><cell> child nodes <cache>, describing
|
|
||||||
caches for NUMA cells.
|
|
||||||
"""
|
|
||||||
XML_NAME = "cache"
|
|
||||||
_XML_PROP_ORDER = ["level", "associativity", "policy",
|
|
||||||
"size_value", "size_unit", "line_value", "line_unit"]
|
|
||||||
|
|
||||||
level = XMLProperty("./@level", is_int=True)
|
|
||||||
associativity = XMLProperty("./@associativity")
|
|
||||||
policy = XMLProperty("./@policy")
|
|
||||||
|
|
||||||
size_value = XMLProperty("./size/@value", is_int=True)
|
|
||||||
size_unit = XMLProperty("./size/@unit")
|
|
||||||
|
|
||||||
line_value = XMLProperty("./line/@value", is_int=True)
|
|
||||||
line_unit = XMLProperty("./line/@unit")
|
|
||||||
|
|
||||||
|
|
||||||
class _NUMACell(XMLBuilder):
|
|
||||||
"""
|
|
||||||
Class for generating <cpu><numa> child nodes <cell> XML, describing NUMA
|
|
||||||
cells.
|
|
||||||
"""
|
|
||||||
XML_NAME = "cell"
|
|
||||||
_XML_PROP_ORDER = ["id", "cpus", "memory", "memAccess", "discard"]
|
|
||||||
|
|
||||||
id = XMLProperty("./@id", is_int=True)
|
|
||||||
cpus = XMLProperty("./@cpus")
|
|
||||||
memory = XMLProperty("./@memory", is_int=True)
|
|
||||||
unit = XMLProperty("./@unit")
|
|
||||||
memAccess = XMLProperty("./@memAccess")
|
|
||||||
discard = XMLProperty("./@discard", is_yesno=True)
|
|
||||||
siblings = XMLChildProperty(_NUMACellSibling, relative_xpath="./distances")
|
|
||||||
caches = XMLChildProperty(_NUMACellCache)
|
|
||||||
|
|
||||||
|
|
||||||
class _NUMALatency(XMLBuilder):
|
|
||||||
"""
|
|
||||||
Class for generating <cpu><numa><cell><interconnects> child nodes
|
|
||||||
<latency>, describing latency between two NUMA memory nodes.
|
|
||||||
"""
|
|
||||||
XML_NAME = "latency"
|
|
||||||
_XML_PROP_ORDER = ["initiator", "target", "cache", "type", "value", "unit"]
|
|
||||||
|
|
||||||
initiator = XMLProperty("./@initiator", is_int=True)
|
|
||||||
target = XMLProperty("./@target", is_int=True)
|
|
||||||
cache = XMLProperty("./@cache", is_int=True)
|
|
||||||
type = XMLProperty("./@type")
|
|
||||||
value = XMLProperty("./@value", is_int=True)
|
|
||||||
unit = XMLProperty("./@unit")
|
|
||||||
|
|
||||||
|
|
||||||
class _NUMABandwidth(XMLBuilder):
|
|
||||||
"""
|
|
||||||
Class for generating <cpu><numa><cell><interconnects> child nodes
|
|
||||||
<bandwidth>, describing bandwidth between two NUMA memory nodes.
|
|
||||||
"""
|
|
||||||
XML_NAME = "bandwidth"
|
|
||||||
_XML_PROP_ORDER = ["initiator", "target", "cache", "type", "value", "unit"]
|
|
||||||
|
|
||||||
# Note: The documentation only mentions <latency> nodes havin a cache=
|
|
||||||
# attribute, but <bandwidth> and <latency> nodes are otherwise identical
|
|
||||||
# and libvirt will happily accept XML with a cache= attribute on
|
|
||||||
# <bandwidth> nodes as well, so let's leave it here for now.
|
|
||||||
initiator = XMLProperty("./@initiator", is_int=True)
|
|
||||||
target = XMLProperty("./@target", is_int=True)
|
|
||||||
cache = XMLProperty("./@cache", is_int=True)
|
|
||||||
type = XMLProperty("./@type")
|
|
||||||
value = XMLProperty("./@value", is_int=True)
|
|
||||||
unit = XMLProperty("./@unit")
|
|
||||||
|
|
||||||
|
|
||||||
class _CPUCache(XMLBuilder):
|
|
||||||
"""
|
|
||||||
Class for generating <cpu> child <cache> XML
|
|
||||||
"""
|
|
||||||
|
|
||||||
XML_NAME = "cache"
|
|
||||||
_XML_PROP_ORDER = ["mode", "level"]
|
|
||||||
|
|
||||||
mode = XMLProperty("./@mode")
|
|
||||||
level = XMLProperty("./@level", is_int=True)
|
|
||||||
|
|
||||||
|
|
||||||
class _CPUFeature(XMLBuilder):
|
|
||||||
"""
|
|
||||||
Class for generating <cpu> child <feature> XML
|
|
||||||
"""
|
|
||||||
XML_NAME = "feature"
|
|
||||||
_XML_PROP_ORDER = ["policy", "name"]
|
|
||||||
|
|
||||||
name = XMLProperty("./@name")
|
|
||||||
policy = XMLProperty("./@policy")
|
|
||||||
|
|
||||||
|
|
||||||
class _CPUTopology(XMLBuilder):
|
class _CPUTopology(XMLBuilder):
|
||||||
"""
|
"""
|
||||||
Class for generating <cpu> <topology> XML
|
Class for generating XML for <cpu> child node <topology>.
|
||||||
"""
|
"""
|
||||||
XML_NAME = "topology"
|
XML_NAME = "topology"
|
||||||
_XML_PROP_ORDER = ["sockets", "dies", "cores", "threads"]
|
_XML_PROP_ORDER = ["sockets", "dies", "cores", "threads"]
|
||||||
|
@ -152,16 +47,177 @@ class _CPUTopology(XMLBuilder):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
# Note: CPU cache is weird. The documentation implies that multiples instances
|
||||||
|
# can be declared, one for each cache level one wishes to define. However,
|
||||||
|
# libvirt doesn't accept more than one <cache> element, so it's implemented
|
||||||
|
# with `is_single=True` for now (see actual CPU Domain below).
|
||||||
|
class _CPUCache(XMLBuilder):
|
||||||
|
"""
|
||||||
|
Class for generating XML for <cpu> child node <cache>.
|
||||||
|
"""
|
||||||
|
XML_NAME = "cache"
|
||||||
|
_XML_PROP_ORDER = ["level", "mode"]
|
||||||
|
|
||||||
|
level = XMLProperty("./@level", is_int=True)
|
||||||
|
mode = XMLProperty("./@mode")
|
||||||
|
|
||||||
|
|
||||||
|
class _CPUFeature(XMLBuilder):
|
||||||
|
"""
|
||||||
|
Class for generating XML for <cpu> child nodes <feature>.
|
||||||
|
"""
|
||||||
|
XML_NAME = "feature"
|
||||||
|
_XML_PROP_ORDER = ["policy", "name"]
|
||||||
|
|
||||||
|
name = XMLProperty("./@name")
|
||||||
|
policy = XMLProperty("./@policy")
|
||||||
|
|
||||||
|
|
||||||
|
##############
|
||||||
|
# NUMA cells #
|
||||||
|
##############
|
||||||
|
|
||||||
|
class _NUMACellSibling(XMLBuilder):
|
||||||
|
"""
|
||||||
|
Class for generating XML for <cpu><numa><cell><distances> child nodes
|
||||||
|
<sibling>, describing the distances to other NUMA cells.
|
||||||
|
"""
|
||||||
|
XML_NAME = "sibling"
|
||||||
|
_XML_PROP_ORDER = ["id", "value"]
|
||||||
|
|
||||||
|
id = XMLProperty("./@id", is_int=True)
|
||||||
|
value = XMLProperty("./@value", is_int=True)
|
||||||
|
|
||||||
|
|
||||||
|
class _NUMACellCache(XMLBuilder):
|
||||||
|
"""
|
||||||
|
Class for generating XML for <cpu><numa><cell> child nodes <cache>,
|
||||||
|
describing caches for NUMA cells.
|
||||||
|
"""
|
||||||
|
XML_NAME = "cache"
|
||||||
|
_XML_PROP_ORDER = ["level", "associativity", "policy",
|
||||||
|
"size_value", "size_unit", "line_value", "line_unit"]
|
||||||
|
|
||||||
|
level = XMLProperty("./@level", is_int=True)
|
||||||
|
associativity = XMLProperty("./@associativity")
|
||||||
|
policy = XMLProperty("./@policy")
|
||||||
|
|
||||||
|
size_value = XMLProperty("./size/@value", is_int=True)
|
||||||
|
size_unit = XMLProperty("./size/@unit")
|
||||||
|
line_value = XMLProperty("./line/@value", is_int=True)
|
||||||
|
line_unit = XMLProperty("./line/@unit")
|
||||||
|
|
||||||
|
|
||||||
|
class _NUMACell(XMLBuilder):
|
||||||
|
"""
|
||||||
|
Class for generating XML for <cpu><numa> child nodes <cell> XML, describing
|
||||||
|
NUMA cells.
|
||||||
|
"""
|
||||||
|
XML_NAME = "cell"
|
||||||
|
_XML_PROP_ORDER = ["id", "cpus", "memory", "unit", "memAccess", "discard",
|
||||||
|
"siblings", "caches"]
|
||||||
|
|
||||||
|
id = XMLProperty("./@id", is_int=True)
|
||||||
|
cpus = XMLProperty("./@cpus")
|
||||||
|
memory = XMLProperty("./@memory", is_int=True)
|
||||||
|
unit = XMLProperty("./@unit")
|
||||||
|
memAccess = XMLProperty("./@memAccess")
|
||||||
|
discard = XMLProperty("./@discard", is_yesno=True)
|
||||||
|
|
||||||
|
siblings = XMLChildProperty(_NUMACellSibling, relative_xpath="./distances")
|
||||||
|
caches = XMLChildProperty(_NUMACellCache)
|
||||||
|
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Interconnections between NUMA cells #
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
class _NUMALatency(XMLBuilder):
|
||||||
|
"""
|
||||||
|
Class for generating XML for <cpu><numa><cell><interconnects> child nodes
|
||||||
|
<latency>, describing latency between two NUMA memory nodes.
|
||||||
|
"""
|
||||||
|
XML_NAME = "latency"
|
||||||
|
_XML_PROP_ORDER = ["initiator", "target", "cache", "type", "value", "unit"]
|
||||||
|
|
||||||
|
# Note: While libvirt happily accepts XML with a unit= property, it is
|
||||||
|
# currently ignored on <latency> nodes.
|
||||||
|
initiator = XMLProperty("./@initiator", is_int=True)
|
||||||
|
target = XMLProperty("./@target", is_int=True)
|
||||||
|
cache = XMLProperty("./@cache", is_int=True)
|
||||||
|
type = XMLProperty("./@type")
|
||||||
|
value = XMLProperty("./@value", is_int=True)
|
||||||
|
unit = XMLProperty("./@unit")
|
||||||
|
|
||||||
|
|
||||||
|
class _NUMABandwidth(XMLBuilder):
|
||||||
|
"""
|
||||||
|
Class for generating XML for <cpu><numa><cell><interconnects> child nodes
|
||||||
|
<bandwidth>, describing bandwidth between two NUMA memory nodes.
|
||||||
|
"""
|
||||||
|
XML_NAME = "bandwidth"
|
||||||
|
_XML_PROP_ORDER = ["initiator", "target", "cache", "type", "value", "unit"]
|
||||||
|
|
||||||
|
# Note: The documentation only mentions <latency> nodes having a cache=
|
||||||
|
# attribute, but <bandwidth> and <latency> nodes are otherwise identical
|
||||||
|
# and libvirt will happily accept XML with a cache= attribute on
|
||||||
|
# <bandwidth> nodes as well, so let's leave it here for now.
|
||||||
|
initiator = XMLProperty("./@initiator", is_int=True)
|
||||||
|
target = XMLProperty("./@target", is_int=True)
|
||||||
|
cache = XMLProperty("./@cache", is_int=True)
|
||||||
|
type = XMLProperty("./@type")
|
||||||
|
value = XMLProperty("./@value", is_int=True)
|
||||||
|
unit = XMLProperty("./@unit")
|
||||||
|
|
||||||
|
|
||||||
|
#####################
|
||||||
|
# Actual CPU domain #
|
||||||
|
#####################
|
||||||
|
|
||||||
class DomainCpu(XMLBuilder):
|
class DomainCpu(XMLBuilder):
|
||||||
"""
|
"""
|
||||||
Class for generating <cpu> XML
|
Class for generating <cpu> XML
|
||||||
"""
|
"""
|
||||||
XML_NAME = "cpu"
|
XML_NAME = "cpu"
|
||||||
_XML_PROP_ORDER = ["mode", "match", "check", "migratable",
|
_XML_PROP_ORDER = ["mode", "match", "check", "migratable",
|
||||||
"model", "vendor", "topology", "features"]
|
"model", "model_fallback", "model_vendor_id", "vendor",
|
||||||
|
"topology", "cache", "features",
|
||||||
|
"cells", "latencies", "bandwidths"]
|
||||||
|
|
||||||
|
|
||||||
|
##################
|
||||||
|
# XML properties #
|
||||||
|
##################
|
||||||
|
|
||||||
|
# Note: This is not a libvirt property. This is specific to the virt-*
|
||||||
|
# tools and causes additional security features to be added to the VM.
|
||||||
|
# See the security mitigation related functions below for more details.
|
||||||
secure = True
|
secure = True
|
||||||
|
|
||||||
|
mode = XMLProperty("./@mode")
|
||||||
|
match = XMLProperty("./@match")
|
||||||
|
check = XMLProperty("./@check")
|
||||||
|
migratable = XMLProperty("./@migratable", is_onoff=True)
|
||||||
|
|
||||||
|
model = XMLProperty("./model")
|
||||||
|
model_fallback = XMLProperty("./model/@fallback")
|
||||||
|
model_vendor_id = XMLProperty("./model/@vendor_id")
|
||||||
|
vendor = XMLProperty("./vendor")
|
||||||
|
|
||||||
|
topology = XMLChildProperty(_CPUTopology, is_single=True)
|
||||||
|
cache = XMLChildProperty(_CPUCache, is_single=True)
|
||||||
|
features = XMLChildProperty(_CPUFeature)
|
||||||
|
|
||||||
|
# NUMA related properties
|
||||||
|
cells = XMLChildProperty(_NUMACell, relative_xpath="./numa")
|
||||||
|
latencies = XMLChildProperty(_NUMALatency, relative_xpath="./numa/interconnects")
|
||||||
|
bandwidths = XMLChildProperty(_NUMABandwidth, relative_xpath="./numa/interconnects")
|
||||||
|
|
||||||
|
|
||||||
|
#############################
|
||||||
|
# Special CPU mode handling #
|
||||||
|
#############################
|
||||||
|
|
||||||
special_mode_was_set = False
|
special_mode_was_set = False
|
||||||
# These values are exposed on the command line, so are stable API
|
# These values are exposed on the command line, so are stable API
|
||||||
SPECIAL_MODE_HOST_MODEL_ONLY = "host-model-only"
|
SPECIAL_MODE_HOST_MODEL_ONLY = "host-model-only"
|
||||||
|
@ -206,6 +262,42 @@ class DomainCpu(XMLBuilder):
|
||||||
|
|
||||||
self.special_mode_was_set = True
|
self.special_mode_was_set = True
|
||||||
|
|
||||||
|
def copy_host_cpu(self, guest):
|
||||||
|
"""
|
||||||
|
Try to manually mimic host-model, copying all the info
|
||||||
|
preferably out of domcapabilities, but capabilities as fallback.
|
||||||
|
"""
|
||||||
|
domcaps = guest.lookup_domcaps()
|
||||||
|
if domcaps.supports_safe_host_model():
|
||||||
|
log.debug("Using domcaps for host-copy")
|
||||||
|
cpu = domcaps.cpu.get_mode("host-model")
|
||||||
|
model = cpu.models[0].model
|
||||||
|
fallback = cpu.models[0].fallback
|
||||||
|
else:
|
||||||
|
cpu = self.conn.caps.host.cpu
|
||||||
|
model = cpu.model
|
||||||
|
fallback = None
|
||||||
|
if not model: # pragma: no cover
|
||||||
|
raise ValueError(_("No host CPU reported in capabilities"))
|
||||||
|
|
||||||
|
self.mode = "custom"
|
||||||
|
self.match = "exact"
|
||||||
|
self.set_model(guest, model)
|
||||||
|
if fallback:
|
||||||
|
self.model_fallback = fallback
|
||||||
|
self.vendor = cpu.vendor
|
||||||
|
|
||||||
|
for feature in self.features:
|
||||||
|
self.remove_child(feature)
|
||||||
|
for feature in cpu.features:
|
||||||
|
policy = getattr(feature, "policy", "require")
|
||||||
|
self.add_feature(feature.name, policy)
|
||||||
|
|
||||||
|
|
||||||
|
########################
|
||||||
|
# Security mitigations #
|
||||||
|
########################
|
||||||
|
|
||||||
def _add_security_features(self, guest):
|
def _add_security_features(self, guest):
|
||||||
domcaps = guest.lookup_domcaps()
|
domcaps = guest.lookup_domcaps()
|
||||||
for feature in domcaps.get_cpu_security_features():
|
for feature in domcaps.get_cpu_security_features():
|
||||||
|
@ -245,6 +337,11 @@ class DomainCpu(XMLBuilder):
|
||||||
self.remove_child(f)
|
self.remove_child(f)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
|
###########
|
||||||
|
# Helpers #
|
||||||
|
###########
|
||||||
|
|
||||||
def set_model(self, guest, val):
|
def set_model(self, guest, val):
|
||||||
log.debug("setting cpu model %s", val)
|
log.debug("setting cpu model %s", val)
|
||||||
if val:
|
if val:
|
||||||
|
@ -261,43 +358,6 @@ class DomainCpu(XMLBuilder):
|
||||||
feature = self.features.add_new()
|
feature = self.features.add_new()
|
||||||
feature.name = name
|
feature.name = name
|
||||||
feature.policy = policy
|
feature.policy = policy
|
||||||
features = XMLChildProperty(_CPUFeature)
|
|
||||||
|
|
||||||
cells = XMLChildProperty(_NUMACell, relative_xpath="./numa")
|
|
||||||
latencies = XMLChildProperty(_NUMALatency, relative_xpath="./numa/interconnects")
|
|
||||||
bandwidths = XMLChildProperty(_NUMABandwidth, relative_xpath="./numa/interconnects")
|
|
||||||
cache = XMLChildProperty(_CPUCache, is_single=True)
|
|
||||||
|
|
||||||
def copy_host_cpu(self, guest):
|
|
||||||
"""
|
|
||||||
Try to manually mimic host-model, copying all the info
|
|
||||||
preferably out of domcapabilities, but capabilities as fallback.
|
|
||||||
"""
|
|
||||||
domcaps = guest.lookup_domcaps()
|
|
||||||
if domcaps.supports_safe_host_model():
|
|
||||||
log.debug("Using domcaps for host-copy")
|
|
||||||
cpu = domcaps.cpu.get_mode("host-model")
|
|
||||||
model = cpu.models[0].model
|
|
||||||
fallback = cpu.models[0].fallback
|
|
||||||
else:
|
|
||||||
cpu = self.conn.caps.host.cpu
|
|
||||||
model = cpu.model
|
|
||||||
fallback = None
|
|
||||||
if not model: # pragma: no cover
|
|
||||||
raise ValueError(_("No host CPU reported in capabilities"))
|
|
||||||
|
|
||||||
self.mode = "custom"
|
|
||||||
self.match = "exact"
|
|
||||||
self.set_model(guest, model)
|
|
||||||
if fallback:
|
|
||||||
self.model_fallback = fallback
|
|
||||||
self.vendor = cpu.vendor
|
|
||||||
|
|
||||||
for feature in self.features:
|
|
||||||
self.remove_child(feature)
|
|
||||||
for feature in cpu.features:
|
|
||||||
policy = getattr(feature, "policy", "require")
|
|
||||||
self.add_feature(feature.name, policy)
|
|
||||||
|
|
||||||
def vcpus_from_topology(self):
|
def vcpus_from_topology(self):
|
||||||
"""
|
"""
|
||||||
|
@ -325,23 +385,6 @@ class DomainCpu(XMLBuilder):
|
||||||
self.topology.set_defaults_from_vcpus(vcpus)
|
self.topology.set_defaults_from_vcpus(vcpus)
|
||||||
|
|
||||||
|
|
||||||
##################
|
|
||||||
# XML properties #
|
|
||||||
##################
|
|
||||||
|
|
||||||
topology = XMLChildProperty(_CPUTopology, is_single=True)
|
|
||||||
|
|
||||||
model = XMLProperty("./model")
|
|
||||||
model_fallback = XMLProperty("./model/@fallback")
|
|
||||||
model_vendor_id = XMLProperty("./model/@vendor_id")
|
|
||||||
|
|
||||||
match = XMLProperty("./@match")
|
|
||||||
vendor = XMLProperty("./vendor")
|
|
||||||
mode = XMLProperty("./@mode")
|
|
||||||
check = XMLProperty("./@check")
|
|
||||||
migratable = XMLProperty("./@migratable", is_onoff=True)
|
|
||||||
|
|
||||||
|
|
||||||
##################
|
##################
|
||||||
# Default config #
|
# Default config #
|
||||||
##################
|
##################
|
||||||
|
|
Loading…
Reference in New Issue