CSIT-843: Update actual topology in case of new/updated/deleted interface
[csit.git] / resources / libraries / python / InterfaceUtil.py
index bf1ba1e..503715c 100644 (file)
@@ -18,6 +18,7 @@ from time import time, sleep
 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
@@ -31,19 +32,39 @@ class InterfaceUtil(object):
     __UDEV_IF_RULES_FILE = '/etc/udev/rules.d/10-network.rules'
 
     @staticmethod
-    def set_interface_state(node, interface, state):
+    def set_interface_state(node, interface, state, if_type="key"):
         """Set interface state on a node.
 
         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 interface: Interface key or sw_if_index or name.
         :param state: One of 'up' or 'down'.
+        :param if_type: Interface type
         :type node: dict
         :type interface: str or int
         :type state: str
-        :return: nothing
+        :type if_type: str
+        :returns: Nothing.
+        :raises ValueError: If the interface type is unknown.
+        :raises ValueError: If the state of interface is unexpected.
+        :raises ValueError: If the node has an unknown node type.
         """
+
+        if if_type == "key":
+            if isinstance(interface, basestring):
+                sw_if_index = Topology.get_interface_sw_index(node, interface)
+                iface_name = Topology.get_interface_name(node, interface)
+            else:
+                sw_if_index = interface
+        elif if_type == "name":
+            iface_key = Topology.get_interface_by_name(node, interface)
+            if iface_key is not None:
+                sw_if_index = Topology.get_interface_sw_index(node, iface_key)
+            iface_name = interface
+        else:
+            raise ValueError("if_type unknown: {}".format(if_type))
+
         if node['type'] == NodeType.DUT:
             if state == 'up':
                 state = 'admin-up'
@@ -51,45 +72,41 @@ class InterfaceUtil(object):
                 state = 'admin-down'
             else:
                 raise ValueError('Unexpected interface state: {}'.format(state))
-
-            if isinstance(interface, basestring):
-                sw_if_index = Topology.get_interface_sw_index(node, interface)
-            else:
-                sw_if_index = interface
-
             VatExecutor.cmd_from_template(node, 'set_if_state.vat',
                                           sw_if_index=sw_if_index, state=state)
-
         elif node['type'] == NodeType.TG or node['type'] == NodeType.VM:
-            cmd = 'ip link set {} {}'.format(interface, state)
+            cmd = 'ip link set {} {}'.format(iface_name, state)
             exec_cmd_no_error(node, cmd, sudo=True)
         else:
-            raise Exception('Node {} has unknown NodeType: "{}"'.
-                            format(node['host'], node['type']))
+            raise ValueError('Node {} has unknown NodeType: "{}"'
+                             .format(node['host'], node['type']))
 
     @staticmethod
-    def set_interface_ethernet_mtu(node, interface, mtu):
+    def set_interface_ethernet_mtu(node, iface_key, mtu):
         """Set Ethernet MTU for specified interface.
 
         Function can be used only for TGs.
 
         :param node: Node where the interface is.
-        :param interface: Interface name.
+        :param iface_key: Interface key from topology file.
         :param mtu: MTU to set.
         :type node: dict
-        :type interface: str
+        :type iface_key: str
         :type mtu: int
-        :return: nothing
+        :returns: Nothing.
+        :raises ValueError: If the node type is "DUT".
+        :raises ValueError: If the node has an unknown node type.
         """
         if node['type'] == NodeType.DUT:
-            ValueError('Node {}: Setting Ethernet MTU for interface '
-                       'on DUT nodes not supported', node['host'])
+            raise ValueError('Node {}: Setting Ethernet MTU for interface '
+                             'on DUT nodes not supported', node['host'])
         elif node['type'] == NodeType.TG:
-            cmd = 'ip link set {} mtu {}'.format(interface, mtu)
+            iface_name = Topology.get_interface_name(node, iface_key)
+            cmd = 'ip link set {} mtu {}'.format(iface_name, mtu)
             exec_cmd_no_error(node, cmd, sudo=True)
         else:
-            raise ValueError('Node {} has unknown NodeType: "{}"'.
-                             format(node['host'], node['type']))
+            raise ValueError('Node {} has unknown NodeType: "{}"'
+                             .format(node['host'], node['type']))
 
     @staticmethod
     def set_default_ethernet_mtu_on_all_interfaces_on_node(node):
@@ -99,10 +116,10 @@ class InterfaceUtil(object):
 
         :param node: Node where to set default MTU.
         :type node: dict
-        :return: nothing
+        :returns: Nothing.
         """
-        for ifc in node['interfaces'].values():
-            InterfaceUtil.set_interface_ethernet_mtu(node, ifc['name'], 1500)
+        for ifc in node['interfaces']:
+            InterfaceUtil.set_interface_ethernet_mtu(node, ifc, 1500)
 
     @staticmethod
     def vpp_node_interfaces_ready_wait(node, timeout=10):
@@ -112,6 +129,7 @@ class InterfaceUtil(object):
         :param timeout: Waiting timeout in seconds (optional, default 10s).
         :type node: dict
         :type timeout: int
+        :returns: Nothing.
         :raises: RuntimeError if the timeout period value has elapsed.
         """
         if_ready = False
@@ -147,7 +165,7 @@ class InterfaceUtil(object):
         :param timeout: Seconds to wait per node for all interfaces to come up.
         :type nodes: list
         :type timeout: int
-        :raises: RuntimeError if the timeout period value has elapsed.
+        :returns: Nothing.
         """
         for node in nodes:
             InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
@@ -161,7 +179,7 @@ class InterfaceUtil(object):
         :param timeout: Seconds to wait per node for all interfaces to come up.
         :type nodes: dict
         :type timeout: int
-        :raises: RuntimeError if the timeout period value has elapsed.
+        :returns: Nothing.
         """
         for node in nodes.values():
             if node['type'] == NodeType.DUT:
@@ -177,9 +195,11 @@ class InterfaceUtil(object):
         :param interface: Numeric index or name string of a specific interface.
         :type node: dict
         :type interface: int or str
-        :return: List of dictionaries containing data for each interface, or a
+        :returns: List of dictionaries containing data for each interface, or a
         single dictionary for the specified interface.
         :rtype: list or dict
+        :raises TypeError: if the data type of interface is neither basestring
+        nor int.
         """
         with VatTerminal(node) as vat:
             response = vat.vat_terminal_exec_cmd_from_template(
@@ -189,15 +209,101 @@ class InterfaceUtil(object):
 
         if interface is not None:
             if isinstance(interface, basestring):
-                sw_if_index = Topology.get_interface_sw_index(node, interface)
+                param = "interface_name"
+            elif isinstance(interface, int):
+                param = "sw_if_index"
             else:
-                sw_if_index = interface
-
+                raise TypeError
             for data_if in data:
-                if data_if["sw_if_index"] == sw_if_index:
-
+                if data_if[param] == interface:
                     return data_if
+            return dict()
+        return data
+
+    @staticmethod
+    def vpp_get_interface_name(node, sw_if_index):
+        """Get interface name for the given SW interface index from actual
+        interface dump.
+
+        :param node: VPP node to get interface data from.
+        :param sw_if_index: SW interface index of the specific interface.
+        :type node: dict
+        :type sw_if_index: int
+        :returns: Name of the given interface.
+        :rtype: str
+        """
+
+        if_data = InterfaceUtil.vpp_get_interface_data(node, sw_if_index)
+        if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
+            if_data = InterfaceUtil.vpp_get_interface_data(
+                node, if_data['sup_sw_if_index'])
+        try:
+            if_name = if_data["interface_name"]
+        except KeyError:
+            if_name = None
+        return if_name
+
+    @staticmethod
+    def vpp_get_interface_mac(node, interface=None):
+        """Get MAC address for the given interface from actual interface dump.
+
+        :param node: VPP node to get interface data from.
+        :param interface: Numeric index or name string of a specific interface.
+        :type node: dict
+        :type interface: int or str
+        :returns: MAC address.
+        :rtype: str
+        """
+
+        if_data = InterfaceUtil.vpp_get_interface_data(node, interface)
+        if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
+            if_data = InterfaceUtil.vpp_get_interface_data(
+                node, if_data['sup_sw_if_index'])
+        mac_data = [str(hex(item))[2:] for item in if_data['l2_address'][:6]]
+        mac_data_nice = []
+        for item in mac_data:
+            if len(item) == 1:
+                item = '0' + item
+            mac_data_nice.append(item)
+        mac = ":".join(mac_data_nice)
+        return mac
+
+    @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
+         :returns: 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
+        """
+
+        try:
+            sw_if_index = Topology.convert_interface_reference(
+                node, interface, "sw_if_index")
+        except RuntimeError:
+            if isinstance(interface, basestring):
+                sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
+            else:
+                raise
+
+        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
@@ -210,6 +316,9 @@ class InterfaceUtil(object):
         :type node: dict
         :type pci_addr: str
         :type driver: str
