summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/stl/trex_stl_lib
diff options
context:
space:
mode:
authorIdo Barnea <ibarnea@cisco.com>2016-03-16 20:04:28 +0200
committerIdo Barnea <ibarnea@cisco.com>2016-03-16 20:04:28 +0200
commit027850daba11821c3c4eeb1d3711d5905c1ed95d (patch)
tree85681ec64d435f4c9bc03deb2e7e16cd3d0f105c /scripts/automation/trex_control_plane/stl/trex_stl_lib
parentdaf8476c5602d026364df9816ade07a3d4831a0a (diff)
parentaa334e0ef9258ffc70f0741627861b832d79a69b (diff)
Merge branch 'master' of csi-sceasr-b32:/auto/proj-pcube-b/apps/PL-b/tools/repo//trex-core
Diffstat (limited to 'scripts/automation/trex_control_plane/stl/trex_stl_lib')
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py72
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py33
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py71
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py22
4 files changed, 180 insertions, 18 deletions
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
index f7e63ccf..de07e9e4 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
@@ -1930,6 +1930,7 @@ class STLClient(object):
parsing_opts.FORCE,
parsing_opts.FILE_PATH,
parsing_opts.DURATION,
+ parsing_opts.TUNABLES,
parsing_opts.MULTIPLIER_STRICT,
parsing_opts.DRY_RUN)
@@ -1950,21 +1951,47 @@ 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):
+ self.logger.log('tunables section count must be 1 or exactly as the number of ports: got {0}'.format(len(opts.tunables)))
+ return
+ tunables = opts.tunables
+
+
# remove all streams
self.remove_all_streams(opts.ports)
# pack the profile
try:
- profile = STLProfile.load(opts.file[0])
+ for port, t in zip(opts.ports, tunables):
+
+ # give priority to the user configuration over default direction
+ if not 'direction' in t:
+ t['direction'] = (port % 2)
+
+ profile = STLProfile.load(opts.file[0], **t)
+
+ self.add_streams(profile.get_streams(), ports = port)
+
except STLError as e:
self.logger.log(format_text("\nError while loading profile '{0}'\n".format(opts.file[0]), 'bold'))
self.logger.log(e.brief() + "\n")
return
- self.add_streams(profile.get_streams(), ports = opts.ports)
-
if opts.dry:
self.validate(opts.ports, opts.mult, opts.duration, opts.total)
else:
@@ -2249,3 +2276,42 @@ class STLClient(object):
return
+
+ @__console
+ def show_profile_line (self, line):
+ '''Shows profile information'''
+
+ parser = parsing_opts.gen_parser(self,
+ "port",
+ self.show_profile_line.__doc__,
+ parsing_opts.FILE_PATH)
+
+ opts = parser.parse_args(line.split())
+ if opts is None:
+ return
+
+ info = STLProfile.get_info(opts.file[0])
+
+ self.logger.log(format_text('\nProfile Information:\n', 'bold'))
+
+ # general info
+ self.logger.log(format_text('\nGeneral Information:', 'underline'))
+ self.logger.log('Filename: {:^12}'.format(opts.file[0]))
+ self.logger.log('Stream count: {:^12}'.format(info['stream_count']))
+
+ # specific info
+ profile_type = info['type']
+ self.logger.log(format_text('\nSpecific Information:', 'underline'))
+
+ if profile_type == 'python':
+ self.logger.log('Type: {:^12}'.format('Python Module'))
+ self.logger.log('Tunables: {:^12}'.format(['{0} = {1}'.format(k ,v) for k, v in info['tunables'].iteritems()]))
+
+ elif profile_type == 'yaml':
+ self.logger.log('Type: {:^12}'.format('YAML'))
+
+ elif profile_type == 'pcap':
+ self.logger.log('Type: {:^12}'.format('PCAP file'))
+
+ self.logger.log("")
+
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py
index 614d8b77..00fa6a93 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py
@@ -122,7 +122,8 @@ class STLSim(object):
mult = "1",
duration = -1,
mode = 'none',
- silent = False):
+ silent = False,
+ tunables = None):
if not mode in ['none', 'gdb', 'valgrind', 'json', 'yaml','pkt','native']:
raise STLArgumentError('mode', mode)
@@ -139,9 +140,18 @@ class STLSim(object):
stream_list = [x for x in input_list if isinstance(x, STLStream)]
# handle YAMLs
+ if tunables == None:
+ tunables = {}
+ else:
+ tunables = tunables[0]
+
for input_file in input_files:
try:
- profile = STLProfile.load(input_file)
+ if not 'direction' in tunables:
+ tunables['direction'] = self.port_id % 2
+
+ profile = STLProfile.load(input_file, **tunables)
+
except STLError as e:
s = format_text("\nError while loading profile '{0}'\n".format(input_file), 'bold')
s += "\n" + e.brief()
@@ -360,6 +370,13 @@ def setParserOptions():
default = None,
type = int)
+ parser.add_argument("-i", "--port",
+ help = "Simulate a specific port ID [default is 0]",
+ dest = "port_id",
+ default = 0,
+ type = int)
+
+
parser.add_argument("-r", "--release",
help = "runs on release image instead of debug [default is False]",
action = "store_true",
@@ -388,6 +405,13 @@ def setParserOptions():
default = -1,
type = float)
+
+ parser.add_argument('-t',
+ help = 'sets tunable for a profile',
+ dest = 'tunables',
+ default = None,
+ type = parsing_opts.decode_tunables)
+
parser.add_argument('-p', '--path',
help = "BP sim path",
dest = 'bp_sim_path',
@@ -465,7 +489,7 @@ def main (args = None):
mode = 'none'
try:
- r = STLSim(bp_sim_path = options.bp_sim_path)
+ r = STLSim(bp_sim_path = options.bp_sim_path, port_id = options.port_id)
r.run(input_list = options.input_file,
outfile = options.output_file,
@@ -476,7 +500,8 @@ def main (args = None):
mult = options.mult,
duration = options.duration,
mode = mode,
- silent = options.silent)
+ silent = options.silent,
+ tunables = options.tunables)
except KeyboardInterrupt as e:
print "\n\n*** Caught Ctrl + C... Exiting...\n\n"
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py
index b1bde030..8a42145d 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py
@@ -508,7 +508,13 @@ class STLStream(object):
def to_code (self):
""" convert to Python code as profile """
packet = Ether(self.pkt)
- packet.hide_defaults()
+ layer = packet
+ while layer: # remove checksums
+ for chksum_name in ('cksum', 'chksum'):
+ if chksum_name in layer.fields:
+ del layer.fields[chksum_name]
+ layer = layer.payload
+ packet.hide_defaults() # remove fields with default values
payload = packet.getlayer('Raw')
packet_command = packet.command()
imports_arr = []
@@ -790,7 +796,6 @@ class STLProfile(object):
streams : list of :class:`trex_stl_lib.trex_stl_streams.STLStream`
a list of stream objects
-
"""
@@ -804,6 +809,7 @@ class STLProfile(object):
raise STLArgumentError('streams', streams, valid_values = STLStream)
self.streams = streams
+ self.meta = None
def get_streams (self):
@@ -825,11 +831,32 @@ class STLProfile(object):
yaml_loader = YAMLLoader(yaml_file)
streams = yaml_loader.parse()
- return STLProfile(streams)
+ profile = STLProfile(streams)
+ profile.meta = {'type': 'yaml'}
+
+ return profile
+
+ @staticmethod
+ def get_module_tunables(module):
+ # remove self and variables
+ func = module.register().get_streams
+ argc = func.__code__.co_argcount
+ tunables = func.__code__.co_varnames[1:argc]
+
+ # fetch defaults
+ defaults = func.func_defaults
+ if len(defaults) != (argc - 1):
+ raise STLError("Module should provide default values for all arguments on get_streams()")
+
+ output = {}
+ for t, d in zip(tunables, defaults):
+ output[t] = d
+
+ return output
@staticmethod
- def load_py (python_file):
+ def load_py (python_file, direction = 0, **kwargs):
""" load from Python profile """
# check filename
@@ -844,9 +871,18 @@ class STLProfile(object):
module = __import__(file, globals(), locals(), [], -1)
reload(module) # reload the update
- streams = module.register().get_streams()
+ t = STLProfile.get_module_tunables(module)
+ for arg in kwargs:
+ if not arg in t:
+ raise STLError("profile {0} does not support tunable '{1}' - supported tunables are: '{2}'".format(python_file, arg, t))
+
+ streams = module.register().get_streams(direction = direction, **kwargs)
+ profile = STLProfile(streams)
- return STLProfile(streams)
+ profile.meta = {'type': 'python',
+ 'tunables': t}
+
+ return profile
except Exception as e:
a, b, tb = sys.exc_info()
@@ -896,6 +932,8 @@ class STLProfile(object):
if ipg_usec < 1:
raise STLError("ipg_usec cannot be less than 1 usec: '{0}'".format(ipg_usec))
+ if loop_count < 0:
+ raise STLError("'loop_count' cannot be negative")
streams = []
last_ts_usec = 0
@@ -928,20 +966,25 @@ class STLProfile(object):
last_ts_usec = ts_usec
+
+ profile = STLProfile(streams)
+ profile.meta = {'type': 'pcap'}
- return STLProfile(streams)
+ return profile
@staticmethod
- def load (filename):
+ def load (filename, direction = 0, **kwargs):
""" load a profile by its type supported type are
* py
* yaml
* pcap file that converted to profile automaticly
:parameters:
- filename : string as filename
+ filename : string as filename
+ direction : profile's direction (if supported by the profile)
+ kwargs : forward those key-value pairs to the profile
"""
@@ -949,7 +992,7 @@ class STLProfile(object):
suffix = x[1] if (len(x) == 2) else None
if suffix == 'py':
- profile = STLProfile.load_py(filename)
+ profile = STLProfile.load_py(filename, direction, **kwargs)
elif suffix == 'yaml':
profile = STLProfile.load_yaml(filename)
@@ -960,8 +1003,14 @@ class STLProfile(object):
else:
raise STLError("unknown profile file type: '{0}'".format(suffix))
+ profile.meta['stream_count'] = len(profile.get_streams()) if isinstance(profile.get_streams(), list) else 1
return profile
+ @staticmethod
+ def get_info (filename):
+ profile = STLProfile.load(filename)
+ return profile.meta
+
def dump_as_pkt (self):
""" dump the profile as scapy packet. in case it is raw convert to scapy and dump it"""
cnt=0;
@@ -990,7 +1039,7 @@ class STLProfile(object):
from trex_stl_lib.api import *
class STLS1(object):
- def get_streams(self):
+ def get_streams(self, direction = 0, **kwargs):
streams = []
'''
for stream in self.streams:
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
index 0390ac9c..c4f2b358 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
@@ -30,6 +30,7 @@ COUNT = 18
PROMISCUOUS = 19
NO_PROMISCUOUS = 20
PROMISCUOUS_SWITCH = 21
+TUNABLES = 22
GLOBAL_STATS = 50
PORT_STATS = 51
@@ -190,6 +191,19 @@ def is_valid_file(filename):
return filename
+def decode_tunables_to_dict (**kwargs):
+ return kwargs
+
+def decode_tunables (tunable_str):
+ try:
+ tunables = [eval('decode_tunables_to_dict({0})'.format(t)) for t in tunable_str.split('#')]
+
+ except (SyntaxError, NameError):
+ raise argparse.ArgumentTypeError("bad syntax for tunables: {0}".format(tunable_str))
+
+ return tunables
+
+
OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
{'help': match_multiplier_help,
'dest': "mult",
@@ -233,6 +247,14 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
'default': None,
'action': "store_true"}),
+
+ TUNABLES: ArgumentPack(['-t'],
+ {'help': "sets tunable for a profile",
+ 'dest': "tunables",
+ 'default': None,
+ 'type': decode_tunables}),
+
+
NO_PROMISCUOUS: ArgumentPack(['--no_prom'],
{'help': "sets port promiscuous off",
'dest': "prom",