From 97e93cd29f1a9c01b139e2d7fcc745d37d4bd944 Mon Sep 17 00:00:00 2001 From: Peter Mikus Date: Mon, 29 Jul 2019 12:36:18 +0000 Subject: [PATCH] Add: Dot1Q + L2BD + GBP Change-Id: I0050f715011ecfa92b3ee88b301809a56abb7946 Signed-off-by: Peter Mikus --- resources/api/vpp/supported_crcs.yaml | 14 + resources/libraries/python/Classify.py | 23 +- resources/libraries/python/GBP.py | 344 +++++++++++++++++++++ resources/libraries/python/InterfaceUtil.py | 9 +- resources/libraries/python/topology.py | 3 +- resources/libraries/robot/features/gbp.robot | 99 ++++++ resources/libraries/robot/shared/default.robot | 3 +- .../trex-sl-dot1qip4-vlan1ip4src254ip4dst254.py | 116 +++++++ ...1x710-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr.robot | 140 +++++++++ ...l-10ge2p1x710-dot1q-l2bdbasemaclrn-ndrpdr.robot | 4 +- 10 files changed, 745 insertions(+), 10 deletions(-) create mode 100644 resources/libraries/python/GBP.py create mode 100644 resources/libraries/robot/features/gbp.robot create mode 100755 resources/traffic_profiles/trex/trex-sl-dot1qip4-vlan1ip4src254ip4dst254.py create mode 100644 tests/vpp/perf/l2/2n1l-10ge2p1x710-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr.robot diff --git a/resources/api/vpp/supported_crcs.yaml b/resources/api/vpp/supported_crcs.yaml index c1bd07b02a..1e4904e678 100644 --- a/resources/api/vpp/supported_crcs.yaml +++ b/resources/api/vpp/supported_crcs.yaml @@ -65,6 +65,20 @@ create_vhost_user_if_reply: '0xfda5941f' # dev create_vlan_subif: '0x70cadeda' # virl create_vlan_subif_reply: '0xfda5941f' # virl + gbp_bridge_domain_add: '0x70f1069c' # perf + gbp_bridge_domain_add_reply: '0xe8d4e804' # perf + gbp_route_domain_add: '0x355b67c0' # perf + gbp_route_domain_add_reply: '0xe8d4e804' # perf + gbp_endpoint_add: '0x6003c704' # perf + gbp_endpoint_add_reply: '0x1dd3ff3e' # perf + gbp_endpoint_group_add: '0x1031b376' # perf + gbp_endpoint_group_add_reply: '0xe8d4e804' # perf + gbp_subnet_add_del: '0x4be859ed' # perf + gbp_subnet_add_del_reply: '0xe8d4e804' # perf + gbp_contract_add_del: '0xc64310d2' # perf + gbp_contract_add_del_reply: '0x1992deab' # perf + gbp_ext_itf_add_del: '0x6995e85f' # perf + gbp_ext_itf_add_del_reply: '0xe8d4e804' # perf gre_tunnel_add_del: '0x04199f47' # virl gre_tunnel_add_del_reply: '0x903324db' # virl gpe_enable_disable: '0xeb0e943b' # virl diff --git a/resources/libraries/python/Classify.py b/resources/libraries/python/Classify.py index 62508e1a49..46785dd3c2 100644 --- a/resources/libraries/python/Classify.py +++ b/resources/libraries/python/Classify.py @@ -425,7 +425,7 @@ class Classify(object): """ cmd = "acl_add_replace" args = dict( - tag=tag, + tag=tag.encode("utf-8"), acl_index=4294967295 if acl_idx is None else acl_idx, count=len(rules), r=rules @@ -803,21 +803,24 @@ class Classify(object): acls=acls) @staticmethod - def add_replace_acl_multi_entries(node, acl_idx=None, rules=None): + def add_replace_acl_multi_entries(node, acl_idx=None, rules=None, tag=""): """Add a new ACL or replace the existing one. To replace an existing ACL, pass the ID of this ACL. :param node: VPP node to set ACL on. :param acl_idx: ID of ACL. (Optional) :param rules: Required rules. (Optional) + :param tag: ACL tag (Optional). :type node: dict :type acl_idx: int :type rules: str + :type tag: str """ reg_ex_src_ip = re.compile(r'(src [0-9a-fA-F.:/\d{1,2}]*)') reg_ex_dst_ip = re.compile(r'(dst [0-9a-fA-F.:/\d{1,2}]*)') reg_ex_sport = re.compile(r'(sport \d{1,5})') reg_ex_dport = re.compile(r'(dport \d{1,5})') + reg_ex_proto = re.compile(r'(proto \d{1,5})') acl_rules = list() for rule in rules.split(", "): @@ -842,18 +845,30 @@ class Classify(object): port = int(groups.group(1).split(' ')[1]) acl_rule["srcport_or_icmptype_first"] = port acl_rule["srcport_or_icmptype_last"] = port + else: + acl_rule["srcport_or_icmptype_first"] = 0 + acl_rule["srcport_or_icmptype_last"] = 65535 groups = re.search(reg_ex_dport, rule) if groups: port = int(groups.group(1).split(' ')[1]) acl_rule["dstport_or_icmpcode_first"] = port acl_rule["dstport_or_icmpcode_last"] = port + else: + acl_rule["dstport_or_icmpcode_first"] = 0 + acl_rule["dstport_or_icmpcode_last"] = 65535 - acl_rule["proto"] = 0 + groups = re.search(reg_ex_proto, rule) + if groups: + proto = int(groups.group(1).split(' ')[1]) + acl_rule["proto"] = proto + else: + acl_rule["proto"] = 0 acl_rules.append(acl_rule) - Classify._acl_add_replace(node, acl_idx=acl_idx, rules=acl_rules) + Classify._acl_add_replace( + node, acl_idx=acl_idx, rules=acl_rules, tag=tag) @staticmethod def add_macip_acl_multi_entries(node, rules=""): diff --git a/resources/libraries/python/GBP.py b/resources/libraries/python/GBP.py new file mode 100644 index 0000000000..4dd5486a86 --- /dev/null +++ b/resources/libraries/python/GBP.py @@ -0,0 +1,344 @@ +# 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. + +"""GBP utilities library.""" + +from enum import IntEnum +from ipaddress import ip_address + +from resources.libraries.python.IPUtil import IPUtil +from resources.libraries.python.L2Util import L2Util +from resources.libraries.python.PapiExecutor import PapiSocketExecutor +from resources.libraries.python.topology import Topology + + +class GBPEndpointFlags(IntEnum): + """GBP Endpoint Flags.""" + GBP_API_ENDPOINT_FLAG_NONE = 0 + GBP_API_ENDPOINT_FLAG_BOUNCE = 1 + GBP_API_ENDPOINT_FLAG_REMOTE = 2 + GBP_API_ENDPOINT_FLAG_LEARNT = 4 + GBP_API_ENDPOINT_FLAG_EXTERNAL = 8 + + +class GBPBridgeDomainFlags(IntEnum): + """GBP Bridge Domain Flags.""" + GBP_BD_API_FLAG_NONE = 0 + GBP_BD_API_FLAG_DO_NOT_LEARN = 1 + GBP_BD_API_FLAG_UU_FWD_DROP = 2 + GBP_BD_API_FLAG_MCAST_DROP = 4 + GBP_BD_API_FLAG_UCAST_ARP = 8 + + +class GBPSubnetType(IntEnum): + """GBP Subnet Type.""" + GBP_API_SUBNET_TRANSPORT = 1 + GBP_API_SUBNET_STITCHED_INTERNAL = 2 + GBP_API_SUBNET_STITCHED_EXTERNAL = 3 + GBP_API_SUBNET_L3_OUT = 4 + GBP_API_SUBNET_ANON_L3_OUT = 5 + + +class GBPExtItfFlags(IntEnum): + """GBP External Interface Flags.""" + GBP_API_EXT_ITF_F_NONE = 0 + GBP_API_EXT_ITF_F_ANON = 1 + + +class GBPRuleAction(IntEnum): + """GBP Rule Action.""" + GBP_API_RULE_PERMIT = 1 + GBP_API_RULE_DENY = 2 + GBP_API_RULE_REDIRECT = 3 + + +class GBP(object): + """GBP utilities.""" + + @staticmethod + def gbp_route_domain_add( + node, rd_id=1, ip4_table_id=1, ip6_table_id=0, + ip4_uu_sw_if_index=0xffffffff, ip6_uu_sw_if_index=0xffffffff): + """Add GBP route domain. + + :param node: Node to add GBP route domain on. + :param rd_id: GBP route domain ID. + :param ip4_table_id: IPv4 table. + :param ip6_table_id: IPv6 table. + :param ip4_uu_sw_if_index: IPv4 unicast interface index. + :param ip6_uu_sw_if_index: IPv6 unicast interface index. + :type node: dict + :type rd_id: int + :type ip4_table_id: int + :type ip6_table_id: int + :type ip4_uu_sw_if_index: int + :type ip6_uu_sw_if_index: int + """ + cmd = 'gbp_route_domain_add' + err_msg = 'Failed to add GBP route domain on {node}!'\ + .format(node=node['host']) + + args_in = dict( + rd = dict ( + rd_id = rd_id, + ip4_table_id = ip4_table_id, + ip6_table_id = ip6_table_id, + ip4_uu_sw_if_index = ip4_uu_sw_if_index, + ip6_uu_sw_if_index = ip6_uu_sw_if_index + ) + ) + + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args_in).get_reply(err_msg) + + @staticmethod + def gbp_bridge_domain_add( + node, bvi_sw_if_index, bd_id=1, rd_id=1, + uu_fwd_sw_if_index=0xffffffff, bm_flood_sw_if_index=0xffffffff): + """Add GBP bridge domain. + + :param node: Node to add GBP bridge domain on. + :param bvi_sw_if_index: SW index of BVI/loopback interface. + :param bd_id: GBP bridge domain ID. + :param rd_id: GBP route domain ID. + :param uu_fwd_sw_if_index: Unicast forward interface index. + :param bm_flood_sw_if_index: Bcast/Mcast flood interface index. + :type node: dict + :type bvi_sw_if_index: int + :type bd_id: int + :type rd_id: int + :type uu_fwd_sw_if_index: int + :type bm_flood_sw_if_index: int + """ + cmd = 'gbp_bridge_domain_add' + err_msg = 'Failed to add GBP bridge domain on {node}!'\ + .format(node=node['host']) + + args_in = dict( + bd = dict( + flags = getattr(GBPBridgeDomainFlags, + 'GBP_BD_API_FLAG_NONE').value, + bvi_sw_if_index = bvi_sw_if_index, + uu_fwd_sw_if_index = uu_fwd_sw_if_index, + bm_flood_sw_if_index = bm_flood_sw_if_index, + bd_id = bd_id, + rd_id = rd_id + ) + ) + + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args_in).get_reply(err_msg) + + @staticmethod + def gbp_endpoint_group_add( + node, sclass, bd_id=1, rd_id=1, vnid=1, + uplink_sw_if_index=0xffffffff, remote_ep_timeout=0xffffffff): + """Add GBP endpoint group. + + :param node: Node to add GBP endpoint group on. + :param sclass: Source CLASS. + :param bd_id: GBP bridge domain ID. + :param rd_id: GBP route domain ID. + :param uplink_sw_if_index: Uplink interface index. + :param remote_ep_timeout: Remote endpoint interface index. + :param vnid: VNID. + :type node: dict + :type sclass: int + :type bd_id: int + :type rd_id: int + :type vnid: int + :type uplink_sw_if_index: int + :type remote_ep_timeout: int + """ + cmd = 'gbp_endpoint_group_add' + err_msg = 'Failed to add GBP endpoint group on {node}!'\ + .format(node=node['host']) + + args_in = dict( + epg = dict ( + uplink_sw_if_index = uplink_sw_if_index, + bd_id = bd_id, + rd_id = rd_id, + vnid = vnid, + sclass = sclass, + retention = dict ( + remote_ep_timeout = remote_ep_timeout + ) + ) + ) + + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args_in).get_reply(err_msg) + + @staticmethod + def gbp_endpoint_add(node, sw_if_index, ip_addr, mac_addr, sclass): + """Add GBP endpoint. + + :param node: Node to add GBP endpoint on. + :param sw_if_index: SW index of interface. + :param ip_addr: GBP route domain ID. + :param mac_addr: MAC address. + :param sclass: Source CLASS. + :type node: dict + :type sw_if_index: int + :type ip_addr: str + :type mac_addr: str + :type sclass: int + """ + cmd = 'gbp_endpoint_add' + err_msg = 'Failed to add GBP endpoint on {node}!'\ + .format(node=node['host']) + + ips = list() + ips.append(IPUtil.create_ip_address_object( + ip_address(unicode(ip_addr)))) + tun_src = IPUtil.create_ip_address_object( + ip_address(unicode('0.0.0.0'))) + tun_dst = IPUtil.create_ip_address_object( + ip_address(unicode('0.0.0.0'))) + + args_in = dict( + endpoint = dict( + sw_if_index = sw_if_index, + ips = ips, + n_ips = len(ips), + mac = L2Util.mac_to_bin(mac_addr), + sclass = sclass, + flags = getattr(GBPEndpointFlags, + 'GBP_API_ENDPOINT_FLAG_EXTERNAL').value, + tun = dict( + src = tun_src, + dst = tun_dst + ) + ) + ) + + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args_in).get_reply(err_msg) + + @staticmethod + def gbp_ext_itf_add_del(node, sw_if_index, bd_id=1, rd_id=1): + """Add external interface to GBP. + + :param node: Node to add external GBP interface on. + :param sw_if_index: SW index of interface. + :param bd_id: GBP bridge domain ID. + :param rd_id: GBP route domain ID. + :type node: dict + :type sw_if_index: int + :type bd_id: int + :type rd_id: int + """ + cmd = 'gbp_ext_itf_add_del' + err_msg = 'Failed to add external GBP interface on {node}!'\ + .format(node=node['host']) + + args_in = dict( + is_add = 1, + ext_itf = dict( + sw_if_index = sw_if_index, + bd_id = bd_id, + rd_id = rd_id, + flags = getattr(GBPExtItfFlags, + 'GBP_API_EXT_ITF_F_NONE').value + ) + ) + + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args_in).get_reply(err_msg) + + @staticmethod + def gbp_subnet_add_del( + node, address, subnet_length, sclass, rd_id=1, + sw_if_index=0xffffffff): + """Add external interface to GBP. + + :param node: Node to add GBP subnet on. + :param address: IPv4 adddress. + :param subnet_length: IPv4 address subnet. + :param sclass: Source CLASS. + :param rd_id: GBP route domain ID. + :param sw_if_index: Interface index. + :type node: dict + :type address: int + :type subnet_length: int + :type sclass: int + :type rd_id: int + :type sw_if_index: int + """ + cmd = 'gbp_subnet_add_del' + err_msg = 'Failed to add GBP subnet on {node}!'\ + .format(node=node['host']) + + args_in = dict( + is_add = 1, + subnet = dict( + type = getattr(GBPSubnetType, + 'GBP_API_SUBNET_L3_OUT').value, + sw_if_index = sw_if_index, + sclass = sclass, + prefix = dict( + address = IPUtil.create_ip_address_object( + ip_address(unicode(address))), + len = int(subnet_length) + ), + rd_id = rd_id + ) + ) + + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args_in).get_reply(err_msg) + + @staticmethod + def gbp_contract_add_del(node, sclass, dclass, acl_index=0): + """Add GBP contract. + + :param node: Node to add GBP contract on. + :param sclass: Source CLASS. + :param dclass: Destination CLASS. + :param acl_index: Index of ACL rule. + :type node: dict + :type sclass: int + :type dclass: int + :type acl_index: int + """ + cmd = 'gbp_contract_add_del' + err_msg = 'Failed to add GBP contract on {node}!'\ + .format(node=node['host']) + + rule_permit = dict( + action = getattr(GBPRuleAction, + 'GBP_API_RULE_PERMIT').value, + nh_set = dict( + hash_mode = list(), + n_nhs = 8, + nhs = [dict()]*8, + ) + ) + rules = [rule_permit, rule_permit] + + args_in = dict( + is_add = 1, + contract = dict( + acl_index = acl_index, + sclass = sclass, + dclass = dclass, + n_rules = len(rules), + rules = rules, + n_ether_types = 16, + allowed_ethertypes = [0x800, 0x86dd] + [0]*14 + ) + ) + + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args_in).get_reply(err_msg) diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py index 898d7fe9ae..34ccd7cadc 100644 --- a/resources/libraries/python/InterfaceUtil.py +++ b/resources/libraries/python/InterfaceUtil.py @@ -1045,18 +1045,20 @@ class InterfaceUtil(object): return ifc_name, sw_if_index @staticmethod - def vpp_create_loopback(node): + def vpp_create_loopback(node, mac=None): """Create loopback interface on VPP node. :param node: Node to create loopback interface on. + :param mac: Optional MAC address for Loopback interface. :type node: dict + :type mac: str :returns: SW interface index. :rtype: int :raises RuntimeError: If it is not possible to create loopback on the node. """ cmd = 'create_loopback' - args = dict(mac_address=0) + args = dict(mac_address=L2Util.mac_to_bin(mac) if mac else 0) err_msg = 'Failed to create loopback interface on host {host}'.format( host=node['host']) with PapiSocketExecutor(node) as papi_exec: @@ -1066,6 +1068,9 @@ class InterfaceUtil(object): Topology.update_interface_sw_if_index(node, if_key, sw_if_index) ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_index) Topology.update_interface_name(node, if_key, ifc_name) + if mac: + mac = InterfaceUtil.vpp_get_interface_mac(node, ifc_name) + Topology.update_interface_mac_address(node, if_key, mac) return sw_if_index diff --git a/resources/libraries/python/topology.py b/resources/libraries/python/topology.py index 394dc9df58..68045bbb68 100644 --- a/resources/libraries/python/topology.py +++ b/resources/libraries/python/topology.py @@ -138,7 +138,8 @@ class Topology(object): :returns: Nothing """ port_types = ('subinterface', 'vlan_subif', 'memif', 'tap', 'vhost', - 'loopback', 'gre_tunnel', 'vxlan_tunnel', 'eth_bond') + 'loopback', 'gre_tunnel', 'vxlan_tunnel', 'eth_bond', + 'avf') for node_data in nodes.values(): if node_data['type'] == NodeType.DUT: diff --git a/resources/libraries/robot/features/gbp.robot b/resources/libraries/robot/features/gbp.robot new file mode 100644 index 0000000000..78f9251180 --- /dev/null +++ b/resources/libraries/robot/features/gbp.robot @@ -0,0 +1,99 @@ +# 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. + +*** Settings *** +| Library | resources.libraries.python.GBP +| ... +| Documentation | GBP keywords + +*** Keywords *** +| Initialize GBP routing domains on node +| | [Documentation] +| | ... | Initialize GBP routing domains on node. +| | ... +| | ... | *Arguments:* +| | ... | - dut - DUT node. Type: string +| | ... | - count - Number of baseline interface variables. Type: integer +| | ... +| | ... | *Example:* +| | ... +| | ... | \| Initialize GBP routing domains on node \| DUT1 \| 1 \| +| | ... +| | [Arguments] | ${dut} | ${count}=${1} +| | ... +| | ${dut_str}= | Convert To Lowercase | ${dut} +| | :FOR | ${id} | IN RANGE | 1 | ${count} + 1 +| | | ${hexa_id}= | Convert To Hex | ${id} | length=2 | lowercase=yes +| | | ${dut_lo}= | VPP Create Loopback | ${nodes['${dut}']} +| | | ... | mac=ba:dc:00:ff:ee:${hexa_id} +| | | Set Interface State +| | | ... | ${nodes['${dut}']} | ${dut_lo} | up +| | | Add Fib Table +| | | ... | ${nodes['${dut}']} | ${id} +| | | GBP Route Domain Add +| | | ... | ${nodes['${dut}']} | rd_id=${id} +| | | Assign Interface To Fib Table +| | | ... | ${nodes['${dut}']} | ${dut_lo} | ${id} +| | | Create L2 BD +| | | ... | ${nodes['${dut}']} | ${id} | arp_term=${1} +| | | GBP Bridge Domain Add +| | | ... | ${nodes['${dut}']} | ${dut_lo} | bd_id=${id} +| | | GBP Endpoint Group Add +| | | ... | ${nodes['${dut}']} | ${100} | bd_id=${id} | rd_id=${id} +| | | Configure IP addresses on interfaces +| | | ... | ${nodes['${dut}']} | ${dut_lo} | 1.1.1.1 | 24 +| | | GBP Subnet Add Del +| | | ... | ${nodes['${dut}']} | 1.1.1.0 | 24 | ${100} | rd_id=${id} +| | | GBP Ext Itf Add Del +| | | ... | ${nodes['${dut}']} | ${dut_lo} | bd_id=${id} | rd_id=${id} +| | | GBP Endpoint Add +| | | ... | ${nodes['${dut}']} | ${${dut_str}_${prev_layer}_${id}_1} | 1.1.1.100 +| | | ... | ${tg_if1_mac} | ${100} +| | | GBP Endpoint Add +| | | ... | ${nodes['${dut}']} | ${${dut_str}_${prev_layer}_${id}_2} | 1.1.1.200 +| | | ... | ${tg_if2_mac} | ${100} +| | | VPP Route Add +| | | ... | ${nodes['${dut}']} | 10.10.10.0 | 24 | gateway=1.1.1.100 +| | | ... | interface=${dut_lo} | vrf=${1} +| | | VPP Route Add +| | | ... | ${nodes['${dut}']} | 20.20.20.0 | 24 | gateway=1.1.1.200 +| | | ... | interface=${dut_lo} | vrf=${1} +| | | GBP Subnet Add Del +| | | ... | ${nodes['${dut}']} | 10.10.10.0 | 24 | ${200} | rd_id=${id} +| | | GBP Subnet Add Del +| | | ... | ${nodes['${dut}']} | 20.20.20.0 | 24 | ${300} | rd_id=${id} +| | | Add Replace Acl Multi Entries +| | | ... | ${nodes['${dut}']} +| | | ... | rules="ipv4 permit src 0.0.0.0/0 dst 0.0.0.0/0 proto 61" +| | | ... | tag="gbp-permit-200-300" +| | | GBP Contract Add Del +| | | ... | ${nodes['${dut}']} | ${200} | ${300} | acl_index=${0} +| | | GBP Contract Add Del +| | | ... | ${nodes['${dut}']} | ${300} | ${200} | acl_index=${0} + +| Initialize GBP routing domains +| | [Documentation] +| | ... | Initialize GBP routing domains on all DUTs. +| | ... +| | ... | *Arguments:* +| | ... | - count - Number of GBP routing domains. Type: integer +| | ... +| | ... | *Example:* +| | ... +| | ... | \| Initialize GBP routing domains \| 1 \| +| | ... +| | [Arguments] | ${count}=${1} +| | ... +| | :FOR | ${dut} | IN | @{duts} +| | | Initialize GBP routing domains on node | ${dut} | count=${count} +| | Set interfaces in path up diff --git a/resources/libraries/robot/shared/default.robot b/resources/libraries/robot/shared/default.robot index 9c8ad458cf..f29a26e59a 100644 --- a/resources/libraries/robot/shared/default.robot +++ b/resources/libraries/robot/shared/default.robot @@ -37,11 +37,12 @@ | Library | resources.libraries.python.VPPUtil | ... | Resource | resources/libraries/robot/crypto/ipsec.robot +| Resource | resources/libraries/robot/features/gbp.robot +| Resource | resources/libraries/robot/features/policer.robot | Resource | resources/libraries/robot/performance/performance_configuration.robot | Resource | resources/libraries/robot/performance/performance_limits.robot | Resource | resources/libraries/robot/performance/performance_utils.robot | Resource | resources/libraries/robot/shared/container.robot -| Resource | resources/libraries/robot/features/policer.robot | Resource | resources/libraries/robot/shared/suite_teardown.robot | Resource | resources/libraries/robot/shared/suite_setup.robot | Resource | resources/libraries/robot/shared/test_teardown.robot diff --git a/resources/traffic_profiles/trex/trex-sl-dot1qip4-vlan1ip4src254ip4dst254.py b/resources/traffic_profiles/trex/trex-sl-dot1qip4-vlan1ip4src254ip4dst254.py new file mode 100755 index 0000000000..be58eb4e3e --- /dev/null +++ b/resources/traffic_profiles/trex/trex-sl-dot1qip4-vlan1ip4src254ip4dst254.py @@ -0,0 +1,116 @@ +# 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. + +"""Stream profile for T-rex traffic generator. + +Stream profile: + - Two streams sent in directions 0 --> 1 and 1 --> 0 at the same time. + - Packet: ETH / DOT1Q / IP / + - Direction 0 --> 1: + - VLAN range: 100 + - Source IP address range: 10.10.10.1 - 10.10.10.254 + - Destination IP address range: 20.20.20.1 - 20.20.20.254 + - Direction 1 --> 0: + - VLAN range: 200 + - Source IP address range: 20.20.20.1 - 20.20.20.254 + - Destination IP address range: 10.10.10.1 - 10.10.10.254 +""" + +from trex.stl.api import * +from profile_trex_stateless_base_class import TrafficStreamsBaseClass + + +class TrafficStreams(TrafficStreamsBaseClass): + """Stream profile.""" + + def __init__(self): + """Initialization and setting of streams' parameters.""" + + super(TrafficStreamsBaseClass, self).__init__() + + # VLAN IDs + self.p1_vlan_start = 100 + self.p2_vlan_start = 200 + + # IPs used in packet headers. + self.p1_src_start_ip = '10.10.10.1' + self.p1_src_end_ip = '10.10.10.254' + + self.p1_dst_start_ip = '20.20.20.1' + self.p1_dst_end_ip = '20.20.20.254' + + self.p2_src_start_ip = '20.20.20.1' + self.p2_src_end_ip = '20.20.20.254' + + self.p2_dst_start_ip = '10.10.10.1' + self.p2_dst_end_ip = '10.10.10.254' + + def define_packets(self): + """Defines the packets to be sent from the traffic generator. + + Packet definition: | ETH | DOT1Q | IP | + + :returns: Packets to be sent from the traffic generator. + :rtype: tuple + """ + + # Direction 0 --> 1 + base_pkt_a = (Ether(dst='ba:dc:00:ff:ee:01') / + Dot1Q(vlan=self.p1_vlan_start) / + IP(src=self.p1_src_start_ip, + dst=self.p1_dst_start_ip, + proto=61)) + # Direction 1 --> 0 + base_pkt_b = (Ether(dst='ba:dc:00:ff:ee:01') / + Dot1Q(vlan=self.p2_vlan_start) / + IP(src=self.p2_src_start_ip, + dst=self.p2_dst_start_ip, + proto=61)) + + # Direction 0 --> 1 + vm1 = STLScVmRaw([STLVmFlowVar(name="ip_src", + min_value=self.p1_src_start_ip, + max_value=self.p1_src_end_ip, + size=4, op="random"), + STLVmWrFlowVar(fv_name="ip_src", pkt_offset="IP.src"), + STLVmFlowVar(name="ip_dst", + min_value=self.p1_dst_start_ip, + max_value=self.p1_dst_end_ip, + size=4, op="random"), + STLVmWrFlowVar(fv_name="ip_dst", pkt_offset="IP.dst"), + STLVmFixIpv4(offset="IP")]) + # Direction 1 --> 0 + vm2 = STLScVmRaw([STLVmFlowVar(name="ip_src", + min_value=self.p2_src_start_ip, + max_value=self.p2_src_end_ip, + size=4, op="random"), + STLVmWrFlowVar(fv_name="ip_src", pkt_offset="IP.src"), + STLVmFlowVar(name="ip_dst", + min_value=self.p2_dst_start_ip, + max_value=self.p2_dst_end_ip, + size=4, op="random"), + STLVmWrFlowVar(fv_name="ip_dst", pkt_offset="IP.dst"), + STLVmFixIpv4(offset="IP")]) + + return base_pkt_a, base_pkt_b, vm1, vm2 + + +def register(): + """Register this traffic profile to T-rex. + + Do not change this function. + + :returns: Traffic streams. + :rtype: Object + """ + return TrafficStreams() diff --git a/tests/vpp/perf/l2/2n1l-10ge2p1x710-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr.robot b/tests/vpp/perf/l2/2n1l-10ge2p1x710-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr.robot new file mode 100644 index 0000000000..bcf5764c21 --- /dev/null +++ b/tests/vpp/perf/l2/2n1l-10ge2p1x710-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr.robot @@ -0,0 +1,140 @@ +# 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. + +*** Settings *** +| Resource | resources/libraries/robot/shared/default.robot +| ... +| Force Tags | 2_NODE_SINGLE_LINK_TOPO | PERFTEST | HW_ENV | NDRPDR +| ... | NIC_Intel-X710 | DOT1Q | L2BDMACLRN | BASE | DRV_AVF | GBP +| ... +| Suite Setup | Setup suite single link | performance_avf +| Suite Teardown | Tear down suite | performance +| Test Setup | Setup test +| Test Teardown | Tear down test | performance +| ... +| Test Template | Local template +| ... +| Documentation | *RFC2544: Pkt throughput L2BD with IEEE 802.1Q and GBP test +| ... | cases* +| ... +| ... | *[Top] Network Topologies:* TG-DUT1-TG 2-node circular topology\ +| ... | with single links between nodes. +| ... | *[Enc] Packet Encapsulations:* Dot1q-IPv4 for L2 switching of IPv4. \ +| ... | IEEE 802.1Q tagging is applied on both links TG-DUT1 . +| ... | *[Cfg] DUT configuration:* DUT1 is configured with:\ +| ... | 2 VLAN subinterfaces (VID 200 and 300),\ +| ... | 1 L2 BD with the 2 VLAN subinterfaces and a BVI,\ +| ... | 1 GBP L3 RD,\ +| ... | 1 GBP L2 BD with the L2 BD,\ +| ... | 1 GBP EPG EPG-1 with sclass 100, the GBP L2 BD and L3 RD,\ +| ... | 2 GBP external EP in EPG-1,\ +| ... | 2 external subnets with sclass 200 and 300,\ +| ... | Contracts allowing full communications between the 2 external subnets.\ +| ... | DUT1 tested with ${nic_name} with VF enabled. +| ... | *[Ver] TG verification:* TG finds and reports throughput NDR (Non Drop\ +| ... | Rate) with zero packet loss tolerance and throughput PDR (Partial Drop\ +| ... | Rate) with non-zero packet loss tolerance (LT) expressed in percentage\ +| ... | of packets transmitted. NDR and PDR are discovered for different\ +| ... | Ethernet L2 frame sizes using MLRsearch library.\ +| ... | Test packets are generated by TG on\ +| ... | links to DUT. TG traffic profile contains two L3 flow-groups\ +| ... | (flow-group per direction, 254 flows per flow-group) with all packets\ +| ... | containing Ethernet header including IEEE 802.1Q tagging, IPv4 header\ +| ... | with IP protocol=61 and static payload. MAC addresses are matching MAC\ +| ... | addresses of the TG node interfaces. +| ... | *[Ref] Applicable standard specifications:* RFC2544. + +*** Variables *** +| @{plugins_to_enable}= | dpdk_plugin.so | avf_plugin.so | gbp_plugin.so +| ... | acl_plugin.so +| ${osi_layer}= | L2 +| ${nic_name}= | Intel-X710 +| ${overhead}= | ${4} +# Traffic profile: +| ${traffic_profile}= | trex-sl-dot1qip4-vlan1ip4src254ip4dst254 + +*** Keywords *** +| Local template +| | [Documentation] +| | ... | [Cfg] DUT runs L2BD with VLAN and GBP config with ${phy_cores}\ +| | ... | physical core(s) for worker threads. +| | ... | [Ver] Measure NDR and PDR values using MLRsearch algorithm.\ +| | ... +| | ... | *Arguments:* +| | ... | - frame_size - Framesize in Bytes in integer or string (IMIX_v4_1). +| | ... | Type: integer, string +| | ... | - phy_cores - Number of physical cores. Type: integer +| | ... | - rxq - Number of RX queues, default value: ${None}. Type: integer +| | ... +| | [Arguments] | ${frame_size} | ${phy_cores} | ${rxq}=${None} +| | ... +| | Set Test Variable | \${frame_size} +| | ... +| | Given Add worker threads and rxqueues to all DUTs | ${phy_cores} | ${rxq} +| | And Add DPDK no PCI to all DUTs +| | And Set Max Rate And Jumbo +| | And Apply startup configuration on all VPP DUTs +| | When Initialize AVF interfaces +| | And Initialize layer interface +| | And Initialize layer dot1q +| | And Initialize GBP routing domains +| | Then Find NDR and PDR intervals using optimized search + +*** Test Cases *** +| tc01-64B-1c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | 64B | 1C +| | frame_size=${64} | phy_cores=${1} + +| tc02-64B-2c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | 64B | 2C +| | frame_size=${64} | phy_cores=${2} + +| tc03-64B-4c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | 64B | 4C +| | frame_size=${64} | phy_cores=${4} + +| tc04-1518B-1c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | 1518B | 1C +| | frame_size=${1518} | phy_cores=${1} + +| tc05-1518B-2c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | 1518B | 2C +| | frame_size=${1518} | phy_cores=${2} + +| tc06-1518B-4c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | 1518B | 4C +| | frame_size=${1518} | phy_cores=${4} + +| tc07-9000B-1c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | 9000B | 1C +| | frame_size=${9000} | phy_cores=${1} + +| tc08-9000B-2c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | 9000B | 2C +| | frame_size=${9000} | phy_cores=${2} + +| tc09-9000B-4c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | 9000B | 4C +| | frame_size=${9000} | phy_cores=${4} + +| tc10-IMIX-1c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | IMIX | 1C +| | frame_size=IMIX_v4_1 | phy_cores=${1} + +| tc11-IMIX-2c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | IMIX | 2C +| | frame_size=IMIX_v4_1 | phy_cores=${2} + +| tc12-IMIX-4c-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr +| | [Tags] | IMIX | 4C +| | frame_size=IMIX_v4_1 | phy_cores=${4} diff --git a/tests/vpp/perf/l2/2n1l-10ge2p1x710-dot1q-l2bdbasemaclrn-ndrpdr.robot b/tests/vpp/perf/l2/2n1l-10ge2p1x710-dot1q-l2bdbasemaclrn-ndrpdr.robot index 7045b35b42..2a54da47a5 100644 --- a/tests/vpp/perf/l2/2n1l-10ge2p1x710-dot1q-l2bdbasemaclrn-ndrpdr.robot +++ b/tests/vpp/perf/l2/2n1l-10ge2p1x710-dot1q-l2bdbasemaclrn-ndrpdr.robot @@ -28,8 +28,8 @@ | ... | ... | *[Top] Network Topologies:* TG-DUT1-TG 2-node circular topology with\ | ... | single links between nodes. -| ... | *[Enc] Packet Encapsulations:* Eth-IPv4 for L2 switching of IPv4. IEEE\ -| ... | 802.1Q tagging is applied on link between DUT1-if2 and TG-if2. +| ... | *[Enc] Packet Encapsulations:* Dot1q-IPv4 for L2 switching of IPv4. \ +| ... | IEEE 802.1Q tagging is applied on link between DUT1-if2 and TG-if2. | ... | *[Cfg] DUT configuration:* DUT1 is configured with L2 bridge domain\ | ... | and MAC learning enabled. DUT1 is tested with ${nic_name}.\ | ... | *[Ver] TG verification:* TG finds and reports throughput NDR (Non Drop\ -- 2.16.6