Merge "Store pf_mac_address and vf_num in extra_info"

This commit is contained in:
Zuul 2022-04-29 12:25:42 +00:00 committed by Gerrit Code Review
commit 17755cc438
8 changed files with 96 additions and 106 deletions

View File

@ -84,7 +84,6 @@ from nova.objects import fields
from nova.objects import instance as obj_instance
from nova.objects import migrate_data as migrate_data_obj
from nova.pci import request as pci_req_module
from nova.pci import utils as pci_utils
from nova.pci import whitelist
from nova import safe_utils
from nova.scheduler.client import query
@ -10926,11 +10925,9 @@ class ComputeManager(manager.Manager):
# tagged as remote-managed have a serial in PCI VPD.
profile['card_serial_number'] = pci_dev.card_serial_number
if profile.get('pf_mac_address'):
profile['pf_mac_address'] = pci_utils.get_mac_by_pci_address(
pci_dev.parent_addr)
profile['pf_mac_address'] = pci_dev.sriov_cap['pf_mac_address']
if profile.get('vf_num'):
profile['vf_num'] = pci_utils.get_vf_num_by_pci_address(
pci_dev.address)
profile['vf_num'] = pci_dev.sriov_cap['vf_num']
mig_vif.profile = profile
LOG.debug("Updating migrate VIF profile for port %(port_id)s:"

View File

@ -1571,40 +1571,16 @@ class API:
forwarding.
"""
vf_profile: ty.Dict[str, ty.Union[str, int]] = {}
try:
pf_mac = pci_utils.get_mac_by_pci_address(pci_dev.parent_addr)
except (exception.PciDeviceNotFoundById) as e:
LOG.debug(
"Could not determine PF MAC address for a VF with"
" addr %(addr)s, error: %(e)s",
{"addr": pci_dev.address, "e": e})
# NOTE(dmitriis): we do not raise here since not all PFs will
# have netdevs even when VFs are netdevs (see LP: #1915255). The
# rest of the fields (VF number and card serial) are not enough
# to fully identify the VF so they are not populated either.
return vf_profile
try:
vf_num = pci_utils.get_vf_num_by_pci_address(
pci_dev.address)
except exception.PciDeviceNotFoundById as e:
# This is unlikely to happen because the kernel has a common SR-IOV
# code that creates physfn symlinks, however, it would be better
# to avoid raising an exception here and simply warn an operator
# that things did not go as planned.
LOG.warning(
"Could not determine a VF logical number for a VF"
" with addr %(addr)s, error: %(e)s", {
"addr": pci_dev.address, "e": e})
return vf_profile
pf_mac = pci_dev.sriov_cap.get('pf_mac_address')
vf_num = pci_dev.sriov_cap.get('vf_num')
card_serial_number = pci_dev.card_serial_number
if card_serial_number:
if all((pf_mac, vf_num, card_serial_number)):
vf_profile.update({
'card_serial_number': card_serial_number
'card_serial_number': card_serial_number,
'pf_mac_address': pf_mac,
'vf_num': vf_num,
})
vf_profile.update({
'pf_mac_address': pf_mac,
'vf_num': vf_num,
})
return vf_profile
def _get_pci_device_profile(self, pci_dev):

View File

@ -517,6 +517,12 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject):
caps = jsonutils.loads(caps_json)
return caps.get('vpd', {}).get('card_serial_number')
@property
def sriov_cap(self):
caps_json = self.extra_info.get('capabilities', '{}')
caps = jsonutils.loads(caps_json)
return caps.get('sriov', {})
@base.NovaObjectRegistry.register
class PciDeviceList(base.ObjectListBase, base.NovaObject):

View File

@ -2185,6 +2185,27 @@ _fake_NodeDevXml = {
<capability type='80203'/>
</capability>
</device>""", # noqa:E501
"net_enp130s0f0v0_36_33_10_a3_94_65": """
<device>
<name>net_enp130s0f0v0_36_33_10_a3_94_64</name>
<path>/sys/devices/pci0002:80/0002:80:03.0/0002:82:00.3/net/enp130s0f0v0</path>
<parent>pci_0002_82_00_3</parent>
<capability type='net'>
<interface>enp130s0f0v0</interface>
<address>36:33:10:a3:94:65</address>
<link state='down'/>
<feature name='rx'/>
<feature name='tx'/>
<feature name='sg'/>
<feature name='tso'/>
<feature name='gso'/>
<feature name='gro'/>
<feature name='rxvlan'/>
<feature name='txvlan'/>
<feature name='rxhash'/>
<capability type='80203'/>
</capability>
</device>""", # noqa:E501
}
_fake_NodeDevXml_parents = {

View File

@ -294,8 +294,6 @@ class SRIOVServersTest(_PCIServersWithMigrationTestBase):
'pci_vendor_info': '8086:1515',
'pci_slot': '0000:81:00.2',
'physical_network': 'physnet4',
'pf_mac_address': '52:54:00:1e:59:c6',
'vf_num': 1,
},
port['binding:profile'],
)
@ -538,8 +536,6 @@ class SRIOVServersTest(_PCIServersWithMigrationTestBase):
# matching one)
'pci_slot': '0000:81:01.4',
'physical_network': 'physnet4',
'pf_mac_address': '52:54:00:1e:59:c6',
'vf_num': 1,
},
port['binding:profile'],
)
@ -572,8 +568,6 @@ class SRIOVServersTest(_PCIServersWithMigrationTestBase):
'pci_vendor_info': '8086:1515',
'pci_slot': '0000:81:00.2',
'physical_network': 'physnet4',
'pf_mac_address': '52:54:00:1e:59:c6',
'vf_num': 1,
},
port['binding:profile'],
)

