]> xenbits.xensource.com Git - osstest/openstack-nova.git/commitdiff
Don't parse PCI whitelist every time neutron ports are created
authorLudovic Beliveau <ludovic.beliveau@windriver.com>
Mon, 4 Jul 2016 13:45:07 +0000 (09:45 -0400)
committerLudovic Beliveau <ludovic.beliveau@windriver.com>
Fri, 4 Nov 2016 14:23:40 +0000 (14:23 +0000)
The neutronv2 API is calling the method get_pci_device_devspec()
everytime a neutron port is created in order to get a PciDeviceSpec for a given
PCI device.  This method creates a new Whitelist (based on the config
CONF.pci_passthrough_whitelist) and parses it every time it is called.  This
is not a huge overhead but this is obvioulsy not needed and a waste of cycles.

Since only neutronv2 API uses get_pci_device_devspec(), this commit removes
the method in favor of using the Whitelist object directly (like it is done
in the PciDevTracker).

Change-Id: Idee4e9edecff0672680f323a916201aee8eeeabd
Closes-Bug: #1598843

nova/network/neutronv2/api.py
nova/pci/whitelist.py
nova/tests/unit/network/test_neutronv2.py

index 7192031c4fa3459dbe76ffc00a4c69d725110220..415d9847b4435549dd792bb05fcafa8affc90a29 100644 (file)
@@ -224,18 +224,6 @@ def _filter_hypervisor_macs(instance, ports, hypervisor_macs):
     return available_macs
 
 
-def get_pci_device_profile(pci_dev):
-    dev_spec = pci_whitelist.get_pci_device_devspec(pci_dev)
-    if dev_spec:
-        return {'pci_vendor_info': "%s:%s" %
-                    (pci_dev.vendor_id, pci_dev.product_id),
-                'pci_slot': pci_dev.address,
-                'physical_network':
-                    dev_spec.get_tags().get('physical_network')}
-    raise exception.PciDeviceNotFound(node_id=pci_dev.compute_node_id,
-                                      address=pci_dev.address)
-
-
 class API(base_api.NetworkAPI):
     """API for interacting with the neutron 2.x API."""
 
@@ -243,6 +231,8 @@ class API(base_api.NetworkAPI):
         super(API, self).__init__()
         self.last_neutron_extension_sync = None
         self.extensions = {}
+        self.pci_whitelist = pci_whitelist.Whitelist(
+            CONF.pci.passthrough_whitelist)
 
     def _update_port_with_migration_profile(
             self, instance, port_id, port_profile, admin_client):
@@ -1025,8 +1015,18 @@ class API(base_api.NetworkAPI):
             self._refresh_neutron_extensions_cache(context, neutron=neutron)
         return constants.AUTO_ALLOCATE_TOPO_EXT in self.extensions
 
