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