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