CSIT-1471: Policer - VAT API to PAPI
[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(object):
85     """Policer utilities."""
86
87     # pylint: disable=too-many-arguments, too-many-locals
88     @staticmethod
89     def policer_set_configuration(
90             node, policer_name, cir, eir, cbs, ebs, rate_type, round_type,
91             policer_type, conform_action_type, exceed_action_type,
92             violate_action_type, color_aware, is_add=True, conform_dscp=None,
93             exceed_dscp=None, violate_dscp=None):
94         """Configure policer on VPP node.
95
96         :param node: VPP node.
97         :param policer_name: Name of the policer.
98         :param cir: Committed information rate.
99         :param eir: Excess (or Peak) information rate.
100         :param cbs: Committed burst size.
101         :param ebs: Excess (or Peak) burst size.
102         :param rate_type: Rate type.
103         :param round_type: Round type.
104         :param policer_type: Policer algorithm.
105         :param conform_action_type: Conform action type.
106         :param exceed_action_type: Exceed action type.
107         :param violate_action_type: Violate action type.
108         :param color_aware: Color-blind (cb) or color-aware (ca).
109         :param is_add: Add policer if True, else delete.
110         :param conform_dscp: DSCP for conform mark_and_transmit action.
111         :param exceed_dscp: DSCP for exceed mark_and_transmit action.
112         :param violate_dscp: DSCP for vilate mark_and_transmit action.
113         :type node: dict
114         :type policer_name: str
115         :type cir: int
116         :type eir: int
117         :type cbs: int
118         :type ebs: int
119         :type rate_type: str
120         :type round_type: str
121         :type policer_type: str
122         :type conform_action_type: str
123         :type exceed_action_type: str
124         :type violate_action_type: str
125         :type color_aware: str
126         :type is_add: bool
127         :type conform_dscp: str
128         :type exceed_dscp: str
129         :type violate_dscp: str
130         """
131         cmd = 'policer_add_del'
132         args = dict(
133             is_add=int(is_add),
134             name=str(policer_name),
135             cir=int(cir),
136             eir=int(eir),
137             cb=int(cbs),
138             eb=int(ebs),
139             rate_type=getattr(PolicerRateType, rate_type.upper()).value,
140             round_type=getattr(
141                 PolicerRoundType, 'ROUND_TO_{rt}'.format(
142                     rt=round_type.upper())).value,
143             type=getattr(PolicerType, 'TYPE_{pt}'.format(
144                 pt=policer_type.upper())).value,
145             conform_action_type=getattr(
146                 PolicerAction, conform_action_type.upper()).value,
147             conform_dscp=getattr(DSCP, 'D_{dscp}'.format(
148                 dscp=conform_dscp.upper())).value
149             if
150             conform_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
151             else 0,
152             exceed_action_type=getattr(
153                 PolicerAction, exceed_action_type.upper()).value,
154             exceed_dscp=getattr(DSCP, 'D_{dscp}'.format(
155                 dscp=exceed_dscp.upper())).value
156             if
157             exceed_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
158             else 0,
159             violate_action_type=getattr(
160                 PolicerAction, violate_action_type.upper()).value,
161             violate_dscp=getattr(DSCP, 'D_{dscp}'.format(
162                 dscp=violate_dscp.upper())).value
163             if
164             violate_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name
165             else 0,
166             color_aware=1 if color_aware == "'ca'" else 0
167         )
168         err_msg = 'Failed to configure policer {pn} on host {host}'.format(
169             pn=policer_name, host=node['host'])
170
171         with PapiSocketExecutor(node) as papi_exec:
172             reply = papi_exec.add(cmd, **args).get_reply(err_msg)
173
174         return reply['policer_index']
175
176     @staticmethod
177     def policer_classify_set_interface(
178             node, interface, ip4_table_index=Constants.BITWISE_NON_ZERO,
179             ip6_table_index=Constants.BITWISE_NON_ZERO,
180             l2_table_index=Constants.BITWISE_NON_ZERO, is_add=1):
181         """Set/unset policer classify interface.
182
183         :param node: VPP node.
184         :param interface: Interface name or sw_if_index to set/unset policer
185             classify.
186         :param ip4_table_index: IP4 classify table index (~0 to skip).
187             (Default value = ~0)
188         :param ip6_table_index: IP6 classify table index (~0 to skip).
189             (Default value = ~0)
190         :param l2_table_index: L2 classify table index (~0 to skip).
191             (Default value = ~0)
192         :param is_add: Set if non-zero, else unset.
193         :type node: dict
194         :type interface: str or int
195         :type ip4_table_index: int
196         :type ip6_table_index: int
197         :type l2_table_index: int
198         """
199         if isinstance(interface, basestring):
200             sw_if_index = Topology.get_interface_sw_index(node, interface)
201         else:
202             sw_if_index = interface
203
204         cmd = 'policer_classify_set_interface'
205
206         args = dict(
207             is_add=int(is_add),
208             sw_if_index=sw_if_index,
209             ip4_table_index=int(ip4_table_index),
210             ip6_table_index=int(ip6_table_index),
211             l2_table_index=int(l2_table_index)
212         )
213         err_msg = 'Failed to set/unset policer classify interface {ifc} ' \
214                   'on host {host}'.format(ifc=interface, host=node['host'])
215
216         with PapiSocketExecutor(node) as papi_exec:
217             papi_exec.add(cmd, **args).get_reply(err_msg)
218
219     @staticmethod
220     def policer_classify_get_precolor(precolor):
221         """Return policer pre-color numeric value.
222
223         :param precolor: Policer pre-color name.
224         :type precolor: str
225         :returns: Policer pre-color numeric value.
226         :rtype: int
227         """
228         return getattr(PolicerPreColor, precolor.upper()).value
229
230     @staticmethod
231     def get_dscp_num_value(dscp):
232         """Return DSCP numeric value.
233
234         :param dscp: DSCP name.
235         :type dscp: str
236         :returns: DSCP numeric value.
237         :rtype: int
238         """
239         return getattr(DSCP, 'D_{dscp}'.format(dscp=dscp.upper())).value