TestConfig.py revision d68951ac
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
16from ipaddress import ip_address, AddressValueError
17from robot.api import logger
18
19from resources.libraries.python.Constants import Constants
20from resources.libraries.python.InterfaceUtil import InterfaceUtil, \
21    InterfaceStatusFlags
22from resources.libraries.python.IPUtil import IPUtil
23from resources.libraries.python.PapiExecutor import PapiSocketExecutor
24from resources.libraries.python.topology import Topology
25from resources.libraries.python.VatExecutor import VatExecutor
26
27
28class 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 vxlan_count > 10:
219            commands = list()
220            for i in range(0, vxlan_count):
221                vxlan_subif_key = Topology.add_new_port(node, u"vxlan_tunnel")
222                vxlan_subif_name = f"vxlan_tunnel{i}"
223                founds = dict(vxlan=False, vlan=False)
224                vxlan_subif_idx = None
225                vlan_subif_key = Topology.add_new_port(node, u"vlan_subif")
226                vlan_subif_name = \
227                    f"{Topology.get_interface_name(node, node_vlan_if)}.{i + 1}"
228                vlan_idx = None
229                for data in InterfaceUtil.vpp_get_interface_data(node):
230                    if_name = data[u"interface_name"]
231                    if not founds[u"vxlan"] and if_name == vxlan_subif_name:
232                        vxlan_subif_idx = data[u"sw_if_index"]
233                        founds[u"vxlan"] = True
234                    elif not founds[u"vlan"] and if_name == vlan_subif_name:
235                        vlan_idx = data[u"sw_if_index"]
236                        founds[u"vlan"] = True
237                    if founds[u"vxlan"] and founds[u"vlan"]:
238                        break
239                Topology.update_interface_sw_if_index(
240                    node, vxlan_subif_key, vxlan_subif_idx)
241                Topology.update_interface_name(
242                    node, vxlan_subif_key, vxlan_subif_name)
243                commands.append(
244                    f"sw_interface_set_flags sw_if_index {vxlan_subif_idx} "
245                    f"admin-up link-up\n"
246                )
247                Topology.update_interface_sw_if_index(
248                    node, vlan_subif_key, vlan_idx
249                )
250                Topology.update_interface_name(
251                    node, vlan_subif_key, vlan_subif_name
252                )
253                commands.append(
254                    f"sw_interface_set_flags sw_if_index {vlan_idx} admin-up "
255                    f"link-up\n"
256                )
257            VatExecutor().write_and_execute_script(
258                node, u"/tmp/put_subinterfaces_up.config", commands
259            )
260            return
261
262        cmd = u"sw_interface_set_flags"
263        args1 = dict(
264            sw_if_index=None,
265            flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
266        )
267        args2 = dict(
268            sw_if_index=None,
269            flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
270        )
271
272        with PapiSocketExecutor(node) as papi_exec:
273            for i in range(0, vxlan_count):
274                vxlan_subif_key = Topology.add_new_port(node, u"vxlan_tunnel")
275                vxlan_subif_name = f"vxlan_tunnel{i}"
276                founds = dict(vxlan=False, vlan=False)
277                vxlan_subif_idx = None
278                vlan_subif_key = Topology.add_new_port(node, u"vlan_subif")
279                vlan_subif_name = \
280                    f"{Topology.get_interface_name(node, node_vlan_if)}.{i+1}"
281                vlan_idx = None
282                for data in InterfaceUtil.vpp_get_interface_data(node):
283                    if not founds[u"vxlan"] \
284                            and data[u"interface_name"] == vxlan_subif_name:
285                        vxlan_subif_idx = data[u"sw_if_index"]
286                        founds[u"vxlan"] = True
287                    elif not founds[u"vlan"] \
288                            and data[u"interface_name"] == vlan_subif_name:
289                        vlan_idx = data[u"sw_if_index"]
290                        founds[u"vlan"] = True
291                    if founds[u"vxlan"] and founds[u"vlan"]:
292                        break
293                Topology.update_interface_sw_if_index(
294                    node, vxlan_subif_key, vxlan_subif_idx
295                )
296                Topology.update_interface_name(
297                    node, vxlan_subif_key, vxlan_subif_name
298                )
299                args1[u"sw_if_index"] = vxlan_subif_idx
300                Topology.update_interface_sw_if_index(
301                    node, vlan_subif_key, vlan_idx
302                )
303                Topology.update_interface_name(
304                    node, vlan_subif_key, vlan_subif_name
305                )
306                args2[u"sw_if_index"] = vlan_idx
307                history = bool(not 1 < i < vxlan_count - 1)
308                papi_exec.add(cmd, history=history, **args1). \
309                    add(cmd, history=history, **args2)
310                papi_exec.add(cmd, **args1).add(cmd, **args2)
311            papi_exec.get_replies()
312
313    @staticmethod
314    def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
315            node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
316            ip_step, bd_id_start):
317        """
318        Configure ARPs and routes for VXLAN interfaces and put each pair of
319        VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain.
320
321        :param node: VPP node.
322        :param node_vxlan_if: VPP node interface key where VXLAN tunnel
323            interfaces have been created.
324        :param vxlan_count: Number of tunnel interfaces.
325        :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
326        :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
327            interfaces.
328        :param dst_ip_start: VXLAN tunnel destination IP address start.
329        :param ip_step: IP address incremental step.
330        :param bd_id_start: Bridge-domain ID start.
331        :type node: dict
332        :type node_vxlan_if: str
333        :type vxlan_count: int
334        :type op_node: dict
335        :type op_node_if:
336        :type dst_ip_start: str
337        :type ip_step: int
338        :type bd_id_start: int
339        """
340        dst_ip_start = ip_address(dst_ip_start)
341
342        if vxlan_count > 1:
343            sw_idx_vxlan = Topology.get_interface_sw_index(node, node_vxlan_if)
344            commands = list()
345            for i in range(0, vxlan_count):
346                dst_ip = dst_ip_start + i * ip_step
347                commands.append(
348                    f"ip_neighbor_add_del sw_if_index {sw_idx_vxlan} "
349                    f"dst {dst_ip} "
350                    f"mac {Topology.get_interface_mac(op_node, op_node_if)}\n"
351                )
352                commands.append(
353                    f"ip_route_add_del "
354                    f"{dst_ip}/{128 if dst_ip.version == 6 else 32} count 1 "
355                    f"via {dst_ip} sw_if_index {sw_idx_vxlan}\n"
356                )
357                sw_idx_vxlan = Topology.get_interface_sw_index(
358                    node, f"vxlan_tunnel{i + 1}"
359                )
360                commands.append(
361                    f"sw_interface_set_l2_bridge sw_if_index {sw_idx_vxlan} "
362                    f"bd_id {bd_id_start + i} shg 0 enable\n"
363                )
364                sw_idx_vlan = Topology.get_interface_sw_index(
365                    node, f"vlan_subif{i + 1}"
366                )
367                commands.append(
368                    f"sw_interface_set_l2_bridge sw_if_index {sw_idx_vlan} "
369                    f"bd_id {bd_id_start + i} shg 0 enable\n"
370                )
371            VatExecutor().write_and_execute_script(
372                node, u"/tmp/configure_routes_and_bridge_domains.config",
373                commands
374            )
375            return
376
377        cmd1 = u"ip_neighbor_add_del"
378        neighbor = dict(
379            sw_if_index=Topology.get_interface_sw_index(node, node_vxlan_if),
380            flags=0,
381            mac_address=Topology.get_interface_mac(op_node, op_node_if),
382            ip_address=u""
383        )
384        args1 = dict(
385            is_add=1,
386            neighbor=neighbor
387        )
388        cmd2 = u"ip_route_add_del"
389        kwargs = dict(
390            interface=node_vxlan_if,
391            gateway=str(dst_ip_start)
392        )
393        route = IPUtil.compose_vpp_route_structure(
394            node, str(dst_ip_start),
395            128 if dst_ip_start.version == 6 else 32, **kwargs
396        )
397        args2 = dict(
398            is_add=1,
399            is_multipath=0,
400            route=route
401        )
402        cmd3 = u"sw_interface_set_l2_bridge"
403        args3 = dict(
404            rx_sw_if_index=None,
405            bd_id=None,
406            shg=0,
407            port_type=0,
408            enable=1
409        )
410        args4 = dict(
411            rx_sw_if_index=None,
412            bd_id=None,
413            shg=0,
414            port_type=0,
415            enable=1
416        )
417
418        with PapiSocketExecutor(node) as papi_exec:
419            for i in range(0, vxlan_count):
420                args1[u"neighbor"][u"ip_address"] = \
421                    str(dst_ip_start + i * ip_step)
422                args2[u"route"][u"prefix"][u"address"][u"un"] = \
423                    IPUtil.union_addr(dst_ip_start + i * ip_step)
424                args2[u"route"][u"paths"][0][u"nh"][u"address"] = \
425                    IPUtil.union_addr(dst_ip_start + i * ip_step)
426                args3[u"rx_sw_if_index"] = Topology.get_interface_sw_index(
427                    node, f"vxlan_tunnel{i+1}"
428                )
429                args3[u"bd_id"] = int(bd_id_start+i)
430                args4[u"rx_sw_if_index"] = Topology.get_interface_sw_index(
431                    node, f"vlan_subif{i+1}"
432                )
433                args4[u"bd_id"] = int(bd_id_start+i)
434                history = bool(not 1 < i < vxlan_count - 1)
435                papi_exec.add(cmd1, history=history, **args1). \
436                    add(cmd2, history=history, **args2). \
437                    add(cmd3, history=history, **args3). \
438                    add(cmd3, history=history, **args4)
439            papi_exec.get_replies()
440