Merge "trex_learning: Add learning packet option to T-Rex testing"
[vswitchperf.git] / tools / functions.py
index 3bd8cc4..c0d1e5f 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2016 Intel Corporation.
+# Copyright 2016-2017 Intel Corporation.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -19,12 +19,15 @@ import os
 import logging
 import glob
 import shutil
+import re
 from conf import settings as S
 
+MAX_L4_FLOWS = 65536
+
 #
 # Support functions
 #
-
+# pylint: disable=too-many-branches
 def settings_update_paths():
     """ Configure paths to OVS, DPDK and QEMU sources and binaries based on
         selected vswitch type and src/binary switch. Data are taken from
@@ -63,17 +66,26 @@ def settings_update_paths():
         but testpmd can't be used as a guest loopback. This is useful in case, that other guest
         loopback applications (e.g. buildin) are used by CI jobs, etc.
     """
-    # set dpdk and ovs paths accorfing to VNF and VSWITCH
+    # set dpdk and ovs paths according to VNF, VSWITCH and TRAFFICGEN selection
     paths = {}
-    vswitch_type = S.getValue('PATHS')['vswitch'][S.getValue('VSWITCH')]['type']
-    paths['vswitch'] = S.getValue('PATHS')['vswitch'][S.getValue('VSWITCH')][vswitch_type]
-    paths['dpdk'] = S.getValue('PATHS')['dpdk'][S.getValue('PATHS')['dpdk']['type']]
-    paths['qemu'] = S.getValue('PATHS')['qemu'][S.getValue('PATHS')['qemu']['type']]
-    paths['paths'] = {}
-    paths['paths']['ovs_var_tmp'] = S.getValue('PATHS')['vswitch']['ovs_var_tmp']
-    paths['paths']['ovs_etc_tmp'] = S.getValue('PATHS')['vswitch']['ovs_etc_tmp']
+    if S.getValue("mode") != 'trafficgen':
+        # VSWITCH & (probably) VNF are needed
+        vswitch_type = S.getValue('PATHS')['vswitch'][S.getValue('VSWITCH')]['type']
+        paths['vswitch'] = S.getValue('PATHS')['vswitch'][S.getValue('VSWITCH')][vswitch_type]
+        paths['dpdk'] = S.getValue('PATHS')['dpdk'][S.getValue('PATHS')['dpdk']['type']]
+        paths['qemu'] = S.getValue('PATHS')['qemu'][S.getValue('PATHS')['qemu']['type']]
+        paths['paths'] = {}
+        paths['paths']['ovs_var_tmp'] = S.getValue('PATHS')['vswitch']['ovs_var_tmp']
+        paths['paths']['ovs_etc_tmp'] = S.getValue('PATHS')['vswitch']['ovs_etc_tmp']
+
+    if S.getValue("mode") != 'trafficgen-off':
+        # TRAFFCIGEN is required
+        if S.getValue('TRAFFICGEN') in S.getValue('PATHS')['trafficgen']:
+            tmp_trafficgen = S.getValue('PATHS')['trafficgen'][S.getValue('TRAFFICGEN')]
+            paths['trafficgen'] = tmp_trafficgen[tmp_trafficgen['type']]
 
     tools = {}
+    # pylint: disable=too-many-nested-blocks
     for path_class in paths:
         for tool in paths[path_class]:
             tmp_tool = paths[path_class][tool]
@@ -123,8 +135,8 @@ def settings_update_paths():
                     tmp_tool = tmp_glob[0]
             elif not os.path.exists(tmp_tool):
                 if tool.endswith('_tmp'):
-                    logging.getLogger().debug('Temporary path to the {} does not '
-                                              'exist: {}.'.format(tool, tmp_tool))
+                    logging.getLogger().debug('Temporary path to the %s does not '
+                                              'exist: %s', tool, tmp_tool)
                 else:
                     raise RuntimeError('Path to the {} is not valid: {}'.format(tool, tmp_tool))
 
@@ -138,3 +150,74 @@ def settings_update_paths():
         tools['dpdk_src'] = S.getValue('PATHS')['dpdk']['src']['path']
 
     S.setValue('TOOLS', tools)
+
+def check_traffic(traffic):
+    """Check traffic definition and correct it if possible.
+    """
+    # check if requested networking layers make sense
+    if traffic['l4']['enabled']:
+        if not traffic['l3']['enabled']:
+            raise RuntimeError('TRAFFIC misconfiguration: l3 must be enabled '
+                               'if l4 is enabled.')
+
+    # check if multistream configuration makes sense
+    if traffic['multistream']:
+        if traffic['stream_type'] == 'L3':
+            if not traffic['l3']['enabled']:
+                raise RuntimeError('TRAFFIC misconfiguration: l3 must be '
+                                   'enabled if l3 streams are requested.')
+        if traffic['stream_type'] == 'L4':
+            if not traffic['l4']['enabled']:
+                raise RuntimeError('TRAFFIC misconfiguration: l4 must be '
+                                   'enabled if l4 streams are requested.')
+
+            # in case of UDP ports we have only 65536 (0-65535) unique options
+            if traffic['multistream'] > MAX_L4_FLOWS:
+                logging.getLogger().warning(
+                    'Requested amount of L4 flows %s is bigger than number of '
+                    'transport protocol ports. It was set to %s.',
+                    traffic['multistream'], MAX_L4_FLOWS)
+                traffic['multistream'] = MAX_L4_FLOWS
+
+    return traffic
+
+def filter_output(output, regex):
+    """Filter output by defined regex. Output can be either string, list or tuple.
+       Every string is split into list line by line. After that regex is applied
+       to filter only matching lines, which are returned back.
+
+       :returns: list of matching records
+    """
+    result = []
+    if isinstance(output, str):
+        for line in output.split('\n'):
+            result += re.findall(regex, line)
+        return result
+    elif isinstance(output, list) or isinstance(output, tuple):
+        tmp_res = []
+        for item in output:
+            tmp_res.append(filter_output(item, regex))
+        return tmp_res
+    else:
+        raise RuntimeError('Only strings and lists are supported by filter_output(), '
+                           'but output has type {}'.format(type(output)))
+
+def format_description(desc, length):
+    """ Split description into multiple lines based on given line length.
+
+    :param desc: A string with testcase description
+    :param length: A maximum line length
+    """
+    # split description to multiple lines
+    words = desc.split()
+    output = []
+    line = ''
+    for word in words:
+        if len(line) + len(word) < length:
+            line += '{} '.format(word)
+        else:
+            output.append(line.strip())
+            line = '{} '.format(word)
+
+    output.append(line.strip())
+    return output