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