Merge "Update dervice_pci script to handle pci address formats" into stable/train
This commit is contained in:
commit
6a9e2b00a8
|
@ -22,10 +22,116 @@ import yaml
|
|||
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
|
||||
_PASSTHROUGH_WHITELIST_KEY = 'nova::compute::pci::passthrough'
|
||||
_PCI_DEVICES_PATH = '/sys/bus/pci/devices'
|
||||
_SYS_CLASS_NET_PATH = '/sys/class/net'
|
||||
_DERIVED_PCI_WHITELIST_FILE = '/etc/puppet/hieradata/pci_passthrough_whitelist.json'
|
||||
|
||||
MAX_FUNC = 0x7
|
||||
MAX_DOMAIN = 0xFFFF
|
||||
MAX_BUS = 0xFF
|
||||
MAX_SLOT = 0x1F
|
||||
ANY = '*'
|
||||
REGEX_ANY = '.*'
|
||||
|
||||
ADD_PF_PCI_ADDRESS = 0x1
|
||||
ADD_VF_PCI_ADDRESS = 0x2
|
||||
DEL_USER_CONFIG = 0x3
|
||||
KEEP_USER_CONFIG = 0x4
|
||||
|
||||
|
||||
class InvalidConfigException(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
def get_pci_field_val(prop, maxval, hex_value):
|
||||
if prop == ANY:
|
||||
return REGEX_ANY
|
||||
try:
|
||||
v = int(prop, 16)
|
||||
except ValueError:
|
||||
raise InvalidConfigException('Invalid PCI address specififed %s' % prop)
|
||||
if v > maxval:
|
||||
raise InvalidConfigException('PCI address specififed %s is out of range' % prop)
|
||||
return hex_value % v
|
||||
|
||||
|
||||
def get_pciaddr_dict_from_usraddr(pci_addr):
|
||||
"""Convert PCI address in STRING format to DICT
|
||||
(this is done for uniformity in PCI address)
|
||||
"""
|
||||
pci_dict = {}
|
||||
dbs, sep, func = pci_addr.partition('.')
|
||||
pci_dict['function'] = ANY
|
||||
if func:
|
||||
func = func.strip()
|
||||
pci_dict['function'] = func
|
||||
if dbs:
|
||||
dbs_fields = dbs.split(':')
|
||||
if len(dbs_fields) > 3:
|
||||
raise InvalidConfigException('Invalid PCI address specififed %s' % pci_addr)
|
||||
# If we got a partial address like ":00.", we need to turn this
|
||||
# into a domain of ANY, a bus of ANY, and a slot of 00. This code
|
||||
# allows the address,bus and/or domain to be left off
|
||||
dbs_all = [ANY] * (3 - len(dbs_fields))
|
||||
dbs_all.extend(dbs_fields)
|
||||
dbs_checked = [s.strip() or ANY for s in dbs_all]
|
||||
|
||||
''' domain, bus, slot = dbs_checked '''
|
||||
pci_dict['domain'], pci_dict['bus'], pci_dict['slot'] = dbs_checked
|
||||
|
||||
pci_dict['domain'] = get_pci_field_val(pci_dict['domain'], MAX_DOMAIN, '%04x')
|
||||
pci_dict['slot'] = get_pci_field_val(pci_dict['slot'], MAX_SLOT, '%02x')
|
||||
pci_dict['bus'] = get_pci_field_val(pci_dict['bus'], MAX_BUS, '%02x')
|
||||
pci_dict['function'] = get_pci_field_val(pci_dict['function'], MAX_FUNC, '%1x')
|
||||
return pci_dict
|
||||
|
||||
|
||||
def get_pci_regex_pattern(config_regex, size, maxval, hex_value):
|
||||
if config_regex in [ANY, REGEX_ANY]:
|
||||
config_regex = "[0-9a-fA-F]{%d}" % size
|
||||
|
||||
try:
|
||||
re.compile(config_regex)
|
||||
except re.error:
|
||||
msg = "Invalid regex pattern identified %s" % config_regex
|
||||
raise InvalidConfigException(msg)
|
||||
try:
|
||||
v = int(config_regex, 16)
|
||||
except ValueError:
|
||||
return config_regex
|
||||
if v > maxval:
|
||||
msg = "Invalid pci address"
|
||||
raise InvalidConfigException(msg)
|
||||
return hex_value % v
|
||||
|
||||
|
||||
def get_user_regex_from_addrdict(addr_dict):
|
||||
if isinstance(addr_dict, dict):
|
||||
domain_regex = get_pci_regex_pattern(addr_dict['domain'], 4, MAX_DOMAIN, '%04x')
|
||||
bus_regex = get_pci_regex_pattern(addr_dict['bus'], 2, MAX_BUS, '%02x')
|
||||
slot_regex = get_pci_regex_pattern(addr_dict['slot'], 2, MAX_SLOT, '%02x')
|
||||
function_regex = get_pci_regex_pattern(addr_dict['function'], 1, MAX_FUNC, '%1x')
|
||||
|
||||
user_address_regex = '%s:%s:%s.%s' % (
|
||||
domain_regex, bus_regex, slot_regex,
|
||||
function_regex)
|
||||
return user_address_regex
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_pci_addr_from_ifname(ifname):
|
||||
"""Given the device name, returns the PCI address of a device
|
||||
and returns True if the address is in a physical function.
|
||||
"""
|
||||
dev_path = os.path.join(_SYS_CLASS_NET_PATH, ifname, "device")
|
||||
if os.path.isdir(dev_path):
|
||||
try:
|
||||
return (os.readlink(dev_path).strip("./"))
|
||||
except OSError:
|
||||
raise
|
||||
return None
|
||||
|
||||
|
||||
def get_sriov_configs():
|
||||
|
@ -78,14 +184,17 @@ def get_pci_device_info_by_ifname(pci_dir, sub_dir):
|
|||
with open(os.path.join(pci_dir, sub_dir,
|
||||
'device')) as product_file:
|
||||
product = product_file.read().strip()
|
||||
return (vendor, product)
|
||||
return vendor, product
|
||||
except IOError:
|
||||
return None
|
||||
|
||||
|
||||
def get_pci_addresses_by_ifname(pfs, allocated_pci):
|
||||
pci_addresses = {}
|
||||
device_info = {}
|
||||
def get_available_vf_pci_addresses_by_ifname(pf_name, allocated_pci):
|
||||
"""It gets the list of all VF's of a PF minus the VFs allocated for
|
||||
NIC Partitioning. If the PF has 10 VFs and VFs 0,1 are allocated then
|
||||
the PCI address of VFs from 2 to 9 along with the device info wout be returned
|
||||
"""
|
||||
vf_pci_addresses = {}
|
||||
pci_dir = _PCI_DEVICES_PATH
|
||||
if os.path.isdir(pci_dir):
|
||||
for sub_dir in os.listdir(pci_dir):
|
||||
|
@ -95,17 +204,12 @@ def get_pci_addresses_by_ifname(pfs, allocated_pci):
|
|||
if os.path.isdir(pci_phyfn_dir):
|
||||
phyfn_dirs = os.listdir(pci_phyfn_dir)
|
||||
for phyfn in phyfn_dirs:
|
||||
if phyfn in pfs:
|
||||
if phyfn not in pci_addresses:
|
||||
pci_addresses[phyfn] = [sub_dir]
|
||||
if phyfn in pf_name:
|
||||
if phyfn not in vf_pci_addresses:
|
||||
vf_pci_addresses[phyfn] = [sub_dir]
|
||||
else:
|
||||
pci_addresses[phyfn].append(sub_dir)
|
||||
if phyfn not in device_info:
|
||||
dev_info = get_pci_device_info_by_ifname(pci_dir,
|
||||
sub_dir)
|
||||
if dev_info:
|
||||
device_info[phyfn] = dev_info
|
||||
return (pci_addresses, device_info)
|
||||
vf_pci_addresses[phyfn].append(sub_dir)
|
||||
return vf_pci_addresses
|
||||
|
||||
|
||||
def get_allocated_pci_addresses(configs):
|
||||
|
@ -117,19 +221,12 @@ def get_allocated_pci_addresses(configs):
|
|||
return alloc_pci_info
|
||||
|
||||
|
||||
def get_pci_passthrough_whitelist(user_config, pf, pci_addresses,
|
||||
device_info):
|
||||
def get_pci_passthrough_whitelist(user_config, pf, pci_addresses):
|
||||
pci_passthrough_list = []
|
||||
|
||||
for pci in pci_addresses:
|
||||
pci_passthrough = dict(user_config)
|
||||
address = {}
|
||||
pci_params = re.split('[:.]+', pci)
|
||||
address['domain'] = '.*'
|
||||
address['bus'] = pci_params[1]
|
||||
address['slot'] = pci_params[2]
|
||||
address['function'] = pci_params[3]
|
||||
pci_passthrough['address'] = address
|
||||
pci_passthrough['address'] = str(pci)
|
||||
|
||||
# devname and address fields can't co exist
|
||||
if 'devname' in pci_passthrough:
|
||||
|
@ -157,87 +254,204 @@ def user_passthrough_config():
|
|||
raise
|
||||
|
||||
|
||||
def get_regex_pattern(config_regex, size):
|
||||
if config_regex == ".*":
|
||||
regex_pattern = "[0-9a-fA-F]{%d}" % size
|
||||
def match_pf_details(user_config, pf_name, is_non_nic_pf):
|
||||
"""Decide the action for whitelist_pci_addr, based on user config
|
||||
|
||||
:param user_configs: THT param NovaPCIPassthrough
|
||||
:param pf_name: Interface/device name (str)
|
||||
:param is_non_nic_pf: Indicates whether the PF is noc-partitioned or not
|
||||
:return: Return the actions to be done, based on match criteria
|
||||
"""
|
||||
|
||||
# get the vendor and product id of the PF and VF
|
||||
pf_path = os.path.join(_SYS_CLASS_NET_PATH, pf_name, "device")
|
||||
vendor, vf_product = get_pci_device_info_by_ifname(pf_path, 'virtfn0')
|
||||
vendor, pf_product = get_pci_device_info_by_ifname(pf_path, '')
|
||||
|
||||
if ('product_id' not in user_config or
|
||||
vf_product[-4:] == user_config['product_id'][-4:]):
|
||||
if is_non_nic_pf:
|
||||
# If NON NIC Part PF matches, then add the complete device
|
||||
return ADD_PF_PCI_ADDRESS
|
||||
else:
|
||||
""" In case of NIC Partitioning PF, add the VFs only (excluding NIC Part VFs)
|
||||
when the product id is not given or product_id matches that of VF
|
||||
"""
|
||||
return ADD_VF_PCI_ADDRESS
|
||||
elif ('product_id' not in user_config or
|
||||
pf_product[-4:] == user_config['product_id'][-4:]):
|
||||
if is_non_nic_pf:
|
||||
# If product id of NON NIC Part VF matches, then add the complete device
|
||||
return ADD_PF_PCI_ADDRESS
|
||||
else:
|
||||
""" When the user_config address matches that of the NIC Partitioned PF,
|
||||
the PF must be removed from the user_config. So return the status such
|
||||
that the caller ignores this user_config if this user_config is very
|
||||
specific to the NIC Partitioned PF
|
||||
"""
|
||||
return DEL_USER_CONFIG
|
||||
else:
|
||||
regex_pattern = config_regex
|
||||
return regex_pattern
|
||||
""" The Product ID neither belongs to VF nor PF, simply ignore matching
|
||||
"""
|
||||
return KEEP_USER_CONFIG
|
||||
|
||||
|
||||
def get_passthrough_config(user_config, pf, allocated_pci):
|
||||
# +------------+-----------------------+---------------------------+-------------------+
|
||||
# | USER | product_id | product_id | Product ID |
|
||||
# | CONFIG | is VF | is PF | NOT mentioned |
|
||||
# +------------+-----------------------+---------------------------+-------------------+
|
||||
# | PCI addr | | | |
|
||||
# | is VF | Matching VF | INVALID | add only VFs |
|
||||
# | | | | |
|
||||
# | | | | |
|
||||
# +------------+-----------------------+---------------------------+-------------------+
|
||||
# | | | | |
|
||||
# | PCI addr | ALL VFs of this | Matching PFs | Add both PF and |
|
||||
# | is PF | addr - | - NIC Part PFs | available VFs |
|
||||
# | | NIC Part VFs | | |
|
||||
# | | | | |
|
||||
# +------------+-----------------------+---------------------------+-------------------+
|
||||
# | | | | |
|
||||
# | PCI addr | All matching | All matching | INVALID CASE |
|
||||
# | not | VFs | PFs - NIC Part PF | |
|
||||
# | specified | NIC Part VFs | | |
|
||||
# | | | | |
|
||||
# +------------+-----------------------+---------------------------+-------------------+
|
||||
def get_passthrough_config(user_config, pf_name,
|
||||
allocated_pci, is_non_nic_pf):
|
||||
"""Handle all variations of user specifid pci addr format
|
||||
|
||||
Arrive at the address fields of the whitelist. Check the address fields of
|
||||
the pci.passthrough_whitelist configuration option, validating the address fields.
|
||||
|
||||
:param user_configs: THT param NovaPCIPassthrough
|
||||
:param pf_name: Interface/device name (str)
|
||||
:param allocated_pci: List of VFs (for nic-partitioned PF), which are used by host
|
||||
:param is_non_nic_pf: Indicates whether the PF is non-partitioned or not
|
||||
:return: pci_passthrough: Derived config list
|
||||
:return del_user_config: Flag to state if the user_config is to be deleted or not
|
||||
|
||||
Example format for user_config:
|
||||
| [pci] in standard string format
|
||||
| passthrough_whitelist = {"address":"*:0a:00.*",
|
||||
"physical_network":"physnet1"}
|
||||
| passthrough_whitelist = {"address": {"domain": ".*",
|
||||
"bus": "02",
|
||||
"slot": "01",
|
||||
"function": "[0-2]"},
|
||||
"physical_network":"net1"}
|
||||
"""
|
||||
sel_addr = []
|
||||
pci_passthrough = []
|
||||
del_user_config = False
|
||||
|
||||
""" Get the regex of the address fields """
|
||||
if 'address' in user_config:
|
||||
addr_dict = user_config['address']
|
||||
user_address_pattern = "%s:%s:%s.%s" % (
|
||||
get_regex_pattern(addr_dict['domain'], 4),
|
||||
get_regex_pattern(addr_dict['bus'], 2),
|
||||
get_regex_pattern(addr_dict['slot'], 2),
|
||||
addr_dict['function'])
|
||||
if isinstance(user_config['address'], dict):
|
||||
addr_dict = user_config['address']
|
||||
elif isinstance(user_config['address'], str):
|
||||
addr_dict = get_pciaddr_dict_from_usraddr(user_config['address'])
|
||||
user_address_pattern = get_user_regex_from_addrdict(addr_dict)
|
||||
else:
|
||||
user_address_pattern = ("[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:"
|
||||
"[0-9a-fA-F]{2}.[0-7]")
|
||||
pci_addresses, dev_info = get_pci_addresses_by_ifname(pf, allocated_pci)
|
||||
for pci_addr in pci_addresses[pf]:
|
||||
user_address_regex = re.compile(user_address_pattern)
|
||||
if user_address_regex.match(pci_addr):
|
||||
sel_addr.append(pci_addr)
|
||||
pci_passthrough = get_pci_passthrough_whitelist(
|
||||
user_config, pf, sel_addr, dev_info)
|
||||
"[0-9a-fA-F]{2}.[0-7]")
|
||||
|
||||
return pci_passthrough
|
||||
""" If address mentioned in user_config is PF, then get all VFs belonging to that PF
|
||||
"""
|
||||
available_vfs = get_available_vf_pci_addresses_by_ifname(pf_name, allocated_pci)
|
||||
|
||||
# get the pci address of the PF
|
||||
parent_pci_address = get_pci_addr_from_ifname(pf_name)
|
||||
user_address_regex = re.compile(user_address_pattern)
|
||||
|
||||
# Match the user_config address with the PF's address
|
||||
if user_address_regex.match(parent_pci_address):
|
||||
match_id = match_pf_details(user_config, pf_name, is_non_nic_pf)
|
||||
""" if the address matches and there is no mismatch in
|
||||
product id's of PF, then add the PF's provided its not a
|
||||
NIC Partitioning PF
|
||||
"""
|
||||
if match_id == ADD_PF_PCI_ADDRESS:
|
||||
sel_addr.append(parent_pci_address)
|
||||
elif match_id == ADD_VF_PCI_ADDRESS:
|
||||
if pf_name in available_vfs:
|
||||
for vf_addr in available_vfs[pf_name]:
|
||||
sel_addr.append(vf_addr)
|
||||
if not sel_addr:
|
||||
del_user_config = True
|
||||
elif match_id == DEL_USER_CONFIG:
|
||||
del_user_config = True
|
||||
|
||||
""" Match the user_config address with the VF's address
|
||||
A Regex of addresses could match both the VF and PF's.
|
||||
If it matches the PF, all available VFs would be included anyway,
|
||||
so it will be inclusive even if the address matches the VFs of the same PF
|
||||
Also if product id is specified, it must match that of the VF's.
|
||||
If product id is not mentioned in user_config, its assumed to have
|
||||
matched and is left to address matching for derived configuration.
|
||||
If Address is not mentioned, then all available VF's (excluding NIC partitioned VFs)
|
||||
with the matching product id shall be added to the derived configuration.
|
||||
"""
|
||||
else:
|
||||
pf_path = os.path.join(_SYS_CLASS_NET_PATH, pf_name, "device")
|
||||
vendor, vf_product = get_pci_device_info_by_ifname(pf_path, 'virtfn0')
|
||||
if (('product_id' not in user_config or
|
||||
user_config['product_id'][-4:] == vf_product[-4:]) and
|
||||
pf_name in available_vfs):
|
||||
for vf_addr in available_vfs[pf_name]:
|
||||
user_address_regex = re.compile(user_address_pattern)
|
||||
if user_address_regex.match(vf_addr):
|
||||
sel_addr.append(vf_addr)
|
||||
if not sel_addr:
|
||||
for vf_addr in allocated_pci:
|
||||
if user_address_regex.match(vf_addr):
|
||||
""" When the user_config address matches that of the NIC Partitioned VF,
|
||||
the VF must be removed from the user_config. So return the status such
|
||||
that the caller ignores this user_config if this user_config is very
|
||||
specific to the NIC Partitioned VF. If the user_config resulted in the
|
||||
derivations of other configurations, the derived configuration shall
|
||||
replace the original user_config.
|
||||
"""
|
||||
del_user_config = True
|
||||
|
||||
if sel_addr:
|
||||
pci_passthrough = get_pci_passthrough_whitelist(
|
||||
user_config, pf_name, sel_addr)
|
||||
return pci_passthrough, del_user_config
|
||||
|
||||
|
||||
def get_passthrough_config_by_address(user_config,
|
||||
system_configs,
|
||||
allocated_pci):
|
||||
nic_part_config = []
|
||||
non_nic_part_config = []
|
||||
def get_passthrough_config_for_all_pf(user_config,
|
||||
system_configs,
|
||||
allocated_pci):
|
||||
derived_config = []
|
||||
nic_partition_pfs = get_sriov_nic_partition_pfs(system_configs)
|
||||
non_nic_partition_pfs = get_sriov_non_nic_partition_pfs(system_configs)
|
||||
del_user_config = False
|
||||
|
||||
"""
|
||||
For each user_config, do the matching for NIC Partitioning PFs/VFs
|
||||
"""
|
||||
for pf in nic_partition_pfs:
|
||||
passthrough_tmp = get_passthrough_config(
|
||||
user_config, pf, allocated_pci)
|
||||
nic_part_config.extend(passthrough_tmp)
|
||||
passthrough_tmp, status = get_passthrough_config(
|
||||
user_config, pf, allocated_pci, False)
|
||||
del_user_config = del_user_config or status
|
||||
if passthrough_tmp:
|
||||
derived_config.extend(passthrough_tmp)
|
||||
|
||||
if len(nic_part_config) == 0:
|
||||
return []
|
||||
"""
|
||||
If there is no config added from NIC Part nics, then skip parsing the
|
||||
NON NIC Partitioned PFs.
|
||||
"""
|
||||
if (derived_config or del_user_config):
|
||||
for pf in non_nic_partition_pfs:
|
||||
passthrough_tmp, status = get_passthrough_config(
|
||||
user_config, pf, allocated_pci, True)
|
||||
derived_config.extend(passthrough_tmp)
|
||||
|
||||
for pf in non_nic_partition_pfs:
|
||||
passthrough_tmp = get_passthrough_config(
|
||||
user_config, pf, allocated_pci)
|
||||
non_nic_part_config.extend(passthrough_tmp)
|
||||
return nic_part_config + non_nic_part_config
|
||||
|
||||
|
||||
def get_passthrough_config_by_product(user_config,
|
||||
system_configs,
|
||||
allocated_pci):
|
||||
nic_part_config = []
|
||||
non_nic_part_config = []
|
||||
nic_partition_pfs = get_sriov_nic_partition_pfs(system_configs)
|
||||
non_nic_partition_pfs = get_sriov_non_nic_partition_pfs(system_configs)
|
||||
for pf in nic_partition_pfs:
|
||||
pf_path = _SYS_CLASS_NET_PATH + "/%s/device" % pf
|
||||
vendor, product = get_pci_device_info_by_ifname(pf_path, 'virtfn0')
|
||||
if (user_config['product_id'][-4:] == product[-4:] and
|
||||
user_config['vendor_id'][-4:] == vendor[-4:]):
|
||||
passthrough_tmp = get_passthrough_config(
|
||||
user_config, pf, allocated_pci)
|
||||
nic_part_config.extend(passthrough_tmp)
|
||||
|
||||
if len(nic_part_config) == 0:
|
||||
return []
|
||||
|
||||
for pf in non_nic_partition_pfs:
|
||||
pf_path = _SYS_CLASS_NET_PATH + "/%s/device" % pf
|
||||
vendor, product = get_pci_device_info_by_ifname(pf_path, 'virtfn0')
|
||||
if (user_config['product_id'][-4:] == product[-4:] and
|
||||
user_config['vendor_id'][-4:] == vendor[-4:]):
|
||||
passthrough_tmp = get_passthrough_config(
|
||||
user_config, pf, allocated_pci)
|
||||
non_nic_part_config.extend(passthrough_tmp)
|
||||
return nic_part_config + non_nic_part_config
|
||||
if derived_config:
|
||||
return derived_config, False
|
||||
else:
|
||||
return derived_config, del_user_config
|
||||
|
||||
|
||||
def get_pf_name_from_phy_network(physical_network):
|
||||
|
@ -247,12 +461,17 @@ def get_pf_name_from_phy_network(physical_network):
|
|||
'neutron::agents::ml2::sriov::physical_device_mappings')
|
||||
if not err:
|
||||
phys_dev_mappings = json.loads(out)
|
||||
''' Check the data type of first json decode '''
|
||||
if not isinstance(phys_dev_mappings, list):
|
||||
msg = ('ml2::sriov::physical_device_mappings specified is not a list %s'
|
||||
% phys_dev_mappings)
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
for phy_dev_map in phys_dev_mappings:
|
||||
net_name, nic_name = phy_dev_map.split(':')
|
||||
if net_name == physical_network:
|
||||
return nic_name
|
||||
return None
|
||||
|
||||
except processutils.ProcessExecutionError:
|
||||
raise
|
||||
|
||||
|
@ -266,67 +485,74 @@ def generate_combined_configuration(user_configs, system_configs):
|
|||
as it is.
|
||||
:param user_configs: THT param NovaPCIPassthrough
|
||||
:param system_configs: Derived from sriov-mapping.yaml
|
||||
:return user_config_copy: Any non-nic partinioned cfg will be returned in this list
|
||||
:return derived_config: All nic partinioned cfg will be returned after derivation in this list
|
||||
"""
|
||||
|
||||
non_nic_part_config = []
|
||||
nic_part_config = []
|
||||
user_config_copy = []
|
||||
derived_config = []
|
||||
|
||||
allocated_pci = get_allocated_pci_addresses(system_configs)
|
||||
nic_partition_pfs = get_sriov_nic_partition_pfs(system_configs)
|
||||
|
||||
for user_config in user_configs:
|
||||
if ('devname' in user_config and
|
||||
(user_config['devname'] in nic_partition_pfs)):
|
||||
passthru_tmp = get_passthrough_config(
|
||||
user_config, user_config['devname'], allocated_pci)
|
||||
nic_part_config.extend(passthru_tmp)
|
||||
elif 'physical_network' in user_config:
|
||||
if 'address' in user_config and 'devname' in user_config:
|
||||
msg = "Both devname and address can't be present in %s" % _PASSTHROUGH_WHITELIST_KEY
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
keys = ['address', 'product_id', 'devname']
|
||||
if not any(k in user_config for k in keys):
|
||||
# address or product_id or devname not present in user_config
|
||||
pf = get_pf_name_from_phy_network(user_config['physical_network'])
|
||||
if pf in nic_partition_pfs:
|
||||
passthru_tmp = get_passthrough_config(
|
||||
user_config, pf, allocated_pci)
|
||||
nic_part_config.extend(passthru_tmp)
|
||||
user_config['address'] = get_pci_addr_from_ifname(pf)
|
||||
|
||||
if 'devname' in user_config:
|
||||
if user_config['devname'] in nic_partition_pfs:
|
||||
user_config['address'] = get_pci_addr_from_ifname(user_config['devname'])
|
||||
del user_config['devname']
|
||||
else:
|
||||
non_nic_part_config.append(user_config)
|
||||
elif 'address' in user_config:
|
||||
passthrough_tmp = get_passthrough_config_by_address(
|
||||
user_config_copy.append(user_config)
|
||||
continue
|
||||
if ('address' in user_config or
|
||||
'product_id' in user_config):
|
||||
passthrough_tmp, del_user_config = get_passthrough_config_for_all_pf(
|
||||
user_config, system_configs, allocated_pci)
|
||||
if len(passthrough_tmp) == 0:
|
||||
non_nic_part_config.append(user_config)
|
||||
else:
|
||||
nic_part_config.extend(passthrough_tmp)
|
||||
elif ('product_id' in user_config and 'vendor_id' in user_config):
|
||||
passthrough_tmp = get_passthrough_config_by_product(
|
||||
user_config, system_configs, allocated_pci)
|
||||
if len(passthrough_tmp) == 0:
|
||||
non_nic_part_config.append(user_config)
|
||||
else:
|
||||
nic_part_config.extend(passthrough_tmp)
|
||||
|
||||
""" If del_user_config is set, do not add to derived_config or
|
||||
user_config_copy
|
||||
"""
|
||||
if not del_user_config:
|
||||
if passthrough_tmp:
|
||||
derived_config.extend(passthrough_tmp)
|
||||
else:
|
||||
user_config_copy.append(user_config)
|
||||
else:
|
||||
non_nic_part_config.append(user_config)
|
||||
return (non_nic_part_config, nic_part_config)
|
||||
user_config_copy.append(user_config)
|
||||
return (user_config_copy, derived_config)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pci_passthrough = {}
|
||||
pci_file_path = '/etc/puppet/hieradata/pci_passthrough_whitelist.json'
|
||||
pci_file_path = _DERIVED_PCI_WHITELIST_FILE
|
||||
system_configs = get_sriov_configs()
|
||||
user_configs = user_passthrough_config()
|
||||
|
||||
# Check if user config list is valid
|
||||
if not isinstance(user_configs, list):
|
||||
msg = "user_config specified is not a list {%s}" % user_configs
|
||||
raise Exception(msg)
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
if (len(user_configs) > 0):
|
||||
non_nic_part, nic_part = generate_combined_configuration(
|
||||
user_configs, system_configs)
|
||||
user_config_copy, derived = generate_combined_configuration(
|
||||
user_configs, system_configs)
|
||||
|
||||
if len(nic_part) > 0:
|
||||
pci_passthrough[_PASSTHROUGH_WHITELIST_KEY] = (non_nic_part +
|
||||
nic_part)
|
||||
|
||||
with open(pci_file_path, 'w') as pci_file:
|
||||
json.dump(pci_passthrough, pci_file)
|
||||
""" If the derivation does not bring in any changes, the user_config_copy list
|
||||
and user_configs shall be same. The pci_passthrough_whitelist.json
|
||||
shall be updated only when there is a change needed due to NIC Partition
|
||||
"""
|
||||
if user_config_copy != user_configs:
|
||||
pci_passthrough[_PASSTHROUGH_WHITELIST_KEY] = (user_config_copy +
|
||||
derived)
|
||||
with open(pci_file_path, 'w') as pci_file:
|
||||
json.dump(pci_passthrough, pci_file)
|
||||
else:
|
||||
print("Empty user_configs, nothing to do")
|
||||
print("user_configs is good, nothing to be modified")
|
||||
|
|
29
tox.ini
29
tox.ini
|
@ -84,3 +84,32 @@ whitelist_externals =
|
|||
bash
|
||||
commands =
|
||||
bash -c tools/roles-data-generate-samples.sh
|
||||
|
||||
[testenv:tht]
|
||||
usedevelop = True
|
||||
setenv =
|
||||
ANSIBLE_FORCE_COLOR=1
|
||||
ANSIBLE_INVENTORY={toxinidir}/test/hosts.ini
|
||||
ANSIBLE_THT_FOLDER={toxinidir}
|
||||
ANSIBLE_NOCOWS=1
|
||||
ANSIBLE_RETRY_FILES_ENABLED=0
|
||||
ANSIBLE_STDOUT_CALLBACK=debug
|
||||
PY_COLORS=1
|
||||
VIRTUAL_ENV={envdir}
|
||||
# Avoid 2020-01-01 warnings: https://github.com/pypa/pip/issues/6207
|
||||
PYTHONWARNINGS=ignore:DEPRECATION::pip._internal.cli.base_command
|
||||
PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
passenv =
|
||||
ANSIBLE_*
|
||||
deps =
|
||||
-r{toxinidir}/test-ansible-requirements.txt
|
||||
allowlist_externals =
|
||||
bash
|
||||
commands_pre =
|
||||
pip install -q bindep fixtures
|
||||
bindep test
|
||||
commands =
|
||||
pytest --color=no \
|
||||
--html={envlogdir}/reports.html \
|
||||
--self-contained-html \
|
||||
{toxinidir}/tripleo_heat_templates/tests/test_tht_derivce_pci.py
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue