CSIT-646 Refactor VPPConfigGenerator script 74/7074/8
authorPeter Mikus <pmikus@cisco.com>
Fri, 9 Jun 2017 07:28:10 +0000 (09:28 +0200)
committerPeter Mikus <pmikus@cisco.com>
Mon, 12 Jun 2017 13:21:14 +0000 (13:21 +0000)
Currently the VPPConfigGenerator script is not modular enough for creating
all combinations of VPP startup configuration. This patch is supposed to
implement unified structured way to create all configuration options.

Change-Id: If3f9cf5dc838fe0a698ea1c601abff6c4c0468b5
Signed-off-by: Peter Mikus <pmikus@cisco.com>
resources/libraries/python/VppConfigGenerator.py
resources/libraries/robot/default.robot
resources/libraries/robot/performance.robot

index 2a8f202..039f629 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""VPP Configuration File Generator library"""
+"""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
 
 __all__ = ['VppConfigGenerator']
 
-#
-# VPP configuration template.
-# TODO: Do we need a better place for this? Somewhere in an external
-# (template) file?
-# Note: We're going to pass this through Python string Formatter, so
-# any literal curly braces need to be escaped.
-#
-VPP_SERVICE_NAME = "vpp"
-VPP_CONFIG_FILENAME = "/etc/vpp/startup.conf"
-DEFAULT_SOCKETMEM_CONFIG = "1024,1024"
-VPP_CONFIG_TEMPLATE = """
-unix {{
-  nodaemon
-  log /tmp/vpe.log
-  cli-listen localhost:5002
-  full-coredump
-}}
-
-api-trace {{
-  on
-}}
-{heapsizeconfig}
-cpu {{
-{cpuconfig}
-}}
-
-dpdk {{
-  socket-mem {socketmemconfig}
-  dev default {{
-  {rxqueuesconfig}
-  {txqueuesconfig}
-  }}
-{pciconfig}
-  {cryptodevconfig}
-  {uiodriverconfig}
-{nomultiseg}
-{enablevhostuser}
-}}
-
-ip6 {{
-  hash-buckets 2000000
-  heap-size 3G
-}}
-{snatconfig}
-"""
-# End VPP configuration template.
-
-
 class VppConfigGenerator(object):
-    """VPP Configuration File Generator"""
+    """VPP Configuration File Generator."""
 
     def __init__(self):
+        # VPP Node to apply configuration on
+        self._node = ''
+        # VPP Hostname
+        self._hostname = ''
+        # VPP Configuration
         self._nodeconfig = {}
+        # Serialized VPP Configuration
+        self._vpp_config = ''
+        # VPP Service name
+        self._vpp_service_name = 'vpp'
+        # VPP Configuration file path
+        self._vpp_config_filename = '/etc/vpp/startup.conf'
 
-    def add_pci_all_devices(self, node):
-        """Add all PCI devices from topology file to startup config
+    def set_node(self, node):
+        """Set DUT node.
 
-        :param node: DUT node
+        :param node: Node to store configuration on.
         :type node: dict
-        :returns: nothing
+        :raises RuntimeError: If Node type is not DUT.
         """
-        for port in node['interfaces'].keys():
-            pci_addr = Topology.get_interface_pci_addr(node, port)
-            if pci_addr:
-                self.add_pci_device(node, pci_addr)
 
-    def add_pci_device(self, node, *pci_devices):
-        """Add PCI device configuration for node.
+        if node['type'] != NodeType.DUT:
+            raise RuntimeError('Startup config can only be applied to DUT'
+                               'node.')
+        self._node = node
+        self._hostname = Topology.get_node_hostname(node)
 
-        :param node: DUT node.
-        :param pci_devices: PCI devices (format 0000:00:00.0 or 00:00.0)
-        :type node: dict
-        :type pci_devices: tuple
-        :returns: nothing
+    def set_config_filename(self, filename):
+        """Set startup configuration filename.
+
+        :param filename: Startup configuration filename.
+        :type filename: str
         """
-        if node['type'] != NodeType.DUT:
-            raise ValueError('Node type is not a DUT')
+        self._vpp_config_filename = filename
 
-        # Specific device was given.
-        hostname = Topology.get_node_hostname(node)
+    def add_config_item(self, config, value, path):
+        """Add startup configuration item.
 
-        pattern = re.compile("^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:"
-                             "[0-9A-Fa-f]{2}\\.[0-9A-Fa-f]$")
-        for pci_device in pci_devices:
-            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))
+        :param config: Startup configuration of node.
+        :param value: Value to insert.
+        :param path: Path where to insert item.
+        :type config: dict
+        :type value: str
+        :type path: list
+        """
 
-            if hostname not in self._nodeconfig:
-                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))
+        if len(path) == 1:
+            config[path[0]] = value
+            return
+        if not config.has_key(path[0]):
+            config[path[0]] = {}
+        self.add_config_item(config[path[0]], value, path[1:])
 
