IPsec Multi-Tunnel performance test suite
[csit.git] / resources / libraries / python / DUTSetup.py
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:
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
14 """DUT setup library."""
15
16 from robot.api import logger
17
18 from resources.libraries.python.topology import NodeType
19 from resources.libraries.python.topology import Topology
20 from resources.libraries.python.ssh import SSH
21 from resources.libraries.python.constants import Constants
22 from resources.libraries.python.VatExecutor import VatExecutor
23
24
25 class DUTSetup(object):
26     """Contains methods for setting up DUTs."""
27     @staticmethod
28     def start_vpp_service_on_all_duts(nodes):
29         """Start up the VPP service on all nodes."""
30         ssh = SSH()
31         for node in nodes.values():
32             if node['type'] == NodeType.DUT:
33                 ssh.connect(node)
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'.
40                                     format(node['host']))
41
42     @staticmethod
43     def vpp_show_version_verbose(node):
44         """Run "show version verbose" CLI command.
45
46         :param node: Node to run command on.
47         :type node: dict
48         """
49         vat = VatExecutor()
50         vat.execute_script("show_version_verbose.vat", node, json_out=False)
51
52     @staticmethod
53     def vpp_api_trace_save(node):
54         """Run "api trace save" CLI command.
55
56         :param node: Node to run command on.
57         :type node: dict
58         """
59         vat = VatExecutor()
60         vat.execute_script("api_trace_save.vat", node, json_out=False)
61
62     @staticmethod
63     def vpp_api_trace_dump(node):
64         """Run "api trace custom-dump" CLI command.
65
66         :param node: Node to run command on.
67         :type node: dict
68         """
69         vat = VatExecutor()
70         vat.execute_script("api_trace_dump.vat", node, json_out=False)
71
72     @staticmethod
73     def setup_all_duts(nodes):
74         """Prepare all DUTs in given topology for test execution."""
75         for node in nodes.values():
76             if node['type'] == NodeType.DUT:
77                 DUTSetup.setup_dut(node)
78
79     @staticmethod
80     def setup_dut(node):
81         """Run script over SSH to setup the DUT node.
82
83         :param node: DUT node to set up.
84         :type node: dict
85
86         :raises Exception: If the DUT setup fails.
87         """
88         ssh = SSH()
89         ssh.connect(node)
90
91         (ret_code, stdout, stderr) = \
92             ssh.exec_command('sudo -Sn bash {0}/{1}/dut_setup.sh'.
93                              format(Constants.REMOTE_FW_DIR,
94                                     Constants.RESOURCES_LIB_SH), timeout=120)
95         logger.trace(stdout)
96         logger.trace(stderr)
97         if int(ret_code) != 0:
98             logger.debug('DUT {0} setup script failed: "{1}"'.
99                          format(node['host'], stdout + stderr))
100             raise Exception('DUT test setup script failed at node {}'.
101                             format(node['host']))
102
103     @staticmethod
104     def get_vpp_pid(node):
105         """Get PID of running VPP process.
106
107         :param node: DUT node.
108         :type node: dict
109         :return: PID
110         :rtype: int
111         :raises RuntimeError if it is not possible to get the PID.
112         """
113
114         ssh = SSH()
115         ssh.connect(node)
116         ret_code, stdout, stderr = ssh.exec_command('pidof vpp')
117
118         logger.trace(stdout)
119         logger.trace(stderr)
120
121         if int(ret_code) != 0:
122             logger.debug('Not possible to get PID of VPP process on node: '
123                          '{0}\n {1}'.format(node['host'], stdout + stderr))
124             raise RuntimeError('Not possible to get PID of VPP process on node:'
125                                ' {}'.format(node['host']))
126
127         if len(stdout.splitlines()) == 1:
128             return int(stdout)
129         elif len(stdout.splitlines()) == 0:
130             raise RuntimeError("No VPP PID found on node {0}".
131                                format(node['host']))
132         else:
133             raise RuntimeError("More then one VPP PID found on node {0}".
134                                format(node['host']))
135
136     @staticmethod
137     def get_vpp_pids(nodes):
138         """Get PID of running VPP process on all DUTs.
139
140         :param nodes: DUT nodes.
141         :type nodes: dict
142         :return: PIDs
143         :rtype: dict
144         """
145
146         pids = dict()
147         for node in nodes.values():
148             if node['type'] == NodeType.DUT:
149                 pids[node['host']] = DUTSetup.get_vpp_pid(node)
150         return pids
151
152     @staticmethod
153     def vpp_show_crypto_device_mapping(node):
154         """Run "show crypto device mapping" CLI command.
155
156         :param node: Node to run command on.
157         :type node: dict
158         """
159         vat = VatExecutor()
160         vat.execute_script("show_crypto_device_mapping.vat", node,
161                            json_out=False)
162
163     @staticmethod
164     def crypto_device_verify(node, force_init=False, numvfs=32):
165         """Verify if Crypto QAT device virtual functions are initialized on all
166         DUTs. If parameter force initialization is set to True, then try to
167         initialize or disable QAT.
168
169         :param node: DUT node.
170         :param force_init: If True then try to initialize to specific value.
171         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
172         :type node: dict
173         :type force_init: bool
174         :type numvfs: int
175         :returns: nothing
176         :raises RuntimeError: If QAT is not initialized or failed to initialize.
177         """
178
179         ssh = SSH()
180         ssh.connect(node)
181
182         cryptodev = Topology.get_cryptodev(node)
183         cmd = 'cat /sys/bus/pci/devices/{}/sriov_numvfs'.format(
184             cryptodev.replace(':', r'\:'))
185
186         # Try to read number of VFs from PCI address of QAT device
187         for _ in range(3):
188             ret_code, stdout, _ = ssh.exec_command(cmd)
189             if int(ret_code) == 0:
190                 try:
191                     sriov_numvfs = int(stdout)
192                 except ValueError:
193                     logger.trace('Reading sriov_numvfs info failed on: {}'\
194                         .format(node['host']))
195                 else:
196                     if sriov_numvfs != numvfs:
197                         if force_init:
198                             # QAT is not initialized and we want to initialize
199                             # with numvfs
200                             DUTSetup.crypto_device_init(node, numvfs)
201                         else:
202                             raise RuntimeError('QAT device {} is not '\
203                                 'initialized to {} on host: {}'.format(\
204                                 cryptodev, numvfs, node['host']))
205                     break
206
207     @staticmethod
208     def crypto_device_init(node, numvfs):
209         """Init Crypto QAT device virtual functions on DUT.
210
211         :param node: DUT node.
212         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
213         :type node: dict
214         :type numvfs: int
215         :returns: nothing
216         :raises RuntimeError: If QAT failed to initialize.
217         """
218
219         ssh = SSH()
220         ssh.connect(node)
221
222         cryptodev = Topology.get_cryptodev(node)
223
224         # QAT device must be bind to kernel driver before initialization
225         DUTSetup.pci_driver_unbind(node, cryptodev)
226         DUTSetup.pci_driver_bind(node, cryptodev, "dh895xcc")
227
228         # Initialize QAT VFs
229         ret_code, _, _ = ssh.exec_command(
230             "sudo sh -c 'echo {} | tee /sys/bus/pci/devices/{}/sriov_numvfs'"
231             .format(numvfs, cryptodev.replace(':', r'\:')))
232
233         if int(ret_code) != 0:
234             raise RuntimeError('Failed to initialize {} VFs on QAT device on '
235                                'host: {}'.format(numvfs, node['host']))
236
237     @staticmethod
238     def pci_driver_unbind(node, pci_addr):
239         """Unbind PCI device from current driver on node.
240
241         :param node: DUT node.
242         :param pci_addr: PCI device address.
243         :type node: dict
244         :type pci_addr: str
245         :returns: nothing
246         :raises RuntimeError: If PCI device unbind failed.
247         """
248
249         ssh = SSH()
250         ssh.connect(node)
251
252         ret_code, _, _ = ssh.exec_command(
253             "sudo sh -c 'echo {} | tee /sys/bus/pci/devices/{}/driver/unbind'"
254             .format(pci_addr, pci_addr.replace(':', r'\:')))
255
256         if int(ret_code) != 0:
257             raise RuntimeError('Failed to unbind PCI device from driver on '
258                                'host: {}'.format(node['host']))
259
260     @staticmethod
261     def pci_driver_bind(node, pci_addr, driver):
262         """Bind PCI device to driver on node.
263
264         :param node: DUT node.
265         :param pci_addr: PCI device address.
266         :param driver: Driver to bind.
267         :type node: dict
268         :type pci_addr: str
269         :type driver: str
270         :returns: nothing
271         :raises RuntimeError: If PCI device bind failed.
272         """
273
274         ssh = SSH()
275         ssh.connect(node)
276
277         ret_code, _, _ = ssh.exec_command(
278             "sudo sh -c 'echo {} | tee /sys/bus/pci/drivers/{}/bind'"
279             .format(pci_addr, driver))
280
281         if int(ret_code) != 0:
282             raise RuntimeError('Failed to bind PCI device to {} driver on '
283                                'host: {}'.format(driver, node['host']))
284
285     @staticmethod
286     def kernel_module_verify(node, module, force_load=False):
287         """Verify if kernel module is loaded on all DUTs. If parameter force
288         load is set to True, then try to load the modules.
289
290         :param node: DUT node.
291         :param module: Module to verify.
292         :param force_load: If True then try to load module.
293         :type node: dict
294         :type module: str
295         :type force_init: bool
296         :returns: nothing
297         :raises RuntimeError: If module is not loaded or failed to load.
298         """
299
300         ssh = SSH()
301         ssh.connect(node)
302
303         cmd = 'grep -w {} /proc/modules'.format(module)
304         ret_code, _, _ = ssh.exec_command(cmd)
305
306         if int(ret_code) != 0:
307             if force_load:
308                 # Module is not loaded and we want to load it
309                 DUTSetup.kernel_module_load(node, module)
310             else:
311                 raise RuntimeError('Kernel module {} is not loaded on host: '\
312                     '{}'.format(module, node['host']))
313
314     @staticmethod
315     def kernel_module_load(node, module):
316         """Load kernel module on node.
317
318         :param node: DUT node.
319         :param module: Module to load.
320         :type node: dict
321         :type module: str
322         :returns: nothing
323         :raises RuntimeError: If loading failed.
324         """
325
326         ssh = SSH()
327         ssh.connect(node)
328
329         ret_code, _, _ = ssh.exec_command_sudo("modprobe {}".format(module))
330
331         if int(ret_code) != 0:
332             raise RuntimeError('Failed to load {} kernel module on host: '\
333                 '{}'.format(module, node['host']))