aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Mikus <pmikus@cisco.com>2019-07-29 12:36:18 +0000
committerPeter Mikus <pmikus@cisco.com>2019-08-06 19:03:52 +0000
commit97e93cd29f1a9c01b139e2d7fcc745d37d4bd944 (patch)
treedc4c9b3d6ece3131024e4e146aa4e083cbca60d1
parent11aa6d6cd19b10d43011f1f55362d158aa488888 (diff)
Add: Dot1Q + L2BD + GBP
Change-Id: I0050f715011ecfa92b3ee88b301809a56abb7946 Signed-off-by: Peter Mikus <pmikus@cisco.com>
-rw-r--r--resources/api/vpp/supported_crcs.yaml14
-rw-r--r--resources/libraries/python/Classify.py23
-rw-r--r--resources/libraries/python/GBP.py344
-rw-r--r--resources/libraries/python/InterfaceUtil.py9
-rw-r--r--resources/libraries/python/topology.py3
-rw-r--r--resources/libraries/robot/features/gbp.robot99
-rw-r--r--resources/libraries/robot/shared/default.robot3
-rwxr-xr-xresources/traffic_profiles/trex/trex-sl-dot1qip4-vlan1ip4src254ip4dst254.py116
-rw-r--r--tests/vpp/perf/l2/2n1l-10ge2p1x710-avf-dot1q-l2bdbasemaclrn-gbp-ndrpdr.robot140
-rw-r--r--tests/vpp/perf/l2/2n1l-10ge2p1x710-dot1q-l2bdbasemaclrn-ndrpdr.robot4
10 files changed, 745 insertions, 10 deletions
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\