rxq_ratio default value changed to 1
[csit.git] / resources / libraries / python / InterfaceUtil.py
index 1245a33..bf36635 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2020 Cisco and/or its affiliates.
+# Copyright (c) 2021 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:
@@ -20,6 +20,7 @@ from ipaddress import ip_address
 from robot.api import logger
 
 from resources.libraries.python.Constants import Constants
+from resources.libraries.python.CpuUtils import CpuUtils
 from resources.libraries.python.DUTSetup import DUTSetup
 from resources.libraries.python.IPAddress import IPAddress
 from resources.libraries.python.L2Util import L2Util
@@ -1029,9 +1030,11 @@ class InterfaceUtil:
         :raises RuntimeError: If it is not possible to create loopback on the
             node.
         """
-        cmd = u"create_loopback"
+        cmd = u"create_loopback_instance"
         args = dict(
-            mac_address=L2Util.mac_to_bin(mac) if mac else 0
+            mac_address=L2Util.mac_to_bin(mac) if mac else 0,
+            is_specified=False,
+            user_instance=0,
         )
         err_msg = f"Failed to create loopback interface on host {node[u'host']}"
         with PapiSocketExecutor(node) as papi_exec:
@@ -1048,24 +1051,28 @@ class InterfaceUtil:
         return sw_if_index
 
     @staticmethod
-    def vpp_create_bond_interface(node, mode, load_balance=None, mac=None):
+    def vpp_create_bond_interface(
+            node, mode, load_balance=None, mac=None, gso=False):
         """Create bond interface on VPP node.
 
         :param node: DUT node from topology.
         :param mode: Link bonding mode.
         :param load_balance: Load balance (optional, valid for xor and lacp
-            modes, otherwise ignored).
+            modes, otherwise ignored). Default: None.
         :param mac: MAC address to assign to the bond interface (optional).
+            Default: None.
+        :param gso: Enable GSO support (optional). Default: False.
         :type node: dict
         :type mode: str
         :type load_balance: str
         :type mac: str
+        :type gso: bool
         :returns: Interface key (name) in topology.
         :rtype: str
         :raises RuntimeError: If it is not possible to create bond interface on
             the node.
         """
-        cmd = u"bond_create"
+        cmd = u"bond_create2"
         args = dict(
             id=int(Constants.BITWISE_NON_ZERO),
             use_custom_mac=bool(mac is not None),
@@ -1078,7 +1085,8 @@ class InterfaceUtil:
                 LinkBondLoadBalanceAlgo,
                 f"BOND_API_LB_ALGO_{load_balance.upper()}"
             ).value,
-            numa_only=False
+            numa_only=False,
+            enable_gso=gso
         )
         err_msg = f"Failed to create bond interface on host {node[u'host']}"
         with PapiSocketExecutor(node) as papi_exec:
@@ -1202,7 +1210,7 @@ class InterfaceUtil:
             node, u"set logging class rdma level debug"
         )
 
-        cmd = u"rdma_create"
+        cmd = u"rdma_create_v2"
         pci_addr = Topology.get_interface_pci_addr(node, if_key)
         args = dict(
             name=InterfaceUtil.pci_to_eth(node, pci_addr),
@@ -1211,6 +1219,9 @@ class InterfaceUtil:
             rxq_size=rxq_size,
             txq_size=txq_size,
             mode=getattr(RdmaMode, f"RDMA_API_MODE_{mode.upper()}").value,
+            # TODO: Set True for non-jumbo packets.
+            no_multi_seg=False,
+            max_pktlen=0,
         )
         err_msg = f"Failed to create RDMA interface on host {node[u'host']}"
         with PapiSocketExecutor(node) as papi_exec:
@@ -1227,8 +1238,8 @@ class InterfaceUtil:
         return Topology.get_interface_by_sw_index(node, sw_if_index)
 
     @staticmethod
-    def vpp_enslave_physical_interface(node, interface, bond_if):
-        """Enslave physical interface to bond interface on VPP node.
+    def vpp_add_bond_member(node, interface, bond_if):
+        """Add member interface to bond interface on VPP node.
 
         :param node: DUT node from topology.
         :param interface: Physical interface key from topology file.
@@ -1236,18 +1247,18 @@ class InterfaceUtil:
         :type node: dict
         :type interface: str
         :type bond_if: str
-        :raises RuntimeError: If it is not possible to enslave physical
-            interface to bond interface on the node.
+        :raises RuntimeError: If it is not possible to add member to bond
+            interface on the node.
         """
-        cmd = u"bond_enslave"
+        cmd = u"bond_add_member"
         args = dict(
             sw_if_index=Topology.get_interface_sw_index(node, interface),
             bond_sw_if_index=Topology.get_interface_sw_index(node, bond_if),
             is_passive=False,
             is_long_timeout=False
         )
-        err_msg = f"Failed to enslave physical interface {interface} to bond " \
-            f"interface {bond_if} on host {node[u'host']}"
+        err_msg = f"Failed to add member {interface} to bond interface " \
+            f"{bond_if} on host {node[u'host']}"
         with PapiSocketExecutor(node) as papi_exec:
             papi_exec.add(cmd, **args).get_reply(err_msg)
 
