Python3: resources and libraries
[csit.git] / resources / libraries / python / Classify.py
index 6d4b84c..4d05079 100644 (file)
@@ -13,7 +13,6 @@
 
 """Classify utilities library."""
 
-import binascii
 import re
 
 from ipaddress import ip_address
@@ -21,16 +20,16 @@ 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
+from resources.libraries.python.topology import Topology
 
 
-class Classify(object):
+class Classify:
     """Classify utilities."""
 
     @staticmethod
-    def _build_mac_mask(dst_mac='', src_mac='', ether_type=''):
-        """Build MAC ACL mask data in hexstring format.
+    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>.
@@ -38,18 +37,19 @@ class Classify(object):
         :type dst_mac: str
         :type src_mac: str
         :type ether_type: str
-        :returns MAC ACL mask in hexstring format.
-        :rtype: str
+        :returns MAC ACL mask in bytes format.
+        :rtype: bytes
         """
-
-        return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
-            dst_mac.replace(':', ''), src_mac.replace(':', ''),
-            ether_type)).decode('hex').rstrip('\0')
+        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='', src_ip='', dst_ip='', src_port='',
-                       dst_port=''):
-        """Build IP ACL mask data in hexstring format.
+    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>.
@@ -61,18 +61,18 @@ class Classify(object):
         :type dst_ip: str
         :type src_port: str
         :type dst_port:src
-        :returns: IP mask in hexstring format.
-        :rtype: str
+        :returns: IP mask in bytes format.
+        :rtype: bytes
         """
-
-        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)).decode('hex').\
-            rstrip('\0')
+        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='', src_ip='', dst_ip='', src_port='',
-                        dst_port=''):
-        """Build IPv6 ACL mask data in hexstring format.
+    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>.
@@ -84,17 +84,17 @@ class Classify(object):
         :type dst_ip: str
         :type src_port: str
         :type dst_port: str
-        :returns: IPv6 ACL mask in hexstring format.
-        :rtype: str
+        :returns: IPv6 ACL mask in bytes format.
+        :rtype: bytes
         """
-
-        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)).decode('hex').\
-            rstrip('\0')
+        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='', src_mac='', ether_type=''):
-        """Build MAC ACL match data in  hexstring format.
+    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>.
@@ -102,17 +102,19 @@ class Classify(object):
         :type dst_mac: str
         :type src_mac: str
         :type ether_type: str
-        :returns: MAC ACL match data in hexstring format.
-        :rtype: str
+        :returns: MAC ACL match data in bytes format.
+        :rtype: bytes
         """
-
-        return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
-            dst_mac.replace(':', ''), src_mac.replace(':', ''),
-            ether_type)).decode('hex').rstrip('\0')
+        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='', dst_ip='', src_port=0, dst_port=0):
-        """Build IP ACL match data in byte-string format.
+    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.
@@ -120,21 +122,22 @@ class Classify(object):
         :param src_port: Source port number "x".
         :param dst_port: Destination port number "x".
         :type proto: int
-        :type src_ip: str
-        :type dst_ip: str
+        :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 ('{!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:])).decode('hex').rstrip('\0')
+        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='', dst_ip='', src_port=0,
-                         dst_port=0):
+    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".
@@ -143,17 +146,18 @@ class Classify(object):
         :param src_port: Source port number "x".
         :param dst_port: Destination port number "x".
         :type next_hdr: int
-        :type src_ip: str
-        :type dst_ip: str
+        :type src_ip: bytes
+        :type dst_ip: bytes
         :type src_port: int
         :type dst_port: int
-        :returns: IPv6 ACL match data in byte-string format.
-        :rtype: str
+        :returns: IPv6 ACL match data in bytes format.
+        :rtype: bytes
         """