+        :returns: None.
+        :raises RuntimeError: If unbinding from the current driver fails.
+        :raises RuntimeError: If binding to the new driver fails.
         """
         old_driver = InterfaceUtil.tg_get_interface_driver(node, pci_addr)
         if old_driver == driver:
@@ -220,19 +329,20 @@ class InterfaceUtil(object):
 
         # Unbind from current driver
         if old_driver is not None:
-            cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'.format(
-                pci_addr, old_driver)
+            cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'\
+                .format(pci_addr, old_driver)
             (ret_code, _, _) = ssh.exec_command_sudo(cmd)
             if int(ret_code) != 0:
-                raise Exception("'{0}' failed on '{1}'".format(cmd,
-                                                               node['host']))
+                raise RuntimeError("'{0}' failed on '{1}'"
+                                   .format(cmd, node['host']))
 
         # Bind to the new driver
-        cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'.format(
-            pci_addr, driver)
+        cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'\
+            .format(pci_addr, driver)
         (ret_code, _, _) = ssh.exec_command_sudo(cmd)
         if int(ret_code) != 0:
-            raise Exception("'{0}' failed on '{1}'".format(cmd, node['host']))
+            raise RuntimeError("'{0}' failed on '{1}'"
+                               .format(cmd, node['host']))
 
     @staticmethod
     def tg_get_interface_driver(node, pci_addr):
@@ -242,8 +352,10 @@ class InterfaceUtil(object):
         :param pci_addr: PCI address of the interface.
         :type node: dict
         :type pci_addr: str
-        :return: Interface driver or None if not found.
+        :returns: Interface driver or None if not found.
         :rtype: str
+        :raises RuntimeError: If it is not possible to get the interface driver
+        information from the node.
 
         .. note::
             # lspci -vmmks 0000:00:05.0
@@ -259,20 +371,35 @@ class InterfaceUtil(object):
         ssh = SSH()
         ssh.connect(node)
 
-        cmd = 'lspci -vmmks {0}'.format(pci_addr)
-
-        (ret_code, stdout, _) = ssh.exec_command(cmd)
-        if int(ret_code) != 0:
-            raise Exception("'{0}' failed on '{1}'".format(cmd, node['host']))
-
-        for line in stdout.splitlines():
-            if len(line) == 0:
-                continue
-            (name, value) = line.split("\t", 1)
-            if name == 'Driver:':
-                return value
+        for i in range(3):
+            logger.trace('Try {}: Get interface driver'.format(i))
+            cmd = 'sh -c "echo 1 > /sys/bus/pci/rescan"'
+            (ret_code, _, _) = ssh.exec_command_sudo(cmd)
+            if int(ret_code) != 0:
+                raise RuntimeError("'{0}' failed on '{1}'"
+                                   .format(cmd, node['host']))
 
-        return None
+            cmd = 'lspci -vmmks {0}'.format(pci_addr)
+            (ret_code, stdout, _) = ssh.exec_command(cmd)
+            if int(ret_code) != 0:
+                raise RuntimeError("'{0}' failed on '{1}'"
+                                   .format(cmd, node['host']))
+
+            for line in stdout.splitlines():
+                if len(line) == 0:
+                    continue
+                try:
+                    (name, value) = line.split("\t", 1)
+                except ValueError:
+                    if name != "Driver:":
+                        pass
+                    else:
+                        return None
+                if name == 'Driver:':
+                    return value if value else None
+        else:
+            raise RuntimeError('Get interface driver for: {0}'
+                               .format(pci_addr))
 
     @staticmethod
     def tg_set_interfaces_udev_rules(node):
@@ -289,6 +416,7 @@ class InterfaceUtil(object):
 
         :param node: Node to set udev rules on (must be TG node).
         :type node: dict
+        :raises RuntimeError: If setting of udev rules fails.
         """
         ssh = SSH()
         ssh.connect(node)
