diff --git a/nova/tests/fixtures/libvirt_data.py b/nova/tests/fixtures/libvirt_data.py
index 43fcc8c950ae..1302510ab9d1 100644
--- a/nova/tests/fixtures/libvirt_data.py
+++ b/nova/tests/fixtures/libvirt_data.py
@@ -2163,6 +2163,27 @@ _fake_NodeDevXml = {
+ """,
+ "net_enp130s0f0v0_36_33_10_a3_94_64": """
+
+ net_enp130s0f0v0_36_33_10_a3_94_64
+ /sys/devices/pci0000:80/0000:80:03.0/0000:82:00.3/net/enp130s0f0v0
+ pci_0000_82_00_3
+
+ enp130s0f0v0
+ 36:33:10:a3:94:64
+
+
+
+
+
+
+
+
+
+
+
+
""", # noqa:E501
}
diff --git a/nova/tests/unit/virt/libvirt/test_host.py b/nova/tests/unit/virt/libvirt/test_host.py
index d71d13ab3721..53f1dfbda615 100644
--- a/nova/tests/unit/virt/libvirt/test_host.py
+++ b/nova/tests/unit/virt/libvirt/test_host.py
@@ -1280,7 +1280,10 @@ 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"],
# Should be obtained from the parent PF in this case.
"vpd": {"card_serial_number": "MT2113X00000"}},
}
diff --git a/nova/virt/libvirt/host.py b/nova/virt/libvirt/host.py
index cdf47008de45..8403497af5e4 100644
--- a/nova/virt/libvirt/host.py
+++ b/nova/virt/libvirt/host.py
@@ -1336,31 +1336,11 @@ class Host(object):
return {'dev_type': fields.PciDeviceType.STANDARD}
- def _get_device_capabilities(
- device_dict: dict,
- device: 'libvirt.virNodeDevice',
- net_devs: ty.List['libvirt.virNodeDevice']
- ) -> ty.Dict[str, ty.Dict[str, ty.Any]]:
- """Get PCI VF device's additional capabilities.
-
- If a PCI device is a virtual function, this function reads the PCI
- parent's network capabilities (must be always a NIC device) and
- appends this information to the device's dictionary.
- """
- caps: ty.Dict[str, ty.Dict[str, ty.Any]] = {}
-
- if device_dict.get('dev_type') == fields.PciDeviceType.SRIOV_VF:
- pcinet_info = self._get_pcinet_info(device, net_devs)
- if pcinet_info:
- return {'capabilities': {'network': pcinet_info}}
-
- return caps
-
def _get_vpd_details(
device_dict: dict,
device: 'libvirt.virNodeDevice',
pci_devs: ty.List['libvirt.virNodeDevice']
- ) -> ty.Dict[str, ty.Dict[str, ty.Any]]:
+ ) -> ty.Dict[str, ty.Any]:
"""Get information from PCI VPD (if present).
PCI/PCIe devices may include the optional VPD capability. It may
@@ -1373,7 +1353,7 @@ class Host(object):
the VPD capability or not may be controlled via a vendor-specific
firmware setting.
"""
- caps: ty.Dict[str, ty.Dict[str, ty.Any]] = {}
+ vpd_info: ty.Dict[str, ty.Any] = {}
# At the time of writing only the serial number had a clear
# use-case. However, the set of fields may be extended.
card_serial_number = self._get_vpd_card_serial_number(device)
@@ -1388,7 +1368,7 @@ class Host(object):
LOG.warning("A VF device dict does not have a parent PF "
"address in it which is unexpected. Skipping "
"serial number retrieval")
- return caps
+ return vpd_info
formatted_addr = pf_addr.replace('.', '_').replace(':', '_')
vpd_cap = self._get_vf_parent_pci_vpd_info(
@@ -1397,8 +1377,35 @@ class Host(object):
card_serial_number = vpd_cap.card_serial_number
if card_serial_number:
- caps = {'capabilities': {
- 'vpd': {"card_serial_number": card_serial_number}}}
+ vpd_info = {'card_serial_number': card_serial_number}
+ return vpd_info
+
+ def _get_device_capabilities(
+ device_dict: dict,
+ device: 'libvirt.virNodeDevice',
+ pci_devs: ty.List['libvirt.virNodeDevice'],
+ net_devs: ty.List['libvirt.virNodeDevice']
+ ) -> ty.Dict[str, ty.Any]:
+ """Get PCI VF device's additional capabilities.
+
+ If a PCI device is a virtual function, this function reads the PCI
+ parent's network capabilities (must be always a NIC device) and
+ appends this information to the device's dictionary.
+ """
+ caps: ty.Dict[str, ty.Any] = {}
+
+ if device_dict.get('dev_type') == fields.PciDeviceType.SRIOV_VF:
+ pcinet_info = self._get_pcinet_info(device, net_devs)
+ if pcinet_info:
+ caps['network'] = pcinet_info
+
+ vpd_info = _get_vpd_details(device_dict, device, pci_devs)
+ if vpd_info:
+ caps['vpd'] = vpd_info
+
+ if caps:
+ return {'capabilities': caps}
+
return caps
xmlstr = dev.XMLDesc(0)
@@ -1424,8 +1431,8 @@ class Host(object):
device['label'] = 'label_%(vendor_id)s_%(product_id)s' % device
device.update(
_get_device_type(cfgdev, address, dev, net_devs, vdpa_devs))
- device.update(_get_device_capabilities(device, dev, net_devs))
- device.update(_get_vpd_details(device, dev, pci_devs))
+ device.update(_get_device_capabilities(device, dev,
+ pci_devs, net_devs))
return device
def get_vdpa_nodedev_by_address(