Skip to content

Commit 87dd10d

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "[yoga] Add PCI VPD Capability Handling"
2 parents cc794b3 + ab49f97 commit 87dd10d

File tree

11 files changed

+642
-31
lines changed

11 files changed

+642
-31
lines changed

nova/network/neutron.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,8 @@ def _unbind_ports(self, context, ports,
667667
# for the physical device but don't want to overwrite the other
668668
# information in the binding profile.
669669
for profile_key in ('pci_vendor_info', 'pci_slot',
670-
constants.ALLOCATION, 'arq_uuid'):
670+
constants.ALLOCATION, 'arq_uuid',
671+
'physical_network', 'card_serial_number'):
671672
if profile_key in port_profile:
672673
del port_profile[profile_key]
673674
port_req_body['port'][constants.BINDING_PROFILE] = port_profile
@@ -1506,11 +1507,22 @@ def delete_port_binding(self, context, port_id, host):
15061507
def _get_pci_device_profile(self, pci_dev):
15071508
dev_spec = self.pci_whitelist.get_devspec(pci_dev)
15081509
if dev_spec:
1509-
return {'pci_vendor_info': "%s:%s" %
1510-
(pci_dev.vendor_id, pci_dev.product_id),
1511-
'pci_slot': pci_dev.address,
1512-
'physical_network':
1513-
dev_spec.get_tags().get('physical_network')}
1510+
dev_profile = {
1511+
'pci_vendor_info': "%s:%s"
1512+
% (pci_dev.vendor_id, pci_dev.product_id),
1513+
'pci_slot': pci_dev.address,
1514+
'physical_network': dev_spec.get_tags().get(
1515+
'physical_network'
1516+
),
1517+
}
1518+
if pci_dev.dev_type == obj_fields.PciDeviceType.SRIOV_VF:
1519+
card_serial_number = pci_dev.card_serial_number
1520+
if card_serial_number:
1521+
dev_profile.update({
1522+
'card_serial_number': card_serial_number
1523+
})
1524+
return dev_profile
1525+
15141526
raise exception.PciDeviceNotFound(node_id=pci_dev.compute_node_id,
15151527
address=pci_dev.address)
15161528

nova/objects/pci_device.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,12 @@ def free(self, instance=None):
511511
def is_available(self):
512512
return self.status == fields.PciDeviceStatus.AVAILABLE
513513

514+
@property
515+
def card_serial_number(self):
516+
caps_json = self.extra_info.get('capabilities', "{}")
517+
caps = jsonutils.loads(caps_json)
518+
return caps.get('vpd', {}).get('card_serial_number')
519+
514520

515521
@base.NovaObjectRegistry.register
516522
class PciDeviceList(base.ObjectListBase, base.NovaObject):

