Tolerate failures when setting MTU
[csit.git] / resources / libraries / python / Policer.py
1 # Copyright (c) 2018 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 Enum
17
18 from ipaddress import ip_address
19
20 from resources.libraries.python.VatExecutor import VatExecutor
21 from resources.libraries.python.VatJsonUtil import VatJsonUtil
22 from resources.libraries.python.topology import Topology
23
24
25 class PolicerRateType(Enum):
26     """Policer rate types."""
27     KBPS = 'kbps'
28     PPS = 'pps'
29
30     def __init__(self, string):
31         self.string = string
32
33
34 # pylint: disable=invalid-name
35 class PolicerRoundType(Enum):
36     """Policer round types."""
37     CLOSEST = 'closest'
38     UP = 'up'
39     DOWN = 'down'
40
41     def __init__(self, string):
42         self.string = string
43
44
45 class PolicerType(Enum):
46     """Policer type."""
47     P_1R2C = '1r2c'
48     P_1R3C = '1r3c'
49     P_2R3C_2698 = '2r3c-2698'
50     P_2R3C_4115 = '2r3c-4115'
51     P_2R3C_MEF5CF1 = '2r3c-mef5cf1'
52
53     def __init__(self, string):
54         self.string = string
55
56
57 class PolicerAction(Enum):
58     """Policer action."""
59     DROP = 'drop'
60     TRANSMIT = 'transmit'
61     MARK_AND_TRANSMIT = 'mark-and-transmit'
62
63     def __init__(self, string):
64         self.string = string
65
66
67 class DSCP(Enum):
68     """DSCP for mark-and-transmit action."""
69     CS0 = ('CS0', 0)
70     CS1 = ('CS1', 8)
71     CS2 = ('CS2', 16)
72     CS3 = ('CS3', 24)
73     CS4 = ('CS4', 32)
74     CS5 = ('CS5', 40)
75     CS6 = ('CS6', 48)
76     CS7 = ('CS7', 56)
77     AF11 = ('AF11', 10)
78     AF12 = ('AF12', 12)
79     AF13 = ('AF13', 14)
80     AF21 = ('AF21', 18)
81     AF22 = ('AF22', 20)
82     AF23 = ('AF23', 22)
83     AF31 = ('AF31', 26)
84     AF32 = ('AF32', 28)
85     AF33 = ('AF33', 30)
86     EF = ('EF', 46)
87
88     def __init__(self, string, num):
89         self.string = string
90         self.num = num
91
92
93 class PolicerClassifyPreColor(Enum):
94     """Policer classify precolor."""
95     CONFORM_COLOR = 'conform-color'
96     EXCEED_COLOR = 'exceed-color'
97
98     def __init__(self, string):
99         self.string = string
100
101
102 class PolicerClassifyTableType(Enum):
103     """Policer classify table type."""
104     IP4_TABLE = 'ip4-table'
105     IP6_TABLE = 'ip6-table'
106     L2_TABLE = 'l2-table'
107
108     def __init__(self, string):
109         self.string = string
110
111
112 # pylint: disable=too-many-instance-attributes
113 class Policer(object):
114     """Policer utilities."""
115
116     def __init__(self):
117         self._cir = 0
118         self._eir = 0
119         self._cb = 0
120         self._eb = 0
121         self._rate_type = None
122         self._round_type = None
123         self._policer_type = None
124         self._conform_action = None
125         self._conform_dscp = None
126         self._exceed_action = None
127         self._exceed_dscp = None
128         self._violate_action = None
129         self._violate_dscp = None
130         self._color_aware = False
131         self._classify_match_ip = ''
132         self._classify_match_is_src = True
133         self._classify_precolor = None
134         self._sw_if_index = 0
135         self._node = None
136         self._policer_name = ''
137
138     def policer_set_configuration(self):
139         """Configure policer on VPP node.
140
141         ...note:: First set all required parameters.
142         """
143         node = self._node
144
145         # create policer
146         color_aware = 'color-aware' if self._color_aware else ''
147
148         # pylint: disable=no-member
149         conform_action = self._conform_action.value
150
151         if PolicerAction.MARK_AND_TRANSMIT == self._conform_action:
152             conform_action += ' {0}'.format(self._conform_dscp.string)
153
154         exceed_action = self._exceed_action.value
155         if PolicerAction.MARK_AND_TRANSMIT == self._exceed_action:
156             exceed_action += ' {0}'.format(self._exceed_dscp.string)
157
158         violate_action = self._violate_action.value
159         if PolicerAction.MARK_AND_TRANSMIT == self._violate_action:
160             violate_action += ' {0}'.format(self._violate_dscp.string)
161
162         out = VatExecutor.cmd_from_template(node,
163                                             "policer/policer_add_3c.vat",
164                                             name=self._policer_name,
165                                             cir=self._cir,
166                                             eir=self._eir,
167                                             cb=self._cb,
168                                             eb=self._eb,
169                                             rate_type=self._rate_type.value,
170                                             round_type=self._round_type.value,
171                                             p_type=self._policer_type.value,
172                                             conform_action=conform_action,
173                                             exceed_action=exceed_action,
174                                             violate_action=violate_action,
175                                             color_aware=color_aware)
176
177         VatJsonUtil.verify_vat_retval(
178             out[0],
179             err_msg='Add policer {0} failed on {1}'.format(self._policer_name,
180                                                            node['host']))
181
182         policer_index = out[0].get('policer_index')
183
184         # create classify table
185         direction = 'src' if self._classify_match_is_src else 'dst'
186
187         if ip_address(unicode(self._classify_match_ip)).version == 6:
188             ip_version = 'ip6'
189             table_type = PolicerClassifyTableType.IP6_TABLE
190         else:
191             ip_version = 'ip4'
192             table_type = PolicerClassifyTableType.IP4_TABLE
193
194         out = VatExecutor.cmd_from_template(node,
195                                             "classify_add_table.vat",
196                                             ip_version=ip_version,
197                                             direction=direction)
198
199         VatJsonUtil.verify_vat_retval(
200             out[0],
201             err_msg='Add classify table failed on {0}'.format(node['host']))
202
203         new_table_index = out[0].get('new_table_index')
204         skip_n_vectors = out[0].get('skip_n_vectors')
205         match_n_vectors = out[0].get('match_n_vectors')
206
207         # create classify session
208         match = 'l3 {0} {1} {2}'.format(ip_version,
209                                         direction,
210                                         self._classify_match_ip)
211
212         out = VatExecutor.cmd_from_template(
213             node,
214             "policer/policer_classify_add_session.vat",
215             policer_index=policer_index,
216             pre_color=self._classify_precolor.value, # pylint: disable=no-member
217             table_index=new_table_index,
218             skip_n=skip_n_vectors,
219             match_n=match_n_vectors,
220             match=match)
221
222         VatJsonUtil.verify_vat_retval(
223             out[0],
224             err_msg='Add classify session failed on {0}'.format(node['host']))
225
226         # set classify interface
227         out = VatExecutor.cmd_from_template(
228             node,
229             "policer/policer_classify_set_interface.vat",
230             sw_if_index=self._sw_if_index,
231             table_type=table_type.value, # pylint: disable=no-member
232             table_index=new_table_index)
233
234         VatJsonUtil.verify_vat_retval(
235             out[0],
236             err_msg='Set classify interface failed on {0}'.format(node['host']))
237
238     def policer_clear_settings(self):
239         """Clear policer settings."""
240         self._cir = 0
241         self._eir = 0
242         self._cb = 0
243         self._eb = 0
244         self._rate_type = None
245         self._round_type = None
246         self._policer_type = None
247         self._conform_action = None
248         self._conform_dscp = None
249         self._exceed_action = None
250         self._exceed_dscp = None
251         self._violate_action = None
252         self._violate_dscp = None
253         self._color_aware = False
254         self._classify_match_ip = ''
255         self._classify_match_is_src = True
256         self._classify_precolor = None
257         self._sw_if_index = 0
258         self._node = None
259         self._policer_name = ''
260
261     def policer_set_name(self, name):
262         """Set policer name.
263
264         :param name: Policer name.
265         :type name: str
266         """
267         self._policer_name = name
268
269     def policer_set_node(self, node):
270         """Set node to setup policer on.
271
272         :param node: VPP node.
273         :type node: dict
274         """
275         self._node = node
276
277     def policer_set_cir(self, cir):
278         """Set policer CIR.
279
280         :param cir: Committed Information Rate.
281         :type cir: int
282         """
283         self._cir = cir
284
285     def policer_set_eir(self, eir):
286         """Set polcier EIR.
287
288         :param eir: Excess Information Rate.
289         :type eir: int
290         """
291         self._eir = eir
292
293     def policer_set_cb(self, cb):
294         """Set policer CB.
295
296         :param cb: Committed Burst size.
297         :type cb: int or str
298         """
299         if cb == "IMIX_v4_1":
300             self._cb = 1518
301         else:
302             self._cb = cb
303
304     def policer_set_eb(self, eb):
305         """Set policer EB.
306
307         :param eb: Excess Burst size.
308         :type eb: int or str
309         """
310         if eb == "IMIX_v4_1":
311             self._eb = 1518
312         else:
313             self._eb = eb
314
315     def policer_set_rate_type_kbps(self):
316         """Set policer rate type to kbps."""
317         self._rate_type = PolicerRateType.KBPS
318
319     def policer_set_rate_type_pps(self):
320         """Set policer rate type to pps."""
321         self._rate_type = PolicerRateType.PPS
322
323     def policer_set_round_type_closest(self):
324         """Set policer round type to closest."""
325         self._round_type = PolicerRoundType.CLOSEST
326
327     def policer_set_round_type_up(self):
328         """Set policer round type to up."""
329         self._round_type = PolicerRoundType.UP
330
331     def policer_set_round_type_down(self):
332         """Set policer round type to down."""
333         self._round_type = PolicerRoundType.DOWN
334
335     def policer_set_type_1r2c(self):
336         """Set policer type to 1r2c."""
337         self._policer_type = PolicerType.P_1R2C
338
339     def policer_set_type_1r3c(self):
340         """Set policer type to 1r3c RFC2697."""
341         self._policer_type = PolicerType.P_1R3C
342
343     def policer_set_type_2r3c_2698(self):
344         """Set policer type to 2r3c RFC2698."""
345         self._policer_type = PolicerType.P_2R3C_2698
346
347     def policer_set_type_2r3c_4115(self):
348         """Set policer type to 2r3c RFC4115."""
349         self._policer_type = PolicerType.P_2R3C_4115
350
351     def policer_set_type_2r3c_mef5cf1(self):
352         """Set policer type to 2r3c MEF5CF1."""
353         self._policer_type = PolicerType.P_2R3C_MEF5CF1
354
355     def policer_set_conform_action_drop(self):
356         """Set policer conform-action to drop."""
357         self._conform_action = PolicerAction.DROP
358
359     def policer_set_conform_action_transmit(self):
360         """Set policer conform-action to transmit."""
361         self._conform_action = PolicerAction.TRANSMIT
362
363     def policer_set_conform_action_mark_and_transmit(self, dscp):
364         """Set policer conform-action to mark-and-transmit.
365
366         :param dscp: DSCP value to mark.
367         :type dscp: DSCP
368         """
369         self._conform_action = PolicerAction.MARK_AND_TRANSMIT
370         self._conform_dscp = dscp
371
372     def policer_set_exceed_action_drop(self):
373         """Set policer exceed-action to drop."""
374         self._exceed_action = PolicerAction.DROP
375
376     def policer_set_exceed_action_transmit(self):
377         """Set policer exceed-action to transmit."""
378         self._exceed_action = PolicerAction.TRANSMIT
379
380     def policer_set_exceed_action_mark_and_transmit(self, dscp):
381         """Set policer exceed-action to mark-and-transmit.
382
383         :param dscp: DSCP value to mark.
384         :type dscp: DSCP
385         """
386         self._exceed_action = PolicerAction.MARK_AND_TRANSMIT
387         self._exceed_dscp = dscp
388
389     def policer_set_violate_action_drop(self):
390         """Set policer violate-action to drop."""
391         self._violate_action = PolicerAction.DROP
392
393     def policer_set_violate_action_transmit(self):
394         """Set policer violate-action to transmit."""
395         self._violate_action = PolicerAction.TRANSMIT
396
397     def policer_set_violate_action_mark_and_transmit(self, dscp):
398         """Set policer violate-action to mark-and-transmit.
399
400         :param dscp: DSCP value to mark.
401         :type dscp: DSCP
402         """
403         self._violate_action = PolicerAction.MARK_AND_TRANSMIT
404         self._violate_dscp = dscp
405
406     def policer_enable_color_aware(self):
407         """Enable color-aware mode for policer."""
408         self._color_aware = True
409
410     def policer_classify_set_precolor_conform(self):
411         """Set policer classify pre-color to conform-color."""
412         self._classify_precolor = PolicerClassifyPreColor.CONFORM_COLOR
413
414     def policer_classify_set_precolor_exceed(self):
415         """Set policer classify pre-color to exceeed-color."""
416         self._classify_precolor = PolicerClassifyPreColor.EXCEED_COLOR
417
418     def policer_classify_set_interface(self, interface):
419         """Set policer classify interface.
420
421         .. note:: First set node with policer_set_node.
422
423         :param interface: Interface name or sw_if_index.
424         :type interface: str or int
425         """
426         if isinstance(interface, basestring):
427             self._sw_if_index = Topology.get_interface_sw_index(self._node,
428                                                                 interface)
429         else:
430             self._sw_if_index = interface
431
432     def policer_classify_set_match_ip(self, ip, is_src=True):
433         """Set policer classify match source IP address.
434
435         :param ip: IPv4 or IPv6 address.
436         :param is_src: Match src IP if True otherwise match dst IP.
437         :type ip: str
438         :type is_src: bool
439         """
440         self._classify_match_ip = ip
441         self._classify_match_is_src = is_src
442
443     @staticmethod
444     def dscp_cs0():
445         """Return DSCP CS0.
446
447         :returns: DSCP enum CS0 object.
448         :rtype: DSCP
449         """
450         return DSCP.CS0
451
452     @staticmethod
453     def dscp_cs1():
454         """Return DSCP CS1.
455
456         :returns: DSCP enum CS1 object.
457         :rtype: DSCP
458         """
459         return DSCP.CS1
460
461     @staticmethod
462     def dscp_cs2():
463         """Return DSCP CS2.
464
465         :returns: DSCP enum CS2 object.
466         :rtype: DSCP
467         """
468         return DSCP.CS2
469
470     @staticmethod
471     def dscp_cs3():
472         """Return DSCP CS3.
473
474         :returns: DSCP enum CS3 object.
475         :rtype: DSCP
476         """
477         return DSCP.CS3
478
479     @staticmethod
480     def dscp_cs4():
481         """Return DSCP CS4.
482
483         :returns: DSCP enum CS4 object.
484         :rtype: DSCP
485         """
486         return DSCP.CS4
487
488     @staticmethod
489     def dscp_cs5():
490         """Return DSCP CS5.
491
492         :returns: DSCP enum CS5 object.
493         :rtype: DSCP
494         """
495         return DSCP.CS5
496
497     @staticmethod
498     def dscp_cs6():
499         """Return DSCP CS6.
500
501         :returns: DSCP enum CS6 object.
502         :rtype: DSCP
503         """
504         return DSCP.CS6
505
506     @staticmethod
507     def dscp_cs7():
508         """Return DSCP CS7.
509
510         :returns: DSCP enum CS7 object.
511         :rtype: DSCP
512         """
513         return DSCP.CS7
514
515     @staticmethod
516     def dscp_ef():
517         """Return DSCP EF.
518
519         :returns: DSCP enum EF object.
520         :rtype: DSCP
521         """
522         return DSCP.EF
523
524     @staticmethod
525     def dscp_af11():
526         """Return DSCP AF11.
527
528         :returns: DSCP enum AF11 object.
529         :rtype: DSCP
530         """
531         return DSCP.AF11
532
533     @staticmethod
534     def dscp_af12():
535         """Return DSCP AF12.
536
537         :returns: DSCP enum AF12 object.
538         :rtype: DSCP
539         """
540         return DSCP.AF12
541
542     @staticmethod
543     def dscp_af13():
544         """Return DSCP AF13.
545
546         :returns: DSCP enum AF13 object.
547         :rtype: DSCP
548         """
549         return DSCP.AF13
550
551     @staticmethod
552     def dscp_af21():
553         """Return DSCP AF21.
554
555         :returns: DSCP enum AF21 object.
556         :rtype: DSCP
557         """
558         return DSCP.AF21
559
560     @staticmethod
561     def dscp_af22():
562         """Return DSCP AF22.
563
564         :returns: DSCP enum AF22 object.
565         :rtype: DSCP
566         """
567         return DSCP.AF22
568
569     @staticmethod
570     def dscp_af23():
571         """Return DSCP AF23.
572
573         :returns: DSCP enum AF23 object.
574         :rtype: DSCP
575         """
576         return DSCP.AF23
577
578     @staticmethod
579     def dscp_af31():
580         """Return DSCP AF31.
581
582         :returns: DSCP enum AF31 object.
583         :rtype: DSCP
584         """
585         return DSCP.AF31
586
587     @staticmethod
588     def dscp_af32():
589         """Return DSCP AF32.
590
591         :returns: DSCP enum AF32 object.
592         :rtype: DSCP
593         """
594         return DSCP.AF32
595
596     @staticmethod
597     def dscp_af33():
598         """Return DSCP AF33.
599
600         :returns: DSCP enum AF33 object.
601         :rtype: DSCP
602         """
603         return DSCP.AF33
604
605     @staticmethod
606     def get_dscp_num_value(dscp):
607         """Return DSCP numeric value.
608
609         :param dscp: DSCP enum object.
610         :type dscp: DSCP
611         :returns: DSCP numeric value.
612         :rtype: int
613         """
614         return dscp.num