Don't parse PCI whitelist every time neutron ports are created

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
This commit is contained in:
Ludovic Beliveau 2016-07-04 09:45:07 -04:00
parent 0412225890
commit 53ab6068a3
3 changed files with 50 additions and 25 deletions

View 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'],

View 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)

View 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',