libvirt: report pci Type-PF type even when VFs are disabled
libvirt < 1.3 reports virt_functions capability only when pf has VFs enabled. This workaround patch updates the is_physical_function function to read the sriov_totalvfs if exists and check it is greater than 0. The sriov_totalvfs is the number for the maximum possible VF for this PF. _get_pcidev_info in libvirt driver is updated to get the correct pci device type using this function. Closes-Bug: #1499204 Change-Id: I8990c36fb1d6c66093a465930ff3f0948dd64986
This commit is contained in:
parent
996c2f6f05
commit
2ba4644f91
@ -67,7 +67,8 @@ class PciAddress(object):
|
|||||||
def _check_physical_function(self):
|
def _check_physical_function(self):
|
||||||
if ANY in (self.domain, self.bus, self.slot, self.func):
|
if ANY in (self.domain, self.bus, self.slot, self.func):
|
||||||
return
|
return
|
||||||
self.is_physical_function = utils.is_physical_function(self)
|
self.is_physical_function = utils.is_physical_function(
|
||||||
|
self.domain, self.bus, self.slot, self.func)
|
||||||
|
|
||||||
def _init_address_fields(self, pci_addr):
|
def _init_address_fields(self, pci_addr):
|
||||||
if self.is_physical_function:
|
if self.is_physical_function:
|
||||||
|
@ -23,7 +23,6 @@ from oslo_log import log as logging
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.i18n import _LE
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -33,7 +32,7 @@ _PCI_ADDRESS_PATTERN = ("^(hex{4}):(hex{2}):(hex{2}).(oct{1})$".
|
|||||||
replace("oct", "[0-7]"))
|
replace("oct", "[0-7]"))
|
||||||
_PCI_ADDRESS_REGEX = re.compile(_PCI_ADDRESS_PATTERN)
|
_PCI_ADDRESS_REGEX = re.compile(_PCI_ADDRESS_PATTERN)
|
||||||
|
|
||||||
_VIRTFN_RE = re.compile("virtfn\d+")
|
_SRIOV_TOTALVFS = "sriov_totalvfs"
|
||||||
|
|
||||||
|
|
||||||
def pci_device_prop_match(pci_dev, specs):
|
def pci_device_prop_match(pci_dev, specs):
|
||||||
@ -74,33 +73,32 @@ def get_function_by_ifname(ifname):
|
|||||||
"""Given the device name, returns the PCI address of a an device
|
"""Given the device name, returns the PCI address of a an device
|
||||||
and returns True if the address in a physical function.
|
and returns True if the address in a physical function.
|
||||||
"""
|
"""
|
||||||
try:
|
dev_path = "/sys/class/net/%s/device" % ifname
|
||||||
dev_path = "/sys/class/net/%s/device" % ifname
|
sriov_totalvfs = 0
|
||||||
dev_info = os.listdir(dev_path)
|
if os.path.isdir(dev_path):
|
||||||
for dev_file in dev_info:
|
try:
|
||||||
if _VIRTFN_RE.match(dev_file):
|
# sriov_totalvfs contains the maximum possible VFs for this PF
|
||||||
return os.readlink(dev_path).strip("./"), True
|
with open(dev_path + _SRIOV_TOTALVFS) as fd:
|
||||||
else:
|
sriov_totalvfs = int(fd.read())
|
||||||
|
return (os.readlink(dev_path).strip("./"),
|
||||||
|
sriov_totalvfs > 0)
|
||||||
|
except (IOError, ValueError):
|
||||||
return os.readlink(dev_path).strip("./"), False
|
return os.readlink(dev_path).strip("./"), False
|
||||||
except Exception:
|
return None, False
|
||||||
LOG.error(_LE("PCI device %s not found") % ifname)
|
|
||||||
return None, False
|
|
||||||
|
|
||||||
|
|
||||||
def is_physical_function(pci_addr):
|
def is_physical_function(domain, bus, slot, function):
|
||||||
dev_path = "/sys/bus/pci/devices/%(d)s:%(b)s:%(s)s.%(f)s/" % {
|
dev_path = "/sys/bus/pci/devices/%(d)s:%(b)s:%(s)s.%(f)s/" % {
|
||||||
"d": pci_addr.domain, "b": pci_addr.bus,
|
"d": domain, "b": bus, "s": slot, "f": function}
|
||||||
"s": pci_addr.slot, "f": pci_addr.func}
|
if os.path.isdir(dev_path):
|
||||||
try:
|
sriov_totalvfs = 0
|
||||||
dev_info = os.listdir(dev_path)
|
try:
|
||||||
for dev_file in dev_info:
|
with open(dev_path + _SRIOV_TOTALVFS) as fd:
|
||||||
if _VIRTFN_RE.match(dev_file):
|
sriov_totalvfs = int(fd.read())
|
||||||
return True
|
return sriov_totalvfs > 0
|
||||||
else:
|
except (IOError, ValueError):
|
||||||
return False
|
pass
|
||||||
except Exception:
|
return False
|
||||||
LOG.error(_LE("PCI device %s not found") % dev_path)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def get_ifname_by_pci_address(pci_addr, pf_interface=False):
|
def get_ifname_by_pci_address(pci_addr, pf_interface=False):
|
||||||
|
@ -18,6 +18,7 @@ import glob
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
from six.moves import builtins
|
||||||
|
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.pci import utils
|
from nova.pci import utils
|
||||||
@ -68,27 +69,28 @@ class PciDeviceAddressParserTestCase(test.NoDBTestCase):
|
|||||||
|
|
||||||
class GetFunctionByIfnameTestCase(test.NoDBTestCase):
|
class GetFunctionByIfnameTestCase(test.NoDBTestCase):
|
||||||
|
|
||||||
|
@mock.patch('os.path.isdir', return_value=True)
|
||||||
@mock.patch.object(os, 'readlink')
|
@mock.patch.object(os, 'readlink')
|
||||||
@mock.patch.object(os, 'listdir')
|
def test_virtual_function(self, mock_readlink, *args):
|
||||||
def test_virtual_function(self, mock_listdir, mock_readlink):
|
|
||||||
mock_listdir.return_value = ['foo', 'bar']
|
|
||||||
mock_readlink.return_value = '../../../0000.00.00.1'
|
mock_readlink.return_value = '../../../0000.00.00.1'
|
||||||
address, physical_function = utils.get_function_by_ifname('eth0')
|
with mock.patch.object(
|
||||||
self.assertEqual(address, '0000.00.00.1')
|
builtins, 'open', side_effect=IOError()):
|
||||||
self.assertFalse(physical_function)
|
address, physical_function = utils.get_function_by_ifname('eth0')
|
||||||
|
self.assertEqual(address, '0000.00.00.1')
|
||||||
|
self.assertFalse(physical_function)
|
||||||
|
|
||||||
|
@mock.patch('os.path.isdir', return_value=True)
|
||||||
@mock.patch.object(os, 'readlink')
|
@mock.patch.object(os, 'readlink')
|
||||||
@mock.patch.object(os, 'listdir')
|
def test_physical_function(self, mock_readlink, *args):
|
||||||
def test_physical_function(self, mock_listdir, mock_readlink):
|
|
||||||
mock_listdir.return_value = ['foo', 'virtfn1', 'bar']
|
|
||||||
mock_readlink.return_value = '../../../0000:00:00.1'
|
mock_readlink.return_value = '../../../0000:00:00.1'
|
||||||
address, physical_function = utils.get_function_by_ifname('eth0')
|
with mock.patch.object(
|
||||||
self.assertEqual(address, '0000:00:00.1')
|
builtins, 'open', mock.mock_open(read_data='4')):
|
||||||
self.assertTrue(physical_function)
|
address, physical_function = utils.get_function_by_ifname('eth0')
|
||||||
|
self.assertEqual(address, '0000:00:00.1')
|
||||||
|
self.assertTrue(physical_function)
|
||||||
|
|
||||||
@mock.patch.object(os, 'listdir')
|
@mock.patch('os.path.isdir', return_value=False)
|
||||||
def test_exception(self, mock_listdir):
|
def test_exception(self, *args):
|
||||||
mock_listdir.side_effect = OSError('No such file or directory')
|
|
||||||
address, physical_function = utils.get_function_by_ifname('lo')
|
address, physical_function = utils.get_function_by_ifname('lo')
|
||||||
self.assertIsNone(address)
|
self.assertIsNone(address)
|
||||||
self.assertFalse(physical_function)
|
self.assertFalse(physical_function)
|
||||||
@ -96,31 +98,25 @@ class GetFunctionByIfnameTestCase(test.NoDBTestCase):
|
|||||||
|
|
||||||
class IsPhysicalFunctionTestCase(test.NoDBTestCase):
|
class IsPhysicalFunctionTestCase(test.NoDBTestCase):
|
||||||
|
|
||||||
class FakePciAddress(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.domain = 0
|
|
||||||
self.bus = 0
|
|
||||||
self.slot = 0
|
|
||||||
self.func = 0
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(IsPhysicalFunctionTestCase, self).setUp()
|
super(IsPhysicalFunctionTestCase, self).setUp()
|
||||||
self.pci_address = self.FakePciAddress()
|
self.pci_args = utils.get_pci_address_fields('0000:00:00.1')
|
||||||
|
|
||||||
@mock.patch.object(os, 'listdir')
|
@mock.patch('os.path.isdir', return_value=True)
|
||||||
def test_virtual_function(self, mock_listdir):
|
def test_virtual_function(self, *args):
|
||||||
mock_listdir.return_value = ['foo', 'bar']
|
with mock.patch.object(
|
||||||
self.assertFalse(utils.is_physical_function(self.pci_address))
|
builtins, 'open', side_effect=IOError()):
|
||||||
|
self.assertFalse(utils.is_physical_function(*self.pci_args))
|
||||||
|
|
||||||
@mock.patch.object(os, 'listdir')
|
@mock.patch('os.path.isdir', return_value=True)
|
||||||
def test_physical_function(self, mock_listdir):
|
def test_physical_function(self, *args):
|
||||||
mock_listdir.return_value = ['foo', 'virtfn1', 'bar']
|
with mock.patch.object(
|
||||||
self.assertTrue(utils.is_physical_function(self.pci_address))
|
builtins, 'open', mock.mock_open(read_data='4')):
|
||||||
|
self.assertTrue(utils.is_physical_function(*self.pci_args))
|
||||||
|
|
||||||
@mock.patch.object(os, 'listdir')
|
@mock.patch('os.path.isdir', return_value=False)
|
||||||
def test_exception(self, mock_listdir):
|
def test_exception(self, *args):
|
||||||
mock_listdir.side_effect = OSError('No such file or directory')
|
self.assertFalse(utils.is_physical_function(*self.pci_args))
|
||||||
self.assertFalse(utils.is_physical_function(self.pci_address))
|
|
||||||
|
|
||||||
|
|
||||||
class GetIfnameByPciAddressTestCase(test.NoDBTestCase):
|
class GetIfnameByPciAddressTestCase(test.NoDBTestCase):
|
||||||
|
@ -65,6 +65,7 @@ from nova.network import model as network_model
|
|||||||
from nova import objects
|
from nova import objects
|
||||||
from nova.objects import fields
|
from nova.objects import fields
|
||||||
from nova.pci import manager as pci_manager
|
from nova.pci import manager as pci_manager
|
||||||
|
from nova.pci import utils as pci_utils
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova.tests.unit import fake_block_device
|
from nova.tests.unit import fake_block_device
|
||||||
from nova.tests.unit import fake_instance
|
from nova.tests.unit import fake_instance
|
||||||
@ -180,7 +181,94 @@ _fake_NodeDevXml = \
|
|||||||
<capability type='virt_functions'>
|
<capability type='virt_functions'>
|
||||||
</capability>
|
</capability>
|
||||||
</capability>
|
</capability>
|
||||||
</device>"""}
|
</device>""",
|
||||||
|
"pci_0000_04_00_1": """
|
||||||
|
<device>
|
||||||
|
<name>pci_0000_04_00_1</name>
|
||||||
|
<path>/sys/devices/pci0000:00/0000:00:02.0/0000:04:00.1</path>
|
||||||
|
<parent>pci_0000_00_02_0</parent>
|
||||||
|
<driver>
|
||||||
|
<name>mlx5_core</name>
|
||||||
|
</driver>
|
||||||
|
<capability type='pci'>
|
||||||
|
<domain>0</domain>
|
||||||
|
<bus>4</bus>
|
||||||
|
<slot>0</slot>
|
||||||
|
<function>1</function>
|
||||||
|
<product id='0x1013'>MT27700 Family [ConnectX-4]</product>
|
||||||
|
<vendor id='0x15b3'>Mellanox Technologies</vendor>
|
||||||
|
<iommuGroup number='15'>
|
||||||
|
<address domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
|
||||||
|
<address domain='0x0000' bus='0x03' slot='0x00' function='0x1'/>
|
||||||
|
</iommuGroup>
|
||||||
|
<numa node='0'/>
|
||||||
|
<pci-express>
|
||||||
|
<link validity='cap' port='0' speed='8' width='16'/>
|
||||||
|
<link validity='sta' speed='8' width='16'/>
|
||||||
|
</pci-express>
|
||||||
|
</capability>
|
||||||
|
</device>""",
|
||||||
|
# libvirt >= 1.3.0 nodedev-dumpxml
|
||||||
|
"pci_0000_03_00_0": """
|
||||||
|
<device>
|
||||||
|
<name>pci_0000_03_00_0</name>
|
||||||
|
<path>/sys/devices/pci0000:00/0000:00:02.0/0000:03:00.0</path>
|
||||||
|
<parent>pci_0000_00_02_0</parent>
|
||||||
|
<driver>
|
||||||
|
<name>mlx5_core</name>
|
||||||
|
</driver>
|
||||||
|
<capability type='pci'>
|
||||||
|
<domain>0</domain>
|
||||||
|
<bus>3</bus>
|
||||||
|
<slot>0</slot>
|
||||||
|
<function>0</function>
|
||||||
|
<product id='0x1013'>MT27700 Family [ConnectX-4]</product>
|
||||||
|
<vendor id='0x15b3'>Mellanox Technologies</vendor>
|
||||||
|
<capability type='virt_functions' maxCount='16'>
|
||||||
|
<address domain='0x0000' bus='0x03' slot='0x00' function='0x2'/>
|
||||||
|
<address domain='0x0000' bus='0x03' slot='0x00' function='0x3'/>
|
||||||
|
<address domain='0x0000' bus='0x03' slot='0x00' function='0x4'/>
|
||||||
|
<address domain='0x0000' bus='0x03' slot='0x00' function='0x5'/>
|
||||||
|
</capability>
|
||||||
|
<iommuGroup number='15'>
|
||||||
|
<address domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
|
||||||
|
<address domain='0x0000' bus='0x03' slot='0x00' function='0x1'/>
|
||||||
|
</iommuGroup>
|
||||||
|
<numa node='0'/>
|
||||||
|
<pci-express>
|
||||||
|
<link validity='cap' port='0' speed='8' width='16'/>
|
||||||
|
<link validity='sta' speed='8' width='16'/>
|
||||||
|
</pci-express>
|
||||||
|
</capability>
|
||||||
|
</device>""",
|
||||||
|
"pci_0000_03_00_1": """
|
||||||
|
<device>
|
||||||
|
<name>pci_0000_03_00_1</name>
|
||||||
|
<path>/sys/devices/pci0000:00/0000:00:02.0/0000:03:00.1</path>
|
||||||
|
<parent>pci_0000_00_02_0</parent>
|
||||||
|
<driver>
|
||||||
|
<name>mlx5_core</name>
|
||||||
|
</driver>
|
||||||
|
<capability type='pci'>
|
||||||
|
<domain>0</domain>
|
||||||
|
<bus>3</bus>
|
||||||
|
<slot>0</slot>
|
||||||
|
<function>1</function>
|
||||||
|
<product id='0x1013'>MT27700 Family [ConnectX-4]</product>
|
||||||
|
<vendor id='0x15b3'>Mellanox Technologies</vendor>
|
||||||
|
<capability type='virt_functions' maxCount='16'/>
|
||||||
|
<iommuGroup number='15'>
|
||||||
|
<address domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
|
||||||
|
<address domain='0x0000' bus='0x03' slot='0x00' function='0x1'/>
|
||||||
|
</iommuGroup>
|
||||||
|
<numa node='0'/>
|
||||||
|
<pci-express>
|
||||||
|
<link validity='cap' port='0' speed='8' width='16'/>
|
||||||
|
<link validity='sta' speed='8' width='16'/>
|
||||||
|
</pci-express>
|
||||||
|
</capability>
|
||||||
|
</device>""",
|
||||||
|
}
|
||||||
|
|
||||||
_fake_cpu_info = {
|
_fake_cpu_info = {
|
||||||
"arch": "test_arch",
|
"arch": "test_arch",
|
||||||
@ -9770,43 +9858,108 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
|||||||
host.Host.device_lookup_by_name = fake_nodeDeviceLookupByName
|
host.Host.device_lookup_by_name = fake_nodeDeviceLookupByName
|
||||||
|
|
||||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||||
actualvf = drvr._get_pcidev_info("pci_0000_04_00_3")
|
with mock.patch.object(
|
||||||
expect_vf = {
|
fakelibvirt.Connection, 'getLibVersion') as mock_lib_version:
|
||||||
"dev_id": "pci_0000_04_00_3",
|
mock_lib_version.return_value = (
|
||||||
"address": "0000:04:00.3",
|
versionutils.convert_version_to_int(
|
||||||
"product_id": '1521',
|
libvirt_driver.MIN_LIBVIRT_PF_WITH_NO_VFS_CAP_VERSION) - 1)
|
||||||
"numa_node": None,
|
|
||||||
"vendor_id": '8086',
|
|
||||||
"label": 'label_8086_1521',
|
|
||||||
"dev_type": fields.PciDeviceType.SRIOV_PF,
|
|
||||||
}
|
|
||||||
|
|
||||||
self.assertEqual(expect_vf, actualvf)
|
actualvf = drvr._get_pcidev_info("pci_0000_04_00_3")
|
||||||
actualvf = drvr._get_pcidev_info("pci_0000_04_10_7")
|
expect_vf = {
|
||||||
expect_vf = {
|
"dev_id": "pci_0000_04_00_3",
|
||||||
"dev_id": "pci_0000_04_10_7",
|
"address": "0000:04:00.3",
|
||||||
"address": "0000:04:10.7",
|
"product_id": '1521',
|
||||||
"product_id": '1520',
|
"numa_node": None,
|
||||||
"numa_node": None,
|
"vendor_id": '8086',
|
||||||
"vendor_id": '8086',
|
"label": 'label_8086_1521',
|
||||||
"label": 'label_8086_1520',
|
"dev_type": fields.PciDeviceType.SRIOV_PF,
|
||||||
"dev_type": fields.PciDeviceType.SRIOV_VF,
|
}
|
||||||
"phys_function": '0000:04:00.3',
|
|
||||||
}
|
|
||||||
self.assertEqual(expect_vf, actualvf)
|
|
||||||
actualvf = drvr._get_pcidev_info("pci_0000_04_11_7")
|
|
||||||
expect_vf = {
|
|
||||||
"dev_id": "pci_0000_04_11_7",
|
|
||||||
"address": "0000:04:11.7",
|
|
||||||
"product_id": '1520',
|
|
||||||
"vendor_id": '8086',
|
|
||||||
"numa_node": 0,
|
|
||||||
"label": 'label_8086_1520',
|
|
||||||
"dev_type": fields.PciDeviceType.SRIOV_VF,
|
|
||||||
"phys_function": '0000:04:00.3',
|
|
||||||
}
|
|
||||||
|
|
||||||
self.assertEqual(expect_vf, actualvf)
|
self.assertEqual(expect_vf, actualvf)
|
||||||
|
actualvf = drvr._get_pcidev_info("pci_0000_04_10_7")
|
||||||
|
expect_vf = {
|
||||||
|
"dev_id": "pci_0000_04_10_7",
|
||||||
|
"address": "0000:04:10.7",
|
||||||
|
"product_id": '1520',
|
||||||
|
"numa_node": None,
|
||||||
|
"vendor_id": '8086',
|
||||||
|
"label": 'label_8086_1520',
|
||||||
|
"dev_type": fields.PciDeviceType.SRIOV_VF,
|
||||||
|
"phys_function": '0000:04:00.3',
|
||||||
|
}
|
||||||
|
self.assertEqual(expect_vf, actualvf)
|
||||||
|
|
||||||
|
actualvf = drvr._get_pcidev_info("pci_0000_04_11_7")
|
||||||
|
expect_vf = {
|
||||||
|
"dev_id": "pci_0000_04_11_7",
|
||||||
|
"address": "0000:04:11.7",
|
||||||
|
"product_id": '1520',
|
||||||
|
"vendor_id": '8086',
|
||||||
|
"numa_node": 0,
|
||||||
|
"label": 'label_8086_1520',
|
||||||
|
"dev_type": fields.PciDeviceType.SRIOV_VF,
|
||||||
|
"phys_function": '0000:04:00.3',
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(expect_vf, actualvf)
|
||||||
|
|
||||||
|
with mock.patch.object(
|
||||||
|
pci_utils, 'is_physical_function', return_value=True):
|
||||||
|
actualvf = drvr._get_pcidev_info("pci_0000_04_00_1")
|
||||||
|
expect_vf = {
|
||||||
|
"dev_id": "pci_0000_04_00_1",
|
||||||
|
"address": "0000:04:00.1",
|
||||||
|
"product_id": '1013',
|
||||||
|
"numa_node": 0,
|
||||||
|
"vendor_id": '15b3',
|
||||||
|
"label": 'label_15b3_1013',
|
||||||
|
"dev_type": fields.PciDeviceType.SRIOV_PF,
|
||||||
|
}
|
||||||
|
self.assertEqual(expect_vf, actualvf)
|
||||||
|
|
||||||
|
with mock.patch.object(
|
||||||
|
pci_utils, 'is_physical_function', return_value=False):
|
||||||
|
actualvf = drvr._get_pcidev_info("pci_0000_04_00_1")
|
||||||
|
expect_vf = {
|
||||||
|
"dev_id": "pci_0000_04_00_1",
|
||||||
|
"address": "0000:04:00.1",
|
||||||
|
"product_id": '1013',
|
||||||
|
"numa_node": 0,
|
||||||
|
"vendor_id": '15b3',
|
||||||
|
"label": 'label_15b3_1013',
|
||||||
|
"dev_type": fields.PciDeviceType.STANDARD,
|
||||||
|
}
|
||||||
|
self.assertEqual(expect_vf, actualvf)
|
||||||
|
|
||||||
|
with mock.patch.object(
|
||||||
|
fakelibvirt.Connection, 'getLibVersion') as mock_lib_version:
|
||||||
|
mock_lib_version.return_value = (
|
||||||
|
versionutils.convert_version_to_int(
|
||||||
|
libvirt_driver.MIN_LIBVIRT_PF_WITH_NO_VFS_CAP_VERSION))
|
||||||
|
actualvf = drvr._get_pcidev_info("pci_0000_03_00_0")
|
||||||
|
expect_vf = {
|
||||||
|
"dev_id": "pci_0000_03_00_0",
|
||||||
|
"address": "0000:03:00.0",
|
||||||
|
"product_id": '1013',
|
||||||
|
"numa_node": 0,
|
||||||
|
"vendor_id": '15b3',
|
||||||
|
"label": 'label_15b3_1013',
|
||||||
|
"dev_type": fields.PciDeviceType.SRIOV_PF,
|
||||||
|
}
|
||||||
|
self.assertEqual(expect_vf, actualvf)
|
||||||
|
|
||||||
|
actualvf = drvr._get_pcidev_info("pci_0000_03_00_1")
|
||||||
|
expect_vf = {
|
||||||
|
"dev_id": "pci_0000_03_00_1",
|
||||||
|
"address": "0000:03:00.1",
|
||||||
|
"product_id": '1013',
|
||||||
|
"numa_node": 0,
|
||||||
|
"vendor_id": '15b3',
|
||||||
|
"label": 'label_15b3_1013',
|
||||||
|
"dev_type": fields.PciDeviceType.SRIOV_PF,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertEqual(expect_vf, actualvf)
|
||||||
|
|
||||||
def test_list_devices_not_supported(self):
|
def test_list_devices_not_supported(self):
|
||||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||||
|
@ -420,6 +420,12 @@ MIN_LIBVIRT_SET_ADMIN_PASSWD = (1, 2, 16)
|
|||||||
MIN_LIBVIRT_KVM_S390_VERSION = (1, 2, 13)
|
MIN_LIBVIRT_KVM_S390_VERSION = (1, 2, 13)
|
||||||
MIN_QEMU_S390_VERSION = (2, 3, 0)
|
MIN_QEMU_S390_VERSION = (2, 3, 0)
|
||||||
|
|
||||||
|
# libvirt < 1.3 reported virt_functions capability
|
||||||
|
# only when VFs are enabled.
|
||||||
|
# libvirt 1.3 fix f391889f4e942e22b9ef8ecca492de05106ce41e
|
||||||
|
MIN_LIBVIRT_PF_WITH_NO_VFS_CAP_VERSION = (1, 3, 0)
|
||||||
|
|
||||||
|
|
||||||
# Names of the types that do not get compressed during migration
|
# Names of the types that do not get compressed during migration
|
||||||
NO_COMPRESSION_TYPES = ('qcow2',)
|
NO_COMPRESSION_TYPES = ('qcow2',)
|
||||||
|
|
||||||
@ -4805,7 +4811,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
def _get_pcidev_info(self, devname):
|
def _get_pcidev_info(self, devname):
|
||||||
"""Returns a dict of PCI device."""
|
"""Returns a dict of PCI device."""
|
||||||
|
|
||||||
def _get_device_type(cfgdev):
|
def _get_device_type(cfgdev, pci_address):
|
||||||
"""Get a PCI device's device type.
|
"""Get a PCI device's device type.
|
||||||
|
|
||||||
An assignable PCI device can be a normal PCI device,
|
An assignable PCI device can be a normal PCI device,
|
||||||
@ -4813,26 +4819,35 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
Function (VF). Only normal PCI devices or SR-IOV VFs
|
Function (VF). Only normal PCI devices or SR-IOV VFs
|
||||||
are assignable, while SR-IOV PFs are always owned by
|
are assignable, while SR-IOV PFs are always owned by
|
||||||
hypervisor.
|
hypervisor.
|
||||||
|
|
||||||
Please notice that a PCI device with SR-IOV
|
|
||||||
capability but not enabled is reported as normal PCI device.
|
|
||||||
"""
|
"""
|
||||||
for fun_cap in cfgdev.pci_capability.fun_capability:
|
for fun_cap in cfgdev.pci_capability.fun_capability:
|
||||||
if len(fun_cap.device_addrs) != 0:
|
if fun_cap.type == 'virt_functions':
|
||||||
if fun_cap.type == 'virt_functions':
|
return {
|
||||||
return {
|
'dev_type': fields.PciDeviceType.SRIOV_PF,
|
||||||
'dev_type': fields.PciDeviceType.SRIOV_PF,
|
}
|
||||||
}
|
if (fun_cap.type == 'phys_function' and
|
||||||
if fun_cap.type == 'phys_function':
|
len(fun_cap.device_addrs) != 0):
|
||||||
phys_address = "%04x:%02x:%02x.%01x" % (
|
phys_address = "%04x:%02x:%02x.%01x" % (
|
||||||
fun_cap.device_addrs[0][0],
|
fun_cap.device_addrs[0][0],
|
||||||
fun_cap.device_addrs[0][1],
|
fun_cap.device_addrs[0][1],
|
||||||
fun_cap.device_addrs[0][2],
|
fun_cap.device_addrs[0][2],
|
||||||
fun_cap.device_addrs[0][3])
|
fun_cap.device_addrs[0][3])
|
||||||
return {
|
return {
|
||||||
'dev_type': fields.PciDeviceType.SRIOV_VF,
|
'dev_type': fields.PciDeviceType.SRIOV_VF,
|
||||||
'phys_function': phys_address,
|
'phys_function': phys_address,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Note(moshele): libvirt < 1.3 reported virt_functions capability
|
||||||
|
# only when VFs are enabled. The check below is a workaround
|
||||||
|
# to get the correct report regardless of whether or not any
|
||||||
|
# VFs are enabled for the device.
|
||||||
|
if not self._host.has_min_version(
|
||||||
|
MIN_LIBVIRT_PF_WITH_NO_VFS_CAP_VERSION):
|
||||||
|
is_physical_function = pci_utils.is_physical_function(
|
||||||
|
*pci_utils.get_pci_address_fields(pci_address))
|
||||||
|
if is_physical_function:
|
||||||
|
return {'dev_type': fields.PciDeviceType.SRIOV_PF}
|
||||||
|
|
||||||
return {'dev_type': fields.PciDeviceType.STANDARD}
|
return {'dev_type': fields.PciDeviceType.STANDARD}
|
||||||
|
|
||||||
virtdev = self._host.device_lookup_by_name(devname)
|
virtdev = self._host.device_lookup_by_name(devname)
|
||||||
@ -4857,7 +4872,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
|
|
||||||
# requirement by DataBase Model
|
# requirement by DataBase Model
|
||||||
device['label'] = 'label_%(vendor_id)s_%(product_id)s' % device
|
device['label'] = 'label_%(vendor_id)s_%(product_id)s' % device
|
||||||
device.update(_get_device_type(cfgdev))
|
device.update(_get_device_type(cfgdev, address))
|
||||||
return device
|
return device
|
||||||
|
|
||||||
def _get_pci_passthrough_devices(self):
|
def _get_pci_passthrough_devices(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user