diff options
author | premkumarv <preym17@gmail.com> | 2019-07-24 08:43:23 -0400 |
---|---|---|
committer | Jan Gelety <jgelety@cisco.com> | 2019-09-26 17:26:32 +0200 |
commit | 7b73d46872db5adfc8f4603a9ca783be7d3fa323 (patch) | |
tree | a04a2a21632d1f4b39a8eaebd24065b3cc8f4bcd /resources/libraries/python | |
parent | f7d43390a6ce60284f54cad4e66b66d1ecd4a166 (diff) |
CSIT-1471: Policer - VAT API to PAPI
Change-Id: I6c7eff8d9cbb196ccb684a45579ac59942351cfe
Signed-off-by: premkumarv <preym17@gmail.com>
Diffstat (limited to 'resources/libraries/python')
-rw-r--r-- | resources/libraries/python/Classify.py | 347 | ||||
-rw-r--r-- | resources/libraries/python/PapiExecutor.py | 2 | ||||
-rw-r--r-- | resources/libraries/python/Policer.py | 725 |
3 files changed, 290 insertions, 784 deletions
diff --git a/resources/libraries/python/Classify.py b/resources/libraries/python/Classify.py index 6f05a6157d..6d4b84c1cc 100644 --- a/resources/libraries/python/Classify.py +++ b/resources/libraries/python/Classify.py @@ -20,6 +20,7 @@ from ipaddress import ip_address from robot.api import logger +from resources.libraries.python.Constants import Constants from resources.libraries.python.topology import Topology from resources.libraries.python.PapiExecutor import PapiSocketExecutor @@ -40,16 +41,10 @@ class Classify(object): :returns MAC ACL mask in hexstring format. :rtype: str """ - if ether_type: - end = 28 - elif src_mac: - end = 24 - else: - end = 12 return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format( dst_mac.replace(':', ''), src_mac.replace(':', ''), - ether_type))[0:end] + ether_type)).decode('hex').rstrip('\0') @staticmethod def _build_ip_mask(proto='', src_ip='', dst_ip='', src_port='', @@ -69,19 +64,10 @@ class Classify(object): :returns: IP mask in hexstring format. :rtype: str """ - if dst_port: - end = 48 - elif src_port: - end = 44 - elif dst_ip: - end = 40 - elif src_ip: - end = 32 - else: - end = 20 return ('{!s:0>20}{!s:0>12}{!s:0>8}{!s:0>4}{!s:0>4}'.format( - proto, src_ip, dst_ip, src_port, dst_port))[0:end] + proto, src_ip, dst_ip, src_port, dst_port)).decode('hex').\ + rstrip('\0') @staticmethod def _build_ip6_mask(next_hdr='', src_ip='', dst_ip='', src_port='', @@ -101,19 +87,10 @@ class Classify(object): :returns: IPv6 ACL mask in hexstring format. :rtype: str """ - if dst_port: - end = 88 - elif src_port: - end = 84 - elif dst_ip: - end = 80 - elif src_ip: - end = 48 - else: - end = 14 return ('{!s:0>14}{!s:0>34}{!s:0>32}{!s:0>4}{!s:0>4}'.format( - next_hdr, src_ip, dst_ip, src_port, dst_port))[0:end] + next_hdr, src_ip, dst_ip, src_port, dst_port)).decode('hex').\ + rstrip('\0') @staticmethod def _build_mac_match(dst_mac='', src_mac='', ether_type=''): @@ -128,24 +105,18 @@ class Classify(object): :returns: MAC ACL match data in hexstring format. :rtype: str """ - if ether_type: - end = 28 - elif src_mac: - end = 24 - else: - end = 12 return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format( dst_mac.replace(':', ''), src_mac.replace(':', ''), - ether_type))[0:end] + ether_type)).decode('hex').rstrip('\0') @staticmethod def _build_ip_match(proto=0, src_ip='', dst_ip='', src_port=0, dst_port=0): - """Build IP ACL match data in hexstring format. + """Build IP ACL match data in byte-string format. :param proto: Protocol number with valid option "x". - :param src_ip: Source ip address with format of "x.x.x.x". - :param dst_ip: Destination ip address with format of "x.x.x.x". + :param src_ip: Source ip address in packed format. + :param dst_ip: Destination ip address in packed format. :param src_port: Source port number "x". :param dst_port: Destination port number "x". :type proto: int @@ -153,37 +124,22 @@ class Classify(object): :type dst_ip: str :type src_port: int :type dst_port: int - :returns: IP ACL match data in hexstring format. + :returns: IP ACL match data in byte-string format. :rtype: str """ - if src_ip: - src_ip = binascii.hexlify(ip_address(unicode(src_ip)).packed) - if dst_ip: - dst_ip = binascii.hexlify(ip_address(unicode(dst_ip)).packed) - if dst_port: - end = 48 - elif src_port: - end = 44 - elif dst_ip: - end = 40 - elif src_ip: - end = 32 - else: - end = 20 return ('{!s:0>20}{!s:0>12}{!s:0>8}{!s:0>4}{!s:0>4}'.format( hex(proto)[2:], src_ip, dst_ip, hex(src_port)[2:], - hex(dst_port)[2:]))[0:end] + hex(dst_port)[2:])).decode('hex').rstrip('\0') @staticmethod def _build_ip6_match(next_hdr=0, src_ip='', dst_ip='', src_port=0, dst_port=0): - """Build IPv6 ACL match data in hexstring format. + """Build IPv6 ACL match data in byte-string format. :param next_hdr: Next header number with valid option "x". - :param src_ip: Source ip6 address with format of "xxxx:xxxx::xxxx". - :param dst_ip: Destination ip6 address with format of - "xxxx:xxxx::xxxx". + :param src_ip: Source ip6 address in packed format. + :param dst_ip: Destination ip6 address in packed format. :param src_port: Source port number "x". :param dst_port: Destination port number "x". :type next_hdr: int @@ -191,52 +147,36 @@ class Classify(object): :type dst_ip: str :type src_port: int :type dst_port: int - :returns: IPv6 ACL match data in hexstring format. + :returns: IPv6 ACL match data in byte-string format. :rtype: str """ - if src_ip: - src_ip = binascii.hexlify(ip_address(unicode(src_ip)).packed) - if dst_ip: - dst_ip = binascii.hexlify(ip_address(unicode(dst_ip)).packed) - if dst_port: - end = 88 - elif src_port: - end = 84 - elif dst_ip: - end = 80 - elif src_ip: - end = 48 - else: - end = 14 return ('{!s:0>14}{!s:0>34}{!s:0>32}{!s:0>4}{!s:0>4}'.format( hex(next_hdr)[2:], src_ip, dst_ip, hex(src_port)[2:], - hex(dst_port)[2:]))[0:end] + hex(dst_port)[2:])).decode('hex').rstrip('\0') @staticmethod - def _classify_add_del_table(node, is_add, mask, match_n_vectors=1, - table_index=0xFFFFFFFF, nbuckets=2, - memory_size=2097152, skip_n_vectors=0, - next_table_index=0xFFFFFFFF, - miss_next_index=0xFFFFFFFF, current_data_flag=0, - current_data_offset=0): + def _classify_add_del_table( + node, is_add, mask, match_n_vectors=Constants.BITWISE_NON_ZERO, + table_index=Constants.BITWISE_NON_ZERO, nbuckets=2, + memory_size=2097152, skip_n_vectors=Constants.BITWISE_NON_ZERO, + next_table_index=Constants.BITWISE_NON_ZERO, + miss_next_index=Constants.BITWISE_NON_ZERO, + current_data_flag=0, current_data_offset=0): """Add or delete a classify table. :param node: VPP node to create classify table. :param is_add: If 1 the table is added, if 0 the table is deleted. :param mask: ACL mask in hexstring format. - :param match_n_vectors: Number of vectors to match (Default value = 1). - :param table_index: Index of the classify table. - (Default value = 0xFFFFFFFF) + :param match_n_vectors: Number of vectors to match (Default value = ~0). + :param table_index: Index of the classify table. (Default value = ~0) :param nbuckets: Number of buckets when adding a table. (Default value = 2) :param memory_size: Memory size when adding a table. (Default value = 2097152) - :param skip_n_vectors: Number of skip vectors (Default value = 0). - :param next_table_index: Index of next table. - (Default value = 0xFFFFFFFF) - :param miss_next_index: Index of miss table. - (Default value = 0xFFFFFFFF) + :param skip_n_vectors: Number of skip vectors (Default value = ~0). + :param next_table_index: Index of next table. (Default value = ~0) + :param miss_next_index: Index of miss table. (Default value = ~0) :param current_data_flag: Option to use current node's packet payload as the starting point from where packets are classified. This option is only valid for L2/L3 input ACL for now. @@ -267,9 +207,7 @@ class Classify(object): match_n: Number of match vectors. :rtype: tuple(int, int, int) """ - mask_len = ((len(mask) - 1) / 16 + 1) * 16 - mask = mask + '\0' * (mask_len - len(mask)) - + cmd = 'classify_add_del_table' args = dict( is_add=is_add, table_index=table_index, @@ -281,11 +219,9 @@ class Classify(object): miss_next_index=miss_next_index, current_data_flag=current_data_flag, current_data_offset=current_data_offset, - mask_len=mask_len, + mask_len=len(mask), mask=mask ) - - cmd = 'classify_add_del_table' err_msg = "Failed to create a classify table on host {host}".format( host=node['host']) @@ -296,10 +232,11 @@ class Classify(object): int(reply["match_n_vectors"]) @staticmethod - def _classify_add_del_session(node, is_add, table_index, match, - opaque_index=0xFFFFFFFF, - hit_next_index=0xFFFFFFFF, advance=0, - action=0, metadata=0): + def _classify_add_del_session( + node, is_add, table_index, match, + opaque_index=Constants.BITWISE_NON_ZERO, + hit_next_index=Constants.BITWISE_NON_ZERO, advance=0, + action=0, metadata=0): """Add or delete a classify session. :param node: VPP node to create classify session. @@ -309,9 +246,9 @@ class Classify(object): include bytes in front with length of skip_n_vectors of target table times sizeof (u32x4) (values of those bytes will be ignored). :param opaque_index: For add, opaque_index of new session. - (Default value = 0xFFFFFFFF) + (Default value = ~0) :param hit_next_index: For add, hit_next_index of new session. - (Default value = 0xFFFFFFFF) + (Default value = ~0) :param advance: For add, advance value for session. (Default value = 0) :param action: 0: No action (by default) metadata is not used. 1: Classified IP packets will be looked up from the specified ipv4 @@ -337,9 +274,7 @@ class Classify(object): :type action: int :type metadata: int """ - - match_len = ((len(match) - 1) / 16 + 1) * 16 - match = match + '\0' * (match_len - len(match)) + cmd = 'classify_add_del_session' args = dict( is_add=is_add, table_index=table_index, @@ -348,10 +283,9 @@ class Classify(object): advance=advance, action=action, metadata=metadata, - match_len=match_len, + match_len=len(match), match=match ) - cmd = 'classify_add_del_session' err_msg = "Failed to create a classify session on host {host}".format( host=node['host']) @@ -438,18 +372,18 @@ class Classify(object): papi_exec.add(cmd, **args).get_reply(err_msg) @staticmethod - def vpp_creates_classify_table_l3(node, ip_version, direction, ip_addr): + def vpp_creates_classify_table_l3(node, ip_version, direction, netmask): """Create classify table for IP address filtering. :param node: VPP node to create classify table. :param ip_version: Version of IP protocol. :param direction: Direction of traffic - src/dst. - :param ip_addr: IPv4 or Ipv6 (depending on the parameter 'ip_version') - address. + :param netmask: IPv4 or Ipv6 (depending on the parameter 'ip_version') + netmask (decimal, e.g. 255.255.255.255). :type node: dict :type ip_version: str :type direction: str - :type ip_addr: str + :type netmask: str :returns: (table_index, skip_n, match_n) table_index: Classify table index. skip_n: Number of skip vectors. @@ -462,181 +396,114 @@ class Classify(object): ip4=Classify._build_ip_mask, ip6=Classify._build_ip6_mask ) + if ip_version == "ip4" or ip_version == "ip6": - ip_addr = binascii.hexlify(ip_address(unicode(ip_addr)).packed) + netmask = binascii.hexlify(ip_address(unicode(netmask)).packed) else: - raise ValueError("IP version {ver} is not supported.". - format(ver=ip_version)) + raise ValueError("IP version {ver} is not supported.".format( + ver=ip_version)) if direction == "src": - mask = mask_f[ip_version](src_ip=ip_addr) + mask = mask_f[ip_version](src_ip=netmask) elif direction == "dst": - mask = mask_f[ip_version](dst_ip=ip_addr) + mask = mask_f[ip_version](dst_ip=netmask) else: - raise ValueError("Direction {dir} is not supported.". - format(dir=direction)) + raise ValueError("Direction {dir} is not supported.".format( + dir=direction)) - return Classify._classify_add_del_table( - node, - is_add=1, - mask=binascii.unhexlify(mask), - match_n_vectors=(len(mask) - 1) // 32 + 1 - ) + # Add l2 ethernet header to mask + mask = 14 * '\0' + mask - @staticmethod - def vpp_creates_classify_table_l2(node, direction, mac=""): - """Create classify table for MAC address filtering. + # Get index of the first significant mask octet + i = len(mask) - len(mask.lstrip('\0')) - :param node: VPP node to create classify table. - :param direction: Direction of traffic - src/dst. - :param mac: Source or destination (depending on the parameter - 'direction') MAC address. - :type node: dict - :type direction: str - :type mac: str - :returns: (table_index, skip_n, match_n) - table_index: Classify table index. - skip_n: Number of skip vectors. - match_n: Number of match vectors. - :rtype: tuple(int, int, int) - :raises ValueError: If the parameter 'direction' has incorrect value. - """ - if direction == "src": - mask = Classify._build_mac_mask(src_mac=mac) - elif direction == "dst": - mask = Classify._build_mac_mask(dst_mac=mac) - else: - raise ValueError("Direction {dir} is not supported.". - format(dir=direction)) - - return Classify._classify_add_del_table( - node, - is_add=1, - mask=binascii.unhexlify(mask), - match_n_vectors=(len(mask) - 1) // 32 + 1 - ) - - @staticmethod - def vpp_creates_classify_table_hex(node, hex_mask): - """Create classify table with hex mask. + # Compute skip_n parameter + skip_n = i // 16 + # Remove octets to be skipped from the mask + mask = mask[skip_n*16:] + # Pad mask to an even multiple of the vector size + mask = mask + (16 - len(mask) % 16 if len(mask) % 16 else 0) * '\0' + # Compute match_n parameter + match_n = len(mask) // 16 - :param node: VPP node to create classify table based on hex mask. - :param hex_mask: Classify hex mask. - :type node: dict - :type hex_mask: str - :returns: (table_index, skip_n, match_n) - table_index: Classify table index. - skip_n: Number of skip vectors. - match_n: Number of match vectors. - :rtype: tuple(int, int, int) - """ return Classify._classify_add_del_table( node, is_add=1, - mask=binascii.unhexlify(hex_mask), - match_n_vectors=(len(hex_mask) - 1) // 32 + 1 + mask=mask, + match_n_vectors=match_n, + skip_n_vectors=skip_n ) @staticmethod - def vpp_configures_classify_session_l3(node, acl_method, table_index, - ip_version, direction, address): + def vpp_configures_classify_session_l3( + node, acl_method, table_index, skip_n, match_n, ip_version, + direction, address, hit_next_index=Constants.BITWISE_NON_ZERO, + opaque_index=Constants.BITWISE_NON_ZERO): """Configuration of classify session for IP address filtering. :param node: VPP node to setup classify session. :param acl_method: ACL method - deny/permit. :param table_index: Classify table index. + :param skip_n: Number of skip vectors. + :param match_n: Number of vectors to match. :param ip_version: Version of IP protocol. :param direction: Direction of traffic - src/dst. :param address: IPv4 or IPv6 address. + :param hit_next_index: hit_next_index of new session. + (Default value = ~0) + :param opaque_index: opaque_index of new session. (Default value = ~0) :type node: dict :type acl_method: str :type table_index: int + :type skip_n: int + :type match_n: int :type ip_version: str :type direction: str :type address: str + :type hit_next_index: int + :type opaque_index: int :raises ValueError: If the parameter 'direction' has incorrect value. """ match_f = dict( ip4=Classify._build_ip_match, ip6=Classify._build_ip6_match ) - if direction == "src": - match = match_f[ip_version](src_ip=address) - elif direction == "dst": - match = match_f[ip_version](dst_ip=address) - else: - raise ValueError("Direction {dir} is not supported.". - format(dir=direction)) action = dict( permit=0, deny=1 ) - Classify._classify_add_del_session( - node, - is_add=1, - table_index=table_index, - match=binascii.unhexlify(match), - action=action[acl_method]) - @staticmethod - def vpp_configures_classify_session_l2(node, acl_method, table_index, - direction, address): - """Configuration of classify session for MAC address filtering. + if ip_version == "ip4" or ip_version == "ip6": + address = binascii.hexlify(ip_address(unicode(address)).packed) + else: + raise ValueError("IP version {ver} is not supported.".format( + ver=ip_version)) - :param node: VPP node to setup classify session. - :param acl_method: ACL method - deny/permit. - :param table_index: Classify table index. - :param direction: Direction of traffic - src/dst. - :param address: MAC address. - :type node: dict - :type acl_method: str - :type table_index: int - :type direction: str - :type address: str - :raises ValueError: If the parameter 'direction' has incorrect value. - """ if direction == "src": - match = Classify._build_mac_match(src_mac=address) + match = match_f[ip_version](src_ip=address) elif direction == "dst": - match = Classify._build_mac_match(dst_mac=address) + match = match_f[ip_version](dst_ip=address) else: - raise ValueError("Direction {dir} is not supported.". - format(dir=direction)) - action = dict( - permit=0, - deny=1 - ) - Classify._classify_add_del_session( - node, - is_add=1, - table_index=table_index, - match=binascii.unhexlify(match), - action=action[acl_method]) + raise ValueError("Direction {dir} is not supported.".format( + dir=direction)) - @staticmethod - def vpp_configures_classify_session_hex(node, acl_method, table_index, - hex_value): - """Configuration of classify session with hex value. + # Prepend match with l2 ethernet header part + match = 14 * '\0' + match + + # Pad match to match skip_n_vector + match_n_vector size + match = match + ((match_n + skip_n) * 16 - len(match) + if len(match) < (match_n + skip_n) * 16 + else 0) * '\0' - :param node: VPP node to setup classify session. - :param acl_method: ACL method - deny/permit. - :param table_index: Classify table index. - :param hex_value: Classify hex value. - :type node: dict - :type acl_method: str - :type table_index: int - :type hex_value: str - """ - action = dict( - permit=0, - deny=1 - ) Classify._classify_add_del_session( node, is_add=1, table_index=table_index, - match=binascii.unhexlify(hex_value), - action=action[acl_method]) + hit_next_index=hit_next_index, + opaque_index=opaque_index, + match=match, + action=action[acl_method] + ) @staticmethod def compute_classify_hex_mask(ip_version, protocol, direction): @@ -757,6 +624,18 @@ class Classify(object): return details @staticmethod + def show_classify_tables_verbose(node): + """Show classify tables verbose. + + :param node: Topology node. + :type node: dict + :returns: Classify tables verbose data. + :rtype: str + """ + return PapiSocketExecutor.run_cli_cmd( + node, "show classify tables verbose") + + @staticmethod def vpp_log_plugin_acl_settings(node): """Retrieve configured settings from the ACL plugin and write to robot log. diff --git a/resources/libraries/python/PapiExecutor.py b/resources/libraries/python/PapiExecutor.py index d651e78cca..60d35a8543 100644 --- a/resources/libraries/python/PapiExecutor.py +++ b/resources/libraries/python/PapiExecutor.py @@ -442,7 +442,7 @@ class PapiSocketExecutor(object): cmd = 'cli_inband' args = dict(cmd=cli_cmd) err_msg = "Failed to run 'cli_inband {cmd}' PAPI command on host " \ - "{host}".format(host=node['host'], cmd=cmd) + "{host}".format(host=node['host'], cmd=cli_cmd) with PapiSocketExecutor(node, remote_vpp_socket) as papi_exec: reply = papi_exec.add(cmd, **args).get_reply(err_msg)["reply"] if log: diff --git a/resources/libraries/python/Policer.py b/resources/libraries/python/Policer.py index 9e14a4fd58..a51f99609c 100644 --- a/resources/libraries/python/Policer.py +++ b/resources/libraries/python/Policer.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Cisco and/or its affiliates. +# Copyright (c) 2019 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: @@ -13,600 +13,227 @@ """Policer utilities library.""" -from enum import Enum +from enum import IntEnum -from ipaddress import ip_address - -from resources.libraries.python.VatExecutor import VatExecutor -from resources.libraries.python.VatJsonUtil import VatJsonUtil +from resources.libraries.python.Constants import Constants +from resources.libraries.python.PapiExecutor import PapiSocketExecutor from resources.libraries.python.topology import Topology -class PolicerRateType(Enum): +class PolicerRateType(IntEnum): """Policer rate types.""" - KBPS = 'kbps' - PPS = 'pps' - - def __init__(self, string): - self.string = string + KBPS = 0 + PPS = 1 + INVALID = 2 -# pylint: disable=invalid-name -class PolicerRoundType(Enum): +class PolicerRoundType(IntEnum): """Policer round types.""" - CLOSEST = 'closest' - UP = 'up' - DOWN = 'down' - - def __init__(self, string): - self.string = string + ROUND_TO_CLOSEST = 0 + ROUND_TO_UP = 1 + ROUND_TO_DOWN = 2 + ROUND_TO_INVALID = 3 -class PolicerType(Enum): +class PolicerType(IntEnum): """Policer type.""" - P_1R2C = '1r2c' - P_1R3C = '1r3c' - P_2R3C_2698 = '2r3c-2698' - P_2R3C_4115 = '2r3c-4115' - P_2R3C_MEF5CF1 = '2r3c-mef5cf1' + 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 - def __init__(self, string): - self.string = string - -class PolicerAction(Enum): +class PolicerAction(IntEnum): """Policer action.""" - DROP = 'drop' - TRANSMIT = 'transmit' - MARK_AND_TRANSMIT = 'mark-and-transmit' - - def __init__(self, string): - self.string = string - - -class DSCP(Enum): - """DSCP for mark-and-transmit action.""" - CS0 = ('CS0', 0) - CS1 = ('CS1', 8) - CS2 = ('CS2', 16) - CS3 = ('CS3', 24) - CS4 = ('CS4', 32) - CS5 = ('CS5', 40) - CS6 = ('CS6', 48) - CS7 = ('CS7', 56) - AF11 = ('AF11', 10) - AF12 = ('AF12', 12) - AF13 = ('AF13', 14) - AF21 = ('AF21', 18) - AF22 = ('AF22', 20) - AF23 = ('AF23', 22) - AF31 = ('AF31', 26) - AF32 = ('AF32', 28) - AF33 = ('AF33', 30) - EF = ('EF', 46) - - def __init__(self, string, num): - self.string = string - self.num = num - + DROP = 0 + TRANSMIT = 1 + MARK_AND_TRANSMIT = 2 -class PolicerClassifyPreColor(Enum): - """Policer classify precolor.""" - CONFORM_COLOR = 'conform-color' - EXCEED_COLOR = 'exceed-color' - def __init__(self, string): - self.string = string +class PolicerPreColor(IntEnum): + """Policer Pre-color.""" + CONFORM_COLOR = 0 + EXCEED_COLOR = 1 + VIOLATE_COLOR = 2 -class PolicerClassifyTableType(Enum): - """Policer classify table type.""" - IP4_TABLE = 'ip4-table' - IP6_TABLE = 'ip6-table' - L2_TABLE = 'l2-table' - - def __init__(self, string): - self.string = string +class DSCP(IntEnum): + """DSCP for mark-and-transmit action.""" + D_CS0 = 0 + D_CS1 = 8 + D_CS2 = 16 + D_CS3 = 24 + D_CS4 = 32 + D_vCS5 = 40 + D_CS6 = 48 + D_CS7 = 56 + D_AF11 = 10 + D_AF12 = 12 + D_AF13 = 14 + D_AF21 = 18 + D_AF22 = 20 + D_AF23 = 22 + D_AF31 = 26 + D_AF32 = 28 + D_AF33 = 30 + D_EF = 46 class Policer(object): """Policer utilities.""" - def __init__(self): - self._cir = 0 - self._eir = 0 - self._cb = 0 - self._eb = 0 - self._rate_type = None - self._round_type = None - self._policer_type = None - self._conform_action = None - self._conform_dscp = None - self._exceed_action = None - self._exceed_dscp = None - self._violate_action = None - self._violate_dscp = None - self._color_aware = False - self._classify_match_ip = '' - self._classify_match_is_src = True - self._classify_precolor = None - self._sw_if_index = 0 - self._node = None - self._policer_name = '' - - def policer_set_configuration(self): + # pylint: disable=too-many-arguments, too-many-locals + @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. - ...note:: First set all required parameters. - """ - node = self._node - - # create policer - color_aware = 'color-aware' if self._color_aware else '' - - conform_action = self._conform_action.value - - if PolicerAction.MARK_AND_TRANSMIT == self._conform_action: - conform_action += ' {0}'.format(self._conform_dscp.string) - - exceed_action = self._exceed_action.value - if PolicerAction.MARK_AND_TRANSMIT == self._exceed_action: - exceed_action += ' {0}'.format(self._exceed_dscp.string) - - violate_action = self._violate_action.value - if PolicerAction.MARK_AND_TRANSMIT == self._violate_action: - violate_action += ' {0}'.format(self._violate_dscp.string) - - out = VatExecutor.cmd_from_template(node, - "policer/policer_add_3c.vat", - name=self._policer_name, - cir=self._cir, - eir=self._eir, - cb=self._cb, - eb=self._eb, - rate_type=self._rate_type.value, - round_type=self._round_type.value, - p_type=self._policer_type.value, - conform_action=conform_action, - exceed_action=exceed_action, - violate_action=violate_action, - color_aware=color_aware) - - VatJsonUtil.verify_vat_retval( - out[0], - err_msg='Add policer {0} failed on {1}'.format(self._policer_name, - node['host'])) - - policer_index = out[0].get('policer_index') - - # create classify table - direction = 'src' if self._classify_match_is_src else 'dst' - - if ip_address(unicode(self._classify_match_ip)).version == 6: - ip_version = 'ip6' - table_type = PolicerClassifyTableType.IP6_TABLE - else: - ip_version = 'ip4' - table_type = PolicerClassifyTableType.IP4_TABLE - - out = VatExecutor.cmd_from_template(node, - "classify_add_table.vat", - ip_version=ip_version, - direction=direction) - - VatJsonUtil.verify_vat_retval( - out[0], - err_msg='Add classify table failed on {0}'.format(node['host'])) - - new_table_index = out[0].get('new_table_index') - skip_n_vectors = out[0].get('skip_n_vectors') - match_n_vectors = out[0].get('match_n_vectors') - - # create classify session - match = 'l3 {0} {1} {2}'.format(ip_version, - direction, - self._classify_match_ip) - - out = VatExecutor.cmd_from_template( - node, - "policer/policer_classify_add_session.vat", - policer_index=policer_index, - pre_color=self._classify_precolor.value, - table_index=new_table_index, - skip_n=skip_n_vectors, - match_n=match_n_vectors, - match=match) - - VatJsonUtil.verify_vat_retval( - out[0], - err_msg='Add classify session failed on {0}'.format(node['host'])) - - # set classify interface - out = VatExecutor.cmd_from_template( - node, - "policer/policer_classify_set_interface.vat", - sw_if_index=self._sw_if_index, - table_type=table_type.value, - table_index=new_table_index) - - VatJsonUtil.verify_vat_retval( - out[0], - err_msg='Set classify interface failed on {0}'.format(node['host'])) - - def policer_clear_settings(self): - """Clear policer settings.""" - self._cir = 0 - self._eir = 0 - self._cb = 0 - self._eb = 0 - self._rate_type = None - self._round_type = None - self._policer_type = None - self._conform_action = None - self._conform_dscp = None - self._exceed_action = None - self._exceed_dscp = None - self._violate_action = None - self._violate_dscp = None - self._color_aware = False - self._classify_match_ip = '' - self._classify_match_is_src = True - self._classify_precolor = None - self._sw_if_index = 0 - self._node = None - self._policer_name = '' - - def policer_set_name(self, name): - """Set policer name. - - :param name: Policer name. - :type name: str - """ - self._policer_name = name - - def policer_set_node(self, node): - """Set node to setup policer on. - :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 - """ - self._node = node - - def policer_set_cir(self, cir): - """Set policer CIR. - - :param cir: Committed Information Rate. + :type policer_name: str :type cir: int - """ - self._cir = cir - - def policer_set_eir(self, eir): - """Set polcier EIR. - - :param eir: Excess Information Rate. :type eir: int - """ - self._eir = eir - - def policer_set_cb(self, cb): - """Set policer CB. - - :param cb: Committed Burst size. - :type cb: int or str - """ - if cb == "IMIX_v4_1": - self._cb = 1518 - else: - self._cb = cb - - def policer_set_eb(self, eb): - """Set policer EB. - - :param eb: Excess Burst size. - :type eb: int or str - """ - if eb == "IMIX_v4_1": - self._eb = 1518 - else: - self._eb = eb - - def policer_set_rate_type_kbps(self): - """Set policer rate type to kbps.""" - self._rate_type = PolicerRateType.KBPS - - def policer_set_rate_type_pps(self): - """Set policer rate type to pps.""" - self._rate_type = PolicerRateType.PPS - - def policer_set_round_type_closest(self): - """Set policer round type to closest.""" - self._round_type = PolicerRoundType.CLOSEST - - def policer_set_round_type_up(self): - """Set policer round type to up.""" - self._round_type = PolicerRoundType.UP - - def policer_set_round_type_down(self): - """Set policer round type to down.""" - self._round_type = PolicerRoundType.DOWN - - def policer_set_type_1r2c(self): - """Set policer type to 1r2c.""" - self._policer_type = PolicerType.P_1R2C - - def policer_set_type_1r3c(self): - """Set policer type to 1r3c RFC2697.""" - self._policer_type = PolicerType.P_1R3C - - def policer_set_type_2r3c_2698(self): - """Set policer type to 2r3c RFC2698.""" - self._policer_type = PolicerType.P_2R3C_2698 - - def policer_set_type_2r3c_4115(self): - """Set policer type to 2r3c RFC4115.""" - self._policer_type = PolicerType.P_2R3C_4115 - - def policer_set_type_2r3c_mef5cf1(self): - """Set policer type to 2r3c MEF5CF1.""" - self._policer_type = PolicerType.P_2R3C_MEF5CF1 - - def policer_set_conform_action_drop(self): - """Set policer conform-action to drop.""" - self._conform_action = PolicerAction.DROP - - def policer_set_conform_action_transmit(self): - """Set policer conform-action to transmit.""" - self._conform_action = PolicerAction.TRANSMIT - - def policer_set_conform_action_mark_and_transmit(self, dscp): - """Set policer conform-action to mark-and-transmit. - - :param dscp: DSCP value to mark. - :type dscp: DSCP - """ - self._conform_action = PolicerAction.MARK_AND_TRANSMIT - self._conform_dscp = dscp - - def policer_set_exceed_action_drop(self): - """Set policer exceed-action to drop.""" - self._exceed_action = PolicerAction.DROP - - def policer_set_exceed_action_transmit(self): - """Set policer exceed-action to transmit.""" - self._exceed_action = PolicerAction.TRANSMIT - - def policer_set_exceed_action_mark_and_transmit(self, dscp): - """Set policer exceed-action to mark-and-transmit. - - :param dscp: DSCP value to mark. - :type dscp: DSCP - """ - self._exceed_action = PolicerAction.MARK_AND_TRANSMIT - self._exceed_dscp = dscp - - def policer_set_violate_action_drop(self): - """Set policer violate-action to drop.""" - self._violate_action = PolicerAction.DROP - - def policer_set_violate_action_transmit(self): - """Set policer violate-action to transmit.""" - self._violate_action = PolicerAction.TRANSMIT - - def policer_set_violate_action_mark_and_transmit(self, dscp): - """Set policer violate-action to mark-and-transmit. + :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 + """ + cmd = 'policer_add_del' + args = dict( + is_add=int(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, 'ROUND_TO_{rt}'.format( + rt=round_type.upper())).value, + type=getattr(PolicerType, 'TYPE_{pt}'.format( + pt=policer_type.upper())).value, + conform_action_type=getattr( + PolicerAction, conform_action_type.upper()).value, + conform_dscp=getattr(DSCP, 'D_{dscp}'.format( + dscp=conform_dscp.upper())).value + if + conform_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name + else 0, + exceed_action_type=getattr( + PolicerAction, exceed_action_type.upper()).value, + exceed_dscp=getattr(DSCP, 'D_{dscp}'.format( + dscp=exceed_dscp.upper())).value + if + exceed_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name + else 0, + violate_action_type=getattr( + PolicerAction, violate_action_type.upper()).value, + violate_dscp=getattr(DSCP, 'D_{dscp}'.format( + dscp=violate_dscp.upper())).value + if + violate_action_type.upper() == PolicerAction.MARK_AND_TRANSMIT.name + else 0, + color_aware=1 if color_aware == "'ca'" else 0 + ) + err_msg = 'Failed to configure policer {pn} on host {host}'.format( + pn=policer_name, host=node['host']) + + with PapiSocketExecutor(node) as papi_exec: + reply = papi_exec.add(cmd, **args).get_reply(err_msg) + + return reply['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=1): + """Set/unset policer classify interface. - :param dscp: DSCP value to mark. - :type dscp: DSCP - """ - self._violate_action = PolicerAction.MARK_AND_TRANSMIT - self._violate_dscp = dscp - - def policer_enable_color_aware(self): - """Enable color-aware mode for policer.""" - self._color_aware = True - - def policer_classify_set_precolor_conform(self): - """Set policer classify pre-color to conform-color.""" - self._classify_precolor = PolicerClassifyPreColor.CONFORM_COLOR - - def policer_classify_set_precolor_exceed(self): - """Set policer classify pre-color to exceeed-color.""" - self._classify_precolor = PolicerClassifyPreColor.EXCEED_COLOR - - def policer_classify_set_interface(self, interface): - """Set policer classify interface. - - .. note:: First set node with policer_set_node. - - :param interface: Interface name or sw_if_index. + :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 non-zero, 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 """ if isinstance(interface, basestring): - self._sw_if_index = Topology.get_interface_sw_index(self._node, - interface) + sw_if_index = Topology.get_interface_sw_index(node, interface) else: - self._sw_if_index = interface - - def policer_classify_set_match_ip(self, ip, is_src=True): - """Set policer classify match source IP address. - - :param ip: IPv4 or IPv6 address. - :param is_src: Match src IP if True otherwise match dst IP. - :type ip: str - :type is_src: bool - """ - self._classify_match_ip = ip - self._classify_match_is_src = is_src - - @staticmethod - def dscp_cs0(): - """Return DSCP CS0. - - :returns: DSCP enum CS0 object. - :rtype: DSCP - """ - return DSCP.CS0 - - @staticmethod - def dscp_cs1(): - """Return DSCP CS1. - - :returns: DSCP enum CS1 object. - :rtype: DSCP - """ - return DSCP.CS1 - - @staticmethod - def dscp_cs2(): - """Return DSCP CS2. - - :returns: DSCP enum CS2 object. - :rtype: DSCP - """ - return DSCP.CS2 - - @staticmethod - def dscp_cs3(): - """Return DSCP CS3. - - :returns: DSCP enum CS3 object. - :rtype: DSCP - """ - return DSCP.CS3 - - @staticmethod - def dscp_cs4(): - """Return DSCP CS4. - - :returns: DSCP enum CS4 object. - :rtype: DSCP - """ - return DSCP.CS4 - - @staticmethod - def dscp_cs5(): - """Return DSCP CS5. - - :returns: DSCP enum CS5 object. - :rtype: DSCP - """ - return DSCP.CS5 - - @staticmethod - def dscp_cs6(): - """Return DSCP CS6. - - :returns: DSCP enum CS6 object. - :rtype: DSCP - """ - return DSCP.CS6 - - @staticmethod - def dscp_cs7(): - """Return DSCP CS7. - - :returns: DSCP enum CS7 object. - :rtype: DSCP - """ - return DSCP.CS7 - - @staticmethod - def dscp_ef(): - """Return DSCP EF. - - :returns: DSCP enum EF object. - :rtype: DSCP - """ - return DSCP.EF - - @staticmethod - def dscp_af11(): - """Return DSCP AF11. - - :returns: DSCP enum AF11 object. - :rtype: DSCP - """ - return DSCP.AF11 - - @staticmethod - def dscp_af12(): - """Return DSCP AF12. + sw_if_index = interface - :returns: DSCP enum AF12 object. - :rtype: DSCP - """ - return DSCP.AF12 + cmd = 'policer_classify_set_interface' - @staticmethod - def dscp_af13(): - """Return DSCP AF13. + args = dict( + is_add=int(is_add), + sw_if_index=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 = 'Failed to set/unset policer classify interface {ifc} ' \ + 'on host {host}'.format(ifc=interface, host=node['host']) - :returns: DSCP enum AF13 object. - :rtype: DSCP - """ - return DSCP.AF13 + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args).get_reply(err_msg) @staticmethod - def dscp_af21(): - """Return DSCP AF21. - - :returns: DSCP enum AF21 object. - :rtype: DSCP - """ - return DSCP.AF21 + def policer_classify_get_precolor(precolor): + """Return policer pre-color numeric value. - @staticmethod - def dscp_af22(): - """Return DSCP AF22. - - :returns: DSCP enum AF22 object. - :rtype: DSCP - """ - return DSCP.AF22 - - @staticmethod - def dscp_af23(): - """Return DSCP AF23. - - :returns: DSCP enum AF23 object. - :rtype: DSCP - """ - return DSCP.AF23 - - @staticmethod - def dscp_af31(): - """Return DSCP AF31. - - :returns: DSCP enum AF31 object. - :rtype: DSCP - """ - return DSCP.AF31 - - @staticmethod - def dscp_af32(): - """Return DSCP AF32. - - :returns: DSCP enum AF32 object. - :rtype: DSCP - """ - return DSCP.AF32 - - @staticmethod - def dscp_af33(): - """Return DSCP AF33. - - :returns: DSCP enum AF33 object. - :rtype: DSCP + :param precolor: Policer pre-color name. + :type precolor: str + :returns: Policer pre-color numeric value. + :rtype: int """ - return DSCP.AF33 + return getattr(PolicerPreColor, precolor.upper()).value @staticmethod def get_dscp_num_value(dscp): """Return DSCP numeric value. - :param dscp: DSCP enum object. - :type dscp: DSCP + :param dscp: DSCP name. + :type dscp: str :returns: DSCP numeric value. :rtype: int """ - return dscp.num + return getattr(DSCP, 'D_{dscp}'.format(dscp=dscp.upper())).value |