CSIT-18: Add GRE tunnel libraries and tests.
[csit.git] / resources / libraries / python / InterfaceUtil.py
index 6526fe8..94250fb 100644 (file)
@@ -18,6 +18,7 @@ from time import time, sleep
 from robot.api import logger
 
 from resources.libraries.python.ssh import SSH
 from robot.api import logger
 
 from resources.libraries.python.ssh import SSH
+from resources.libraries.python.IPUtil import convert_ipv4_netmask_prefix
 from resources.libraries.python.ssh import exec_cmd_no_error
 from resources.libraries.python.topology import NodeType, Topology
 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
 from resources.libraries.python.ssh import exec_cmd_no_error
 from resources.libraries.python.topology import NodeType, Topology
 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
@@ -36,9 +37,9 @@ class InterfaceUtil(object):
 
         Function can be used for DUTs as well as for TGs.
 
 
         Function can be used for DUTs as well as for TGs.
 
-        :param node: node where the interface is
-        :param interface: interface name or sw_if_index
-        :param state: one of 'up' or 'down'
+        :param node: Node where the interface is.
+        :param interface: Interface name or sw_if_index.
+        :param state: One of 'up' or 'down'.
         :type node: dict
         :type interface: str or int
         :type state: str
         :type node: dict
         :type interface: str or int
         :type state: str
@@ -73,9 +74,9 @@ class InterfaceUtil(object):
 
         Function can be used only for TGs.
 
 
         Function can be used only for TGs.
 
-        :param node: node where the interface is
-        :param interface: interface name
-        :param mtu: MTU to set
+        :param node: Node where the interface is.
+        :param interface: Interface name.
+        :param mtu: MTU to set.
         :type node: dict
         :type interface: str
         :type mtu: int
         :type node: dict
         :type interface: str
         :type mtu: int
@@ -97,7 +98,7 @@ class InterfaceUtil(object):
 
         Function can be used only for TGs.
 
 
         Function can be used only for TGs.
 
-        :param node: node where to set default MTU
+        :param node: Node where to set default MTU.
         :type node: dict
         :return: nothing
         """
         :type node: dict
         :return: nothing
         """
@@ -109,7 +110,7 @@ class InterfaceUtil(object):
         """Wait until all interfaces with admin-up are in link-up state.
 
         :param node: Node to wait on.
         """Wait until all interfaces with admin-up are in link-up state.
 
         :param node: Node to wait on.
-        :param timeout: Waiting timeout in seconds (optional, default 10s)
+        :param timeout: Waiting timeout in seconds (optional, default 10s).
         :type node: dict
         :type timeout: int
         :raises: RuntimeError if the timeout period value has elapsed.
         :type node: dict
         :type timeout: int
         :raises: RuntimeError if the timeout period value has elapsed.
@@ -172,6 +173,7 @@ class InterfaceUtil(object):
         """Get all interface data from a VPP node. If a name or
         sw_interface_index is provided, return only data for the matching
         interface.
         """Get all interface data from a VPP node. If a name or
         sw_interface_index is provided, return only data for the matching
         interface.
+
         :param node: VPP node to get interface data from.
         :param interface: Numeric index or name string of a specific interface.
         :type node: dict
         :param node: VPP node to get interface data from.
         :param interface: Numeric index or name string of a specific interface.
         :type node: dict
@@ -199,6 +201,36 @@ class InterfaceUtil(object):
 
         return data
 
 
         return data
 
