aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python
diff options
context:
space:
mode:
Diffstat (limited to 'resources/libraries/python')
-rw-r--r--resources/libraries/python/Classify.py347
-rw-r--r--resources/libraries/python/PapiExecutor.py2
-rw-r--r--resources/libraries/python/Policer.py725
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