@@ -296,7 +424,8 @@ class InterfaceUtil(object):
         cmd = 'rm -f {0}'.format(InterfaceUtil.__UDEV_IF_RULES_FILE)
         (ret_code, _, _) = ssh.exec_command_sudo(cmd)
         if int(ret_code) != 0:
-            raise Exception("'{0}' failed on '{1}'".format(cmd, node['host']))
+            raise RuntimeError("'{0}' failed on '{1}'"
+                               .format(cmd, node['host']))
 
         for interface in node['interfaces'].values():
             rule = 'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \
@@ -306,8 +435,8 @@ class InterfaceUtil(object):
                 rule, InterfaceUtil.__UDEV_IF_RULES_FILE)
             (ret_code, _, _) = ssh.exec_command_sudo(cmd)
             if int(ret_code) != 0:
-                raise Exception("'{0}' failed on '{1}'".format(cmd,
-                                                               node['host']))
+                raise RuntimeError("'{0}' failed on '{1}'"
+                                   .format(cmd, node['host']))
 
         cmd = '/etc/init.d/udev restart'
         ssh.exec_command_sudo(cmd)
@@ -343,12 +472,54 @@ class InterfaceUtil(object):
         VatJsonUtil.update_vpp_interface_data_from_json(node,
                                                         interface_dump_json)
 
