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".format(ids[i])
57 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
59 device["driver"] = stdout.split(":")[1].rstrip("\n")
61 cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(ids[i])
62 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
64 raise RuntimeError("{} failed {} {}".format(cmd, stderr, stdout))
65 numa_node = stdout.rstrip("\n")
67 device["numa_node"] = "0"
69 device["numa_node"] = numa_node
72 device["interfaces"] = []
73 cmd = "ls /sys/bus/pci/devices/{}/net".format(ids[i])
74 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
76 interfaces = stdout.rstrip("\n").split()
77 device["interfaces"] = interfaces
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)
84 raise RuntimeError("{} failed {} {}".format(cmd, stderr, stdout))
86 l2_addrs.append(stdout.rstrip("\n"))
88 device["l2addr"] = l2_addrs
90 devices[ids[i]] = device
94 def __init__(self, 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 = {}
104 def get_all_devices(self):
106 Returns a list of all the devices
111 rootdir = node["rootdir"]
112 dpdk_script = rootdir + DPDK_SCRIPT
113 cmd = dpdk_script + " --status"
114 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
117 "{} failed on node {} {}".format(cmd, node["host"], stderr)
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)
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)
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)
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)
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)
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)
151 # Get the devices used by the kernel
152 for devk in self._kernel_devices.items():
155 for i in device["interfaces"]:
156 cmd = "ip addr show " + i
157 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
160 "{} failed on node {} {}".format(cmd, node["host"], stderr)
162 lstate = re.findall(r"state \w+", stdout)[0].split(" ")[1]
164 # Take care of the links that are UP
166 device["linkup"] = True
167 self._link_up_devices[dvid] = device
169 for devl in self._link_up_devices.items():
171 del self._kernel_devices[dvid]
173 def get_dpdk_devices(self):
175 Returns a list the dpdk devices
178 return self._dpdk_devices
180 def get_kernel_devices(self):
182 Returns a list the kernel devices
185 return self._kernel_devices
187 def get_other_devices(self):
189 Returns a list the other devices
192 return self._other_devices
194 def get_crypto_dpdk_devices(self):
196 Returns a list the crypto dpdk devices
199 return self._crypto_dpdk_devices
201 def get_crypto_kernel_devices(self):
203 Returns a list the crypto kernel devices
206 return self._crypto_kernel_devices
208 def get_crypto_other_devices(self):
210 Returns a list the crypto other devices
213 return self._crypto_other_devices
215 def get_link_up_devices(self):
217 Returns a list the link up devices
220 return self._link_up_devices
223 def vpp_create_interface(interfaces, device_id, device):
225 Create an interface using the device is and device
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):
237 mname = "mac_address" + str(i + 1)
238 interfaces[name][mname] = l2_addrs[i]
240 interfaces[name]["mac_address"] = l2_addrs[i]
243 def show_vpp_devices(devices, show_interfaces=True, show_header=True):
245 show the vpp devices specified in the argument
247 :param devices: A list of devices
248 :param show_interfaces: show the kernel information
249 :param show_header: Display the header if true
251 :type show_interfaces: bool
252 :type show_header: bool
256 header = "{:15} {:25} {:50}".format(
257 "PCI ID", "Kernel Interface(s)", "Description"
260 header = "{:15} {:50}".format("PCI ID", "Description")
261 dashseparator = "-" * (len(header) - 2)
263 if show_header is True:
266 for dit in devices.items():
270 interfaces = device["interfaces"]
272 for i, j in enumerate(interfaces):
274 interface += "," + interfaces[i]
276 interface = interfaces[i]
279 "{:15} {:25} {:50}".format(dvid, interface, device["description"])
282 print("{:15} {:50}".format(dvid, device["description"]))
285 def unbind_vpp_device(node, device_id):
287 unbind the device specified
289 :param node: Node dictionary with cpuinfo.
290 :param device_id: The device id
292 :type device_id: string
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)
301 "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr)
305 def bind_vpp_device(node, driver, device_id):
307 bind the device specified
309 :param node: Node dictionary with cpuinfo.
310 :param driver: The driver
311 :param device_id: The device id
314 :type device_id: string
315 :returns ret: Command return code
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)
324 "{} failed on node {}".format(cmd, node["host"], stdout, stderr)
326 logging.error("{} {}".format(stdout, stderr))