diff options
Diffstat (limited to 'extras/vpp_config/vpplib/VppPCIUtil.py')
-rw-r--r-- | extras/vpp_config/vpplib/VppPCIUtil.py | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/extras/vpp_config/vpplib/VppPCIUtil.py b/extras/vpp_config/vpplib/VppPCIUtil.py new file mode 100644 index 00000000000..829d66ae374 --- /dev/null +++ b/extras/vpp_config/vpplib/VppPCIUtil.py @@ -0,0 +1,330 @@ +# 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)) |