cyborg/cyborg/accelerator/drivers/nic/intel/sysinfo.py

254 lines
8.0 KiB
Python

# Copyright 2020 Intel, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Cyborg Intel NIC driver implementation.
"""
import glob
import os
import socket
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from cyborg.accelerator.common import utils
import cyborg.conf
from cyborg.objects.driver_objects import driver_attach_handle
from cyborg.objects.driver_objects import driver_attribute
from cyborg.objects.driver_objects import driver_controlpath_id
from cyborg.objects.driver_objects import driver_deployable
from cyborg.objects.driver_objects import driver_device
LOG = logging.getLogger(__name__)
PCI_DEVICES_PATH_PATTERN = "/sys/bus/pci/devices/*"
KNOWN_NICS = [("0x8086", "0x158b"), ("0x8086", "0x1572")]
DRIVER_NAME = "intel"
VF = "virtfn*"
_SRIOV_TOTALVFS = "sriov_totalvfs"
CONF = cyborg.conf.CONF
def _parse_config():
# parse nic config.
cyborg.conf.devices.register_dynamic_opts(CONF)
try:
pdm = utils.parse_mappings(CONF.x710_static.physical_device_mappings)
fdm = utils.parse_mappings(CONF.x710_static.function_device_mappings)
except cfg.NoSuchOptError:
return None, None
else:
return pdm, fdm
def get_physical_network_and_traits(pci_info, physnet_device_mappings,
function_device_mappings, pf_nic=None):
traits = []
physnet = None
func_name = None
if pf_nic:
pf_addr = pf_nic["device"]
traits.append("CUSTOM_VF")
else:
pf_addr = pci_info["PCI_SLOT_NAME"]
traits.append("CUSTOM_PF")
if not pf_addr:
LOG.error("Incorrect report data received. Missing PF info.")
pf_ifname = utils.get_ifname_by_pci_address(pf_addr)
if physnet_device_mappings:
for key, devices in physnet_device_mappings.items():
if pf_ifname in devices:
physnet = key
break
if function_device_mappings:
for key, devices in function_device_mappings.items():
if pf_ifname in devices:
func_name = key
break
if func_name:
traits.append("CUSTOM_" + func_name.upper())
if physnet:
traits.append("CUSTOM_" + physnet.upper())
return {"traits": traits, "physical_network": physnet}
def read_line(filename):
with open(filename) as f:
return f.readline().strip()
def find_nics_by_know_list():
return set(filter(
lambda p: (
read_line(os.path.join(p, "vendor")),
read_line(os.path.join(p, "device"))
) in KNOWN_NICS,
glob.glob(PCI_DEVICES_PATH_PATTERN)))
def pci_attributes(path):
with open(os.path.join(path, "uevent")) as f:
attributes = dict(map(
lambda p: p.strip().split("="),
f.readlines()
))
with open(os.path.join(path, "vendor")) as f:
attributes["VENDOR"] = f.readline().strip()
with open(os.path.join(path, "device")) as f:
attributes["PRODUCT_ID"] = f.readline().strip()
return attributes
def nic_gen(path, physnet_device_mappings=None, function_device_mappings=None,
pf_nic=None):
pci_info = pci_attributes(path)
nic = {
"name": "_".join((socket.gethostname(), pci_info["PCI_SLOT_NAME"])),
"device": pci_info["PCI_SLOT_NAME"],
"type": "NIC",
"vendor": pci_info["VENDOR"],
"product_id": pci_info["PRODUCT_ID"],
"rc": "CUSTOM_NIC",
"stub": False,
}
# TODO(Xinran): need check device id and call get_traits differently.
updates = get_physical_network_and_traits(pci_info,
physnet_device_mappings,
function_device_mappings,
pf_nic)
nic.update(updates)
return nic
def all_pfs_with_vf():
return set(filter(
lambda p: glob.glob(os.path.join(p, VF)),
find_nics_by_know_list()))
def all_vfs_in_pf(pf_path):
return map(
lambda p:
os.path.join(
os.path.dirname(os.path.dirname(p)),
os.path.basename(os.readlink(p))),
glob.glob(os.path.join(pf_path, VF)))
def nic_tree():
physnet_device_mappings, function_device_mappings = _parse_config()
nics = []
pfs_has_vf = all_pfs_with_vf()
for n in find_nics_by_know_list():
nic = nic_gen(n, physnet_device_mappings, function_device_mappings)
if n in pfs_has_vf:
vfs = []
for vf in all_vfs_in_pf(n):
vf_nic = nic_gen(vf, physnet_device_mappings,
function_device_mappings, nic)
vfs.append(vf_nic)
nic["vfs"] = vfs
nics.append(_generate_driver_device(nic))
return nics
def _generate_driver_device(nic):
driver_device_obj = driver_device.DriverDevice()
driver_device_obj.vendor = nic["vendor"]
driver_device_obj.stub = nic["stub"]
driver_device_obj.model = nic.get("model", "miss_model_info")
driver_device_obj.vendor_board_info = nic.get(
"vendor_board_info",
"miss_vb_info")
std_board_info = {"product_id": nic.get("product_id", None)}
driver_device_obj.std_board_info = jsonutils.dumps(std_board_info)
driver_device_obj.type = nic["type"]
driver_device_obj.controlpath_id = _generate_controlpath_id(nic)
driver_device_obj.deployable_list = _generate_dep_list(nic)
return driver_device_obj
def _generate_controlpath_id(nic):
driver_cpid = driver_controlpath_id.DriverControlPathID()
driver_cpid.cpid_type = "PCI"
driver_cpid.cpid_info = utils.pci_str_to_json(nic["device"])
return driver_cpid
def _generate_dep_list(nic):
dep_list = []
# pf without sriov enabled.
if "vfs" not in nic:
driver_dep = driver_deployable.DriverDeployable()
driver_dep.num_accelerators = 1
driver_dep.attach_handle_list = [
_generate_attach_handle(nic)]
driver_dep.name = nic["name"]
driver_dep.driver_name = DRIVER_NAME
driver_dep.attribute_list = _generate_attribute_list(nic)
dep_list = [driver_dep]
# pf with sriov enabled, may have several vfs.
else:
for vf in nic["vfs"]:
driver_dep = driver_deployable.DriverDeployable()
driver_dep.num_accelerators = 1
driver_dep.attach_handle_list = [
_generate_attach_handle(vf)]
driver_dep.name = vf["name"]
driver_dep.driver_name = DRIVER_NAME
driver_dep.attribute_list = _generate_attribute_list(vf)
dep_list.append(driver_dep)
return dep_list
def _generate_attach_handle(nic):
driver_ah = driver_attach_handle.DriverAttachHandle()
driver_ah.attach_type = "PCI"
driver_ah.attach_info = utils.pci_str_to_json(nic["device"],
nic["physical_network"])
driver_ah.in_use = False
return driver_ah
def _generate_attribute_list(nic):
attr_list = []
for k, v in nic.items():
if k == "rc":
driver_attr = driver_attribute.DriverAttribute()
driver_attr.key, driver_attr.value = k, v
attr_list.append(driver_attr)
if k == "traits":
values = nic.get(k, [])
for idx, val in enumerate(values):
driver_attr = driver_attribute.DriverAttribute()
driver_attr.key = "trait" + str(idx)
driver_attr.value = val
attr_list.append(driver_attr)
return attr_list