CSIT-171 CSIT-172 Policer tests initial commit 32/1832/5
authorMatus Fabian <matfabia@cisco.com>
Fri, 1 Jul 2016 11:40:00 +0000 (04:40 -0700)
committerMatus Fabian <matfabia@cisco.com>
Fri, 19 Aug 2016 05:27:36 +0000 (22:27 -0700)
policer python library, traffic script and IPv4/IPv6 example tests

Change-Id: I6470c86ce1acdcaaff9fdcf81510126836f1135e
Signed-off-by: Matus Fabian <matfabia@cisco.com>
resources/libraries/python/Policer.py [new file with mode: 0644]
resources/libraries/robot/policer.robot [new file with mode: 0644]
resources/templates/vat/policer/policer_add_3c.vat [new file with mode: 0644]
resources/templates/vat/policer/policer_classify_add_session.vat [new file with mode: 0644]
resources/templates/vat/policer/policer_classify_set_interface.vat [new file with mode: 0644]
resources/traffic_scripts/policer.py [new file with mode: 0755]
tests/func/policer/policer_ip4.robot [new file with mode: 0644]
tests/func/policer/policer_ip6.robot [new file with mode: 0644]

diff --git a/resources/libraries/python/Policer.py b/resources/libraries/python/Policer.py
new file mode 100644 (file)
index 0000000..6098ac0
--- /dev/null
@@ -0,0 +1,610 @@
+# Copyright (c) 2016 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.
+
+"""Policer utilities library."""
+
+from enum import Enum
+
+from ipaddress import ip_address
+
+from resources.libraries.python.VatExecutor import VatExecutor
+from resources.libraries.python.VatJsonUtil import VatJsonUtil
+from resources.libraries.python.topology import Topology
+
+
+# pylint: disable=too-few-public-methods
+class PolicerRateType(Enum):
+    """Policer rate types."""
+    KBPS = 'kbps'
+    PPS = 'pps'
+
+    def __init__(self, string):
+        self.string = string
+
+
+# pylint: disable=invalid-name
+class PolicerRoundType(Enum):
+    """Policer round types."""
+    CLOSEST = 'closest'
+    UP = 'up'
+    DOWN = 'down'
+
+    def __init__(self, string):
+        self.string = string
+
+
+class PolicerType(Enum):
+    """Policer type."""
+    P_1R2C = '1r2c'
+    P_1R3C = '1r3c'
+    P_2R3C_2698 = '2r3c-2698'
+    P_2R3C_4115 = '2r3c-4115'
+    P_2R3C_MEF5CF1 = '2r3c-mef5cf1'
+
+    def __init__(self, string):
+        self.string = string
+
+
+class PolicerAction(Enum):
+    """Policer action."""
+    DROP = 'drop'
+    TRANSMIT = 'transmit'
+    MARK_AND_TRANSMIT = 'mark-and-transmit'
+
+    def __init__(self, string):
+        self.string = string
+
+
+class DSCP(Enum):
+    """DSCP for mark-and-transmit action."""
+    CS0 = ('CS0', 0)
+    CS1 = ('CS1', 8)
+    CS2 = ('CS2', 16)
+    CS3 = ('CS3', 24)
+    CS4 = ('CS4', 32)
+    CS5 = ('CS5', 40)
+    CS6 = ('CS6', 48)
+    CS7 = ('CS7', 56)
+    AF11 = ('AF11', 10)
+    AF12 = ('AF12', 12)
+    AF13 = ('AF13', 14)
+    AF21 = ('AF21', 18)
+    AF22 = ('AF22', 20)
+    AF23 = ('AF23', 22)
+    AF31 = ('AF31', 26)
+    AF32 = ('AF32', 28)
+    AF33 = ('AF33', 30)
+    EF = ('EF', 46)
+
+    def __init__(self, string, num):
+        self.string = string
+        self.num = num
+
+
+class PolicerClassifyPreColor(Enum):
+    """Policer classify precolor."""
+    CONFORM_COLOR = 'conform-color'
+    EXCEED_COLOR = 'exceed-color'
+
+    def __init__(self, string):
+        self.string = string
+
+
+class PolicerClassifyTableType(Enum):
+    """Policer classify table type."""
+    IP4_TABLE = 'ip4-table'
+    IP6_TABLE = 'ip6-table'
+    L2_TABLE = 'l2-table'
+
+    def __init__(self, string):
+        self.string = string
+
+
+# pylint: disable=too-many-instance-attributes
+# pylint: disable=too-many-public-methods
+class Policer(object):
+    """Policer utilities."""
+
+    def __init__(self):
+        self._cir = 0
+        self._eir = 0
+        self._cb = 0
+        self._eb = 0
+        self._rate_type = None
+        self._round_type = None
+        self._policer_type = None
+        self._conform_action = None
+        self._conform_dscp = None
+        self._exceed_action = None
+        self._exceed_dscp = None
+        self._violate_action = None
+        self._violate_dscp = None
+        self._color_aware = False
+        self._classify_match_ip = ''
+        self._classify_match_is_src = True
+        self._classify_precolor = None
+        self._sw_if_index = 0
+        self._node = None
+        self._policer_name = ''
+
+    def policer_set_configuration(self):
+        """Configure policer on VPP node.
+
+        ...note:: First set all required parameters.
+        """
+        node = self._node
+
+        # create policer
+        color_aware = 'color-aware' if self._color_aware else ''
+
+        # pylint: disable=no-member
+        conform_action = self._conform_action.value
+
+        if PolicerAction.MARK_AND_TRANSMIT == self._conform_action:
+            conform_action += ' {0}'.format(self._conform_dscp.string)
+
+        exceed_action = self._exceed_action.value
+        if PolicerAction.MARK_AND_TRANSMIT == self._exceed_action:
+            exceed_action += ' {0}'.format(self._exceed_dscp.string)
+
+        violate_action = self._violate_action.value
+        if PolicerAction.MARK_AND_TRANSMIT == self._violate_action:
+            violate_action += ' {0}'.format(self._violate_dscp.string)
+
+        out = VatExecutor.cmd_from_template(node,
+                                            "policer/policer_add_3c.vat",
+                                            name=self._policer_name,
+                                            cir=self._cir,
+                                            eir=self._eir,
+                                            cb=self._cb,
+                                            eb=self._eb,
+                                            rate_type=self._rate_type.value,
+                                            round_type=self._round_type.value,
+                                            p_type=self._policer_type.value,
+                                            conform_action=conform_action,
+                                            exceed_action=exceed_action,
+                                            violate_action=violate_action,
+                                            color_aware=color_aware)
+        # pylint: enable=no-member
+
+        VatJsonUtil.verify_vat_retval(
+            out[0],
+            err_msg='Add policer {0} failed on {1}'.format(self._policer_name,
+                                                           node['host']))
+
+        policer_index = out[0].get('policer_index')
+
+        # create classify table
+        direction = 'src' if self._classify_match_is_src else 'dst'
+
+        if 6 == ip_address(unicode(self._classify_match_ip)).version:
+            ip_version = 'ip6'
+            table_type = PolicerClassifyTableType.IP6_TABLE
+        else:
+            ip_version = 'ip4'
+            table_type = PolicerClassifyTableType.IP4_TABLE
+
+        out = VatExecutor.cmd_from_template(node,
+                                            "classify_add_table.vat",
+                                            ip_version=ip_version,
+                                            direction=direction)
+
+        VatJsonUtil.verify_vat_retval(
+            out[0],
+            err_msg='Add classify table failed on {0}'.format(node['host']))
+
+        new_table_index = out[0].get('new_table_index')
+        skip_n_vectors = out[0].get('skip_n_vectors')
+        match_n_vectors = out[0].get('match_n_vectors')
+
+        # create classify session
+        match = 'l3 {0} {1} {2}'.format(ip_version,
+                                        direction,
+                                        self._classify_match_ip)
+
+        out = VatExecutor.cmd_from_template(
+            node,
+            "policer/policer_classify_add_session.vat",
+            policer_index=policer_index,
+            pre_color=self._classify_precolor.value, # pylint: disable=no-member
+            table_index=new_table_index,
+            skip_n=skip_n_vectors,
+            match_n=match_n_vectors,
+            match=match)
+
+        VatJsonUtil.verify_vat_retval(
+            out[0],
+            err_msg='Add classify session failed on {0}'.format(node['host']))
+
+        # set classify interface
+        out = VatExecutor.cmd_from_template(
+            node,
+            "policer/policer_classify_set_interface.vat",
+            sw_if_index=self._sw_if_index,
+            table_type=table_type.value, # pylint: disable=no-member
+            table_index=new_table_index)
+
+        VatJsonUtil.verify_vat_retval(
+            out[0],
+            err_msg='Set classify interface failed on {0}'.format(node['host']))
+
+    def policer_clear_settings(self):
+        """Clear policer settings."""
+        self._cir = 0
+        self._eir = 0
+        self._cb = 0
+        self._eb = 0
+        self._rate_type = None
+        self._round_type = None
+        self._policer_type = None
+        self._conform_action = None
+        self._conform_dscp = None
+        self._exceed_action = None
+        self._exceed_dscp = None
+        self._violate_action = None
+        self._violate_dscp = None
+        self._color_aware = False
+        self._classify_match_ip = ''
+        self._classify_match_is_src = True
+        self._classify_precolor = None
+        self._sw_if_index = 0
+        self._node = None
+        self._policer_name = ''
+
+    def policer_set_name(self, name):
+        """Set policer name.
+
+        :param name: Policer name.
+        :type name: str
+        """
+        self._policer_name = name
+
+    def policer_set_node(self, node):
+        """Set node to setup policer on.
+
+        :param node: VPP node.
+        :type node: dict
+        """
+        self._node = node
+
+    def policer_set_cir(self, cir):
+        """Set policer CIR.
+
+        :param cir: Committed Information Rate.
+        :type cir: int
+        """
+        self._cir = cir
+
+    def policer_set_eir(self, eir):
+        """Set polcier EIR.
+
+        :param eir: Excess Information Rate.
+        :type eir: int
+        """
+        self._eir = eir
+
+    def policer_set_cb(self, cb):
+        """Set policer CB.
+
+        :param cb: Committed Burst size.
+        :type cb: int
+        """
+        self._cb = cb
+
+    def policer_set_eb(self, eb):
+        """Set policer EB.
+
+        :param eb: Excess Burst size.
+        :type eb: int
+        """
+        self._eb = eb
+
+    def policer_set_rate_type_kbps(self):
+        """Set policer rate type to kbps."""
+        self._rate_type = PolicerRateType.KBPS
+
+    def policer_set_rate_type_pps(self):
+        """Set policer rate type to pps."""
+        self._rate_type = PolicerRateType.PPS
+
+    def policer_set_round_type_closest(self):
+        """Set policer round type to closest."""
+        self._round_type = PolicerRoundType.CLOSEST
+
+    def policer_set_round_type_up(self):
+        """Set policer round type to up."""
+        self._round_type = PolicerRoundType.UP
+
+    def policer_set_round_type_down(self):
+        """Set policer round type to down."""
+        self._round_type = PolicerRoundType.DOWN
+
+    def policer_set_type_1r2c(self):
+        """Set policer type to 1r2c."""
+        self._policer_type = PolicerType.P_1R2C
+
+    def policer_set_type_1r3c(self):
+        """Set policer type to 1r3c RFC2697."""
+        self._policer_type = PolicerType.P_1R3C
+
+    def policer_set_type_2r3c_2698(self):
+        """Set policer type to 2r3c RFC2698."""
+        self._policer_type = PolicerType.P_2R3C_2698
+
+    def policer_set_type_2r3c_4115(self):
+        """Set policer type to 2r3c RFC4115."""
+        self._policer_type = PolicerType.P_2R3C_4115
+
+    def policer_set_type_2r3c_mef5cf1(self):
+        """Set policer type to 2r3c MEF5CF1."""
+        self._policer_type = PolicerType.P_2R3C_MEF5CF1
+
+    def policer_set_conform_action_drop(self):
+        """Set policer conform-action to drop."""
+        self._conform_action = PolicerAction.DROP
+
+    def policer_set_conform_action_transmit(self):
+        """Set policer conform-action to transmit."""
+        self._conform_action = PolicerAction.TRANSMIT
+
+    def policer_set_conform_action_mark_and_transmit(self, dscp):
+        """Set policer conform-action to mark-and-transmit.
+
+        :param dscp: DSCP value to mark.
+        :type dscp: DSCP
+        """
+        self._conform_action = PolicerAction.MARK_AND_TRANSMIT
+        self._conform_dscp = dscp
+
+    def policer_set_exceed_action_drop(self):
+        """Set policer exceed-action to drop."""
+        self._exceed_action = PolicerAction.DROP
+
+    def policer_set_exceed_action_transmit(self):
+        """Set policer exceed-action to transmit."""
+        self._exceed_action = PolicerAction.TRANSMIT
+
+    def policer_set_exceed_action_mark_and_transmit(self, dscp):
+        """Set policer exceed-action to mark-and-transmit.
+
+        :param dscp: DSCP value to mark.
+        :type dscp: DSCP
+        """
+        self._exceed_action = PolicerAction.MARK_AND_TRANSMIT
+        self._exceed_dscp = dscp
+
+    def policer_set_violate_action_drop(self):
+        """Set policer violate-action to drop."""
+        self._violate_action = PolicerAction.DROP
+
+    def policer_set_violate_action_transmit(self):
+        """Set policer violate-action to transmit."""
+        self._violate_action = PolicerAction.TRANSMIT
+
+    def policer_set_violate_action_mark_and_transmit(self, dscp):
+        """Set policer violate-action to mark-and-transmit.
+
+        :param dscp: DSCP value to mark.
+        :type dscp: DSCP
+        """
+        self._violate_action = PolicerAction.MARK_AND_TRANSMIT
+        self._violate_dscp = dscp
+
+    def policer_enable_color_aware(self):
+        """Enable color-aware mode for policer."""
+        self._color_aware = True
+
+    def policer_classify_set_precolor_conform(self):
+        """Set policer classify pre-color to conform-color."""
+        self._classify_precolor = PolicerClassifyPreColor.CONFORM_COLOR
+
+    def policer_classify_set_precolor_exceed(self):
+        """Set policer classify pre-color to exceeed-color."""
+        self._classify_precolor = PolicerClassifyPreColor.EXCEED_COLOR
+
+    def policer_classify_set_interface(self, interface):
+        """Set policer classify interface.
+
+        :param interface: Interface name or sw_if_index.
+        :type interface: str or int
+        .. note:: First set node with policer_set_node.
+        """
+        if isinstance(interface, basestring):
+            self._sw_if_index = Topology.get_interface_sw_index(self._node,
+                                                                interface)
+        else:
+            self._sw_if_index = interface
+
+    def policer_classify_set_match_ip(self, ip, is_src=True):
+        """Set policer classify match source IP address.
+
+        :param ip: IPv4 or IPv6 address.
+        :param is_src: Match src IP if True otherwise match dst IP.
+        :type ip: str
+        :type is_src: bool
+        """
+        self._classify_match_ip = ip
+        self._classify_match_is_src = is_src
+
+    @staticmethod
+    def dscp_cs0():
+        """Return DSCP CS0.
+
+        :return: DSCP enum CS0 object.
+        :rtype: DSCP
+        """
+        return DSCP.CS0
+
+    @staticmethod
+    def dscp_cs1():
+        """Return DSCP CS1.
+
+        :return: DSCP enum CS1 object.
+        :rtype: DSCP
+        """
+        return DSCP.CS1
+
+    @staticmethod
+    def dscp_cs2():
+        """Return DSCP CS2.
+
+        :return: DSCP enum CS2 object.
+        :rtype: DSCP
+        """
+        return DSCP.CS2
+
+    @staticmethod
+    def dscp_cs3():
+        """Return DSCP CS3.
+
+        :return: DSCP enum CS3 object.
+        :rtype: DSCP
+        """
+        return DSCP.CS3
+
+    @staticmethod
+    def dscp_cs4():
+        """Return DSCP CS4.
+
+        :return: DSCP enum CS4 object.
+        :rtype: DSCP
+        """
+        return DSCP.CS4
+
+    @staticmethod
+    def dscp_cs5():
+        """Return DSCP CS5.
+
+        :return: DSCP enum CS5 object.
+        :rtype: DSCP
+        """
+        return DSCP.CS5
+
+    @staticmethod
+    def dscp_cs6():
+        """Return DSCP CS6.
+
+        :return: DSCP enum CS6 object.
+        :rtype: DSCP
+        """
+        return DSCP.CS6
+
+    @staticmethod
+    def dscp_cs7():
+        """Return DSCP CS7.
+
+        :return: DSCP enum CS7 object.
+        :rtype: DSCP
+        """
+        return DSCP.CS7
+
+    @staticmethod
+    def dscp_ef():
+        """Return DSCP EF.
+
+        :return: DSCP enum EF object.
+        :rtype: DSCP
+        """
+        return DSCP.EF
+
+    @staticmethod
+    def dscp_af11():
+        """Return DSCP AF11.
+
+        :return: DSCP enum AF11 object.
+        :rtype: DSCP
+        """
+        return DSCP.AF11
+
+    @staticmethod
+    def dscp_af12():
+        """Return DSCP AF12.
+
+        :return: DSCP enum AF12 object.
+        :rtype: DSCP
+        """
+        return DSCP.AF12
+
+    @staticmethod
+    def dscp_af13():
+        """Return DSCP AF13.
+
+        :return: DSCP enum AF13 object.
+        :rtype: DSCP
+        """
+        return DSCP.AF13
+
+    @staticmethod
+    def dscp_af21():
+        """Return DSCP AF21.
+
+        :return: DSCP enum AF21 object.
+        :rtype: DSCP
+        """
+        return DSCP.AF21
+
+    @staticmethod
+    def dscp_af22():
+        """Return DSCP AF22.
+
+        :return: DSCP enum AF22 object.
+        :rtype: DSCP
+        """
+        return DSCP.AF22
+
+    @staticmethod
+    def dscp_af23():
+        """Return DSCP AF23.
+
+        :return: DSCP enum AF23 object.
+        :rtype: DSCP
+        """
+        return DSCP.AF23
+
+    @staticmethod
+    def dscp_af31():
+        """Return DSCP AF31.
+
+        :return: DSCP enum AF31 object.
+        :rtype: DSCP
+        """
+        return DSCP.AF31
+
+    @staticmethod
+    def dscp_af32():
+        """Return DSCP AF32.
+
+        :return: DSCP enum AF32 object.
+        :rtype: DSCP
+        """
+        return DSCP.AF32
+
+    @staticmethod
+    def dscp_af33():
+        """Return DSCP AF33.
+
+        :return: DSCP enum AF33 object.
+        :rtype: DSCP
+        """
+        return DSCP.AF33
+
+    @staticmethod
+    def get_dscp_num_value(dscp):
+        """Return DSCP numeric value.
+
+        :param dscp: DSCP enum object.
+        :type dscp: DSCP
+        :return: DSCP numeric value.
+        :rtype: int
+        """
+        return dscp.num
diff --git a/resources/libraries/robot/policer.robot b/resources/libraries/robot/policer.robot
new file mode 100644 (file)
index 0000000..bf67ab7
--- /dev/null
@@ -0,0 +1,99 @@
+# Copyright (c) 2016 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/default.robot
+| Resource | resources/libraries/robot/testing_path.robot
+| Library | resources.libraries.python.Policer
+| Library | resources.libraries.python.InterfaceUtil
+| Library | resources.libraries.python.IPv4Util
+| Library | resources.libraries.python.TrafficScriptExecutor
+| Library | resources.libraries.python.IPv6Util
+| Library | resources.libraries.python.IPv6Setup
+| Library | resources.libraries.python.IPv4Setup.Dut | ${nodes['DUT1']}
+| ...     | WITH NAME | dut1_v4
+| Documentation | *Policer keywords*
+
+*** Keywords ***
+| Setup Topology for IPv4 policer testing
+| | [Documentation] | Setup topology for IPv4 policer testing.
+| | ...
+| | ... | _NOTE:_ This KW sets following test case variables:
+| | ... | - dut_to_tg_if1_ip - DUT first interface IP address. Type: string
+| | ... | - dut_to_tg_if2_ip - DUT second interface IP address. Type: string
+| | ... | - tg_to_dut_if1_ip - TG first interface IP address. Type: string
+| | ... | - tg_to_dut_if2_ip - TG second interface IP address. Type: string
+| | Path for 2-node testing is set | ${nodes['TG']} | ${nodes['DUT1']}
+| | ...                            | ${nodes['TG']}
+| | Interfaces in 2-node path are up
+| | Set Interface Address | ${dut_node} | ${dut_to_tg_if1}
+| | ...                   | ${dut_to_tg_if1_ip4} | ${ip4_plen}
+| | Set Interface Address | ${dut_node} | ${dut_to_tg_if2}
+| | ...                   | ${dut_to_tg_if2_ip4} | ${ip4_plen}
+| | dut1_v4.Set ARP | ${dut_to_tg_if2} | ${tg_to_dut_if2_ip4}
+| | ...             | ${tg_to_dut_if2_mac}
+| | Set Test Variable | ${dut_to_tg_if1_ip} | ${dut_to_tg_if1_ip4}
+| | Set Test Variable | ${dut_to_tg_if2_ip} | ${dut_to_tg_if2_ip4}
+| | Set Test Variable | ${tg_to_dut_if1_ip} | ${tg_to_dut_if1_ip4}
+| | Set Test Variable | ${tg_to_dut_if2_ip} | ${tg_to_dut_if2_ip4}
+
+| Setup Topology for IPv6 policer testing
+| | [Documentation] | Setup topology for IPv6 policer testing.
+| | ...
+| | ... | _NOTE:_ This KW sets following test case variables:
+| | ... | - dut_to_tg_if1_ip - DUT first interface IP address. Type: string
+| | ... | - dut_to_tg_if2_ip - DUT second interface IP address. Type: string
+| | ... | - tg_to_dut_if1_ip - TG first interface IP address. Type: string
+| | ... | - tg_to_dut_if2_ip - TG second interface IP address. Type: string
+| | Path for 2-node testing is set | ${nodes['TG']} | ${nodes['DUT1']}
+| | ...                            | ${nodes['TG']}
+| | Interfaces in 2-node path are up
+| | Vpp Set If IPv6 Addr | ${dut_node} | ${dut_to_tg_if1}
+| | ...                  | ${dut_to_tg_if1_ip6} | ${ip6_plen}
+| | Vpp Set If IPv6 Addr | ${dut_node} | ${dut_to_tg_if2}
+| | ...                  | ${dut_to_tg_if2_ip6} | ${ip6_plen}
+| | Add IP Neighbor | ${dut_node} | ${dut_to_tg_if2} | ${tg_to_dut_if2_ip6}
+| | ...             | ${tg_to_dut_if2_mac}
+| | Vpp All RA Suppress Link Layer | ${nodes}
+| | Set Test Variable | ${dut_to_tg_if1_ip} | ${dut_to_tg_if1_ip6}
+| | Set Test Variable | ${dut_to_tg_if2_ip} | ${dut_to_tg_if2_ip6}
+| | Set Test Variable | ${tg_to_dut_if1_ip} | ${tg_to_dut_if1_ip6}
+| | Set Test Variable | ${tg_to_dut_if2_ip} | ${tg_to_dut_if2_ip6}
+
+| Send Packet and Verify Marking
+| | [Documentation] | Send packet and verify DSCP of the received packet.
+| | ...
+| | ... | *Arguments:*
+| | ... | - node - TG node. Type: dictionary
+| | ... | - tx_if - TG transmit interface. Type: string
+| | ... | - rx_if - TG receive interface. Type: string
+| | ... | - src_mac - Packet source MAC. Type: string
+| | ... | - dst_mac - Packet destination MAC. Type: string
+| | ... | - src_ip - Packet source IP address. Type: string
+| | ... | - dst_ip - Packet destination IP address. Type: string
+| | ... | - dscp - DSCP value to verify. Type: enum
+| | ...
+| | ... | *Example:*
+| | ... | \| ${dscp}= \| DSCP AF22 \|
+| | ... | \| Send Packet and Verify Marking \| ${nodes['TG']} \| eth1 \| eth2 \
+| | ... | \| 08:00:27:87:4d:f7 \| 52:54:00:d4:d8:22 \| 192.168.122.2 \
+| | ... | \| 192.168.122.1 \| ${dscp} \|
+| | [Arguments] | ${node} | ${tx_if} | ${rx_if} | ${src_mac} | ${dst_mac}
+| | ...         | ${src_ip} | ${dst_ip} | ${dscp}
+| | ${tx_if_name}= | Get Interface Name | ${node} | ${tx_if}
+| | ${rx_if_name}= | Get Interface Name | ${node} | ${rx_if}
+| | ${args}= | Traffic Script Gen Arg | ${rx_if_name} | ${tx_if_name}
+| | ...      | ${src_mac} | ${dst_mac} | ${src_ip} | ${dst_ip}
+| | ${dscp_num}= | Get DSCP Num Value | ${dscp}
+| | ${args}= | Set Variable | ${args} --dscp ${dscp_num}
+| | Run Traffic Script On Node | policer.py | ${node} | ${args}
diff --git a/resources/templates/vat/policer/policer_add_3c.vat b/resources/templates/vat/policer/policer_add_3c.vat
new file mode 100644 (file)
index 0000000..a1a4ade
--- /dev/null
@@ -0,0 +1 @@
+policer_add_del name {name}  cir {cir} eir {eir} cb {cb} eb {eb} rate_type {rate_type} round_type {round_type} type {p_type} conform_action {conform_action} exceed_action {exceed_action} violate_action {violate_action} {color_aware}
diff --git a/resources/templates/vat/policer/policer_classify_add_session.vat b/resources/templates/vat/policer/policer_classify_add_session.vat
new file mode 100644 (file)
index 0000000..7ba466d
--- /dev/null
@@ -0,0 +1 @@
+classify_add_del_session policer-hit-next {policer_index} {pre_color} table-index {table_index} skip_n {skip_n} match_n {match_n} match {match}
diff --git a/resources/templates/vat/policer/policer_classify_set_interface.vat b/resources/templates/vat/policer/policer_classify_set_interface.vat
new file mode 100644 (file)
index 0000000..d0141c9
--- /dev/null
@@ -0,0 +1 @@
+policer_classify_set_interface sw_if_index {sw_if_index} {table_type} {table_index}
diff --git a/resources/traffic_scripts/policer.py b/resources/traffic_scripts/policer.py
new file mode 100755 (executable)
index 0000000..ee9fa29
--- /dev/null
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016 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.
+
+"""Traffic script for IPsec verification."""
+
+import sys
+import logging
+
+# pylint: disable=no-name-in-module
+# pylint: disable=import-error
+logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
+from scapy.all import Ether, IP, IPv6, TCP
+from ipaddress import ip_address
+
+from resources.libraries.python.TrafficScriptArg import TrafficScriptArg
+from resources.libraries.python.PacketVerifier import RxQueue, TxQueue
+
+
+def check_ipv4(pkt_recv, dscp):
+    """Check received IPv4 IPsec packet.
+
+    :param pkt_recv: Received packet to verify.
+    :param dscp: DSCP value to check.
+    :type pkt_recv: scapy.Ether
+    :type dscp: int
+    :raises RuntimeError: If received packet is invalid.
+    """
+    if not pkt_recv.haslayer(IP):
+        raise RuntimeError(
+            'Not an IPv4 packet received: {0}'.format(pkt_recv.__repr__()))
+
+    rx_dscp = pkt_recv['IP'].tos >> 2
+    if rx_dscp != dscp:
+        raise RuntimeError(
+            'Invalid DSCP {0} should be {1}'.format(rx_dscp, dscp))
+
+    if not pkt_recv.haslayer(TCP):
+        raise RuntimeError(
+            'Not a TCP packet received: {0}'.format(pkt_recv.__repr__()))
+
+
+def check_ipv6(pkt_recv, dscp):
+    """Check received IPv6 IPsec packet.
+
+    :param pkt_recv: Received packet to verify.
+    :param dscp: DSCP value to check.
+    :type pkt_recv: scapy.Ether
+    :type dscp: int
+    :raises RuntimeError: If received packet is invalid.
+    """
+    if not pkt_recv.haslayer(IPv6):
+        raise RuntimeError(
+            'Not an IPv6 packet received: {0}'.format(pkt_recv.__repr__()))
+
+    rx_dscp = pkt_recv['IPv6'].tc >> 2
+    if rx_dscp != dscp:
+        raise RuntimeError(
+            'Invalid DSCP {0} should be {1}'.format(rx_dscp, dscp))
+
+    if not pkt_recv.haslayer(TCP):
+        raise RuntimeError(
+            'Not a TCP packet received: {0}'.format(pkt_recv.__repr__()))
+
+
+# pylint: disable=too-many-locals
+# pylint: disable=too-many-statements
+def main():
+    """Send and receive TCP packet."""
+    args = TrafficScriptArg(['src_mac', 'dst_mac', 'src_ip', 'dst_ip', 'dscp'])
+
+    rxq = RxQueue(args.get_arg('rx_if'))
+    txq = TxQueue(args.get_arg('tx_if'))
+
+    src_mac = args.get_arg('src_mac')
+    dst_mac = args.get_arg('dst_mac')
+    src_ip = args.get_arg('src_ip')
+    dst_ip = args.get_arg('dst_ip')
+    dscp = int(args.get_arg('dscp'))
+
+    if 6 == ip_address(unicode(src_ip)).version:
+        is_ipv4 = False
+    else:
+        is_ipv4 = True
+
+    sent_packets = []
+
+    if is_ipv4:
+        ip_pkt = IP(src=src_ip, dst=dst_ip) / \
+                 TCP()
+    else:
+        ip_pkt = IPv6(src=src_ip, dst=dst_ip) / \
+                 TCP()
+
+    pkt_send = Ether(src=src_mac, dst=dst_mac) / \
+               ip_pkt
+
+    sent_packets.append(pkt_send)
+    txq.send(pkt_send)
+
+    pkt_recv = rxq.recv(2, sent_packets)
+
+    if pkt_recv is None:
+        raise RuntimeError('Rx timeout')
+
+    if is_ipv4:
+        check_ipv4(pkt_recv, dscp)
+    else:
+        check_ipv6(pkt_recv, dscp)
+
+    sys.exit(0)
+
+if __name__ == "__main__":
+    main()
diff --git a/tests/func/policer/policer_ip4.robot b/tests/func/policer/policer_ip4.robot
new file mode 100644 (file)
index 0000000..28023b8
--- /dev/null
@@ -0,0 +1,74 @@
+# Copyright (c) 2016 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 ***
+| Force Tags | 3_NODE_DOUBLE_LINK_TOPO | VM_ENV | HW_ENV
+| Resource | resources/libraries/robot/policer.robot
+| Library | resources.libraries.python.Trace
+| Test Setup | Run Keywords | Setup all DUTs before test
+| ...        | AND          | Setup all TGs before traffic script
+| ...        | AND          | Setup Topology for IPv4 policer testing
+| Test Teardown | Run Keywords | Show Packet Trace on All DUTs | ${nodes}
+| ...           | AND          | Show vpp trace dump on all DUTs
+| Documentation | *IPv4 policer test cases*
+| ...
+| ... | *[Top] Network topologies:* TG=DUT1 2-node topology with two links\
+| ... | between nodes.
+| ... | *[Cfg] DUT configuration:* On DUT1 configure interfaces IPv4 adresses,\
+| ... | and static ARP record on the second interface.
+| ... | *[Ver] TG verification:* Test packet is sent from TG on the first link\
+| ... | to DUT1. Packet is received on TG on the second link from DUT1.
+| ... | *[Ref] Applicable standard specifications:* RFC2474, RFC2697, RFC2698.
+
+*** Variables ***
+| ${tg_to_dut_if1_ip4}= | 192.168.122.2
+| ${tg_to_dut_if2_ip4}= | 192.168.123.2
+| ${dut_to_tg_if1_ip4}= | 192.168.122.1
+| ${dut_to_tg_if2_ip4}= | 192.168.123.1
+| ${ip4_plen}= | ${24}
+
+*** Test Cases ***
+| TC01: VPP policer marks packet
+| | [Documentation]
+| | ... | [Top] TG=DUT1.
+| | ... | [Ref] RFC2474, RFC2698.
+| | ... | [Cfg] On DUT1 configure 2R3C color-aware policer on the first\
+| | ... | interface.
+| | ... | [Ver] TG sends IPv4 TCP packet on the first link to DUT1, verify if\
+| | ... | DUT1 sends correct IPv4 TCP packet with correct DSCP on the second\
+| | ... | link to TG.
+| | ${cir}= | Set Variable | ${100}
+| | ${eir}= | Set Variable | ${100}
+| | ${cb}= | Set Variable | ${100}
+| | ${eb}= | Set Variable | ${100}
+| | ${dscp}= | DSCP AF22
+| | Given Policer Set Name | policer1
+| | And Policer Set Node | ${dut_node}
+| | And Policer Set CIR | ${cir}
+| | And Policer Set EIR | ${eir}
+| | And Policer Set CB | ${cb}
+| | And Policer Set EB | ${eb}
+| | And Policer Set Rate Type pps
+| | And Policer Set Round Type Closest
+| | And Policer Set Type 2R3C 2698
+| | And Policer Set Conform Action Transmit
+| | And Policer Set Exceed Action Mark and Transmit | ${dscp}
+| | And Policer Set Violate Action Drop
+| | And Policer Enable Color Aware
+| | And Policer Classify Set Precolor Exceed
+| | And Policer Classify Set Interface | ${dut_to_tg_if1}
+| | And Policer Classify Set Match IP | ${tg_to_dut_if1_ip}
+| | When Policer Set Configuration
+| | Then Send Packet and Verify Marking | ${tg_node} | ${tg_to_dut_if1}
+| | ... | ${tg_to_dut_if2} | ${tg_to_dut_if1_mac} | ${dut_to_tg_if1_mac}
+| | ... | ${tg_to_dut_if1_ip} | ${tg_to_dut_if2_ip} | ${dscp}
diff --git a/tests/func/policer/policer_ip6.robot b/tests/func/policer/policer_ip6.robot
new file mode 100644 (file)
index 0000000..fb4fa9c
--- /dev/null
@@ -0,0 +1,74 @@
+# Copyright (c) 2016 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.
+
+*** Variables ***
+| ${tg_to_dut_if1_ip6}= | 3ffe:5f::2
+| ${tg_to_dut_if2_ip6}= | 3ffe:60::2
+| ${dut_to_tg_if1_ip6}= | 3ffe:5f::1
+| ${dut_to_tg_if2_ip6}= | 3ffe:60::1
+| ${ip6_plen}= | ${64}
+
+*** Settings ***
+| Force Tags | 3_NODE_DOUBLE_LINK_TOPO | VM_ENV | HW_ENV
+| Resource | resources/libraries/robot/policer.robot
+| Library | resources.libraries.python.Trace
+| Test Setup | Run Keywords | Setup all DUTs before test
+| ...        | AND          | Setup all TGs before traffic script
+| ...        | AND          | Setup Topology for IPv6 policer testing
+| Test Teardown | Run Keywords | Show Packet Trace on All DUTs | ${nodes}
+| ...           | AND          | Show vpp trace dump on all DUTs
+| Documentation | *IPv6 policer test cases*
+| ...
+| ... | *[Top] Network topologies:* TG=DUT1 2-node topology with two links\
+| ... | between nodes.
+| ... | *[Cfg] DUT configuration:* On DUT1 configure interfaces IPv6 adresses,\
+| ... | and static neighbor record on the second interface.
+| ... | *[Ver] TG verification:* Test packet is sent from TG on the first link\
+| ... | to DUT1. Packet is received on TG on the second link from DUT1.
+| ... | *[Ref] Applicable standard specifications:* RFC2474, RFC2697, RFC2698.
+
+*** Test Cases ***
+| TC01: VPP policer marks packet
+| | [Documentation]
+| | ... | [Top] TG=DUT1.
+| | ... | [Ref] RFC2474, RFC2698.
+| | ... | [Cfg] On DUT1 configure 2R3C color-aware policer on the first\
+| | ... | interface.
+| | ... | [Ver] TG sends IPv6 TCP packet on the first link to DUT1, verify if\
+| | ... | DUT1 sends correct IPv6 TCP packet with correct DSCP on the second\
+| | ... | link to TG.
+| | ${cir}= | Set Variable | ${100}
+| | ${eir}= | Set Variable | ${100}
+| | ${cb}= | Set Variable | ${100}
+| | ${eb}= | Set Variable | ${100}
+| | ${dscp}= | DSCP AF22
+| | Given Policer Set Name | policer1
+| | And Policer Set Node | ${dut_node}
+| | And Policer Set CIR | ${cir}
+| | And Policer Set EIR | ${eir}
+| | And Policer Set CB | ${cb}
+| | And Policer Set EB | ${eb}
+| | And Policer Set Rate Type pps
+| | And Policer Set Round Type Closest
+| | And Policer Set Type 2R3C 2698
+| | And Policer Set Conform Action Transmit
+| | And Policer Set Exceed Action Mark and Transmit | ${dscp}
+| | And Policer Set Violate Action Drop
+| | And Policer Enable Color Aware
+| | And Policer Classify Set Precolor Exceed
+| | And Policer Classify Set Interface | ${dut_to_tg_if1}
+| | And Policer Classify Set Match IP | ${tg_to_dut_if1_ip}
+| | When Policer Set Configuration
+| | Then Send Packet and Verify Marking | ${tg_node} | ${tg_to_dut_if1}
+| | ... | ${tg_to_dut_if2} | ${tg_to_dut_if1_mac} | ${dut_to_tg_if1_mac}
+| | ... | ${tg_to_dut_if1_ip} | ${tg_to_dut_if2_ip} | ${dscp}