View File

@ -7697,78 +7697,22 @@ class TestAPIPortbinding(TestAPIBase):
'address': '0000:0a:00.1',
'parent_addr': '0000:0a:00.0',
'card_serial_number': 'MT2113X00000',
'sriov_cap': {
'pf_mac_address': '52:54:00:1e:59:c6',
'vf_num': 1,
},
'dev_type': obj_fields.PciDeviceType.SRIOV_VF,
}
PciDevice = collections.namedtuple('PciDevice',
['vendor_id', 'product_id', 'address',
'card_serial_number', 'dev_type',
'parent_addr'])
'card_serial_number', 'sriov_cap',
'dev_type', 'parent_addr'])
mydev = PciDevice(**pci_dev)
self.assertEqual(self.api._get_vf_pci_device_profile(mydev),
{'pf_mac_address': '52:54:00:1e:59:c6',
'vf_num': 1,
'card_serial_number': 'MT2113X00000'})
@mock.patch.object(
pci_utils, 'get_mac_by_pci_address',
new=mock.MagicMock(
side_effect=exception.PciDeviceNotFoundById(id='0000:0a:00.1'))
)
def test__get_vf_pci_device_profile_invalid_pf_address(self):
pci_dev = {'vendor_id': 'a2d6',
'product_id': '15b3',
'address': '0000:0a:00.1',
'parent_addr': '0000:0a:00.0',
'card_serial_number': 'MT2113X00000',
'dev_type': obj_fields.PciDeviceType.SRIOV_VF,
}
PciDevice = collections.namedtuple('PciDevice',
['vendor_id', 'product_id', 'address',
'card_serial_number', 'dev_type',
'parent_addr'])
mydev = PciDevice(**pci_dev)
self.assertEqual(self.api._get_vf_pci_device_profile(mydev), {})
@mock.patch.object(
pci_utils, 'get_vf_num_by_pci_address',
new=mock.MagicMock(
side_effect=exception.PciDeviceNotFoundById(id='0000:0a:00.0'))
)
@mock.patch.object(
pci_utils, 'get_mac_by_pci_address',
new=mock.MagicMock(side_effect=(lambda vf_a: {
'0000:0a:00.0': '52:54:00:1e:59:c6'}.get(vf_a))))
def test__get_vf_pci_device_profile_invalid_vf_address(self):
pci_dev = {'vendor_id': 'a2d6',
'product_id': '15b3',
'address': '0000:0a:00.1',
'parent_addr': '0000:0a:00.0',
'card_serial_number': 'MT2113X00000',
'dev_type': obj_fields.PciDeviceType.SRIOV_VF,
}
PciDevice = collections.namedtuple('PciDevice',
['vendor_id', 'product_id', 'address',
'card_serial_number', 'dev_type',
'parent_addr'])
mydev = PciDevice(**pci_dev)
vf_profile = self.api._get_vf_pci_device_profile(mydev)
self.assertEqual(vf_profile, {})
def test__get_vf_pci_device_profile_not_vf_address(self):
pci_dev = {'vendor_id': 'a2d6',
'product_id': '15b3',
'address': '0000:0a:00.1',
'parent_addr': None,
'card_serial_number': 'MT2113X00000',
'dev_type': obj_fields.PciDeviceType.SRIOV_VF,
}
PciDevice = collections.namedtuple('PciDevice',
['vendor_id', 'product_id', 'address',
'card_serial_number', 'dev_type',
'parent_addr'])
mydev = PciDevice(**pci_dev)
self.assertEqual(self.api._get_vf_pci_device_profile(mydev), {})
@mock.patch.object(
neutronapi.API, '_get_vf_pci_device_profile',
new=mock.MagicMock(side_effect=(

View File

@ -1113,6 +1113,10 @@ Active: 8381604 kB
expect_vf = ["rx", "tx", "sg", "tso", "gso", "gro", "rxvlan", "txvlan"]
self.assertEqual(expect_vf, actualvf)
@mock.patch.object(pci_utils, 'get_mac_by_pci_address',
new=mock.MagicMock(
side_effect=exception.PciDeviceNotFoundById(
'0000:04:00.3')))
@mock.patch.object(pci_utils, 'get_ifname_by_pci_address')
def test_get_pcidev_info_non_nic(self, mock_get_ifname):
dev_name = "pci_0000_04_11_7"
@ -1184,7 +1188,9 @@ Active: 8381604 kB
"parent_ifname": "ens1",
"capabilities": {
"network": ["rx", "tx", "sg", "tso", "gso", "gro",
"rxvlan", "txvlan"]},
"rxvlan", "txvlan"],
"sriov": {"pf_mac_address": "52:54:00:1e:59:c6",
"vf_num": 1}},
}
self.assertEqual(expect_vf, actual_vf)
@ -1202,7 +1208,9 @@ Active: 8381604 kB
"parent_addr": '0000:04:00.3',
"capabilities": {
"network": ["rx", "tx", "sg", "tso", "gso", "gro",
"rxvlan", "txvlan"]},
"rxvlan", "txvlan"],
"sriov": {"pf_mac_address": "52:54:00:1e:59:c6",
"vf_num": 1}},
"parent_ifname": "ens1",
}
self.assertEqual(expect_vf, actual_vf)
@ -1284,6 +1292,8 @@ Active: 8381604 kB
"capabilities": {
"network": ["rx", "tx", "sg", "tso", "gso", "gro", "rxvlan",
"txvlan", "rxhash"],
"sriov": {"pf_mac_address": "52:54:00:1e:59:c6",
"vf_num": 1},
# Should be obtained from the parent PF in this case.
"vpd": {"card_serial_number": "MT2113X00000"}},
}
@ -1323,6 +1333,12 @@ Active: 8381604 kB
"vendor_id": "15b3",
"label": "label_15b3_101e",
"dev_type": obj_fields.PciDeviceType.SRIOV_VF,
'parent_ifname': 'ens1',
"capabilities": {
"network": ["rx", "tx", "sg", "tso", "gso", "gro",
"rxvlan", "txvlan", "rxhash"],
"sriov": {"pf_mac_address": "52:54:00:1e:59:c6",
"vf_num": 1}},
}
self.assertEqual(expect_vf, actual_vf)