+    @staticmethod
+    def update_nic_interface_names(node):
+        """Update interface names based on nic type and PCI address.
+
+        This method updates interface names in the same format as VPP does.
+
+        :param node: Node dictionary.
+        :type node: dict
+        """
+        for ifc in node['interfaces'].values():
+            if_pci = ifc['pci_address'].replace('.', ':').split(':')
+            bus = '{:x}'.format(int(if_pci[1], 16))
+            dev = '{:x}'.format(int(if_pci[2], 16))
+            fun = '{:x}'.format(int(if_pci[3], 16))
+            loc = '{bus}/{dev}/{fun}'.format(bus=bus, dev=dev, fun=fun)
+            if ifc['model'] == 'Intel-XL710':
+                ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
+            elif ifc['model'] == 'Intel-X710':
+                ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
+            elif ifc['model'] == 'Intel-X520-DA2':
+                ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
+            elif ifc['model'] == 'Cisco-VIC-1385':
+                ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
+            elif ifc['model'] == 'Cisco-VIC-1227':
+                ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
+            else:
+                ifc['name'] = 'UnknownEthernet{loc}'.format(loc=loc)
+
+    @staticmethod
+    def update_nic_interface_names_on_all_duts(nodes):
+        """Update interface names based on nic type and PCI address on all DUTs.
+
+        This method updates interface names in the same format as VPP does.
+
+        :param nodes: Topology nodes.
+        :type nodes: dict
+        """
+        for node in nodes.values():
+            if node['type'] == NodeType.DUT:
+                InterfaceUtil.update_nic_interface_names(node)
+
     @staticmethod
     def update_tg_interface_data_on_node(node):
         """Update interface name for TG/linux node in DICT__nodes.
 
         :param node: Node selected from DICT__nodes.
         :type node: dict
+        :raises RuntimeError: If getting of interface name and MAC fails.
 
         .. note::
             # for dev in `ls /sys/class/net/`;
@@ -372,7 +543,7 @@ class InterfaceUtil(object):
 
         (ret_code, stdout, _) = ssh.exec_command(cmd)
         if int(ret_code) != 0:
-            raise Exception('Get interface name and MAC failed')
+            raise RuntimeError('Get interface name and MAC failed')
         tmp = "{" + stdout.rstrip().replace('\n', ',') + "}"
         interfaces = JsonParser().parse_data(tmp)
         for interface in node['interfaces'].values():
@@ -385,21 +556,83 @@ class InterfaceUtil(object):
         InterfaceUtil.tg_set_interfaces_udev_rules(node)
 
     @staticmethod
-    def update_all_interface_data_on_all_nodes(nodes):
+    def iface_update_numa_node(node):
+        """For all interfaces from topology file update numa node based on
+           information from the node.
+
+        :param node: Node from topology.
+        :type node: dict
+        :returns: Nothing.
+        :raises ValueError: If numa node ia less than 0.
+        :raises RuntimeError: If update of numa node failes.
+        """
+        ssh = SSH()
+        for if_key in Topology.get_node_interfaces(node):
+            if_pci = Topology.get_interface_pci_addr(node, if_key)
+            ssh.connect(node)
+            cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(if_pci)
+            for _ in range(3):
+                (ret, out, _) = ssh.exec_command(cmd)
+                if ret == 0:
+                    try:
+                        numa_node = int(out)
+                        if numa_node < 0:
+                            raise ValueError
+                    except ValueError:
+                        logger.trace('Reading numa location failed for: {0}'\
+                            .format(if_pci))
+                    else:
+                        Topology.set_interface_numa_node(node, if_key,
+                                                         numa_node)
+                        break
+            else:
+                raise RuntimeError('Update numa node failed for: {0}'\
+                    .format(if_pci))
+
+    @staticmethod
+    def update_all_numa_nodes(nodes, skip_tg=False):
+        """For all nodes and all their interfaces from topology file update numa
+        node information based on information from the node.
+
+        :param nodes: Nodes in the topology.
+        :param skip_tg: Skip TG node
+        :type nodes: dict
+        :type skip_tg: bool
+        :returns: Nothing.
+        """
+        for node in nodes.values():
+            if node['type'] == NodeType.DUT:
+                InterfaceUtil.iface_update_numa_node(node)
+            elif node['type'] == NodeType.TG and not skip_tg:
+                InterfaceUtil.iface_update_numa_node(node)
+
+    @staticmethod
+    def update_all_interface_data_on_all_nodes(nodes, skip_tg=False,
+                                               numa_node=False):
         """Update interface names on all nodes in DICT__nodes.
 
         This method updates the topology dictionary by querying interface lists
         of all nodes mentioned in the topology dictionary.
 
         :param nodes: Nodes in the topology.
+        :param skip_tg: Skip TG node
+        :param numa_node: Retrieve numa_node location.
         :type nodes: dict
+        :type skip_tg: bool
+        :type numa_node: bool
         """
         for node_data in nodes.values():
             if node_data['type'] == NodeType.DUT:
                 InterfaceUtil.update_vpp_interface_data_on_node(node_data)
-            elif node_data['type'] == NodeType.TG:
+            elif node_data['type'] == NodeType.TG and not skip_tg:
                 InterfaceUtil.update_tg_interface_data_on_node(node_data)
 
+            if numa_node:
+                if node_data['type'] == NodeType.DUT:
+                    InterfaceUtil.iface_update_numa_node(node_data)
+                elif node_data['type'] == NodeType.TG and not skip_tg:
+                    InterfaceUtil.iface_update_numa_node(node_data)
+
     @staticmethod
     def create_vlan_subinterface(node, interface, vlan):
         """Create VLAN subinterface on node.
@@ -410,19 +643,26 @@ class InterfaceUtil(object):
         :type node: dict
         :type interface: str
         :type vlan: int
-        :return: Name and index of created subinterface.
+        :returns: Name and index of created subinterface.
         :rtype: tuple
