Support old & new versions of svm and vmx traits

I1c9a72d19ef9dadfb931efa3894867099974bcc7 added new Intel- and
AMD-specific trait namespaces for certain X86 CPU features, including a
couple that had already been defined in the generic X86 namespace (the
Intel-specific 'vmx' feature and the AMD-specific 'svm' feature).
Unfortunately, the libvirt driver was already exposing the generic
versions of these. For backward compatibility reasons, we have to
continue exposing those versions of those traits. But we also need to
expose the new arch-namespaced versions.

We accomplish this by reworking libvirt's CPU_TRAITS_MAPPING such that
the values can be tuples of traits, all of which are set when the
feature corresponding to the key is enabled.

Change-Id: Ib29c975d3d4e1adf14e215b1a28d30681ee16a77
This commit is contained in:
Eric Fried 2019-05-21 15:28:22 -05:00 committed by Lee Yarwood
parent a4068802ef
commit b420c343f2
3 changed files with 37 additions and 18 deletions

View File

@ -81,7 +81,10 @@ class LibvirtReportTraitsTests(LibvirtReportTraitsTestBase):
# trait values are coming from fakelibvirt's baselineCPU result.
# COMPUTE_NODE is always set on the compute node provider.
traits = self._get_provider_traits(self.host_uuid)
for trait in ('HW_CPU_X86_VMX', 'HW_CPU_X86_AESNI', 'COMPUTE_NODE'):
for trait in (
'HW_CPU_X86_VMX', 'HW_CPU_X86_INTEL_VMX', 'HW_CPU_X86_AESNI',
'COMPUTE_NODE',
):
self.assertIn(trait, traits)
self._create_trait('CUSTOM_TRAITS')
@ -96,10 +99,14 @@ class LibvirtReportTraitsTests(LibvirtReportTraitsTestBase):
# and it's not in the baseline for the host.
traits = set(self._get_provider_traits(self.host_uuid))
expected_traits = self.expected_libvirt_driver_capability_traits.union(
[u'HW_CPU_X86_VMX', u'HW_CPU_X86_AESNI', u'CUSTOM_TRAITS',
# The periodic restored the COMPUTE_NODE trait.
u'COMPUTE_NODE']
)
[
'HW_CPU_X86_VMX',
'HW_CPU_X86_INTEL_VMX',
'HW_CPU_X86_AESNI',
'CUSTOM_TRAITS',
# The periodic restored the COMPUTE_NODE trait.
'COMPUTE_NODE',
])
for trait in expected_traits:
self.assertIn(trait, traits)

View File

@ -21101,7 +21101,7 @@ class TestUpdateProviderTree(test.NoDBTestCase):
pcpus = 12
memory_mb = 1024
disk_gb = 200
cpu_traits = {t: False for t in libvirt_utils.CPU_TRAITS_MAPPING.values()}
cpu_traits = libvirt_utils.cpu_features_to_traits({})
def setUp(self):
super(TestUpdateProviderTree, self).setUp()
@ -21816,7 +21816,7 @@ class TraitsComparisonMixin(object):
def assertTraitsEqual(self, expected, actual):
exp = {t: t in expected
for t in libvirt_utils.CPU_TRAITS_MAPPING.values()}
for t in libvirt_utils.cpu_features_to_traits({})}
self.assertEqual(exp, actual)
@ -25538,8 +25538,9 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
are calculated from fakelibvirt's baseline CPU features.
"""
self.flags(cpu_mode='host-passthrough', group='libvirt')
self.assertTraitsEqual(['HW_CPU_X86_AESNI', 'HW_CPU_X86_VMX'],
self.drvr._get_cpu_feature_traits())
self.assertTraitsEqual(
['HW_CPU_X86_AESNI', 'HW_CPU_X86_VMX', 'HW_CPU_X86_INTEL_VMX'],
self.drvr._get_cpu_feature_traits())
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.baselineCPU')
def test_cpu_traits_with_mode_none(self, mock_baseline):
@ -25548,9 +25549,10 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
"""
self.flags(cpu_mode='none', group='libvirt')
mock_baseline.return_value = _fake_qemu64_cpu_feature
self.assertTraitsEqual(['HW_CPU_X86_SSE', 'HW_CPU_X86_SVM',
'HW_CPU_X86_MMX', 'HW_CPU_X86_SSE2'],
self.drvr._get_cpu_feature_traits())
self.assertTraitsEqual(
['HW_CPU_X86_SSE', 'HW_CPU_X86_SVM', 'HW_CPU_X86_AMD_SVM',
'HW_CPU_X86_MMX', 'HW_CPU_X86_SSE2'],
self.drvr._get_cpu_feature_traits())
mock_baseline.assert_called_with([u'''<cpu>
<arch>x86_64</arch>
@ -25638,6 +25640,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
'HW_CPU_X86_SSE2',
'HW_CPU_X86_SSE',
'HW_CPU_X86_MMX',
'HW_CPU_X86_AMD_SVM',
'HW_CPU_X86_SVM'
], self.drvr._get_cpu_feature_traits()
)
@ -25705,6 +25708,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
'HW_CPU_X86_SSE2',
'HW_CPU_X86_SSE',
'HW_CPU_X86_MMX',
'HW_CPU_X86_AMD_SVM',
'HW_CPU_X86_SVM'
], self.drvr._get_cpu_feature_traits()
)

View File

@ -93,9 +93,13 @@ CPU_TRAITS_MAPPING = {
'sse4.2': os_traits.HW_CPU_X86_SSE42,
'sse4a': os_traits.HW_CPU_X86_SSE4A,
'ssse3': os_traits.HW_CPU_X86_SSSE3,
'svm': os_traits.HW_CPU_X86_SVM,
# We have to continue to support the old (generic) trait for the
# AMD-specific svm feature.
'svm': (os_traits.HW_CPU_X86_SVM, os_traits.HW_CPU_X86_AMD_SVM),
'tbm': os_traits.HW_CPU_X86_TBM,
'vmx': os_traits.HW_CPU_X86_VMX,
# We have to continue to support the old (generic) trait for the
# Intel-specific vmx feature.
'vmx': (os_traits.HW_CPU_X86_VMX, os_traits.HW_CPU_X86_INTEL_VMX),
'xop': os_traits.HW_CPU_X86_XOP
}
@ -577,11 +581,15 @@ def cpu_features_to_traits(features: ty.Set[str]) -> ty.Dict[str, bool]:
"""Returns this driver's CPU traits dict where keys are trait names from
CPU_TRAITS_MAPPING, values are boolean indicates whether the trait should
be set in the provider tree.
:param features: A set of feature names (short, lowercase,
CPU_TRAITS_MAPPING's keys).
"""
traits = {trait_name: False for trait_name in CPU_TRAITS_MAPPING.values()}
for f in features:
if f in CPU_TRAITS_MAPPING:
traits[CPU_TRAITS_MAPPING[f]] = True
traits = {}
for feature_name, val in CPU_TRAITS_MAPPING.items():
trait_tuple = val if isinstance(val, tuple) else (val,)
for trait_name in trait_tuple:
traits[trait_name] = feature_name in features
return traits