blob: 032a262c21c11040061d4e60ddc61fa2e792bf2f [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
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020026PCI_DEV_ID_REGEX = "[0-9A-Fa-f]+:[0-9A-Fa-f]+:[0-9A-Fa-f]+.[0-9A-Fa-f]+"
John DeNisco68b0ee32017-09-27 16:35:23 -040027
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)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020048 descriptions = re.findall(r"\'([\s\S]*?)\'", device_string)
49 unused = re.findall(r"unused=\w+|unused=", device_string)
John DeNisco68b0ee32017-09-27 16:35:23 -040050
51 for i, j in enumerate(ids):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020052 device = {"description": descriptions[i]}
John DeNisco68b0ee32017-09-27 16:35:23 -040053 if unused:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020054 device["unused"] = unused[i].split("=")[1].split(",")
John DeNisco68b0ee32017-09-27 16:35:23 -040055
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020056 cmd = "ls /sys/bus/pci/devices/{}/driver/module/drivers".format(ids[i])
John DeNisco68b0ee32017-09-27 16:35:23 -040057 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
58 if ret == 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020059 device["driver"] = stdout.split(":")[1].rstrip("\n")
John DeNisco68b0ee32017-09-27 16:35:23 -040060
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020061 cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(ids[i])
John DeNisco68b0ee32017-09-27 16:35:23 -040062 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
63 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020064 raise RuntimeError("{} failed {} {}".format(cmd, stderr, stdout))
65 numa_node = stdout.rstrip("\n")
66 if numa_node == "-1":
67 device["numa_node"] = "0"
John DeNisco68b0ee32017-09-27 16:35:23 -040068 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020069 device["numa_node"] = numa_node
John DeNisco68b0ee32017-09-27 16:35:23 -040070
71 interfaces = []
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020072 device["interfaces"] = []
73 cmd = "ls /sys/bus/pci/devices/{}/net".format(ids[i])
John DeNisco68b0ee32017-09-27 16:35:23 -040074 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
75 if ret == 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020076 interfaces = stdout.rstrip("\n").split()
77 device["interfaces"] = interfaces
John DeNisco68b0ee32017-09-27 16:35:23 -040078
79 l2_addrs = []
80 for intf in interfaces:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020081 cmd = "cat /sys/bus/pci/devices/{}/net/{}/address".format(ids[i], intf)
John DeNisco68b0ee32017-09-27 16:35:23 -040082 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
83 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020084 raise RuntimeError("{} failed {} {}".format(cmd, stderr, stdout))
John DeNisco68b0ee32017-09-27 16:35:23 -040085
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020086 l2_addrs.append(stdout.rstrip("\n"))
John DeNisco68b0ee32017-09-27 16:35:23 -040087
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020088 device["l2addr"] = l2_addrs
John DeNisco68b0ee32017-09-27 16:35:23 -040089
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
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200111 rootdir = node["rootdir"]
John DeNisco68b0ee32017-09-27 16:35:23 -0400112 dpdk_script = rootdir + DPDK_SCRIPT
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200113 cmd = dpdk_script + " --status"
John DeNisco68b0ee32017-09-27 16:35:23 -0400114 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
115 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200116 raise RuntimeError(
117 "{} failed on node {} {}".format(cmd, node["host"], stderr)
118 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400119
120 # Get the network devices using the DPDK
121 # First get everything after using DPDK
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200122 stda = stdout.split("Network devices using DPDK-compatible driver")[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400123 # Then get everything before using kernel driver
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200124 using_dpdk = stda.split("Network devices using kernel driver")[0]
John DeNisco68b0ee32017-09-27 16:35:23 -0400125 self._dpdk_devices = self._create_device_list(using_dpdk)
126
127 # Get the network devices using the kernel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200128 stda = stdout.split("Network devices using kernel driver")[1]
129 using_kernel = stda.split("Other network devices")[0]
John DeNisco68b0ee32017-09-27 16:35:23 -0400130 self._kernel_devices = self._create_device_list(using_kernel)
131
132 # Get the other network devices
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200133 stda = stdout.split("Other network devices")[1]
134 other = stda.split("Crypto devices using DPDK-compatible driver")[0]
John DeNisco68b0ee32017-09-27 16:35:23 -0400135 self._other_devices = self._create_device_list(other)
136
137 # Get the crypto devices using the DPDK
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200138 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)
John DeNisco68b0ee32017-09-27 16:35:23 -0400141
142 # Get the network devices using the kernel
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200143 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)
John DeNisco68b0ee32017-09-27 16:35:23 -0400146
147 # Get the other network devices
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200148 crypto_other = stdout.split("Other crypto devices")[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400149 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]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200155 for i in device["interfaces"]:
John DeNisco68b0ee32017-09-27 16:35:23 -0400156 cmd = "ip addr show " + i
157 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
158 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200159 raise RuntimeError(
160 "{} failed on node {} {}".format(cmd, node["host"], stderr)
161 )
162 lstate = re.findall(r"state \w+", stdout)[0].split(" ")[1]
John DeNisco68b0ee32017-09-27 16:35:23 -0400163
164 # Take care of the links that are UP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200165 if lstate == "UP":
166 device["linkup"] = True
John DeNisco68b0ee32017-09-27 16:35:23 -0400167 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
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200229 name = "port" + str(len(interfaces))
John DeNisco68b0ee32017-09-27 16:35:23 -0400230 interfaces[name] = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200231 interfaces[name]["pci_address"] = device_id
232 interfaces[name]["numa_node"] = device["numa_node"]
233 if "l2addr" in device:
234 l2_addrs = device["l2addr"]
John DeNisco68b0ee32017-09-27 16:35:23 -0400235 for i, j in enumerate(l2_addrs):
236 if i > 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200237 mname = "mac_address" + str(i + 1)
John DeNisco68b0ee32017-09-27 16:35:23 -0400238 interfaces[name][mname] = l2_addrs[i]
239 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200240 interfaces[name]["mac_address"] = l2_addrs[i]
John DeNisco68b0ee32017-09-27 16:35:23 -0400241
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
John DeNiscoc6b2a202017-11-01 12:37:47 -0400249 :param show_header: Display the header if true
John DeNisco68b0ee32017-09-27 16:35:23 -0400250 :type devices: dict
251 :type show_interfaces: bool
John DeNiscoc6b2a202017-11-01 12:37:47 -0400252 :type show_header: bool
John DeNisco68b0ee32017-09-27 16:35:23 -0400253 """
254
John DeNisco68b0ee32017-09-27 16:35:23 -0400255 if show_interfaces:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200256 header = "{:15} {:25} {:50}".format(
257 "PCI ID", "Kernel Interface(s)", "Description"
258 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400259 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200260 header = "{:15} {:50}".format("PCI ID", "Description")
261 dashseparator = "-" * (len(header) - 2)
John DeNisco68b0ee32017-09-27 16:35:23 -0400262
John DeNiscoc6b2a202017-11-01 12:37:47 -0400263 if show_header is True:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200264 print(header)
265 print(dashseparator)
John DeNisco68b0ee32017-09-27 16:35:23 -0400266 for dit in devices.items():
267 dvid = dit[0]
268 device = dit[1]
269 if show_interfaces:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200270 interfaces = device["interfaces"]
271 interface = ""
John DeNisco68b0ee32017-09-27 16:35:23 -0400272 for i, j in enumerate(interfaces):
273 if i > 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200274 interface += "," + interfaces[i]
John DeNisco68b0ee32017-09-27 16:35:23 -0400275 else:
276 interface = interfaces[i]
277
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200278 print(
279 "{:15} {:25} {:50}".format(dvid, interface, device["description"])
280 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400281 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200282 print("{:15} {:50}".format(dvid, device["description"]))
John DeNisco68b0ee32017-09-27 16:35:23 -0400283
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
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200295 rootdir = node["rootdir"]
John DeNisco68b0ee32017-09-27 16:35:23 -0400296 dpdk_script = rootdir + DPDK_SCRIPT
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200297 cmd = dpdk_script + " -u " + " " + device_id
John DeNisco68b0ee32017-09-27 16:35:23 -0400298 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
299 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200300 raise RuntimeError(
301 "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
302 )
John DeNisco68b0ee32017-09-27 16:35:23 -0400303
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
jdenisco7c37a672018-11-20 11:25:17 -0500315 :returns ret: Command return code
John DeNisco68b0ee32017-09-27 16:35:23 -0400316 """
317
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200318 rootdir = node["rootdir"]
John DeNisco68b0ee32017-09-27 16:35:23 -0400319 dpdk_script = rootdir + DPDK_SCRIPT
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200320 cmd = dpdk_script + " -b " + driver + " " + device_id
John DeNisco68b0ee32017-09-27 16:35:23 -0400321 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
322 if ret != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200323 logging.error(
324 "{} failed on node {}".format(cmd, node["host"], stdout, stderr)
325 )
326 logging.error("{} {}".format(stdout, stderr))
jdenisco7c37a672018-11-20 11:25:17 -0500327
328 return ret