FIX: set host physical interface mac address to rdma interface
[csit.git] / resources / libraries / python / InterfaceUtil.py
index 2921f7d..ad76eac 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2019 Cisco and/or its affiliates.
+# Copyright (c) 2020 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:
@@ -103,11 +103,16 @@ class LinkBondMode(IntEnum):
     BOND_API_MODE_LACP = 5
 
 
+class RdmaMode(IntEnum):
+    """RDMA interface mode."""
+    RDMA_API_MODE_AUTO = 0
+    RDMA_API_MODE_IBV = 1
+    RDMA_API_MODE_DV = 2
+
+
 class InterfaceUtil:
     """General utilities for managing interfaces"""
 
-    __UDEV_IF_RULES_FILE = u"/etc/udev/rules.d/10-network.rules"
-
     @staticmethod
     def pci_to_int(pci_str):
         """Convert PCI address from string format (0000:18:0a.0) to
@@ -486,6 +491,27 @@ class InterfaceUtil:
 
         return if_data.get(u"l2_address")
 
+    @staticmethod
+    def vpp_set_interface_mac(node, interface, mac):
+        """Set MAC address for the given interface.
+
+        :param node: VPP node to set interface MAC.
+        :param interface: Numeric index or name string of a specific interface.
+        :param mac: Required MAC address.
+        :type node: dict
+        :type interface: int or str
+        :type mac: str
+        """
+        cmd = u"sw_interface_set_mac_address"
+        args = dict(
+            sw_if_index=InterfaceUtil.get_interface_index(node, interface),
+            mac_address=L2Util.mac_to_bin(mac)
+        )
+        err_msg = f"Failed to set MAC address of interface {interface}" \
+            f"on host {node[u'host']}"
+        with PapiSocketExecutor(node) as papi_exec:
+            papi_exec.add(cmd, **args).get_reply(err_msg)
+
     @staticmethod
     def tg_set_interface_driver(node, pci_addr, driver):
         """Set interface driver on the TG node.
@@ -534,45 +560,6 @@ class InterfaceUtil:
         """
         return DUTSetup.get_pci_dev_driver(node, pci_addr)
 
-    @staticmethod
-    def tg_set_interfaces_udev_rules(node):
-        """Set udev rules for interfaces.
-
-        Create udev rules file in /etc/udev/rules.d where are rules for each
-        interface used by TG node, based on MAC interface has specific name.
-        So after unbind and bind again to kernel driver interface has same
-        name as before. This must be called after TG has set name for each
-        port in topology dictionary.
-        udev rule example
-        SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="52:54:00:e1:8a:0f",
-        NAME="eth1"
-
-        :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)
-
-        cmd = f"rm -f {InterfaceUtil.__UDEV_IF_RULES_FILE}"
-        ret_code, _, _ = ssh.exec_command_sudo(cmd)
-        if int(ret_code) != 0:
-            raise RuntimeError(f"'{cmd}' failed on '{node[u'host']}'")
-
-        for interface in node[u"interfaces"].values():
-            rule = u'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \
-                   u'==\\"' + interface[u"mac_address"] + u'\\", NAME=\\"' + \
-                   interface[u"name"] + u'\\"'
-            cmd = f"sh -c \"echo '{rule}'\" >> " \
-                f"{InterfaceUtil.__UDEV_IF_RULES_FILE}'"
-
-            ret_code, _, _ = ssh.exec_command_sudo(cmd)
-            if int(ret_code) != 0:
-                raise RuntimeError(f"'{cmd}' failed on '{node[u'host']}'")
-
-        cmd = u"/etc/init.d/udev restart"
-        ssh.exec_command_sudo(cmd)
-
     @staticmethod
     def tg_set_interfaces_default_driver(node):
         """Set interfaces default driver specified in topology yaml file.
@@ -660,7 +647,7 @@ class InterfaceUtil:
                 InterfaceUtil.update_nic_interface_names(node)
 
     @staticmethod
-    def update_tg_interface_data_on_node(node, skip_tg_udev=False):
+    def update_tg_interface_data_on_node(node):
         """Update interface name for TG/linux node in DICT__nodes.
 
         .. note::
@@ -672,9 +659,7 @@ class InterfaceUtil:
             "00:00:00:00:00:00": "lo"
 
         :param node: Node selected from DICT__nodes.
-        :param skip_tg_udev: Skip udev rename on TG node.
         :type node: dict
-        :type skip_tg_udev: bool
         :raises RuntimeError: If getting of interface name and MAC fails.
         """
         # First setup interface driver specified in yaml file
@@ -699,10 +684,6 @@ class InterfaceUtil:
                 continue
             interface[u"name"] = name
 
-        # Set udev rules for interfaces
-        if not skip_tg_udev:
-            InterfaceUtil.tg_set_interfaces_udev_rules(node)
-
     @staticmethod
     def iface_update_numa_node(node):
         """For all interfaces from topology file update numa node based on
