"Fossies" - the Fresh Open Source Software Archive

Member "nova-22.0.1/nova/tests/unit/pci/test_stats.py" (19 Nov 2020, 29833 Bytes) of package /linux/misc/openstack/nova-22.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_stats.py": 22.0.0_vs_22.0.1.

    1 # Copyright (c) 2012 OpenStack Foundation
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 import mock
   17 from oslo_config import cfg
   18 
   19 from nova import exception
   20 from nova import objects
   21 from nova.objects import fields
   22 from nova.pci import stats
   23 from nova.pci import whitelist
   24 from nova import test
   25 from nova.tests.unit.pci import fakes
   26 
   27 CONF = cfg.CONF
   28 fake_pci_1 = {
   29     'compute_node_id': 1,
   30     'address': '0000:00:00.1',
   31     'product_id': 'p1',
   32     'vendor_id': 'v1',
   33     'status': 'available',
   34     'extra_k1': 'v1',
   35     'request_id': None,
   36     'numa_node': 0,
   37     'dev_type': fields.PciDeviceType.STANDARD,
   38     'parent_addr': None,
   39     }
   40 
   41 
   42 fake_pci_2 = dict(fake_pci_1, vendor_id='v2',
   43                   product_id='p2',
   44                   address='0000:00:00.2',
   45                   numa_node=1)
   46 
   47 
   48 fake_pci_3 = dict(fake_pci_1, address='0000:00:00.3')
   49 
   50 fake_pci_4 = dict(fake_pci_1, vendor_id='v3',
   51                   product_id='p3',
   52                   address='0000:00:00.3',
   53                   numa_node= None)
   54 
   55 pci_requests = [objects.InstancePCIRequest(count=1,
   56                     spec=[{'vendor_id': 'v1'}]),
   57                 objects.InstancePCIRequest(count=1,
   58                     spec=[{'vendor_id': 'v2'}])]
   59 
   60 
   61 pci_requests_multiple = [objects.InstancePCIRequest(count=1,
   62                              spec=[{'vendor_id': 'v1'}]),
   63                          objects.InstancePCIRequest(count=3,
   64                           spec=[{'vendor_id': 'v2'}])]
   65 
   66 
   67 class PciDeviceStatsTestCase(test.NoDBTestCase):
   68 
   69     @staticmethod
   70     def _get_fake_requests(vendor_ids=None, numa_policy=None, count=1):
   71         if not vendor_ids:
   72             vendor_ids = ['v1', 'v2']
   73 
   74         specs = [{'vendor_id': vendor_id} for vendor_id in vendor_ids]
   75 
   76         return [objects.InstancePCIRequest(count=count, spec=[spec],
   77                 numa_policy=numa_policy) for spec in specs]
   78 
   79     def _create_fake_devs(self):
   80         self.fake_dev_1 = objects.PciDevice.create(None, fake_pci_1)
   81         self.fake_dev_2 = objects.PciDevice.create(None, fake_pci_2)
   82         self.fake_dev_3 = objects.PciDevice.create(None, fake_pci_3)
   83         self.fake_dev_4 = objects.PciDevice.create(None, fake_pci_4)
   84 
   85         for dev in [self.fake_dev_1, self.fake_dev_2,
   86                     self.fake_dev_3, self.fake_dev_4]:
   87             self.pci_stats.add_device(dev)
   88 
   89     def _add_fake_devs_with_numa(self):
   90         fake_pci = dict(fake_pci_1, vendor_id='v4', product_id='pr4')
   91         devs = [dict(fake_pci, product_id='pr0', numa_node=0, ),
   92                 dict(fake_pci, product_id='pr1', numa_node=1),
   93                 dict(fake_pci, product_id='pr_none', numa_node=None)]
   94 
   95         for dev in devs:
   96             self.pci_stats.add_device(objects.PciDevice.create(None, dev))
   97 
   98     def setUp(self):
   99         super(PciDeviceStatsTestCase, self).setUp()
  100         self.pci_stats = stats.PciDeviceStats()
  101         # The following two calls need to be made before adding the devices.
  102         patcher = fakes.fake_pci_whitelist()
  103         self.addCleanup(patcher.stop)
  104         self._create_fake_devs()
  105 
  106     def test_add_device(self):
  107         self.assertEqual(len(self.pci_stats.pools), 3)
  108         self.assertEqual(set([d['vendor_id'] for d in self.pci_stats]),
  109                          set(['v1', 'v2', 'v3']))
  110         self.assertEqual(set([d['count'] for d in self.pci_stats]),
  111                          set([1, 2]))
  112 
  113     def test_remove_device(self):
  114         self.pci_stats.remove_device(self.fake_dev_2)
  115         self.assertEqual(len(self.pci_stats.pools), 2)
  116         self.assertEqual(self.pci_stats.pools[0]['count'], 2)
  117         self.assertEqual(self.pci_stats.pools[0]['vendor_id'], 'v1')
  118 
  119     def test_remove_device_exception(self):
  120         self.pci_stats.remove_device(self.fake_dev_2)
  121         self.assertRaises(exception.PciDevicePoolEmpty,
  122                           self.pci_stats.remove_device,
  123                           self.fake_dev_2)
  124 
  125     def test_pci_stats_equivalent(self):
  126         pci_stats2 = stats.PciDeviceStats()
  127         for dev in [self.fake_dev_1,
  128                     self.fake_dev_2,
  129                     self.fake_dev_3,
  130                     self.fake_dev_4]:
  131             pci_stats2.add_device(dev)
  132         self.assertEqual(self.pci_stats, pci_stats2)
  133 
  134     def test_pci_stats_not_equivalent(self):
  135         pci_stats2 = stats.PciDeviceStats()
  136         for dev in [self.fake_dev_1,
  137                     self.fake_dev_2,
  138                     self.fake_dev_3]:
  139             pci_stats2.add_device(dev)
  140         self.assertNotEqual(self.pci_stats, pci_stats2)
  141 
  142     def test_object_create(self):
  143         m = self.pci_stats.to_device_pools_obj()
  144         new_stats = stats.PciDeviceStats(m)
  145 
  146         self.assertEqual(len(new_stats.pools), 3)
  147         self.assertEqual(set([d['count'] for d in new_stats]),
  148                          set([1, 2]))
  149         self.assertEqual(set([d['vendor_id'] for d in new_stats]),
  150                          set(['v1', 'v2', 'v3']))
  151 
  152     def test_apply_requests(self):
  153         self.pci_stats.apply_requests(pci_requests)
  154         self.assertEqual(len(self.pci_stats.pools), 2)
  155         self.assertEqual(self.pci_stats.pools[0]['vendor_id'], 'v1')
  156         self.assertEqual(self.pci_stats.pools[0]['count'], 1)
  157 
  158     def test_apply_requests_failed(self):
  159         self.assertRaises(exception.PciDeviceRequestFailed,
  160             self.pci_stats.apply_requests,
  161             pci_requests_multiple)
  162 
  163     def test_support_requests(self):
  164         self.assertTrue(self.pci_stats.support_requests(pci_requests))
  165         self.assertEqual(len(self.pci_stats.pools), 3)
  166         self.assertEqual(set([d['count'] for d in self.pci_stats]),
  167                          set((1, 2)))
  168 
  169     def test_support_requests_failed(self):
  170         self.assertFalse(
  171             self.pci_stats.support_requests(pci_requests_multiple))
  172         self.assertEqual(len(self.pci_stats.pools), 3)
  173         self.assertEqual(set([d['count'] for d in self.pci_stats]),
  174                          set([1, 2]))
  175 
  176     def test_support_requests_numa(self):
  177         cells = [
  178             objects.InstanceNUMACell(
  179                 id=0, cpuset=set(), pcpuset=set(), memory=0),
  180             objects.InstanceNUMACell(
  181                 id=1, cpuset=set(), pcpuset=set(), memory=0),
  182         ]
  183         self.assertTrue(self.pci_stats.support_requests(pci_requests, cells))
  184 
  185     def test_support_requests_numa_failed(self):
  186         cells = [
  187             objects.InstanceNUMACell(
  188                 id=0, cpuset=set(), pcpuset=set(), memory=0),
  189         ]
  190         self.assertFalse(self.pci_stats.support_requests(pci_requests, cells))
  191 
  192     def test_support_requests_no_numa_info(self):
  193         cells = [
  194             objects.InstanceNUMACell(
  195                 id=0, cpuset=set(), pcpuset=set(), memory=0),
  196         ]
  197         pci_requests = self._get_fake_requests(vendor_ids=['v3'])
  198         self.assertTrue(self.pci_stats.support_requests(pci_requests, cells))
  199 
  200         # 'legacy' is the default numa_policy so the result must be same
  201         pci_requests = self._get_fake_requests(vendor_ids=['v3'],
  202             numa_policy = fields.PCINUMAAffinityPolicy.LEGACY)
  203         self.assertTrue(self.pci_stats.support_requests(pci_requests, cells))
  204 
  205     def test_support_requests_numa_pci_numa_policy_preferred(self):
  206         # numa node 0 has 2 devices with vendor_id 'v1'
  207         # numa node 1 has 1 device with vendor_id 'v2'
  208         # we request two devices with vendor_id 'v1' and 'v2'.
  209         # pci_numa_policy is 'preferred' so we can ignore numa affinity
  210         cells = [
  211             objects.InstanceNUMACell(
  212                 id=0, cpuset=set(), pcpuset=set(), memory=0),
  213         ]
  214         pci_requests = self._get_fake_requests(
  215             numa_policy=fields.PCINUMAAffinityPolicy.PREFERRED)
  216 
  217         self.assertTrue(self.pci_stats.support_requests(pci_requests, cells))
  218 
  219     def test_support_requests_no_numa_info_pci_numa_policy_required(self):
  220         # pci device with vendor_id 'v3' has numa_node=None.
  221         # pci_numa_policy is 'required' so we can't use this device
  222         cells = [
  223             objects.InstanceNUMACell(
  224                 id=0, cpuset=set(), pcpuset=set(), memory=0),
  225         ]
  226         pci_requests = self._get_fake_requests(vendor_ids=['v3'],
  227             numa_policy=fields.PCINUMAAffinityPolicy.REQUIRED)
  228 
  229         self.assertFalse(self.pci_stats.support_requests(pci_requests, cells))
  230 
  231     def test_consume_requests(self):
  232         devs = self.pci_stats.consume_requests(pci_requests)
  233         self.assertEqual(2, len(devs))
  234         self.assertEqual(set(['v1', 'v2']),
  235                          set([dev.vendor_id for dev in devs]))
  236 
  237     def test_consume_requests_empty(self):
  238         devs = self.pci_stats.consume_requests([])
  239         self.assertEqual(0, len(devs))
  240 
  241     def test_consume_requests_failed(self):
  242         self.assertIsNone(self.pci_stats.consume_requests(
  243                           pci_requests_multiple))
  244 
  245     def test_consume_requests_numa(self):
  246         cells = [
  247             objects.InstanceNUMACell(
  248                 id=0, cpuset=set(), pcpuset=set(), memory=0),
  249             objects.InstanceNUMACell(
  250                 id=1, cpuset=set(), pcpuset=set(), memory=0),
  251         ]
  252         devs = self.pci_stats.consume_requests(pci_requests, cells)
  253         self.assertEqual(2, len(devs))
  254         self.assertEqual(set(['v1', 'v2']),
  255                          set([dev.vendor_id for dev in devs]))
  256 
  257     def test_consume_requests_numa_failed(self):
  258         cells = [
  259             objects.InstanceNUMACell(
  260                 id=0, cpuset=set(), pcpuset=set(), memory=0),
  261         ]
  262         self.assertIsNone(self.pci_stats.consume_requests(pci_requests, cells))
  263 
  264     def test_consume_requests_no_numa_info(self):
  265         cells = [
  266             objects.InstanceNUMACell(
  267                 id=0, cpuset=set(), pcpuset=set(), memory=0),
  268         ]
  269         pci_request = [objects.InstancePCIRequest(count=1,
  270                                                   spec=[{'vendor_id': 'v3'}])]
  271         devs = self.pci_stats.consume_requests(pci_request, cells)
  272         self.assertEqual(1, len(devs))
  273         self.assertEqual(set(['v3']),
  274                          set([dev.vendor_id for dev in devs]))
  275 
  276     def _test_consume_requests_numa_policy(self, cell_ids, policy,
  277             expected, vendor_id='v4', count=1):
  278         """Base test for 'consume_requests' function.
  279 
  280         Create three devices with vendor_id of 'v4': 'pr0' in NUMA node 0,
  281         'pr1' in NUMA node 1, 'pr_none' without NUMA affinity info. Attempt to
  282         consume a PCI request with a single device with ``vendor_id`` using the
  283         provided ``cell_ids`` and ``policy``. Compare result against
  284         ``expected``.
  285         """
  286         self._add_fake_devs_with_numa()
  287         cells = [
  288             objects.InstanceNUMACell(
  289                 id=id, cpuset=set(), pcpuset=set(), memory=0)
  290             for id in cell_ids]
  291 
  292         pci_requests = self._get_fake_requests(vendor_ids=[vendor_id],
  293             numa_policy=policy, count=count)
  294         devs = self.pci_stats.consume_requests(pci_requests, cells)
  295 
  296         if expected is None:
  297             self.assertIsNone(devs)
  298         else:
  299             self.assertEqual(set(expected),
  300                              set([dev.product_id for dev in devs]))
  301 
  302     def test_consume_requests_numa_policy_required(self):
  303         """Ensure REQUIRED policy will ensure NUMA affinity.
  304 
  305         Policy is 'required' which means we must use a device with strict NUMA
  306         affinity. Request a device from NUMA node 0, which contains such a
  307         device, and ensure it's used.
  308         """
  309         self._test_consume_requests_numa_policy(
  310             [0], fields.PCINUMAAffinityPolicy.REQUIRED, ['pr0'])
  311 
  312     def test_consume_requests_numa_policy_required_fail(self):
  313         """Ensure REQUIRED policy will *only* provide NUMA affinity.
  314 
  315         Policy is 'required' which means we must use a device with strict NUMA
  316         affinity. Request a device from NUMA node 999, which does not contain
  317         any suitable devices, and ensure nothing is returned.
  318         """
  319         self._test_consume_requests_numa_policy(
  320             [999], fields.PCINUMAAffinityPolicy.REQUIRED, None)
  321 
  322     def test_consume_requests_numa_policy_legacy(self):
  323         """Ensure LEGACY policy will ensure NUMA affinity if possible.
  324 
  325         Policy is 'legacy' which means we must use a device with strict NUMA
  326         affinity or no provided NUMA affinity. Request a device from NUMA node
  327         0, which contains such a device, and ensure it's used.
  328         """
  329         self._test_consume_requests_numa_policy(
  330             [0], fields.PCINUMAAffinityPolicy.LEGACY, ['pr0'])
  331 
  332     def test_consume_requests_numa_policy_legacy_fallback(self):
  333         """Ensure LEGACY policy will fallback to no NUMA affinity.
  334 
  335         Policy is 'legacy' which means we must use a device with strict NUMA
  336         affinity or no provided NUMA affinity. Request a device from NUMA node
  337         999, which contains no such device, and ensure we fallback to the
  338         device without any NUMA affinity.
  339         """
  340         self._test_consume_requests_numa_policy(
  341             [999], fields.PCINUMAAffinityPolicy.LEGACY, ['pr_none'])
  342 
  343     def test_consume_requests_numa_policy_legacy_multiple(self):
  344         """Ensure LEGACY policy will use best policy for multiple devices.
  345 
  346         Policy is 'legacy' which means we must use a device with strict NUMA
  347         affinity or no provided NUMA affinity. Request two devices from NUMA
  348         node 0, which contains only one such device, and ensure we use that
  349         device and the next best thing for the second device.
  350         """
  351         self._test_consume_requests_numa_policy(
  352             [0], fields.PCINUMAAffinityPolicy.PREFERRED, ['pr0', 'pr_none'],
  353             count=2)
  354 
  355     def test_consume_requests_numa_policy_legacy_fail(self):
  356         """Ensure REQUIRED policy will *not* provide NUMA non-affinity.
  357 
  358         Policy is 'legacy' which means we must use a device with strict NUMA
  359         affinity or no provided NUMA affinity. Request a device with
  360         ``vendor_id`` of ``v2``, which can only be found in NUMA node 1, from
  361         NUMA node 0, and ensure nothing is returned.
  362         """
  363         self._test_consume_requests_numa_policy(
  364             [0], fields.PCINUMAAffinityPolicy.LEGACY, None, vendor_id='v2')
  365 
  366     def test_consume_requests_numa_policy_preferred(self):
  367         """Ensure PREFERRED policy will ensure NUMA affinity if possible.
  368 
  369         Policy is 'preferred' which means we must use a device with any level
  370         of NUMA affinity. Request a device from NUMA node 0, which contains
  371         an affined device, and ensure it's used.
  372         """
  373         self._test_consume_requests_numa_policy(
  374             [0], fields.PCINUMAAffinityPolicy.PREFERRED, ['pr0'])
  375 
  376     def test_consume_requests_numa_policy_preferred_fallback_a(self):
  377         """Ensure PREFERRED policy will fallback to no NUMA affinity.
  378 
  379         Policy is 'preferred' which means we must use a device with any level
  380         of NUMA affinity. Request a device from NUMA node 999, which contains
  381         no such device, and ensure we fallback to the device without any NUMA
  382         affinity.
  383         """
  384         self._test_consume_requests_numa_policy(
  385             [999], fields.PCINUMAAffinityPolicy.PREFERRED, ['pr_none'])
  386 
  387     def test_consume_requests_numa_policy_preferred_fallback_b(self):
  388         """Ensure PREFERRED policy will fallback to different NUMA affinity.
  389 
  390         Policy is 'preferred' which means we must use a device with any level
  391         of NUMA affinity. Request a device with ``vendor_id`` of ``v2``, which
  392         can only be found in NUMA node 1, from NUMA node 0, and ensure we
  393         fallback to this device.
  394         """
  395         self._test_consume_requests_numa_policy(
  396             [0], fields.PCINUMAAffinityPolicy.PREFERRED, ['p2'],
  397             vendor_id='v2')
  398 
  399     def test_consume_requests_numa_policy_preferred_multiple_a(self):
  400         """Ensure PREFERRED policy will use best policy for multiple devices.
  401 
  402         Policy is 'preferred' which means we must use a device with any level
  403         of NUMA affinity. Request two devices from NUMA node 0, which contains
  404         only one such device, and ensure we use that device and gracefully
  405         degrade for the other device.
  406         """
  407         self._test_consume_requests_numa_policy(
  408             [0], fields.PCINUMAAffinityPolicy.PREFERRED, ['pr0', 'pr_none'],
  409             count=2)
  410 
  411     def test_consume_requests_numa_policy_preferred_multiple_b(self):
  412         """Ensure PREFERRED policy will use best policy for multiple devices.
  413 
  414         Policy is 'preferred' which means we must use a device with any level
  415         of NUMA affinity. Request three devices from NUMA node 0, which
  416         contains only one such device, and ensure we use that device and
  417         gracefully degrade for the other devices.
  418         """
  419         self._test_consume_requests_numa_policy(
  420             [0], fields.PCINUMAAffinityPolicy.PREFERRED,
  421             ['pr0', 'pr_none', 'pr1'], count=3)
  422 
  423     @mock.patch(
  424         'nova.pci.whitelist.Whitelist._parse_white_list_from_config')
  425     def test_white_list_parsing(self, mock_whitelist_parse):
  426         white_list = '{"product_id":"0001", "vendor_id":"8086"}'
  427         CONF.set_override('passthrough_whitelist', white_list, 'pci')
  428         pci_stats = stats.PciDeviceStats()
  429         pci_stats.add_device(self.fake_dev_2)
  430         pci_stats.remove_device(self.fake_dev_2)
  431         self.assertEqual(1, mock_whitelist_parse.call_count)
  432 
  433 
  434 class PciDeviceStatsWithTagsTestCase(test.NoDBTestCase):
  435 
  436     def setUp(self):
  437         super(PciDeviceStatsWithTagsTestCase, self).setUp()
  438         white_list = ['{"vendor_id":"1137","product_id":"0071",'
  439                         '"address":"*:0a:00.*","physical_network":"physnet1"}',
  440                        '{"vendor_id":"1137","product_id":"0072"}']
  441         self.flags(passthrough_whitelist=white_list, group='pci')
  442         dev_filter = whitelist.Whitelist(white_list)
  443         self.pci_stats = stats.PciDeviceStats(dev_filter=dev_filter)
  444 
  445     def _create_pci_devices(self):
  446         self.pci_tagged_devices = []
  447         for dev in range(4):
  448             pci_dev = {'compute_node_id': 1,
  449                        'address': '0000:0a:00.%d' % dev,
  450                        'vendor_id': '1137',
  451                        'product_id': '0071',
  452                        'status': 'available',
  453                        'request_id': None,
  454                        'dev_type': 'type-PCI',
  455                        'parent_addr': None,
  456                        'numa_node': 0}
  457             self.pci_tagged_devices.append(objects.PciDevice.create(None,
  458                                                                     pci_dev))
  459 
  460         self.pci_untagged_devices = []
  461         for dev in range(3):
  462             pci_dev = {'compute_node_id': 1,
  463                        'address': '0000:0b:00.%d' % dev,
  464                        'vendor_id': '1137',
  465                        'product_id': '0072',
  466                        'status': 'available',
  467                        'request_id': None,
  468                        'dev_type': 'type-PCI',
  469                        'parent_addr': None,
  470                        'numa_node': 0}
  471             self.pci_untagged_devices.append(objects.PciDevice.create(None,
  472                                                                       pci_dev))
  473 
  474         for dev in self.pci_tagged_devices:
  475             self.pci_stats.add_device(dev)
  476 
  477         for dev in self.pci_untagged_devices:
  478             self.pci_stats.add_device(dev)
  479 
  480     def _assertPoolContent(self, pool, vendor_id, product_id, count, **tags):
  481         self.assertEqual(vendor_id, pool['vendor_id'])
  482         self.assertEqual(product_id, pool['product_id'])
  483         self.assertEqual(count, pool['count'])
  484         if tags:
  485             for k, v in tags.items():
  486                 self.assertEqual(v, pool[k])
  487 
  488     def _assertPools(self):
  489         # Pools are ordered based on the number of keys. 'product_id',
  490         # 'vendor_id' are always part of the keys. When tags are present,
  491         # they are also part of the keys. In this test class, we have
  492         # two pools with the second one having the tag 'physical_network'
  493         # and the value 'physnet1'
  494         self.assertEqual(2, len(self.pci_stats.pools))
  495         self._assertPoolContent(self.pci_stats.pools[0], '1137', '0072',
  496                                 len(self.pci_untagged_devices))
  497         self.assertEqual(self.pci_untagged_devices,
  498                          self.pci_stats.pools[0]['devices'])
  499         self._assertPoolContent(self.pci_stats.pools[1], '1137', '0071',
  500                                 len(self.pci_tagged_devices),
  501                                 physical_network='physnet1')
  502         self.assertEqual(self.pci_tagged_devices,
  503                          self.pci_stats.pools[1]['devices'])
  504 
  505     def test_add_devices(self):
  506         self._create_pci_devices()
  507         self._assertPools()
  508 
  509     def test_consume_requests(self):
  510         self._create_pci_devices()
  511         pci_requests = [objects.InstancePCIRequest(count=1,
  512                             spec=[{'physical_network': 'physnet1'}]),
  513                         objects.InstancePCIRequest(count=1,
  514                             spec=[{'vendor_id': '1137',
  515                                    'product_id': '0072'}])]
  516         devs = self.pci_stats.consume_requests(pci_requests)
  517         self.assertEqual(2, len(devs))
  518         self.assertEqual(set(['0071', '0072']),
  519                          set([dev.product_id for dev in devs]))
  520         self._assertPoolContent(self.pci_stats.pools[0], '1137', '0072', 2)
  521         self._assertPoolContent(self.pci_stats.pools[1], '1137', '0071', 3,
  522                                 physical_network='physnet1')
  523 
  524     def test_add_device_no_devspec(self):
  525         self._create_pci_devices()
  526         pci_dev = {'compute_node_id': 1,
  527                    'address': '0000:0c:00.1',
  528                    'vendor_id': '2345',
  529                    'product_id': '0172',
  530                    'status': 'available',
  531                    'parent_addr': None,
  532                    'request_id': None}
  533         pci_dev_obj = objects.PciDevice.create(None, pci_dev)
  534         self.pci_stats.add_device(pci_dev_obj)
  535         # There should be no change
  536         self.assertIsNone(
  537             self.pci_stats._create_pool_keys_from_dev(pci_dev_obj))
  538         self._assertPools()
  539 
  540     def test_remove_device_no_devspec(self):
  541         self._create_pci_devices()
  542         pci_dev = {'compute_node_id': 1,
  543                    'address': '0000:0c:00.1',
  544                    'vendor_id': '2345',
  545                    'product_id': '0172',
  546                    'status': 'available',
  547                    'parent_addr': None,
  548                    'request_id': None}
  549         pci_dev_obj = objects.PciDevice.create(None, pci_dev)
  550         self.pci_stats.remove_device(pci_dev_obj)
  551         # There should be no change
  552         self.assertIsNone(
  553             self.pci_stats._create_pool_keys_from_dev(pci_dev_obj))
  554         self._assertPools()
  555 
  556     def test_remove_device(self):
  557         self._create_pci_devices()
  558         dev1 = self.pci_untagged_devices.pop()
  559         self.pci_stats.remove_device(dev1)
  560         dev2 = self.pci_tagged_devices.pop()
  561         self.pci_stats.remove_device(dev2)
  562         self._assertPools()
  563 
  564     def test_update_device(self):
  565         # Update device type of one of the device from type-PCI to
  566         # type-PF. Verify if the existing pool is updated and a new
  567         # pool is created with dev_type type-PF.
  568         self._create_pci_devices()
  569         dev1 = self.pci_tagged_devices.pop()
  570         dev1.dev_type = 'type-PF'
  571         self.pci_stats.update_device(dev1)
  572         self.assertEqual(3, len(self.pci_stats.pools))
  573         self._assertPoolContent(self.pci_stats.pools[0], '1137', '0072',
  574                                 len(self.pci_untagged_devices))
  575         self.assertEqual(self.pci_untagged_devices,
  576                          self.pci_stats.pools[0]['devices'])
  577         self._assertPoolContent(self.pci_stats.pools[1], '1137', '0071',
  578                                 len(self.pci_tagged_devices),
  579                                 physical_network='physnet1')
  580         self.assertEqual(self.pci_tagged_devices,
  581                          self.pci_stats.pools[1]['devices'])
  582         self._assertPoolContent(self.pci_stats.pools[2], '1137', '0071',
  583                                 1,
  584                                 physical_network='physnet1')
  585         self.assertEqual(dev1,
  586                          self.pci_stats.pools[2]['devices'][0])
  587 
  588 
  589 class PciDeviceVFPFStatsTestCase(test.NoDBTestCase):
  590 
  591     def setUp(self):
  592         super(PciDeviceVFPFStatsTestCase, self).setUp()
  593         white_list = ['{"vendor_id":"8086","product_id":"1528"}',
  594                       '{"vendor_id":"8086","product_id":"1515"}']
  595         self.flags(passthrough_whitelist=white_list, group='pci')
  596         self.pci_stats = stats.PciDeviceStats()
  597 
  598     def _create_pci_devices(self, vf_product_id=1515, pf_product_id=1528):
  599         self.sriov_pf_devices = []
  600         for dev in range(2):
  601             pci_dev = {'compute_node_id': 1,
  602                        'address': '0000:81:00.%d' % dev,
  603                        'vendor_id': '8086',
  604                        'product_id': '%d' % pf_product_id,
  605                        'status': 'available',
  606                        'request_id': None,
  607                        'dev_type': fields.PciDeviceType.SRIOV_PF,
  608                        'parent_addr': None,
  609                        'numa_node': 0}
  610             dev_obj = objects.PciDevice.create(None, pci_dev)
  611             dev_obj.child_devices = []
  612             self.sriov_pf_devices.append(dev_obj)
  613 
  614         self.sriov_vf_devices = []
  615         for dev in range(8):
  616             pci_dev = {'compute_node_id': 1,
  617                        'address': '0000:81:10.%d' % dev,
  618                        'vendor_id': '8086',
  619                        'product_id': '%d' % vf_product_id,
  620                        'status': 'available',
  621                        'request_id': None,
  622                        'dev_type': fields.PciDeviceType.SRIOV_VF,
  623                        'parent_addr': '0000:81:00.%d' % int(dev / 4),
  624                        'numa_node': 0}
  625             dev_obj = objects.PciDevice.create(None, pci_dev)
  626             dev_obj.parent_device = self.sriov_pf_devices[int(dev / 4)]
  627             dev_obj.parent_device.child_devices.append(dev_obj)
  628             self.sriov_vf_devices.append(dev_obj)
  629 
  630         list(map(self.pci_stats.add_device, self.sriov_pf_devices))
  631         list(map(self.pci_stats.add_device, self.sriov_vf_devices))
  632 
  633     def test_consume_VF_requests(self):
  634         self._create_pci_devices()
  635         pci_requests = [objects.InstancePCIRequest(count=2,
  636                             spec=[{'product_id': '1515'}])]
  637         devs = self.pci_stats.consume_requests(pci_requests)
  638         self.assertEqual(2, len(devs))
  639         self.assertEqual(set(['1515']),
  640                             set([dev.product_id for dev in devs]))
  641         free_devs = self.pci_stats.get_free_devs()
  642         # Validate that the parents of these VFs has been removed
  643         # from pools.
  644         for dev in devs:
  645             self.assertNotIn(dev.parent_addr,
  646                              [free_dev.address for free_dev in free_devs])
  647 
  648     def test_consume_PF_requests(self):
  649         self._create_pci_devices()
  650         pci_requests = [objects.InstancePCIRequest(count=2,
  651                             spec=[{'product_id': '1528',
  652                                     'dev_type': 'type-PF'}])]
  653         devs = self.pci_stats.consume_requests(pci_requests)
  654         self.assertEqual(2, len(devs))
  655         self.assertEqual(set(['1528']),
  656                             set([dev.product_id for dev in devs]))
  657         free_devs = self.pci_stats.get_free_devs()
  658         # Validate that there are no free devices left, as when allocating
  659         # both available PFs, its VFs should not be available.
  660         self.assertEqual(0, len(free_devs))
  661 
  662     def test_consume_VF_and_PF_requests(self):
  663         self._create_pci_devices()
  664         pci_requests = [objects.InstancePCIRequest(count=2,
  665                             spec=[{'product_id': '1515'}]),
  666                         objects.InstancePCIRequest(count=1,
  667                             spec=[{'product_id': '1528',
  668                                     'dev_type': 'type-PF'}])]
  669         devs = self.pci_stats.consume_requests(pci_requests)
  670         self.assertEqual(3, len(devs))
  671         self.assertEqual(set(['1528', '1515']),
  672                             set([dev.product_id for dev in devs]))
  673 
  674     def test_consume_VF_and_PF_requests_failed(self):
  675         self._create_pci_devices()
  676         pci_requests = [objects.InstancePCIRequest(count=5,
  677                             spec=[{'product_id': '1515'}]),
  678                         objects.InstancePCIRequest(count=1,
  679                             spec=[{'product_id': '1528',
  680                                     'dev_type': 'type-PF'}])]
  681         self.assertIsNone(self.pci_stats.consume_requests(pci_requests))
  682 
  683     def test_consume_VF_and_PF_same_prodict_id_failed(self):
  684         self._create_pci_devices(pf_product_id=1515)
  685         pci_requests = [objects.InstancePCIRequest(count=9,
  686                             spec=[{'product_id': '1515'}])]
  687         self.assertIsNone(self.pci_stats.consume_requests(pci_requests))