-
-        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:])).decode('hex').rstrip('\0')
+        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(
@@ -191,7 +195,7 @@ class Classify(object):
             (Default value = 0)
         :type node: dict
         :type is_add: int
-        :type mask: str
+        :type mask: bytes
         :type match_n_vectors: int
         :type table_index: int
         :type nbuckets: int
@@ -207,7 +211,7 @@ class Classify(object):
             match_n: Number of match vectors.
         :rtype: tuple(int, int, int)
         """
-        cmd = 'classify_add_del_table'
+        cmd = u"classify_add_del_table"
         args = dict(
             is_add=is_add,
             table_index=table_index,
@@ -222,14 +226,13 @@ class Classify(object):
             mask_len=len(mask),
             mask=mask
         )
-        err_msg = "Failed to create a classify table on host {host}".format(
-            host=node['host'])
+        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["new_table_index"]), int(reply["skip_n_vectors"]),\
-            int(reply["match_n_vectors"])
+        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(
@@ -267,14 +270,14 @@ class Classify(object):
         :type node: dict
         :type is_add: int
         :type table_index: int
-        :type match: str
+        :type match: bytes
         :type opaque_index: int
         :type hit_next_index: int
         :type advance: int
         :type action: int
         :type metadata: int
         """
-        cmd = 'classify_add_del_session'
+        cmd = u"classify_add_del_session"
         args = dict(
             is_add=is_add,
             table_index=table_index,
@@ -286,8 +289,7 @@ class Classify(object):
             match_len=len(match),
             match=match
         )
-        err_msg = "Failed to create a classify session on host {host}".format(
-            host=node['host'])
+        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)
@@ -303,15 +305,14 @@ class Classify(object):
         :type rules: list
         :type tag: str
         """
-        cmd = "macip_acl_add"
+        cmd = u"macip_acl_add"
         args = dict(
             r=rules,
             count=len(rules),
             tag=tag
         )
 
-        err_msg = "Failed to create a classify session on host {host}".format(
-            host=node['host'])
+        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)
@@ -329,8 +330,8 @@ class Classify(object):
         :type acl_type: str
         :type acls: list
         """
-        cmd = "acl_interface_set_acl_list"
-        n_input = len(acls) if acl_type == "input" else 0
+        cmd = u"acl_interface_set_acl_list"
+        n_input = len(acls) if acl_type == u"input" else 0
         args = dict(
             sw_if_index=sw_if_index,
             acls=acls,
@@ -338,8 +339,8 @@ class Classify(object):
             count=len(acls)
         )
 
