d5500e1d89220ca841925f5ed18f596efa06447a
[csit.git] / resources / libraries / python / Policer.py
1 # Copyright (c) 2019 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.PapiExecutor import PapiSocketExecutor
20 from resources.libraries.python.topology import Topology
21
22
23 class PolicerRateType(IntEnum):
24     """Policer rate types."""
25     KBPS = 0
26     PPS = 1
27     INVALID = 2
28
29
30 class PolicerRoundType(IntEnum):
31     """Policer round types."""
32     ROUND_TO_CLOSEST = 0
33     ROUND_TO_UP = 1
34     ROUND_TO_DOWN = 2
35     ROUND_TO_INVALID = 3
36
37
38 class PolicerType(IntEnum):
39     """Policer type."""
40     TYPE_1R2C = 0
41     TYPE_1R3C_RFC_2697 = 1
42     TYPE_2R3C_RFC_2698 = 2
43     TYPE_2R3C_RFC_4115 = 3
44     TYPE_2R3C_RFC_MEF5CF1 = 4
45     TYPE_MAX = 5
46
47
48 class PolicerAction(IntEnum):
49     """Policer action."""
50     DROP = 0
51     TRANSMIT = 1
52     MARK_AND_TRANSMIT = 2
53
54
55 class PolicerPreColor(IntEnum):
56     """Policer Pre-color."""
57     CONFORM_COLOR = 0
58     EXCEED_COLOR = 1
59     VIOLATE_COLOR = 2
60
61
62 class DSCP(IntEnum):
63     """DSCP for mark-and-transmit action."""
64     D_CS0 = 0
65     D_CS1 = 8
66     D_CS2 = 16
67     D_CS3 = 24
68     D_CS4 = 32
69     D_vCS5 = 40
70     D_CS6 = 48
71     D_CS7 = 56
72     D_AF11 = 10
73     D_AF12 = 12
74     D_AF13 = 14
75     D_AF21 = 18
76     D_AF22 = 20
77     D_AF23 = 22
78     D_AF31 = 26
79     D_AF32 = 28
80     D_AF33 = 30
81     D_EF = 46
82
83
84 class Policer:
85     """Policer utilities."""
86
87     # TODO: Pylint says too-many-arguments and too-many-locals.
88     # It is right, we should refactor the code
89     # and group similar arguments together (into documented classes).
90     # Note that even the call from Robot Framework
91     # is not very readable with this many arguments.
92     @staticmethod
93     def policer_set_configuration(
94             node, policer_name, cir, eir, cbs, ebs, rate_type, round_type,
95             policer_type, conform_action_type, exceed_action_type,
96             violate_action_type, color_aware, is_add=True, conform_dscp=None,
97             exceed_dscp=None, violate_dscp=None):
98         """Configure policer on VPP node.
99
100         :param node: VPP node.
101         :param policer_name: Name of the policer.
102         :param cir: Committed information rate.
103         :param eir: Excess (or Peak) information rate.
104         :param cbs: Committed burst size.
105         :param ebs: Excess (or Peak) burst size.
106         :param rate_type: Rate type.
107         :param round_type: Round type.
108         :param policer_type: Policer algorithm.
109         :param conform_action_type: Conform action type.
110         :param exceed_action_type: Exceed action type.
111         :param violate_action_type: Violate action type.
112         :param color_aware: Color-blind (cb) or color-aware (ca).
113         :param is_add: Add policer if True, else delete.
114         :param conform_dscp: DSCP for conform mark_and_transmit action.
115         :param exceed_dscp: DSCP for exceed mark_and_transmit action.
116         :param violate_dscp: DSCP for vilate mark_and_transmit action.
117         :type node: dict
118         :type policer_name: str
119         :type cir: int
120         :type eir: int
121         :type cbs: int
122         :type ebs: int
123         :type rate_type: str
124         :type round_type: str
125         :type policer_type: str
126         :type conform_action_type: str
127         :type exceed_action_type: str
128         :type violate_action_type: str
129         :type color_aware: str
130         :type is_add: bool
131         :type conform_dscp: str
132         :type exceed_dscp: str
133         :type violate_dscp: str
134         """
135         cmd = u"policer_add_del"
136         args = dict(
137             is_add=int(is_add),
138             name=str(policer_name).encode(encoding=u"utf-8"),
139             cir=int(cir),
140             eir=int(eir),
141             cb=int(cbs),
142             eb=int(ebs),
143             rate_type=getattr(PolicerRateType, rate_type.upper()).value,
144             round_type=getattr(
145                 PolicerRoundType, f"ROUND_TO_{round_type.upper()}"
146             ).value,
147             type=getattr(PolicerType, f"TYPE_{policer_type.upper()}").value,
148             conform_action_type=getattr(
149                 PolicerAction, conform_action_type.upper()
150             ).value,
151             conform_dscp=getattr(DSCP, f"D_{conform_dscp.upper()}").value
152             if
153             conform_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
154             else 0,
155             exceed_action_type=getattr(
156                 PolicerAction, exceed_action_type.upper()
157             ).value,
158             exceed_dscp=getattr(DSCP, f"D_{exceed_dscp.upper()}").value
159             if
160             exceed_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
161             else 0,
162             violate_action_type=getattr(
163                 PolicerAction, violate_action_type.upper()
164             ).value,
165             violate_dscp=getattr(DSCP, f"D_{violate_dscp.upper()}").value
166             if
167             violate_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
168             else 0,
169             color_aware=1 if color_aware == u"'ca'" else 0
170         )
171         err_msg = f"Failed to configure policer {policer_name} " \
172             f"on host {node['host']}"
173
174         with PapiSocketExecutor(node) as papi_exec:
175             reply = papi_exec.add(cmd, **args).get_reply(err_msg)
176
177         return reply[u"policer_index"]
178
179     @staticmethod
180     def policer_classify_set_interface(
181             node, interface, ip4_table_index=Constants.BITWISE_NON_ZERO,
182             ip6_table_index=Constants.BITWISE_NON_ZERO,
183             l2_table_index=Constants.BITWISE_NON_ZERO, is_add=1):
184         """Set/unset policer classify interface.
185
186         :param node: VPP node.
187         :param interface: Interface name or sw_if_index to set/unset policer
188             classify.
189         :param ip4_table_index: IP4 classify table index (~0 to skip).
190             (Default value = ~0)
191         :param ip6_table_index: IP6 classify table index (~0 to skip).
192             (Default value = ~0)
193         :param l2_table_index: L2 classify table index (~0 to skip).
194             (Default value = ~0)
195         :param is_add: Set if non-zero, else unset.
196         :type node: dict
197         :type interface: str or int
198         :type ip4_table_index: int
199         :type ip6_table_index: int
200         :type l2_table_index: int
201         """
202         if isinstance(interface, str):
203             sw_if_index = Topology.get_interface_sw_index(node, interface)
204         else:
205             sw_if_index = interface
206
207         cmd = u"policer_classify_set_interface"
208         args = dict(
209             is_add=int(is_add),
210             sw_if_index=sw_if_index,
211             ip4_table_index=int(ip4_table_index),
212             ip6_table_index=int(ip6_table_index),
213             l2_table_index=int(l2_table_index)
214         )
215         err_msg = f"Failed to set/unset policer classify interface " \
216             f"{interface} on host {node[u'host']}"
217
218         with PapiSocketExecutor(node) as papi_exec:
219             papi_exec.add(cmd, **args).get_reply(err_msg)
220
221     @staticmethod
222     def policer_classify_get_precolor(precolor):
223         """Return policer pre-color numeric value.
224
225         :param precolor: Policer pre-color name.
226         :type precolor: str
227         :returns: Policer pre-color numeric value.
228         :rtype: int
229         """
230         return getattr(PolicerPreColor, precolor.upper()).value
231
232     @staticmethod
233     def get_dscp_num_value(dscp):
234         """Return DSCP numeric value.
235
236         :param dscp: DSCP name.
237         :type dscp: str
238         :returns: DSCP numeric value.
239         :rtype: int
240         """
241         return getattr(DSCP, f"D_{dscp.upper()}").value