+    @staticmethod
+    def vpp_get_interface_ip_addresses(node, interface, ip_version):
+        """Get list of IP addresses from an interface on a VPP node.
+
+         :param node: VPP node to get data from.
+         :param interface: Name of an interface on the VPP node.
+         :param ip_version: IP protocol version (ipv4 or ipv6).
+         :type node: dict
+         :type interface: str
+         :type ip_version: str
+         :return: List of dictionaries, each containing IP address, subnet
+         prefix length and also the subnet mask for ipv4 addresses.
+         Note: A single interface may have multiple IP addresses assigned.
+         :rtype: list
+        """
+        sw_if_index = Topology.get_interface_sw_index(node, interface)
+
+        with VatTerminal(node) as vat:
+            response = vat.vat_terminal_exec_cmd_from_template(
+                "ip_address_dump.vat", ip_version=ip_version,
+                sw_if_index=sw_if_index)
+
+        data = response[0]
+
+        if ip_version == "ipv4":
+            for item in data:
+                item["netmask"] = convert_ipv4_netmask_prefix(
+                    item["prefix_length"])
+        return data
+
     @staticmethod
     def tg_set_interface_driver(node, pci_addr, driver):
         """Set interface driver on the TG node.
     @staticmethod
     def tg_set_interface_driver(node, pci_addr, driver):
         """Set interface driver on the TG node.
@@ -325,7 +357,7 @@ class InterfaceUtil(object):
 
     @staticmethod
     def update_vpp_interface_data_on_node(node):
 
     @staticmethod
     def update_vpp_interface_data_on_node(node):
-        """Update vpp generated interface data for a given node in DICT__nodes
+        """Update vpp generated interface data for a given node in DICT__nodes.
 
         Updates interface names, software if index numbers and any other details
         generated specifically by vpp that are unknown before testcase run.
 
         Updates interface names, software if index numbers and any other details
         generated specifically by vpp that are unknown before testcase run.
@@ -333,7 +365,7 @@ class InterfaceUtil(object):
         devices using vpp_api_test, and pairing known information from topology
         (mac address/pci address of interface) to state from VPP.
 
         devices using vpp_api_test, and pairing known information from topology
         (mac address/pci address of interface) to state from VPP.
 
-        :param node: Node selected from DICT__nodes
+        :param node: Node selected from DICT__nodes.
         :type node: dict
         """
         vat_executor = VatExecutor()
         :type node: dict
         """
         vat_executor = VatExecutor()
@@ -460,3 +492,158 @@ class InterfaceUtil(object):
         else:
             raise RuntimeError('Unable to create VXLAN interface on node {}'
                                .format(node))
         else:
             raise RuntimeError('Unable to create VXLAN interface on node {}'
                                .format(node))
