"""Defines nodes and topology structure."""
+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']
def load_topo_from_yaml():
"""Load topology from file defined in "${TOPOLOGY_PATH}" variable.
- :return: Nodes from loaded topology.
+ :returns: Nodes from loaded topology.
"""
- topo_path = BuiltIn().get_variable_value("${TOPOLOGY_PATH}")
+ try:
+ topo_path = BuiltIn().get_variable_value("${TOPOLOGY_PATH}")
+ except RobotNotRunningError:
+ return ''
with open(topo_path) as work_file:
return load(work_file.read())['nodes']
+# pylint: disable=invalid-name
+
class NodeType(object):
"""Defines node types used in topology dictionaries."""
# Device Under Test (this node has VPP running on it)
class NodeSubTypeTG(object):
+ """Defines node sub-type TG - traffic generator."""
# T-Rex traffic generator
TREX = 'TREX'
# Moongen
"""
node['interfaces'][iface_key]['vpp_sw_index'] = int(sw_if_index)
+ @staticmethod
+ def update_interface_name(node, iface_key, name):
+ """Update name on the interface from the node.
+
+ :param node: Node to update name on.
+ :param iface_key: Topology key of the interface.
+ :param name: Interface name to store.
+ :type node: dict
+ :type iface_key: str
+ :type name: str
+ """
+ node['interfaces'][iface_key]['name'] = str(name)
+
@staticmethod
def update_interface_mac_address(node, iface_key, mac_address):
"""Update mac_address on the interface from the node.
:return: Interface name of the interface connected to the given link.
:rtype: str
"""
- return Topology._get_interface_by_key_value(node, "vpp_sw_index", sw_index)
+ return Topology._get_interface_by_key_value(node, "vpp_sw_index",
+ sw_index)
@staticmethod
def get_interface_sw_index(node, iface_key):
- """Get VPP sw_if_index for the interface.
+ """Get VPP sw_if_index for the interface using interface key.
:param node: Node to get interface sw_if_index on.
:param iface_key: Interface key from topology file, or sw_index.
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):
return None
+ @staticmethod
+ def get_interface_sw_index_by_name(node, iface_name):
+ """Get VPP sw_if_index for the interface using interface name.
+
+ :param node: Node to get interface sw_if_index on.
+ :param iface_name: Interface name.
+ :type node: dict
+ :type iface_name: str
+ :return: Return sw_if_index or None if not found.
+ :raises TypeError: If provided interface name is not a string.
+ """
+ try:
+ if isinstance(iface_name, basestring):
+ iface_key = Topology.get_interface_by_name(node, iface_name)
+ return node['interfaces'][iface_key].get('vpp_sw_index')
+ else:
+ raise TypeError("Interface name must be a string.")
+ except (KeyError, ValueError):
+ return None
+
@staticmethod
def get_interface_mtu(node, iface_key):
"""Get interface MTU.
:type node: dict
:type iface_key: str
:return: Interface name or None if not found.
- :rtype: int
+ :rtype: str
"""
try:
return node['interfaces'][iface_key].get('name')
except KeyError:
return None
+ @staticmethod
+ def convert_interface_reference_to_key(node, interface):
+ """Takes interface reference in any format
+ (name, link name, interface key or sw_if_index)
+ and converts to interface key using Topology methods.
+
+ :param node: Node in topology.
+ :param interface: Name, sw_if_index, link name or key of an interface
+ on the node.
+ Valid formats are: sw_if_index, key, name.
+ :type node: dict
+ :type interface: str or int
+
+ :return: Interface key.
+ :rtype: str
+
+ :raises TypeError: If provided with invalid interface argument.
+ :raises RuntimeError: If the interface does not exist in topology.
+ """
+
+ if isinstance(interface, int):
+ key = Topology.get_interface_by_sw_index(node, interface)
+ if key is None:
+ raise RuntimeError("Interface with sw_if_index={0} does not "
+ "exist in topology.".format(interface))
+ elif interface in Topology.get_node_interfaces(node):
+ key = interface
+ elif interface in Topology.get_links({"dut": node}):
+ key = Topology.get_interface_by_link_name(node, interface)
+ elif isinstance(interface, basestring):
+ key = Topology.get_interface_by_name(node, interface)
+ if key is None:
+ raise RuntimeError("Interface with key, name or link name "
+ "\"{0}\" does not exist in topology."
+ .format(interface))
+ else:
+ raise TypeError("Type of interface argument must be integer"
+ " or string.")
+ return key
+
+ @staticmethod
+ def convert_interface_reference(node, interface, wanted_format):
+ """Takes interface reference in any format
+ (name, link name, topology key or sw_if_index) and returns
+ its equivalent in the desired format.
+
+ :param node: Node in topology.
+ :param interface: Name, sw_if_index, link name or key of an interface
+ on the node.
+ :param wanted_format: Format of return value wanted.
+ Valid options are: sw_if_index, key, name.
+ :type node: dict
+ :type interface: str or int
+ :type wanted_format: str
+
+ :return: Interface name, interface key or sw_if_index.
+ :rtype: str or int
+
+ :raises TypeError, ValueError: If provided with invalid arguments.
+ :raises RuntimeError: If the interface does not exist in topology.
+ """
+
+ key = Topology.convert_interface_reference_to_key(node, interface)
+
+ conversions = {
+ "key": lambda x, y: y,
+ "name": Topology.get_interface_name,
+ "sw_if_index": Topology.get_interface_sw_index
+ }
+
+ try:
+ return conversions[wanted_format](node, key)
+ except KeyError:
+ raise ValueError("Unrecognized return value wanted: {0}."
+ "Valid options are key, name, sw_if_index"
+ .format(wanted_format))
+
+ @staticmethod
+ def get_interface_numa_node(node, iface_key):
+ """Get interface numa node.
+
+ Returns physical relation to numa node, numa_id.
+
+ :param node: Node to get numa id on.
+ :param iface_key: Interface key from topology file.
+ :type node: dict
+ :type iface_key: str
+ :return: numa node id, None if not available.
+ :rtype: int
+ """
+ try:
+ return node['interfaces'][iface_key].get('numa_node')
+ except KeyError:
+ return None
+
+ @staticmethod
+ def get_interfaces_numa_node(node, *iface_keys):
+ """Get numa node on which are located most of the interfaces.
+
+ Return numa node with highest count of interfaces provided as arguments.
+ Return 0 if the interface does not have numa_node information available.
+ If all interfaces have unknown location (-1), then return 0.
+ If most of interfaces have unknown location (-1), but there are
+ some interfaces with known location, then return the second most
+ location of the provided interfaces.
+
+ :param node: Node from DICT__nodes.
+ :param iface_keys: Interface keys for lookup.
+ :type node: dict
+ :type iface_keys: strings
+ """
+ numa_list = []
+ for if_key in iface_keys:
+ try:
+ numa_list.append(node['interfaces'][if_key].get('numa_node'))
+ except KeyError:
+ pass
+
+ numa_cnt_mc = Counter(numa_list).most_common()
+
+ if len(numa_cnt_mc) > 0 and numa_cnt_mc[0][0] != -1:
+ return numa_cnt_mc[0][0]
+ elif len(numa_cnt_mc) > 1 and numa_cnt_mc[0][0] == -1:
+ return numa_cnt_mc[1][0]
+ else:
+ return 0
+
@staticmethod
def get_interface_mac(node, iface_key):
"""Get MAC address for the interface.
except KeyError:
return None
+ @staticmethod
+ def get_node_interfaces(node):
+ """Get all node interfaces.
+
+ :param node: Node to get list of interfaces from.
+ :type node: dict
+ :return: Return list of keys of all interfaces.
+ :rtype: list
+ """
+ return node['interfaces'].keys()
+
@staticmethod
def get_node_link_mac(node, link_name):
"""Return interface mac address by link name.
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'])
:param filter_list_node2: Link filter criteria for node2.
:type node1: dict
:type node2: dict
- :type filter_list1: list of strings
- :type filter_list2: list of strings
+ :type filter_list_node1: list of strings
+ :type filter_list_node2: list of strings
:return: List of strings that represent connecting link names.
:rtype: list
"""
else:
return connecting_links[0]
- @keyword('Get egress interfaces name on "${node1}" for link with "${node2}"')
+ @keyword('Get egress interfaces name on "${node1}" for link with '
+ '"${node2}"')
def get_egress_interfaces_name_for_nodes(self, node1, node2):
"""Get egress interfaces on node1 for link with node2.
:rtype: str
"""
return node['host']
+
+ @staticmethod
+ def get_cryptodev(node):
+ """Return Crytodev configuration of the node.
+
+ :param node: Node created from topology.
+ :type node: dict
+ :return: 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
+ :return: 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.
+
+ :param node: Node to set numa_node on.
+ :param iface_key: Interface key from topology file.
+ :type node: dict
+ :type iface_key: str
+ :return: Return iface_key or None if not found.
+ """
+ try:
+ node['interfaces'][iface_key]['numa_node'] = numa_node_id
+ return iface_key
+ except KeyError:
+ return None