Update Honeycomb tests
[csit.git] / resources / libraries / python / VppConfigGenerator.py
index 6085882..9ca9fc4 100644 (file)
 
 """VPP Configuration File Generator library"""
 
+import re
+import time
+
 from robot.api import logger
 
 from resources.libraries.python.ssh import SSH
 from resources.libraries.python.topology import NodeType
 from resources.libraries.python.topology import Topology
 
-import re
-import time
-
 __all__ = ['VppConfigGenerator']
 
 #
@@ -52,8 +52,10 @@ cpu {{
 
 dpdk {{
   socket-mem {socketmemconfig}
+{txqueuesconfig}
 {pciconfig}
 {rssconfig}
+{nomultiseg}
 }}
 """
 # End VPP configuration template.
@@ -68,12 +70,12 @@ class VppConfigGenerator(object):
     def add_pci_device(self, node, pci_device=None):
         """Add PCI device configuration for node.
 
-        :param node: DUT node
+        :param node: DUT node.
         :param pci_device: PCI device (format 0000:00:00.0 or 00:00.0).
         If none given, all PCI devices for this node as per topology will be
         added.
         :type node: dict
-        :type pci_device: string
+        :type pci_device: str
         :return: nothing
         """
         if node['type'] != NodeType.DUT:
@@ -90,84 +92,85 @@ class VppConfigGenerator(object):
             # Specific device was given.
             hostname = Topology.get_node_hostname(node)
 
-            pattern = re.compile("^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:"\
-                "[0-9A-Fa-f]{2}\\.[0-9A-Fa-f]$")
+            pattern = re.compile("^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:"
+                                 "[0-9A-Fa-f]{2}\\.[0-9A-Fa-f]$")
             if not pattern.match(pci_device):
-                raise ValueError('PCI address {} to be added to host {} '\
-                    'is not in valid format xxxx:xx:xx.x'.\
-                    format(pci_device, hostname))
+                raise ValueError('PCI address {} to be added to host {} '
+                                 'is not in valid format xxxx:xx:xx.x'.
+                                 format(pci_device, hostname))
 
-            if not hostname in self._nodeconfig:
+            if hostname not in self._nodeconfig:
                 self._nodeconfig[hostname] = {}
-            if not 'pci_addrs' in self._nodeconfig[hostname]:
+            if 'pci_addrs' not in self._nodeconfig[hostname]:
                 self._nodeconfig[hostname]['pci_addrs'] = []
             self._nodeconfig[hostname]['pci_addrs'].append(pci_device)
-            logger.debug('Adding PCI device {1} to {0}'.format(hostname,\
-               pci_device))
+            logger.debug('Adding PCI device {1} to {0}'.format(hostname,
+                                                               pci_device))
 
     def add_cpu_config(self, node, cpu_config):
         """Add CPU configuration for node.
 
-        :param node: DUT node
-        :param cpu_config: CPU configuration option, as a string
+        :param node: DUT node.
+        :param cpu_config: CPU configuration option, as a string.
         :type node: dict
-        :type cpu_config: string
+        :type cpu_config: str
         :return: nothing
         """
         if node['type'] != NodeType.DUT:
             raise ValueError('Node type is not a DUT')
         hostname = Topology.get_node_hostname(node)
-        if not hostname in self._nodeconfig:
+        if hostname not in self._nodeconfig:
             self._nodeconfig[hostname] = {}
-        if not 'cpu_config' in self._nodeconfig[hostname]:
+        if 'cpu_config' not in self._nodeconfig[hostname]:
             self._nodeconfig[hostname]['cpu_config'] = []
         self._nodeconfig[hostname]['cpu_config'].append(cpu_config)
-        logger.debug('Adding {} to hostname {} CPU config'.format(hostname, \
-            cpu_config))
+        logger.debug('Adding {} to hostname {} CPU config'.format(hostname,
+                                                                  cpu_config))
 
     def add_socketmem_config(self, node, socketmem_config):
         """Add Socket Memory configuration for node.
 
-        :param node: DUT node
-        :param socketmem_config: Socket Memory configuration option, as a string
+        :param node: DUT node.
+        :param socketmem_config: Socket Memory configuration option,
+        as a string.
         :type node: dict
-        :type cpu_config: string
+        :type socketmem_config: str
         :return: nothing
         """
         if node['type'] != NodeType.DUT:
             raise ValueError('Node type is not a DUT')
         hostname = Topology.get_node_hostname(node)
-        if not hostname in self._nodeconfig:
+        if hostname not in self._nodeconfig:
             self._nodeconfig[hostname] = {}
         self._nodeconfig[hostname]['socketmem_config'] = socketmem_config
-        logger.debug('Setting hostname {} Socket Memory config to {}'.\
-            format(hostname, socketmem_config))
+        logger.debug('Setting hostname {} Socket Memory config to {}'.
+                     format(hostname, socketmem_config))
 
     def add_heapsize_config(self, node, heapsize_config):
         """Add Heap Size configuration for node.
 
-        :param node: DUT node
-        :param heapsize_config: Heap Size configuration, as a string
+        :param node: DUT node.
+        :param heapsize_config: Heap Size configuration, as a string.
         :type node: dict
-        :type cpu_config: string
+        :type heapsize_config: str
         :return: nothing
         """
         if node['type'] != NodeType.DUT:
             raise ValueError('Node type is not a DUT')
         hostname = Topology.get_node_hostname(node)
-        if not hostname in self._nodeconfig:
+        if hostname not in self._nodeconfig:
             self._nodeconfig[hostname] = {}
         self._nodeconfig[hostname]['heapsize_config'] = heapsize_config
-        logger.debug('Setting hostname {} Heap Size config to {}'.\
-            format(hostname, heapsize_config))
+        logger.debug('Setting hostname {} Heap Size config to {}'.
+                     format(hostname, heapsize_config))
 
     def add_rss_config(self, node, rss_config):
         """Add RSS configuration for node.
 
-        :param node: DUT node
-        :param rss_config: RSS configuration, as a string
+        :param node: DUT node.
+        :param rss_config: RSS configuration, as a string.
         :type node: dict
-        :type rss_config: string
+        :type rss_config: str
         :return: nothing
         """
         if node['type'] != NodeType.DUT:
@@ -181,11 +184,51 @@ class VppConfigGenerator(object):
         logger.debug('Setting hostname {} RSS config to {}'.\
             format(hostname, rss_config))
 
+    def add_max_tx_queues_config(self, node, max_tx_queues_config):
+        """Add Max TX Queues configuration for node.
+
+        :param node: DUT node.
+        :param max_tx_queues_config: Max TX Queues configuration, as a string.
+        :type node: dict
+        :type max_tx_queues_config: str
+        :return: nothing
+        """
+        if node['type'] != NodeType.DUT:
+            raise ValueError('Node type is not a DUT')
+        hostname = Topology.get_node_hostname(node)
+        if not hostname in self._nodeconfig:
+            self._nodeconfig[hostname] = {}
+        if not 'max_tx_queues_config' in self._nodeconfig[hostname]:
+            self._nodeconfig[hostname]['max_tx_queues_config'] = []
+        self._nodeconfig[hostname]['max_tx_queues_config'].append(
+            max_tx_queues_config)
+        logger.debug('Setting hostname {} max_tx_queues config to {}'.\
+            format(hostname, max_tx_queues_config))
+
+    def add_no_multi_seg_config(self, node):
+        """Add No Multi Seg configuration for node.
+
+        :param node: DUT node.
+        :type node: dict
+        :return: nothing
+        """
+        if node['type'] != NodeType.DUT:
+            raise ValueError('Node type is not a DUT')
+        hostname = Topology.get_node_hostname(node)
+        if not hostname in self._nodeconfig:
+            self._nodeconfig[hostname] = {}
+        if not 'no_multi_seg_config' in self._nodeconfig[hostname]:
+            self._nodeconfig[hostname]['no_multi_seg_config'] = []
+        self._nodeconfig[hostname]['no_multi_seg_config'].append(
+            "no-multi-seg")
+        logger.debug('Setting hostname {} config with {}'.\
+            format(hostname, "no-multi-seg"))
+
     def remove_all_pci_devices(self, node):
         """Remove PCI device configuration from node.
 
-        :param node: DUT node
-        :type: node: dict
+        :param node: DUT node.
+        :type node: dict
         :return: nothing
         """
         if node['type'] != NodeType.DUT:
@@ -193,14 +236,14 @@ class VppConfigGenerator(object):
         hostname = Topology.get_node_hostname(node)
         if hostname in self._nodeconfig:
             self._nodeconfig[hostname]['pci_addrs'] = []
-        logger.debug('Clearing all PCI devices for hostname {}.'.\
-            format(hostname))
+        logger.debug('Clearing all PCI devices for hostname {}.'.
+                     format(hostname))
 
     def remove_all_cpu_config(self, node):
         """Remove CPU configuration from node.
 
-        :param node: DUT node
-        :type: node: dict
+        :param node: DUT node.
+        :type node: dict
         :return: nothing
         """
         if node['type'] != NodeType.DUT:
@@ -208,14 +251,14 @@ class VppConfigGenerator(object):
         hostname = Topology.get_node_hostname(node)
         if hostname in self._nodeconfig:
             self._nodeconfig[hostname]['cpu_config'] = []
-        logger.debug('Clearing all CPU config for hostname {}.'.\
-            format(hostname))
+        logger.debug('Clearing all CPU config for hostname {}.'.
+                     format(hostname))
 
     def remove_socketmem_config(self, node):
         """Remove Socket Memory configuration from node.
 
-        :param node: DUT node
-        :type: node: dict
+        :param node: DUT node.
+        :type node: dict
         :return: nothing
         """
         if node['type'] != NodeType.DUT:
@@ -223,14 +266,14 @@ class VppConfigGenerator(object):
         hostname = Topology.get_node_hostname(node)
         if hostname in self._nodeconfig:
             self._nodeconfig[hostname].pop('socketmem_config', None)
-        logger.debug('Clearing Socket Memory config for hostname {}.'.\
-            format(hostname))
+        logger.debug('Clearing Socket Memory config for hostname {}.'.
+                     format(hostname))
 
     def remove_heapsize_config(self, node):
         """Remove Heap Size configuration from node.
 
-        :param node: DUT node
-        :type: node: dict
+        :param node: DUT node.
+        :type node: dict
         :return: nothing
         """
         if node['type'] != NodeType.DUT:
@@ -238,14 +281,14 @@ class VppConfigGenerator(object):
         hostname = Topology.get_node_hostname(node)
         if hostname in self._nodeconfig:
             self._nodeconfig[hostname].pop('heapsize_config', None)
-        logger.debug('Clearing Heap Size config for hostname {}.'.\
-            format(hostname))
+        logger.debug('Clearing Heap Size config for hostname {}.'.
+                     format(hostname))
 
     def remove_rss_config(self, node):
         """Remove RSS configuration from node.
 
-        :param node: DUT node
-        :type: node: dict
+        :param node: DUT node.
+        :type node: dict
         :return: nothing
         """
         if node['type'] != NodeType.DUT:
@@ -256,15 +299,45 @@ class VppConfigGenerator(object):
         logger.debug('Clearing RSS config for hostname {}.'.\
             format(hostname))
 
+    def remove_max_tx_queues_config(self, node):
+        """Remove Max TX Queues configuration from node.
+
+        :param node: DUT node.
+        :type node: dict
+        :return: nothing
+        """
+        if node['type'] != NodeType.DUT:
+            raise ValueError('Node type is not a DUT')
+        hostname = Topology.get_node_hostname(node)
+        if hostname in self._nodeconfig:
+            self._nodeconfig[hostname]['max_tx_queues_config'] = []
+        logger.debug('Clearing Max TX Queues config for hostname {}.'.\
+            format(hostname))
+
+    def remove_no_multi_seg_config(self, node):
+        """Remove No Multi Seg configuration from node.
+
+        :param node: DUT node.
+        :type node: dict
+        :return: nothing
+        """
+        if node['type'] != NodeType.DUT:
+            raise ValueError('Node type is not a DUT')
+        hostname = Topology.get_node_hostname(node)
+        if hostname in self._nodeconfig:
+            self._nodeconfig[hostname]['no_multi_seg_config'] = []
+        logger.debug('Clearing No Multi Seg config for hostname {}.'.\
+            format(hostname))
+
     def apply_config(self, node, waittime=5, retries=12):
         """Generate and apply VPP configuration for node.
 
         Use data from calls to this class to form a startup.conf file and
         replace /etc/vpp/startup.conf with it on node.
 
-        :param node: DUT node
-        :param waittime: time to wait for VPP to restart (default 5 seconds)
-        :param retries: number of times (default 12) to re-try waiting
+        :param node: DUT node.
+        :param waittime: Time to wait for VPP to restart (default 5 seconds).
+        :param retries: Number of times (default 12) to re-try waiting.
         :type node: dict
         :type waittime: int
         :type retries: int
@@ -279,6 +352,8 @@ class VppConfigGenerator(object):
         socketmemconfig = DEFAULT_SOCKETMEM_CONFIG
         heapsizeconfig = ""
         rssconfig = ""
+        txqueuesconfig = ""
+        nomultiseg = ""
 
         if hostname in self._nodeconfig:
             cfg = self._nodeconfig[hostname]
@@ -298,14 +373,23 @@ class VppConfigGenerator(object):
             if 'rss_config' in cfg:
                 rssconfig = "  " + "\n  ".join(cfg['rss_config'])
 
+            if 'max_tx_queues_config' in cfg:
+                txqueuesconfig = "  " + "\n  ".join(
+                    cfg['max_tx_queues_config'])
+
+            if 'no_multi_seg_config' in cfg:
+                nomultiseg = "  " + "\n  ".join(cfg['no_multi_seg_config'])
+
         vppconfig = VPP_CONFIG_TEMPLATE.format(cpuconfig=cpuconfig,
                                                pciconfig=pciconfig,
                                                socketmemconfig=socketmemconfig,
                                                heapsizeconfig=heapsizeconfig,
-                                               rssconfig=rssconfig)
+                                               rssconfig=rssconfig,
+                                               txqueuesconfig=txqueuesconfig,
+                                               nomultiseg = nomultiseg)
 
-        logger.debug('Writing VPP config to host {}: "{}"'.format(hostname,\
-               vppconfig))
+        logger.debug('Writing VPP config to host {}: "{}"'.format(hostname,
+                                                                  vppconfig))
 
         ssh = SSH()
         ssh.connect(node)
@@ -314,16 +398,16 @@ class VppConfigGenerator(object):
         # a sudo'd outut ("sudo echo xxx > /path/to/file") does not
         # work on most platforms...
         (ret, stdout, stderr) = \
-            ssh.exec_command('echo "{0}" | sudo tee {1}'.\
-            format(vppconfig, VPP_CONFIG_FILENAME))
+            ssh.exec_command('echo "{0}" | sudo tee {1}'.
+                             format(vppconfig, VPP_CONFIG_FILENAME))
 
         if ret != 0:
-            logger.debug('Writing config file failed to node {}'.\
-                format(hostname))
+            logger.debug('Writing config file failed to node {}'.
+                         format(hostname))
             logger.debug('stdout: {}'.format(stdout))
             logger.debug('stderr: {}'.format(stderr))
-            raise RuntimeError('Writing config file failed to node {}'.\
-                format(hostname))
+            raise RuntimeError('Writing config file failed to node {}'.
+                               format(hostname))
 
         # Instead of restarting, we'll do separate start and stop
         # actions. This way we don't care whether VPP was running
@@ -332,12 +416,12 @@ class VppConfigGenerator(object):
         (ret, stdout, stderr) = \
             ssh.exec_command('sudo initctl start {}'.format(VPP_SERVICE_NAME))
         if ret != 0:
-            logger.debug('Restarting VPP failed on node {}'.\
-                format(hostname))
+            logger.debug('Restarting VPP failed on node {}'.
+                         format(hostname))
             logger.debug('stdout: {}'.format(stdout))
             logger.debug('stderr: {}'.format(stderr))
-            raise RuntimeError('Restarting VPP failed on node {}'.\
-                format(hostname))
+            raise RuntimeError('Restarting VPP failed on node {}'.
+                               format(hostname))
 
         # Sleep <waittime> seconds, up to <retry> times,
         # and verify if VPP is running.
@@ -357,16 +441,16 @@ class VppConfigGenerator(object):
             # healthy or not, or a call that waits (up to a defined length
             # of time) and returns immediately if VPP is or becomes healthy.
             (ret, stdout, stderr) = \
-                ssh.exec_command('echo show hardware-interfaces | '\
-                    'nc 0 5002')
+                ssh.exec_command('echo show hardware-interfaces | '
+                                 'nc 0 5002')
 
             if ret == 0:
                 vpp_is_running = True
             else:
-                logger.debug('VPP not yet running, {} retries left'.\
-                    format(retries_left))
+                logger.debug('VPP not yet running, {} retries left'.
+                             format(retries_left))
         if retries_left == 0:
-            raise RuntimeError('VPP failed to restart on node {}'.\
-                format(hostname))
-        logger.debug('VPP interfaces found on node {}'.\
-           format(stdout))
+            raise RuntimeError('VPP failed to restart on node {}'.
+                               format(hostname))
+        logger.debug('VPP interfaces found on node {}'.
+                     format(stdout))