diff options
author | Jan Gelety <jgelety@cisco.com> | 2019-06-18 13:17:31 +0200 |
---|---|---|
committer | Jan Gelety <jgelety@cisco.com> | 2019-06-19 06:21:24 +0200 |
commit | dbe149c85501bc15dde1496a722e2b9dce86ee92 (patch) | |
tree | b8047b910c4d77ef61fc687dcbc5f042550af721 /resources/libraries/python/TestConfig.py | |
parent | 33ea31791a8be80194a0a86a24e9172e80e9e688 (diff) |
FIX: VXLAN scale tests
Change-Id: I9287d5ed6d7876b98add3fb3d523e9764094843b
Signed-off-by: Jan Gelety <jgelety@cisco.com>
Diffstat (limited to 'resources/libraries/python/TestConfig.py')
-rw-r--r-- | resources/libraries/python/TestConfig.py | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/resources/libraries/python/TestConfig.py b/resources/libraries/python/TestConfig.py new file mode 100644 index 0000000000..1f8af5d457 --- /dev/null +++ b/resources/libraries/python/TestConfig.py @@ -0,0 +1,428 @@ +# Copyright (c) 2019 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Special test configurations library.""" + +from ipaddress import ip_address, AddressValueError +from robot.api import logger + +from resources.libraries.python.Constants import Constants +from resources.libraries.python.InterfaceUtil import InterfaceUtil +from resources.libraries.python.IPUtil import IPUtil +from resources.libraries.python.PapiExecutor import PapiExecutor +from resources.libraries.python.topology import Topology +from resources.libraries.python.VatExecutor import VatExecutor + + +class TestConfig(object): + """Contains special test configurations implemented in python for faster + execution.""" + + @staticmethod + def vpp_create_multiple_vxlan_ipv4_tunnels( + node, node_vxlan_if, node_vlan_if, op_node, op_node_if, + n_tunnels, vni_start, src_ip_start, dst_ip_start, ip_step, + bd_id_start): + """Create multiple VXLAN tunnel interfaces and VLAN sub-interfaces on + VPP node. + + Put each pair of VXLAN tunnel interface and VLAN sub-interface to + separate bridge-domain. + + :param node: VPP node to create VXLAN tunnel interfaces. + :param node_vxlan_if: VPP node interface key to create VXLAN tunnel + interfaces. + :param node_vlan_if: VPP node interface key to create VLAN + sub-interface. + :param op_node: Opposite VPP node for VXLAN tunnel interfaces. + :param op_node_if: Opposite VPP node interface key for VXLAN tunnel + interfaces. + :param n_tunnels: Number of tunnel interfaces to create. + :param vni_start: VNI start ID. + :param src_ip_start: VXLAN tunnel source IP address start. + :param dst_ip_start: VXLAN tunnel destination IP address start. + :param ip_step: IP address incremental step. + :param bd_id_start: Bridge-domain ID start. + :type node: dict + :type node_vxlan_if: str + :type node_vlan_if: str + :type op_node: dict + :type op_node_if: str + :type n_tunnels: int + :type vni_start: int + :type src_ip_start: str + :type dst_ip_start: str + :type ip_step: int + :type bd_id_start: int + """ + # configure IPs, create VXLAN interfaces and VLAN sub-interfaces + vxlan_count = TestConfig.vpp_create_vxlan_and_vlan_interfaces( + node, node_vxlan_if, node_vlan_if, n_tunnels, vni_start, + src_ip_start, dst_ip_start, ip_step) + + # update topology with VXLAN interfaces and VLAN sub-interfaces data + # and put interfaces up + TestConfig.vpp_put_vxlan_and_vlan_interfaces_up( + node, vxlan_count, node_vlan_if) + + # configure bridge domains, ARPs and routes + TestConfig.vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain( + node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start, + ip_step, bd_id_start) + + @staticmethod + def vpp_create_vxlan_and_vlan_interfaces( + node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start, + src_ip_start, dst_ip_start, ip_step): + """ + Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP + node. + + :param node: VPP node. + :param node_vxlan_if: VPP node interface key to create VXLAN tunnel + interfaces. + :param node_vlan_if: VPP node interface key to create VLAN + sub-interface. + :param vxlan_count: Number of tunnel interfaces to create. + :param vni_start: VNI start ID. + :param src_ip_start: VXLAN tunnel source IP address start. + :param dst_ip_start: VXLAN tunnel destination IP address start. + :param ip_step: IP address incremental step. + :type node: dict + :type node_vxlan_if: str + :type node_vlan_if: str + :type vxlan_count: int + :type vni_start: int + :type src_ip_start: str + :type dst_ip_start: str + :type ip_step: int + :returns: Number of created VXLAN interfaces. + :rtype: int + """ + src_ip_addr_start = ip_address(unicode(src_ip_start)) + dst_ip_addr_start = ip_address(unicode(dst_ip_start)) + + if vxlan_count > 10: + commands = list() + tmp_fn = '/tmp/create_vxlan_interfaces.config' + for i in xrange(0, vxlan_count): + try: + src_ip = src_ip_addr_start + i * ip_step + dst_ip = dst_ip_addr_start + i * ip_step + except AddressValueError: + logger.warn("Can't do more iterations - IP address limit " + "has been reached.") + vxlan_count = i + break + commands.append( + 'sw_interface_add_del_address sw_if_index {sw_idx} ' + '{ip}/{ip_len}\n'.format( + sw_idx=Topology.get_interface_sw_index( + node, node_vxlan_if), + ip=src_ip, + ip_len=128 if src_ip.version == 6 else 32)) + commands.append( + 'vxlan_add_del_tunnel src {src_ip} dst {dst_ip} vni {vni}\n' + .format(src_ip=src_ip, dst_ip=dst_ip, + vni=vni_start + i)) + commands.append( + 'create_vlan_subif sw_if_index {sw_idx} vlan {vlan}\n' + .format(sw_idx=Topology.get_interface_sw_index( + node, node_vlan_if), vlan=i + 1)) + VatExecutor().write_and_execute_script(node, tmp_fn, commands) + return vxlan_count + + cmd1 = 'sw_interface_add_del_address' + args1 = dict( + sw_if_index=InterfaceUtil.get_interface_index(node, node_vxlan_if), + is_add=1, + is_ipv6=1 if src_ip_addr_start.version == 6 else 0, + del_all=0, + address_length=128 if src_ip_addr_start.version == 6 else 32, + address=None) + cmd2 = 'vxlan_add_del_tunnel' + args2 = dict( + is_add=1, + is_ipv6=0, + instance=Constants.BITWISE_NON_ZERO, + src_address=None, + dst_address=None, + mcast_sw_if_index=Constants.BITWISE_NON_ZERO, + encap_vrf_id=0, + decap_next_index=Constants.BITWISE_NON_ZERO, + vni=None) + cmd3 = 'create_vlan_subif' + args3 = dict( + sw_if_index=InterfaceUtil.get_interface_index( + node, node_vlan_if), + vlan_id=None) + err_msg = 'Failed to create VXLAN and VLAN interfaces on host {host}'.\ + format(host=node['host']) + + with PapiExecutor(node) as papi_exec: + for i in xrange(0, vxlan_count): + try: + src_ip = src_ip_addr_start + i * ip_step + dst_ip = dst_ip_addr_start + i * ip_step + except AddressValueError: + logger.warn("Can't do more iterations - IP address limit " + "has been reached.") + vxlan_count = i + break + args1['address'] = src_ip.packed + args2['src_address'] = src_ip.packed + args2['dst_address'] = dst_ip.packed + args2['vni'] = int(vni_start) + i + args3['vlan_id'] = i + 1 + history = False if 1 < i < vxlan_count else True + papi_exec.add(cmd1, history=history, **args1).\ + add(cmd2, history=history, **args2).\ + add(cmd3, history=history, **args3) + if i > 0 and i % (Constants.PAPI_MAX_API_BULK / 3) == 0: + papi_exec.get_replies(err_msg).verify_replies( + err_msg=err_msg) + papi_exec.get_replies().verify_replies() + + return vxlan_count + + @staticmethod + def vpp_put_vxlan_and_vlan_interfaces_up(node, vxlan_count, node_vlan_if): + """ + Update topology with VXLAN interfaces and VLAN sub-interfaces data + and put interfaces up. + + :param node: VPP node. + :param vxlan_count: Number of tunnel interfaces. + :param node_vlan_if: VPP node interface key where VLAN sub-interfaces + have been created. + :type node: dict + :type vxlan_count: int + :type node_vlan_if: str + """ + if_data = InterfaceUtil.vpp_get_interface_data(node) + vlan_if_name = Topology.get_interface_name(node, node_vlan_if) + + if vxlan_count > 10: + tmp_fn = '/tmp/put_subinterfaces_up.config' + commands = list() + for i in xrange(0, vxlan_count): + vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel') + vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i) + vxlan_found = False + vxlan_subif_idx = None + vlan_subif_key = Topology.add_new_port(node, 'vlan_subif') + vlan_subif_name = '{if_name}.{vlan}'.format( + if_name=vlan_if_name, vlan=i + 1) + vlan_found = False + vlan_idx = None + for data in if_data: + if_name = data['interface_name'] + if not vxlan_found and if_name == vxlan_subif_name: + vxlan_subif_idx = data['sw_if_index'] + vxlan_found = True + elif not vlan_found and if_name == vlan_subif_name: + vlan_idx = data['sw_if_index'] + vlan_found = True + if vxlan_found and vlan_found: + break + Topology.update_interface_sw_if_index( + node, vxlan_subif_key, vxlan_subif_idx) + Topology.update_interface_name( + node, vxlan_subif_key, vxlan_subif_name) + commands.append( + 'sw_interface_set_flags sw_if_index {sw_idx} admin-up ' + 'link-up\n'.format(sw_idx=vxlan_subif_idx)) + Topology.update_interface_sw_if_index( + node, vlan_subif_key, vlan_idx) + Topology.update_interface_name( + node, vlan_subif_key, vlan_subif_name) + commands.append( + 'sw_interface_set_flags sw_if_index {sw_idx} admin-up ' + 'link-up\n'.format(sw_idx=vlan_idx)) + VatExecutor().write_and_execute_script(node, tmp_fn, commands) + return + + cmd = 'sw_interface_set_flags' + args1 = dict( + sw_if_index=None, + admin_up_down=1) + args2 = dict( + sw_if_index=None, + admin_up_down=1) + err_msg = 'Failed to put VXLAN and VLAN interfaces up on host {host}'. \ + format(host=node['host']) + + with PapiExecutor(node) as papi_exec: + for i in xrange(0, vxlan_count): + vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel') + vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i) + vxlan_found = False + vxlan_subif_idx = None + vlan_subif_key = Topology.add_new_port(node, 'vlan_subif') + vlan_subif_name = '{if_name}.{vlan}'.format( + if_name=vlan_if_name, vlan=i+1) + vlan_found = False + vlan_idx = None + for data in if_data: + if not vxlan_found \ + and data['interface_name'] == vxlan_subif_name: + vxlan_subif_idx = data['sw_if_index'] + vxlan_found = True + elif not vlan_found \ + and data['interface_name'] == vlan_subif_name: + vlan_idx = data['sw_if_index'] + vlan_found = True + if vxlan_found and vlan_found: + break + Topology.update_interface_sw_if_index( + node, vxlan_subif_key, vxlan_subif_idx) + Topology.update_interface_name( + node, vxlan_subif_key, vxlan_subif_name) + args1['sw_if_index'] = vxlan_subif_idx + Topology.update_interface_sw_if_index( + node, vlan_subif_key, vlan_idx) + Topology.update_interface_name( + node, vlan_subif_key, vlan_subif_name) + args2['sw_if_index'] = vlan_idx + history = False if 1 < i < vxlan_count else True + papi_exec.add(cmd, history=history, **args1). \ + add(cmd, history=history, **args2) + if i > 0 and i % (Constants.PAPI_MAX_API_BULK / 2) == 0: + papi_exec.get_replies(err_msg).verify_replies( + err_msg=err_msg) + papi_exec.add(cmd, **args1).add(cmd, **args2) + papi_exec.get_replies().verify_replies() + + @staticmethod + def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain( + node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start, + ip_step, bd_id_start): + """ + Configure ARPs and routes for VXLAN interfaces and put each pair of + VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain. + + :param node: VPP node. + :param node_vxlan_if: VPP node interface key where VXLAN tunnel + interfaces have been created. + :param vxlan_count: Number of tunnel interfaces. + :param op_node: Opposite VPP node for VXLAN tunnel interfaces. + :param op_node_if: Opposite VPP node interface key for VXLAN tunnel + interfaces. + :param dst_ip_start: VXLAN tunnel destination IP address start. + :param ip_step: IP address incremental step. + :param bd_id_start: Bridge-domain ID start. + :type node: dict + :type node_vxlan_if: str + :type vxlan_count: int + :type op_node: dict + :type op_node_if: + :type dst_ip_start: str + :type ip_step: int + :type bd_id_start: int + """ + dst_ip_addr_start = ip_address(unicode(dst_ip_start)) + + if vxlan_count > 1: + sw_idx_vxlan = Topology.get_interface_sw_index(node, node_vxlan_if) + tmp_fn = '/tmp/configure_routes_and_bridge_domains.config' + commands = list() + for i in xrange(0, vxlan_count): + dst_ip = dst_ip_addr_start + i * ip_step + commands.append( + 'ip_neighbor_add_del sw_if_index {sw_idx} dst {ip} ' + 'mac {mac}\n'.format( + sw_idx=sw_idx_vxlan, + ip=dst_ip, + mac=Topology.get_interface_mac(op_node, op_node_if))) + commands.append( + 'ip_route_add_del {ip}/{ip_len} count 1 via {ip} ' + 'sw_if_index {sw_idx}\n'.format( + ip=dst_ip, + ip_len=128 if dst_ip.version == 6 else 32, + sw_idx=sw_idx_vxlan)) + commands.append( + 'sw_interface_set_l2_bridge sw_if_index {sw_idx} ' + 'bd_id {bd_id} shg 0 enable\n'.format( + sw_idx=Topology.get_interface_sw_index( + node, 'vxlan_tunnel{nr}'.format(nr=i + 1)), + bd_id=bd_id_start + i)) + commands.append( + 'sw_interface_set_l2_bridge sw_if_index {sw_idx} ' + 'bd_id {bd_id} shg 0 enable\n'.format( + sw_idx=Topology.get_interface_sw_index( + node, 'vlan_subif{nr}'.format(nr=i + 1)), + bd_id=bd_id_start + i)) + VatExecutor().write_and_execute_script(node, tmp_fn, commands) + return + + cmd1 = 'ip_neighbor_add_del' + neighbor = dict( + sw_if_index=Topology.get_interface_sw_index(node, node_vxlan_if), + flags=0, + mac_address=Topology.get_interface_mac(op_node, op_node_if), + ip_address='') + args1 = dict( + is_add=1, + neighbor=neighbor) + cmd2 = 'ip_route_add_del' + kwargs = dict( + interface=node_vxlan_if, + gateway=str(dst_ip_addr_start)) + route = IPUtil.compose_vpp_route_structure( + node, + str(dst_ip_addr_start), + 128 if dst_ip_addr_start.version == 6 else 32, + **kwargs) + args2 = dict( + is_add=1, + is_multipath=0, + route=route) + cmd3 = 'sw_interface_set_l2_bridge' + args3 = dict( + rx_sw_if_index=None, + bd_id=None, + shg=0, + port_type=0, + enable=1) + args4 = dict( + rx_sw_if_index=None, + bd_id=None, + shg=0, + port_type=0, + enable=1) + err_msg = 'Failed to put VXLAN and VLAN interfaces to bridge domain ' \ + 'on host {host}'.format(host=node['host']) + + with PapiExecutor(node) as papi_exec: + for i in xrange(0, vxlan_count): + dst_ip = dst_ip_addr_start + i * ip_step + args1['neighbor']['ip_address'] = str(dst_ip) + args2['route']['prefix']['address']['un'] = \ + IPUtil.union_addr(dst_ip) + args2['route']['paths'][0]['nh']['address'] = \ + IPUtil.union_addr(dst_ip) + args3['rx_sw_if_index'] = Topology.get_interface_sw_index( + node, 'vxlan_tunnel{nr}'.format(nr=i+1)) + args3['bd_id'] = int(bd_id_start+i) + args4['rx_sw_if_index'] = Topology.get_interface_sw_index( + node, 'vlan_subif{nr}'.format(nr=i+1)) + args4['bd_id'] = int(bd_id_start+i) + history = False if 1 < i < vxlan_count else True + papi_exec.add(cmd1, history=history, **args1). \ + add(cmd2, history=history, **args2). \ + add(cmd3, history=history, **args3). \ + add(cmd3, history=history, **args4) + if i > 0 and i % (Constants.PAPI_MAX_API_BULK / 4) == 0: + papi_exec.get_replies(err_msg).verify_replies( + err_msg=err_msg) + papi_exec.get_replies().verify_replies() |