fix parsing tunables, add support for separate -t in console, add benchmark profile
authorYaroslav Brustinov <[email protected]>
Fri, 30 Sep 2016 09:52:29 +0000 (12:52 +0300)
committerYaroslav Brustinov <[email protected]>
Fri, 30 Sep 2016 09:55:16 +0000 (12:55 +0300)
scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
scripts/stl/bench.py [new file with mode: 0644]

index 2d7cb26..82aa932 100755 (executable)
@@ -837,7 +837,7 @@ class STLClient(object):
         if not rc:
             return rc
 
-        self.supported_cmds = rc.data()
+        self.supported_cmds = sorted(rc.data())
 
         # create ports
         for port_id in range(self.system_info["port_count"]):
@@ -2831,26 +2831,12 @@ class STLClient(object):
             else:
                 self.stop(active_ports)
 
-        
-        # default value for tunables (empty)
-        tunables = [{}] * len(opts.ports)
 
         # process tunables
-        if opts.tunables:
-
-            # for one tunable - duplicate for all ports
-            if len(opts.tunables) == 1:
-                tunables = opts.tunables * len(opts.ports)
-
-            else:
-                # must be exact
-                if len(opts.ports) != len(opts.tunables):
-                    msg = 'tunables section count must be 1 or exactly as the number of ports: got {0}'.format(len(opts.tunables))
-                    self.logger.log(msg)
-                    return RC_ERR(msg)
-
-                tunables = opts.tunables
-            
+        if type(opts.tunables) is dict:
+            tunables = opts.tunables
+        else:
+            tunables = {}
 
 
         # remove all streams
@@ -2858,12 +2844,12 @@ class STLClient(object):
 
         # pack the profile
         try:
-            for port, t in zip(opts.ports, tunables):
+            for port in opts.ports:
 
                 profile = STLProfile.load(opts.file[0],
-                                          direction = t.get('direction', port % 2),
+                                          direction = tunables.get('direction', port % 2),
                                           port_id = port,
-                                          **t)
+                                          **tunables)
 
                 self.add_streams(profile.get_streams(), ports = port)
 
index b42b56a..8ae8698 100755 (executable)
@@ -217,15 +217,28 @@ def is_valid_file(filename):
 def decode_tunables (tunable_str):
     tunables = {}
 
-    # split by diaz to tokens
-    tokens = tunable_str.split('#')
+    # split by comma to tokens
+    tokens = tunable_str.split(',')
 
     # each token is of form X=Y
     for token in tokens:
-        m = re.search('(.*)=(.*)', token)
+        m = re.search('(\S+)=(.+)', token)
         if not m:
             raise argparse.ArgumentTypeError("bad syntax for tunables: {0}".format(token))
-        tunables[m.group(1)] = m.group(2)
+        val = m.group(2)           # string
+        if val.startswith(("'", '"')) and val.endswith(("'", '"')) and len(val) > 1: # need to remove the quotes from value
+            val = val[1:-1]
+        elif val.startswith('0x'): # hex
+            val = int(val, 16)
+        else:
+            try:
+                if '.' in val:     # float
+                    val = float(val)
+                else:              # int
+                    val = int(val)
+            except:
+                pass
+        tunables[m.group(1)] = val
 
     return tunables
 
@@ -279,9 +292,10 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
                                       'metavar': 'T1=VAL[,T2=VAL ...]',
                                       'dest': "tunables",
                                       'default': None,
+                                      'action': 'merge',
                                       'type': decode_tunables}),
 