-    def add_cpu_config(self, node, cpu_config):
-        """Add CPU configuration for node.
+    def dump_config(self, obj, level=-1):
+        """Dump the startup configuration in VPP config format.
 
-        :param node: DUT node.
-        :param cpu_config: CPU configuration option, as a string.
-        :type node: dict
-        :type cpu_config: str
+        :param obj: Python Object to print.
+        :param nested_level: Nested level for indentation.
+        :type obj: Obj
+        :type nested_level: int
         :returns: nothing
         """
-        if node['type'] != NodeType.DUT:
-            raise ValueError('Node type is not a DUT')
-        hostname = Topology.get_node_hostname(node)
-        if hostname not in self._nodeconfig:
-            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))
-
-    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.
-        :type node: dict
-        :type socketmem_config: str
-        :returns: nothing
+        indent = '  '
+        if level >= 0:
+            self._vpp_config += '{}{{\n'.format((level) * indent)
+        if isinstance(obj, dict):
+            for key, val in obj.items():
+                if hasattr(val, '__iter__'):
+                    self._vpp_config += '{}{}\n'.format((level + 1) * indent,
+                                                        key)
+                    self.dump_config(val, level + 1)
+                else:
+                    self._vpp_config += '{}{} {}\n'.format((level + 1) * indent,
+                                                           key, val)
+        else:
+            for val in obj:
+                self._vpp_config += '{}{}\n'.format((level + 1) * indent, val)
+        if level >= 0:
+            self._vpp_config += '{}}}\n'.format(level * indent)
+
+    def add_unix_log(self, value='/tmp/vpe.log'):
+        """Add UNIX log configuration.
+
+        :param value: Log file.
+        :type value: str
         """
-        if node['type'] != NodeType.DUT:
-            raise ValueError('Node type is not a DUT')
-        hostname = Topology.get_node_hostname(node)
-        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))
-
-    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.
-        :type node: dict
-        :type heapsize_config: str
-        :returns: nothing
-        """
-        if node['type'] != NodeType.DUT:
-            raise ValueError('Node type is not a DUT')
-        hostname = Topology.get_node_hostname(node)
-        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))
-
-    def add_rxqueues_config(self, node, rxqueues_config):
-        """Add Rx Queues configuration for node.
-
-        :param node: DUT node.
-        :param rxqueues_config: Rxqueues configuration, as a string.
-        :type node: dict
-        :type rxqueues_config: str
-        :returns: nothing
-        """
-        if node['type'] != NodeType.DUT:
-            raise ValueError('Node type is not a DUT')
-        hostname = Topology.get_node_hostname(node)
-        if hostname not in self._nodeconfig:
-            self._nodeconfig[hostname] = {}
-        if 'rxqueues_config' not in self._nodeconfig[hostname]:
-            self._nodeconfig[hostname]['rxqueues_config'] = []
-        self._nodeconfig[hostname]['rxqueues_config'].append(rxqueues_config)
-        logger.debug('Setting hostname {} rxqueues config to {}'.
-                     format(hostname, rxqueues_config))
-
-    def add_no_multi_seg_config(self, node):
-        """Add No Multi Seg configuration for node.
-
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
-        """
-        if node['type'] != NodeType.DUT:
-            raise ValueError('Node type is not a DUT')
-        hostname = Topology.get_node_hostname(node)
-        if hostname not in self._nodeconfig:
-            self._nodeconfig[hostname] = {}
-        if 'no_multi_seg_config' not 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 add_enable_vhost_user_config(self, node):
-        """Add enable-vhost-user configuration for node.
-
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
+        path = ['unix', 'log']
+        self.add_config_item(self._nodeconfig, value, path)
+
+    def add_unix_cli_listen(self, value='localhost:5002'):
+        """Add UNIX cli-listen configuration.
+
+        :param value: CLI listen address and port.
+        :type value: str
         """
-        if node['type'] != NodeType.DUT:
-            raise ValueError('Node type is not a DUT')
-        hostname = Topology.get_node_hostname(node)
-        if hostname not in self._nodeconfig:
-            self._nodeconfig[hostname] = {}
-        if 'enable_vhost_user' not in self._nodeconfig[hostname]:
-            self._nodeconfig[hostname]['enable_vhost_user'] = []
-        self._nodeconfig[hostname]['enable_vhost_user'].\
-            append("enable-vhost-user")
-        logger.debug('Setting hostname {} config with {}'.
-                     format(hostname, "enable-vhost-user"))
-
-    def add_snat_config(self, node):
-        """Add SNAT configuration for the node.
-
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
+        path = ['unix', 'cli-listen']
+        self.add_config_item(self._nodeconfig, value, path)
+        self._nodeconfig = {'unix': {'nodaemon': ''}}
+
+    def add_unix_nodaemon(self):
+        """Add UNIX nodaemon configuration."""
+        path = ['unix', 'nodaemon']
+        self.add_config_item(self._nodeconfig, '', path)
+
+    def add_dpdk_dev(self, *devices):
+        """Add DPDK PCI device configuration.
+
+        :param devices: PCI device(s) (format xxxx:xx:xx.x)
+        :type devices: tuple
+        :raises ValueError: If PCI address format is not valid.
         """
