98e18181a437ebc9712c6ce7e6589d061c177193
[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         err_msg = 'Failed to create VXLAN and VLAN interfaces on host {host}'.\
170             format(host=node['host'])
171
172         with PapiSocketExecutor(node) as papi_exec:
173             for i in xrange(0, vxlan_count):
174                 try:
175                     src_ip = src_ip_addr_start + i * ip_step
176                     dst_ip = dst_ip_addr_start + i * ip_step
177                 except AddressValueError:
178                     logger.warn("Can't do more iterations - IP address limit "
179                                 "has been reached.")
180                     vxlan_count = i
181                     break
182                 args1['address'] = getattr(src_ip, 'packed')
183                 args2['src_address'] = getattr(src_ip, 'packed')
184                 args2['dst_address'] = getattr(dst_ip, 'packed')
185                 args2['vni'] = int(vni_start) + i
186                 args3['vlan_id'] = i + 1
187                 history = False if 1 < i < vxlan_count else True
188                 papi_exec.add(cmd1, history=history, **args1).\
189                     add(cmd2, history=history, **args2).\
190                     add(cmd3, history=history, **args3)
191                 if i > 0 and i % (Constants.PAPI_MAX_API_BULK / 3) == 0:
192                     papi_exec.get_replies(err_msg)
193             papi_exec.get_replies()
194
195         return vxlan_count
196
197     @staticmethod
198     def vpp_put_vxlan_and_vlan_interfaces_up(node, vxlan_count, node_vlan_if):
199         """
200         Update topology with VXLAN interfaces and VLAN sub-interfaces data
201         and put interfaces up.
202
203         :param node: VPP node.
204         :param vxlan_count: Number of tunnel interfaces.
205         :param node_vlan_if: VPP node interface key where VLAN sub-interfaces
206             have been created.
207         :type node: dict
208         :type vxlan_count: int
209         :type node_vlan_if: str
210         """
211         if_data = InterfaceUtil.vpp_get_interface_data(node)
212         vlan_if_name = Topology.get_interface_name(node, node_vlan_if)
213
214         if vxlan_count > 10:
215             tmp_fn = '/tmp/put_subinterfaces_up.config'
216             commands = list()
217             for i in xrange(0, vxlan_count):
218                 vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel')
219                 vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i)
220                 vxlan_found = False
221                 vxlan_subif_idx = None
222                 vlan_subif_key = Topology.add_new_port(node, 'vlan_subif')
223                 vlan_subif_name = '{if_name}.{vlan}'.format(
224                     if_name=vlan_if_name, vlan=i + 1)
225                 vlan_found = False
226                 vlan_idx = None
227                 for data in if_data:
228                     if_name = data['interface_name']
229                     if not vxlan_found and if_name == vxlan_subif_name:
230                         vxlan_subif_idx = data['sw_if_index']
231                         vxlan_found = True
232                     elif not vlan_found and if_name == vlan_subif_name:
233                         vlan_idx = data['sw_if_index']
234                         vlan_found = True
235                     if vxlan_found and vlan_found:
236                         break
237                 Topology.update_interface_sw_if_index(
238                     node, vxlan_subif_key, vxlan_subif_idx)
239                 Topology.update_interface_name(
240                     node, vxlan_subif_key, vxlan_subif_name)
241                 commands.append(
242                     'sw_interface_set_flags sw_if_index {sw_idx} admin-up '
243                     'link-up\n'.format(sw_idx=vxlan_subif_idx))
244                 Topology.update_interface_sw_if_index(
245                     node, vlan_subif_key, vlan_idx)
246                 Topology.update_interface_name(
247                     node, vlan_subif_key, vlan_subif_name)
248                 commands.append(
249                     'sw_interface_set_flags sw_if_index {sw_idx} admin-up '
250                     'link-up\n'.format(sw_idx=vlan_idx))
251             VatExecutor().write_and_execute_script(node, tmp_fn, commands)
252             return
253
254         cmd = 'sw_interface_set_flags'
255         args1 = dict(
256             sw_if_index=None,
257             admin_up_down=1)
258         args2 = dict(
259             sw_if_index=None,
260             admin_up_down=1)
261         err_msg = 'Failed to put VXLAN and VLAN interfaces up on host {host}'. \
262             format(host=node['host'])
263
264         with PapiSocketExecutor(node) as papi_exec:
265             for i in xrange(0, vxlan_count):
266                 vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel')
267                 vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i)
268                 vxlan_found = False
269                 vxlan_subif_idx = None
270                 vlan_subif_key = Topology.add_new_port(node, 'vlan_subif')
271                 vlan_subif_name = '{if_name}.{vlan}'.format(
272                     if_name=vlan_if_name, vlan=i+1)
273                 vlan_found = False
274                 vlan_idx = None
275                 for data in if_data:
276                     if not vxlan_found \
277                             and data['interface_name'] == vxlan_subif_name:
278                         vxlan_subif_idx = data['sw_if_index']
279                         vxlan_found = True
280                     elif not vlan_found \
281                             and data['interface_name'] == vlan_subif_name:
282                         vlan_idx = data['sw_if_index']
283                         vlan_found = True
284                     if vxlan_found and vlan_found:
285                         break
286                 Topology.update_interface_sw_if_index(
287                     node, vxlan_subif_key, vxlan_subif_idx)
288                 Topology.update_interface_name(
289                     node, vxlan_subif_key, vxlan_subif_name)
290                 args1['sw_if_index'] = vxlan_subif_idx
291                 Topology.update_interface_sw_if_index(
292                     node, vlan_subif_key, vlan_idx)
293                 Topology.update_interface_name(
294                     node, vlan_subif_key, vlan_subif_name)
295                 args2['sw_if_index'] = vlan_idx
296                 history = False if 1 < i < vxlan_count else True
297                 papi_exec.add(cmd, history=history, **args1). \
298                     add(cmd, history=history, **args2)
299                 if i > 0 and i % (Constants.PAPI_MAX_API_BULK / 2) == 0:
300                     papi_exec.get_replies(err_msg)
301                 papi_exec.add(cmd, **args1).add(cmd, **args2)
302             papi_exec.get_replies()
303
304     @staticmethod
305     def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
306             node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
307             ip_step, bd_id_start):
308         """
309         Configure ARPs and routes for VXLAN interfaces and put each pair of
310         VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain.
311
312         :param node: VPP node.
313         :param node_vxlan_if: VPP node interface key where VXLAN tunnel
314             interfaces have been created.
315         :param vxlan_count: Number of tunnel interfaces.
316         :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
317         :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
318             interfaces.
319         :param dst_ip_start: VXLAN tunnel destination IP address start.
320         :param ip_step: IP address incremental step.
321         :param bd_id_start: Bridge-domain ID start.
322         :type node: dict
323         :type node_vxlan_if: str
324         :type vxlan_count: int
325         :type op_node: dict
326         :type op_node_if:
327         :type dst_ip_start: str
328         :type ip_step: int
329         :type bd_id_start: int
330         """
331         dst_ip_addr_start = ip_address(unicode(dst_ip_start))
332
333         if vxlan_count > 1:
334             sw_idx_vxlan = Topology.get_interface_sw_index(node, node_vxlan_if)
335             tmp_fn = '/tmp/configure_routes_and_bridge_domains.config'
336             commands = list()
337             for i in xrange(0, vxlan_count):
338                 dst_ip = dst_ip_addr_start + i * ip_step
339                 commands.append(
340                     'ip_neighbor_add_del sw_if_index {sw_idx} dst {ip} '
341                     'mac {mac}\n'.format(
342                         sw_idx=sw_idx_vxlan,
343                         ip=dst_ip,
344                         mac=Topology.get_interface_mac(op_node, op_node_if)))
345                 commands.append(
346                     'ip_route_add_del {ip}/{ip_len} count 1 via {ip} '
347                     'sw_if_index {sw_idx}\n'.format(
348                         ip=dst_ip,
349                         ip_len=128 if dst_ip.version == 6 else 32,
350                         sw_idx=sw_idx_vxlan))
351                 commands.append(
352                     'sw_interface_set_l2_bridge sw_if_index {sw_idx} '
353                     'bd_id {bd_id} shg 0 enable\n'.format(
354                         sw_idx=Topology.get_interface_sw_index(
355                             node, 'vxlan_tunnel{nr}'.format(nr=i + 1)),
356                         bd_id=bd_id_start + i))
357                 commands.append(
358                     'sw_interface_set_l2_bridge sw_if_index {sw_idx} '
359                     'bd_id {bd_id} shg 0 enable\n'.format(
360                         sw_idx=Topology.get_interface_sw_index(
361                             node, 'vlan_subif{nr}'.format(nr=i + 1)),
362                         bd_id=bd_id_start + i))
363             VatExecutor().write_and_execute_script(node, tmp_fn, commands)
364             return
365
366         cmd1 = 'ip_neighbor_add_del'
367         neighbor = dict(
368             sw_if_index=Topology.get_interface_sw_index(node, node_vxlan_if),
369             flags=0,
370             mac_address=Topology.get_interface_mac(op_node, op_node_if),
371             ip_address='')
372         args1 = dict(
373             is_add=1,
374             neighbor=neighbor)
375         cmd2 = 'ip_route_add_del'
376         kwargs = dict(
377             interface=node_vxlan_if,
378             gateway=str(dst_ip_addr_start))
379         route = IPUtil.compose_vpp_route_structure(
380             node,
381             str(dst_ip_addr_start),
382             128 if dst_ip_addr_start.version == 6 else 32,
383             **kwargs)
384         args2 = dict(
385             is_add=1,
386             is_multipath=0,
387             route=route)
388         cmd3 = 'sw_interface_set_l2_bridge'
389         args3 = dict(
390             rx_sw_if_index=None,
391             bd_id=None,
392             shg=0,
393             port_type=0,
394             enable=1)
395         args4 = dict(
396             rx_sw_if_index=None,
397             bd_id=None,
398             shg=0,
399             port_type=0,
400             enable=1)
401         err_msg = 'Failed to put VXLAN and VLAN interfaces to bridge domain ' \
402                   'on host {host}'.format(host=node['host'])
403
404         with PapiSocketExecutor(node) as papi_exec:
405             for i in xrange(0, vxlan_count):
406                 dst_ip = dst_ip_addr_start + i * ip_step
407                 args1['neighbor']['ip_address'] = str(dst_ip)
408                 args2['route']['prefix']['address']['un'] = \
409                     IPUtil.union_addr(dst_ip)
410                 args2['route']['paths'][0]['nh']['address'] = \
411                     IPUtil.union_addr(dst_ip)
412                 args3['rx_sw_if_index'] = Topology.get_interface_sw_index(
413                     node, 'vxlan_tunnel{nr}'.format(nr=i+1))
414                 args3['bd_id'] = int(bd_id_start+i)
415                 args4['rx_sw_if_index'] = Topology.get_interface_sw_index(
416                     node, 'vlan_subif{nr}'.format(nr=i+1))
417                 args4['bd_id'] = int(bd_id_start+i)
418                 history = False if 1 < i < vxlan_count else True
419                 papi_exec.add(cmd1, history=history, **args1). \
420                     add(cmd2, history=history, **args2). \
421                     add(cmd3, history=history, **args3). \
422                     add(cmd3, history=history, **args4)
423                 if i > 0 and i % (Constants.PAPI_MAX_API_BULK / 4) == 0:
424                     papi_exec.get_replies(err_msg)
425             papi_exec.get_replies()