summaryrefslogtreecommitdiffstats
path: root/src/vnet/gso
AgeCommit message (Expand)AuthorFilesLines
2020-04-22gso: add vxlan tunnel supportMohsin Kazmi5-124/+605
2020-03-30gso: fix the header parser to read onlyMohsin Kazmi1-2/+0
2020-01-16gso: fix typo in the quad-loopSteven Luong1-3/+3
2020-01-10gso: add FEATURE.yamlMohsin Kazmi1-0/+12
2020-01-02gso: fix number of buffers required for segmentationMohsin Kazmi1-3/+4
2019-12-17gso: minor fixes to gso segmentationMohsin Kazmi1-110/+115
2019-12-10api: multiple connections per processDave Barach1-1/+1
2019-12-05gso: add protocol header parserMohsin Kazmi3-24/+121
2019-10-24gso: fix buffers traceBenoƮt Ganne1-0/+1
2019-10-14gso: Add gso feature arcMohsin Kazmi6-0/+1018
ref='#n8'>8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
# Copyright (c) 2021 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 IntEnum

from resources.libraries.python.Constants import Constants
from resources.libraries.python.IPUtil import IpDscp
from resources.libraries.python.PapiExecutor import PapiSocketExecutor
from resources.libraries.python.topology import Topology


class PolicerRateType(IntEnum):
    """Policer rate types."""
    KBPS = 0
    PPS = 1
    INVALID = 2


class PolicerRoundType(IntEnum):
    """Policer round types."""
    ROUND_TO_CLOSEST = 0
    ROUND_TO_UP = 1
    ROUND_TO_DOWN = 2
    ROUND_INVALID = 3


class PolicerType(IntEnum):
    """Policer type."""
    TYPE_1R2C = 0
    TYPE_1R3C_RFC_2697 = 1
    TYPE_2R3C_RFC_2698 = 2
    TYPE_2R3C_RFC_4115 = 3
    TYPE_2R3C_RFC_MEF5CF1 = 4
    TYPE_MAX = 5


class PolicerAction(IntEnum):
    """Policer action."""
    DROP = 0
    TRANSMIT = 1
    MARK_AND_TRANSMIT = 2


class PolicerPreColor(IntEnum):
    """Policer Pre-color."""
    CONFORM_COLOR = 0
    EXCEED_COLOR = 1
    VIOLATE_COLOR = 2


