Consider user configuration during the derivation of passthrough whitelist
The user configuration supplied in NovaPCIPassthrough shall be considered
during the derivation of the pci::passthrough parameter for NIC Partitioning.
The VF's specified by user configuration minus the VF's alloted for NIC
Partitioning shall be derrived.
Change-Id: Ic8f506a0eef5c1c8b1cf0d4fca9b2c6d68ef0fc3
(cherry picked from commit e51920623e
)
This commit is contained in:
parent
44636dde61
commit
d3aa1a9ef0
|
@ -20,6 +20,13 @@ import os
|
||||||
import re
|
import re
|
||||||
import yaml
|
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'
|
||||||
|
|
||||||
|
|
||||||
def get_sriov_configs():
|
def get_sriov_configs():
|
||||||
configs = []
|
configs = []
|
||||||
|
@ -44,6 +51,21 @@ def get_sriov_nic_partition_pfs(configs):
|
||||||
return pfs
|
return pfs
|
||||||
|
|
||||||
|
|
||||||
|
def get_sriov_non_nic_partition_pfs(configs):
|
||||||
|
all_pfs = []
|
||||||
|
non_nicp_pfs = []
|
||||||
|
nicp_pfs = get_sriov_nic_partition_pfs(configs)
|
||||||
|
|
||||||
|
for config in configs:
|
||||||
|
device_type = config.get('device_type', None)
|
||||||
|
if device_type and 'pf' in device_type:
|
||||||
|
name = config.get('name', None)
|
||||||
|
if name and name not in all_pfs:
|
||||||
|
all_pfs.append(name)
|
||||||
|
non_nicp_pfs = [x for x in all_pfs if x not in nicp_pfs]
|
||||||
|
return non_nicp_pfs
|
||||||
|
|
||||||
|
|
||||||
def get_pci_device_info_by_ifname(pci_dir, sub_dir):
|
def get_pci_device_info_by_ifname(pci_dir, sub_dir):
|
||||||
if not os.path.isdir(os.path.join(pci_dir, sub_dir)):
|
if not os.path.isdir(os.path.join(pci_dir, sub_dir)):
|
||||||
return None
|
return None
|
||||||
|
@ -57,14 +79,14 @@ def get_pci_device_info_by_ifname(pci_dir, sub_dir):
|
||||||
'device')) as product_file:
|
'device')) as product_file:
|
||||||
product = product_file.read().strip()
|
product = product_file.read().strip()
|
||||||
return (vendor, product)
|
return (vendor, product)
|
||||||
except IOError as exc:
|
except IOError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_pci_addresses_by_ifname(pfs, allocated_pci):
|
def get_pci_addresses_by_ifname(pfs, allocated_pci):
|
||||||
pci_addresses = {}
|
pci_addresses = {}
|
||||||
device_info = {}
|
device_info = {}
|
||||||
pci_dir = '/sys/bus/pci/devices'
|
pci_dir = _PCI_DEVICES_PATH
|
||||||
if os.path.isdir(pci_dir):
|
if os.path.isdir(pci_dir):
|
||||||
for sub_dir in os.listdir(pci_dir):
|
for sub_dir in os.listdir(pci_dir):
|
||||||
if sub_dir in allocated_pci:
|
if sub_dir in allocated_pci:
|
||||||
|
@ -79,7 +101,8 @@ def get_pci_addresses_by_ifname(pfs, allocated_pci):
|
||||||
else:
|
else:
|
||||||
pci_addresses[phyfn].append(sub_dir)
|
pci_addresses[phyfn].append(sub_dir)
|
||||||
if phyfn not in device_info:
|
if phyfn not in device_info:
|
||||||
dev_info = get_pci_device_info_by_ifname(pci_dir, sub_dir)
|
dev_info = get_pci_device_info_by_ifname(pci_dir,
|
||||||
|
sub_dir)
|
||||||
if dev_info:
|
if dev_info:
|
||||||
device_info[phyfn] = dev_info
|
device_info[phyfn] = dev_info
|
||||||
return (pci_addresses, device_info)
|
return (pci_addresses, device_info)
|
||||||
|
@ -94,32 +117,201 @@ def get_allocated_pci_addresses(configs):
|
||||||
return alloc_pci_info
|
return alloc_pci_info
|
||||||
|
|
||||||
|
|
||||||
def get_pci_passthrough_whitelist(pci_addresses, device_info):
|
def get_pci_passthrough_whitelist(user_config, pf, pci_addresses,
|
||||||
pci_passthrough_whitelist = {}
|
device_info):
|
||||||
pci_passthrough_list = []
|
pci_passthrough_list = []
|
||||||
for pf, pci_list in pci_addresses.items():
|
|
||||||
for pci in pci_list:
|
for pci in pci_addresses:
|
||||||
pci_passthrough = {}
|
pci_passthrough = {}
|
||||||
address = {}
|
address = {}
|
||||||
pci_params = re.split('[:.]+', pci)
|
pci_params = re.split('[:.]+', pci)
|
||||||
address['domain'] = '.*'
|
address['domain'] = '.*'
|
||||||
address['bus'] = pci_params[1]
|
address['bus'] = pci_params[1]
|
||||||
address['slot'] = pci_params[2]
|
address['slot'] = pci_params[2]
|
||||||
address['function'] = pci_params[3]
|
address['function'] = pci_params[3]
|
||||||
pci_passthrough['address'] = address
|
pci_passthrough['address'] = address
|
||||||
pci_passthrough['vendor_id'] = device_info[pf][0]
|
pci_passthrough['vendor_id'] = device_info[pf][0]
|
||||||
pci_passthrough['product_id'] = device_info[pf][1]
|
pci_passthrough['product_id'] = device_info[pf][1]
|
||||||
pci_passthrough_list.append(pci_passthrough)
|
if 'trusted' in user_config:
|
||||||
pci_passthrough_whitelist['nova::compute::pci::passthrough'] = str(json.dumps(pci_passthrough_list))
|
pci_passthrough['trusted'] = user_config['trusted']
|
||||||
return pci_passthrough_whitelist
|
pci_passthrough_list.append(pci_passthrough)
|
||||||
|
return pci_passthrough_list
|
||||||
|
|
||||||
|
|
||||||
|
def user_passthrough_config():
|
||||||
|
try:
|
||||||
|
out, err = processutils.execute(
|
||||||
|
'hiera', '-c', '/etc/puppet/hiera.yaml',
|
||||||
|
_PASSTHROUGH_WHITELIST_KEY
|
||||||
|
)
|
||||||
|
if not err:
|
||||||
|
return json.loads(out)
|
||||||
|
except processutils.ProcessExecutionError:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def get_regex_pattern(config_regex, size):
|
||||||
|
if config_regex == ".*":
|
||||||
|
regex_pattern = "[0-9a-fA-F]{%d}" % size
|
||||||
|
else:
|
||||||
|
regex_pattern = config_regex
|
||||||
|
return regex_pattern
|
||||||
|
|
||||||
|
|
||||||
|
def get_passthrough_config(user_config, pf, allocated_pci):
|
||||||
|
sel_addr = []
|
||||||
|
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'])
|
||||||
|
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)
|
||||||
|
|
||||||
|
return pci_passthrough
|
||||||
|
|
||||||
|
|
||||||
|
def get_passthrough_config_by_address(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:
|
||||||
|
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:
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def get_pf_name_from_phy_network(physical_network):
|
||||||
|
try:
|
||||||
|
out, err = processutils.execute(
|
||||||
|
'hiera', '-c', '/etc/puppet/hiera.yaml',
|
||||||
|
'neutron::agents::ml2::sriov::physical_device_mappings')
|
||||||
|
if not err:
|
||||||
|
phys_dev_mappings = json.loads(out)
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def generate_combined_configuration(user_configs, system_configs):
|
||||||
|
"""Derived configuration = user_config - system_configs
|
||||||
|
|
||||||
|
Identify the user_defined configuration that overlaps with the
|
||||||
|
NIC Partitioned VFs and remove those VFs from the derived configuration
|
||||||
|
In case of no overlap, the user defined configuration shall be used
|
||||||
|
as it is.
|
||||||
|
:param user_configs: THT param NovaPCIPassthrough
|
||||||
|
:param system_configs: Derived from sriov-mapping.yaml
|
||||||
|
"""
|
||||||
|
|
||||||
|
non_nic_part_config = []
|
||||||
|
nic_part_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:
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
non_nic_part_config.append(user_config)
|
||||||
|
elif 'address' in user_config:
|
||||||
|
passthrough_tmp = get_passthrough_config_by_address(
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
non_nic_part_config.append(user_config)
|
||||||
|
return (non_nic_part_config, nic_part_config)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
pci_passthrough = {}
|
||||||
pci_file_path = '/etc/puppet/hieradata/pci_passthrough_whitelist.json'
|
pci_file_path = '/etc/puppet/hieradata/pci_passthrough_whitelist.json'
|
||||||
configs = get_sriov_configs()
|
system_configs = get_sriov_configs()
|
||||||
nic_partition_pfs = get_sriov_nic_partition_pfs(configs)
|
user_configs = user_passthrough_config()
|
||||||
allocated_pci = get_allocated_pci_addresses(configs)
|
|
||||||
pci_addresses, device_info = get_pci_addresses_by_ifname(nic_partition_pfs, allocated_pci)
|
non_nic_part, nic_part = generate_combined_configuration(
|
||||||
pci_passthrough = get_pci_passthrough_whitelist(pci_addresses, device_info)
|
user_configs, system_configs)
|
||||||
with open(pci_file_path, 'w') as pci_file:
|
|
||||||
json.dump(pci_passthrough, pci_file)
|
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)
|
||||||
|
|
|
@ -152,8 +152,8 @@ outputs:
|
||||||
mode: 0750
|
mode: 0750
|
||||||
- name: derive pci passthrough whitelist
|
- name: derive pci passthrough whitelist
|
||||||
copy:
|
copy:
|
||||||
content: {get_file: ./derive_pci_passthrough_whitelist.py}
|
src: /usr/share/openstack-tripleo-heat-templates/docker/services/derive_pci_passthrough_whitelist.py
|
||||||
dest: '/var/lib/pci_passthrough_whitelist_scripts/derive_pci_passthrough_whitelist.py'
|
dest: /var/lib/pci_passthrough_whitelist_scripts/derive_pci_passthrough_whitelist.py
|
||||||
mode: 0700
|
mode: 0700
|
||||||
- name: run derive_pci_passthrough_whitelist.py
|
- name: run derive_pci_passthrough_whitelist.py
|
||||||
command: /var/lib/pci_passthrough_whitelist_scripts/derive_pci_passthrough_whitelist.py
|
command: /var/lib/pci_passthrough_whitelist_scripts/derive_pci_passthrough_whitelist.py
|
||||||
|
|
Loading…
Reference in New Issue