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