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