Python3: resources and libraries
[csit.git] / resources / libraries / python / TestConfig.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 """Special test configurations library."""
15
16 from ipaddress import ip_address, AddressValueError
17 from robot.api import logger
18
19 from resources.libraries.python.Constants import Constants
20 from resources.libraries.python.InterfaceUtil import InterfaceUtil, \
21     InterfaceStatusFlags
22 from resources.libraries.python.IPUtil import IPUtil
23 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
24 from resources.libraries.python.topology import Topology
25 from resources.libraries.python.VatExecutor import VatExecutor
26
27
28 class TestConfig:
29     """Contains special test configurations implemented in python for faster
30     execution."""
31
32     @staticmethod
33     def vpp_create_multiple_vxlan_ipv4_tunnels(
34             node, node_vxlan_if, node_vlan_if, op_node, op_node_if,
35             n_tunnels, vni_start, src_ip_start, dst_ip_start, ip_step,
36             bd_id_start):
37         """Create multiple VXLAN tunnel interfaces and VLAN sub-interfaces on
38         VPP node.
39
40         Put each pair of VXLAN tunnel interface and VLAN sub-interface to
41         separate bridge-domain.
42
43         :param node: VPP node to create VXLAN tunnel interfaces.
44         :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
45             interfaces.
46         :param node_vlan_if: VPP node interface key to create VLAN
47             sub-interface.
48         :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
49         :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
50             interfaces.
51         :param n_tunnels: Number of tunnel interfaces to create.
52         :param vni_start: VNI start ID.
53         :param src_ip_start: VXLAN tunnel source IP address start.
54         :param dst_ip_start: VXLAN tunnel destination IP address start.
55         :param ip_step: IP address incremental step.
56         :param bd_id_start: Bridge-domain ID start.
57         :type node: dict
58         :type node_vxlan_if: str
59         :type node_vlan_if: str
60         :type op_node: dict
61         :type op_node_if: str
62         :type n_tunnels: int
63         :type vni_start: int
64         :type src_ip_start: str
65         :type dst_ip_start: str
66         :type ip_step: int
67         :type bd_id_start: int
68         """
69         # configure IPs, create VXLAN interfaces and VLAN sub-interfaces
70         vxlan_count = TestConfig.vpp_create_vxlan_and_vlan_interfaces(
71             node, node_vxlan_if, node_vlan_if, n_tunnels, vni_start,
72             src_ip_start, dst_ip_start, ip_step
73         )
74
75         # update topology with VXLAN interfaces and VLAN sub-interfaces data
76         # and put interfaces up
77         TestConfig.vpp_put_vxlan_and_vlan_interfaces_up(
78             node, vxlan_count, node_vlan_if
79         )
80
81         # configure bridge domains, ARPs and routes
82         TestConfig.vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
83             node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
84             ip_step, bd_id_start
85         )
86
87     @staticmethod
88     def vpp_create_vxlan_and_vlan_interfaces(
89             node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start,
90             src_ip_start, dst_ip_start, ip_step):
91         """
92         Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP
93         node.
94
95         :param node: VPP node.
96         :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
97             interfaces.
98         :param node_vlan_if: VPP node interface key to create VLAN
99             sub-interface.
100         :param vxlan_count: Number of tunnel interfaces to create.
101         :param vni_start: VNI start ID.
102         :param src_ip_start: VXLAN tunnel source IP address start.
103         :param dst_ip_start: VXLAN tunnel destination IP address start.
104         :param ip_step: IP address incremental step.
105         :type node: dict
106         :type node_vxlan_if: str
107         :type node_vlan_if: str
108         :type vxlan_count: int
109         :type vni_start: int
110         :type src_ip_start: str
111         :type dst_ip_start: str
112         :type ip_step: int
113         :returns: Number of created VXLAN interfaces.
114         :rtype: int
115         """
116         src_ip_start = ip_address(src_ip_start)
117         dst_ip_start = ip_address(dst_ip_start)
118
119         if vxlan_count > 10:
120             commands = list()
121             for i in range(0, vxlan_count):
122                 try:
123                     src_ip = src_ip_start + i * ip_step
124                     dst_ip = dst_ip_start + i * ip_step
125                 except AddressValueError:
126                     logger.warn(
127                         u"Can't do more iterations - IP address limit "
128                         u"has been reached."
129                     )
130                     vxlan_count = i
131                     break
132                 commands.append(
133                     f"sw_interface_add_del_address sw_if_index "
134                     f"{Topology.get_interface_sw_index(node, node_vxlan_if)} "
135                     f"{src_ip}/{128 if src_ip.version == 6 else 32}\n"
136                 )
137                 commands.append(
138                     f"vxlan_add_del_tunnel src {src_ip} dst {dst_ip} "
139                     f"vni {vni_start + i}\n"
140                 )
141                 commands.append(
142                     f"create_vlan_subif sw_if_index "
143                     f"{Topology.get_interface_sw_index(node, node_vlan_if)} "
144                     f"vlan {i + 1}\n"
145                 )
146             VatExecutor().write_and_execute_script(
147                 node, u"/tmp/create_vxlan_interfaces.config", commands
148             )
149             return vxlan_count
150
151         cmd1 = u"sw_interface_add_del_address"
152         args1 = dict(
153             sw_if_index=InterfaceUtil.get_interface_index(node, node_vxlan_if),
154             is_add=True,
155             del_all=False,
156             prefix=None
157         )
158         cmd2 = u"vxlan_add_del_tunnel"
159         args2 = dict(
160             is_add=1,
161             is_ipv6=0,
162             instance=Constants.BITWISE_NON_ZERO,
163             src_address=None,
164             dst_address=None,
165             mcast_sw_if_index=Constants.BITWISE_NON_ZERO,
166             encap_vrf_id=0,
167             decap_next_index=Constants.BITWISE_NON_ZERO,
168             vni=None
169         )
170         cmd3 = u"create_vlan_subif"
171         args3 = dict(
172             sw_if_index=InterfaceUtil.get_interface_index(
173                 node, node_vlan_if),
174             vlan_id=None
175         )
176
177         with PapiSocketExecutor(node) as papi_exec:
178             for i in range(0, vxlan_count):
179                 try:
180                     src_ip = src_ip_start + i * ip_step
181                     dst_ip = dst_ip_start + i * ip_step
182                 except AddressValueError:
183                     logger.warn(
184                         u"Can't do more iterations - IP address limit "
185                         u"has been reached."
186                     )
187                     vxlan_count = i
188                     break
189                 args1[u"prefix"] = IPUtil.create_prefix_object(
190                     src_ip, 128 if src_ip_start.version == 6 else 32
191                 )
192                 args2[u"src_address"] = getattr(src_ip, u"packed")
193                 args2[u"dst_address"] = getattr(dst_ip, u"packed")
194                 args2[u"vni"] = int(vni_start) + i
195                 args3[u"vlan_id"] = i + 1
196                 history = bool(not 1 < i < vxlan_count - 1)
197                 papi_exec.add(cmd1, history=history, **args1).\
198                     add(cmd2, history=history, **args2).\
199                     add(cmd3, history=history, **args3)
200             papi_exec.get_replies()
201
202         return vxlan_count
203
204     @staticmethod
205     def vpp_put_vxlan_and_vlan_interfaces_up(node, vxlan_count, node_vlan_if):
206         """
207         Update topology with VXLAN interfaces and VLAN sub-interfaces data
208         and put interfaces up.
209
210         :param node: VPP node.
211         :param vxlan_count: Number of tunnel interfaces.
212         :param node_vlan_if: VPP node interface key where VLAN sub-interfaces
213             have been created.
214         :type node: dict
215         :type vxlan_count: int
216         :type node_vlan_if: str
217         """
218         if vxlan_count > 10:
219             commands = list()
220             for i in range(0, vxlan_count):
221                 vxlan_subif_key = Topology.add_new_port(node, u"vxlan_tunnel")
222                 vxlan_subif_name = f"vxlan_tunnel{i}"
223                 founds = dict(vxlan=False, vlan=False)
224                 vxlan_subif_idx = None
225                 vlan_subif_key = Topology.add_new_port(node, u"vlan_subif")
226                 vlan_subif_name = \
227                     f"{Topology.get_interface_name(node, node_vlan_if)}.{i + 1}"
228                 vlan_idx = None
229                 for data in InterfaceUtil.vpp_get_interface_data(node):
230                     if_name = data[u"interface_name"]
231                     if not founds[u"vxlan"] and if_name == vxlan_subif_name:
232                         vxlan_subif_idx = data[u"sw_if_index"]
233                         founds[u"vxlan"] = True
234                     elif not founds[u"vlan"] and if_name == vlan_subif_name:
235                         vlan_idx = data[u"sw_if_index"]
236                         founds[u"vlan"] = True
237                     if founds[u"vxlan"] and founds[u"vlan"]:
238                         break
239                 Topology.update_interface_sw_if_index(
240                     node, vxlan_subif_key, vxlan_subif_idx)
241                 Topology.update_interface_name(
242                     node, vxlan_subif_key, vxlan_subif_name)
243                 commands.append(
244                     f"sw_interface_set_flags sw_if_index {vxlan_subif_idx} "
245                     f"admin-up link-up\n"
246                 )
247                 Topology.update_interface_sw_if_index(
248                     node, vlan_subif_key, vlan_idx
249                 )
250                 Topology.update_interface_name(
251                     node, vlan_subif_key, vlan_subif_name
252                 )
253                 commands.append(
254                     f"sw_interface_set_flags sw_if_index {vlan_idx} admin-up "
255                     f"link-up\n"
256                 )
257             VatExecutor().write_and_execute_script(
258                 node, u"/tmp/put_subinterfaces_up.config", commands
259             )
260             return
261
262         cmd = u"sw_interface_set_flags"
263         args1 = dict(
264             sw_if_index=None,
265             flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
266         )
267         args2 = dict(
268             sw_if_index=None,
269             flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
270         )
271
272         with PapiSocketExecutor(node) as papi_exec:
273             for i in range(0, vxlan_count):
274                 vxlan_subif_key = Topology.add_new_port(node, u"vxlan_tunnel")
275                 vxlan_subif_name = f"vxlan_tunnel{i}"
276                 founds = dict(vxlan=False, vlan=False)
277                 vxlan_subif_idx = None
278                 vlan_subif_key = Topology.add_new_port(node, u"vlan_subif")
279                 vlan_subif_name = \
280                     f"{Topology.get_interface_name(node, node_vlan_if)}.{i+1}"
281                 vlan_idx = None
282                 for data in InterfaceUtil.vpp_get_interface_data(node):
283                     if not founds[u"vxlan"] \
284                             and data[u"interface_name"] == vxlan_subif_name:
285                         vxlan_subif_idx = data[u"sw_if_index"]
286                         founds[u"vxlan"] = True
287                     elif not founds[u"vlan"] \
288                             and data[u"interface_name"] == vlan_subif_name:
289                         vlan_idx = data[u"sw_if_index"]
290                         founds[u"vlan"] = True
291                     if founds[u"vxlan"] and founds[u"vlan"]:
292                         break
293                 Topology.update_interface_sw_if_index(
294                     node, vxlan_subif_key, vxlan_subif_idx
295                 )
296                 Topology.update_interface_name(
297                     node, vxlan_subif_key, vxlan_subif_name
298                 )
299                 args1[u"sw_if_index"] = vxlan_subif_idx
300                 Topology.update_interface_sw_if_index(
301                     node, vlan_subif_key, vlan_idx
302                 )
303                 Topology.update_interface_name(
304                     node, vlan_subif_key, vlan_subif_name
305                 )
306                 args2[u"sw_if_index"] = vlan_idx
307                 history = bool(not 1 < i < vxlan_count - 1)
308                 papi_exec.add(cmd, history=history, **args1). \
309                     add(cmd, history=history, **args2)
310                 papi_exec.add(cmd, **args1).add(cmd, **args2)
311             papi_exec.get_replies()
312
313     @staticmethod
314     def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
315             node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
316             ip_step, bd_id_start):
317         """
318         Configure ARPs and routes for VXLAN interfaces and put each pair of
319         VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain.
320
321         :param node: VPP node.
322         :param node_vxlan_if: VPP node interface key where VXLAN tunnel
323             interfaces have been created.
324         :param vxlan_count: Number of tunnel interfaces.
325         :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
326         :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
327             interfaces.
328         :param dst_ip_start: VXLAN tunnel destination IP address start.
329         :param ip_step: IP address incremental step.
330         :param bd_id_start: Bridge-domain ID start.
331         :type node: dict
332         :type node_vxlan_if: str
333         :type vxlan_count: int
334         :type op_node: dict
335         :type op_node_if:
336         :type dst_ip_start: str
337         :type ip_step: int
338         :type bd_id_start: int
339         """
340         dst_ip_start = ip_address(dst_ip_start)
341
342         if vxlan_count > 1:
343             sw_idx_vxlan = Topology.get_interface_sw_index(node, node_vxlan_if)
344             commands = list()
345             for i in range(0, vxlan_count):
346                 dst_ip = dst_ip_start + i * ip_step
347                 commands.append(
348                     f"ip_neighbor_add_del sw_if_index {sw_idx_vxlan} "
349                     f"dst {dst_ip} "
350                     f"mac {Topology.get_interface_mac(op_node, op_node_if)}\n"
351                 )
352                 commands.append(
353                     f"ip_route_add_del "
354                     f"{dst_ip}/{128 if dst_ip.version == 6 else 32} count 1 "
355                     f"via {dst_ip} sw_if_index {sw_idx_vxlan}\n"
356                 )
357                 sw_idx_vxlan = Topology.get_interface_sw_index(
358                     node, f"vxlan_tunnel{i + 1}"
359                 )
360                 commands.append(
361                     f"sw_interface_set_l2_bridge sw_if_index {sw_idx_vxlan} "
362                     f"bd_id {bd_id_start + i} shg 0 enable\n"
363                 )
364                 sw_idx_vlan = Topology.get_interface_sw_index(
365                     node, f"vlan_subif{i + 1}"
366                 )
367                 commands.append(
368                     f"sw_interface_set_l2_bridge sw_if_index {sw_idx_vlan} "
369                     f"bd_id {bd_id_start + i} shg 0 enable\n"
370                 )
371             VatExecutor().write_and_execute_script(
372                 node, u"/tmp/configure_routes_and_bridge_domains.config",
373                 commands
374             )
375             return
376
377         cmd1 = u"ip_neighbor_add_del"
378         neighbor = dict(
379             sw_if_index=Topology.get_interface_sw_index(node, node_vxlan_if),
380             flags=0,
381             mac_address=Topology.get_interface_mac(op_node, op_node_if),
382             ip_address=u""
383         )
384         args1 = dict(
385             is_add=1,
386             neighbor=neighbor
387         )
388         cmd2 = u"ip_route_add_del"
389         kwargs = dict(
390             interface=node_vxlan_if,
391             gateway=str(dst_ip_start)
392         )
393         route = IPUtil.compose_vpp_route_structure(
394             node, str(dst_ip_start),
395             128 if dst_ip_start.version == 6 else 32, **kwargs
396         )
397         args2 = dict(
398             is_add=1,
399             is_multipath=0,
400             route=route
401         )
402         cmd3 = u"sw_interface_set_l2_bridge"
403         args3 = dict(
404             rx_sw_if_index=None,
405             bd_id=None,
406             shg=0,
407             port_type=0,
408             enable=1
409         )
410         args4 = dict(
411             rx_sw_if_index=None,
412             bd_id=None,
413             shg=0,
414             port_type=0,
415             enable=1
416         )
417
418         with PapiSocketExecutor(node) as papi_exec:
419             for i in range(0, vxlan_count):
420                 args1[u"neighbor"][u"ip_address"] = \
421                     str(dst_ip_start + i * ip_step)
422                 args2[u"route"][u"prefix"][u"address"][u"un"] = \
423                     IPUtil.union_addr(dst_ip_start + i * ip_step)
424                 args2[u"route"][u"paths"][0][u"nh"][u"address"] = \
425                     IPUtil.union_addr(dst_ip_start + i * ip_step)
426                 args3[u"rx_sw_if_index"] = Topology.get_interface_sw_index(
427                     node, f"vxlan_tunnel{i+1}"
428                 )
429                 args3[u"bd_id"] = int(bd_id_start+i)
430                 args4[u"rx_sw_if_index"] = Topology.get_interface_sw_index(
431                     node, f"vlan_subif{i+1}"
432                 )
433                 args4[u"bd_id"] = int(bd_id_start+i)
434                 history = bool(not 1 < i < vxlan_count - 1)
435                 papi_exec.add(cmd1, history=history, **args1). \
436                     add(cmd2, history=history, **args2). \
437                     add(cmd3, history=history, **args3). \
438                     add(cmd3, history=history, **args4)
439             papi_exec.get_replies()