-        if node['type'] != NodeType.DUT:
-            raise ValueError('Node type is not a DUT')
-        hostname = Topology.get_node_hostname(node)
-        if hostname not in self._nodeconfig:
-            self._nodeconfig[hostname] = {}
-        if 'snat_config' not in self._nodeconfig[hostname]:
-            self._nodeconfig[hostname]['snat_config'] = []
-        self._nodeconfig[hostname]['snat_config'].append("deterministic")
-        logger.debug('Setting hostname {} config with {}'.
-                     format(hostname, "SNAT"))
-
-    def add_cryptodev_config(self, node, count):
-        """Add cryptodev configuration for node.
-
-        :param node: DUT node.
+
+        pattern = re.compile("^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:"
+                             "[0-9A-Fa-f]{2}\\.[0-9A-Fa-f]$")
+        for device in devices:
+            if not pattern.match(device):
+                raise ValueError('PCI address {} to be added to host {} '
+                                 'is not in valid format xxxx:xx:xx.x'.
+                                 format(device, self._hostname))
+            path = ['dpdk', 'dev {0}'.format(device)]
+            self.add_config_item(self._nodeconfig, '', path)
+
+    def add_dpdk_cryptodev(self, count):
+        """Add DPDK Crypto PCI device configuration.
+
         :param count: Number of crypto devices to add.
-        :type node: dict
         :type count: int
-        :returns: nothing
-        :raises ValueError: If node type is not a DUT
         """
-        if node['type'] != NodeType.DUT:
-            raise ValueError('Node type is not a DUT')
-        hostname = Topology.get_node_hostname(node)
-        if hostname not in self._nodeconfig:
-            self._nodeconfig[hostname] = {}
-
-        cryptodev = Topology.get_cryptodev(node)
-        cryptodev_config = ''
-
+        cryptodev = Topology.get_cryptodev(self._node)
         for i in range(count):
-            cryptodev_config += 'dev {}\n'.format(
+            cryptodev_config = 'dev {0}'.format(
                 re.sub(r'\d.\d$', '1.'+str(i), cryptodev))
+            path = ['dpdk', cryptodev_config]
+            self.add_config_item(self._nodeconfig, '', path)
+        self.add_dpdk_uio_driver('igb_uio')
 
-        self._nodeconfig[hostname]['cryptodev_config'] = cryptodev_config
-        logger.debug('Setting hostname {} Cryptodev config to {}'.
-                     format(hostname, cryptodev_config))
-
-        uio_driver_config = 'uio-driver {}'.\
-            format(Topology.get_uio_driver(node))
+    def add_dpdk_dev_default_rxq(self, value):
+        """Add DPDK dev default rxq configuration.
 
-        self._nodeconfig[hostname]['uio_driver_config'] = uio_driver_config
-        logger.debug('Setting hostname {} uio_driver config to {}'.
-                     format(hostname, uio_driver_config))
+        :param value: Default number of rxqs.
+        :type value: str
+        """
+        path = ['dpdk', 'dev default', 'num-rx-queues']
+        self.add_config_item(self._nodeconfig, value, path)
 
-    def remove_all_pci_devices(self, node):
-        """Remove PCI device configuration from node.
+    def add_dpdk_dev_default_txq(self, value):
+        """Add DPDK dev default txq configuration.
 
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
+        :param value: Default number of txqs.
+        :type value: str
         """
-        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]['pci_addrs'] = []
-        logger.debug('Clearing all PCI devices for hostname {}.'.
-                     format(hostname))
+        path = ['dpdk', 'dev default', 'num-tx-queues']
+        self.add_config_item(self._nodeconfig, value, path)
 
-    def remove_all_cpu_config(self, node):
-        """Remove CPU configuration from node.
+    def add_dpdk_socketmem(self, value):
+        """Add DPDK socket memory configuration.
 
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
+        :param value: Socket memory size.
+        :type value: str
         """
-        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]['cpu_config'] = []
-        logger.debug('Clearing all CPU config for hostname {}.'.
-                     format(hostname))
+        path = ['dpdk', 'socket-mem']
+        self.add_config_item(self._nodeconfig, value, path)
 
-    def remove_socketmem_config(self, node):
-        """Remove Socket Memory configuration from node.
+    def add_dpdk_uio_driver(self, value):
+        """Add DPDK uio-driver configuration.
 
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
+        :param value: DPDK uio-driver configuration.
+        :type value: str
         """
-        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].pop('socketmem_config', None)
-        logger.debug('Clearing Socket Memory config for hostname {}.'.
-                     format(hostname))
+        path = ['dpdk', 'uio-driver']
+        self.add_config_item(self._nodeconfig, value, path)
 
