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