Fix N3000 FPGA SR-IOV config for split NICs
This commit fixes an issue that can occur if a user creates an SR-IOV interface of type VF with a parent SR-IOV interface that belongs to a NIC on an Intel N3000 FPGA. The FPGA is reset on every worker node bootup (if present), clearing all SR-IOV config. Because of this, the current puppet code waits for the reset to be completed before restarting the interface via the sysconfig network interface scripts. Because the VF interface is a separate hieradata entry than the parent interface, this can cause a race condition where the device is re-initialized after one of the child/parent interfaces has already bound a driver to the interface. Since the whole point of the VF interfaces is to 'split' a NIC to allow multiple SR-IOV VF drivers on one physical NIC, this commit makes a single hieradata entry for the parent interface, rather than individual entries for the parent and child(ren). The information to bind the child interfaces appropriately is embedded in the vf_config dict of the parent interface. Change-Id: Iad34de8ae1b913a1c188e5473e0c92cdf8007ba2 Partial-Bug: #1885229 Signed-off-by: Steven Webster <steven.webster@windriver.com>
This commit is contained in:
parent
93be0c8d08
commit
ff1be48bf0
|
@ -1024,17 +1024,13 @@ def get_sriov_interface_vf_addrs(context, iface, vf_addr_list):
|
|||
return interface.get_sriov_interface_vf_addrs(context, iface, vf_addr_list)
|
||||
|
||||
|
||||
def get_sriov_config(context, iface):
|
||||
def get_sriov_vf_config(context, iface, port, vf_config):
|
||||
"""
|
||||
Returns an SR-IOV interface config dictionary.
|
||||
Determine the virtual function config for an SR-IOV interface.
|
||||
"""
|
||||
vf_driver = iface['sriov_vf_driver']
|
||||
vf_config = {}
|
||||
|
||||
port = interface.get_sriov_interface_port(context, iface)
|
||||
if not port:
|
||||
return {}
|
||||
|
||||
# Calculate the VF addresses to assign to a logical VF interface,
|
||||
# taking into account any upper or lower interfaces.
|
||||
vf_addr_list = ''
|
||||
vf_addrs = port.get('sriov_vfs_pci_address', None)
|
||||
if vf_addrs:
|
||||
|
@ -1043,23 +1039,21 @@ def get_sriov_config(context, iface):
|
|||
context, iface, vf_addr_list)
|
||||
vf_addr_list = ",".join(vf_addr_list)
|
||||
|
||||
if vf_driver:
|
||||
if constants.SRIOV_DRIVER_TYPE_VFIO in vf_driver:
|
||||
vf_driver = constants.SRIOV_DRIVER_VFIO_PCI
|
||||
elif constants.SRIOV_DRIVER_TYPE_NETDEVICE in vf_driver:
|
||||
if port['sriov_vf_driver'] is not None:
|
||||
vf_driver = port['sriov_vf_driver']
|
||||
else:
|
||||
# Should not happen, but in this case the vf driver
|
||||
# will be determined by the kernel. That is,
|
||||
# no explicit bind will be performed by Puppet.
|
||||
vf_driver = None
|
||||
|
||||
# Format the vf addresses as quoted strings in order to prevent
|
||||
# puppet from treating the address as a time/date value
|
||||
vf_addrs = [quoted_str(addr.strip())
|
||||
for addr in vf_addr_list.split(",") if addr]
|
||||
|
||||
# Get the user specified VF driver, if any. If the driver is
|
||||
# None, the driver will be determined by the kernel. That is,
|
||||
# No explicit bind will be done.
|
||||
vf_driver = iface.get('sriov_vf_driver', None)
|
||||
if vf_driver:
|
||||
if constants.SRIOV_DRIVER_TYPE_VFIO in vf_driver:
|
||||
vf_driver = constants.SRIOV_DRIVER_VFIO_PCI
|
||||
elif constants.SRIOV_DRIVER_TYPE_NETDEVICE in vf_driver:
|
||||
vf_driver = port.get('sriov_vf_driver', None)
|
||||
|
||||
for addr in vf_addrs:
|
||||
vf_config.update({
|
||||
addr: {
|
||||
|
@ -1068,6 +1062,26 @@ def get_sriov_config(context, iface):
|
|||
}
|
||||
})
|
||||
|
||||
if iface.get('used_by', None):
|
||||
upper_ifaces = iface['used_by']
|
||||
for upper_ifname in upper_ifaces:
|
||||
upper_iface = context['interfaces'][upper_ifname]
|
||||
get_sriov_vf_config(context, upper_iface, port, vf_config)
|
||||
|
||||
|
||||
def get_sriov_config(context, iface):
|
||||
"""
|
||||
Returns an SR-IOV interface config dictionary.
|
||||
"""
|
||||
vf_config = {}
|
||||
|
||||
if iface['iftype'] != constants.INTERFACE_TYPE_ETHERNET:
|
||||
return {}
|
||||
|
||||
port = interface.get_sriov_interface_port(context, iface)
|
||||
if not port:
|
||||
return {}
|
||||
|
||||
# Include the desired number of VFs if the device supports SR-IOV
|
||||
# config via sysfs and is not a sub-interface
|
||||
num_vfs = None
|
||||
|
@ -1075,6 +1089,8 @@ def get_sriov_config(context, iface):
|
|||
and iface['iftype'] != constants.INTERFACE_TYPE_VF):
|
||||
num_vfs = iface['sriov_numvfs']
|
||||
|
||||
get_sriov_vf_config(context, iface, port, vf_config)
|
||||
|
||||
config = {
|
||||
'ifname': iface['ifname'],
|
||||
'addr': quoted_str(port['pciaddr'].strip()),
|
||||
|
|
|
@ -968,6 +968,7 @@ def get_test_ethernet_port(**kw):
|
|||
'sriov_numvfs': kw.get('sriov_numvfs'),
|
||||
'sriov_vf_driver': kw.get('sriov_vf_driver'),
|
||||
'sriov_vf_pdevice_id': kw.get('sriov_vf_pdevice_id'),
|
||||
'sriov_vfs_pci_address': kw.get('sriov_vfs_pci_address'),
|
||||
'driver': kw.get('driver'),
|
||||
'numa_node': kw.get('numa_node', -1)
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import yaml
|
|||
from sysinv.common import constants
|
||||
from sysinv.puppet import interface
|
||||
from sysinv.puppet import puppet
|
||||
from sysinv.puppet import quoted_str
|
||||
from sysinv.objects import base as objbase
|
||||
|
||||
from sysinv.tests.db import base as dbbase
|
||||
|
@ -153,7 +152,7 @@ class InterfaceTestCaseMixin(base.PuppetTestCaseMixin):
|
|||
'networktype': networktype,
|
||||
'imtu': 1500,
|
||||
'sriov_numvfs': kwargs.get('sriov_numvfs', 0),
|
||||
'sriov_vf_driver': kwargs.get('sriov_vf_driver', None)}
|
||||
'sriov_vf_driver': kwargs.get('iface_sriov_vf_driver', None)}
|
||||
db_interface = dbutils.create_test_interface(**interface)
|
||||
self.interfaces.append(db_interface)
|
||||
|
||||
|
@ -170,7 +169,7 @@ class InterfaceTestCaseMixin(base.PuppetTestCaseMixin):
|
|||
'pciaddr': kwargs.get('pciaddr',
|
||||
'0000:00:00.' + str(port_id + 1)),
|
||||
'dev_id': kwargs.get('dev_id', 0),
|
||||
'sriov_vf_driver': kwargs.get('sriov_vf_driver', None),
|
||||
'sriov_vf_driver': kwargs.get('port_sriov_vf_driver', None),
|
||||
'sriov_vf_pdevice_id': kwargs.get('sriov_vf_pdevice_id', None),
|
||||
'sriov_vfs_pci_address': kwargs.get('sriov_vfs_pci_address', '')}
|
||||
db_port = dbutils.create_test_ethernet_port(**port)
|
||||
|
@ -1123,29 +1122,16 @@ class InterfaceTestCase(InterfaceTestCaseMixin, dbbase.BaseHostTestCase):
|
|||
|
||||
def _get_sriov_config(self, ifname='default',
|
||||
vf_driver=constants.SRIOV_DRIVER_TYPE_VFIO,
|
||||
vf_addrs=None, num_vfs=2,
|
||||
pf_addr=None, device_id='1572', port_name="eth0"):
|
||||
if vf_addrs is None:
|
||||
vf_addrs = []
|
||||
num_vfs=2, pf_addr=None, device_id='1572',
|
||||
port_name="eth0", vf_config=None):
|
||||
if vf_config is None:
|
||||
vf_config = {}
|
||||
config = {'ifname': ifname,
|
||||
'addr': pf_addr if pf_addr else self.port['pciaddr'],
|
||||
'device_id': device_id,
|
||||
'num_vfs': num_vfs,
|
||||
'port_name': port_name,
|
||||
'vf_config': {}}
|
||||
if vf_addrs:
|
||||
for addr in vf_addrs:
|
||||
vf_config = config['vf_config']
|
||||
if addr in vf_config.keys():
|
||||
vf_config.update({addr: {
|
||||
'addr': addr,
|
||||
'driver': vf_driver
|
||||
}})
|
||||
else:
|
||||
vf_config[addr] = {
|
||||
'addr': addr,
|
||||
'driver': vf_driver
|
||||
}
|
||||
'vf_config': vf_config}
|
||||
|
||||
return config
|
||||
|
||||
|
@ -1454,60 +1440,141 @@ class InterfaceTestCase(InterfaceTestCaseMixin, dbbase.BaseHostTestCase):
|
|||
config = self._create_sriov_vf_config(
|
||||
constants.SRIOV_DRIVER_TYPE_NETDEVICE, 'i40evf', vf_addr_list,
|
||||
num_vfs)
|
||||
expected_vf_config = {
|
||||
'0000:81:00.0': {'addr': '0000:81:00.0', 'driver': 'i40evf'},
|
||||
'0000:81:01.0': {'addr': '0000:81:01.0', 'driver': 'i40evf'}
|
||||
}
|
||||
expected = self._get_sriov_config(
|
||||
self.iface['ifname'], 'i40evf',
|
||||
[quoted_str(vf_addr1),
|
||||
quoted_str(vf_addr2)],
|
||||
num_vfs,
|
||||
ifname=self.iface['ifname'],
|
||||
vf_driver='i40evf',
|
||||
num_vfs=num_vfs,
|
||||
device_id=device_id,
|
||||
port_name=port_name)
|
||||
port_name=port_name,
|
||||
vf_config=expected_vf_config,)
|
||||
self.assertEqual(expected, config)
|
||||
|
||||
def test_get_sriov_config_vfio(self):
|
||||
vf_addr1 = "0000:81:00.0"
|
||||
vf_addr2 = "0000:81:01.0"
|
||||
device_id = '1572'
|
||||
port_name = 'eth0'
|
||||
vf_addr_list = "{},{}".format(vf_addr1, vf_addr2)
|
||||
num_vfs = 4
|
||||
|
||||
config = self._create_sriov_vf_config(
|
||||
constants.SRIOV_DRIVER_TYPE_VFIO, 'i40evf', vf_addr_list,
|
||||
num_vfs)
|
||||
expected_vf_config = {
|
||||
'0000:81:00.0': {'addr': '0000:81:00.0', 'driver': 'vfio-pci'},
|
||||
'0000:81:01.0': {'addr': '0000:81:01.0', 'driver': 'vfio-pci'}
|
||||
}
|
||||
expected = self._get_sriov_config(
|
||||
self.iface['ifname'], 'vfio-pci',
|
||||
[quoted_str(vf_addr1),
|
||||
quoted_str(vf_addr2)],
|
||||
num_vfs)
|
||||
ifname=self.iface['ifname'],
|
||||
vf_driver='vfio-pci',
|
||||
num_vfs=num_vfs,
|
||||
device_id=device_id,
|
||||
port_name=port_name,
|
||||
vf_config=expected_vf_config)
|
||||
self.assertEqual(expected, config)
|
||||
|
||||
def test_get_sriov_config_default(self):
|
||||
vf_addr1 = "0000:81:00.0"
|
||||
vf_addr2 = "0000:81:01.0"
|
||||
device_id = '1572'
|
||||
port_name = 'eth0'
|
||||
vf_addr_list = "{},{}".format(vf_addr1, vf_addr2)
|
||||
num_vfs = 1
|
||||
|
||||
config = self._create_sriov_vf_config(
|
||||
None, 'i40evf', vf_addr_list, num_vfs)
|
||||
expected_vf_config = {
|
||||
'0000:81:00.0': {'addr': '0000:81:00.0', 'driver': None},
|
||||
'0000:81:01.0': {'addr': '0000:81:01.0', 'driver': None}
|
||||
}
|
||||
expected = self._get_sriov_config(
|
||||
self.iface['ifname'], None,
|
||||
[quoted_str(vf_addr1),
|
||||
quoted_str(vf_addr2)],
|
||||
num_vfs)
|
||||
ifname=self.iface['ifname'],
|
||||
vf_driver=None,
|
||||
device_id=device_id,
|
||||
port_name=port_name,
|
||||
num_vfs=num_vfs,
|
||||
vf_config=expected_vf_config)
|
||||
self.assertEqual(expected, config)
|
||||
|
||||
def test_get_sriov_config_iftype_vf(self):
|
||||
port, iface = self._create_ethernet_test(
|
||||
'sriov1', constants.INTERFACE_CLASS_PCI_SRIOV,
|
||||
constants.NETWORK_TYPE_PCI_SRIOV, sriov_numvfs=2,
|
||||
sriov_vf_driver=None)
|
||||
vf = self._create_vf_test("vf1", 1, None, lower_iface=iface)
|
||||
constants.NETWORK_TYPE_PCI_SRIOV, sriov_numvfs=4,
|
||||
iface_sriov_vf_driver=None,
|
||||
port_sriov_vf_driver="iavf",
|
||||
sriov_vfs_pci_address="0000:b1:02.0,0000:b1:02.1,0000:b1:02.2,0000:b1:02.3")
|
||||
self._create_vf_test("vf1", 1, 'vfio', lower_iface=iface)
|
||||
self._update_context()
|
||||
|
||||
config = interface.get_sriov_config(self.context, vf)
|
||||
config = interface.get_sriov_config(self.context, iface)
|
||||
|
||||
expected_vf_config = {
|
||||
'0000:b1:02.0': {'addr': '0000:b1:02.0', 'driver': None},
|
||||
'0000:b1:02.1': {'addr': '0000:b1:02.1', 'driver': None},
|
||||
'0000:b1:02.2': {'addr': '0000:b1:02.2', 'driver': None},
|
||||
'0000:b1:02.3': {'addr': '0000:b1:02.3', 'driver': 'vfio-pci'}
|
||||
}
|
||||
expected = self._get_sriov_config(
|
||||
vf['ifname'], None,
|
||||
None,
|
||||
None, pf_addr=port['pciaddr'],
|
||||
port_name="eth1")
|
||||
iface['ifname'], None,
|
||||
num_vfs=4, pf_addr=port['pciaddr'],
|
||||
port_name="eth1",
|
||||
vf_config=expected_vf_config)
|
||||
self.assertEqual(expected, config)
|
||||
|
||||
def test_get_sriov_config_iftype_vf_nested(self):
|
||||
port, iface = self._create_ethernet_test(
|
||||
'sriov1', constants.INTERFACE_CLASS_PCI_SRIOV,
|
||||
constants.NETWORK_TYPE_PCI_SRIOV, sriov_numvfs=4,
|
||||
iface_sriov_vf_driver=None,
|
||||
port_sriov_vf_driver="iavf",
|
||||
sriov_vfs_pci_address="0000:b1:02.0,0000:b1:02.1,0000:b1:02.2,0000:b1:02.3")
|
||||
vf1 = self._create_vf_test("vf1", 2, 'vfio', lower_iface=iface)
|
||||
self._create_vf_test("vf2", 1, 'netdevice', lower_iface=vf1)
|
||||
self._update_context()
|
||||
|
||||
config = interface.get_sriov_config(self.context, iface)
|
||||
|
||||
expected_vf_config = {
|
||||
'0000:b1:02.0': {'addr': '0000:b1:02.0', 'driver': None},
|
||||
'0000:b1:02.1': {'addr': '0000:b1:02.1', 'driver': None},
|
||||
'0000:b1:02.2': {'addr': '0000:b1:02.2', 'driver': 'vfio-pci'},
|
||||
'0000:b1:02.3': {'addr': '0000:b1:02.3', 'driver': 'iavf'}
|
||||
}
|
||||
expected = self._get_sriov_config(
|
||||
iface['ifname'], None,
|
||||
num_vfs=4, pf_addr=port['pciaddr'],
|
||||
port_name="eth1",
|
||||
vf_config=expected_vf_config)
|
||||
self.assertEqual(expected, config)
|
||||
|
||||
def test_get_sriov_config_iftype_vf_sibling(self):
|
||||
port, iface = self._create_ethernet_test(
|
||||
'sriov1', constants.INTERFACE_CLASS_PCI_SRIOV,
|
||||
constants.NETWORK_TYPE_PCI_SRIOV, sriov_numvfs=4,
|
||||
iface_sriov_vf_driver=None,
|
||||
port_sriov_vf_driver="iavf",
|
||||
sriov_vfs_pci_address="0000:b1:02.0,0000:b1:02.1,0000:b1:02.2,0000:b1:02.3")
|
||||
self._create_vf_test("vf1", 2, 'vfio', lower_iface=iface)
|
||||
self._create_vf_test("vf2", 1, 'netdevice', lower_iface=iface)
|
||||
self._update_context()
|
||||
|
||||
config = interface.get_sriov_config(self.context, iface)
|
||||
|
||||
expected_vf_config = {
|
||||
'0000:b1:02.0': {'addr': '0000:b1:02.0', 'driver': None},
|
||||
'0000:b1:02.1': {'addr': '0000:b1:02.1', 'driver': 'iavf'},
|
||||
'0000:b1:02.2': {'addr': '0000:b1:02.2', 'driver': 'vfio-pci'},
|
||||
'0000:b1:02.3': {'addr': '0000:b1:02.3', 'driver': 'vfio-pci'}
|
||||
}
|
||||
expected = self._get_sriov_config(
|
||||
iface['ifname'], None,
|
||||
num_vfs=4, pf_addr=port['pciaddr'],
|
||||
port_name="eth1",
|
||||
vf_config=expected_vf_config)
|
||||
self.assertEqual(expected, config)
|
||||
|
||||
def test_is_a_mellanox_cx3_device_false(self):
|
||||
|
|
Loading…
Reference in New Issue