FIX: Remove eth_avf and portX_vifY interfaces from topo in TC/TS tear down
[csit.git] / resources / libraries / python / topology.py
index d60bed1..1e5ce4b 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
+# Copyright (c) 2019 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:
@@ -13,6 +13,8 @@
 
 """Defines nodes and topology structure."""
 
+import re
+
 from collections import Counter
 
 from yaml import load
@@ -59,6 +61,7 @@ class NodeSubTypeTG(object):
     # IxNetwork
     IXNET = 'IXNET'
 
+
 DICT__nodes = load_topo_from_yaml()
 
 
@@ -138,13 +141,40 @@ class Topology(object):
         :returns: Nothing
         """
         port_types = ('subinterface', 'vlan_subif', 'memif', 'tap', 'vhost',
-                      'loopback', 'gre_tunnel', 'vxlan_tunnel', 'eth_bond')
+                      'loopback', 'gre_tunnel', 'vxlan_tunnel', 'eth_bond',
+                      'eth_avf')
 
         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 remove_all_vif_ports(node):
+        """Remove all Virtual Interfaces on DUT node.
+
+        :param node: Node to remove VIF ports on.
+        :type node: dict
+        :returns: Nothing
+        """
+        reg_ex = re.compile(r'port\d+_vif\d+')
+        for if_key in list(node['interfaces']):
+            if re.match(reg_ex, if_key):
+                node['interfaces'].pop(if_key)
+
+    @staticmethod
+    def remove_all_added_vif_ports_on_all_duts_from_topology(nodes):
+        """Remove all added Virtual Interfaces on all DUT nodes in
+        the topology.
+
+        :param nodes: Nodes in the topology.
+        :type nodes: dict
+        :returns: Nothing
+        """
+        for node_data in nodes.values():
+            if node_data['type'] == NodeType.DUT:
+                Topology.remove_all_vif_ports(node_data)
+
     @staticmethod
     def update_interface_sw_if_index(node, iface_key, sw_if_index):
         """Update sw_if_index on the interface from the node.
@@ -184,6 +214,32 @@ class Topology(object):
         """
         node['interfaces'][iface_key]['mac_address'] = str(mac_address)
 
+    @staticmethod
+    def update_interface_pci_address(node, iface_key, pci_address):
+        """Update pci_address on the interface from the node.
+
+        :param node: Node to update PCI on.
+        :param iface_key: Topology key of the interface.
+        :param pci_address: PCI address.
+        :type node: dict
+        :type iface_key: str
+        :type pci_address: str
+        """
+        node['interfaces'][iface_key]['pci_address'] = str(pci_address)
+
+    @staticmethod
+    def update_interface_vlan(node, iface_key, vlan):
+        """Update VLAN on the interface from the node.
+
+        :param node: Node to update VLAN on.
+        :param iface_key: Topology key of the interface.
+        :param vlan: VLAN ID.
+        :type node: dict
+        :type iface_key: str
+        :type vlan: str
+        """
+        node['interfaces'][iface_key]['vlan'] = int(vlan)
+
     @staticmethod
     def update_interface_vhost_socket(node, iface_key, vhost_socket):
         """Update vhost socket name on the interface from the node.
@@ -369,38 +425,39 @@ class Topology(object):
         return retval
 
     @staticmethod
-    def get_interface_by_sw_index(node, sw_index):
+    def get_interface_by_sw_index(node, sw_if_index):
         """Return interface name of link on node.
 
         This method returns the interface name associated with a software
         interface index assigned to the interface by vpp for a given node.
 
         :param node: The node topology dictionary.
-        :param sw_index: Sw_index of the link that a interface is connected to.
+        :param sw_if_index: sw_if_index of the link that a interface is
+            connected to.
         :type node: dict
-        :type sw_index: int
+        :type sw_if_index: int
         :returns: 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)
+                                                    sw_if_index)
 
     @staticmethod
     def get_interface_sw_index(node, iface_key):
         """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.
+        :param iface_key: Interface key from topology file, or sw_if_index.
         :type node: dict
         :type iface_key: str/int
         :returns: Return sw_if_index or None if not found.
