blob: 829d66ae3747fb6c7c799c0bab780db8757d5edc [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.
"""VPP PCI Utility libraries"""
import re
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,]+', 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
:type devices: dict
:type show_interfaces: 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 == 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
"""
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:
raise RuntimeError('{} failed on node {} {} {}'.format(
cmd, node['host'], stdout, stderr))