Fix for shared NIC with the N3000 FPGA

An issue can occur when using an N3000 FPGA NIC with upper
vlan interfaces (oam, mgmt, etc).  Because the N3000 is reset
after the networking initialization is complete, any IPv6
addresses, or (IPv4 / IPv6) default routes configured on the
vlan interfaces will be removed.

This commit fixes the issue by creating an FPGA resource
for puppet containing the N3000 interface name and any of
the 'used by' (upper) interfaces belonging to the interface.

If these resources are present, puppet will restart the
upper interfaces after the N3000 FPGA is reset, allowing
any configured IP addresses and routes to be restored.

Depends-On: https://review.opendev.org/c/starlingx/stx-puppet/+/795710
Partial-Bug: #1931461
Change-Id: Ie6725f572a32bfe649962a6eadca498bcc2c9e7c
Signed-off-by: Steven Webster <steven.webster@windriver.com>
This commit is contained in:
Steven Webster 2021-06-01 17:09:34 -04:00
parent 81051adf46
commit ec8ff34ab1
3 changed files with 89 additions and 8 deletions

View File

@ -32,6 +32,7 @@ PCI_DEVICE_VENDOR_INTEL = "8086"
# Device Ids
PCI_DEVICE_ID_FPGA_INTEL_5GNR_FEC_PF = "0d8f"
PCI_DEVICE_ID_FPGA_INTEL_5GNR_FEC_VF = "0d90"
PCI_DEVICE_ID_FPGA_INTEL_I40_PF = "0d58"
PCI_DEVICE_ID_ACC100_INTEL_5GNR_FEC_PF = "0d5c"
PCI_DEVICE_ID_ACC100_INTEL_5GNR_FEC_VF = "0d5d"

View File

@ -127,6 +127,22 @@ def get_lower_interface(context, iface):
return context['interfaces'][lower_ifname]
def get_pci_device_id(port):
"""
Determine the PCI device id of given port.
"""
# The device id can be found by inspecting the '[xxxx]' at the
# end of the port's pdevice field
if not port or not port.get('pdevice', None):
return None
device_id = re.search(r'\[([0-9a-fA-F]{1,4})\]$', port['pdevice'])
if device_id:
device_id = device_id.group(1)
return str(device_id)
return None
def get_sriov_interface_port(context, iface):
"""
Determine the underlying port of the SR-IOV interface.
@ -143,15 +159,10 @@ def get_sriov_interface_device_id(context, iface):
"""
Determine the underlying PCI device id of the SR-IOV interface.
"""
# The device id can be found by inspecting the '[xxxx]' at the
# end of the port's pdevice field
device_id = None
port = get_sriov_interface_port(context, iface)
if port:
device_id = re.search(r'\[([0-9a-fA-F]{1,4})\]$', port['pdevice'])
if device_id:
device_id = device_id.group(1)
return device_id
if not port:
return None
return get_pci_device_id(port)
def get_sriov_interface_vf_addrs(context, iface, vf_addr_list):

View File

@ -14,6 +14,7 @@ from netaddr import IPNetwork
from oslo_log import log
from sysinv._i18n import _
from sysinv.common import constants
from sysinv.common import device as dconstants
from sysinv.common import exception
from sysinv.common import interface
from sysinv.common import utils
@ -53,6 +54,7 @@ DHCP_METHOD = 'dhcp'
NETWORK_CONFIG_RESOURCE = 'platform::interfaces::network_config'
SRIOV_CONFIG_RESOURCE = 'platform::interfaces::sriov::sriov_config'
FPGA_CONFIG_RESOURCE = 'platform::interfaces::fpga::fpga_config'
ADDRESS_CONFIG_RESOURCE = 'platform::network::addresses::address_config'
ROUTE_CONFIG_RESOURCE = 'platform::network::routes::route_config'
@ -89,6 +91,7 @@ class InterfacePuppet(base.BasePuppet):
ROUTE_CONFIG_RESOURCE: {},
ADDRESS_CONFIG_RESOURCE: {},
SRIOV_CONFIG_RESOURCE: {},
FPGA_CONFIG_RESOURCE: {},
DATA_IFACE_LIST_RESOURCE: [],
}
@ -457,6 +460,28 @@ def is_a_mellanox_cx3_device(context, iface):
return False
def is_an_n3000_i40_device(context, iface):
"""
Determine if the underlying device is onboard an N3000 FPGA.
"""
if iface['iftype'] != constants.INTERFACE_TYPE_ETHERNET:
# We only care about configuring specific settings for related ethernet
# devices.
return False
port = get_interface_port(context, iface)
if not port:
return False
device_id = interface.get_pci_device_id(port)
if not device_id:
return False
if device_id == dconstants.PCI_DEVICE_ID_FPGA_INTEL_I40_PF:
return True
return False
def get_master_interface(context, iface):
"""
Get the interface name of the given interface's master (if any). The
@ -1116,6 +1141,34 @@ def get_sriov_config(context, iface):
return config
def get_n3000_config(context, iface):
config = {}
if is_an_n3000_i40_device(context, iface):
port = get_interface_port(context, iface)
if not port:
return {}
device_id = interface.get_pci_device_id(port)
if not device_id:
return {}
config = {
'ifname': port['name'],
'device_id': device_id,
'used_by': iface['used_by'] or []
}
return config
def get_fpga_config(context, iface):
"""
Returns an FPGA interface config dictionary.
"""
config = {}
config.update(get_n3000_config(context, iface))
return config
def get_common_network_config(context, iface, config, network_id=None):
"""
Augments a basic config dictionary with the attributes specific to an upper
@ -1253,6 +1306,12 @@ def generate_network_config(context, config, iface):
sriov_config['ifname']: format_sriov_config(sriov_config)
})
fpga_config = get_fpga_config(context, iface)
if fpga_config:
config[FPGA_CONFIG_RESOURCE].update({
fpga_config['ifname']: format_fpga_config(fpga_config)
})
def find_network_by_pool_uuid(context, pool_uuid):
for networktype, network in six.iteritems(context['networks']):
@ -1489,3 +1548,13 @@ def format_sriov_config(config):
sriov_config = copy.copy(config)
del sriov_config['ifname']
return sriov_config
def format_fpga_config(config):
"""
Converts a fpga_config resource dictionary to the equivalent puppet
resource definition parameters.
"""
fpga_config = copy.copy(config)
del fpga_config['ifname']
return fpga_config