+ def _build_mac_mask(dst_mac=u"", src_mac=u"", ether_type=u""):
+ """Build MAC ACL mask data in bytes format.
+
+ :param dst_mac: Source MAC address <0-ffffffffffff>.
+ :param src_mac: Destination MAC address <0-ffffffffffff>.
+ :param ether_type: Ethernet type <0-ffff>.
+ :type dst_mac: str
+ :type src_mac: str
+ :type ether_type: str
+ :returns MAC ACL mask in bytes format.
+ :rtype: bytes
+ """
+ return bytes.fromhex(
+ f"{dst_mac.replace(u':', u'')!s:0>12}"
+ f"{src_mac.replace(u':', u'')!s:0>12}"
+ f"{ether_type!s:0>4}"
+ ).rstrip(b'\0')
+
+ @staticmethod
+ def _build_ip_mask(
+ proto=u"", src_ip=u"", dst_ip=u"", src_port=u"", dst_port=u""):
+ """Build IP ACL mask data in bytes format.
+
+ :param proto: Protocol number <0-ff>.
+ :param src_ip: Source ip address <0-ffffffff>.
+ :param dst_ip: Destination ip address <0-ffffffff>.
+ :param src_port: Source port number <0-ffff>.
+ :param str dst_port: Destination port number <0-ffff>.
+ :type proto: str
+ :type src_ip: str
+ :type dst_ip: str
+ :type src_port: str
+ :type dst_port:src
+ :returns: IP mask in bytes format.
+ :rtype: bytes
+ """
+ return bytes.fromhex(
+ f"{proto!s:0>20}{src_ip!s:0>12}{dst_ip!s:0>8}{src_port!s:0>4}"
+ f"{dst_port!s:0>4}"
+ ).rstrip(b'\0')
+
+ @staticmethod
+ def _build_ip6_mask(
+ next_hdr=u"", src_ip=u"", dst_ip=u"", src_port=u"", dst_port=u""):
+ """Build IPv6 ACL mask data in bytes format.
+
+ :param next_hdr: Next header number <0-ff>.
+ :param src_ip: Source ip address <0-ffffffff>.
+ :param dst_ip: Destination ip address <0-ffffffff>.
+ :param src_port: Source port number <0-ffff>.
+ :param dst_port: Destination port number <0-ffff>.
+ :type next_hdr: str
+ :type src_ip: str
+ :type dst_ip: str
+ :type src_port: str
+ :type dst_port: str
+ :returns: IPv6 ACL mask in bytes format.
+ :rtype: bytes
+ """
+ return bytes.fromhex(
+ f"{next_hdr!s:0>14}{src_ip!s:0>34}{dst_ip!s:0>32}{src_port!s:0>4}"
+ f"{dst_port!s:0>4}"
+ ).rstrip(b'\0')
+
+ @staticmethod
+ def _build_mac_match(dst_mac=u"", src_mac=u"", ether_type=u""):
+ """Build MAC ACL match data in bytes format.
+
+ :param dst_mac: Source MAC address <x:x:x:x:x:x>.
+ :param src_mac: Destination MAC address <x:x:x:x:x:x>.
+ :param ether_type: Ethernet type <0-ffff>.
+ :type dst_mac: str
+ :type src_mac: str
+ :type ether_type: str
+ :returns: MAC ACL match data in bytes format.
+ :rtype: bytes
+ """
+ return bytes.fromhex(
+ f"{dst_mac.replace(u':', u'')!s:0>12}"
+ f"{src_mac.replace(u':', u'')!s:0>12}"
+ f"{ether_type!s:0>4}"
+ ).rstrip(b'\0')
+
+ @staticmethod
+ def _build_ip_match(
+ proto=0, src_ip=4*b"\0", dst_ip=4*b"\0", src_port=0, dst_port=0):
+ """Build IP ACL match data in bytes format.
+
+ :param proto: Protocol number with valid option "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
+ :type src_ip: bytes
+ :type dst_ip: bytes
+ :type src_port: int
+ :type dst_port: int
+ :returns: IP ACL match data in byte-string format.
+ :rtype: str
+ """
+ return bytes.fromhex(
+ f"{hex(proto)[2:]!s:0>20}{src_ip.hex()!s:0>12}{dst_ip.hex()!s:0>8}"
+ f"{hex(src_port)[2:]!s:0>4}{hex(dst_port)[2:]!s:0>4}"
+ ).rstrip(b'\0')
+
+ @staticmethod
+ def _build_ip6_match(
+ next_hdr=0, src_ip=16*b"\0", dst_ip=16*b"\0", src_port=0,
+ dst_port=0):
+ """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 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
+ :type src_ip: bytes
+ :type dst_ip: bytes
+ :type src_port: int
+ :type dst_port: int
+ :returns: IPv6 ACL match data in bytes format.
+ :rtype: bytes
+ """
+ return bytes.fromhex(
+ f"{hex(next_hdr)[2:]!s:0>14}{src_ip.hex()!s:0>34}"
+ f"{dst_ip.hex()!s:0>32}{hex(src_port)[2:]!s:0>4}"
+ f"{hex(dst_port)[2:]!s:0>4}"
+ ).rstrip(b'\0')
+
+ @staticmethod
+ 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 True the table is added, if False table is deleted.
+ :param mask: ACL mask in hexstring format.
+ :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 = ~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.
+ 0: by default, classify data from the buffer's start location
+ 1: classify packets from VPP node's current data pointer.
+ :param current_data_offset: A signed value to shift the start location
+ of the packet to be classified.
+ For example, if input IP ACL node is used, L2 header's first byte
+ can be accessible by configuring current_data_offset to -14
+ if there is no vlan tag.
+ This is valid only if current_data_flag is set to 1.
+ (Default value = 0)
+ :type node: dict
+ :type is_add: bool
+ :type mask: str
+ :type match_n_vectors: int
+ :type table_index: int
+ :type nbuckets: int
+ :type memory_size: int
+ :type skip_n_vectors: int
+ :type next_table_index: int
+ :type miss_next_index: int
+ :type current_data_flag: int
+ :type current_data_offset: int
+ :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)
+ """
+ cmd = u"classify_add_del_table"
+ args = dict(
+ is_add=is_add,
+ del_chain=False,
+ table_index=table_index,
+ nbuckets=nbuckets,
+ memory_size=memory_size,
+ skip_n_vectors=skip_n_vectors,
+ match_n_vectors=match_n_vectors,
+ next_table_index=next_table_index,
+ miss_next_index=miss_next_index,
+ current_data_flag=current_data_flag,
+ current_data_offset=current_data_offset,
+ mask_len=len(mask),
+ mask=mask
+ )
+ err_msg = f"Failed to create a classify table on host {node[u'host']}"
+
+ with PapiSocketExecutor(node) as papi_exec:
+ reply = papi_exec.add(cmd, **args).get_reply(err_msg)
+
+ return int(reply[u"new_table_index"]), int(reply[u"skip_n_vectors"]),\
+ int(reply[u"match_n_vectors"])
+
+ @staticmethod
+ 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.
+ :param is_add: If True the session is added, if False the session
+ is deleted.
+ :param table_index: Index of the table to add/del the session.
+ :param match: For add, match value for session, required, needs to
+ 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 = ~0)
+ :param hit_next_index: For add, hit_next_index of new session.
+ (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
+ fib table (configured by metadata as VRF id).
+ Only valid for L3 input ACL node
+ 2: Classified IP packets will be looked up from the specified ipv6
+ fib table (configured by metadata as VRF id).
+ Only valid for L3 input ACL node
+ 3: Classified packet will be steered to source routing policy of
+ given index (in metadata).
+ This is only valid for IPv6 packets redirected to a source
+ routing node.
+ :param metadata: Valid only if action != 0. VRF id if action is 1 or 2.
+ SR policy index if action is 3. (Default value = 0)
+ :type node: dict
+ :type is_add: bool
+ :type table_index: int
+ :type match: bytes
+ :type opaque_index: int
+ :type hit_next_index: int
+ :type advance: int
+ :type action: int
+ :type metadata: int
+ """
+ cmd = u"classify_add_del_session"
+ args = dict(
+ is_add=is_add,
+ table_index=table_index,
+ hit_next_index=hit_next_index,
+ opaque_index=opaque_index,
+ advance=advance,
+ action=action,
+ metadata=metadata,
+ match_len=len(match),
+ match=match
+ )
+ err_msg = f"Failed to create a classify session on host {node[u'host']}"
+
+ with PapiSocketExecutor(node) as papi_exec:
+ papi_exec.add(cmd, **args).get_reply(err_msg)
+
+ @staticmethod
+ def _macip_acl_add(node, rules, tag=""):
+ """Add MACIP ACL.
+
+ :param node: VPP node to add MACIP ACL.
+ :param rules: List of rules for given ACL.
+ :param tag: ACL tag.
+ :type node: dict
+ :type rules: list
+ :type tag: str
+ """
+ cmd = u"macip_acl_add"
+ args = dict(
+ r=rules,
+ count=len(rules),
+ tag=tag
+ )
+
+ err_msg = f"Failed to add MACIP ACL on host {node[u'host']}"
+
+ with PapiSocketExecutor(node) as papi_exec:
+ papi_exec.add(cmd, **args).get_reply(err_msg)
+
+ @staticmethod
+ def _acl_interface_set_acl_list(node, sw_if_index, acl_type, acls):
+ """Set ACL list for interface.
+
+ :param node: VPP node to set ACL list for interface.
+ :param sw_if_index: sw_if_index of the used interface.
+ :param acl_type: Type of ACL(s) - input or output.
+ :param acls: List of ACLs.
+ :type node: dict
+ :type sw_if_index: int
+ :type acl_type: str
+ :type acls: list
+ """
+ cmd = u"acl_interface_set_acl_list"
+ args = dict(
+ sw_if_index=sw_if_index,
+ acls=acls,
+ n_input=len(acls) if acl_type == u"input" else 0,
+ count=len(acls)
+ )
+
+ err_msg = f"Failed to set acl list for interface {sw_if_index} " \
+ f"on host {node[u'host']}"
+
+ with PapiSocketExecutor(node) as papi_exec:
+ papi_exec.add(cmd, **args).get_reply(err_msg)
+
+ @staticmethod
+ def _acl_add_replace(node, acl_idx, rules, tag=""):
+ """ Add/replace ACLs.
+
+ :param node: VPP node to add MACIP ACL.
+ :param acl_idx: ACL index.
+ :param rules: List of rules for given ACL.
+ :param tag: ACL tag.
+ :type node: dict
+ :type acl_idx: int
+ :type rules: list
+ :type tag: str
+ """
+ cmd = u"acl_add_replace"
+ args = dict(
+ tag=tag,
+ acl_index=4294967295 if acl_idx is None else acl_idx,
+ count=len(rules),
+ r=rules
+ )
+
+ err_msg = f"Failed to add/replace ACLs on host {node[u'host']}"
+
+ with PapiSocketExecutor(node) as papi_exec:
+ papi_exec.add(cmd, **args).get_reply(err_msg)
+
+ @staticmethod
+ def vpp_creates_classify_table_l3(node, ip_version, direction, netmask):
+ """Create classify table for IP address filtering.