add new topology parameter: arch
[csit.git] / resources / libraries / python / topology.py
index 0214cc9..13dbddd 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2016 Cisco and/or its affiliates.
+# Copyright (c) 2018 Cisco and/or its affiliates.
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at:
@@ -18,20 +18,20 @@ from collections import Counter
 from yaml import load
 
 from robot.api import logger
-from robot.libraries.BuiltIn import BuiltIn
+from robot.libraries.BuiltIn import BuiltIn, RobotNotRunningError
 from robot.api.deco import keyword
 
-__all__ = ["DICT__nodes", 'Topology']
+__all__ = ["DICT__nodes", 'Topology', 'NodeType']
 
 
 def load_topo_from_yaml():
     """Load topology from file defined in "${TOPOLOGY_PATH}" variable.
 
-    :return: Nodes from loaded topology.
+    :returns: Nodes from loaded topology.
     """
     try:
         topo_path = BuiltIn().get_variable_value("${TOPOLOGY_PATH}")
-    except:
+    except RobotNotRunningError:
         return ''
 
     with open(topo_path) as work_file:
@@ -39,6 +39,7 @@ def load_topo_from_yaml():
 
 
 # pylint: disable=invalid-name
+
 class NodeType(object):
     """Defines node types used in topology dictionaries."""
     # Device Under Test (this node has VPP running on it)
@@ -86,7 +87,7 @@ class Topology(object):
         :param ptype: Port type, used as key prefix.
         :type node: dict
         :type ptype: str
-        :return: Port key or None
+        :returns: Port key or None
         :rtype: string or None
         """
         max_ports = 1000000
@@ -98,6 +99,21 @@ class Topology(object):
                 break
         return iface
 
+    @staticmethod
+    def remove_port(node, iface_key):
+        """Remove required port from active topology.
+
+        :param node: Node to remove port on.
+        :param: iface_key: Topology key of the interface.
+        :type node: dict
+        :type iface_key: str
+        :returns: Nothing
+        """
+        try:
+            node['interfaces'].pop(iface_key)
+        except KeyError:
+            pass
+
     @staticmethod
     def remove_all_ports(node, ptype):
         """Remove all ports with ptype as prefix.
@@ -106,12 +122,28 @@ class Topology(object):
         :param: ptype: Port type, used as key prefix.
         :type node: dict
         :type ptype: str
-        :return: Nothing
+        :returns: Nothing
         """
         for if_key in list(node['interfaces']):
             if if_key.startswith(str(ptype)):
                 node['interfaces'].pop(if_key)
 
+    @staticmethod
+    def remove_all_added_ports_on_all_duts_from_topology(nodes):
+        """Remove all added ports on all DUT nodes in the topology.
+
+        :param nodes: Nodes in the topology.
+        :type nodes: dict
+        :returns: Nothing
+        """
+        port_types = ('subinterface', 'vlan_subif', 'memif', 'tap', 'vhost',
+                      'loopback', 'gre_tunnel', 'vxlan_tunnel')
+
+        for node_data in nodes.values():
+            if node_data['type'] == NodeType.DUT:
+                for ptype in port_types:
+                    Topology.remove_all_ports(node_data, ptype)
+
     @staticmethod
     def update_interface_sw_if_index(node, iface_key, sw_if_index):
         """Update sw_if_index on the interface from the node.