-    def remove_cryptodev_config(self, node):
-        """Remove Cryptodev configuration from node.
+    def add_cpu_main_core(self, value):
+        """Add CPU main core configuration.
 
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
-        :raises ValueError: If node type is not a DUT
+        :param value: Main core option.
+        :type value: str
         """
-        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].pop('cryptodev_config', None)
-        logger.debug('Clearing Cryptodev config for hostname {}.'.
-                     format(hostname))
+        path = ['cpu', 'main-core']
+        self.add_config_item(self._nodeconfig, value, path)
 
-    def remove_heapsize_config(self, node):
-        """Remove Heap Size configuration from node.
+    def add_cpu_corelist_workers(self, value):
+        """Add CPU corelist-workers configuration.
 
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
+        :param value: Corelist-workers option.
+        :type value: str
         """
-        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].pop('heapsize_config', None)
-        logger.debug('Clearing Heap Size config for hostname {}.'.
-                     format(hostname))
+        path = ['cpu', 'corelist-workers']
+        self.add_config_item(self._nodeconfig, value, path)
 
-    def remove_rxqueues_config(self, node):
-        """Remove Rxqueues configuration from node.
+    def add_heapsize(self, value):
+        """Add Heapsize configuration.
 
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
+        :param value: Amount of heapsize.
+        :type value: str
         """
-        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]['rxqueues_config'] = []
-        logger.debug('Clearing rxqueues config for hostname {}.'.
-                     format(hostname))
+        path = ['heapsize']
+        self.add_config_item(self._nodeconfig, value, path)
 
-    def remove_no_multi_seg_config(self, node):
-        """Remove No Multi Seg configuration from node.
+    def add_api_trace(self):
+        """Add API trace configuration."""
+        path = ['api-trace', 'on']
+        self.add_config_item(self._nodeconfig, path, '')
 
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
+    def add_ip6_hash_buckets(self, value):
+        """Add IP6 hash buckets configuration.
+
+        :param value: Number of IP6 hash buckets.
+        :type value: str
         """
-        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))
+        path = ['ip6', 'hash-buckets']
+        self.add_config_item(self._nodeconfig, value, path)
 
-    def remove_enable_vhost_user_config(self, node):
-        """Remove enable-vhost-user configuration from node.
+    def add_ip6_heap_size(self, value):
+        """Add IP6 heap-size configuration.
 
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
+        :param value: IP6 Heapsize amount.
+        :type value: str
         """
-        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]['enable_vhost_user'] = []
-        logger.debug('Clearing enable-vhost-user config for hostname {}.'.
-                     format(hostname))
+        path = ['ip6', 'heap-size']
+        self.add_config_item(self._nodeconfig, value, path)
 
-    def remove_snat_config(self, node):
-        """Remove SNAT configuration for the node.
+    def add_dpdk_no_multi_seg(self):
+        """Add DPDK no-multi-seg configuration."""
+        path = ['dpdk', 'no-multi-seg']
+        self.add_config_item(self._nodeconfig, '', path)
 
-        :param node: DUT node.
-        :type node: dict
-        :returns: nothing
+    def add_snat(self, value='deterministic'):
+        """Add SNAT configuration.
+
+        :param value: SNAT mode.
+        :type value: str
         """
-        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]['snat_config'] = []
-        logger.debug('Clearing SNAT config for hostname {}.'.format(hostname))
+        path = ['snat']
+        self.add_config_item(self._nodeconfig, value, path)
 