-        err_msg = "Failed to set acl list for interface {idx} on host {host}".\
-            format(idx=sw_if_index, host=node['host'])
+        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)
@@ -357,7 +358,7 @@ class Classify(object):
         :type rules: list
         :type tag: str
         """
-        cmd = "acl_add_replace"
+        cmd = u"acl_add_replace"
         args = dict(
             tag=tag.encode("utf-8"),
             acl_index=4294967295 if acl_idx is None else acl_idx,
@@ -365,8 +366,7 @@ class Classify(object):
             r=rules
         )
 
-        err_msg = "Failed to add/replace acls on host {host}".format(
-            host=node['host'])
+        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)
@@ -397,32 +397,30 @@ class Classify(object):
             ip6=Classify._build_ip6_mask
         )
 
-        if ip_version == "ip4" or ip_version == "ip6":
-            netmask = binascii.hexlify(ip_address(unicode(netmask)).packed)
+        if ip_version in (u"ip4", u"ip6"):
+            netmask = ip_address(netmask).packed
         else:
-            raise ValueError("IP version {ver} is not supported.".format(
-                ver=ip_version))
+            raise ValueError(f"IP version {ip_version} is not supported.")
 
-        if direction == "src":
-            mask = mask_f[ip_version](src_ip=netmask)
-        elif direction == "dst":
-            mask = mask_f[ip_version](dst_ip=netmask)
+        if direction == u"src":
+            mask = mask_f[ip_version](src_ip=netmask.hex())
+        elif direction == u"dst":
+            mask = mask_f[ip_version](dst_ip=netmask.hex())
         else:
-            raise ValueError("Direction {dir} is not supported.".format(
-                dir=direction))
+            raise ValueError(f"Direction {direction} is not supported.")
 
         # Add l2 ethernet header to mask
-        mask = 14 * '\0' + mask
+        mask = 14 * b'\0' + mask
 
         # Get index of the first significant mask octet
-        i = len(mask) - len(mask.lstrip('\0'))
+        i = len(mask) - len(mask.lstrip(b'\0'))
 
         # 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'
+        mask = mask + (16 - len(mask) % 16 if len(mask) % 16 else 0) * b'\0'
         # Compute match_n parameter
         match_n = len(mask) // 16
 
@@ -473,27 +471,25 @@ class Classify(object):
             deny=1
         )
 
-        if ip_version == "ip4" or ip_version == "ip6":
-            address = binascii.hexlify(ip_address(unicode(address)).packed)
+        if ip_version in (u"ip4", u"ip6"):
+            address = ip_address(address).packed
         else:
-            raise ValueError("IP version {ver} is not supported.".format(
-                ver=ip_version))
+            raise ValueError(f"IP version {ip_version} is not supported.")
 
-        if direction == "src":
+        if direction == u"src":
             match = match_f[ip_version](src_ip=address)
-        elif direction == "dst":
+        elif direction == u"dst":
             match = match_f[ip_version](dst_ip=address)
         else:
-            raise ValueError("Direction {dir} is not supported.".format(
-                dir=direction))
+            raise ValueError(f"Direction {direction} is not supported.")
 
         # Prepend match with l2 ethernet header part
-        match = 14 * '\0' + match
+        match = 14 * b'\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'
+                         else 0) * b'\0'
 
         Classify._classify_add_del_session(
             node,
@@ -505,83 +501,6 @@ class Classify(object):
             action=action[acl_method]
         )
 
-    @staticmethod
-    def compute_classify_hex_mask(ip_version, protocol, direction):
-        """Compute classify hex mask for TCP or UDP packet matching.
-
-        :param ip_version: Version of IP protocol.
-        :param protocol: Type of protocol.
-        :param direction: Traffic direction.
-        :type ip_version: str
-        :type protocol: str
-        :type direction: str
-        :returns: Classify hex mask.
-        :rtype: str
-        :raises ValueError: If protocol is not TCP or UDP.
-        :raises ValueError: If direction is not source or destination or
-            source + destination.
-        """
-        if protocol in ('TCP', 'UDP'):
-            base_mask = Classify._compute_base_mask(ip_version)
-
-            if direction == 'source':
-                return base_mask + 'FFFF0000'
-            elif direction == 'destination':
-                return base_mask + '0000FFFF'
-            elif direction == 'source + destination':
-                return base_mask + 'FFFFFFFF'
-            else:
-                raise ValueError("Invalid direction!")
-        else:
-            raise ValueError("Invalid protocol!")
-
-    @staticmethod
-    def compute_classify_hex_value(hex_mask, source_port, destination_port):
-        """Compute classify hex value for TCP or UDP packet matching.
-
-        :param hex_mask: Classify hex mask.
-        :param source_port: Source TCP/UDP port.
-        :param destination_port: Destination TCP/UDP port.
-        :type hex_mask: str
-        :type source_port: str
-        :type destination_port: str
-        :returns: Classify hex value.
-        :rtype: str
-        """
-        source_port_hex = Classify._port_convert(source_port)
-        destination_port_hex = Classify._port_convert(destination_port)
-
-        return hex_mask[:-8] + source_port_hex + destination_port_hex
-
-    @staticmethod
-    def _port_convert(port):
-        """Convert port number for classify hex table format.
-
-        :param port: TCP/UDP port number.
-        :type port: str
-        :returns: TCP/UDP port number in 4-digit hexadecimal format.
-        :rtype: str
-        """
-        return '{0:04x}'.format(int(port))
-
-    @staticmethod
-    def _compute_base_mask(ip_version):
-        """Compute base classify hex mask based on IP version.
-
-        :param ip_version: Version of IP protocol.
-        :type ip_version: str
-        :returns: Base hex mask.
-        :rtype: str
-        """
-        if ip_version == 'ip4':
-            return 68 * '0'
-            # base value of classify hex table for IPv4 TCP/UDP ports
-        elif ip_version == 'ip6':
-            return 108 * '0'
-            # base value of classify hex table for IPv6 TCP/UDP ports
-        else:
-            raise ValueError("Invalid IP version!")
-
     @staticmethod
     def get_classify_table_data(node, table_index):
         """Retrieve settings for classify table by ID.
