Add: Dot1Q + L2BD + GBP 01/20901/15
authorPeter Mikus <pmikus@cisco.com>
Mon, 29 Jul 2019 12:36:18 +0000 (12:36 +0000)
committerPeter Mikus <pmikus@cisco.com>
Tue, 6 Aug 2019 19:03:52 +0000 (19:03 +0000)
Change-Id: I0050f715011ecfa92b3ee88b301809a56abb7946
Signed-off-by: Peter Mikus <pmikus@cisco.com>
resources/api/vpp/supported_crcs.yaml
resources/libraries/python/Classify.py
resources/libraries/python/GBP.py [new file with mode: 0644]
resources/libraries/python/InterfaceUtil.py
resources/libraries/python/topology.py
resources/libraries/robot/features/gbp.robot [new file with mode: 0644]
resources/libraries/robot/shared/default.robot
resources/traffic_profiles/trex/trex-sl-dot1qip4-vlan1ip4src254ip4dst254.py [new file with mode: 0755]
tests/vpp/perf/l2/2n1l-10ge2p1x710-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr.robot [new file with mode: 0644]
tests/vpp/perf/l2/2n1l-10ge2p1x710-dot1q-l2bdbasemaclrn-ndrpdr.robot

index c1bd07b..1e4904e 100644 (file)
     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
index 62508e1..46785dd 100644 (file)
@@ -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 (file)
index 0000000..4dd5486
--- /dev/null
@@ -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)
index 898d7fe..34ccd7c 100644 (file)
@@ -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
 
index 394dc9d..68045bb 100644 (file)
@@ -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 (file)
index 0000000..78f9251
--- /dev/null
@@ -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
index 9c8ad45..f29a26e 100644 (file)
 | 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 (executable)
index 0000000..be58eb4
--- /dev/null
@@ -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 (file)
index 0000000..bcf5764
--- /dev/null
@@ -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}
index 7045b35..2a54da4 100644 (file)
@@ -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\