+        :raises RuntimeError: if it is unable to create VLAN subinterface on the
+        node.
         """
-        sw_if_index = Topology.get_interface_sw_index(node, interface)
+        iface_key = Topology.get_interface_by_name(node, interface)
+        sw_if_index = Topology.get_interface_sw_index(node, iface_key)
 
         output = VatExecutor.cmd_from_template(node, "create_vlan_subif.vat",
                                                sw_if_index=sw_if_index,
                                                vlan=vlan)
         if output[0]["retval"] == 0:
-            sw_subif_index = output[0]["sw_if_index"]
+            sw_subif_idx = output[0]["sw_if_index"]
             logger.trace('VLAN subinterface with sw_if_index {} and VLAN ID {} '
-                         'created on node {}'.format(sw_subif_index,
+                         'created on node {}'.format(sw_subif_idx,
                                                      vlan, node['host']))
+            if_key = Topology.add_new_port(node, "vlan_subif")
+            Topology.update_interface_sw_if_index(node, if_key, sw_subif_idx)
+            ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_subif_idx)
+            Topology.update_interface_name(node, if_key, ifc_name)
         else:
             raise RuntimeError('Unable to create VLAN subinterface on node {}'
                                .format(node['host']))
@@ -430,7 +670,7 @@ class InterfaceUtil(object):
         with VatTerminal(node, False) as vat:
             vat.vat_terminal_exec_cmd('exec show interfaces')
 
-        return '{}.{}'.format(interface, vlan), sw_subif_index
+        return '{}.{}'.format(interface, vlan), sw_subif_idx
 
     @staticmethod
     def create_vxlan_interface(node, vni, source_ip, destination_ip):
@@ -447,8 +687,10 @@ class InterfaceUtil(object):
         :type vni: int
         :type source_ip: str
         :type destination_ip: str
-        :return: SW IF INDEX of created interface.
+        :returns: SW IF INDEX of created interface.
         :rtype: int
+        :raises RuntimeError: if it is unable to create VxLAN interface on the
+        node.
         """
         output = VatExecutor.cmd_from_template(node, "vxlan_create.vat",
                                                src=source_ip,
@@ -457,7 +699,413 @@ class InterfaceUtil(object):
         output = output[0]
 
         if output["retval"] == 0:
-            return output["sw_if_index"]
+            sw_if_idx = output["sw_if_index"]
+            if_key = Topology.add_new_port(node, "vxlan_tunnel")
+            Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
+            ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
+            Topology.update_interface_name(node, if_key, ifc_name)
+            return sw_if_idx
         else:
-            raise RuntimeError('Unable to create VXLAN interface on node {}'
+            raise RuntimeError("Unable to create VXLAN interface on node {0}"
                                .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
+        :returns: Dictionary containing data for the given VxLAN interface or if
+        interface=None, the list of dictionaries with all VxLAN interfaces.
+        :rtype: dict or list
+        :raises TypeError: if the data type of interface is neither basestring
+        nor int.
+        """
+        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 TypeError("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 vhost_user_dump(node):
+        """Get vhost-user data for the given node.
+
+        :param node: VPP node to get interface data from.
+        :type node: dict
+        :returns: List of dictionaries with all vhost-user interfaces.
+        :rtype: list
+        """
+        with VatTerminal(node) as vat:
+            response = vat.vat_terminal_exec_cmd_from_template(
+                "vhost_user_dump.vat")
+
+        return response[0]
+
+    @staticmethod
+    def tap_dump(node, name=None):
+        """Get all TAP interface data from the given node, or data about
+        a specific TAP interface.
+
+        :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
+        """
+        with VatTerminal(node) as vat:
+            response = vat.vat_terminal_exec_cmd_from_template(
+                "tap_dump.vat")
+        if name is None:
+            return response[0]
+        else:
+            for item in response[0]:
+                if name == item['dev_name']:
+                    return item
+            return {}
+
+    @staticmethod
+    def create_subinterface(node, interface, sub_id, outer_vlan_id=None,
+                            inner_vlan_id=None, type_subif=None):
+        """Create sub-interface on node. It is possible to set required
+        sub-interface type and VLAN tag(s).
+
+        :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: Optional outer VLAN ID.
+        :param inner_vlan_id: Optional inner VLAN ID.
+        :param type_subif: Optional type of sub-interface. Values supported by
+        VPP: [no_tags] [one_tag] [two_tags] [dot1ad] [exact_match] [default_sub]
+        :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
+        :returns: Name and index of created sub-interface.
+        :rtype: tuple
+        :raises RuntimeError: If it is not possible to create sub-interface.
+        """
+
+        outer_vlan_id = 'outer_vlan_id {0}'.format(outer_vlan_id)\
+            if outer_vlan_id else ''
+
+        inner_vlan_id = 'inner_vlan_id {0}'.format(inner_vlan_id)\
+            if inner_vlan_id else ''
+
+        if type_subif is None:
+            type_subif = ''
+
+        if isinstance(interface, basestring):
+            iface_key = Topology.get_interface_by_name(node, interface)
+            sw_if_index = Topology.get_interface_sw_index(node, iface_key)
+        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_idx = output[0]["sw_if_index"]
+            logger.trace('Created subinterface with index {}'
+                         .format(sw_subif_idx))
+            if_key = Topology.add_new_port(node, "subinterface")
+            Topology.update_interface_sw_if_index(node, if_key, sw_subif_idx)
+            ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_subif_idx)
+            Topology.update_interface_name(node, if_key, ifc_name)
+        else:
+            raise RuntimeError('Unable to create sub-interface on node {}'
+                               .format(node['host']))
+
+        with VatTerminal(node, json_param=False) as vat:
+            vat.vat_terminal_exec_cmd('exec show interfaces')
+
+        name = '{}.{}'.format(interface, sub_id)
+        return name, sw_subif_idx
+
+    @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
+        :returns: 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_idx = 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_idx)
+
+            if_key = Topology.add_new_port(node, "gre_tunnel")
+            Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
+            Topology.update_interface_name(node, if_key, name)
+
+            return name, sw_if_idx
+        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
+        :returns: SW interface index.
+        :rtype: int
+        :raises RuntimeError: If it is not possible to create loopback on the
+        node.
+        """
+        out = VatExecutor.cmd_from_template(node, "create_loopback.vat")
+        if out[0].get('retval') == 0:
+            sw_if_idx = out[0].get('sw_if_index')
+            if_key = Topology.add_new_port(node, "loopback")
+            Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
+            ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
+            Topology.update_interface_name(node, if_key, ifc_name)
+            return sw_if_idx
+        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)
+
+    @staticmethod
+    def get_interface_classify_table(node, interface):
+        """Get name of classify table for the given interface.
+
+        :param node: VPP node to get data from.
+        :param interface: Name or sw_if_index of a specific interface.
+        :type node: dict
+        :type interface: str or int
+        :returns: Classify table name.
+        :rtype: str
+        """
+        if isinstance(interface, basestring):
+            sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
+        else:
+            sw_if_index = interface
+
+        with VatTerminal(node) as vat:
+            data = vat.vat_terminal_exec_cmd_from_template(
+                "classify_interface_table.vat",
+                sw_if_index=sw_if_index)
+        return data[0]
+
+    @staticmethod
+    def get_interface_vrf_table(node, interface):
+        """Get vrf ID for the given interface.
+
+        :param node: VPP node.
+        :param interface: Name or sw_if_index of a specific interface.
+        :type node: dict
+        :type interface: str or int
+        :returns: vrf ID of the specified interface.
+        :rtype: int
+        """
+
+        if isinstance(interface, basestring):
+            sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
+        else:
+            sw_if_index = interface
+
+        with VatTerminal(node) as vat:
+            data = vat.vat_terminal_exec_cmd_from_template(
+                "interface_vrf_dump.vat",
+                sw_if_index=sw_if_index)
+        return data[0]["vrf_id"]
+
+    @staticmethod
+    def get_sw_if_index(node, interface_name):
+        """Get sw_if_index for the given interface from actual interface dump.
+
+        :param node: VPP node to get interface data from.
+        :param interface_name: Name of the specific interface.
+        :type node: dict
+        :type interface_name: str
+        :returns: sw_if_index of the given interface.
+        :rtype: str
+        """
+
+        with VatTerminal(node) as vat:
+            if_data = vat.vat_terminal_exec_cmd_from_template(
+                "interface_dump.vat")
+        for interface in if_data[0]:
+            if interface["interface_name"] == interface_name:
+                return interface["sw_if_index"]
+
+        return None
+
+    @staticmethod
+    def vxlan_gpe_dump(node, interface_name=None):
+        """Get VxLAN GPE data for the given interface.
+
+        :param node: VPP node to get interface data from.
+        :param interface_name: Name of the specific interface. If None,
+        information about all VxLAN GPE interfaces is returned.
+        :type node: dict
+        :type interface_name: str
+        :returns: Dictionary containing data for the given VxLAN GPE interface
+        or if interface=None, the list of dictionaries with all VxLAN GPE
+        interfaces.
+        :rtype: dict or list
+        """
+
+        with VatTerminal(node) as vat:
+            vxlan_gpe_data = vat.vat_terminal_exec_cmd_from_template(
+                "vxlan_gpe_dump.vat")
+
+        if interface_name:
+            sw_if_index = InterfaceUtil.get_sw_if_index(node, interface_name)
+            if sw_if_index:
+                for vxlan_gpe in vxlan_gpe_data[0]:
+                    if vxlan_gpe["sw_if_index"] == sw_if_index:
+                        return vxlan_gpe
+            return {}
+
+        return vxlan_gpe_data[0]
+
+    @staticmethod
+    def vpp_proxy_arp_interface_enable(node, interface):
+        """Enable proxy ARP on interface.
+
+        :param node: VPP node to enable proxy ARP on interface.
+        :param interface: Interface to enable proxy ARP.
+        :type node: dict
+        :type interface: str or int
+        """
+        if isinstance(interface, basestring):
+            sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
+        else:
+            sw_if_index = interface
+
+        with VatTerminal(node) as vat:
+            vat.vat_terminal_exec_cmd_from_template(
+                "proxy_arp_intfc_enable.vat",
+                sw_if_index=sw_if_index)
+
+    @staticmethod
+    def vpp_ip_source_check_setup(node, interface):
+        """Setup Reverse Path Forwarding source check on interface.
+
+        :param node: Node to setup RPF source check.
+        :param interface: Interface name to setup RPF source check.
+        :type node: dict
+        :type interface: str
+        """
+        with VatTerminal(node) as vat:
+            vat.vat_terminal_exec_cmd_from_template("ip_source_check.vat",
+                                                    interface_name=interface)
+
+    @staticmethod
+    def assign_interface_to_fib_table(node, interface, table_id, ipv6=False):
+        """Assign VPP interface to specific VRF/FIB table.
+
+        :param node: VPP node where the FIB and interface are located.
+        :param interface: Interface to be assigned to FIB.
+        :param table_id: VRF table ID.
+        :param ipv6: Assign to IPv6 table. Default False.
+        :type node: dict
+        :type interface: str or int
+        :type table_id: int
+        :type ipv6: bool
+        """
+        if isinstance(interface, basestring):
+            sw_if_index = Topology.get_interface_sw_index(node, interface)
+        else:
+            sw_if_index = interface
+
+        ipv6 = 'ipv6' if ipv6 else ''
+
+        with VatTerminal(node) as vat:
+            ret = vat.vat_terminal_exec_cmd_from_template(
+                "set_fib_to_interface.vat",
+                sw_index=sw_if_index, vrf=table_id, ipv6=ipv6)
+
+        if ret[0]["retval"] != 0:
+            raise RuntimeError('Unable to assign interface to FIB node {}.'
+                               .format(node))
+
+    @staticmethod
+    def set_linux_interface_mac(node, interface, mac, namespace=None):
+        """Set MAC address for interface in linux.
+
+        :param node: Node where to execute command.
+        :param interface: Interface in namespace.
+        :param mac: MAC to be assigned to interface.
+        :param namespace: Execute command in namespace. Optional
+        :type node: dict
+        :type interface: str
+        :type mac: str
+        :type namespace: str
+        """
+        if namespace is not None:
+            cmd = 'ip netns exec {} ip link set {} address {}'.format(
+                namespace, interface, mac)
+        else:
+            cmd = 'ip link set {} address {}'.format(interface, mac)
+        exec_cmd_no_error(node, cmd, sudo=True)