class Policer:
    """Policer utilities."""

    # TODO: Pylint says too-many-arguments and too-many-locals.
    # It is right, we should refactor the code
    # and group similar arguments together (into documented classes).
    # Note that even the call from Robot Framework
    # is not very readable with this many arguments.
    @staticmethod
    def policer_set_configuration(
            node, policer_name, cir, eir, cbs, ebs, rate_type, round_type,
            policer_type, conform_action_type, exceed_action_type,
            violate_action_type, color_aware, is_add=True, conform_dscp=None,
            exceed_dscp=None, violate_dscp=None):
        """Configure policer on VPP node.

        :param node: VPP node.
        :param policer_name: Name of the policer.
        :param cir: Committed information rate.
        :param eir: Excess (or Peak) information rate.
        :param cbs: Committed burst size.
        :param ebs: Excess (or Peak) burst size.
        :param rate_type: Rate type.
        :param round_type: Round type.
        :param policer_type: Policer algorithm.
        :param conform_action_type: Conform action type.
        :param exceed_action_type: Exceed action type.
        :param violate_action_type: Violate action type.
        :param color_aware: Color-blind (cb) or color-aware (ca).
        :param is_add: Add policer if True, else delete.
        :param conform_dscp: DSCP for conform mark_and_transmit action.
        :param exceed_dscp: DSCP for exceed mark_and_transmit action.
        :param violate_dscp: DSCP for vilate mark_and_transmit action.
        :type node: dict
        :type policer_name: str
        :type cir: int
        :type eir: int
        :type cbs: int
        :type ebs: int
        :type rate_type: str
        :type round_type: str
        :type policer_type: str
        :type conform_action_type: str
        :type exceed_action_type: str
        :type violate_action_type: str
        :type color_aware: str
        :type is_add: bool
        :type conform_dscp: str
        :type exceed_dscp: str
        :type violate_dscp: str
        """
        conform_action = dict(
            type=getattr(PolicerAction, conform_action_type.upper()).value,
            dscp=Policer.get_dscp_num_value(conform_dscp) if
            conform_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
            else 0
        )
        exceed_action = dict(
            type=getattr(PolicerAction, exceed_action_type.upper()).value,
            dscp=Policer.get_dscp_num_value(exceed_dscp) if
            exceed_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
            else 0
        )
        violate_action = dict(
            type=getattr(PolicerAction, violate_action_type.upper()).value,
            dscp=Policer.get_dscp_num_value(violate_dscp) if
            violate_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
            else 0
        )

        cmd = u"policer_add_del"
        args = dict(
            is_add=is_add,
            name=str(policer_name),
            cir=int(cir),
            eir=int(eir),
            cb=int(cbs),
            eb=int(ebs),
            rate_type=getattr(PolicerRateType, rate_type.upper()).value,
            round_type=getattr(
                PolicerRoundType, f"ROUND_TO_{round_type.upper()}"
            ).value,
            type=getattr(PolicerType, f"TYPE_{policer_type.upper()}").value,
            conform_action=conform_action,
            exceed_action=exceed_action,
            violate_action=violate_action,
            color_aware=bool(color_aware == u"'ca'")
        )
        err_msg = f"Failed to configure policer {policer_name} " \
            f"on host {node['host']}"

        with PapiSocketExecutor(node) as papi_exec:
            reply = papi_exec.add(cmd, **args).get_reply(err_msg)

        return reply[u"policer_index"]

    @staticmethod
    def policer_classify_set_interface(
            node, interface, ip4_table_index=Constants.BITWISE_NON_ZERO,
            ip6_table_index=Constants.BITWISE_NON_ZERO,
            l2_table_index=Constants.BITWISE_NON_ZERO, is_add=True):
        """Set/unset policer classify interface.

        :param node: VPP node.
        :param interface: Interface name or sw_if_index to set/unset policer
            classify.
        :param ip4_table_index: IP4 classify table index (~0 to skip).
            (Default value = ~0)
        :param ip6_table_index: IP6 classify table index (~0 to skip).
            (Default value = ~0)
        :param l2_table_index: L2 classify table index (~0 to skip).
            (Default value = ~0)
        :param is_add: Set if True, else unset.
        :type node: dict
        :type interface: str or int
        :type ip4_table_index: int
        :type ip6_table_index: int
        :type l2_table_index: int
        :type is_add: bool
        """
        if isinstance(interface, str):
            sw_if_index = Topology.get_interface_sw_index(node, interface)
        else:
            sw_if_index = interface

        cmd = u"policer_classify_set_interface"
        args = dict(
            is_add=is_add,
            sw_if_index=int(sw_if_index),
            ip4_table_index=int(ip4_table_index),
            ip6_table_index=int(ip6_table_index),
            l2_table_index=int(l2_table_index)
        )
        err_msg = f"Failed to set/unset policer classify interface " \
            f"{interface} on host {node[u'host']}"

        with PapiSocketExecutor(node) as papi_exec:
            papi_exec.add(cmd, **args).get_reply(err_msg)

    @staticmethod
    def policer_classify_get_precolor(precolor):
        """Return policer pre-color numeric value.

        :param precolor: Policer pre-color name.
        :type precolor: str
        :returns: Policer pre-color numeric value.
        :rtype: int
        """
        return getattr(PolicerPreColor, precolor.upper()).value

    @staticmethod
    def get_dscp_num_value(dscp):
        """Return DSCP numeric value.

        :param dscp: DSCP name.
        :type dscp: str
        :returns: DSCP numeric value.
        :rtype: int
        """
        return getattr(IpDscp, f"IP_API_DSCP_{dscp.upper()}").value