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