@@ -1260,7 +1271,7 @@ class InterfaceUtil:
         :type node: dict
         :type verbose: bool
         """
-        cmd = u"sw_interface_bond_dump"
+        cmd = u"sw_bond_interface_dump"
         err_msg = f"Failed to get bond interface dump on host {node[u'host']}"
 
         data = f"Bond data on node {node[u'host']}:\n"
@@ -1275,26 +1286,26 @@ class InterfaceUtil:
             data += u"  load balance: {lb}\n".format(
                 lb=bond[u"lb"].name.replace(u"BOND_API_LB_ALGO_", u"").lower()
             )
-            data += f"  number of active slaves: {bond[u'active_slaves']}\n"
+            data += f"  number of active members: {bond[u'active_members']}\n"
             if verbose:
-                slave_data = InterfaceUtil.vpp_bond_slave_dump(
+                member_data = InterfaceUtil.vpp_bond_member_dump(
                     node, Topology.get_interface_by_sw_index(
                         node, bond[u"sw_if_index"]
                     )
                 )
-                for slave in slave_data:
-                    if not slave[u"is_passive"]:
-                        data += f"    {slave[u'interface_name']}\n"
-            data += f"  number of slaves: {bond[u'slaves']}\n"
+                for member in member_data:
+                    if not member[u"is_passive"]:
+                        data += f"    {member[u'interface_name']}\n"
+            data += f"  number of members: {bond[u'members']}\n"
             if verbose:
-                for slave in slave_data:
-                    data += f"    {slave[u'interface_name']}\n"
+                for member in member_data:
+                    data += f"    {member[u'interface_name']}\n"
             data += f"  interface id: {bond[u'id']}\n"
             data += f"  sw_if_index: {bond[u'sw_if_index']}\n"
         logger.info(data)
 
     @staticmethod
-    def vpp_bond_slave_dump(node, interface):
+    def vpp_bond_member_dump(node, interface):
         """Get bond interface slave(s) data on VPP node.
 
         :param node: DUT node from topology.
@@ -1304,7 +1315,7 @@ class InterfaceUtil:
         :returns: Bond slave interface data.
         :rtype: dict
         """
-        cmd = u"sw_interface_slave_dump"
+        cmd = u"sw_member_interface_dump"
         args = dict(
             sw_if_index=Topology.get_interface_sw_index(node, interface)
         )
@@ -1313,7 +1324,7 @@ class InterfaceUtil:
         with PapiSocketExecutor(node) as papi_exec:
             details = papi_exec.add(cmd, **args).get_details(err_msg)
 
-        logger.debug(f"Slave data:\n{details}")
+        logger.debug(f"Member data:\n{details}")
         return details
 
     @staticmethod
@@ -1672,6 +1683,19 @@ class InterfaceUtil:
             details = papi_exec.get_details(err_msg)
         return sorted(details, key=lambda k: k[u"sw_if_index"])
 
+    @staticmethod
+    def vpp_sw_interface_rx_placement_dump_on_all_duts(nodes):
+        """Dump VPP interface RX placement on all given nodes.
+
+        :param nodes: Nodes to run command on.
+        :type nodes: dict
+        :returns: Thread mapping information as a list of dictionaries.
+        :rtype: list
+        """
+        for node in nodes.values():
+            if node[u"type"] == NodeType.DUT:
+                InterfaceUtil.vpp_sw_interface_rx_placement_dump(node)
+
     @staticmethod
     def vpp_sw_interface_set_rx_placement(
             node, sw_if_index, queue_id, worker_id):
@@ -1701,17 +1725,29 @@ class InterfaceUtil:
             papi_exec.add(cmd, **args).get_reply(err_msg)
 
     @staticmethod
-    def vpp_round_robin_rx_placement(node, prefix):
+    def vpp_round_robin_rx_placement(
+        node, prefix, dp_worker_limit=None
+    ):
         """Set Round Robin interface RX placement on all worker threads
         on node.
 
+        If specified, dp_core_limit limits the number of physical cores used
+        for data plane I/O work. Other cores are presumed to do something else,
+        e.g. asynchronous crypto processing.
+        None means all workers are used for data plane work.
+        Note this keyword specifies workers, not cores.
+
         :param node: Topology nodes.
         :param prefix: Interface name prefix.
+        :param dp_worker_limit: How many cores for data plane work.
         :type node: dict
         :type prefix: str
+        :type dp_worker_limit: Optional[int]
         """
         worker_id = 0
         worker_cnt = len(VPPUtil.vpp_show_threads(node)) - 1
+        if dp_worker_limit is not None:
+            worker_cnt = min(worker_cnt, dp_worker_limit)
         if not worker_cnt:
             return
         for placement in InterfaceUtil.vpp_sw_interface_rx_placement_dump(node):
@@ -1725,15 +1761,31 @@ class InterfaceUtil:
                     worker_id += 1
 
     @staticmethod
-    def vpp_round_robin_rx_placement_on_all_duts(nodes, prefix):
+    def vpp_round_robin_rx_placement_on_all_duts(
+        nodes, prefix, dp_core_limit=None
+    ):
         """Set Round Robin interface RX placement on all worker threads
         on all DUTs.
 
+        If specified, dp_core_limit limits the number of physical cores used
+        for data plane I/O work. Other cores are presumed to do something else,
+        e.g. asynchronous crypto processing.
+        None means all cores are used for data plane work.
+        Note this keyword specifies cores, not workers.
+
         :param nodes: Topology nodes.
         :param prefix: Interface name prefix.
+        :param dp_worker_limit: How many cores for data plane work.
         :type nodes: dict
         :type prefix: str
+        :type dp_worker_limit: Optional[int]
         """
         for node in nodes.values():
             if node[u"type"] == NodeType.DUT:
-                InterfaceUtil.vpp_round_robin_rx_placement(node, prefix)
+                dp_worker_limit = CpuUtils.worker_count_from_cores_and_smt(
+                    phy_cores=dp_core_limit,
+                    smt_used=CpuUtils.is_smt_enabled(node[u"cpuinfo"]),
+                )
+                InterfaceUtil.vpp_round_robin_rx_placement(
+                    node, prefix, dp_worker_limit
+                )