@@ -164,6 +196,59 @@ class Topology(object):
         """
         node['interfaces'][iface_key]['vhost_socket'] = str(vhost_socket)
 
+    @staticmethod
+    def update_interface_memif_socket(node, iface_key, memif_socket):
+        """Update memif socket name on the interface from the node.
+
+        :param node: Node to update socket name on.
+        :param iface_key: Topology key of the interface.
+        :param memif_socket: Path to named socket on node.
+        :type node: dict
+        :type iface_key: str
+        :type memif_socket: str
+        """
+        node['interfaces'][iface_key]['memif_socket'] = str(memif_socket)
+
+    @staticmethod
+    def update_interface_memif_id(node, iface_key, memif_id):
+        """Update memif ID on the interface from the node.
+
+        :param node: Node to update memif ID on.
+        :param iface_key: Topology key of the interface.
+        :param memif_id: Memif interface ID.
+        :type node: dict
+        :type iface_key: str
+        :type memif_id: str
+        """
+        node['interfaces'][iface_key]['memif_id'] = str(memif_id)
+
+    @staticmethod
+    def update_interface_memif_role(node, iface_key, memif_role):
+        """Update memif role on the interface from the node.
+
+        :param node: Node to update memif role on.
+        :param iface_key: Topology key of the interface.
+        :param memif_role: Memif role.
+        :type node: dict
+        :type iface_key: str
+        :type memif_role: str
+        """
+        node['interfaces'][iface_key]['memif_role'] = str(memif_role)
+
+    @staticmethod
+    def update_interface_tap_dev_name(node, iface_key, dev_name):
+        """Update device name on the tap interface from the node.
+
+        :param node: Node to update tap device name on.
+        :param iface_key: Topology key of the interface.
+        :param dev_name: Device name of the tap interface.
+        :type node: dict
+        :type iface_key: str
+        :type dev_name: str
+        :returns: Nothing
+        """
+        node['interfaces'][iface_key]['dev_name'] = str(dev_name)
+
     @staticmethod
     def get_node_by_hostname(nodes, hostname):
         """Get node from nodes of the topology by hostname.
@@ -172,7 +257,7 @@ class Topology(object):
         :param hostname: Host name.
         :type nodes: dict
         :type hostname: str
-        :return: Node dictionary or None if not found.
+        :returns: Node dictionary or None if not found.
         """
         for node in nodes.values():
             if node['host'] == hostname:
@@ -186,7 +271,7 @@ class Topology(object):
 
         :param nodes: Nodes of the test topology.
         :type nodes: dict
-        :return: Links in the topology.
+        :returns: Links in the topology.
         :rtype: list
         """
         links = []
@@ -211,7 +296,7 @@ class Topology(object):
         :type node: dict
         :type key: string
         :type value: string
-        :return: Interface key from topology file
+        :returns: Interface key from topology file
         :rtype: string
         """
         interfaces = node['interfaces']
@@ -235,7 +320,7 @@ class Topology(object):
         :param iface_name: Interface name (string form).
         :type node: dict
         :type iface_name: string
-        :return: Interface key.
+        :returns: Interface key.
         :rtype: str
         """
         return Topology._get_interface_by_key_value(node, "name", iface_name)
@@ -251,7 +336,7 @@ class Topology(object):
         :param link_name: Name of the link that a interface is connected to.
         :type node: dict
         :type link_name: string
-        :return: Interface key of the interface connected to the given link.
+        :returns: Interface key of the interface connected to the given link.
         :rtype: str
         """
         return Topology._get_interface_by_key_value(node, "link", link_name)
@@ -267,7 +352,7 @@ class Topology(object):
         connected to.
         :type node: dict
         :type link_names: list
-        :return: Dictionary of interface names that are connected to the given
+        :returns: Dictionary of interface names that are connected to the given
         links.
         :rtype: dict
         """
@@ -293,7 +378,7 @@ class Topology(object):
         :param sw_index: Sw_index of the link that a interface is connected to.
         :type node: dict
         :type sw_index: int
-        :return: Interface name of the interface connected to the given link.
+        :returns: Interface name of the interface connected to the given link.
         :rtype: str
         """
         return Topology._get_interface_by_key_value(node, "vpp_sw_index",
@@ -307,12 +392,12 @@ class Topology(object):
         :param iface_key: Interface key from topology file, or sw_index.
         :type node: dict
         :type iface_key: str/int
-        :return: Return sw_if_index or None if not found.
+        :returns: Return sw_if_index or None if not found.
         """
         try:
             if isinstance(iface_key, basestring):
                 return node['interfaces'][iface_key].get('vpp_sw_index')
-            #FIXME: use only iface_key, do not use integer
+            # TODO: use only iface_key, do not use integer
             else:
                 return int(iface_key)
         except (KeyError, ValueError):
@@ -326,7 +411,7 @@ class Topology(object):
         :param iface_name: Interface name.
         :type node: dict
         :type iface_name: str
