1 # Copyright (c) 2016 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 from __future__ import print_function
16 """VPP PCI Utility libraries"""
21 from vpplib.VPPUtil import VPPUtil
23 DPDK_SCRIPT = "/vpp/vpp-config/scripts/dpdk-devbind.py"
25 # PCI Device id regular expresssion
26 PCI_DEV_ID_REGEX = '[0-9A-Fa-f]+:[0-9A-Fa-f]+:[0-9A-Fa-f]+.[0-9A-Fa-f]+'
29 class VppPCIUtil(object):
36 def _create_device_list(device_string):
38 Returns a list of PCI devices
40 :param device_string: The devices string from dpdk_devbind
41 :returns: The device list
47 ids = re.findall(PCI_DEV_ID_REGEX, device_string)
48 descriptions = re.findall(r'\'([\s\S]*?)\'', device_string)
49 unused = re.findall(r'unused=\w+|unused=', device_string)
51 for i, j in enumerate(ids):
52 device = {'description': descriptions[i]}
54 device['unused'] = unused[i].split('=')[1].split(',')
56 cmd = 'ls /sys/bus/pci/devices/{}/driver/module/drivers'. \
58 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
60 device['driver'] = stdout.split(':')[1].rstrip('\n')
62 cmd = 'cat /sys/bus/pci/devices/{}/numa_node'.format(ids[i])
63 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
65 raise RuntimeError('{} failed {} {}'.
66 format(cmd, stderr, stdout))
67 numa_node = stdout.rstrip('\n')
69 device['numa_node'] = '0'
71 device['numa_node'] = numa_node
74 device['interfaces'] = []
75 cmd = 'ls /sys/bus/pci/devices/{}/net'.format(ids[i])
76 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
78 interfaces = stdout.rstrip('\n').split()
79 device['interfaces'] = interfaces
82 for intf in interfaces:
83 cmd = 'cat /sys/bus/pci/devices/{}/net/{}/address'.format(
85 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
87 raise RuntimeError('{} failed {} {}'.
88 format(cmd, stderr, stdout))
90 l2_addrs.append(stdout.rstrip('\n'))
92 device['l2addr'] = l2_addrs
94 devices[ids[i]] = device
98 def __init__(self, node):
100 self._dpdk_devices = {}
101 self._kernel_devices = {}
102 self._other_devices = {}
103 self._crypto_dpdk_devices = {}
104 self._crypto_kernel_devices = {}
105 self._crypto_other_devices = {}
106 self._link_up_devices = {}
108 def get_all_devices(self):
110 Returns a list of all the devices
115 rootdir = node['rootdir']
116 dpdk_script = rootdir + DPDK_SCRIPT
117 cmd = dpdk_script + ' --status'
118 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
120 raise RuntimeError('{} failed on node {} {}'.format(
125 # Get the network devices using the DPDK
126 # First get everything after using DPDK
127 stda = stdout.split('Network devices using DPDK-compatible driver')[1]
128 # Then get everything before using kernel driver
129 using_dpdk = stda.split('Network devices using kernel driver')[0]
130 self._dpdk_devices = self._create_device_list(using_dpdk)
132 # Get the network devices using the kernel
133 stda = stdout.split('Network devices using kernel driver')[1]
134 using_kernel = stda.split('Other network devices')[0]
135 self._kernel_devices = self._create_device_list(using_kernel)
137 # Get the other network devices
138 stda = stdout.split('Other network devices')[1]
139 other = stda.split('Crypto devices using DPDK-compatible driver')[0]
140 self._other_devices = self._create_device_list(other)
142 # Get the crypto devices using the DPDK
143 stda = stdout.split('Crypto devices using DPDK-compatible driver')[1]
144 crypto_using_dpdk = stda.split('Crypto devices using kernel driver')[0]
145 self._crypto_dpdk_devices = self._create_device_list(
148 # Get the network devices using the kernel
149 stda = stdout.split('Crypto devices using kernel driver')[1]
150 crypto_using_kernel = stda.split('Other crypto devices')[0]
151 self._crypto_kernel_devices = self._create_device_list(
154 # Get the other network devices
155 crypto_other = stdout.split('Other crypto devices')[1]
156 self._crypto_other_devices = self._create_device_list(crypto_other)
158 # Get the devices used by the kernel
159 for devk in self._kernel_devices.items():
162 for i in device['interfaces']:
163 cmd = "ip addr show " + i
164 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
166 raise RuntimeError('{} failed on node {} {}'.format(
170 lstate = re.findall(r'state \w+', stdout)[0].split(' ')[1]
172 # Take care of the links that are UP
174 device['linkup'] = True
175 self._link_up_devices[dvid] = device
177 for devl in self._link_up_devices.items():
179 del self._kernel_devices[dvid]
181 def get_dpdk_devices(self):
183 Returns a list the dpdk devices
186 return self._dpdk_devices
188 def get_kernel_devices(self):
190 Returns a list the kernel devices
193 return self._kernel_devices
195 def get_other_devices(self):
197 Returns a list the other devices
200 return self._other_devices
202 def get_crypto_dpdk_devices(self):
204 Returns a list the crypto dpdk devices
207 return self._crypto_dpdk_devices
209 def get_crypto_kernel_devices(self):
211 Returns a list the crypto kernel devices
214 return self._crypto_kernel_devices
216 def get_crypto_other_devices(self):
218 Returns a list the crypto other devices
221 return self._crypto_other_devices
223 def get_link_up_devices(self):
225 Returns a list the link up devices
228 return self._link_up_devices
231 def vpp_create_interface(interfaces, device_id, device):
233 Create an interface using the device is and device
237 name = 'port' + str(len(interfaces))
238 interfaces[name] = {}
239 interfaces[name]['pci_address'] = device_id
240 interfaces[name]['numa_node'] = device['numa_node']
241 if 'l2addr' in device:
242 l2_addrs = device['l2addr']
243 for i, j in enumerate(l2_addrs):
245 mname = 'mac_address' + str(i + 1)
246 interfaces[name][mname] = l2_addrs[i]
248 interfaces[name]['mac_address'] = l2_addrs[i]
251 def show_vpp_devices(devices, show_interfaces=True, show_header=True):
253 show the vpp devices specified in the argument
255 :param devices: A list of devices
256 :param show_interfaces: show the kernel information
257 :param show_header: Display the header if true
259 :type show_interfaces: bool
260 :type show_header: bool
264 header = "{:15} {:25} {:50}".format("PCI ID",
265 "Kernel Interface(s)",
268 header = "{:15} {:50}".format("PCI ID",
270 dashseparator = ("-" * (len(header) - 2))
272 if show_header is True:
274 print (dashseparator)
275 for dit in devices.items():
279 interfaces = device['interfaces']
281 for i, j in enumerate(interfaces):
283 interface += ',' + interfaces[i]
285 interface = interfaces[i]
287 print ("{:15} {:25} {:50}".format(
288 dvid, interface, device['description']))
290 print ("{:15} {:50}".format(
291 dvid, device['description']))
294 def unbind_vpp_device(node, device_id):
296 unbind the device specified
298 :param node: Node dictionary with cpuinfo.
299 :param device_id: The device id
301 :type device_id: string
304 rootdir = node['rootdir']
305 dpdk_script = rootdir + DPDK_SCRIPT
306 cmd = dpdk_script + ' -u ' + ' ' + device_id
307 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
309 raise RuntimeError('{} failed on node {} {} {}'.format(
314 def bind_vpp_device(node, driver, device_id):
316 bind the device specified
318 :param node: Node dictionary with cpuinfo.
319 :param driver: The driver
320 :param device_id: The device id
323 :type device_id: string
324 :returns ret: Command return code
327 rootdir = node['rootdir']
328 dpdk_script = rootdir + DPDK_SCRIPT
329 cmd = dpdk_script + ' -b ' + driver + ' ' + device_id
330 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
332 logging.error('{} failed on node {}'.format(
333 cmd, node['host'], stdout, stderr))
334 logging.error('{} {}'.format(