-    def apply_config(self, node, waittime=5, retries=12):
+    def apply_config(self, 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.
-        :type node: dict
         :type waittime: int
         :type retries: int
         :raises RuntimeError: If writing config file failed, or restarting of
         VPP failed.
         """
-
-        if node['type'] != NodeType.DUT:
-            raise ValueError('Node type is not a DUT')
-        hostname = Topology.get_node_hostname(node)
-
-        cpuconfig = ""
-        pciconfig = ""
-        socketmemconfig = DEFAULT_SOCKETMEM_CONFIG
-        heapsizeconfig = ""
-        rxqueuesconfig = ""
-        txqueuesconfig = ""
-        nomultiseg = ""
-        enablevhostuser = ""
-        cryptodevconfig = ""
-        uiodriverconfig = ""
-        snatconfig = ""
-
-        if hostname in self._nodeconfig:
-            cfg = self._nodeconfig[hostname]
-            if 'cpu_config' in cfg:
-                cpuconfig = "  " + "\n  ".join(cfg['cpu_config'])
-
-            if 'pci_addrs' in cfg:
-                pciconfig = "  dev " + "\n  dev ".join(cfg['pci_addrs'])
-
-            if 'socketmem_config' in cfg:
-                socketmemconfig = cfg['socketmem_config']
-
-            if 'cryptodev_config' in cfg:
-                cryptodevconfig = cfg['cryptodev_config']
-
-            if 'uio_driver_config' in cfg:
-                uiodriverconfig = cfg['uio_driver_config']
-
-            if 'heapsize_config' in cfg:
-                heapsizeconfig = "\nheapsize {}\n".\
-                    format(cfg['heapsize_config'])
-
-            if 'rxqueues_config' in cfg:
-                rxqueuesconfig = "  " + "\n  ".join(cfg['rxqueues_config'])
-
-            if 'no_multi_seg_config' in cfg:
-                nomultiseg = "  " + "\n  ".join(cfg['no_multi_seg_config'])
-
-            if 'enable_vhost_user' in cfg:
-                enablevhostuser = "  " + "\n  ".join(cfg['enable_vhost_user'])
-
-            if 'snat_config' in cfg:
-                snatconfig = "snat {\n"
-                snatconfig += "  " + "\n  ".join(cfg['snat_config'])
-                snatconfig += "\n}"
-
-        vppconfig = VPP_CONFIG_TEMPLATE.format(cpuconfig=cpuconfig,
-                                               pciconfig=pciconfig,
-                                               cryptodevconfig=cryptodevconfig,
-                                               uiodriverconfig=uiodriverconfig,
-                                               socketmemconfig=socketmemconfig,
-                                               heapsizeconfig=heapsizeconfig,
-                                               rxqueuesconfig=rxqueuesconfig,
-                                               txqueuesconfig=txqueuesconfig,
-                                               nomultiseg=nomultiseg,
-                                               enablevhostuser=enablevhostuser,
-                                               snatconfig=snatconfig)
-
-        logger.debug('Writing VPP config to host {}: "{}"'.format(hostname,
-                                                                  vppconfig))
+        self.dump_config(self._nodeconfig)
 
         ssh = SSH()
-        ssh.connect(node)
+        ssh.connect(self._node)
 
         # We're using this "| sudo tee" construct because redirecting
-        # a sudo'd outut ("sudo echo xxx > /path/to/file") does not
+        # a sudo's output ("sudo echo xxx > /path/to/file") does not
         # work on most platforms...
-        (ret, stdout, stderr) = \
+        (ret, _, _) = \
             ssh.exec_command('echo "{0}" | sudo tee {1}'.
-                             format(vppconfig, VPP_CONFIG_FILENAME))
+                             format(self._vpp_config,
+                                    self._vpp_config_filename))
 
         if ret != 0:
-            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))
+                               format(self._hostname))
 
         # Instead of restarting, we'll do separate start and stop
         # actions. This way we don't care whether VPP was running
         # to begin with.
-        ssh.exec_command('sudo service {} stop'.format(VPP_SERVICE_NAME))
-        (ret, stdout, stderr) = \
-            ssh.exec_command('sudo service {} start'.format(VPP_SERVICE_NAME))
+        ssh.exec_command('sudo service {} stop'
+                         .format(self._vpp_service_name))
+        (ret, _, _) = \
+            ssh.exec_command('sudo service {} start'
+                             .format(self._vpp_service_name))
         if ret != 0:
-            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))
+                               format(self._hostname))
 
         # Sleep <waittime> seconds, up to <retry> times,
         # and verify if VPP is running.
-        vpp_is_running = False
-        retries_left = retries
-        while (not vpp_is_running) and (retries_left > 0):
+        for _ in range(retries):
             time.sleep(waittime)
-            retries_left -= 1
-
-            # FIXME: Need to find a good way to check if VPP is operational.
-            #
-            # If VatTerminal/VatExecutor is anything like vppctl or
-            # vpp_api_test, then in case VPP is NOT running it will block for
-            # 30 seconds or so and not even return if VPP becomes alive during
-            # that time. This makes it unsuitable in this case. We either need
-            # a call that returns immediately, indicating whether VPP is
-            # 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) = \
+            (ret, _, _) = \
                 ssh.exec_command('echo show hardware-interfaces | '
-                                 'nc 0 5002')
+                                 'nc 0 5002 || echo "VPP not yet running"')
             if ret == 0:
-                vpp_is_running = True
-            else:
-                logger.debug('VPP not yet running, {} retries left'.
-                             format(retries_left))
-        if retries_left == 0:
+                break
+        else:
             raise RuntimeError('VPP failed to restart on node {}'.
-                               format(hostname))
-        logger.debug('VPP interfaces found on node {}'.
-                     format(stdout))
+                               format(self._hostname))
index d6952db..932fcae 100644 (file)
 | | | Kernel Module Verify | ${nodes['${dut}']} | ${module}
 | | | ... | force_load=${force_load}
 
+| Create base startup configuration of VPP on all DUTs
+| | [Documentation] | Create base startup configuration of VPP to all DUTs.
+| | ...
+| | ${duts}= | Get Matches | ${nodes} | DUT*
+| | :FOR | ${dut} | IN | @{duts}
+| | | Import Library | resources.libraries.python.VppConfigGenerator
+| | | ... | WITH NAME | ${dut}
+| | | Run keyword | ${dut}.Set Node |  ${nodes['${dut}']}
+| | | Run keyword | ${dut}.Add Unix Log
+| | | Run keyword | ${dut}.Add Unix CLI Listen
+| | | Run keyword | ${dut}.Add Unix Nodaemon
+| | | Run keyword | ${dut}.Add DPDK Socketmem | "1024,1024"
+| | | Run keyword | ${dut}.Add Heapsize | "3G"
+| | | Run keyword | ${dut}.Add IP6 Hash Buckets | "2000000"
+| | | Run keyword | ${dut}.Add IP6 Heap Size | "3G"
+
 | Add '${m}' worker threads and '${n}' rxqueues in 3-node single-link circular topology
 | | [Documentation] | Setup M worker threads and N rxqueues in vpp startup\
 | | ... | configuration on all DUTs in 3-node single-link topology.
 | | ... | skip_cnt=${1} | cpu_cnt=${1}
 | | ${dut2_cpu_w}= | Cpu list per node str | ${dut2} | ${dut2_numa}
 | | ... | skip_cnt=${2} | cpu_cnt=${m_int}
-| | ${dut1_cpu}= | Catenate | main-core | ${dut1_cpu_main}
-| | ... | corelist-workers | ${dut1_cpu_w}
-| | ${dut2_cpu}= | Catenate | main-core | ${dut2_cpu_main}
-| | ... | corelist-workers | ${dut2_cpu_w}
-| | ${rxqueues}= | Catenate | num-rx-queues | ${n}
-| | Add CPU config | ${dut1} | ${dut1_cpu}
-| | Add CPU config | ${dut2} | ${dut2_cpu}
-| | Add rxqueues config | ${dut1} | ${rxqueues}
-| | Add rxqueues config | ${dut2} | ${rxqueues}
+| | Run keyword | DUT1.Add CPU Main Core | ${dut1_cpu_main}
+| | Run keyword | DUT2.Add CPU Main Core | ${dut2_cpu_main}
+| | Run keyword | DUT1.Add CPU Corelist Workers | ${dut1_cpu_w}
+| | Run keyword | DUT2.Add CPU Corelist Workers | ${dut2_cpu_w}
+| | Run keyword | DUT1.Add DPDK Dev Default RXQ | ${n}
+| | Run keyword | DUT2.Add DPDK Dev Default RXQ | ${n}
 
 | Add '${m}' worker threads and '${n}' rxqueues in 2-node single-link circular topology
 | | [Documentation] | Setup M worker threads and N rxqueues in vpp startup\
 | | ... | skip_cnt=${1} | cpu_cnt=${1}
 | | ${dut1_cpu_w}= | Cpu list per node str | ${dut1} | ${dut1_numa}
 | | ... | skip_cnt=${2} | cpu_cnt=${m_int}
-| | ${dut1_cpu}= | Catenate | main-core | ${dut1_cpu_main}
-| | ... | corelist-workers | ${dut1_cpu_w}
-| | ${rxqueues}= | Catenate | num-rx-queues | ${n}
-| | Add CPU config | ${dut1} | ${dut1_cpu}
-| | Add rxqueues config | ${dut1} | ${rxqueues}
+| | Run keyword | DUT1.Add CPU Main Core | ${dut1_cpu_main}
+| | Run keyword | DUT1.Add CPU Corelist Workers | ${dut1_cpu_w}
+| | Run keyword | DUT1.Add DPDK Dev Default RXQ | ${n}
 
 | Add '${m}' worker threads using SMT and '${n}' rxqueues in 3-node single-link circular topology
 | | [Documentation] | Setup M worker threads using SMT and N rxqueues in vpp\
 | | ... | skip_cnt=${1} | cpu_cnt=${1} | smt_used=${True}
 | | ${dut2_cpu_w}= | Cpu list per node str | ${dut2} | ${dut2_numa}
 | | ... | skip_cnt=${2} | cpu_cnt=${m_int} | smt_used=${True}
-| | ${dut1_cpu}= | Catenate | main-core | ${dut1_cpu_main}
-| | ... | corelist-workers | ${dut1_cpu_w}
-| | ${dut2_cpu}= | Catenate | main-core | ${dut2_cpu_main}
-| | ... | corelist-workers | ${dut2_cpu_w}
-| | ${rxqueues}= | Catenate | num-rx-queues | ${n}
-| | Add CPU config | ${dut1} | ${dut1_cpu}
-| | Add CPU config | ${dut2} | ${dut2_cpu}
-| | Add rxqueues config | ${dut1} | ${rxqueues}
-| | Add rxqueues config | ${dut2} | ${rxqueues}
+| | Run keyword | DUT1.Add CPU Main Core | ${dut1_cpu_main}
+| | Run keyword | DUT2.Add CPU Main Core | ${dut2_cpu_main}
+| | Run keyword | DUT1.Add CPU Corelist Workers | ${dut1_cpu_w}
+| | Run keyword | DUT2.Add CPU Corelist Workers | ${dut2_cpu_w}
+| | Run keyword | DUT1.Add DPDK Dev Default RXQ | ${n}
+| | Run keyword | DUT2.Add DPDK Dev Default RXQ | ${n}
 
 | Add '${m}' worker threads using SMT and '${n}' rxqueues in 2-node single-link circular topology
 | | [Documentation] | Setup M worker threads and N rxqueues in vpp startup\
 | | ... | skip_cnt=${1} | cpu_cnt=${1} | smt_used=${True}
 | | ${dut1_cpu_w}= | Cpu list per node str | ${dut1} | ${dut1_numa}
 | | ... | skip_cnt=${2} | cpu_cnt=${m_int} | smt_used=${True}
-| | ${dut1_cpu}= | Catenate | main-core | ${dut1_cpu_main}
-| | ... | corelist-workers | ${dut1_cpu_w}
-| | ${rxqueues}= | Catenate | num-rx-queues | ${n}
-| | Add CPU config | ${dut1} | ${dut1_cpu}
-| | Add rxqueues config | ${dut1} | ${rxqueues}
-
-| Add all PCI devices to all DUTs
-| | [Documentation] | Add all available PCI devices from topology file to VPP\
-| | ... | startup configuration to all DUTs.
-| | ...
-| | ${duts}= | Get Matches | ${nodes} | DUT*
-| | :FOR | ${dut} | IN | @{duts}
-| | | Add PCI all devices | ${nodes['${dut}']}
-
-| Add PCI device to DUT
-| | [Documentation] | Add PCI device to VPP startup configuration
-| | ... | to DUT specified as argument.
-| | ...
-| | ... | *Arguments:*
-| | ... | - ${node} - DUT node. Type: dictionary
-| | ... | - ${pci_address} - PCI address. Type: string
-| | ...
-| | ... | *Example:*
-| | ...
-| | ... | \| Add PCI device to DUT \| ${nodes['DUT1']} \| 0000:00:00.0 \|
-| | ...
-| | [Arguments] | ${node} | ${pci_address}
-| | ...
-| | Add PCI device | ${node} | ${pci_address}
-
-| Add heapsize config to all DUTs
-| | [Documentation] | Add Add Heapsize Config to VPP startup configuration\
-| | ... | to all DUTs.
-| | ...
-| | ... | *Arguments:*
-| | ... | - ${heapsize} - Heapsize string (5G, 200M, ...)
-| | ...
-| | ... | *Example:*
-| | ...
-| | ... | \| Add heapsize config to all DUTs \| 200M \|
-| | ...
-| | [Arguments] | ${heapsize}
-| | ...
-| | ${duts}= | Get Matches | ${nodes} | DUT*
-| | :FOR | ${dut} | IN | @{duts}
-| | | Add Heapsize Config | ${nodes['${dut}']} | ${heapsize}
+| | Run keyword | DUT1.Add CPU Main Core | ${dut1_cpu_main}
+| | Run keyword | DUT1.Add CPU Corelist Workers | ${dut1_cpu_w}
+| | Run keyword | DUT1.Add DPDK Dev Default RXQ | ${n}
 
 | Add no multi seg to all DUTs
 | | [Documentation] | Add No Multi Seg to VPP startup configuration to all DUTs.
 | | ...
 | | ${duts}= | Get Matches | ${nodes} | DUT*
 | | :FOR | ${dut} | IN | @{duts}
-| | | Add No Multi Seg Config | ${nodes['${dut}']}
-
-| Add Enable Vhost User to all DUTs
-| | [Documentation] | Add Enable Vhost User to VPP startup configuration to all\
-| | ... | DUTs.
-| | ...
-| | ${duts}= | Get Matches | ${nodes} | DUT*
-| | :FOR | ${dut} | IN | @{duts}
-| | | Add Enable Vhost User Config | ${nodes['${dut}']}
+| | | Run keyword | ${dut}.Add DPDK No Multi Seg
 
 | Add SNAT to all DUTs
 | | [Documentation] | Add SNAT configuration to all DUTs.
 | | ...
 | | ${duts}= | Get Matches | ${nodes} | DUT*
 | | :FOR | ${dut} | IN | @{duts}
-| | | Add SNAT Config | ${nodes['${dut}']}
+| | | Run keyword | ${dut}.Add SNAT
 
 | Add cryptodev to all DUTs
-| | [Documentation] | AddCryptodev to VPP startup configuration to all DUTs.
+| | [Documentation] | Add Cryptodev to VPP startup configuration to all DUTs.
 | | ...
 | | ... | *Arguments:*
 | | ... | - ${count} - Number of QAT devices. Type: integer
 | | [Arguments] | ${count}
 | | ${duts}= | Get Matches | ${nodes} | DUT*
 | | :FOR | ${dut} | IN | @{duts}
-| | | Add Cryptodev Config | ${nodes['${dut}']} | ${count}
-
-| Remove startup configuration of VPP from all DUTs
-| | [Documentation] | Remove VPP startup configuration from all DUTs.
-| | ...
-| | ${duts}= | Get Matches | ${nodes} | DUT*
-| | :FOR | ${dut} | IN | @{duts}
-| | | Remove All PCI Devices | ${nodes['${dut}']}
-| | | Remove All CPU Config | ${nodes['${dut}']}
-| | | Remove Socketmem Config | ${nodes['${dut}']}
-| | | Remove Cryptodev Config | ${nodes['${dut}']}
-| | | Remove Heapsize Config | ${nodes['${dut}']}
-| | | Remove Rxqueues Config | ${nodes['${dut}']}
-| | | Remove No Multi Seg Config | ${nodes['${dut}']}
-| | | Remove Enable Vhost User Config | ${nodes['${dut}']}
-| | | Remove SNAT Config | ${nodes['${dut}']}
-
-| Setup default startup configuration of VPP on all DUTs
-| | [Documentation] | Setup default startup configuration of VPP to all DUTs.
-| | ...
-| | Remove startup configuration of VPP from all DUTs
-| | Add '1' worker threads and '1' rxqueues in 3-node single-link circular topology
-| | Add all PCI devices to all DUTs
-| | Apply startup configuration on all VPP DUTs
+| | | Run keyword | ${dut}.Add DPDK Cryptodev | ${count}
 
 | Apply startup configuration on all VPP DUTs
-| | [Documentation] | Apply startup configuration of VPP and restart VPP on all\
-| | ... | DUTs.
+| | [Documentation] | Write startup configuration and restart VPP on all DUTs.
 | | ...
 | | ${duts}= | Get Matches | ${nodes} | DUT*
 | | :FOR | ${dut} | IN | @{duts}
-| | | Apply Config | ${nodes['${dut}']}
+| | | Run keyword | ${dut}.Apply Config
 | | Update All Interface Data On All Nodes | ${nodes} | skip_tg=${TRUE}
 
 | Save VPP PIDs
index 9435d82..d0feed2 100644 (file)
 | | ${dut1_if2_pci}= | Get Interface PCI Addr | ${dut1} | ${dut1_if2}
 | | ${dut2_if1_pci}= | Get Interface PCI Addr | ${dut2} | ${dut2_if1}
 | | ${dut2_if2_pci}= | Get Interface PCI Addr | ${dut2} | ${dut2_if2}
-| | Add PCI device | ${dut1} | ${dut1_if1_pci} | ${dut1_if2_pci}
-| | Add PCI device | ${dut2} | ${dut2_if1_pci} | ${dut2_if2_pci}
+| | Run keyword | DUT1.Add DPDK Dev | ${dut1_if1_pci} | ${dut1_if2_pci}
+| | Run keyword | DUT2.Add DPDK Dev | ${dut2_if1_pci} | ${dut2_if2_pci}
 
 | Add PCI devices to DUTs in 2-node single link topology
 | | ${dut1_if1_pci}= | Get Interface PCI Addr | ${dut1} | ${dut1_if1}
 | | ${dut1_if2_pci}= | Get Interface PCI Addr | ${dut1} | ${dut1_if2}
-| | Add PCI device | ${dut1} | ${dut1_if1_pci} | ${dut1_if2_pci}
+| | Run keyword | DUT1.Add DPDK Dev | ${dut1_if1_pci} | ${dut1_if2_pci}
 
 | Configure guest VM with dpdk-testpmd connected via vhost-user
 | | [Documentation]
 | | [Documentation] | Common test setup for performance tests.
 | | ...
 | | Reset VAT History On All DUTs | ${nodes}
+| | Create base startup configuration of VPP on all DUTs
 
 | Tear down performance discovery test
 | | [Documentation] | Common test teardown for ndrdisc and pdrdisc performance \
 | | Run Keyword If Test Failed
 | | ... | Traffic should pass with no loss | ${perf_trial_duration} | ${rate}
 | | ... | ${framesize} | ${topology_type} | fail_on_loss=${False}
-| | Remove startup configuration of VPP from all DUTs
 
 | Tear down performance ndrchk test
 | | [Documentation] | Common test teardown for ndrchk performance tests.
 | | ...
 | | Show VAT History On All DUTs | ${nodes}
 | | Show statistics on all DUTs
-| | Remove startup configuration of VPP from all DUTs
 
 | Performance pdrchk test teardown
 | | [Documentation] | Common test teardown for pdrchk performance tests.
 | | ...
 | | Show VAT History On All DUTs | ${nodes}
 | | Show statistics on all DUTs
-| | Remove startup configuration of VPP from all DUTs
 
 | Tear down performance test with vhost and VM with dpdk-testpmd
 | | [Documentation] | Common test teardown for performance tests which use
 | | Run Keyword If Test Failed
 | | ... | Traffic should pass with no loss | ${perf_trial_duration} | ${rate}
 | | ... | ${framesize} | ${topology_type} | fail_on_loss=${False}
-| | Remove startup configuration of VPP from all DUTs
 | | Run keyword unless | ${dut1_node}==${None}
 | | ... | Tear down guest VM with dpdk-testpmd | ${dut1} | ${dut1_vm_refs}
 | | Run keyword unless | ${dut2_node}==${None}

©2016 FD.io a Linux Foundation Collaborative Project. All Rights Reserved.
Linux Foundation is a registered trademark of The Linux Foundation. Linux is a registered trademark of Linus Torvalds.
Please see our privacy policy and terms of use.