nova/tests/fixtures/libvirt_data.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,6 +2002,168 @@ def fake_kvm_guest():
20022002
</capability>
20032003
</device>
20042004
""",
2005+
# A PF with the VPD capability.
2006+
"pci_0000_82_00_0": """
2007+
<device>
2008+
<name>pci_0000_82_00_0</name>
2009+
<path>/sys/devices/pci0000:80/0000:80:03.0/0000:82:00.0</path>
2010+
<parent>pci_0000_80_03_0</parent>
2011+
<driver>
2012+
<name>mlx5_core</name>
2013+
</driver>
2014+
<capability type='pci'>
2015+
<class>0x020000</class>
2016+
<domain>0</domain>
2017+
<bus>130</bus>
2018+
<slot>0</slot>
2019+
<function>0</function>
2020+
<product id='0xa2d6'>MT42822 BlueField-2 integrated ConnectX-6 Dx network controller</product>
2021+
<vendor id='0x15b3'>Mellanox Technologies</vendor>
2022+
<capability type='virt_functions' maxCount='8'>
2023+
<address domain='0x0000' bus='0x82' slot='0x00' function='0x3'/>
2024+
<address domain='0x0000' bus='0x82' slot='0x00' function='0x4'/>
2025+
<address domain='0x0000' bus='0x82' slot='0x00' function='0x5'/>
2026+
<address domain='0x0000' bus='0x82' slot='0x00' function='0x6'/>
2027+
<address domain='0x0000' bus='0x82' slot='0x00' function='0x7'/>
2028+
<address domain='0x0000' bus='0x82' slot='0x01' function='0x0'/>
2029+
<address domain='0x0000' bus='0x82' slot='0x01' function='0x1'/>
2030+
<address domain='0x0000' bus='0x82' slot='0x01' function='0x2'/>
2031+
</capability>
2032+
<capability type='vpd'>
2033+
<name>BlueField-2 DPU 25GbE Dual-Port SFP56, Crypto Enabled, 16GB on-board DDR, 1GbE OOB management, Tall Bracket</name>
2034+
<fields access='readonly'>
2035+
<change_level>B1</change_level>
2036+
<manufacture_id>foobar</manufacture_id>
2037+
<part_number>MBF2H332A-AEEOT</part_number>
2038+
<serial_number>MT2113X00000</serial_number>
2039+
<vendor_field index='0'>PCIeGen4 x8</vendor_field>
2040+
<vendor_field index='2'>MBF2H332A-AEEOT</vendor_field>
2041+
<vendor_field index='3'>3c53d07eec484d8aab34dabd24fe575aa</vendor_field>
2042+
<vendor_field index='A'>MLX:MN=MLNX:CSKU=V2:UUID=V3:PCI=V0:MODL=BF2H332A</vendor_field>
2043+
</fields>
2044+
<fields access='readwrite'>
2045+
<asset_tag>fooasset</asset_tag>
2046+
<vendor_field index='0'>vendorfield0</vendor_field>
2047+
<vendor_field index='2'>vendorfield2</vendor_field>
2048+
<vendor_field index='A'>vendorfieldA</vendor_field>
2049+
<system_field index='B'>systemfieldB</system_field>
2050+
<system_field index='0'>systemfield0</system_field>
2051+
</fields>
2052+
</capability>
2053+
<iommuGroup number='65'>
2054+
<address domain='0x0000' bus='0x82' slot='0x00' function='0x0'/>
2055+
</iommuGroup>
2056+
<numa node='1'/>
2057+
<pci-express>
2058+
<link validity='cap' port='0' speed='16' width='8'/>
2059+
<link validity='sta' speed='8' width='8'/>
2060+
</pci-express>
2061+
</capability>
2062+
</device>""", # noqa:E501
2063+
# A VF without the VPD capability with a PF that has a VPD capability.
2064+
"pci_0000_82_00_3": """
2065+
<device>
2066+
<name>pci_0000_82_00_3</name>
2067+
<path>/sys/devices/pci0000:80/0000:80:03.0/0000:82:00.3</path>
2068+
<parent>pci_0000_80_03_0</parent>
2069+
<driver>
2070+
<name>mlx5_core</name>
2071+
</driver>
2072+
<capability type='pci'>
2073+
<class>0x020000</class>
2074+
<domain>0</domain>
2075+
<bus>130</bus>
2076+
<slot>0</slot>
2077+
<function>3</function>
2078+
<product id='0x101e'>ConnectX Family mlx5Gen Virtual Function</product>
2079+
<vendor id='0x15b3'>Mellanox Technologies</vendor>
2080+
<capability type='phys_function'>
2081+
<address domain='0x0000' bus='0x82' slot='0x00' function='0x0'/>
2082+
</capability>
2083+
<iommuGroup number='99'>
2084+
<address domain='0x0000' bus='0x82' slot='0x00' function='0x3'/>
2085+
</iommuGroup>
2086+
<numa node='1'/>
2087+
<pci-express>
2088+
<link validity='cap' port='0' speed='16' width='8'/>
2089+
<link validity='sta' width='0'/>
2090+
</pci-express>
2091+
</capability>
2092+
</device>""",
2093+
# A VF with the VPD capability but without a parent defined in test data
2094+
# so that the VPD cap is extracted from the VF directly.
2095+
"pci_0001_82_00_3": """
2096+
<device>
2097+
<name>pci_0001_82_00_3</name>
2098+
<path>/sys/devices/pci0001:80/0001:80:03.0/0001:82:00.3</path>
2099+
<parent>pci_0001_80_03_0</parent>
2100+
<driver>
2101+
<name>mlx5_core</name>
2102+
</driver>
2103+
<capability type='pci'>
2104+
<class>0x020000</class>
2105+
<domain>1</domain>
2106+
<bus>130</bus>
2107+
<slot>0</slot>
2108+
<function>3</function>
2109+
<product id='0x101e'>ConnectX Family mlx5Gen Virtual Function</product>
2110+
<vendor id='0x15b3'>Mellanox Technologies</vendor>
2111+
<capability type='phys_function'>
2112+
<address domain='0x0001' bus='0x82' slot='0x00' function='0x0'/>
2113+
</capability>
2114+
<capability type='vpd'>
2115+
<name>BlueField-2 DPU 25GbE Dual-Port SFP56, Crypto Enabled, 16GB on-board DDR, 1GbE OOB management, Tall Bracket</name>
2116+
<fields access='readonly'>
2117+
<change_level>B1</change_level>
2118+
<part_number>MBF2H332A-AEEOT</part_number>
2119+
<serial_number>MT2113XBEEF0</serial_number>
2120+
<vendor_field index='2'>MBF2H332A-AEEOT</vendor_field>
2121+
<vendor_field index='3'>9644e3586190eb118000b8cef671bf3e</vendor_field>
2122+
<vendor_field index='A'>MLX:MN=MLNX:CSKU=V2:UUID=V3:PCI=V0:MODL=BF2H332A</vendor_field>
2123+
<vendor_field index='0'>PCIeGen4 x8</vendor_field>
2124+
</fields>
2125+
</capability>
2126+
<iommuGroup number='99'>
2127+
<address domain='0x0001' bus='0x82' slot='0x00' function='0x3'/>
2128+
</iommuGroup>
2129+
<numa node='1'/>
2130+
<pci-express>
2131+
<link validity='cap' port='0' speed='16' width='8'/>
2132+
<link validity='sta' width='0'/>
2133+
</pci-express>
2134+
</capability>
2135+
</device>""", # noqa:E501
2136+
# A VF without the VPD capability and without a parent PF defined
2137+
# in the test data.
2138+
"pci_0002_82_00_3": """
2139+
<device>
2140+
<name>pci_0002_82_00_3</name>
2141+
<path>/sys/devices/pci0002:80/0002:80:03.0/0002:82:00.3</path>
2142+
<parent>pci_0002_80_03_0</parent>
2143+
<driver>
2144+
<name>mlx5_core</name>
2145+
</driver>
2146+
<capability type='pci'>
2147+
<class>0x020000</class>
2148+
<domain>2</domain>
2149+
<bus>130</bus>
2150+
<slot>0</slot>
2151+
<function>3</function>
2152+
<product id='0x101e'>ConnectX Family mlx5Gen Virtual Function</product>
2153+
<vendor id='0x15b3'>Mellanox Technologies</vendor>
2154+
<capability type='phys_function'>
2155+
<address domain='0x0002' bus='0x82' slot='0x00' function='0x0'/>
2156+
</capability>
2157+
<iommuGroup number='99'>
2158+
<address domain='0x0002' bus='0x82' slot='0x00' function='0x3'/>
2159+
</iommuGroup>
2160+
<numa node='1'/>
2161+
<pci-express>
2162+
<link validity='cap' port='0' speed='16' width='8'/>
2163+
<link validity='sta' width='0'/>
2164+
</pci-express>
2165+
</capability>
2166+
</device>""", # noqa:E501
20052167
}
20062168

20072169
_fake_NodeDevXml_parents = {

nova/tests/unit/network/test_neutron.py

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from nova.network import model
4040
from nova.network import neutron as neutronapi
4141
from nova import objects
42+
from nova.objects import fields as obj_fields
4243
from nova.objects import network_request as net_req_obj
4344
from nova.objects import virtual_interface as obj_vif
4445
from nova.pci import manager as pci_manager
@@ -4494,17 +4495,21 @@ def test_update_port_bindings_for_instance_with_pci(self,
44944495
instance = fake_instance.fake_instance_obj(self.context)
44954496
instance.migration_context = objects.MigrationContext()
44964497
instance.migration_context.old_pci_devices = objects.PciDeviceList(
4497-
objects=[objects.PciDevice(vendor_id='1377',
4498-
product_id='0047',
4499-
address='0000:0a:00.1',
4500-
compute_node_id=1,
4501-
request_id='1234567890')])
4498+
objects=[objects.PciDevice(
4499+
vendor_id='1377',
4500+
product_id='0047',
4501+
address='0000:0a:00.1',
4502+
compute_node_id=1,
4503+
request_id='1234567890',
4504+
dev_type=obj_fields.PciDeviceType.SRIOV_VF)])
45024505
instance.migration_context.new_pci_devices = objects.PciDeviceList(
4503-
objects=[objects.PciDevice(vendor_id='1377',
4504-
product_id='0047',
4505-
address='0000:0b:00.1',
4506-
compute_node_id=2,
4507-
request_id='1234567890')])
4506+
objects=[objects.PciDevice(
4507+
vendor_id='1377',
4508+
product_id='0047',
4509+
address='0000:0b:00.1',
4510+
compute_node_id=2,
4511+
request_id='1234567890',
4512+
dev_type=obj_fields.PciDeviceType.SRIOV_VF)])
45084513
instance.pci_devices = instance.migration_context.old_pci_devices
45094514

45104515
# Validate that non-direct port aren't updated (fake-port-2).
@@ -5928,14 +5933,14 @@ def test_unbind_ports_reset_binding_profile(self, mock_show):
59285933
'id': uuids.port,
59295934
'binding:profile': {'pci_vendor_info': '1377:0047',
59305935
'pci_slot': '0000:0a:00.1',
5936+
'card_serial_number': 'MT2113X00000',
59315937
'physical_network': 'physnet1',
59325938
'capabilities': ['switchdev']}
59335939
}
59345940
self.api._unbind_ports(self.context, ports, neutron, port_client)
59355941
port_req_body = {'port': {'binding:host_id': None,
59365942
'binding:profile':
5937-
{'physical_network': 'physnet1',
5938-
'capabilities': ['switchdev']},
5943+
{'capabilities': ['switchdev']},
59395944
'device_id': '',
59405945
'device_owner': ''}
59415946
}
@@ -7402,9 +7407,12 @@ def test_populate_neutron_extension_values_binding_sriov(self,
74027407
pci_dev = {'vendor_id': '1377',
74037408
'product_id': '0047',
74047409
'address': '0000:0a:00.1',
7410+
'card_serial_number': None,
7411+
'dev_type': 'TEST_TYPE',
74057412
}
74067413
PciDevice = collections.namedtuple('PciDevice',
7407-
['vendor_id', 'product_id', 'address'])
7414+
['vendor_id', 'product_id', 'address',
7415+
'card_serial_number', 'dev_type'])
74087416
mydev = PciDevice(**pci_dev)
74097417
profile = {'pci_vendor_info': '1377:0047',
74107418
'pci_slot': '0000:0a:00.1',
@@ -7422,6 +7430,43 @@ def test_populate_neutron_extension_values_binding_sriov(self,
74227430
port_req_body['port'][
74237431
constants.BINDING_PROFILE])
74247432

7433+
@mock.patch.object(pci_whitelist.Whitelist, 'get_devspec')
7434+
@mock.patch.object(pci_manager, 'get_instance_pci_devs')
7435+
def test_populate_neutron_extension_values_binding_sriov_card_serial(
7436+
self, mock_get_instance_pci_devs, mock_get_pci_device_devspec):
7437+
host_id = 'my_host_id'
7438+
instance = {'host': host_id}
7439+
port_req_body = {'port': {}}
7440+
pci_req_id = 'my_req_id'
7441+
pci_dev = {'vendor_id': 'a2d6',
7442+
'product_id': '15b3',
7443+
'address': '0000:82:00.1',
7444+
'card_serial_number': 'MT2113X00000',
7445+
'dev_type': obj_fields.PciDeviceType.SRIOV_VF,
7446+
}
7447+
PciDevice = collections.namedtuple('PciDevice',
7448+
['vendor_id', 'product_id', 'address',
7449+
'card_serial_number', 'dev_type'])
7450+
mydev = PciDevice(**pci_dev)
7451+
profile = {'pci_vendor_info': 'a2d6:15b3',
7452+
'pci_slot': '0000:82:00.1',
7453+
'physical_network': 'physnet1',
7454+
# card_serial_number is a property of the object obtained
7455+
# from extra_info.
7456+
'card_serial_number': 'MT2113X00000',
7457+
}
7458+
7459+
mock_get_instance_pci_devs.return_value = [mydev]
7460+
devspec = mock.Mock()
7461+
devspec.get_tags.return_value = {'physical_network': 'physnet1'}
7462+
mock_get_pci_device_devspec.return_value = devspec
7463+
self.api._populate_neutron_binding_profile(
7464+
instance, pci_req_id, port_req_body, None)
7465+
7466+
self.assertEqual(profile,
7467+
port_req_body['port'][
7468+
constants.BINDING_PROFILE])
7469+
74257470
def test_populate_neutron_extension_values_binding_arq(self):
74267471
host_id = 'my_host_id'
74277472
instance = {'host': host_id}
@@ -7474,9 +7519,12 @@ def test_populate_neutron_extension_values_binding_sriov_with_cap(self,
74747519
pci_dev = {'vendor_id': '1377',
74757520
'product_id': '0047',
74767521
'address': '0000:0a:00.1',
7522+
'card_serial_number': None,
7523+
'dev_type': 'TEST_TYPE',
74777524
}
74787525
PciDevice = collections.namedtuple('PciDevice',
7479-
['vendor_id', 'product_id', 'address'])
7526+
['vendor_id', 'product_id', 'address',
7527+
'card_serial_number', 'dev_type'])
74807528
mydev = PciDevice(**pci_dev)
74817529
profile = {'pci_vendor_info': '1377:0047',
74827530
'pci_slot': '0000:0a:00.1',
@@ -7547,6 +7595,7 @@ def test_pci_parse_whitelist_called_once(self,
75477595
pci_dev = {'vendor_id': '1377',
75487596
'product_id': '0047',
75497597
'address': '0000:0a:00.1',
7598+
'dev_type': obj_fields.PciDeviceType.SRIOV_VF,
75507599
}
75517600

75527601
whitelist = pci_whitelist.Whitelist(CONF.pci.passthrough_whitelist)

nova/tests/unit/objects/test_pci_device.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,16 @@ def test_pci_device_extra_info_with_dict(self):
161161
'vendor_id', 'numa_node', 'status', 'uuid',
162162
'extra_info', 'dev_type', 'parent_addr']))
163163

164+
def test_pci_device_extra_info_card_serial_number(self):
165+
self.dev_dict = copy.copy(dev_dict)
166+
self.pci_device = pci_device.PciDevice.create(None, self.dev_dict)
167+
self.assertIsNone(self.pci_device.card_serial_number)
168+
169+
self.dev_dict = copy.copy(dev_dict)
170+
self.dev_dict['capabilities'] = {'vpd': {'card_serial_number': '42'}}
171+
self.pci_device = pci_device.PciDevice.create(None, self.dev_dict)
172+
self.assertEqual(self.pci_device.card_serial_number, '42')
173+
164174
def test_update_device(self):
165175
self.pci_device = pci_device.PciDevice.create(None, dev_dict)
166176
self.pci_device.obj_reset_changes()

0 commit comments

Comments
 (0)