Update of VPP_STABLE_VER files
[csit.git] / resources / libraries / python / VPPUtil.py
1 # Copyright (c) 2019 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 """VPP util library."""
15
16 from robot.api import logger
17
18 from resources.libraries.python.Constants import Constants
19 from resources.libraries.python.DUTSetup import DUTSetup
20 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
21 from resources.libraries.python.ssh import exec_cmd_no_error
22 from resources.libraries.python.topology import NodeType
23
24
25 class VPPUtil(object):
26     """General class for any VPP related methods/functions."""
27
28     @staticmethod
29     def show_vpp_settings(node, *additional_cmds):
30         """Print default VPP settings. In case others are needed, can be
31         accepted as next parameters (each setting one parameter), preferably
32         in form of a string.
33
34         :param node: VPP node.
35         :param additional_cmds: Additional commands that the vpp should print
36             settings for.
37         :type node: dict
38         :type additional_cmds: tuple
39         """
40         def_setting_tb_displayed = {
41             'IPv6 FIB': 'ip6 fib',
42             'IPv4 FIB': 'ip fib',
43             'Interface IP': 'int addr',
44             'Interfaces': 'int',
45             'ARP': 'ip arp',
46             'Errors': 'err'
47         }
48
49         if additional_cmds:
50             for cmd in additional_cmds:
51                 def_setting_tb_displayed['Custom Setting: {}'.format(cmd)] = cmd
52
53         for _, cmd in def_setting_tb_displayed.items():
54             command = 'vppctl sh {cmd}'.format(cmd=cmd)
55             exec_cmd_no_error(node, command, timeout=30, sudo=True)
56
57     @staticmethod
58     def restart_vpp_service(node):
59         """Restart VPP service on the specified topology node.
60
61         :param node: Topology node.
62         :type node: dict
63         """
64         DUTSetup.restart_service(node, Constants.VPP_UNIT)
65
66     @staticmethod
67     def restart_vpp_service_on_all_duts(nodes):
68         """Restart VPP service on all DUT nodes.
69
70         :param nodes: Topology nodes.
71         :type nodes: dict
72         """
73         for node in nodes.values():
74             if node['type'] == NodeType.DUT:
75                 VPPUtil.restart_vpp_service(node)
76
77     @staticmethod
78     def stop_vpp_service(node):
79         """Stop VPP service on the specified topology node.
80
81         :param node: Topology node.
82         :type node: dict
83         """
84         DUTSetup.stop_service(node, Constants.VPP_UNIT)
85
86     @staticmethod
87     def stop_vpp_service_on_all_duts(nodes):
88         """Stop VPP service on all DUT nodes.
89
90         :param nodes: Topology nodes.
91         :type nodes: dict
92         """
93         for node in nodes.values():
94             if node['type'] == NodeType.DUT:
95                 VPPUtil.stop_vpp_service(node)
96
97     @staticmethod
98     def verify_vpp_installed(node):
99         """Verify that VPP is installed on the specified topology node.
100
101         :param node: Topology node.
102         :type node: dict
103         """
104         cmd = 'command -v vpp'
105         exec_cmd_no_error(
106             node, cmd, message='VPP is not installed!')
107
108     @staticmethod
109     def verify_vpp_started(node):
110         """Verify that VPP is started on the specified topology node.
111
112         :param node: Topology node.
113         :type node: dict
114         """
115         cmd = 'echo "show pci" | sudo socat - UNIX-CONNECT:/run/vpp/cli.sock'
116         exec_cmd_no_error(
117             node, cmd, sudo=False, message='VPP failed to start!', retries=120)
118
119         cmd = ('vppctl show pci 2>&1 | '
120                'fgrep -v "Connection refused" | '
121                'fgrep -v "No such file or directory"')
122         exec_cmd_no_error(
123             node, cmd, sudo=True, message='VPP failed to start!', retries=120)
124
125     @staticmethod
126     def verify_vpp(node):
127         """Verify that VPP is installed and started on the specified topology
128         node.
129
130         :param node: Topology node.
131         :type node: dict
132         :raises RuntimeError: If VPP service fails to start.
133         """
134         VPPUtil.verify_vpp_installed(node)
135         try:
136             # Verify responsivness of vppctl.
137             VPPUtil.verify_vpp_started(node)
138             # Verify responsivness of PAPI.
139             VPPUtil.show_log(node)
140             VPPUtil.vpp_show_version(node)
141         finally:
142             DUTSetup.get_service_logs(node, Constants.VPP_UNIT)
143
144     @staticmethod
145     def verify_vpp_on_all_duts(nodes):
146         """Verify that VPP is installed and started on all DUT nodes.
147
148         :param nodes: Nodes in the topology.
149         :type nodes: dict
150         """
151         for node in nodes.values():
152             if node['type'] == NodeType.DUT:
153                 VPPUtil.verify_vpp(node)
154
155     @staticmethod
156     def vpp_show_version(node, verbose=True):
157         """Run "show_version" PAPI command.
158
159         :param node: Node to run command on.
160         :param verbose: Show version, compile date and compile location if True
161             otherwise show only version.
162         :type node: dict
163         :type verbose: bool
164         :returns: VPP version.
165         :rtype: str
166         """
167         cmd = 'show_version'
168         with PapiSocketExecutor(node) as papi_exec:
169             reply = papi_exec.add(cmd).get_reply()
170         return_version = reply['version'].rstrip('\0x00')
171         version = 'VPP version:      {ver}\n'.format(ver=return_version)
172         if verbose:
173             version += ('Compile date:     {date}\n'
174                         'Compile location: {cl}\n'.
175                         format(date=reply['build_date'].rstrip('\0x00'),
176                                cl=reply['build_directory'].rstrip('\0x00')))
177         logger.info(version)
178         return return_version
179
180     @staticmethod
181     def show_vpp_version_on_all_duts(nodes):
182         """Show VPP version verbose on all DUTs.
183
184         :param nodes: Nodes in the topology.
185         :type nodes: dict
186         """
187         for node in nodes.values():
188             if node['type'] == NodeType.DUT:
189                 VPPUtil.vpp_show_version(node)
190
191     @staticmethod
192     def vpp_show_interfaces(node):
193         """Run "show interface" CLI command.
194
195         :param node: Node to run command on.
196         :type node: dict
197         """
198
199         cmd = 'sw_interface_dump'
200         args = dict(
201             name_filter_valid=False,
202             name_filter=''
203         )
204         err_msg = 'Failed to get interface dump on host {host}'.format(
205             host=node['host'])
206         with PapiSocketExecutor(node) as papi_exec:
207             details = papi_exec.add(cmd, **args).get_details(err_msg)
208
209         for if_dump in details:
210             if_dump['l2_address'] = str(if_dump['l2_address'])
211             if_dump['b_dmac'] = str(if_dump['b_dmac'])
212             if_dump['b_smac'] = str(if_dump['b_smac'])
213             if_dump['flags'] = if_dump['flags'].value
214             if_dump['type'] = if_dump['type'].value
215             if_dump['link_duplex'] = if_dump['link_duplex'].value
216             if_dump['sub_if_flags'] = if_dump['sub_if_flags'].value \
217                 if hasattr(if_dump['sub_if_flags'], 'value') \
218                 else int(if_dump['sub_if_flags'])
219         # TODO: return only base data
220         logger.trace('Interface data of host {host}:\n{details}'.format(
221             host=node['host'], details=details))
222
223     @staticmethod
224     def vpp_enable_traces_on_dut(node, fail_on_error=False):
225         """Enable vpp packet traces on the DUT node.
226
227         :param node: DUT node to set up.
228         :param fail_on_error: If True, keyword fails if an error occurs,
229             otherwise passes.
230         :type node: dict
231         :type fail_on_error: bool
232         """
233         cmds = [
234             "trace add dpdk-input 50",
235             "trace add vhost-user-input 50",
236             "trace add memif-input 50",
237             "trace add avf-input 50"
238         ]
239
240         for cmd in cmds:
241             try:
242                 PapiSocketExecutor.run_cli_cmd(node, cmd)
243             except AssertionError:
244                 if fail_on_error:
245                     raise
246
247     @staticmethod
248     def vpp_enable_traces_on_all_duts(nodes, fail_on_error=False):
249         """Enable vpp packet traces on all DUTs in the given topology.
250
251         :param nodes: Nodes in the topology.
252         :param fail_on_error: If True, keyword fails if an error occurs,
253             otherwise passes.
254         :type nodes: dict
255         :type fail_on_error: bool
256         """
257         for node in nodes.values():
258             if node['type'] == NodeType.DUT:
259                 VPPUtil.vpp_enable_traces_on_dut(node, fail_on_error)
260
261     @staticmethod
262     def vpp_enable_elog_traces_on_dut(node):
263         """Enable API/CLI/Barrier traces on the DUT node.
264
265         :param node: DUT node to set up.
266         :type node: dict
267         """
268         PapiSocketExecutor.run_cli_cmd(node, "elog trace api cli barrier")
269
270     @staticmethod
271     def vpp_enable_elog_traces_on_all_duts(nodes):
272         """Enable API/CLI/Barrier traces on all DUTs in the given topology.
273
274         :param nodes: Nodes in the topology.
275         :type nodes: dict
276         """
277         for node in nodes.values():
278             if node['type'] == NodeType.DUT:
279                 VPPUtil.vpp_enable_elog_traces_on_dut(node)
280
281     @staticmethod
282     def show_event_logger_on_dut(node):
283         """Show event logger on the DUT node.
284
285         :param node: DUT node to show traces on.
286         :type node: dict
287         """
288         PapiSocketExecutor.run_cli_cmd(node, "show event-logger")
289
290     @staticmethod
291     def show_event_logger_on_all_duts(nodes):
292         """Show event logger on all DUTs in the given topology.
293
294         :param nodes: Nodes in the topology.
295         :type nodes: dict
296         """
297         for node in nodes.values():
298             if node['type'] == NodeType.DUT:
299                 VPPUtil.show_event_logger_on_dut(node)
300
301     @staticmethod
302     def show_log(node):
303         """Show log on the specified topology node.
304
305         :param node: Topology node.
306         :type node: dict
307         :returns: VPP log data.
308         :rtype: list
309         """
310         return PapiSocketExecutor.run_cli_cmd(node, "show log")
311
312     @staticmethod
313     def vpp_show_threads(node):
314         """Show VPP threads on node.
315
316         :param node: Node to run command on.
317         :type node: dict
318         :returns: VPP thread data.
319         :rtype: list
320         """
321         cmd = 'show_threads'
322         with PapiSocketExecutor(node) as papi_exec:
323             reply = papi_exec.add(cmd).get_reply()
324
325         threads_data = list()
326         for thread in reply["thread_data"]:
327             thread_data = list()
328             for item in thread:
329                 if isinstance(item, unicode):
330                     item = item.rstrip('\x00')
331                 thread_data.append(item)
332             threads_data.append(thread_data)
333
334         logger.info("show threads:\n{threads}".format(threads=threads_data))
335
336         return threads_data