Introduce VPP-IPsec container tests.
[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 Topology, SocketType, 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, node_key=None):
59         """Restart VPP service on the specified topology node.
60
61         :param node: Topology node.
62         :param node_key: Topology node key.
63         :type node: dict
64         :type node_key: str
65         """
66         DUTSetup.restart_service(node, Constants.VPP_UNIT)
67         if node_key:
68             Topology.add_new_socket(
69                 node, SocketType.PAPI, node_key, Constants.SOCKSVR_PATH)
70             Topology.add_new_socket(
71                 node, SocketType.STATS, node_key, Constants.SOCKSTAT_PATH)
72
73     @staticmethod
74     def restart_vpp_service_on_all_duts(nodes):
75         """Restart VPP service on all DUT nodes.
76
77         :param nodes: Topology nodes.
78         :type nodes: dict
79         """
80         for node_key, node in nodes.items():
81             if node[u"type"] == NodeType.DUT:
82                 VPPUtil.restart_vpp_service(node, node_key)
83
84     @staticmethod
85     def stop_vpp_service(node, node_key=None):
86         """Stop VPP service on the specified topology node.
87
88         :param node: Topology node.
89         :param node_key: Topology node key.
90         :type node: dict
91         :type node_key: str
92         """
93         DUTSetup.stop_service(node, Constants.VPP_UNIT)
94         if node_key:
95             Topology.del_node_socket_id(node, SocketType.PAPI, node_key)
96             Topology.del_node_socket_id(node, SocketType.STATS, node_key)
97
98     @staticmethod
99     def stop_vpp_service_on_all_duts(nodes):
100         """Stop VPP service on all DUT nodes.
101
102         :param nodes: Topology nodes.
103         :type nodes: dict
104         """
105         for node_key, node in nodes.items():
106             if node[u"type"] == NodeType.DUT:
107                 VPPUtil.stop_vpp_service(node, node_key)
108
109     @staticmethod
110     def verify_vpp_installed(node):
111         """Verify that VPP is installed on the specified topology node.
112
113         :param node: Topology node.
114         :type node: dict
115         """
116         cmd = u"command -v vpp"
117         exec_cmd_no_error(node, cmd, message=u"VPP is not installed!")
118
119     @staticmethod
120     def verify_vpp_started(node):
121         """Verify that VPP is started on the specified topology node.
122
123         :param node: Topology node.
124         :type node: dict
125         """
126         cmd = u"echo \"show ver\" | sudo socat - UNIX-CONNECT:/run/vpp/cli.sock"
127         exec_cmd_no_error(
128             node, cmd, sudo=False, message=u"VPP failed to start!", retries=120
129         )
130
131         cmd = u"vppctl show ver 2>&1 | fgrep -v \"Connection refused\" | " \
132               u"fgrep -v \"No such file or directory\""
133         exec_cmd_no_error(
134             node, cmd, sudo=True, message=u"VPP failed to start!", retries=120
135         )
136
137     @staticmethod
138     def verify_vpp(node):
139         """Verify that VPP is installed and started on the specified topology
140         node.
141
142         :param node: Topology node.
143         :type node: dict
144         :raises RuntimeError: If VPP service fails to start.
145         """
146         VPPUtil.verify_vpp_installed(node)
147         try:
148             # Verify responsiveness of vppctl.
149             VPPUtil.verify_vpp_started(node)
150             # Verify responsiveness of PAPI.
151             VPPUtil.show_log(node)
152             VPPUtil.vpp_show_version(node)
153         finally:
154             DUTSetup.get_service_logs(node, Constants.VPP_UNIT)
155
156     @staticmethod
157     def verify_vpp_on_all_duts(nodes):
158         """Verify that VPP is installed and started on all DUT nodes.
159
160         :param nodes: Nodes in the topology.
161         :type nodes: dict
162         """
163         for node in nodes.values():
164             if node[u"type"] == NodeType.DUT:
165                 VPPUtil.verify_vpp(node)
166
167     @staticmethod
168     def vpp_show_version(node):
169         """Run "show_version" PAPI command.
170
171         :param node: Node to run command on.
172         :type node: dict
173         :returns: VPP version.
174         :rtype: str
175         """
176         cmd = u"show_version"
177         with PapiSocketExecutor(node) as papi_exec:
178             reply = papi_exec.add(cmd).get_reply()
179         logger.info(f"VPP version: {reply[u'version']}\n")
180         return f"{reply[u'version']}"
181
182     @staticmethod
183     def show_vpp_version_on_all_duts(nodes):
184         """Show VPP version verbose on all DUTs.
185
186         :param nodes: Nodes in the topology.
187         :type nodes: dict
188         """
189         for node in nodes.values():
190             if node[u"type"] == NodeType.DUT:
191                 VPPUtil.vpp_show_version(node)
192
193     @staticmethod
194     def vpp_show_interfaces(node):
195         """Run "show interface" CLI command.
196
197         :param node: Node to run command on.
198         :type node: dict
199         """
200
201         cmd = u"sw_interface_dump"
202         args = dict(
203             name_filter_valid=False,
204             name_filter=u""
205         )
206         err_msg = f"Failed to get interface dump on host {node[u'host']}"
207         with PapiSocketExecutor(node) as papi_exec:
208             details = papi_exec.add(cmd, **args).get_details(err_msg)
209
210         for if_dump in details:
211             if_dump[u"l2_address"] = str(if_dump[u"l2_address"])
212             if_dump[u"b_dmac"] = str(if_dump[u"b_dmac"])
213             if_dump[u"b_smac"] = str(if_dump[u"b_smac"])
214             if_dump[u"flags"] = if_dump[u"flags"].value
215             if_dump[u"type"] = if_dump[u"type"].value
216             if_dump[u"link_duplex"] = if_dump[u"link_duplex"].value
217             if_dump[u"sub_if_flags"] = if_dump[u"sub_if_flags"].value \
218                 if hasattr(if_dump[u"sub_if_flags"], u"value") \
219                 else int(if_dump[u"sub_if_flags"])
220         # TODO: return only base data
221         logger.trace(f"Interface data of host {node[u'host']}:\n{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             u"trace add dpdk-input 50",
235             u"trace add vhost-user-input 50",
236             u"trace add memif-input 50",
237             u"trace add avf-input 50"
238         ]
239
240         for cmd in cmds:
241             try:
242                 PapiSocketExecutor.run_cli_cmd_on_all_sockets(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[u"type"] == NodeType.DUT:
259                 VPPUtil.vpp_enable_traces_on_dut(node, fail_on_error)
260
261     @staticmethod
262     def vpp_enable_elog_traces(node):
263         """Enable API/CLI/Barrier traces on the specified topology node.
264
265         :param node: Topology node.
266         :type node: dict
267         """
268         PapiSocketExecutor.run_cli_cmd_on_all_sockets(
269             node, u"elog trace api cli barrier")
270
271     @staticmethod
272     def vpp_enable_elog_traces_on_all_duts(nodes):
273         """Enable API/CLI/Barrier traces on all DUTs in the given topology.
274
275         :param nodes: Nodes in the topology.
276         :type nodes: dict
277         """
278         for node in nodes.values():
279             if node[u"type"] == NodeType.DUT:
280                 VPPUtil.vpp_enable_elog_traces(node)
281
282     @staticmethod
283     def show_event_logger(node):
284         """Show event logger on the specified topology node.
285
286         :param node: Topology node.
287         :type node: dict
288         """
289         PapiSocketExecutor.run_cli_cmd_on_all_sockets(
290             node, u"show event-logger")
291
292     @staticmethod
293     def show_event_logger_on_all_duts(nodes):
294         """Show event logger on all DUTs in the given topology.
295
296         :param nodes: Nodes in the topology.
297         :type nodes: dict
298         """
299         for node in nodes.values():
300             if node[u"type"] == NodeType.DUT:
301                 VPPUtil.show_event_logger(node)
302
303     @staticmethod
304     def show_log(node):
305         """Show logging on the specified topology node.
306
307         :param node: Topology node.
308         :type node: dict
309         """
310         PapiSocketExecutor.run_cli_cmd(node, u"show logging")
311
312     @staticmethod
313     def show_log_on_all_duts(nodes):
314         """Show logging on all DUTs in the given topology.
315
316         :param nodes: Nodes in the topology.
317         :type nodes: dict
318         """
319         for node in nodes.values():
320             if node[u"type"] == NodeType.DUT:
321                 VPPUtil.show_log(node)
322
323     @staticmethod
324     def vpp_show_threads(node):
325         """Show VPP threads on node.
326
327         :param node: Node to run command on.
328         :type node: dict
329         :returns: VPP thread data.
330         :rtype: list
331         """
332         cmd = u"show_threads"
333         with PapiSocketExecutor(node) as papi_exec:
334             reply = papi_exec.add(cmd).get_reply()
335
336         threads_data = list()
337         for thread in reply[u"thread_data"]:
338             thread_data = list()
339             for item in thread:
340                 if isinstance(item, str):
341                     item = item.rstrip('\x00')
342                 thread_data.append(item)
343             threads_data.append(thread_data)
344
345         logger.trace(f"show threads:\n{threads_data}")
346
347         return threads_data