@@ -593,9 +512,8 @@ class Classify(object):
         :returns: Classify table settings.
         :rtype: dict
         """
-        cmd = 'classify_table_info'
-        err_msg = "Failed to get 'classify_table_info' on host {host}".format(
-            host=node['host'])
+        cmd = u"classify_table_info"
+        err_msg = f"Failed to get 'classify_table_info' on host {node[u'host']}"
         args = dict(
             table_id=int(table_index)
         )
@@ -614,7 +532,7 @@ class Classify(object):
         :returns: List of classify session settings.
         :rtype: list or dict
         """
-        cmd = "classify_session_dump"
+        cmd = u"classify_session_dump"
         args = dict(
             table_id=int(table_index)
         )
@@ -633,7 +551,8 @@ class Classify(object):
         :rtype: str
         """
         return PapiSocketExecutor.run_cli_cmd(
-            node, "show classify tables verbose")
+            node, u"show classify tables verbose"
+        )
 
     @staticmethod
     def vpp_log_plugin_acl_settings(node):
@@ -643,7 +562,7 @@ class Classify(object):
         :param node: VPP node.
         :type node: dict
         """
-        PapiSocketExecutor.dump_and_log(node, ["acl_dump", ])
+        PapiSocketExecutor.dump_and_log(node, [u"acl_dump", ])
 
     @staticmethod
     def vpp_log_plugin_acl_interface_assignment(node):
@@ -653,7 +572,7 @@ class Classify(object):
         :param node: VPP node.
         :type node: dict
         """
-        PapiSocketExecutor.dump_and_log(node, ["acl_interface_list_dump", ])
+        PapiSocketExecutor.dump_and_log(node, [u"acl_interface_list_dump", ])
 
     @staticmethod
     def set_acl_list_for_interface(node, interface, acl_type, acl_idx=None):
@@ -669,20 +588,19 @@ class Classify(object):
         :type acl_type: str
         :type acl_idx: list
         """
-        if isinstance(interface, basestring):
+        if isinstance(interface, str):
             sw_if_index = Topology.get_interface_sw_index(node, interface)
         else:
             sw_if_index = int(interface)
 
         acls = acl_idx if isinstance(acl_idx, list) else list()
 
-        Classify._acl_interface_set_acl_list(node=node,
-                                             sw_if_index=sw_if_index,
-                                             acl_type=acl_type,
-                                             acls=acls)
+        Classify._acl_interface_set_acl_list(
+            node=node, sw_if_index=sw_if_index, acl_type=acl_type, acls=acls
+        )
 
     @staticmethod
-    def add_replace_acl_multi_entries(node, acl_idx=None, rules=None, tag=""):
+    def add_replace_acl_multi_entries(node, acl_idx=None, rules=None, tag=u""):
         """Add a new ACL or replace the existing one. To replace an existing
         ACL, pass the ID of this ACL.
 
@@ -695,54 +613,54 @@ class Classify(object):
         :type rules: str
         :type tag: str
         """
-        reg_ex_src_ip = re.compile(r'(src [0-9a-fA-F.:/\d{1,2}]*)')
-        reg_ex_dst_ip = re.compile(r'(dst [0-9a-fA-F.:/\d{1,2}]*)')
-        reg_ex_sport = re.compile(r'(sport \d{1,5})')
-        reg_ex_dport = re.compile(r'(dport \d{1,5})')
-        reg_ex_proto = re.compile(r'(proto \d{1,5})')
+        reg_ex_src_ip = re.compile(r"(src [0-9a-fA-F.:/\d{1,2}]*)")
+        reg_ex_dst_ip = re.compile(r"(dst [0-9a-fA-F.:/\d{1,2}]*)")
+        reg_ex_sport = re.compile(r"(sport \d{1,5})")
+        reg_ex_dport = re.compile(r"(dport \d{1,5})")
+        reg_ex_proto = re.compile(r"(proto \d{1,5})")
 
         acl_rules = list()
-        for rule in rules.split(", "):
+        for rule in rules.split(u", "):
             acl_rule = dict()
-            acl_rule["is_permit"] = 1 if "permit" in rule else 0
-            acl_rule["is_ipv6"] = 1 if "ipv6" in rule else 0
+            acl_rule[u"is_permit"] = 1 if u"permit" in rule else 0
+            acl_rule[u"is_ipv6"] = 1 if u"ipv6" in rule else 0
 
             groups = re.search(reg_ex_src_ip, rule)
             if groups:
-                grp = groups.group(1).split(' ')[1].split('/')
-                acl_rule["src_ip_addr"] = ip_address(unicode(grp[0])).packed
-                acl_rule["src_ip_prefix_len"] = int(grp[1])
+                grp = groups.group(1).split(u" ")[1].split(u"/")
+                acl_rule[u"src_ip_addr"] = ip_address(grp[0]).packed
+                acl_rule[u"src_ip_prefix_len"] = int(grp[1])
 
             groups = re.search(reg_ex_dst_ip, rule)
             if groups:
-                grp = groups.group(1).split(' ')[1].split('/')
-                acl_rule["dst_ip_addr"] = ip_address(unicode(grp[0])).packed
-                acl_rule["dst_ip_prefix_len"] = int(grp[1])
+                grp = groups.group(1).split(u" ")[1].split(u"/")
+                acl_rule[u"dst_ip_addr"] = ip_address(grp[0]).packed
+                acl_rule[u"dst_ip_prefix_len"] = int(grp[1])
 
             groups = re.search(reg_ex_sport, rule)
             if groups:
-                port = int(groups.group(1).split(' ')[1])
-                acl_rule["srcport_or_icmptype_first"] = port
-                acl_rule["srcport_or_icmptype_last"] = port
+                port = int(groups.group(1).split(u" ")[1])
+                acl_rule[u"srcport_or_icmptype_first"] = port
+                acl_rule[u"srcport_or_icmptype_last"] = port
             else:
-                acl_rule["srcport_or_icmptype_first"] = 0
-                acl_rule["srcport_or_icmptype_last"] = 65535
+                acl_rule[u"srcport_or_icmptype_first"] = 0
+                acl_rule[u"srcport_or_icmptype_last"] = 65535
 
             groups = re.search(reg_ex_dport, rule)
             if groups:
-                port = int(groups.group(1).split(' ')[1])
-                acl_rule["dstport_or_icmpcode_first"] = port
-                acl_rule["dstport_or_icmpcode_last"] = port
+                port = int(groups.group(1).split(u" ")[1])
+                acl_rule[u"dstport_or_icmpcode_first"] = port
+                acl_rule[u"dstport_or_icmpcode_last"] = port
             else:
-                acl_rule["dstport_or_icmpcode_first"] = 0
-                acl_rule["dstport_or_icmpcode_last"] = 65535
+                acl_rule[u"dstport_or_icmpcode_first"] = 0
+                acl_rule[u"dstport_or_icmpcode_last"] = 65535
 
             groups = re.search(reg_ex_proto, rule)
             if groups:
                 proto = int(groups.group(1).split(' ')[1])
-                acl_rule["proto"] = proto
+                acl_rule[u"proto"] = proto
             else:
-                acl_rule["proto"] = 0
+                acl_rule[u"proto"] = 0
 
             acl_rules.append(acl_rule)
 
@@ -750,7 +668,7 @@ class Classify(object):
             node, acl_idx=acl_idx, rules=acl_rules, tag=tag)
 
     @staticmethod
-    def add_macip_acl_multi_entries(node, rules=""):
+    def add_macip_acl_multi_entries(node, rules=u""):
         """Add a new MACIP ACL.
 
         :param node: VPP node to set MACIP ACL on.
@@ -758,31 +676,31 @@ class Classify(object):
         :type node: dict
         :type rules: str
         """
