blob: 591dfab96cdce2a948500f61abd0bd799e6e8c37 [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
14"""VPP PCI Utility libraries"""
15
16import re
17
18from vpplib.VPPUtil import VPPUtil
19
20DPDK_SCRIPT = "/vpp/vpp-config/scripts/dpdk-devbind.py"
21
22# PCI Device id regular expresssion
23PCI_DEV_ID_REGEX = '[0-9A-Fa-f]+:[0-9A-Fa-f]+:[0-9A-Fa-f]+.[0-9A-Fa-f]+'
24
25
26class VppPCIUtil(object):
27 """
28 PCI Utilities
29
30 """
31
32 @staticmethod
33 def _create_device_list(device_string):
34 """
35 Returns a list of PCI devices
36
37 :param device_string: The devices string from dpdk_devbind
38 :returns: The device list
39 :rtype: dictionary
40 """
41
42 devices = {}
43
44 ids = re.findall(PCI_DEV_ID_REGEX, device_string)
45 descriptions = re.findall(r'\'([\s\S]*?)\'', device_string)
46 unused = re.findall(r'unused=[\w,]+', device_string)
47
48 for i, j in enumerate(ids):
49 device = {'description': descriptions[i]}
50 if unused:
51 device['unused'] = unused[i].split('=')[1].split(',')
52
53 cmd = 'ls /sys/bus/pci/devices/{}/driver/module/drivers'. \
54 format(ids[i])
55 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
56 if ret == 0:
57 device['driver'] = stdout.split(':')[1].rstrip('\n')
58
59 cmd = 'cat /sys/bus/pci/devices/{}/numa_node'.format(ids[i])
60 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
61 if ret != 0:
62 raise RuntimeError('{} failed {} {}'.
63 format(cmd, stderr, stdout))
64 numa_node = stdout.rstrip('\n')
65 if numa_node == '-1':
66 device['numa_node'] = '0'
67 else:
68 device['numa_node'] = numa_node
69
70 interfaces = []
71 device['interfaces'] = []
72 cmd = 'ls /sys/bus/pci/devices/{}/net'.format(ids[i])
73 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
74 if ret == 0:
75 interfaces = stdout.rstrip('\n').split()
76 device['interfaces'] = interfaces
77
78 l2_addrs = []
79 for intf in interfaces:
80 cmd = 'cat /sys/bus/pci/devices/{}/net/{}/address'.format(
81 ids[i], intf)
82 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
83 if ret != 0:
84 raise RuntimeError('{} failed {} {}'.
85 format(cmd, stderr, stdout))
86
87 l2_addrs.append(stdout.rstrip('\n'))
88
89 device['l2addr'] = l2_addrs
90
91 devices[ids[i]] = device
92
93 return devices
94
95 def __init__(self, node):
96 self._node = node
97 self._dpdk_devices = {}
98 self._kernel_devices = {}
99 self._other_devices = {}
100 self._crypto_dpdk_devices = {}
101 self._crypto_kernel_devices = {}
102 self._crypto_other_devices = {}
103 self._link_up_devices = {}
104
105 def get_all_devices(self):
106 """
107 Returns a list of all the devices
108
109 """
110
111 node = self._node
112 rootdir = node['rootdir']
113 dpdk_script = rootdir + DPDK_SCRIPT
114 cmd = dpdk_script + ' --status'
115 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
116 if ret != 0:
117 raise RuntimeError('{} failed on node {} {}'.format(
118 cmd,
119 node['host'],
120 stderr))
121
122 # Get the network devices using the DPDK
123 # First get everything after using DPDK
124 stda = stdout.split('Network devices using DPDK-compatible driver')[1]
125 # Then get everything before using kernel driver
126 using_dpdk = stda.split('Network devices using kernel driver')[0]
127 self._dpdk_devices = self._create_device_list(using_dpdk)
128
129 # Get the network devices using the kernel
130 stda = stdout.split('Network devices using kernel driver')[1]
131 using_kernel = stda.split('Other network devices')[0]
132 self._kernel_devices = self._create_device_list(using_kernel)
133
134 # Get the other network devices
135 stda = stdout.split('Other network devices')[1]
136 other = stda.split('Crypto devices using DPDK-compatible driver')[0]
137 self._other_devices = self._create_device_list(other)
138
139 # Get the crypto devices using the DPDK
140 stda = stdout.split('Crypto devices using DPDK-compatible driver')[1]
141 crypto_using_dpdk = stda.split('Crypto devices using kernel driver')[0]
142 self._crypto_dpdk_devices = self._create_device_list(
143 crypto_using_dpdk)
144
145 # Get the network devices using the kernel
146 stda = stdout.split('Crypto devices using kernel driver')[1]
147 crypto_using_kernel = stda.split('Other crypto devices')[0]
148 self._crypto_kernel_devices = self._create_device_list(
149 crypto_using_kernel)
150
151 # Get the other network devices
152 crypto_other = stdout.split('Other crypto devices')[1]
153 self._crypto_other_devices = self._create_device_list(crypto_other)
154
155 # Get the devices used by the kernel
156 for devk in self._kernel_devices.items():
157 dvid = devk[0]
158 device = devk[1]
159 for i in device['interfaces']:
160 cmd = "ip addr show " + i
161 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
162 if ret != 0:
163 raise RuntimeError('{} failed on node {} {}'.format(
164 cmd,
165 node['host'],
166 stderr))
167 lstate = re.findall(r'state \w+', stdout)[0].split(' ')[1]
168
169 # Take care of the links that are UP
170 if lstate == 'UP':
171 device['linkup'] = True
172 self._link_up_devices[dvid] = device
173
174 for devl in self._link_up_devices.items():
175 dvid = devl[0]
176 del self._kernel_devices[dvid]
177
178 def get_dpdk_devices(self):
179 """
180 Returns a list the dpdk devices
181
182 """
183 return self._dpdk_devices
184
185 def get_kernel_devices(self):
186 """
187 Returns a list the kernel devices
188
189 """
190 return self._kernel_devices
191
192 def get_other_devices(self):
193 """
194 Returns a list the other devices
195
196 """
197 return self._other_devices
198
199 def get_crypto_dpdk_devices(self):
200 """
201 Returns a list the crypto dpdk devices
202
203 """
204 return self._crypto_dpdk_devices
205
206 def get_crypto_kernel_devices(self):
207 """
208 Returns a list the crypto kernel devices
209
210 """
211 return self._crypto_kernel_devices
212
213 def get_crypto_other_devices(self):
214 """
215 Returns a list the crypto other devices
216
217 """
218 return self._crypto_other_devices
219
220 def get_link_up_devices(self):
221 """
222 Returns a list the link up devices
223
224 """
225 return self._link_up_devices
226
227 @staticmethod
228 def vpp_create_interface(interfaces, device_id, device):
229 """
230 Create an interface using the device is and device
231
232 """
233
234 name = 'port' + str(len(interfaces))
235 interfaces[name] = {}
236 interfaces[name]['pci_address'] = device_id
237 interfaces[name]['numa_node'] = device['numa_node']
238 if 'l2addr' in device:
239 l2_addrs = device['l2addr']
240 for i, j in enumerate(l2_addrs):
241 if i > 0:
242 mname = 'mac_address' + str(i + 1)
243 interfaces[name][mname] = l2_addrs[i]
244 else:
245 interfaces[name]['mac_address'] = l2_addrs[i]
246
247 @staticmethod
248 def show_vpp_devices(devices, show_interfaces=True, show_header=True):
249 """
250 show the vpp devices specified in the argument
251
252 :param devices: A list of devices
253 :param show_interfaces: show the kernel information
John DeNiscoc6b2a202017-11-01 12:37:47 -0400254 :param show_header: Display the header if true
John DeNisco68b0ee32017-09-27 16:35:23 -0400255 :type devices: dict
256 :type show_interfaces: bool
John DeNiscoc6b2a202017-11-01 12:37:47 -0400257 :type show_header: bool
John DeNisco68b0ee32017-09-27 16:35:23 -0400258 """
259
John DeNisco68b0ee32017-09-27 16:35:23 -0400260 if show_interfaces:
261 header = "{:15} {:25} {:50}".format("PCI ID",
262 "Kernel Interface(s)",
263 "Description")
264 else:
265 header = "{:15} {:50}".format("PCI ID",
266 "Description")
267 dashseparator = ("-" * (len(header) - 2))
268
John DeNiscoc6b2a202017-11-01 12:37:47 -0400269 if show_header is True:
John DeNisco68b0ee32017-09-27 16:35:23 -0400270 print header
271 print dashseparator
272 for dit in devices.items():
273 dvid = dit[0]
274 device = dit[1]
275 if show_interfaces:
276 interfaces = device['interfaces']
277 interface = ''
278 for i, j in enumerate(interfaces):
279 if i > 0:
280 interface += ',' + interfaces[i]
281 else:
282 interface = interfaces[i]
283
284 print "{:15} {:25} {:50}".format(
285 dvid, interface, device['description'])
286 else:
287 print "{:15} {:50}".format(
288 dvid, device['description'])
289
290 @staticmethod
291 def unbind_vpp_device(node, device_id):
292 """
293 unbind the device specified
294
295 :param node: Node dictionary with cpuinfo.
296 :param device_id: The device id
297 :type node: dict
298 :type device_id: string
299 """
300
John DeNisco68b0ee32017-09-27 16:35:23 -0400301 rootdir = node['rootdir']
302 dpdk_script = rootdir + DPDK_SCRIPT
303 cmd = dpdk_script + ' -u ' + ' ' + device_id
304 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
305 if ret != 0:
306 raise RuntimeError('{} failed on node {} {} {}'.format(
307 cmd, node['host'],
308 stdout, stderr))
309
310 @staticmethod
311 def bind_vpp_device(node, driver, device_id):
312 """
313 bind the device specified
314
315 :param node: Node dictionary with cpuinfo.
316 :param driver: The driver
317 :param device_id: The device id
318 :type node: dict
319 :type driver: string
320 :type device_id: string
321 """
322
323 rootdir = node['rootdir']
324 dpdk_script = rootdir + DPDK_SCRIPT
325 cmd = dpdk_script + ' -b ' + driver + ' ' + device_id
326 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
327 if ret != 0:
328 raise RuntimeError('{} failed on node {} {} {}'.format(
329 cmd, node['host'], stdout, stderr))