From b420c343f21a767e8db470254ece39eae6186832 Mon Sep 17 00:00:00 2001 From: Eric Fried Date: Tue, 21 May 2019 15:28:22 -0500 Subject: [PATCH] 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 --- .../libvirt/test_report_cpu_traits.py | 17 +++++++++++----- nova/tests/unit/virt/libvirt/test_driver.py | 18 ++++++++++------- nova/virt/libvirt/utils.py | 20 +++++++++++++------ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/nova/tests/functional/libvirt/test_report_cpu_traits.py b/nova/tests/functional/libvirt/test_report_cpu_traits.py index 0964029cd725..b470cdf1ac9d 100644 --- a/nova/tests/functional/libvirt/test_report_cpu_traits.py +++ b/nova/tests/functional/libvirt/test_report_cpu_traits.py @@ -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) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index a2bab72e38ea..1c28860fb7ed 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -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''' x86_64 @@ -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() ) diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py index 5a6090257393..317785d0482d 100644 --- a/nova/virt/libvirt/utils.py +++ b/nova/virt/libvirt/utils.py @@ -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