-        :return: Return sw_if_index or None if not found.
+        :returns: Return sw_if_index or None if not found.
         :raises TypeError: If provided interface name is not a string.
         """
         try:
@@ -347,7 +432,7 @@ class Topology(object):
         :param iface_key: Interface key from topology file.
         :type node: dict
         :type iface_key: str
-        :return: MTU or None if not found.
+        :returns: MTU or None if not found.
         :rtype: int
         """
         try:
@@ -364,7 +449,7 @@ class Topology(object):
         :param iface_key: Interface key from topology file.
         :type node: dict
         :type iface_key: str
-        :return: Interface name or None if not found.
+        :returns: Interface name or None if not found.
         :rtype: str
         """
         try:
@@ -385,7 +470,7 @@ class Topology(object):
         :type node: dict
         :type interface: str or int
 
-        :return: Interface key.
+        :returns: Interface key.
         :rtype: str
 
         :raises TypeError: If provided with invalid interface argument.
@@ -427,7 +512,7 @@ class Topology(object):
         :type interface: str or int
         :type wanted_format: str
 
-        :return: Interface name, interface key or sw_if_index.
+        :returns: Interface name, interface key or sw_if_index.
         :rtype: str or int
 
         :raises TypeError, ValueError: If provided with invalid arguments.
@@ -459,7 +544,7 @@ class Topology(object):
         :param iface_key: Interface key from topology file.
         :type node: dict
         :type iface_key: str
-        :return: numa node id, None if not available.
+        :returns: numa node id, None if not available.
         :rtype: int
         """
         try:
@@ -507,13 +592,28 @@ class Topology(object):
         :param iface_key: Interface key from topology file.
         :type node: dict
         :type iface_key: str
-        :return: Return MAC or None if not found.
+        :returns: Return MAC or None if not found.
         """
         try:
             return node['interfaces'][iface_key].get('mac_address')
         except KeyError:
             return None
 
+    @staticmethod
+    def get_interface_ip4(node, iface_key):
+        """Get IP4 address for the interface.
+
+        :param node: Node to get interface mac on.
+        :param iface_key: Interface key from topology file.
+        :type node: dict
+        :type iface_key: str
+        :returns: Return IP4 or None if not found.
+        """
+        try:
+            return node['interfaces'][iface_key].get('ip4_address', None)
+        except KeyError:
+            return None
+
     @staticmethod
     def get_adjacent_node_and_interface(nodes_info, node, iface_key):
         """Get node and interface adjacent to specified interface
@@ -526,7 +626,7 @@ class Topology(object):
         :type nodes_info: dict
         :type node: dict
         :type iface_key: str
-        :return: Return (node, interface_key) tuple or None if not found.
+        :returns: Return (node, interface_key) tuple or None if not found.
         :rtype: (dict, str)
         """
         link_name = None
@@ -561,7 +661,7 @@ class Topology(object):
         :param iface_key: Interface key from topology file.
         :type node: dict
         :type iface_key: str
-        :return: Return PCI address or None if not found.
+        :returns: Return PCI address or None if not found.
         """
         try:
             return node['interfaces'][iface_key].get('pci_address')
@@ -576,7 +676,7 @@ class Topology(object):
         :param iface_key: Interface key from topology file.
         :type node: dict
         :type iface_key: str
-        :return: Return interface driver or None if not found.
+        :returns: Return interface driver or None if not found.
         """
         try:
             return node['interfaces'][iface_key].get('driver')
@@ -589,7 +689,7 @@ class Topology(object):
 
         :param node: Node to get list of interfaces from.
         :type node: dict
-        :return: Return list of keys of all interfaces.
+        :returns: Return list of keys of all interfaces.
         :rtype: list
         """
         return node['interfaces'].keys()
@@ -602,7 +702,7 @@ class Topology(object):
         :param link_name: Link name.
         :type node: dict
         :type link_name: str
