Revert "fix(ip6scale): Unify rnd profiles"
[csit.git] / resources / libraries / python / Policer.py
1 # Copyright (c) 2024 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Policer utilities library."""
15
16 from enum import IntEnum
17
18 from resources.libraries.python.Constants import Constants
19 from resources.libraries.python.IPUtil import IpDscp
20 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
21 from resources.libraries.python.topology import Topology
22
23
24 class PolicerRateType(IntEnum):
25     """Policer rate types."""
26     KBPS = 0
27     PPS = 1
28     INVALID = 2
29
30
31 class PolicerRoundType(IntEnum):
32     """Policer round types."""
33     ROUND_TO_CLOSEST = 0
34     ROUND_TO_UP = 1
35     ROUND_TO_DOWN = 2
36     ROUND_INVALID = 3
37
38
39 class PolicerType(IntEnum):
40     """Policer type."""
41     TYPE_1R2C = 0
42     TYPE_1R3C_RFC_2697 = 1
43     TYPE_2R3C_RFC_2698 = 2
44     TYPE_2R3C_RFC_4115 = 3
45     TYPE_2R3C_RFC_MEF5CF1 = 4
46     TYPE_MAX = 5
47
48
49 class PolicerAction(IntEnum):
50     """Policer action."""
51     DROP = 0
52     TRANSMIT = 1
53     MARK_AND_TRANSMIT = 2
54
55
56 class PolicerPreColor(IntEnum):
57     """Policer Pre-color."""
58     CONFORM_COLOR = 0
59     EXCEED_COLOR = 1
60     VIOLATE_COLOR = 2
61
62
63 class Policer:
64     """Policer utilities."""
65
66     # TODO: Pylint says too-many-arguments and too-many-locals.
67     # It is right, we should refactor the code
68     # and group similar arguments together (into documented classes).
69     # Note that even the call from Robot Framework
70     # is not very readable with this many arguments.
71     @staticmethod
72     def policer_set_configuration(
73             node, policer_name, cir, eir, cbs, ebs, rate_type, round_type,
74             policer_type, conform_action_type, exceed_action_type,
75             violate_action_type, color_aware, conform_dscp=None,
76             exceed_dscp=None, violate_dscp=None):
77         """Configure policer on VPP node.
78
79         :param node: VPP node.
80         :param policer_name: Name of the policer.
81         :param cir: Committed information rate.
82         :param eir: Excess (or Peak) information rate.
83         :param cbs: Committed burst size.
84         :param ebs: Excess (or Peak) burst size.
85         :param rate_type: Rate type.
86         :param round_type: Round type.
87         :param policer_type: Policer algorithm.
88         :param conform_action_type: Conform action type.
89         :param exceed_action_type: Exceed action type.
90         :param violate_action_type: Violate action type.
91         :param color_aware: Color-blind (cb) or color-aware (ca).
92         :param conform_dscp: DSCP for conform mark_and_transmit action.
93         :param exceed_dscp: DSCP for exceed mark_and_transmit action.
94         :param violate_dscp: DSCP for vilate mark_and_transmit action.
95         :type node: dict
96         :type policer_name: str
97         :type cir: int
98         :type eir: int
99         :type cbs: int
100         :type ebs: int
101         :type rate_type: str
102         :type round_type: str
103         :type policer_type: str
104         :type conform_action_type: str
105         :type exceed_action_type: str
106         :type violate_action_type: str
107         :type color_aware: str
108         :type conform_dscp: str
109         :type exceed_dscp: str
110         :type violate_dscp: str
111         """
112         conform_action = dict(
113             type=getattr(PolicerAction, conform_action_type.upper()).value,
114             dscp=Policer.get_dscp_num_value(conform_dscp) if
115             conform_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
116             else 0
117         )
118         exceed_action = dict(
119             type=getattr(PolicerAction, exceed_action_type.upper()).value,
120             dscp=Policer.get_dscp_num_value(exceed_dscp) if
121             exceed_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
122             else 0
123         )
124         violate_action = dict(
125             type=getattr(PolicerAction, violate_action_type.upper()).value,
126             dscp=Policer.get_dscp_num_value(violate_dscp) if
127             violate_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
128             else 0
129         )
130
131         cmd = u"policer_add"
132         infos = dict(
133             cir=int(cir),
134             eir=int(eir),
135             cb=int(cbs),
136             eb=int(ebs),
137             rate_type=getattr(PolicerRateType, rate_type.upper()).value,
138             round_type=getattr(
139                 PolicerRoundType, f"ROUND_TO_{round_type.upper()}"
140             ).value,
141             type=getattr(PolicerType, f"TYPE_{policer_type.upper()}").value,
142             conform_action=conform_action,
143             exceed_action=exceed_action,
144             violate_action=violate_action,
145             color_aware=bool(color_aware == u"'ca'")
146         )
147         args = dict(
148             name=str(policer_name),
149             infos=infos,
150         )
151         err_msg = f"Failed to configure policer {policer_name} " \
152             f"on host {node['host']}"
153
154         with PapiSocketExecutor(node) as papi_exec:
155             reply = papi_exec.add(cmd, **args).get_reply(err_msg)
156
157         return reply[u"policer_index"]
158
159     @staticmethod
160     def policer_classify_set_interface(
161             node, interface, ip4_table_index=Constants.BITWISE_NON_ZERO,
162             ip6_table_index=Constants.BITWISE_NON_ZERO,
163             l2_table_index=Constants.BITWISE_NON_ZERO, is_add=True):
164         """Set/unset policer classify interface.
165
166         :param node: VPP node.
167         :param interface: Interface name or sw_if_index to set/unset policer
168             classify.
169         :param ip4_table_index: IP4 classify table index (~0 to skip).
170             (Default value = ~0)
171         :param ip6_table_index: IP6 classify table index (~0 to skip).
172             (Default value = ~0)
173         :param l2_table_index: L2 classify table index (~0 to skip).
174             (Default value = ~0)
175         :param is_add: Set if True, else unset.
176         :type node: dict
177         :type interface: str or int
178         :type ip4_table_index: int
179         :type ip6_table_index: int
180         :type l2_table_index: int
181         :type is_add: bool
182         """
183         if isinstance(interface, str):
184             sw_if_index = Topology.get_interface_sw_index(node, interface)
185         else:
186             sw_if_index = interface
187
188         cmd = u"policer_classify_set_interface"
189         args = dict(
190             is_add=is_add,
191             sw_if_index=int(sw_if_index),
192             ip4_table_index=int(ip4_table_index),
193             ip6_table_index=int(ip6_table_index),
194             l2_table_index=int(l2_table_index)
195         )
196         err_msg = f"Failed to set/unset policer classify interface " \
197             f"{interface} on host {node[u'host']}"
198
199         with PapiSocketExecutor(node) as papi_exec:
200             papi_exec.add(cmd, **args).get_reply(err_msg)
201
202     @staticmethod
203     def policer_classify_get_precolor(precolor):
204         """Return policer pre-color numeric value.
205
206         :param precolor: Policer pre-color name.
207         :type precolor: str
208         :returns: Policer pre-color numeric value.
209         :rtype: int
210         """
211         return getattr(PolicerPreColor, precolor.upper()).value
212
213     @staticmethod
214     def get_dscp_num_value(dscp):
215         """Return DSCP numeric value.
216
217         :param dscp: DSCP name.
218         :type dscp: str
219         :returns: DSCP numeric value.
220         :rtype: int
221         """
222         return getattr(IpDscp, f"IP_API_DSCP_{dscp.upper()}").value