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 """VPP PCI Utility libraries"""
19 from vpplib.VPPUtil import VPPUtil
21 DPDK_SCRIPT = "/vpp/vpp-config/scripts/dpdk-devbind.py"
23 # PCI Device id regular expresssion
24 PCI_DEV_ID_REGEX = '[0-9A-Fa-f]+:[0-9A-Fa-f]+:[0-9A-Fa-f]+.[0-9A-Fa-f]+'
27 class VppPCIUtil(object):
34 def _create_device_list(device_string):
36 Returns a list of PCI devices
38 :param device_string: The devices string from dpdk_devbind
39 :returns: The device list
45 ids = re.findall(PCI_DEV_ID_REGEX, device_string)
46 descriptions = re.findall(r'\'([\s\S]*?)\'', device_string)
47 unused = re.findall(r'unused=[\w,]+', device_string)
49 for i, j in enumerate(ids):
50 device = {'description': descriptions[i]}
52 device['unused'] = unused[i].split('=')[1].split(',')
54 cmd = 'ls /sys/bus/pci/devices/{}/driver/module/drivers'. \
56 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
58 device['driver'] = stdout.split(':')[1].rstrip('\n')
60 cmd = 'cat /sys/bus/pci/devices/{}/numa_node'.format(ids[i])
61 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
63 raise RuntimeError('{} failed {} {}'.
64 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(
83 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
85 raise RuntimeError('{} failed {} {}'.
86 format(cmd, stderr, stdout))
88 l2_addrs.append(stdout.rstrip('\n'))
90 device['l2addr'] = l2_addrs
92 devices[ids[i]] = device
96 def __init__(self, node):
98 self._dpdk_devices = {}
99 self._kernel_devices = {}
100 self._other_devices = {}
101 self._crypto_dpdk_devices = {}
102 self._crypto_kernel_devices = {}
103 self._crypto_other_devices = {}
104 self._link_up_devices = {}
106 def get_all_devices(self):
108 Returns a list of all the devices
113 rootdir = node['rootdir']
114 dpdk_script = rootdir + DPDK_SCRIPT
115 cmd = dpdk_script + ' --status'
116 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
118 raise RuntimeError('{} failed on node {} {}'.format(
123 # Get the network devices using the DPDK
124 # First get everything after using DPDK
125 stda = stdout.split('Network devices using DPDK-compatible driver')[1]
126 # Then get everything before using kernel driver
127 using_dpdk = stda.split('Network devices using kernel driver')[0]
128 self._dpdk_devices = self._create_device_list(using_dpdk)
130 # Get the network devices using the kernel
131 stda = stdout.split('Network devices using kernel driver')[1]
132 using_kernel = stda.split('Other network devices')[0]
133 self._kernel_devices = self._create_device_list(using_kernel)
135 # Get the other network devices
136 stda = stdout.split('Other network devices')[1]
137 other = stda.split('Crypto devices using DPDK-compatible driver')[0]
138 self._other_devices = self._create_device_list(other)
140 # Get the crypto devices using the DPDK
141 stda = stdout.split('Crypto devices using DPDK-compatible driver')[1]
142 crypto_using_dpdk = stda.split('Crypto devices using kernel driver')[0]
143 self._crypto_dpdk_devices = self._create_device_list(
146 # Get the network devices using the kernel
147 stda = stdout.split('Crypto devices using kernel driver')[1]
148 crypto_using_kernel = stda.split('Other crypto devices')[0]
149 self._crypto_kernel_devices = self._create_device_list(
152 # Get the other network devices
153 crypto_other = stdout.split('Other crypto devices')[1]
154 self._crypto_other_devices = self._create_device_list(crypto_other)
156 # Get the devices used by the kernel
157 for devk in self._kernel_devices.items():
160 for i in device['interfaces']:
161 cmd = "ip addr show " + i
162 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
164 raise RuntimeError('{} failed on node {} {}'.format(
168 lstate = re.findall(r'state \w+', stdout)[0].split(' ')[1]
170 # Take care of the links that are UP
172 device['linkup'] = True
173 self._link_up_devices[dvid] = device
175 for devl in self._link_up_devices.items():
177 del self._kernel_devices[dvid]
179 def get_dpdk_devices(self):
181 Returns a list the dpdk devices
184 return self._dpdk_devices
186 def get_kernel_devices(self):
188 Returns a list the kernel devices
191 return self._kernel_devices
193 def get_other_devices(self):
195 Returns a list the other devices
198 return self._other_devices
200 def get_crypto_dpdk_devices(self):
202 Returns a list the crypto dpdk devices
205 return self._crypto_dpdk_devices
207 def get_crypto_kernel_devices(self):
209 Returns a list the crypto kernel devices
212 return self._crypto_kernel_devices
214 def get_crypto_other_devices(self):
216 Returns a list the crypto other devices
219 return self._crypto_other_devices
221 def get_link_up_devices(self):
223 Returns a list the link up devices
226 return self._link_up_devices
229 def vpp_create_interface(interfaces, device_id, device):
231 Create an interface using the device is and device
235 name = 'port' + str(len(interfaces))
236 interfaces[name] = {}
237 interfaces[name]['pci_address'] = device_id
238 interfaces[name]['numa_node'] = device['numa_node']
239 if 'l2addr' in device:
240 l2_addrs = device['l2addr']
241 for i, j in enumerate(l2_addrs):
243 mname = 'mac_address' + str(i + 1)
244 interfaces[name][mname] = l2_addrs[i]
246 interfaces[name]['mac_address'] = l2_addrs[i]
249 def show_vpp_devices(devices, show_interfaces=True, show_header=True):
251 show the vpp devices specified in the argument
253 :param devices: A list of devices
254 :param show_interfaces: show the kernel information
255 :param show_header: Display the header if true
257 :type show_interfaces: bool
258 :type show_header: bool
262 header = "{:15} {:25} {:50}".format("PCI ID",
263 "Kernel Interface(s)",
266 header = "{:15} {:50}".format("PCI ID",
268 dashseparator = ("-" * (len(header) - 2))
270 if show_header is True:
273 for dit in devices.items():
277 interfaces = device['interfaces']
279 for i, j in enumerate(interfaces):
281 interface += ',' + interfaces[i]
283 interface = interfaces[i]
285 print "{:15} {:25} {:50}".format(
286 dvid, interface, device['description'])
288 print "{:15} {:50}".format(
289 dvid, device['description'])
292 def unbind_vpp_device(node, device_id):
294 unbind the device specified
296 :param node: Node dictionary with cpuinfo.
297 :param device_id: The device id
299 :type device_id: string
302 rootdir = node['rootdir']
303 dpdk_script = rootdir + DPDK_SCRIPT
304 cmd = dpdk_script + ' -u ' + ' ' + device_id
305 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
307 raise RuntimeError('{} failed on node {} {} {}'.format(
312 def bind_vpp_device(node, driver, device_id):
314 bind the device specified
316 :param node: Node dictionary with cpuinfo.
317 :param driver: The driver
318 :param device_id: The device id
321 :type device_id: string
322 :returns ret: Command return code
325 rootdir = node['rootdir']
326 dpdk_script = rootdir + DPDK_SCRIPT
327 cmd = dpdk_script + ' -b ' + driver + ' ' + device_id
328 (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
330 logging.error('{} failed on node {}'.format(
331 cmd, node['host'], stdout, stderr))
332 logging.error('{} {}'.format(