From c9d198a9f6494558574238dd055a14ef3a251d31 Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Fri, 1 Jul 2016 04:40:00 -0700 Subject: [PATCH] CSIT-171 CSIT-172 Policer tests initial commit policer python library, traffic script and IPv4/IPv6 example tests Change-Id: I6470c86ce1acdcaaff9fdcf81510126836f1135e Signed-off-by: Matus Fabian --- resources/libraries/python/Policer.py | 610 +++++++++++++++++++++ resources/libraries/robot/policer.robot | 99 ++++ resources/templates/vat/policer/policer_add_3c.vat | 1 + .../vat/policer/policer_classify_add_session.vat | 1 + .../vat/policer/policer_classify_set_interface.vat | 1 + resources/traffic_scripts/policer.py | 125 +++++ tests/func/policer/policer_ip4.robot | 74 +++ tests/func/policer/policer_ip6.robot | 74 +++ 8 files changed, 985 insertions(+) create mode 100644 resources/libraries/python/Policer.py create mode 100644 resources/libraries/robot/policer.robot create mode 100644 resources/templates/vat/policer/policer_add_3c.vat create mode 100644 resources/templates/vat/policer/policer_classify_add_session.vat create mode 100644 resources/templates/vat/policer/policer_classify_set_interface.vat create mode 100755 resources/traffic_scripts/policer.py create mode 100644 tests/func/policer/policer_ip4.robot create mode 100644 tests/func/policer/policer_ip6.robot diff --git a/resources/libraries/python/Policer.py b/resources/libraries/python/Policer.py new file mode 100644 index 0000000000..6098ac0402 --- /dev/null +++ b/resources/libraries/python/Policer.py @@ -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 index 0000000000..bf67ab7894 --- /dev/null +++ b/resources/libraries/robot/policer.robot @@ -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 index 0000000000..a1a4ade0b2 --- /dev/null +++ b/resources/templates/vat/policer/policer_add_3c.vat @@ -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 index 0000000000..7ba466d16d --- /dev/null +++ b/resources/templates/vat/policer/policer_classify_add_session.vat @@ -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 index 0000000000..d0141c9595 --- /dev/null +++ b/resources/templates/vat/policer/policer_classify_set_interface.vat @@ -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 index 0000000000..ee9fa29c4a --- /dev/null +++ b/resources/traffic_scripts/policer.py @@ -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 index 0000000000..28023b8641 --- /dev/null +++ b/tests/func/policer/policer_ip4.robot @@ -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 index 0000000000..fb4fa9ce7c --- /dev/null +++ b/tests/func/policer/policer_ip6.robot @@ -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} -- 2.16.6