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