@@ -744,26 +725,9 @@ class InterfaceUtil:
             else:
                 raise RuntimeError(f"Update numa node failed for: {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[u"type"] == NodeType.DUT:
-                InterfaceUtil.iface_update_numa_node(node)
-            elif node[u"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, skip_tg_udev=False, numa_node=False):
+            nodes, skip_tg=False, skip_vpp=False):
         """Update interface names on all nodes in DICT__nodes.
 
         This method updates the topology dictionary by querying interface lists
@@ -771,25 +735,17 @@ class InterfaceUtil:
 
         :param nodes: Nodes in the topology.
         :param skip_tg: Skip TG node.
-        :param skip_tg_udev: Skip udev rename on TG node.
-        :param numa_node: Retrieve numa_node location.
+        :param skip_vpp: Skip VPP node.
         :type nodes: dict
         :type skip_tg: bool
-        :type skip_tg_udev: bool
-        :type numa_node: bool
+        :type skip_vpp: bool
         """
-        for node_data in nodes.values():
-            if node_data[u"type"] == NodeType.DUT:
-                InterfaceUtil.update_vpp_interface_data_on_node(node_data)
-            elif node_data[u"type"] == NodeType.TG and not skip_tg:
-                InterfaceUtil.update_tg_interface_data_on_node(
-                    node_data, skip_tg_udev)
-
-            if numa_node:
-                if node_data[u"type"] == NodeType.DUT:
-                    InterfaceUtil.iface_update_numa_node(node_data)
-                elif node_data[u"type"] == NodeType.TG and not skip_tg:
-                    InterfaceUtil.iface_update_numa_node(node_data)
+        for node in nodes.values():
+            if node[u"type"] == NodeType.DUT and not skip_vpp:
+                InterfaceUtil.update_vpp_interface_data_on_node(node)
+            elif node[u"type"] == NodeType.TG and not skip_tg:
+                InterfaceUtil.update_tg_interface_data_on_node(node)
+            InterfaceUtil.iface_update_numa_node(node)
 
     @staticmethod
     def create_vlan_subinterface(node, interface, vlan):
@@ -1152,7 +1108,7 @@ class InterfaceUtil:
         :type ifc_name: str
         :type sw_if_index: int
         :type ifc_pfx: str
-        :type ifc_pfx: host_if_key
+        :type host_if_key: str
         """
         if_key = Topology.add_new_port(node, ifc_pfx)
 
@@ -1171,6 +1127,9 @@ class InterfaceUtil:
                     node, host_if_key
                 )
             )
+            Topology.update_interface_pci_address(
+                node, if_key, Topology.get_interface_pci_addr(node, host_if_key)
+            )
 
     @staticmethod
     def vpp_create_avf_interface(node, if_key, num_rx_queues=None):
@@ -1183,7 +1142,7 @@ class InterfaceUtil:
         :type node: dict
         :type if_key: str
         :type num_rx_queues: int
-        :returns: Interface key (name) in topology.
+        :returns: AVF interface key (name) in topology.
         :rtype: str
         :raises RuntimeError: If it is not possible to create AVF interface on
             the node.
@@ -1209,21 +1168,23 @@ class InterfaceUtil:
             node, sw_if_index=sw_if_index, ifc_pfx=u"eth_avf",
             host_if_key=if_key
         )
-        if_key = Topology.get_interface_by_sw_index(node, sw_if_index)
 
-        return if_key
+        return Topology.get_interface_by_sw_index(node, sw_if_index)
 
     @staticmethod
-    def vpp_create_rdma_interface(node, if_key, num_rx_queues=None):
+    def vpp_create_rdma_interface(
+            node, if_key, num_rx_queues=None, mode=u"auto"):
         """Create RDMA interface on VPP node.
 
         :param node: DUT node from topology.
         :param if_key: Physical interface key from topology file of interface
             to be bound to rdma-core driver.
         :param num_rx_queues: Number of RX queues.
+        :param mode: RDMA interface mode - auto/ibv/dv.
         :type node: dict
         :type if_key: str
         :type num_rx_queues: int
+        :type mode: str
         :returns: Interface key (name) in topology file.
         :rtype: str
         :raises RuntimeError: If it is not possible to create RDMA interface on
@@ -1235,13 +1196,17 @@ class InterfaceUtil:
             name=InterfaceUtil.pci_to_eth(node, pci_addr),
             host_if=InterfaceUtil.pci_to_eth(node, pci_addr),
             rxq_num=int(num_rx_queues) if num_rx_queues else 0,
-            rxq_size=0,
-            txq_size=0
+            rxq_size=1024,
+            txq_size=1024,
+            mode=getattr(RdmaMode,f"RDMA_API_MODE_{mode.upper()}").value,
         )
         err_msg = f"Failed to create RDMA interface on host {node[u'host']}"
         with PapiSocketExecutor(node) as papi_exec:
             sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
 
+        InterfaceUtil.vpp_set_interface_mac(
+            node, sw_if_index, Topology.get_interface_mac(node, if_key)
+        )
         InterfaceUtil.add_eth_interface(
             node, sw_if_index=sw_if_index, ifc_pfx=u"eth_rdma",
             host_if_key=if_key
@@ -1412,6 +1377,8 @@ class InterfaceUtil:
     def get_sw_if_index(node, interface_name):
         """Get sw_if_index for the given interface from actual interface dump.
 
+        FIXME: Delete and redirect callers to vpp_get_interface_sw_index.
+
         :param node: VPP node to get interface data from.
         :param interface_name: Name of the specific interface.
         :type node: dict