blob: 032a262c21c11040061d4e60ddc61fa2e792bf2f [file] [log] [blame]
# Copyright (c) 2016 Cisco and/or its affiliates.
# 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.
from __future__ import print_function
"""VPP PCI Utility libraries"""
import re
import logging
from vpplib.VPPUtil import VPPUtil
DPDK_SCRIPT = "/vpp/vpp-config/scripts/dpdk-devbind.py"
# PCI Device id regular expresssion
PCI_DEV_ID_REGEX = "[0-9A-Fa-f]+:[0-9A-Fa-f]+:[0-9A-Fa-f]+.[0-9A-Fa-f]+"
class VppPCIUtil(object):
"""
PCI Utilities
"""
@staticmethod
def _create_device_list(device_string):
"""
Returns a list of PCI devices
:param device_string: The devices string from dpdk_devbind
:returns: The device list
:rtype: dictionary
"""
devices = {}
ids = re.findall(PCI_DEV_ID_REGEX, device_string)
descriptions = re.findall(r"\'([\s\S]*?)\'", device_string)
unused = re.findall(r"unused=\w+|unused=", device_string)
for i, j in enumerate(ids):
device = {"description": descriptions[i]}
if unused:
device["unused"] = unused[i].split("=")[1].split(",")
cmd = "ls /sys/bus/pci/devices/{}/driver/module/drivers".format(ids[i])
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
if ret == 0:
device["driver"] = stdout.split(":")[1].rstrip("\n")
cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(ids[i])
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
if ret != 0:
raise RuntimeError("{} failed {} {}".format(cmd, stderr, stdout))
numa_node = stdout.rstrip("\n")
if numa_node == "-1":
device["numa_node"] = "0"
else:
device["numa_node"] = numa_node
interfaces = []
device["interfaces"] = []
cmd = "ls /sys/bus/pci/devices/{}/net".format(ids[i])
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
if ret == 0:
interfaces = stdout.rstrip("\n").split()
device["interfaces"] = interfaces
l2_addrs = []
for intf in interfaces:
cmd = "cat /sys/bus/pci/devices/{}/net/{}/address".format(ids[i], intf)
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
if ret != 0:
raise RuntimeError("{} failed {} {}".format(cmd, stderr, stdout))
l2_addrs.append(stdout.rstrip("\n"))
device["l2addr"] = l2_addrs
devices[ids[i]] = device
return devices
def __init__(self, node):
self._node = node
self._dpdk_devices = {}
self._kernel_devices = {}
self._other_devices = {}
self._crypto_dpdk_devices = {}
self._crypto_kernel_devices = {}
self._crypto_other_devices = {}
self._link_up_devices = {}
def get_all_devices(self):
"""
Returns a list of all the devices
"""
node = self._node
rootdir = node["rootdir"]
dpdk_script = rootdir + DPDK_SCRIPT
cmd = dpdk_script + " --status"
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
if ret != 0:
raise RuntimeError(
"{} failed on node {} {}".format(cmd, node["host"], stderr)
)
# Get the network devices using the DPDK
# First get everything after using DPDK
stda = stdout.split("Network devices using DPDK-compatible driver")[1]
# Then get everything before using kernel driver
using_dpdk = stda.split("Network devices using kernel driver")[0]
self._dpdk_devices = self._create_device_list(using_dpdk)
# Get the network devices using the kernel
stda = stdout.split("Network devices using kernel driver")[1]
using_kernel = stda.split("Other network devices")[0]
self._kernel_devices = self._create_device_list(using_kernel)
# Get the other network devices
stda = stdout.split("Other network devices")[1]
other = stda.split("Crypto devices using DPDK-compatible driver")[0]
self._other_devices = self._create_device_list(other)
# Get the crypto devices using the DPDK
stda = stdout.split("Crypto devices using DPDK-compatible driver")[1]
crypto_using_dpdk = stda.split("Crypto devices using kernel driver")[0]
self._crypto_dpdk_devices = self._create_device_list(crypto_using_dpdk)
# Get the network devices using the kernel
stda = stdout.split("Crypto devices using kernel driver")[1]
crypto_using_kernel = stda.split("Other crypto devices")[0]
self._crypto_kernel_devices = self._create_device_list(crypto_using_kernel)
# Get the other network devices
crypto_other = stdout.split("Other crypto devices")[1]
self._crypto_other_devices = self._create_device_list(crypto_other)
# Get the devices used by the kernel
for devk in self._kernel_devices.items():
dvid = devk[0]
device = devk[1]
for i in device["interfaces"]:
cmd = "ip addr show " + i
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
if ret != 0:
raise RuntimeError(
"{} failed on node {} {}".format(cmd, node["host"], stderr)
)
lstate = re.findall(r"state \w+", stdout)[0].split(" ")[1]
# Take care of the links that are UP
if lstate == "UP":
device["linkup"] = True
self._link_up_devices[dvid] = device
for devl in self._link_up_devices.items():
dvid = devl[0]
del self._kernel_devices[dvid]
def get_dpdk_devices(self):
"""
Returns a list the dpdk devices
"""
return self._dpdk_devices
def get_kernel_devices(self):
"""
Returns a list the kernel devices
"""
return self._kernel_devices
def get_other_devices(self):
"""
Returns a list the other devices
"""
return self._other_devices
def get_crypto_dpdk_devices(self):
"""
Returns a list the crypto dpdk devices
"""
return self._crypto_dpdk_devices
def get_crypto_kernel_devices(self):
"""
Returns a list the crypto kernel devices
"""
return self._crypto_kernel_devices
def get_crypto_other_devices(self):
"""
Returns a list the crypto other devices
"""
return self._crypto_other_devices
def get_link_up_devices(self):
"""
Returns a list the link up devices
"""
return self._link_up_devices
@staticmethod
def vpp_create_interface(interfaces, device_id, device):
"""
Create an interface using the device is and device
"""
name = "port" + str(len(interfaces))
interfaces[name] = {}
interfaces[name]["pci_address"] = device_id
interfaces[name]["numa_node"] = device["numa_node"]
if "l2addr" in device:
l2_addrs = device["l2addr"]
for i, j in enumerate(l2_addrs):
if i > 0:
mname = "mac_address" + str(i + 1)
interfaces[name][mname] = l2_addrs[i]
else:
interfaces[name]["mac_address"] = l2_addrs[i]
@staticmethod
def show_vpp_devices(devices, show_interfaces=True, show_header=True):
"""
show the vpp devices specified in the argument
:param devices: A list of devices
:param show_interfaces: show the kernel information
:param show_header: Display the header if true
:type devices: dict
:type show_interfaces: bool
:type show_header: bool
"""
if show_interfaces:
header = "{:15} {:25} {:50}".format(
"PCI ID", "Kernel Interface(s)", "Description"
)
else:
header = "{:15} {:50}".format("PCI ID", "Description")
dashseparator = "-" * (len(header) - 2)
if show_header is True:
print(header)
print(dashseparator)
for dit in devices.items():
dvid = dit[0]
device = dit[1]
if show_interfaces:
interfaces = device["interfaces"]
interface = ""
for i, j in enumerate(interfaces):
if i > 0:
interface += "," + interfaces[i]
else:
interface = interfaces[i]
print(
"{:15} {:25} {:50}".format(dvid, interface, device["description"])
)
else:
print("{:15} {:50}".format(dvid, device["description"]))
@staticmethod
def unbind_vpp_device(node, device_id):
"""
unbind the device specified
:param node: Node dictionary with cpuinfo.
:param device_id: The device id
:type node: dict
:type device_id: string
"""
rootdir = node["rootdir"]
dpdk_script = rootdir + DPDK_SCRIPT
cmd = dpdk_script + " -u " + " " + device_id
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
if ret != 0:
raise RuntimeError(
"{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
)
@staticmethod
def bind_vpp_device(node, driver, device_id):
"""
bind the device specified
:param node: Node dictionary with cpuinfo.
:param driver: The driver
:param device_id: The device id
:type node: dict
:type driver: string
:type device_id: string
:returns ret: Command return code
"""
rootdir = node["rootdir"]
dpdk_script = rootdir + DPDK_SCRIPT
cmd = dpdk_script + " -b " + driver + " " + device_id
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
if ret != 0:
logging.error(
"{} failed on node {}".format(cmd, node["host"], stdout, stderr)
)
logging.error("{} {}".format(stdout, stderr))
return ret