-        :return: MAC address string.
+        :returns: MAC address string.
         :rtype: str
         """
         for port in node['interfaces'].values():
@@ -618,7 +718,7 @@ class Topology(object):
         :param filter_list: Link filter criteria.
         :type node: dict
         :type filter_list: list of strings
-        :return: List of strings that represent link names occupied by the node.
+        :returns: List of strings representing link names occupied by the node.
         :rtype: list
         """
         interfaces = node['interfaces']
@@ -630,7 +730,7 @@ class Topology(object):
                         if filt == interface['model']:
                             link_names.append(interface['link'])
                 elif (filter_list is not None) and ('model' not in interface):
-                    logger.trace("Cannot apply filter on interface: {}"
+                    logger.trace('Cannot apply filter on interface: {}'
                                  .format(str(interface)))
                 else:
                     link_names.append(interface['link'])
@@ -652,7 +752,7 @@ class Topology(object):
         :type node2: dict
         :type filter_list_node1: list of strings
         :type filter_list_node2: list of strings
-        :return: List of strings that represent connecting link names.
+        :returns: List of strings that represent connecting link names.
         :rtype: list
         """
 
@@ -684,7 +784,7 @@ class Topology(object):
         :param node2: Connected node.
         :type node1: dict
         :type node2: dict
-        :return: Name of link connecting the two nodes together.
+        :returns: Name of link connecting the two nodes together.
         :rtype: str
         :raises: RuntimeError
         """
@@ -703,7 +803,7 @@ class Topology(object):
         :param node2: Second node.
         :type node1: dict
         :type node2: dict
-        :return: Egress interfaces.
+        :returns: Egress interfaces.
         :rtype: list
         """
         interfaces = []
@@ -731,7 +831,7 @@ class Topology(object):
         :param node2: Second node.
         :type node1: dict
         :type node2: dict
-        :return: Egress interface name.
+        :returns: Egress interface name.
         :rtype: str
         """
         interfaces = self.get_egress_interfaces_name_for_nodes(node1, node2)
@@ -764,7 +864,7 @@ class Topology(object):
         :type tgen: dict
         :type dut1: dict
         :type dut2: dict
-        :return: Dictionary of possible link combinations.
+        :returns: Dictionary of possible link combinations.
         :rtype: dict
         """
         # TODO: replace with generic function.
@@ -788,7 +888,7 @@ class Topology(object):
 
         :param node: Node to examine.
         :type node: dict
-        :return: True if node is type of TG, otherwise False.
+        :returns: True if node is type of TG, otherwise False.
         :rtype: bool
         """
         return node['type'] == NodeType.TG
@@ -799,11 +899,55 @@ class Topology(object):
 
         :param node: Node created from topology.
         :type node: dict
-        :return: Hostname or IP address.
+        :returns: Hostname or IP address.
         :rtype: str
         """
         return node['host']
 
+    @staticmethod
+    def get_node_arch(node):
+        """Return arch of the node.
+           Default to x86_64 if no arch present
+
+        :param node: Node created from topology.
+        :type node: dict
+        :returns: Node architecture
+        :rtype: str
+        """
+        try:
+            return node['arch']
+        except KeyError:
+            node['arch'] = 'x86_64'
+            return 'x86_64'
+
+    @staticmethod
+    def get_cryptodev(node):
+        """Return Crytodev configuration of the node.
+
+        :param node: Node created from topology.
+        :type node: dict
+        :returns: Cryptodev configuration string.
+        :rtype: str
+        """
+        try:
+            return node['cryptodev']
+        except KeyError:
+            return None
+
+    @staticmethod
+    def get_uio_driver(node):
+        """Return uio-driver configuration of the node.
+
+        :param node: Node created from topology.
+        :type node: dict
+        :returns: uio-driver configuration string.
+        :rtype: str
+        """
+        try:
+            return node['uio_driver']
+        except KeyError:
+            return None
+
     @staticmethod
     def set_interface_numa_node(node, iface_key, numa_node_id):
         """Set interface numa_node location.
@@ -812,7 +956,7 @@ class Topology(object):
         :param iface_key: Interface key from topology file.
         :type node: dict
         :type iface_key: str
-        :return: Return iface_key or None if not found.
+        :returns: Return iface_key or None if not found.
         """
         try:
             node['interfaces'][iface_key]['numa_node'] = numa_node_id