-              NO_PROMISCUOUS: ArgumentPack(['--no_prom'],
+              NO_PROMISCUOUS: ArgumentPack(['--no-prom', '--no_prom'],
                                            {'help': "Sets port promiscuous off",
                                             'dest': "prom",
                                             'default': None,
@@ -291,6 +305,7 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
                                         {"nargs": '+',
                                          'dest':'ports',
                                          'metavar': 'PORTS',
+                                         'action': 'merge',
                                          'type': int,
                                          'help': "A list of ports on which to apply the command",
                                          'default': []}),
@@ -438,6 +453,17 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
 
               }
 
+class _MergeAction(argparse._AppendAction):
+    def __call__(self, parser, namespace, values, option_string=None):
+        items = getattr(namespace, self.dest)
+        if not items:
+            items = values
+        elif type(items) is list and type(values) is list:
+            items.extend(values)
+        elif type(items) is dict and type(values) is dict: # tunables are dict
+            items.update(values)
+
+        setattr(namespace, self.dest, items)
 
 class CCmdArgParser(argparse.ArgumentParser):
 
@@ -445,7 +471,7 @@ class CCmdArgParser(argparse.ArgumentParser):
         super(CCmdArgParser, self).__init__(*args, **kwargs)
         self.stateless_client = stateless_client
         self.cmd_name = kwargs.get('prog')
-
+        self.register('action', 'merge', _MergeAction)
 
     # hook this to the logger
     def _print_message(self, message, file=None):
diff --git a/scripts/stl/bench.py b/scripts/stl/bench.py
new file mode 100644 (file)
index 0000000..6647359
--- /dev/null
@@ -0,0 +1,88 @@
+from trex_stl_lib.api import *
+
+class STLBench(object):
+    ip_range = {}
+    ip_range['src'] = {'start': '16.0.0.0', 'end': '16.0.255.255'}
+    ip_range['dst'] = {'start': '48.0.0.0', 'end': '48.0.255.255'}
+    ports = {'min': 1234, 'max': 65500}
+    pkt_size = {'min': 64, 'max': 9216}
+
+    def create_stream (self, size, vm):
+        # Create base packet and pad it to size
+        base_pkt = Ether()/IP()/UDP()
+        pad = max(0, size - len(base_pkt) - 4) * 'x'
+
+        pkt = STLPktBuilder(pkt = base_pkt/pad,
+                            vm = vm)
+
+        return STLStream(packet = pkt,
+                         mode = STLTXCont())
+
+
+    def get_streams (self, size=64, vm=None, direction=0, **kwargs):
+        if direction == 0:
+            src, dst = self.ip_range['src'], self.ip_range['dst']
+        else:
+            src, dst = self.ip_range['dst'], self.ip_range['src']
+
+        if not vm or vm == 'none':
+            vm_var = None
+        elif vm == 'var1':
+            vm_var =[
+                STLVmFlowVar(name = 'src', min_value = src['start'], max_value = src['end'], size = 4, op = 'inc'),
+                STLVmWrFlowVar(fv_name = 'src', pkt_offset = 'IP.src'),
+                STLVmFixIpv4(offset = 'IP')
+            ]
+        elif vm == 'var2':
+            vm_var =[
+                STLVmFlowVar(name = 'src', min_value = src['start'], max_value = src['end'], size = 4, op = 'inc'),
+                STLVmWrFlowVar(fv_name = 'src', pkt_offset = 'IP.src'),
+                STLVmFlowVar(name = 'dst', min_value = dst['start'], max_value = dst['end'], size = 4, op = 'inc'),
+                STLVmWrFlowVar(fv_name = 'dst', pkt_offset = 'IP.dst'),
+                STLVmFixIpv4(offset = 'IP')
+            ]
+        elif vm == 'random':
+            vm_var =[
+                STLVmFlowVar(name = 'src', min_value = src['start'], max_value = src['end'], size = 4, op = 'random'),
+                STLVmWrFlowVar(fv_name = 'src', pkt_offset = 'IP.src'),
+                STLVmFixIpv4(offset = 'IP')
+            ]
+        elif vm == 'tuple':
+            vm_var =[
+                STLVmTupleGen(ip_min = src['start'], ip_max = src['end'], port_min = self.ports['min'], port_max = self.ports['max'], name = 'tuple'),
+                STLVmWrFlowVar(fv_name = 'tuple.ip', pkt_offset =  'IP.src'),
+                STLVmWrFlowVar(fv_name = 'tuple.port', pkt_offset =  'UDP.sport'),
+                STLVmFixIpv4(offset = 'IP')
+            ]
+        elif vm == 'size':
+            size = self.pkt_size['max']
+            l3_len_fix = -len(Ether())
+            l4_len_fix = l3_len_fix - len(IP())
+            vm_var = [
+                STLVmFlowVar(name = 'fv_rand', min_value = (self.pkt_size['min'] - 4), max_value = (self.pkt_size['max'] - 4), size = 2, op = 'random'),
+                STLVmTrimPktSize('fv_rand'),
+                STLVmWrFlowVar(fv_name = 'fv_rand', pkt_offset = 'IP.len', add_val = l3_len_fix),
+                STLVmWrFlowVar(fv_name = 'fv_rand', pkt_offset = 'UDP.len', add_val = l4_len_fix),
+                STLVmFixIpv4(offset = 'IP')
+            ]
+        elif vm == 'cached':
+            vm_raw =[
+                STLVmFlowVar(name = 'src', min_value = src['start'], max_value = src['end'], size = 4, op = 'inc'),
+                STLVmWrFlowVar(fv_name = 'src', pkt_offset = 'IP.src'),
+                STLVmFixIpv4(offset = 'IP')
+            ]
+            vm_var = STLScVmRaw(vm_raw, cache_size = 255);
+        else:
+            raise Exception("VM '%s' not available" % vm)
+
+        return [self.create_stream(size, vm_var)]
+
+
+
+# dynamic load - used for trex console or simulator
+def register():
+    return STLBench()
+
+
+
+