+        :rtype: int or None
         """
         try:
             if isinstance(iface_key, basestring):
                 return node['interfaces'][iface_key].get('vpp_sw_index')
             # TODO: use only iface_key, do not use integer
-            else:
-                return int(iface_key)
+            return int(iface_key)
         except (KeyError, ValueError):
             return None
 
@@ -416,11 +473,10 @@ class Topology(object):
         :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:
+            if not isinstance(iface_name, basestring):
                 raise TypeError("Interface name must be a string.")
+            iface_key = Topology.get_interface_by_name(node, iface_name)
+            return node['interfaces'][iface_key].get('vpp_sw_index')
         except (KeyError, ValueError):
             return None
 
@@ -565,6 +621,8 @@ class Topology(object):
         :param iface_keys: Interface keys for lookup.
         :type node: dict
         :type iface_keys: strings
+        :returns: Numa node of most given interfaces or 0.
+        :rtype: int
         """
         numa_list = []
         for if_key in iface_keys:
@@ -575,12 +633,11 @@ class Topology(object):
 
         numa_cnt_mc = Counter(numa_list).most_common()
 
-        if len(numa_cnt_mc) > 0 and numa_cnt_mc[0][0] != -1:
+        if numa_cnt_mc 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:
+        if len(numa_cnt_mc) > 1 and numa_cnt_mc[0][0] == -1:
             return numa_cnt_mc[1][0]
-        else:
-            return 0
+        return 0
 
     @staticmethod
     def get_interface_mac(node, iface_key):
@@ -650,6 +707,7 @@ class Topology(object):
                     continue
                 if if_val['link'] == link_name:
                     return node_data, if_key
+        return None
 
     @staticmethod
     def get_interface_pci_addr(node, iface_key):
@@ -681,6 +739,21 @@ class Topology(object):
         except KeyError:
             return None
 
+    @staticmethod
+    def get_interface_vlan(node, iface_key):
+        """Get interface vlan.
+
+        :param node: Node to get interface driver on.
+        :param iface_key: Interface key from topology file.
+        :type node: dict
+        :type iface_key: str
+        :returns: Return interface vlan or None if not found.
+        """
+        try:
+            return node['interfaces'][iface_key].get('vlan')
+        except KeyError:
+            return None
+
     @staticmethod
     def get_node_interfaces(node):
         """Get all node interfaces.
@@ -696,7 +769,7 @@ class Topology(object):
     def get_node_link_mac(node, link_name):
         """Return interface mac address by link name.
 
-        :param node: Node to get interface sw_index on.
+        :param node: Node to get interface sw_if_index on.
         :param link_name: Link name.
         :type node: dict
         :type link_name: str
@@ -716,8 +789,8 @@ class Topology(object):
         :param filter_list: Link filter criteria.
         :type node: dict
         :type filter_list: list of strings
-        :returns: List of strings representing link names occupied by the node.
-        :rtype: list
+        :returns: List of link names occupied by the node.
+        :rtype: None or list of string
         """
         interfaces = node['interfaces']
         link_names = []
@@ -732,7 +805,7 @@ class Topology(object):
                                  .format(str(interface)))
                 else:
                     link_names.append(interface['link'])
-        if len(link_names) == 0:
+        if not link_names:
             link_names = None
         return link_names
 
@@ -782,15 +855,14 @@ class Topology(object):
         :param node2: Connected node.
         :type node1: dict
         :type node2: dict
-        :returns: Name of link connecting the two nodes together.
+        :returns: Name of link connecting the two nodes together.
         :rtype: str
         :raises RuntimeError: If no links are found.
         """
         connecting_links = self.get_active_connecting_links(node1, node2)
-        if len(connecting_links) == 0:
+        if not connecting_links:
             raise RuntimeError("No links connecting the nodes were found")
-        else:
-            return connecting_links[0]
+        return connecting_links[0]
 
     @keyword('Get egress interfaces name on "${node1}" for link with '
              '"${node2}"')
@@ -806,7 +878,7 @@ class Topology(object):
         """
         interfaces = []
         links = self.get_active_connecting_links(node1, node2)
-        if len(links) == 0:
+        if not links:
             raise RuntimeError('No link between nodes')
         for interface in node1['interfaces'].values():
             link = interface.get('link')