-    @staticmethod
-    def _populate_neutron_binding_profile(instance, pci_request_id,
+    def _get_pci_device_profile(self, pci_dev):
+        dev_spec = self.pci_whitelist.get_devspec(pci_dev)
+        if dev_spec:
+            return {'pci_vendor_info': "%s:%s" %
+                        (pci_dev.vendor_id, pci_dev.product_id),
+                    'pci_slot': pci_dev.address,
+                    'physical_network':
+                        dev_spec.get_tags().get('physical_network')}
+        raise exception.PciDeviceNotFound(node_id=pci_dev.compute_node_id,
+                                          address=pci_dev.address)
+
+    def _populate_neutron_binding_profile(self, instance, pci_request_id,
                                           port_req_body):
         """Populate neutron binding:profile.
 
@@ -1035,7 +1035,7 @@ class API(base_api.NetworkAPI):
         if pci_request_id:
             pci_dev = pci_manager.get_instance_pci_devs(
                 instance, pci_request_id).pop()
-            profile = get_pci_device_profile(pci_dev)
+            profile = self._get_pci_device_profile(pci_dev)
             port_req_body['port']['binding:profile'] = profile
 
     @staticmethod
@@ -2398,7 +2398,8 @@ class API(base_api.NetworkAPI):
                 pci_slot = binding_profile.get('pci_slot')
                 new_dev = pci_mapping.get(pci_slot)
                 if new_dev:
-                    binding_profile.update(get_pci_device_profile(new_dev))
+                    binding_profile.update(
+                        self._get_pci_device_profile(new_dev))
                     updates[BINDING_PROFILE] = binding_profile
                 else:
                     raise exception.PortUpdateFailed(port_id=p['id'],
index 5c3549064ad5f37b7dd67b1db3405a832d1c1976..ef7793f247fda7265fe640ecccd8e7db15add47b 100644 (file)
@@ -93,8 +93,3 @@ class Whitelist(object):
         for spec in self.specs:
             if spec.match_pci_obj(pci_dev):
                 return spec
-
-
-def get_pci_device_devspec(pci_dev):
-    dev_filter = Whitelist(CONF.pci.passthrough_whitelist)
-    return dev_filter.get_devspec(pci_dev)
index 59f67c8b8d49f3c39a5e71a9b6fbb1a7a13ad55b..8d17f1cf414c64d351681250f99bc29f99ae86bd 100644 (file)
@@ -3700,7 +3700,7 @@ class TestNeutronv2WithMock(test.TestCase):
         update_port_mock.assert_called_once_with(
             'fake-port-2', {'port': {'binding:host_id': instance.host}})
 
-    @mock.patch.object(pci_whitelist, 'get_pci_device_devspec')
+    @mock.patch.object(pci_whitelist.Whitelist, 'get_devspec')
     @mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
     def test_update_port_bindings_for_instance_with_pci(self,
                                             get_client_mock,
@@ -3756,7 +3756,7 @@ class TestNeutronv2WithMock(test.TestCase):
                                          'physical_network': 'physnet1',
                                          'pci_vendor_info': '1377:0047'}}})
 
-    @mock.patch.object(pci_whitelist, 'get_pci_device_devspec')
+    @mock.patch.object(pci_whitelist.Whitelist, 'get_devspec')
     @mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
     def test_update_port_bindings_for_instance_with_pci_fail(self,
                                             get_client_mock,
@@ -4573,7 +4573,7 @@ class TestNeutronv2Portbinding(TestNeutronv2Base):
         self.assertEqual(host_id, port_req_body['port']['binding:host_id'])
         self.assertFalse(port_req_body['port'].get('binding:profile'))
 
-    @mock.patch.object(pci_whitelist, 'get_pci_device_devspec')
+    @mock.patch.object(pci_whitelist.Whitelist, 'get_devspec')
     @mock.patch.object(pci_manager, 'get_instance_pci_devs')
     def test_populate_neutron_extension_values_binding_sriov(self,
                                          mock_get_instance_pci_devs,
@@ -4604,7 +4604,7 @@ class TestNeutronv2Portbinding(TestNeutronv2Base):
 
         self.assertEqual(profile, port_req_body['port']['binding:profile'])
 
-    @mock.patch.object(pci_whitelist, 'get_pci_device_devspec')
+    @mock.patch.object(pci_whitelist.Whitelist, 'get_devspec')
     @mock.patch.object(pci_manager, 'get_instance_pci_devs')
     def test_populate_neutron_extension_values_binding_sriov_fail(
         self, mock_get_instance_pci_devs, mock_get_pci_device_devspec):
@@ -4626,6 +4626,35 @@ class TestNeutronv2Portbinding(TestNeutronv2Base):
             exception.PciDeviceNotFound, api._populate_neutron_binding_profile,
             instance, pci_req_id, port_req_body)
 
+    @mock.patch.object(pci_manager, 'get_instance_pci_devs')
+    def test_pci_parse_whitelist_called_once(self,
+                                             mock_get_instance_pci_devs):
+        white_list = [
+            '{"address":"0000:0a:00.1","physical_network":"default"}']
+        cfg.CONF.set_override('passthrough_whitelist', white_list, 'pci')
+
+        api = neutronapi.API()
+        host_id = 'my_host_id'
+        instance = {'host': host_id}
+        pci_req_id = 'my_req_id'
+        port_req_body = {'port': {}}
+        pci_dev = {'vendor_id': '1377',
+                   'product_id': '0047',
+                   'address': '0000:0a:00.1',
+                  }
+
+        whitelist = pci_whitelist.Whitelist(CONF.pci.passthrough_whitelist)
+        with mock.patch.object(pci_whitelist.Whitelist,
+                '_parse_white_list_from_config',
+                wraps=whitelist._parse_white_list_from_config
+                ) as mock_parse_whitelist:
+            for i in range(2):
+                mydev = objects.PciDevice.create(None, pci_dev)
+                mock_get_instance_pci_devs.return_value = [mydev]
+                api._populate_neutron_binding_profile(instance,
+                                                  pci_req_id, port_req_body)
+                self.assertEqual(0, mock_parse_whitelist.call_count)
+
     def _populate_pci_mac_address_fakes(self):
         instance = fake_instance.fake_instance_obj(self.context)
         pci_dev = {'vendor_id': '1377',