+
+    @staticmethod
+    def vxlan_dump(node, interface=None):
+        """Get VxLAN data for the given interface.
+
+        :param node: VPP node to get interface data from.
+        :param interface: Numeric index or name string of a specific interface.
+        If None, information about all VxLAN interfaces is returned.
+        :type node: dict
+        :type interface: int or str
+        :return: Dictionary containing data for the given VxLAN interface or if
+        interface=None, the list of dictionaries with all VxLAN interfaces.
+        :rtype dict or list
+        """
+        param = "sw_if_index"
+        if interface is None:
+            param = ''
+            sw_if_index = ''
+        elif isinstance(interface, basestring):
+            sw_if_index = Topology.get_interface_sw_index(node, interface)
+        elif isinstance(interface, int):
+            sw_if_index = interface
+        else:
+            raise Exception("Wrong interface format {0}".format(interface))
+
+        with VatTerminal(node) as vat:
+            response = vat.vat_terminal_exec_cmd_from_template(
+                "vxlan_dump.vat", param=param, sw_if_index=sw_if_index)
+
+        if sw_if_index:
+            for vxlan in response[0]:
+                if vxlan["sw_if_index"] == sw_if_index:
+                    return vxlan
+            return {}
+        return response[0]
+
+    @staticmethod
+    def create_subinterface(node, interface, sub_id, outer_vlan_id,
+                            inner_vlan_id, type_subif):
+        """Create sub-interface on node.
+
+        :param node: Node to add sub-interface.
+        :param interface: Interface name on which create sub-interface.
+        :param sub_id: ID of the sub-interface to be created.
+        :param outer_vlan_id: Outer VLAN ID.
+        :param inner_vlan_id: Inner VLAN ID.
+        :param type_subif: Type of sub-interface.
+        :type node: dict
+        :type interface: str or int
+        :type sub_id: int
+        :type outer_vlan_id: int
+        :type inner_vlan_id: int
+        :type type_subif: str
+        :return: name and index of created sub-interface
+        :rtype: tuple
+        """
+
+        if isinstance(interface, basestring):
+            sw_if_index = Topology.get_interface_sw_index(node, interface)
+        else:
+            sw_if_index = interface
+
+        output = VatExecutor.cmd_from_template(node, "create_sub_interface.vat",
+                                               sw_if_index=sw_if_index,
+                                               sub_id=sub_id,
+                                               outer_vlan_id=outer_vlan_id,
+                                               inner_vlan_id=inner_vlan_id,
+                                               type_subif=type_subif)
+
+        if output[0]["retval"] == 0:
+            sw_subif_index = output[0]["sw_if_index"]
+            logger.trace('Created subinterface with index {}'
+                         .format(sw_subif_index))
+        else:
+            raise RuntimeError('Unable to create subinterface on node {}'
+                               .format(node['host']))
+
+        with VatTerminal(node) as vat:
+            vat.vat_terminal_exec_cmd('exec show interfaces')
+
+        name = '{}.{}'.format(interface, sub_id)
+        return name, sw_subif_index
+
+    @staticmethod
+    def create_gre_tunnel_interface(node, source_ip, destination_ip):
+        """Create GRE tunnel interface on node.
+
+        :param node: VPP node to add tunnel interface.
+        :param source_ip: Source of the GRE tunnel.
+        :param destination_ip: Destination of the GRE tunnel.
+        :type node: dict
+        :type source_ip: str
+        :type destination_ip: str
+        :return: Name and index of created GRE tunnel interface.
+        :rtype: tuple
+        :raises RuntimeError: If unable to create GRE tunnel interface.
+        """
+        output = VatExecutor.cmd_from_template(node, "create_gre.vat",
+                                               src=source_ip,
+                                               dst=destination_ip)
+        output = output[0]
+
+        if output["retval"] == 0:
+            sw_if_index = output["sw_if_index"]
+
+            vat_executor = VatExecutor()
+            vat_executor.execute_script_json_out("dump_interfaces.vat", node)
+            interface_dump_json = vat_executor.get_script_stdout()
+            name = VatJsonUtil.get_interface_name_from_json(
+                interface_dump_json, sw_if_index)
+            return name, sw_if_index
+        else:
+            raise RuntimeError('Unable to create GRE tunnel on node {}.'
+                               .format(node))
+
+    @staticmethod
+    def vpp_create_loopback(node):
+        """Create loopback interface on VPP node.
+
+        :param node: Node to create loopback interface on.
+        :type node: dict
+        :return: SW interface index.
+        :rtype: int
+        """
+        out = VatExecutor.cmd_from_template(node, "create_loopback.vat")
+        if out[0].get('retval') == 0:
+            return out[0].get('sw_if_index')
+        else:
+            raise RuntimeError('Create loopback failed on node "{}"'
+                               .format(node['host']))
+
+    @staticmethod
+    def vpp_enable_input_acl_interface(node, interface, ip_version,
+                                       table_index):
+        """Enable input acl on interface.
+
+        :param node: VPP node to setup interface for input acl.
+        :param interface: Interface to setup input acl.
+        :param ip_version: Version of IP protocol.
+        :param table_index: Classify table index.
+        :type node: dict
+        :type interface: str or int
+        :type ip_version: str
+        :type table_index: int
+        """
+        if isinstance(interface, basestring):
+            sw_if_index = Topology.get_interface_sw_index(node, interface)
+        else:
+            sw_if_index = interface
+
+        with VatTerminal(node) as vat:
+            vat.vat_terminal_exec_cmd_from_template("input_acl_int.vat",
+                                                    sw_if_index=sw_if_index,
+                                                    ip_version=ip_version,
+                                                    table_index=table_index)