View File

@ -1380,6 +1380,37 @@ class Host(object):
vpd_info = {'card_serial_number': card_serial_number}
return vpd_info
def _get_sriov_netdev_details(
device_dict: dict,
device: 'libvirt.virNodeDevice',
) -> ty.Dict[str, ty.Dict[str, ty.Any]]:
"""Get SR-IOV related information"""
sriov_info: ty.Dict[str, ty.Any] = {}
if device_dict.get('dev_type') != fields.PciDeviceType.SRIOV_VF:
return sriov_info
pf_addr = device_dict['parent_addr']
# A netdev VF may be associated with a PF which does not have a
# netdev as described in LP #1915255.
try:
sriov_info.update({
'pf_mac_address': pci_utils.get_mac_by_pci_address(pf_addr)
})
except exception.PciDeviceNotFoundById:
LOG.debug(f'Could not get a PF mac for {pf_addr}')
# For the purposes Nova uses this information currently,
# having both a PF MAC and a VF number is needed so we return
# an empty dict if a PF MAC is not available.
return {}
vf_num = pci_utils.get_vf_num_by_pci_address(
device_dict['address'])
sriov_info.update({'vf_num': vf_num})
return sriov_info
def _get_device_capabilities(
device_dict: dict,
device: 'libvirt.virNodeDevice',
@ -1398,6 +1429,11 @@ class Host(object):
pcinet_info = self._get_pcinet_info(device, net_devs)
if pcinet_info:
caps['network'] = pcinet_info
# Only attempt to get SR-IOV details if a VF is a netdev
# because there are no use cases for other dev types yet.
sriov_caps = _get_sriov_netdev_details(device_dict, dev)
if sriov_caps:
caps['sriov'] = sriov_caps
vpd_info = _get_vpd_details(device_dict, device, pci_devs)
if vpd_info: