CSIT-1473: Migrate Tap library from VAT to PAPI 54/20754/16
authorJan Gelety <jgelety@cisco.com>
Fri, 12 Jul 2019 12:53:24 +0000 (14:53 +0200)
committerJan Gelety <jgelety@cisco.com>
Wed, 7 Aug 2019 13:49:30 +0000 (13:49 +0000)
Change-Id: Ibf4a4839c2e8b799b03eebd9dffae891d8f00dd4
Signed-off-by: Jan Gelety <jgelety@cisco.com>
resources/api/vpp/supported_crcs.yaml
resources/libraries/python/InterfaceUtil.py
resources/libraries/python/Tap.py

index d0c7cc7..677efd9 100644 (file)
     sw_interface_set_table_reply: '0xe8d4e804'  # dev
     sw_interface_set_vxlan_bypass: '0xe74ca095'  # dev
     sw_interface_set_vxlan_bypass_reply: '0xe8d4e804'  # dev
+    sw_interface_tap_v2_dump: '0x51077d14'  # dev
+    sw_interface_tap_v2_details: '0x5ee87a5f'  # dev
     sw_interface_vhost_user_details: '0x91ff3307'  # dev
     sw_interface_vhost_user_dump: '0x51077d14'  # dev
+    tap_create_v2: '0x8fa99320'  # dev
+    tap_create_v2_reply: '0xfda5941f'  # dev
     vxlan_add_del_tunnel: '0x00f4bdd0'  # virl
     vxlan_add_del_tunnel_reply: '0xfda5941f'  # virl
     vxlan_tunnel_details: '0xce38e127'  # virl
index 34ccd7c..7024e85 100644 (file)
@@ -13,7 +13,6 @@
 
 """Interface util library."""
 
-from socket import AF_INET, AF_INET6, inet_ntop
 from time import sleep
 
 from enum import IntEnum
@@ -305,6 +304,21 @@ class InterfaceUtil(object):
         :raises TypeError: if the data type of interface is neither basestring
             nor int.
         """
+        def process_if_dump(if_dump):
+            """Process interface dump.
+
+            :param if_dump: Interface dump.
+            :type if_dump: dict
+            :returns: Processed interface dump.
+            :rtype: dict
+            """
+            if_dump['interface_name'] = if_dump['interface_name'].rstrip('\x00')
+            if_dump['tag'] = if_dump['tag'].rstrip('\x00')
+            if_dump['l2_address'] = L2Util.bin_to_mac(if_dump['l2_address'])
+            if_dump['b_dmac'] = L2Util.bin_to_mac(if_dump['b_dmac'])
+            if_dump['b_smac'] = L2Util.bin_to_mac(if_dump['b_smac'])
+            return if_dump
+
         if interface is not None:
             if isinstance(interface, basestring):
                 param = 'interface_name'
@@ -324,27 +338,12 @@ class InterfaceUtil(object):
         with PapiSocketExecutor(node) as papi_exec:
             details = papi_exec.add(cmd, **args).get_details(err_msg)
 
-        def process_if_dump(if_dump):
-            """Process interface dump.
-
-            :param if_dump: Interface dump.
-            :type if_dump: dict
-            :returns: Processed interface dump.
-            :rtype: dict
-            """
-            if_dump['interface_name'] = if_dump['interface_name'].rstrip('\x00')
-            if_dump['tag'] = if_dump['tag'].rstrip('\x00')
-            if_dump['l2_address'] = L2Util.bin_to_mac(if_dump['l2_address'])
-            if_dump['b_dmac'] = L2Util.bin_to_mac(if_dump['b_dmac'])
-            if_dump['b_smac'] = L2Util.bin_to_mac(if_dump['b_smac'])
-            return if_dump
-
         data = list() if interface is None else dict()
-        for if_dump in details:
+        for dump in details:
             if interface is None:
-                data.append(process_if_dump(if_dump))
-            elif str(if_dump.get(param)).rstrip('\x00') == str(interface):
-                data = process_if_dump(if_dump)
+                data.append(process_if_dump(dump))
+            elif str(dump.get(param)).rstrip('\x00') == str(interface):
+                data = process_if_dump(dump)
                 break
 
         logger.debug('Interface data:\n{if_data}'.format(if_data=data))
@@ -823,18 +822,6 @@ class InterfaceUtil(object):
         :raises TypeError: if the data type of interface is neither basestring
             nor int.
         """
-        if interface is not None:
-            sw_if_index = InterfaceUtil.get_interface_index(node, interface)
-        else:
-            sw_if_index = int(Constants.BITWISE_NON_ZERO)
-
-        cmd = 'vxlan_tunnel_dump'
-        args = dict(sw_if_index=sw_if_index)
-        err_msg = 'Failed to get VXLAN dump on host {host}'.format(
-            host=node['host'])
-        with PapiSocketExecutor(node) as papi_exec:
-            details = papi_exec.add(cmd, **args).get_details(err_msg)
-
         def process_vxlan_dump(vxlan_dump):
             """Process vxlan dump.
 
@@ -845,22 +832,34 @@ class InterfaceUtil(object):
             """
             if vxlan_dump['is_ipv6']:
                 vxlan_dump['src_address'] = \
-                    inet_ntop(AF_INET6, vxlan_dump['src_address'])
+                    ip_address(unicode(vxlan_dump['src_address']))
                 vxlan_dump['dst_address'] = \
-                    inet_ntop(AF_INET6, vxlan_dump['dst_address'])
+                    ip_address(unicode(vxlan_dump['dst_address']))
             else:
                 vxlan_dump['src_address'] = \
-                    inet_ntop(AF_INET, vxlan_dump['src_address'][0:4])
+                    ip_address(unicode(vxlan_dump['src_address'][0:4]))
                 vxlan_dump['dst_address'] = \
-                    inet_ntop(AF_INET, vxlan_dump['dst_address'][0:4])
+                    ip_address(unicode(vxlan_dump['dst_address'][0:4]))
             return vxlan_dump
 
+        if interface is not None:
+            sw_if_index = InterfaceUtil.get_interface_index(node, interface)
+        else:
+            sw_if_index = int(Constants.BITWISE_NON_ZERO)
+
+        cmd = 'vxlan_tunnel_dump'
+        args = dict(sw_if_index=sw_if_index)
+        err_msg = 'Failed to get VXLAN dump on host {host}'.format(
+            host=node['host'])
+        with PapiSocketExecutor(node) as papi_exec:
+            details = papi_exec.add(cmd, **args).get_details(err_msg)
+
         data = list() if interface is None else dict()
-        for vxlan_dump in details:
+        for dump in details:
             if interface is None:
-                data.append(process_vxlan_dump(vxlan_dump))
-            elif vxlan_dump['sw_if_index'] == sw_if_index:
-                data = process_vxlan_dump(vxlan_dump)
+                data.append(process_vxlan_dump(dump))
+            elif dump['sw_if_index'] == sw_if_index:
+                data = process_vxlan_dump(dump)
                 break
 
         logger.debug('VXLAN data:\n{vxlan_data}'.format(vxlan_data=data))
@@ -877,12 +876,6 @@ class InterfaceUtil(object):
         :returns: List of dictionaries with all vhost-user interfaces.
         :rtype: list
         """
-        cmd = 'sw_interface_vhost_user_dump'
-        err_msg = 'Failed to get vhost-user dump on host {host}'.format(
-            host=node['host'])
-        with PapiSocketExecutor(node) as papi_exec:
-            details = papi_exec.add(cmd).get_details(err_msg)
-
         def process_vhost_dump(vhost_dump):
             """Process vhost dump.
 
@@ -897,65 +890,19 @@ class InterfaceUtil(object):
                 vhost_dump['sock_filename'].rstrip('\x00')
             return vhost_dump
 
-        for vhost_dump in details:
-            # In-place edits.
-            process_vhost_dump(vhost_dump)
-
-        logger.debug('Vhost-user details:\n{vhost_details}'.format(
-            vhost_details=details))
-        return details
-
-    @staticmethod
-    def tap_dump(node, name=None):
-        """Get all TAP interface data from the given node, or data about
-        a specific TAP interface.
-
-        TODO: Move to Tap.py
-
-        :param node: VPP node to get data from.
-        :param name: Optional name of a specific TAP interface.
-        :type node: dict
-        :type name: str
-        :returns: Dictionary of information about a specific TAP interface, or
-            a List of dictionaries containing all TAP data for the given node.
-        :rtype: dict or list
-        """
-        cmd = 'sw_interface_tap_v2_dump'
-        err_msg = 'Failed to get TAP dump on host {host}'.format(
+        cmd = 'sw_interface_vhost_user_dump'
+        err_msg = 'Failed to get vhost-user dump on host {host}'.format(
             host=node['host'])
         with PapiSocketExecutor(node) as papi_exec:
             details = papi_exec.add(cmd).get_details(err_msg)
 
-        def process_tap_dump(tap_dump):
-            """Process tap dump.
-
-            :param tap_dump: Tap interface dump.
-            :type tap_dump: dict
-            :returns: Processed tap interface dump.
-            :rtype: dict
-            """
-            tap_dump['dev_name'] = tap_dump['dev_name'].rstrip('\x00')
-            tap_dump['host_if_name'] = tap_dump['host_if_name'].rstrip('\x00')
-            tap_dump['host_namespace'] = \
-                tap_dump['host_namespace'].rstrip('\x00')
-            tap_dump['host_mac_addr'] = \
-                L2Util.bin_to_mac(tap_dump['host_mac_addr'])
-            tap_dump['host_ip4_addr'] = \
-                inet_ntop(AF_INET, tap_dump['host_ip4_addr'])
-            tap_dump['host_ip6_addr'] = \
-                inet_ntop(AF_INET6, tap_dump['host_ip6_addr'])
-            return tap_dump
-
-        data = list() if name is None else dict()
-        for tap_dump in details:
-            if name is None:
-                data.append(process_tap_dump(tap_dump))
-            elif tap_dump.get('dev_name').rstrip('\x00') == name:
-                data = process_tap_dump(tap_dump)
-                break
+        for dump in details:
+            # In-place edits.
+            process_vhost_dump(dump)
 
-        logger.debug('TAP data:\n{tap_data}'.format(tap_data=data))
-        return data
+        logger.debug('Vhost-user details:\n{vhost_details}'.format(
+            vhost_details=details))
+        return details
 
     @staticmethod
     def create_subinterface(node, interface, sub_id, outer_vlan_id=None,
@@ -1246,15 +1193,6 @@ class InterfaceUtil(object):
         :returns: Bond slave interface data.
         :rtype: dict
         """
-        cmd = 'sw_interface_slave_dump'
-        args = dict(sw_if_index=Topology.get_interface_sw_index(
-            node, interface))
-        err_msg = 'Failed to get slave dump on host {host}'.format(
-            host=node['host'])
-
-        with PapiSocketExecutor(node) as papi_exec:
-            details = papi_exec.add(cmd, **args).get_details(err_msg)
-
         def process_slave_dump(slave_dump):
             """Process slave dump.
 
@@ -1267,9 +1205,18 @@ class InterfaceUtil(object):
                 rstrip('\x00')
             return slave_dump
 
-        for slave_dump in details:
+        cmd = 'sw_interface_slave_dump'
+        args = dict(sw_if_index=Topology.get_interface_sw_index(
+            node, interface))
+        err_msg = 'Failed to get slave dump on host {host}'.format(
+            host=node['host'])
+
+        with PapiSocketExecutor(node) as papi_exec:
+            details = papi_exec.add(cmd, **args).get_details(err_msg)
+
+        for dump in details:
             # In-place edits.
-            process_slave_dump(slave_dump)
+            process_slave_dump(dump)
 
         logger.debug('Slave data:\n{slave_data}'.format(slave_data=details))
         return details
@@ -1372,19 +1319,6 @@ class InterfaceUtil(object):
             interfaces.
         :rtype: dict or list
         """
-        if interface_name is not None:
-            sw_if_index = InterfaceUtil.get_interface_index(
-                node, interface_name)
-        else:
-            sw_if_index = int(Constants.BITWISE_NON_ZERO)
-
-        cmd = 'vxlan_gpe_tunnel_dump'
-        args = dict(sw_if_index=sw_if_index)
-        err_msg = 'Failed to get VXLAN-GPE dump on host {host}'.format(
-            host=node['host'])
-        with PapiSocketExecutor(node) as papi_exec:
-            details = papi_exec.add(cmd, **args).get_details(err_msg)
-
         def process_vxlan_gpe_dump(vxlan_dump):
             """Process vxlan_gpe dump.
 
@@ -1395,22 +1329,35 @@ class InterfaceUtil(object):
             """
             if vxlan_dump['is_ipv6']:
                 vxlan_dump['local'] = \
-                    inet_ntop(AF_INET6, vxlan_dump['local'])
+                    ip_address(unicode(vxlan_dump['local']))
                 vxlan_dump['remote'] = \
-                    inet_ntop(AF_INET6, vxlan_dump['remote'])
+                    ip_address(unicode(vxlan_dump['remote']))
             else:
                 vxlan_dump['local'] = \
-                    inet_ntop(AF_INET, vxlan_dump['local'][0:4])
+                    ip_address(unicode(vxlan_dump['local'][0:4]))
                 vxlan_dump['remote'] = \
-                    inet_ntop(AF_INET, vxlan_dump['remote'][0:4])
+                    ip_address(unicode(vxlan_dump['remote'][0:4]))
             return vxlan_dump
 
+        if interface_name is not None:
+            sw_if_index = InterfaceUtil.get_interface_index(
+                node, interface_name)
+        else:
+            sw_if_index = int(Constants.BITWISE_NON_ZERO)
+
+        cmd = 'vxlan_gpe_tunnel_dump'
+        args = dict(sw_if_index=sw_if_index)
+        err_msg = 'Failed to get VXLAN-GPE dump on host {host}'.format(
+            host=node['host'])
+        with PapiSocketExecutor(node) as papi_exec:
+            details = papi_exec.add(cmd, **args).get_details(err_msg)
+
         data = list() if interface_name is None else dict()
-        for vxlan_dump in details:
+        for dump in details:
             if interface_name is None:
-                data.append(process_vxlan_gpe_dump(vxlan_dump))
-            elif vxlan_dump['sw_if_index'] == sw_if_index:
-                data = process_vxlan_gpe_dump(vxlan_dump)
+                data.append(process_vxlan_gpe_dump(dump))
+            elif dump['sw_if_index'] == sw_if_index:
+                data = process_vxlan_gpe_dump(dump)
                 break
 
         logger.debug('VXLAN-GPE data:\n{vxlan_gpe_data}'.format(
index 2a1d7ef..103eeff 100644 (file)
 
 """Tap utilities library."""
 
-from resources.libraries.python.VatExecutor import VatTerminal
+from ipaddress import ip_address
+from robot.api import logger
+
+from resources.libraries.python.Constants import Constants
+from resources.libraries.python.L2Util import L2Util
 from resources.libraries.python.InterfaceUtil import InterfaceUtil
+from resources.libraries.python.PapiExecutor import PapiSocketExecutor
 from resources.libraries.python.topology import Topology
 
 
@@ -29,147 +34,115 @@ class Tap(object):
         :param tap_name: Tap interface name for linux tap.
         :param mac: Optional MAC address for VPP tap.
         :type node: dict
-        :type tap_name: str
+        :type tap_name: str or unicode
         :type mac: str
         :returns: Returns a interface index.
         :rtype: int
         """
-        command = 'create'
-        if mac is not None:
-            args = 'tapname {} mac {}'.format(tap_name, mac)
-        else:
-            args = 'tapname {}'.format(tap_name)
-        with VatTerminal(node) as vat:
-            resp = vat.vat_terminal_exec_cmd_from_template('tap.vat',
-                                                           tap_command=command,
-                                                           tap_arguments=args)
-        sw_if_index = resp[0]['sw_if_index']
+        if isinstance(tap_name, unicode):
+            tap_name = str(tap_name)
+        cmd = 'tap_create_v2'
+        args = dict(
+            id=Constants.BITWISE_NON_ZERO,
+            use_random_mac=0 if mac else 1,
+            mac_address=L2Util.mac_to_bin(mac) if mac else 6 * b'\x00',
+            host_namespace=64 * b'\x00',
+            host_mac_addr=6 * b'\x00',
+            host_if_name_set=1,
+            host_if_name=tap_name + (64 - len(tap_name)) * b'\x00',
+            host_bridge=64 * b'\x00',
+            host_ip4_addr=4 * b'\x00',
+            host_ip6_addr=16 * b'\x00',
+            host_ip4_gw=4 * b'\x00',
+            host_ip6_gw=16 * b'\x00'
+        )
+        err_msg = 'Failed to create tap interface {tap} on host {host}'.format(
+            tap=tap_name, host=node['host'])
+
+        with PapiSocketExecutor(node) as papi_exec:
+            sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
+
         if_key = Topology.add_new_port(node, 'tap')
         Topology.update_interface_sw_if_index(node, if_key, sw_if_index)
-        ifc_name = Tap.vpp_get_tap_interface_name(node, sw_if_index)
-        Topology.update_interface_name(node, if_key, ifc_name)
+        Topology.update_interface_name(node, if_key, tap_name)
         if mac is None:
-            mac = Tap.vpp_get_tap_interface_mac(node, sw_if_index)
+            mac = Tap.vpp_get_tap_interface_mac(node, tap_name)
         Topology.update_interface_mac_address(node, if_key, mac)
-        Topology.update_interface_tap_dev_name(node, if_key, tap_name)
+        tap_dev_name = Tap.vpp_get_tap_dev_name(node, tap_name)
+        Topology.update_interface_tap_dev_name(node, if_key, tap_dev_name)
 
         return sw_if_index
 
     @staticmethod
-    def modify_tap_interface(node, sw_if_index, tap_name, mac=None):
-        """Modify tap interface like linux interface name or VPP MAC.
-
-        :param node: Node to modify tap on.
-        :param sw_if_index: Index of tap interface to be modified.
-        :param tap_name: Tap interface name for linux tap.
-        :param mac: Optional MAC address for VPP tap.
-        :type node: dict
-        :type sw_if_index: int
-        :type tap_name: str
-        :type mac: str
-        :returns: Returns a interface index.
-        :rtype: int
-        """
-        command = 'modify'
-        if mac is not None:
-            args = 'sw_if_index {} tapname {} mac {}'.format(
-                sw_if_index, tap_name, mac)
-        else:
-            args = 'sw_if_index {} tapname {}'.format(sw_if_index, tap_name)
-        with VatTerminal(node) as vat:
-            resp = vat.vat_terminal_exec_cmd_from_template('tap.vat',
-                                                           tap_command=command,
-                                                           tap_arguments=args)
-        if_key = Topology.get_interface_by_sw_index(node, sw_if_index)
-        Topology.update_interface_tap_dev_name(node, if_key, tap_name)
-        if mac:
-            Topology.update_interface_mac_address(node, if_key, mac)
-
-        return resp[0]['sw_if_index']
-
-    @staticmethod
-    def delete_tap_interface(node, sw_if_index):
-        """Delete tap interface.
-
-        :param node: Node to delete tap on.
-        :param sw_if_index: Index of tap interface to be deleted.
-        :type node: dict
-        :type sw_if_index: int
-        :raises RuntimeError: Deletion was not successful.
-        """
-        command = 'delete'
-        args = 'sw_if_index {}'.format(sw_if_index)
-        with VatTerminal(node) as vat:
-            resp = vat.vat_terminal_exec_cmd_from_template('tap.vat',
-                                                           tap_command=command,
-                                                           tap_arguments=args)
-            if int(resp[0]['retval']) != 0:
-                raise RuntimeError(
-                    'Could not remove tap interface: {}'.format(resp))
-        if_key = Topology.get_interface_sw_index(node, sw_if_index)
-        Topology.remove_port(node, if_key)
-
-    @staticmethod
-    def check_tap_present(node, tap_name):
-        """Check whether specific tap interface exists.
+    def vpp_get_tap_dev_name(node, host_if_name):
+        """Get VPP tap interface name from hardware interfaces dump.
 
-        :param node: Node to check tap on.
-        :param tap_name: Tap interface name for linux tap.
+        :param node: DUT node.
+        :param host_if_name: Tap host interface name.
         :type node: dict
-        :type tap_name: str
-        :raises RuntimeError: Specified interface was not found.
+        :type host_if_name: str
+        :returns: VPP tap interface dev_name.
+        :rtype: str
         """
-        tap_if = InterfaceUtil.tap_dump(node, tap_name)
-        if not tap_if:
-            raise RuntimeError(
-                'Tap interface :{} does not exist'.format(tap_name))
+        return Tap.tap_dump(node, host_if_name).get('dev_name')
 
     @staticmethod
-    def vpp_get_tap_interface_name(node, sw_if_index):
-        """Get VPP tap interface name from hardware interfaces dump.
+    def vpp_get_tap_interface_mac(node, interface_name):
+        """Get tap interface MAC address from interfaces dump.
 
         :param node: DUT node.
-        :param sw_if_index: DUT node.
+        :param interface_name: Tap interface name.
         :type node: dict
-        :type sw_if_index: int
-        :returns: VPP tap interface name.
+        :type interface_name: str
+        :returns: Tap interface MAC address.
         :rtype: str
         """
-        with VatTerminal(node, json_param=False) as vat:
-            response = vat.vat_terminal_exec_cmd_from_template(
-                'show_hardware_detail.vat')
-
-        for line in str(response[0]).splitlines():
-            if line.startswith('tap-'):
-                line_split = line.split()
-                if line_split[1] == sw_if_index:
-                    return line_split[0]
-
-        return None
+        return InterfaceUtil.vpp_get_interface_mac(node, interface_name)
 
     @staticmethod
-    def vpp_get_tap_interface_mac(node, sw_if_index):
-        """Get tap interface MAC address from hardware interfaces dump.
+    def tap_dump(node, name=None):
+        """Get all TAP interface data from the given node, or data about
+        a specific TAP interface.
 
-        :param node: DUT node.
-        :param sw_if_index: DUT node.
+        :param node: VPP node to get data from.
+        :param name: Optional name of a specific TAP interface.
         :type node: dict
-        :type sw_if_index: int
-        :returns: Tap interface MAC address.
-        :rtype: str
+        :type name: str
+        :returns: Dictionary of information about a specific TAP interface, or
+            a List of dictionaries containing all TAP data for the given node.
+        :rtype: dict or list
         """
-        with VatTerminal(node, json_param=False) as vat:
-            response = vat.vat_terminal_exec_cmd_from_template(
-                'show_hardware_detail.vat')
-
-        tap_if_match = False
-        for line in str(response[0]).splitlines():
-            if tap_if_match:
-                line_split = line.split()
-                return line_split[-1]
-            if line.startswith('tap-'):
-                line_split = line.split()
-                if line_split[1] == sw_if_index:
-                    tap_if_match = True
-
-        return None
+        def process_tap_dump(tap_dump):
+            """Process tap dump.
+
+            :param tap_dump: Tap interface dump.
+            :type tap_dump: dict
+            :returns: Processed tap interface dump.
+            :rtype: dict
+            """
+            tap_dump['dev_name'] = tap_dump['dev_name'].rstrip('\x00')
+            tap_dump['host_if_name'] = tap_dump['host_if_name'].rstrip('\x00')
+            tap_dump['host_namespace'] = \
+                tap_dump['host_namespace'].rstrip('\x00')
+            tap_dump['host_mac_addr'] = \
+                L2Util.bin_to_mac(tap_dump['host_mac_addr'])
+            tap_dump['host_ip4_addr'] = ip_address(tap_dump['host_ip4_addr'])
+            tap_dump['host_ip6_addr'] = ip_address(tap_dump['host_ip6_addr'])
+            return tap_dump
+
+        cmd = 'sw_interface_tap_v2_dump'
+        err_msg = 'Failed to get TAP dump on host {host}'.format(
+            host=node['host'])
+        with PapiSocketExecutor(node) as papi_exec:
+            details = papi_exec.add(cmd).get_details(err_msg)
+
+        data = list() if name is None else dict()
+        for dump in details:
+            if name is None:
+                data.append(process_tap_dump(dump))
+            elif dump.get('host_if_name').rstrip('\x00') == name:
+                data = process_tap_dump(dump)
+                break
+
+        logger.debug('TAP data:\n{tap_data}'.format(tap_data=data))
+        return data