339bc6b51d
On ubuntu: $cd <basedir>/extras/vpp_config $./scripts/clean.sh $./scripts/cp-data.sh $sudo apt-get install python3-pip python3-setuptools $python3 -m pip install . $vpp-config Changes: * Convert to print() function. * raw_input changes. * floor division changes. * replace vpp-config.py with a setuptools 'vpp-config' entry_point. * replace netaddr with ipaddress from the standard library and backport. * .decode() subprocess.Popen's stdout because in python3 they are bytes. Change-Id: Id98894ee54e0c31a0ba0304134b159caef415705 Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
338 lines
11 KiB
Python
338 lines
11 KiB
Python
# 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
|