aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python/Classify.py
diff options
context:
space:
mode:
Diffstat (limited to 'resources/libraries/python/Classify.py')
-rw-r--r--resources/libraries/python/Classify.py347
1 files changed, 113 insertions, 234 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.