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 """DUT setup library."""
16 from robot.api import logger
18 from resources.libraries.python.topology import NodeType, Topology
19 from resources.libraries.python.ssh import SSH
20 from resources.libraries.python.constants import Constants
21 from resources.libraries.python.VatExecutor import VatExecutor
22 from resources.libraries.python.VPPUtil import VPPUtil
25 class DUTSetup(object):
26 """Contains methods for setting up DUTs."""
28 def start_vpp_service_on_all_duts(nodes):
29 """Start up the VPP service on all nodes."""
31 for node in nodes.values():
32 if node['type'] == NodeType.DUT:
34 (ret_code, stdout, stderr) = \
35 ssh.exec_command_sudo('service vpp restart', timeout=120)
36 if int(ret_code) != 0:
37 logger.debug('stdout: {0}'.format(stdout))
38 logger.debug('stderr: {0}'.format(stderr))
39 raise Exception('DUT {0} failed to start VPP service'.
43 def vpp_show_version_verbose(node):
44 """Run "show version verbose" CLI command.
46 :param node: Node to run command on.
50 vat.execute_script("show_version_verbose.vat", node, json_out=False)
53 def show_vpp_version_on_all_duts(nodes):
54 """Show VPP version verbose on all DUTs.
56 :param nodes: VPP nodes
59 for node in nodes.values():
60 if node['type'] == NodeType.DUT:
61 DUTSetup.vpp_show_version_verbose(node)
64 def vpp_api_trace_save(node):
65 """Run "api trace save" CLI command.
67 :param node: Node to run command on.
71 vat.execute_script("api_trace_save.vat", node, json_out=False)
74 def vpp_api_trace_dump(node):
75 """Run "api trace custom-dump" CLI command.
77 :param node: Node to run command on.
81 vat.execute_script("api_trace_dump.vat", node, json_out=False)
84 def setup_all_duts(nodes):
85 """Prepare all DUTs in given topology for test execution."""
86 for node in nodes.values():
87 if node['type'] == NodeType.DUT:
88 DUTSetup.setup_dut(node)
92 """Run script over SSH to setup the DUT node.
94 :param node: DUT node to set up.
97 :raises Exception: If the DUT setup fails.
102 (ret_code, stdout, stderr) = \
103 ssh.exec_command('sudo -Sn bash {0}/{1}/dut_setup.sh'.
104 format(Constants.REMOTE_FW_DIR,
105 Constants.RESOURCES_LIB_SH), timeout=120)
108 if int(ret_code) != 0:
109 logger.debug('DUT {0} setup script failed: "{1}"'.
110 format(node['host'], stdout + stderr))
111 raise Exception('DUT test setup script failed at node {}'.
112 format(node['host']))
115 def get_vpp_pid(node):
116 """Get PID of running VPP process.
118 :param node: DUT node.
122 :raises RuntimeError if it is not possible to get the PID.
129 logger.trace('Try {}: Get VPP PID'.format(i))
130 ret_code, stdout, stderr = ssh.exec_command('pidof vpp')
132 if int(ret_code) != 0:
133 raise RuntimeError('Not possible to get PID of VPP process '
134 'on node: {0}\n {1}'.
135 format(node['host'], stdout + stderr))
137 if len(stdout.splitlines()) == 1:
139 elif len(stdout.splitlines()) == 0:
140 logger.debug("No VPP PID found on node {0}".
141 format(node['host']))
144 logger.debug("More then one VPP PID found on node {0}".
145 format(node['host']))
147 for line in stdout.splitlines():
148 ret_list.append(int(line))
154 def get_vpp_pids(nodes):
155 """Get PID of running VPP process on all DUTs.
157 :param nodes: DUT nodes.
164 for node in nodes.values():
165 if node['type'] == NodeType.DUT:
166 pids[node['host']] = DUTSetup.get_vpp_pid(node)
170 def vpp_show_crypto_device_mapping(node):
171 """Run "show crypto device mapping" CLI command.
173 :param node: Node to run command on.
177 vat.execute_script("show_crypto_device_mapping.vat", node,
181 def crypto_device_verify(node, force_init=False, numvfs=32):
182 """Verify if Crypto QAT device virtual functions are initialized on all
183 DUTs. If parameter force initialization is set to True, then try to
184 initialize or disable QAT.
186 :param node: DUT node.
187 :param force_init: If True then try to initialize to specific value.
188 :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
190 :type force_init: bool
193 :raises RuntimeError: If QAT is not initialized or failed to initialize.
199 cryptodev = Topology.get_cryptodev(node)
200 cmd = 'cat /sys/bus/pci/devices/{0}/sriov_numvfs'.\
201 format(cryptodev.replace(':', r'\:'))
203 # Try to read number of VFs from PCI address of QAT device
205 ret_code, stdout, _ = ssh.exec_command(cmd)
206 if int(ret_code) == 0:
208 sriov_numvfs = int(stdout)
210 logger.trace('Reading sriov_numvfs info failed on {0}'.
211 format(node['host']))
213 if sriov_numvfs != numvfs:
215 # QAT is not initialized and we want to initialize
217 DUTSetup.crypto_device_init(node, numvfs)
219 raise RuntimeError('QAT device {0} is not '
220 'initialized to {1} on host {2}'
221 .format(cryptodev, numvfs,
226 def crypto_device_init(node, numvfs):
227 """Init Crypto QAT device virtual functions on DUT.
229 :param node: DUT node.
230 :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
234 :raises RuntimeError: If failed to stop VPP or QAT failed to initialize.
236 cryptodev = Topology.get_cryptodev(node)
238 # QAT device must be re-bound to kernel driver before initialization
240 kernel_module = 'qat_dh895xcc'
241 current_driver = DUTSetup.get_pci_dev_driver(
242 node, cryptodev.replace(':', r'\:'))
244 DUTSetup.kernel_module_verify(node, kernel_module, force_load=True)
246 VPPUtil.stop_vpp_service(node)
247 if current_driver is not None:
248 DUTSetup.pci_driver_unbind(node, cryptodev)
249 DUTSetup.pci_driver_bind(node, cryptodev, driver)
256 cmd = 'echo "{0}" | tee /sys/bus/pci/devices/{1}/sriov_numvfs'.\
257 format(numvfs, cryptodev.replace(':', r'\:'), timeout=180)
258 ret_code, _, _ = ssh.exec_command_sudo("sh -c '{0}'".format(cmd))
260 if int(ret_code) != 0:
261 raise RuntimeError('Failed to initialize {0} VFs on QAT device '
262 ' on host {1}'.format(numvfs, node['host']))
265 def pci_driver_unbind(node, pci_addr):
266 """Unbind PCI device from current driver on node.
268 :param node: DUT node.
269 :param pci_addr: PCI device address.
273 :raises RuntimeError: If PCI device unbind failed.
279 ret_code, _, _ = ssh.exec_command_sudo(
280 "sh -c 'echo {0} | tee /sys/bus/pci/devices/{1}/driver/unbind'"
281 .format(pci_addr, pci_addr.replace(':', r'\:')), timeout=180)
283 if int(ret_code) != 0:
284 raise RuntimeError('Failed to unbind PCI device {0} from driver on '
285 'host {1}'.format(pci_addr, node['host']))
288 def pci_driver_bind(node, pci_addr, driver):
289 """Bind PCI device to driver on node.
291 :param node: DUT node.
292 :param pci_addr: PCI device address.
293 :param driver: Driver to bind.
298 :raises RuntimeError: If PCI device bind failed.
304 ret_code, _, _ = ssh.exec_command_sudo(
305 "sh -c 'echo {0} | tee /sys/bus/pci/drivers/{1}/bind'".format(
306 pci_addr, driver), timeout=180)
308 if int(ret_code) != 0:
309 raise RuntimeError('Failed to bind PCI device {0} to {1} driver on '
310 'host {2}'.format(pci_addr, driver,
314 def get_pci_dev_driver(node, pci_addr):
315 """Get current PCI device driver on node.
317 :param node: DUT node.
318 :param pci_addr: PCI device address.
321 :returns: Driver or None
322 :raises RuntimeError: If PCI rescan or lspci command execution failed.
328 logger.trace('Try {0}: Get interface driver'.format(i))
329 cmd = 'sh -c "echo 1 > /sys/bus/pci/rescan"'
330 ret_code, _, _ = ssh.exec_command_sudo(cmd)
331 if int(ret_code) != 0:
332 raise RuntimeError("'{0}' failed on '{1}'"
333 .format(cmd, node['host']))
335 cmd = 'lspci -vmmks {0}'.format(pci_addr)
336 ret_code, stdout, _ = ssh.exec_command(cmd)
337 if int(ret_code) != 0:
338 raise RuntimeError("'{0}' failed on '{1}'"
339 .format(cmd, node['host']))
341 for line in stdout.splitlines():
347 name, value = line.split("\t", 1)
349 if name == "Driver:":
351 if name == 'Driver:':
357 def kernel_module_verify(node, module, force_load=False):
358 """Verify if kernel module is loaded on all DUTs. If parameter force
359 load is set to True, then try to load the modules.
361 :param node: DUT node.
362 :param module: Module to verify.
363 :param force_load: If True then try to load module.
366 :type force_load: bool
368 :raises RuntimeError: If module is not loaded or failed to load.
374 cmd = 'grep -w {0} /proc/modules'.format(module)
375 ret_code, _, _ = ssh.exec_command(cmd)
377 if int(ret_code) != 0:
379 # Module is not loaded and we want to load it
380 DUTSetup.kernel_module_load(node, module)
382 raise RuntimeError('Kernel module {0} is not loaded on host '
383 '{1}'.format(module, node['host']))
386 def kernel_module_load(node, module):
387 """Load kernel module on node.
389 :param node: DUT node.
390 :param module: Module to load.
394 :raises RuntimeError: If loading failed.
400 ret_code, _, _ = ssh.exec_command_sudo("modprobe {0}".format(module))
402 if int(ret_code) != 0:
403 raise RuntimeError('Failed to load {0} kernel module on host {1}'.
404 format(module, node['host']))