Python3: resources and libraries
[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:
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             u"IPv6 FIB": u"ip6 fib",
42             u"IPv4 FIB": u"ip fib",
43             u"Interface IP": u"int addr",
44             u"Interfaces": u"int",
45             u"ARP": u"ip arp",
46             u"Errors": u"err"
47         }
48
49         if additional_cmds:
50             for cmd in additional_cmds:
51                 def_setting_tb_displayed[f"Custom Setting: {cmd}"] = cmd
52
53         for _, cmd in def_setting_tb_displayed.items():
54             command = f"vppctl sh {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[u"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[u"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 = u"command -v vpp"
105         exec_cmd_no_error(node, cmd, message=u"VPP is not installed!")
106
107     @staticmethod
108     def verify_vpp_started(node):
109         """Verify that VPP is started on the specified topology node.
110
111         :param node: Topology node.
112         :type node: dict
113         """
114         cmd = u"echo \"show pci\" | sudo socat - UNIX-CONNECT:/run/vpp/cli.sock"
115         exec_cmd_no_error(
116             node, cmd, sudo=False, message=u"VPP failed to start!", retries=120
117         )
118
119         cmd = u"vppctl show pci 2>&1 | fgrep -v \"Connection refused\" | " \
120               u"fgrep -v \"No such file or directory\""
121         exec_cmd_no_error(
122             node, cmd, sudo=True, message=u"VPP failed to start!", retries=120
123         )
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 responsiveness of vppctl.
137             VPPUtil.verify_vpp_started(node)
138             # Verify responsiveness 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[u"type"] == NodeType.DUT:
153                 VPPUtil.verify_vpp(node)
154
155     @staticmethod
156     def vpp_show_version(node):
157         """Run "show_version" PAPI command.
158
159         :param node: Node to run command on.
160         :type node: dict
161         :returns: VPP version.
162         :rtype: str
163         """
164         cmd = u"show_version"
165         with PapiSocketExecutor(node) as papi_exec:
166             reply = papi_exec.add(cmd).get_reply()
167         logger.info(f"VPP version: {reply[u'version']}\n")
168         return f"{reply[u'version']}"
169
170     @staticmethod
171     def show_vpp_version_on_all_duts(nodes):
172         """Show VPP version verbose on all DUTs.
173
174         :param nodes: Nodes in the topology.
175         :type nodes: dict
176         """
177         for node in nodes.values():
178             if node[u"type"] == NodeType.DUT:
179                 VPPUtil.vpp_show_version(node)
180
181     @staticmethod
182     def vpp_show_interfaces(node):
183         """Run "show interface" CLI command.
184
185         :param node: Node to run command on.
186         :type node: dict
187         """
188
189         cmd = u"sw_interface_dump"
190         args = dict(
191             name_filter_valid=False,
192             name_filter=u""
193         )
194         err_msg = f"Failed to get interface dump on host {node[u'host']}"
195         with PapiSocketExecutor(node) as papi_exec:
196             details = papi_exec.add(cmd, **args).get_details(err_msg)
197
198         for if_dump in details:
199             if_dump[u"l2_address"] = str(if_dump[u"l2_address"])
200             if_dump[u"b_dmac"] = str(if_dump[u"b_dmac"])
201             if_dump[u"b_smac"] = str(if_dump[u"b_smac"])
202             if_dump[u"flags"] = if_dump[u"flags"].value
203             if_dump[u"type"] = if_dump[u"type"].value
204             if_dump[u"link_duplex"] = if_dump[u"link_duplex"].value
205             if_dump[u"sub_if_flags"] = if_dump[u"sub_if_flags"].value \
206                 if hasattr(if_dump[u"sub_if_flags"], u"value") \
207                 else int(if_dump[u"sub_if_flags"])
208         # TODO: return only base data
209         logger.trace(f"Interface data of host {node[u'host']}:\n{details}")
210
211     @staticmethod
212     def vpp_enable_traces_on_dut(node, fail_on_error=False):
213         """Enable vpp packet traces on the DUT node.
214
215         :param node: DUT node to set up.
216         :param fail_on_error: If True, keyword fails if an error occurs,
217             otherwise passes.
218         :type node: dict
219         :type fail_on_error: bool
220         """
221         cmds = [
222             u"trace add dpdk-input 50",
223             u"trace add vhost-user-input 50",
224             u"trace add memif-input 50",
225             u"trace add avf-input 50"
226         ]
227
228         for cmd in cmds:
229             try:
230                 PapiSocketExecutor.run_cli_cmd(node, cmd)
231             except AssertionError:
232                 if fail_on_error:
233                     raise
234
235     @staticmethod
236     def vpp_enable_traces_on_all_duts(nodes, fail_on_error=False):
237         """Enable vpp packet traces on all DUTs in the given topology.
238
239         :param nodes: Nodes in the topology.
240         :param fail_on_error: If True, keyword fails if an error occurs,
241             otherwise passes.
242         :type nodes: dict
243         :type fail_on_error: bool
244         """
245         for node in nodes.values():
246             if node[u"type"] == NodeType.DUT:
247                 VPPUtil.vpp_enable_traces_on_dut(node, fail_on_error)
248
249     @staticmethod
250     def vpp_enable_elog_traces(node):
251         """Enable API/CLI/Barrier traces on the specified topology node.
252
253         :param node: Topology node.
254         :type node: dict
255         """
256         PapiSocketExecutor.run_cli_cmd(node, "elog trace api cli barrier")
257
258     @staticmethod
259     def vpp_enable_elog_traces_on_all_duts(nodes):
260         """Enable API/CLI/Barrier traces on all DUTs in the given topology.
261
262         :param nodes: Nodes in the topology.
263         :type nodes: dict
264         """
265         for node in nodes.values():
266             if node[u"type"] == NodeType.DUT:
267                 VPPUtil.vpp_enable_elog_traces(node)
268
269     @staticmethod
270     def show_event_logger(node):
271         """Show event logger on the specified topology node.
272
273         :param node: Topology node.
274         :type node: dict
275         """
276         PapiSocketExecutor.run_cli_cmd(node, u"show event-logger")
277
278     @staticmethod
279     def show_event_logger_on_all_duts(nodes):
280         """Show event logger on all DUTs in the given topology.
281
282         :param nodes: Nodes in the topology.
283         :type nodes: dict
284         """
285         for node in nodes.values():
286             if node[u"type"] == NodeType.DUT:
287                 VPPUtil.show_event_logger(node)
288
289     @staticmethod
290     def show_log(node):
291         """Show logging on the specified topology node.
292
293         :param node: Topology node.
294         :type node: dict
295         """
296         PapiSocketExecutor.run_cli_cmd(node, u"show logging")
297
298     @staticmethod
299     def show_log_on_all_duts(nodes):
300         """Show logging on all DUTs in the given topology.
301
302         :param nodes: Nodes in the topology.
303         :type nodes: dict
304         """
305         for node in nodes.values():
306             if node[u"type"] == NodeType.DUT:
307                 VPPUtil.show_log(node)
308
309     @staticmethod
310     def vpp_show_threads(node):
311         """Show VPP threads on node.
312
313         :param node: Node to run command on.
314         :type node: dict
315         :returns: VPP thread data.
316         :rtype: list
317         """
318         cmd = u"show_threads"
319         with PapiSocketExecutor(node) as papi_exec:
320             reply = papi_exec.add(cmd).get_reply()
321
322         threads_data = list()
323         for thread in reply[u"thread_data"]:
324             thread_data = list()
325             for item in thread:
326                 if isinstance(item, str):
327                     item = item.rstrip('\x00')
328                 thread_data.append(item)
329             threads_data.append(thread_data)
330
331         logger.trace(f"show threads:\n{threads_data}")
332
333         return threads_data