-        reg_ex_ip = re.compile(r'(ip [0-9a-fA-F.:/\d{1,2}]*)')
-        reg_ex_mac = re.compile(r'(mac \S\S:\S\S:\S\S:\S\S:\S\S:\S\S)')
-        reg_ex_mask = re.compile(r'(mask \S\S:\S\S:\S\S:\S\S:\S\S:\S\S)')
+        reg_ex_ip = re.compile(r"(ip [0-9a-fA-F.:/\d{1,2}]*)")
+        reg_ex_mac = re.compile(r"(mac \S\S:\S\S:\S\S:\S\S:\S\S:\S\S)")
+        reg_ex_mask = re.compile(r"(mask \S\S:\S\S:\S\S:\S\S:\S\S:\S\S)")
 
         acl_rules = list()
-        for rule in rules.split(", "):
+        for rule in rules.split(u", "):
             acl_rule = dict()
-            acl_rule["is_permit"] = 1 if "permit" in rule else 0
-            acl_rule["is_ipv6"] = 1 if "ipv6" in rule else 0
+            acl_rule[u"is_permit"] = 1 if u"permit" in rule else 0
+            acl_rule[u"is_ipv6"] = 1 if u"ipv6" in rule else 0
 
             groups = re.search(reg_ex_mac, rule)
             if groups:
-                mac = groups.group(1).split(' ')[1].replace(':', '')
-                acl_rule["src_mac"] = binascii.unhexlify(unicode(mac))
+                mac = groups.group(1).split(u" ")[1].replace(u":", u"")
+                acl_rule[u"src_mac"] = bytes.fromhex(mac)
 
             groups = re.search(reg_ex_mask, rule)
             if groups:
-                mask = groups.group(1).split(' ')[1].replace(':', '')
-                acl_rule["src_mac_mask"] = binascii.unhexlify(unicode(mask))
+                mask = groups.group(1).split(u" ")[1].replace(u":", u"")
+                acl_rule[u"src_mac_mask"] = bytes.fromhex(mask)
 
             groups = re.search(reg_ex_ip, rule)
             if groups:
-                grp = groups.group(1).split(' ')[1].split('/')
-                acl_rule["src_ip_addr"] = ip_address(unicode(grp[0])).packed
-                acl_rule["src_ip_prefix_len"] = int(grp[1])
+                grp = groups.group(1).split(u" ")[1].split(u"/")
+                acl_rule[u"src_ip_addr"] = ip_address((grp[0])).packed
+                acl_rule[u"src_ip_prefix_len"] = int(grp[1])
 
             acl_rules.append(acl_rule)
 
@@ -796,7 +714,7 @@ class Classify(object):
         :param node: VPP node.
         :type node: dict
         """
-        PapiSocketExecutor.dump_and_log(node, ["macip_acl_dump", ])
+        PapiSocketExecutor.dump_and_log(node, [u"macip_acl_dump", ])
 
     @staticmethod
     def add_del_macip_acl_interface(node, interface, action, acl_idx):
@@ -812,16 +730,15 @@ class Classify(object):
         :type acl_idx: str or int
         :raises RuntimeError: If unable to set MACIP ACL for the interface.
         """
-        if isinstance(interface, basestring):
+        if isinstance(interface, str):
             sw_if_index = Topology.get_interface_sw_index(node, interface)
         else:
             sw_if_index = interface
 
-        is_add = 1 if action == "add" else 0
+        is_add = 1 if action == u"add" else 0
 
-        cmd = 'macip_acl_interface_add_del'
-        err_msg = "Failed to get 'macip_acl_interface' on host {host}".format(
-            host=node['host'])
+        cmd = u"macip_acl_interface_add_del"
+        err_msg = f"Failed to get 'macip_acl_interface' on host {node[u'host']}"
         args = dict(
             is_add=is_add,
             sw_if_index=int(sw_if_index),
@@ -837,9 +754,8 @@ class Classify(object):
         :param node: VPP node.
         :type node: dict
         """
-        cmd = 'macip_acl_interface_get'
-        err_msg = "Failed to get 'macip_acl_interface' on host {host}".format(
-            host=node['host'])
+        cmd = u"macip_acl_interface_get"
+        err_msg = f"Failed to get 'macip_acl_interface' on host {node[u'host']}"
         with PapiSocketExecutor(node) as papi_exec:
             reply = papi_exec.add(cmd).get_reply(err_msg)
         logger.info(reply)