1 # Copyright (c) 2018 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 :param nodes: Nodes in the topology.
35 for node in nodes.values():
36 if node['type'] == NodeType.DUT:
38 (ret_code, stdout, stderr) = \
39 ssh.exec_command_sudo('service vpp restart', timeout=120)
40 if int(ret_code) != 0:
41 logger.debug('stdout: {0}'.format(stdout))
42 logger.debug('stderr: {0}'.format(stderr))
43 raise Exception('DUT {0} failed to start VPP service'.
47 def vpp_show_version_verbose(node):
48 """Run "show version verbose" CLI command.
50 :param node: Node to run command on.
54 vat.execute_script("show_version_verbose.vat", node, json_out=False)
57 def show_vpp_version_on_all_duts(nodes):
58 """Show VPP version verbose on all DUTs.
60 :param nodes: VPP nodes
63 for node in nodes.values():
64 if node['type'] == NodeType.DUT:
65 DUTSetup.vpp_show_version_verbose(node)
68 def vpp_api_trace_save(node):
69 """Run "api trace save" CLI command.
71 :param node: Node to run command on.
75 vat.execute_script("api_trace_save.vat", node, json_out=False)
78 def vpp_api_trace_dump(node):
79 """Run "api trace custom-dump" CLI command.
81 :param node: Node to run command on.
85 vat.execute_script("api_trace_dump.vat", node, json_out=False)
88 def setup_all_duts(nodes):
89 """Prepare all DUTs in given topology for test execution."""
90 for node in nodes.values():
91 if node['type'] == NodeType.DUT:
92 DUTSetup.setup_dut(node)
96 """Run script over SSH to setup the DUT node.
98 :param node: DUT node to set up.
101 :raises Exception: If the DUT setup fails.
106 (ret_code, stdout, stderr) = \
107 ssh.exec_command('sudo -Sn bash {0}/{1}/dut_setup.sh'.
108 format(Constants.REMOTE_FW_DIR,
109 Constants.RESOURCES_LIB_SH), timeout=120)
112 if int(ret_code) != 0:
113 logger.debug('DUT {0} setup script failed: "{1}"'.
114 format(node['host'], stdout + stderr))
115 raise Exception('DUT test setup script failed at node {}'.
116 format(node['host']))
119 def get_vpp_pid(node):
120 """Get PID of running VPP process.
122 :param node: DUT node.
126 :raises RuntimeError if it is not possible to get the PID.
133 logger.trace('Try {}: Get VPP PID'.format(i))
134 ret_code, stdout, stderr = ssh.exec_command('pidof vpp')
136 if int(ret_code) != 0:
137 raise RuntimeError('Not possible to get PID of VPP process '
138 'on node: {0}\n {1}'.
139 format(node['host'], stdout + stderr))
141 if len(stdout.splitlines()) == 1:
143 elif len(stdout.splitlines()) == 0:
144 logger.debug("No VPP PID found on node {0}".
145 format(node['host']))
148 logger.debug("More then one VPP PID found on node {0}".
149 format(node['host']))
151 for line in stdout.splitlines():
152 ret_list.append(int(line))
158 def get_vpp_pids(nodes):
159 """Get PID of running VPP process on all DUTs.
161 :param nodes: DUT nodes.
168 for node in nodes.values():
169 if node['type'] == NodeType.DUT:
170 pids[node['host']] = DUTSetup.get_vpp_pid(node)
174 def vpp_show_crypto_device_mapping(node):
175 """Run "show crypto device mapping" CLI command.
177 :param node: Node to run command on.
181 vat.execute_script("show_crypto_device_mapping.vat", node,
185 def crypto_device_verify(node, force_init=False, numvfs=32):
186 """Verify if Crypto QAT device virtual functions are initialized on all
187 DUTs. If parameter force initialization is set to True, then try to
188 initialize or disable QAT.
190 :param node: DUT node.
191 :param force_init: If True then try to initialize to specific value.
192 :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
194 :type force_init: bool
197 :raises RuntimeError: If QAT is not initialized or failed to initialize.
203 cryptodev = Topology.get_cryptodev(node)
204 cmd = 'cat /sys/bus/pci/devices/{0}/sriov_numvfs'.\
205 format(cryptodev.replace(':', r'\:'))
207 # Try to read number of VFs from PCI address of QAT device
209 ret_code, stdout, _ = ssh.exec_command(cmd)
210 if int(ret_code) == 0:
212 sriov_numvfs = int(stdout)
214 logger.trace('Reading sriov_numvfs info failed on {0}'.
215 format(node['host']))
217 if sriov_numvfs != numvfs:
219 # QAT is not initialized and we want to initialize
221 DUTSetup.crypto_device_init(node, numvfs)
223 raise RuntimeError('QAT device {0} is not '
224 'initialized to {1} on host {2}'
225 .format(cryptodev, numvfs,
230 def crypto_device_init(node, numvfs):
231 """Init Crypto QAT device virtual functions on DUT.
233 :param node: DUT node.
234 :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
238 :raises RuntimeError: If failed to stop VPP or QAT failed to initialize.
240 cryptodev = Topology.get_cryptodev(node)
242 # QAT device must be re-bound to kernel driver before initialization
244 kernel_module = 'qat_dh895xcc'
245 current_driver = DUTSetup.get_pci_dev_driver(
246 node, cryptodev.replace(':', r'\:'))
248 DUTSetup.kernel_module_verify(node, kernel_module, force_load=True)
250 VPPUtil.stop_vpp_service(node)
251 if current_driver is not None:
252 DUTSetup.pci_driver_unbind(node, cryptodev)
253 DUTSetup.pci_driver_bind(node, cryptodev, driver)
260 cmd = 'echo "{0}" | tee /sys/bus/pci/devices/{1}/sriov_numvfs'.\
261 format(numvfs, cryptodev.replace(':', r'\:'), timeout=180)
262 ret_code, _, _ = ssh.exec_command_sudo("sh -c '{0}'".format(cmd))
264 if int(ret_code) != 0:
265 raise RuntimeError('Failed to initialize {0} VFs on QAT device '
266 ' on host {1}'.format(numvfs, node['host']))
269 def pci_driver_unbind(node, pci_addr):
270 """Unbind PCI device from current driver on node.
272 :param node: DUT node.
273 :param pci_addr: PCI device address.
277 :raises RuntimeError: If PCI device unbind failed.
283 ret_code, _, _ = ssh.exec_command_sudo(
284 "sh -c 'echo {0} | tee /sys/bus/pci/devices/{1}/driver/unbind'"
285 .format(pci_addr, pci_addr.replace(':', r'\:')), timeout=180)
287 if int(ret_code) != 0:
288 raise RuntimeError('Failed to unbind PCI device {0} from driver on '
289 'host {1}'.format(pci_addr, node['host']))
292 def pci_driver_bind(node, pci_addr, driver):
293 """Bind PCI device to driver on node.
295 :param node: DUT node.
296 :param pci_addr: PCI device address.
297 :param driver: Driver to bind.
302 :raises RuntimeError: If PCI device bind failed.
308 ret_code, _, _ = ssh.exec_command_sudo(
309 "sh -c 'echo {0} | tee /sys/bus/pci/drivers/{1}/bind'".format(
310 pci_addr, driver), timeout=180)
312 if int(ret_code) != 0:
313 raise RuntimeError('Failed to bind PCI device {0} to {1} driver on '
314 'host {2}'.format(pci_addr, driver,
318 def get_pci_dev_driver(node, pci_addr):
319 """Get current PCI device driver on node.
321 :param node: DUT node.
322 :param pci_addr: PCI device address.
325 :returns: Driver or None
326 :raises RuntimeError: If PCI rescan or lspci command execution failed.
332 logger.trace('Try {0}: Get interface driver'.format(i))
333 cmd = 'sh -c "echo 1 > /sys/bus/pci/rescan"'
334 ret_code, _, _ = ssh.exec_command_sudo(cmd)
335 if int(ret_code) != 0:
336 raise RuntimeError("'{0}' failed on '{1}'"
337 .format(cmd, node['host']))
339 cmd = 'lspci -vmmks {0}'.format(pci_addr)
340 ret_code, stdout, _ = ssh.exec_command(cmd)
341 if int(ret_code) != 0:
342 raise RuntimeError("'{0}' failed on '{1}'"
343 .format(cmd, node['host']))
345 for line in stdout.splitlines():
351 name, value = line.split("\t", 1)
353 if name == "Driver:":
355 if name == 'Driver:':
361 def kernel_module_verify(node, module, force_load=False):
362 """Verify if kernel module is loaded on all DUTs. If parameter force
363 load is set to True, then try to load the modules.
365 :param node: DUT node.
366 :param module: Module to verify.
367 :param force_load: If True then try to load module.
370 :type force_load: bool
372 :raises RuntimeError: If module is not loaded or failed to load.
378 cmd = 'grep -w {0} /proc/modules'.format(module)
379 ret_code, _, _ = ssh.exec_command(cmd)
381 if int(ret_code) != 0:
383 # Module is not loaded and we want to load it
384 DUTSetup.kernel_module_load(node, module)
386 raise RuntimeError('Kernel module {0} is not loaded on host '
387 '{1}'.format(module, node['host']))
390 def kernel_module_load(node, module):
391 """Load kernel module on node.
393 :param node: DUT node.
394 :param module: Module to load.
398 :raises RuntimeError: If loading failed.
404 ret_code, _, _ = ssh.exec_command_sudo("modprobe {0}".format(module))
406 if int(ret_code) != 0:
407 raise RuntimeError('Failed to load {0} kernel module on host {1}'.
408 format(module, node['host']))
411 def vpp_enable_traces_on_all_duts(nodes):
412 """Enable vpp packet traces on all DUTs in the given topology.
414 :param nodes: Nodes in the topology.
417 for node in nodes.values():
418 if node['type'] == NodeType.DUT:
419 DUTSetup.vpp_enable_traces_on_dut(node)
422 def vpp_enable_traces_on_dut(node):
423 """Enable vpp packet traces on the DUT node.
425 :param node: DUT node to set up.
430 vat.execute_script("enable_dpdk_traces.vat", node, json_out=False)
431 vat.execute_script("enable_vhost_user_traces.vat", node, json_out=False)