blob: ceda46f97b9e5bef67de0a5905d36d1755ca49dc [file] [log] [blame]
John DeNisco68b0ee32017-09-27 16:35:23 -04001# 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:
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
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.
13
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -080014from __future__ import print_function
15
John DeNisco68b0ee32017-09-27 16:35:23 -040016"""VPP PCI Utility libraries"""
17
18import re
jdenisco7c37a672018-11-20 11:25:17 -050019import logging
John DeNisco68b0ee32017-09-27 16:35:23 -040020
21from vpplib.VPPUtil import VPPUtil
22
23DPDK_SCRIPT = "/vpp/vpp-config/scripts/dpdk-devbind.py"
24
25# PCI Device id regular expresssion
26PCI_DEV_ID_REGEX = '[0-9A-Fa-f]+:[0-9A-Fa-f]+:[0-9A-Fa-f]+.[0-9A-Fa-f]+'
27
28
29class VppPCIUtil(object):
30 """
31 PCI Utilities
32
33 """
34
35 @staticmethod
36 def _create_device_list(device_string):
37 """
38 Returns a list of PCI devices
39
40 :param device_string: The devices string from dpdk_devbind
41 :returns: The device list
42 :rtype: dictionary
43 """
44
45 devices = {}
46
47 ids = re.findall(PCI_DEV_ID_REGEX, device_string)
48 descriptions = re.findall(r'\'([\s\S]*?)\'', device_string)
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -080049 unused = re.findall(r'unused=\w+|unused=', device_string)
John DeNisco68b0ee32017-09-27 16:35:23 -040050
51 for i, j in enumerate(ids):
52 device = {'description': descriptions[i]}
53 if unused:
54 device['unused'] = unused[i].split('=')[1].split(',')
55
56 cmd = 'ls /sys/bus/pci/devices/{}/driver/module/drivers'. \
57 format(ids[i])
58 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
59 if ret == 0:
60 device['driver'] = stdout.split(':')[1].rstrip('\n')
61
62 cmd = 'cat /sys/bus/pci/devices/{}/numa_node'.format(ids[i])
63 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
64 if ret != 0:
65 raise RuntimeError('{} failed {} {}'.
66 format(cmd, stderr, stdout))
67 numa_node = stdout.rstrip('\n')
68 if numa_node == '-1':
69 device['numa_node'] = '0'
70 else:
71 device['numa_node'] = numa_node
72
73 interfaces = []
74 device['interfaces'] = []
75 cmd = 'ls /sys/bus/pci/devices/{}/net'.format(ids[i])
76 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
77 if ret == 0:
78 interfaces = stdout.rstrip('\n').split()
79 device['interfaces'] = interfaces
80
81 l2_addrs = []
82 for intf in interfaces:
83 cmd = 'cat /sys/bus/pci/devices/{}/net/{}/address'.format(
84 ids[i], intf)
85 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
86 if ret != 0:
87 raise RuntimeError('{} failed {} {}'.
88 format(cmd, stderr, stdout))
89
90 l2_addrs.append(stdout.rstrip('\n'))
91
92 device['l2addr'] = l2_addrs
93
94 devices[ids[i]] = device
95
96 return devices
97
98 def __init__(self, node):
99 self._node = 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 = {}
107
108 def get_all_devices(self):
109 """
110 Returns a list of all the devices
111
112 """
113
114 node = self._node
115 rootdir = node['rootdir']
116 dpdk_script = rootdir + DPDK_SCRIPT
117 cmd = dpdk_script + ' --status'
118 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
119 if ret != 0:
120 raise RuntimeError('{} failed on node {} {}'.format(
121 cmd,
122 node['host'],
123 stderr))
124
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)
131
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)
136
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)
141
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(
146 crypto_using_dpdk)
147
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(
152 crypto_using_kernel)
153
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)
157
158 # Get the devices used by the kernel
159 for devk in self._kernel_devices.items():
160 dvid = devk[0]
161 device = devk[1]
162 for i in device['interfaces']:
163 cmd = "ip addr show " + i
164 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
165 if ret != 0:
166 raise RuntimeError('{} failed on node {} {}'.format(
167 cmd,
168 node['host'],
169 stderr))
170 lstate = re.findall(r'state \w+', stdout)[0].split(' ')[1]
171
172 # Take care of the links that are UP
173 if lstate == 'UP':
174 device['linkup'] = True
175 self._link_up_devices[dvid] = device
176
177 for devl in self._link_up_devices.items():
178 dvid = devl[0]
179 del self._kernel_devices[dvid]
180
181 def get_dpdk_devices(self):
182 """
183 Returns a list the dpdk devices
184
185 """
186 return self._dpdk_devices
187
188 def get_kernel_devices(self):
189 """
190 Returns a list the kernel devices
191
192 """
193 return self._kernel_devices
194
195 def get_other_devices(self):
196 """
197 Returns a list the other devices
198
199 """
200 return self._other_devices
201
202 def get_crypto_dpdk_devices(self):
203 """
204 Returns a list the crypto dpdk devices
205
206 """
207 return self._crypto_dpdk_devices
208
209 def get_crypto_kernel_devices(self):
210 """
211 Returns a list the crypto kernel devices
212
213 """
214 return self._crypto_kernel_devices
215
216 def get_crypto_other_devices(self):
217 """
218 Returns a list the crypto other devices
219
220 """
221 return self._crypto_other_devices
222
223 def get_link_up_devices(self):
224 """
225 Returns a list the link up devices
226
227 """
228 return self._link_up_devices
229
230 @staticmethod
231 def vpp_create_interface(interfaces, device_id, device):
232 """
233 Create an interface using the device is and device
234
235 """
236
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):
244 if i > 0:
245 mname = 'mac_address' + str(i + 1)
246 interfaces[name][mname] = l2_addrs[i]
247 else:
248 interfaces[name]['mac_address'] = l2_addrs[i]
249
250 @staticmethod
251 def show_vpp_devices(devices, show_interfaces=True, show_header=True):
252 """
253 show the vpp devices specified in the argument
254
255 :param devices: A list of devices
256 :param show_interfaces: show the kernel information
John DeNiscoc6b2a202017-11-01 12:37:47 -0400257 :param show_header: Display the header if true
John DeNisco68b0ee32017-09-27 16:35:23 -0400258 :type devices: dict
259 :type show_interfaces: bool
John DeNiscoc6b2a202017-11-01 12:37:47 -0400260 :type show_header: bool
John DeNisco68b0ee32017-09-27 16:35:23 -0400261 """
262
John DeNisco68b0ee32017-09-27 16:35:23 -0400263 if show_interfaces:
264 header = "{:15} {:25} {:50}".format("PCI ID",
265 "Kernel Interface(s)",
266 "Description")
267 else:
268 header = "{:15} {:50}".format("PCI ID",
269 "Description")
270 dashseparator = ("-" * (len(header) - 2))
271
John DeNiscoc6b2a202017-11-01 12:37:47 -0400272 if show_header is True:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800273 print (header)
274 print (dashseparator)
John DeNisco68b0ee32017-09-27 16:35:23 -0400275 for dit in devices.items():
276 dvid = dit[0]
277 device = dit[1]
278 if show_interfaces:
279 interfaces = device['interfaces']
280 interface = ''
281 for i, j in enumerate(interfaces):
282 if i > 0:
283 interface += ',' + interfaces[i]
284 else:
285 interface = interfaces[i]
286
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800287 print ("{:15} {:25} {:50}".format(
288 dvid, interface, device['description']))
John DeNisco68b0ee32017-09-27 16:35:23 -0400289 else:
Paul Vinciguerra339bc6b2018-12-19 02:05:25 -0800290 print ("{:15} {:50}".format(
291 dvid, device['description']))
John DeNisco68b0ee32017-09-27 16:35:23 -0400292
293 @staticmethod
294 def unbind_vpp_device(node, device_id):
295 """
296 unbind the device specified
297
298 :param node: Node dictionary with cpuinfo.
299 :param device_id: The device id
300 :type node: dict
301 :type device_id: string
302 """
303
John DeNisco68b0ee32017-09-27 16:35:23 -0400304 rootdir = node['rootdir']
305 dpdk_script = rootdir + DPDK_SCRIPT
306 cmd = dpdk_script + ' -u ' + ' ' + device_id
307 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
308 if ret != 0:
309 raise RuntimeError('{} failed on node {} {} {}'.format(
310 cmd, node['host'],
311 stdout, stderr))
312
313 @staticmethod
314 def bind_vpp_device(node, driver, device_id):
315 """
316 bind the device specified
317
318 :param node: Node dictionary with cpuinfo.
319 :param driver: The driver
320 :param device_id: The device id
321 :type node: dict
322 :type driver: string
323 :type device_id: string
jdenisco7c37a672018-11-20 11:25:17 -0500324 :returns ret: Command return code
John DeNisco68b0ee32017-09-27 16:35:23 -0400325 """
326
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)
331 if ret != 0:
jdenisco7c37a672018-11-20 11:25:17 -0500332 logging.error('{} failed on node {}'.format(
John DeNisco68b0ee32017-09-27 16:35:23 -0400333 cmd, node['host'], stdout, stderr))
jdenisco7c37a672018-11-20 11:25:17 -0500334 logging.error('{} {}'.format(
335 stdout, stderr))
336
337 return ret