From 0814f72d66600967c9bf5f1c743ce0ee64e5c1f2 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Thu, 2 Jun 2016 17:19:43 +0300 Subject: update doc section --- README.asciidoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.asciidoc b/README.asciidoc index a4cc808d..bda3bac7 100755 --- a/README.asciidoc +++ b/README.asciidoc @@ -125,6 +125,11 @@ link:http://www.youtube.com/watch?v=U0gRalB7DOs[Video DPDK summit 2015] link:https://trex-tgn.cisco.com/trex/doc/trex_preso.html[Presentation] + +=== Documentation + +link:https://trex-tgn.cisco.com/trex/doc/index.html[Documentation] + === Wiki Internal link:https://github.com/cisco-system-traffic-generator/trex-core/wiki[Wiki] -- cgit 1.2.3-korg From b646f5c0d88d90322291a5a0a021d77a4824187a Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Sun, 5 Jun 2016 16:38:22 +0300 Subject: remove STLSim from pcap example, remove search of BP-sim path --- .../trex_control_plane/stl/examples/stl_pcap.py | 4 +--- .../trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py | 15 ++++----------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_pcap.py b/scripts/automation/trex_control_plane/stl/examples/stl_pcap.py index eae0f18b..98af6134 100644 --- a/scripts/automation/trex_control_plane/stl/examples/stl_pcap.py +++ b/scripts/automation/trex_control_plane/stl/examples/stl_pcap.py @@ -39,14 +39,12 @@ def inject_pcap (pcap_file, server, port, loop_count, ipg_usec, use_vm, remove_f c.reset(ports = [port]) c.clear_stats() - d = c.push_pcap(pcap_file, + c.push_pcap(pcap_file, ipg_usec = ipg_usec, count = loop_count, vm = vm, packet_hook = packet_hook) - STLSim().run(d, outfile = 'test.cap') - c.wait_on_traffic() 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 11e80b9a..62724e64 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 @@ -40,18 +40,11 @@ class BpSimException(Exception): # stateless simulation class STLSim(object): - def __init__ (self, bp_sim_path = None, handler = 0, port_id = 0, api_h = "dummy"): + def __init__ (self, bp_sim_path, handler = 0, port_id = 0, api_h = "dummy"): - if not bp_sim_path: - # auto find scripts - m = re.match(".*/trex-core", os.getcwd()) - if not m: - raise STLError('cannot find BP sim path, please provide it') - - self.bp_sim_path = os.path.join(m.group(0), 'scripts') - - else: - self.bp_sim_path = bp_sim_path + self.bp_sim_path = os.path.abspath(bp_sim_path) + if not os.path.exists(self.bp_sim_path): + raise STLError('BP sim path %s does not exist' % self.bp_sim_path) # dummies self.handler = handler -- cgit 1.2.3-korg From c3347adaa94e6dea31530804cbb0e6c8e2be1b30 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Sun, 5 Jun 2016 16:44:25 +0300 Subject: regression: add path to stl-sim at tests --- scripts/automation/regression/functional_tests/stl_basic_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/automation/regression/functional_tests/stl_basic_tests.py b/scripts/automation/regression/functional_tests/stl_basic_tests.py index dbbf2530..863307f1 100644 --- a/scripts/automation/regression/functional_tests/stl_basic_tests.py +++ b/scripts/automation/regression/functional_tests/stl_basic_tests.py @@ -119,9 +119,9 @@ class CStlBasic_Test(functional_general_test.CGeneralFunctional_Test): def run_sim (self, yaml, output, options = "", silent = False, obj = None): if output: - user_cmd = "-f {0} -o {1} {2}".format(yaml, output, options) + user_cmd = "-f {0} -o {1} {2} -p {3}".format(yaml, output, options, self.scripts_path) else: - user_cmd = "-f {0} {1}".format(yaml, options) + user_cmd = "-f {0} {1} -p {2}".format(yaml, options, self.scripts_path) if silent: user_cmd += " --silent" -- cgit 1.2.3-korg From 2aaf83ee88b49e3a10543f8415f73652be606ecc Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Sun, 5 Jun 2016 17:35:12 +0300 Subject: singleton_daemon:verify RPC connectivity, shutdown the socket for immediate close --- .../trex_control_plane/server/singleton_daemon.py | 40 +++++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/scripts/automation/trex_control_plane/server/singleton_daemon.py b/scripts/automation/trex_control_plane/server/singleton_daemon.py index 7cfbc3bc..81b384c5 100755 --- a/scripts/automation/trex_control_plane/server/singleton_daemon.py +++ b/scripts/automation/trex_control_plane/server/singleton_daemon.py @@ -6,6 +6,8 @@ import tempfile import types from subprocess import Popen from time import sleep +import outer_packages +import jsonrpclib # uses Unix sockets for determine running process. # (assumes used daemons will register proper socket) @@ -28,14 +30,14 @@ class SingletonDaemon(object): # returns True if daemon is running def is_running(self): - lock_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) try: - lock_socket.bind('\0' + self.tag) # the check is ~200000 faster and more reliable than checking via 'netstat' or 'ps' etc. + lock_socket = register_socket(self.tag) # the check is ~200000 faster and more reliable than checking via 'netstat' or 'ps' etc. + lock_socket.shutdown(socket.SHUT_RDWR) lock_socket.close() except socket.error: # Unix socket in use return True # Unix socket is not used, but maybe it's old version of daemon not using socket - return bool(self.get_pid()) + return bool(self.get_pid_by_listening_port()) # get pid of running daemon by registered Unix socket (most robust way) @@ -73,7 +75,7 @@ class SingletonDaemon(object): # kill daemon - def kill(self, timeout = 5): + def kill(self, timeout = 10): pid = self.get_pid() if not pid: return False @@ -88,17 +90,32 @@ class SingletonDaemon(object): ret_code, stdout, stderr = run_command('kill -9 %s' % pid) # unconditional kill if ret_code: raise Exception('Failed to run kill -9 command for %s: %s' % (self.name, [ret_code, stdout, stderr])) - poll_rate = 0.1 - for i in range(inr(timeout / poll_rate)): + for i in range(int(timeout / poll_rate)): if not self.is_running(): return True sleep(poll_rate) raise Exception('Could not kill %s, even with -9' % self.name) + # try connection as RPC client, return True upon success, False if fail + def check_connectivity(self, timeout = 5): + daemon = jsonrpclib.Server('http://127.0.0.1:%s/' % self.port) + poll_rate = 0.1 + for i in range(int(timeout/poll_rate)): + try: + daemon.not_existing_function_asdfasd() + except socket.error: # daemon is not up yet + sleep(poll_rate) + except Exception as e: # expect error of not supported function + if type(e.args) is tuple and\ + type(e.args[0]) is tuple and\ + e.args[0][0] == -32601: # error code is written hardcoded in JsonRPC Server + return True + raise + return False # start daemon # returns True if success, False if already running - def start(self, timeout = 5): + def start(self, timeout = 20): if self.is_running(): raise Exception('%s is already running' % self.name) if not self.run_cmd: @@ -112,6 +129,8 @@ class SingletonDaemon(object): if timeout > 0: poll_rate = 0.1 for i in range(int(timeout/poll_rate)): + if self.is_running(): + break sleep(poll_rate) if bool(proc.poll()): # process ended with error stdout_file.seek(0) @@ -120,7 +139,9 @@ class SingletonDaemon(object): elif proc.poll() == 0: # process runs other process, and ended break if self.is_running(): - return True + if self.check_connectivity(): + return True + raise Exception('Daemon process is running, but no connectivity') raise Exception('%s failed to run.' % self.name) # restart the daemon @@ -136,8 +157,9 @@ def register_socket(tag): lock_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) try: lock_socket.bind('\0%s' % tag) + return lock_socket except socket.error: - raise Exception('Error: process with tag %s is already running.' % tag) + raise socket.error('Error: process with tag %s is already running.' % tag) # runs command def run_command(command, timeout = 15, cwd = None): -- cgit 1.2.3-korg From 1454985e5408bdf796a9c9978622f2ba66ec04d8 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Mon, 6 Jun 2016 11:10:44 +0300 Subject: daemons fixes --- scripts/automation/regression/trex_unit_test.py | 8 +++---- .../trex_control_plane/server/singleton_daemon.py | 13 ++++------- .../server/trex_launch_thread.py | 3 ++- .../trex_control_plane/server/trex_server.py | 27 ++++++++-------------- 4 files changed, 20 insertions(+), 31 deletions(-) diff --git a/scripts/automation/regression/trex_unit_test.py b/scripts/automation/regression/trex_unit_test.py index 0762fc95..b32279e8 100755 --- a/scripts/automation/regression/trex_unit_test.py +++ b/scripts/automation/regression/trex_unit_test.py @@ -238,11 +238,11 @@ class CTRexTestConfiguringPlugin(Plugin): if self.stateful: CTRexScenario.trex = None if self.stateless: - if not self.no_daemon: + if self.no_daemon: + if CTRexScenario.stl_trex and CTRexScenario.stl_trex.is_connected(): + CTRexScenario.stl_trex.disconnect() + else: CTRexScenario.trex.force_kill(False) - if CTRexScenario.stl_trex and CTRexScenario.stl_trex.is_connected(): - CTRexScenario.stl_trex.disconnect() - #time.sleep(3) CTRexScenario.stl_trex = None diff --git a/scripts/automation/trex_control_plane/server/singleton_daemon.py b/scripts/automation/trex_control_plane/server/singleton_daemon.py index 81b384c5..8fdedc6e 100755 --- a/scripts/automation/trex_control_plane/server/singleton_daemon.py +++ b/scripts/automation/trex_control_plane/server/singleton_daemon.py @@ -11,7 +11,7 @@ import jsonrpclib # uses Unix sockets for determine running process. # (assumes used daemons will register proper socket) -# all daemons should use -p argument as listening tcp port +# all daemons should use -p argument as listening tcp port and check_connectivity RPC method class SingletonDaemon(object): # run_cmd can be function of how to run daemon or a str to run at subprocess @@ -102,15 +102,10 @@ class SingletonDaemon(object): poll_rate = 0.1 for i in range(int(timeout/poll_rate)): try: - daemon.not_existing_function_asdfasd() + daemon.check_connectivity() + return True except socket.error: # daemon is not up yet sleep(poll_rate) - except Exception as e: # expect error of not supported function - if type(e.args) is tuple and\ - type(e.args[0]) is tuple and\ - e.args[0][0] == -32601: # error code is written hardcoded in JsonRPC Server - return True - raise return False # start daemon @@ -175,6 +170,8 @@ def run_command(command, timeout = 15, cwd = None): if proc.poll() is None: proc.kill() # timeout return (errno.ETIME, '', 'Timeout on running: %s' % command) + else: + proc.wait() stdout_file.seek(0) stderr_file.seek(0) return (proc.returncode, stdout_file.read().decode(errors = 'replace'), stderr_file.read().decode(errors = 'replace')) diff --git a/scripts/automation/trex_control_plane/server/trex_launch_thread.py b/scripts/automation/trex_control_plane/server/trex_launch_thread.py index 74ce1750..82a7f996 100755 --- a/scripts/automation/trex_control_plane/server/trex_launch_thread.py +++ b/scripts/automation/trex_control_plane/server/trex_launch_thread.py @@ -6,6 +6,7 @@ import signal import socket from common.trex_status_e import TRexStatus import subprocess +import shlex import time import threading import logging @@ -32,7 +33,7 @@ class AsynchronousTRexSession(threading.Thread): with open(os.devnull, 'w') as DEVNULL: self.time_stamps['start'] = self.time_stamps['run_time'] = time.time() - self.session = subprocess.Popen("exec "+self.cmd, cwd = self.launch_path, shell=True, stdin = DEVNULL, stderr = subprocess.PIPE, preexec_fn=os.setsid) + self.session = subprocess.Popen(shlex.split(self.cmd), cwd = self.launch_path, stdin = DEVNULL, stderr = subprocess.PIPE, preexec_fn=os.setsid, close_fds = True) logger.info("TRex session initialized successfully, Parent process pid is {pid}.".format( pid = self.session.pid )) while self.session.poll() is None: # subprocess is NOT finished time.sleep(0.5) diff --git a/scripts/automation/trex_control_plane/server/trex_server.py b/scripts/automation/trex_control_plane/server/trex_server.py index 45ef9ac1..8f7e99f0 100755 --- a/scripts/automation/trex_control_plane/server/trex_server.py +++ b/scripts/automation/trex_control_plane/server/trex_server.py @@ -30,9 +30,9 @@ import shlex import tempfile try: - from .singleton_daemon import register_socket + from .singleton_daemon import register_socket, run_command except: - from singleton_daemon import register_socket + from singleton_daemon import register_socket, run_command # setup the logger @@ -134,6 +134,7 @@ class CTRexServer(object): self.server.register_function(self.add) self.server.register_function(self.cancel_reservation) self.server.register_function(self.connectivity_check) + self.server.register_function(self.connectivity_check, 'check_connectivity') # alias self.server.register_function(self.force_trex_kill) self.server.register_function(self.get_file) self.server.register_function(self.get_files_list) @@ -164,16 +165,6 @@ class CTRexServer(object): self.server.shutdown() #self.server.server_close() - def _run_command(self, command, timeout = 15, cwd = None): - if timeout: - command = 'timeout %s %s' % (timeout, command) - # pipes might stuck, even with timeout - with tempfile.TemporaryFile() as stdout_file, tempfile.TemporaryFile() as stderr_file: - proc = subprocess.Popen(shlex.split(command), stdout=stdout_file, stderr=stderr_file, cwd = cwd) - proc.wait() - stdout_file.seek(0) - stderr_file.seek(0) - return (proc.returncode, stdout_file.read().decode(errors = 'replace'), stderr_file.read().decode(errors = 'replace')) # get files from Trex server and return their content (mainly for logs) @staticmethod @@ -234,7 +225,7 @@ class CTRexServer(object): try: logger.info("Processing get_trex_version() command.") if not self.trex_version: - ret_code, stdout, stderr = self._run_command('./t-rex-64 --help', cwd = self.TREX_PATH, timeout = 0) + ret_code, stdout, stderr = run_command('./t-rex-64 --help', cwd = self.TREX_PATH) search_result = re.search('\n\s*(Version\s*:.+)', stdout, re.DOTALL) if not search_result: raise Exception('Could not determine version from ./t-rex-64 --help') @@ -383,7 +374,7 @@ class CTRexServer(object): # returns list of tuples (pid, command line) of running TRex(es) def get_trex_cmds(self): logger.info('Processing get_trex_cmds() command.') - ret_code, stdout, stderr = self._run_command('ps -u root --format pid,comm,cmd') + ret_code, stdout, stderr = run_command('ps -u root --format pid,comm,cmd') if ret_code: raise Exception('Failed to determine running processes, stderr: %s' % stderr) trex_cmds_list = [] @@ -403,12 +394,12 @@ class CTRexServer(object): return False for pid, cmd in trex_cmds_list: logger.info('Killing process %s %s' % (pid, cmd)) - self._run_command('kill %s' % pid) - ret_code_ps, _, _ = self._run_command('ps -p %s' % pid) + run_command('kill %s' % pid) + ret_code_ps, _, _ = run_command('ps -p %s' % pid) if not ret_code_ps: logger.info('Killing with -9.') - self._run_command('kill -9 %s' % pid) - ret_code_ps, _, _ = self._run_command('ps -p %s' % pid) + run_command('kill -9 %s' % pid) + ret_code_ps, _, _ = run_command('ps -p %s' % pid) if not ret_code_ps: logger.info('Could not kill process.') raise Exception('Could not kill process %s %s' % (pid, cmd)) -- cgit 1.2.3-korg From f2aeea5212180bc0b9efce725adaf0d832f6f199 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Mon, 6 Jun 2016 14:36:09 +0300 Subject: regression: reduce 1 json request --- scripts/automation/regression/trex_unit_test.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/automation/regression/trex_unit_test.py b/scripts/automation/regression/trex_unit_test.py index b32279e8..83650164 100755 --- a/scripts/automation/regression/trex_unit_test.py +++ b/scripts/automation/regression/trex_unit_test.py @@ -203,11 +203,10 @@ class CTRexTestConfiguringPlugin(Plugin): print('Could not restart TRex daemon server') sys.exit(-1) - trex_cmds = CTRexScenario.trex.get_trex_cmds() - if trex_cmds: - if self.kill_running: - CTRexScenario.trex.kill_all_trexes() - else: + if self.kill_running: + CTRexScenario.trex.kill_all_trexes() + else: + if CTRexScenario.trex.get_trex_cmds(): print('TRex is already running') sys.exit(-1) -- cgit 1.2.3-korg From 918ae3cda75a01c8a4769df79bf6bfd0b270a41f Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Mon, 6 Jun 2016 15:38:29 +0300 Subject: add logger to master daemon --- scripts/master_daemon.py | 70 +++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/scripts/master_daemon.py b/scripts/master_daemon.py index 0b1b7363..390db0a3 100755 --- a/scripts/master_daemon.py +++ b/scripts/master_daemon.py @@ -9,6 +9,7 @@ from collections import OrderedDict from argparse import * from time import time, sleep from glob import glob +import signal sys.path.append(os.path.join('automation', 'trex_control_plane', 'server')) import outer_packages @@ -16,7 +17,7 @@ from singleton_daemon import SingletonDaemon, register_socket, run_command from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer import termstyle -logging.basicConfig(level = logging.FATAL) # keep quiet +logger = logging.getLogger('Master daemon') ### Server functions ### @@ -83,33 +84,52 @@ def start_master_daemon(): proc.start() for i in range(50): if master_daemon.is_running(): - print(termstyle.green('Master daemon is started')) + print(termstyle.green('Master daemon is started.')) os._exit(0) sleep(0.1) - fail(termstyle.red('Master daemon failed to run')) - + fail(termstyle.red('Master daemon failed to run. Please look in log: %s' % logging_file)) + +def set_logger(): + if os.path.exists(logging_file): + if os.path.exists(logging_file_bu): + os.unlink(logging_file_bu) + os.rename(logging_file, logging_file_bu) + hdlr = logging.FileHandler(logging_file) + formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', datefmt = '%Y-%m-%d %H:%M:%S') + hdlr.setFormatter(formatter) + logger.addHandler(hdlr) + logger.setLevel(logging.INFO) def start_master_daemon_func(): - register_socket(master_daemon.tag) - server = SimpleJSONRPCServer(('0.0.0.0', master_daemon.port)) - print('Started master daemon (port %s)' % master_daemon.port) - server.register_function(add) - server.register_function(check_connectivity) - server.register_function(get_trex_path) - server.register_function(update_trex) - # trex_daemon_server - server.register_function(trex_daemon_server.is_running, 'is_trex_daemon_running') - server.register_function(trex_daemon_server.restart, 'restart_trex_daemon') - server.register_function(trex_daemon_server.start, 'start_trex_daemon') - server.register_function(trex_daemon_server.stop, 'stop_trex_daemon') - # stl rpc proxy - server.register_function(stl_rpc_proxy.is_running, 'is_stl_rpc_proxy_running') - server.register_function(stl_rpc_proxy.restart, 'restart_stl_rpc_proxy') - server.register_function(stl_rpc_proxy.start, 'start_stl_rpc_proxy') - server.register_function(stl_rpc_proxy.stop, 'stop_stl_rpc_proxy') - server.register_function(server.funcs.keys, 'get_methods') # should be last - server.serve_forever() + try: + set_logger() + register_socket(master_daemon.tag) + server = SimpleJSONRPCServer(('0.0.0.0', master_daemon.port)) + logger.info('Started master daemon (port %s)' % master_daemon.port) + server.register_function(add) + server.register_function(check_connectivity) + server.register_function(get_trex_path) + server.register_function(update_trex) + # trex_daemon_server + server.register_function(trex_daemon_server.is_running, 'is_trex_daemon_running') + server.register_function(trex_daemon_server.restart, 'restart_trex_daemon') + server.register_function(trex_daemon_server.start, 'start_trex_daemon') + server.register_function(trex_daemon_server.stop, 'stop_trex_daemon') + # stl rpc proxy + server.register_function(stl_rpc_proxy.is_running, 'is_stl_rpc_proxy_running') + server.register_function(stl_rpc_proxy.restart, 'restart_stl_rpc_proxy') + server.register_function(stl_rpc_proxy.start, 'start_stl_rpc_proxy') + server.register_function(stl_rpc_proxy.stop, 'stop_stl_rpc_proxy') + server.register_function(server.funcs.keys, 'get_methods') # should be last + signal.signal(signal.SIGTSTP, stop_handler) + signal.signal(signal.SIGTERM, stop_handler) + server.serve_forever() + except Exception as e: + logger.error('Closing due to error: %s' % e) +def stop_handler(*args, **kwargs): + logger.info('Got killed explicitly.') + sys.exit(0) # returns True if given path is under current dir or /tmp def _check_path_under_current_or_temp(path): @@ -170,8 +190,9 @@ stl_rpc_proxy = SingletonDaemon('Stateless RPC proxy', 'trex_stl_rpc_proxy' trex_daemon_server = SingletonDaemon('TRex daemon server', 'trex_daemon_server', args.trex_daemon_port, './trex_daemon_server start', args.trex_dir) master_daemon = SingletonDaemon('Master daemon', 'trex_master_daemon', args.master_port, start_master_daemon) # add ourself for easier check if running, kill etc. -daemons_by_name = {} tmp_dir = '/tmp/trex-tmp' +logging_file = '/var/log/trex/master_daemon.log' +logging_file_bu = '/var/log/trex/master_daemon.log_bu' if not _check_path_under_current_or_temp(args.trex_dir): raise Exception('Only allowed to use path under /tmp or current directory') @@ -182,6 +203,7 @@ if not os.path.exists(args.trex_dir): os.makedirs(args.trex_dir) os.chmod(args.trex_dir, 0o777) elif args.allow_update: + print('Due to allow updates flag, setting mode 777 on given directory') os.chmod(args.trex_dir, 0o777) if not os.path.exists(tmp_dir): -- cgit 1.2.3-korg From ca8b613f14121579d99ce8b7c994e5b87984d410 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Tue, 7 Jun 2016 15:16:13 +0300 Subject: fix wd issue, in some cases it can't exit with CTRL-C --- src/bp_sim.h | 8 ++++++++ src/main_dpdk.cpp | 18 ++++++++++++++++-- src/trex_watchdog.cpp | 49 ++++++++++++++++++++++++++++++++++++++----------- src/trex_watchdog.h | 12 +++++++----- 4 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/bp_sim.h b/src/bp_sim.h index d940080e..3c865eac 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -670,6 +670,14 @@ public: return (btGetMaskBit32(m_flags1,4,4) ? true:false); } + /* split mac is enabled */ + void setWDDisable(bool wd_disable){ + btSetMaskBit32(m_flags1,6,6,wd_disable?1:0); + } + + bool getWDDisable(){ + return (btGetMaskBit32(m_flags1,6,6) ? true:false); + } diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index c72af57a..90d08ab0 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -552,7 +552,8 @@ enum { OPT_HELP, OPT_VIRT_ONE_TX_RX_QUEUE, OPT_PREFIX, OPT_MAC_SPLIT, - OPT_SEND_DEBUG_PKT + OPT_SEND_DEBUG_PKT, + OPT_NO_WATCHDOG }; @@ -614,6 +615,7 @@ static CSimpleOpt::SOption parser_options[] = { OPT_MAC_SPLIT, "--mac-spread", SO_REQ_SEP }, { OPT_SEND_DEBUG_PKT, "--send-debug-pkt", SO_REQ_SEP }, { OPT_MBUF_FACTOR , "--mbuf-factor", SO_REQ_SEP }, + { OPT_NO_WATCHDOG , "--no-watchdog", SO_NONE }, SO_END_OF_OPTIONS @@ -715,6 +717,8 @@ static int usage(){ printf(" --mbuf-factor : factor for packet memory \n"); + printf(" --no-watchdog : disable watchdog \n"); + printf("\n simulation mode : \n"); printf(" Using this mode you can generate the traffic into a pcap file and learn how trex works \n"); printf(" With this version you must be SUDO to use this mode ( I know this is not normal ) \n"); @@ -936,6 +940,10 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t po->preview.set_1g_mode(true); break; + case OPT_NO_WATCHDOG : + po->preview.setWDDisable(true); + break; + case OPT_LATENCY_PREVIEW : sscanf(args.OptionArg(),"%d", &po->m_latency_prev); break; @@ -3849,6 +3857,7 @@ CGlobalTRex::handle_slow_path(bool &was_stopped) { if ( CGlobalInfo::m_options.preview.get_no_keyboard() ==false ) { if ( m_io_modes.handle_io_modes() ) { + printf(" CTRL -C ... \n"); was_stopped=true; return false; } @@ -4009,6 +4018,9 @@ int CGlobalTRex::run_in_master() { /* on exit release the lock */ cp_lock.unlock(); + /* first stop the WD */ + m_watchdog.stop(); + if (!is_all_cores_finished()) { /* probably CLTR-C */ try_stop_all_cores(); @@ -4016,7 +4028,6 @@ int CGlobalTRex::run_in_master() { m_mg.stop(); - m_watchdog.stop(); delay(1000); if ( was_stopped ){ @@ -4769,6 +4780,9 @@ int main_test(int argc , char * argv[]){ g_trex.reset_counters(); } + /* disable WD if needed */ + g_trex.m_watchdog.init(CGlobalInfo::m_options.preview.getWDDisable()?false:true); + /* this will give us all cores - master + tx + latency */ g_trex.m_watchdog.mark_pending_monitor(g_trex.m_max_cores); diff --git a/src/trex_watchdog.cpp b/src/trex_watchdog.cpp index e78e8e6d..b320a1b3 100644 --- a/src/trex_watchdog.cpp +++ b/src/trex_watchdog.cpp @@ -36,7 +36,6 @@ limitations under the License. #include #include -#define DISABLE_WATCHDOG_ON_GDB static TrexWatchDog::monitor_st *global_monitor; @@ -122,7 +121,20 @@ static void _callstack_signal_handler(int signr, siginfo_t *info, void *secret) throw std::runtime_error(ss.str()); } + +void TrexWatchDog::init(bool enable){ + m_enable =enable; + if (m_enable) { + register_signal(); + } +} + + void TrexWatchDog::mark_pending_monitor(int count) { + if (!m_enable){ + return; + } + std::unique_lock lock(m_lock); m_pending += count; lock.unlock(); @@ -130,6 +142,10 @@ void TrexWatchDog::mark_pending_monitor(int count) { void TrexWatchDog::block_on_pending(int max_block_time_ms) { + if (!m_enable){ + return; + } + int timeout_msec = max_block_time_ms; std::unique_lock lock(m_lock); @@ -163,8 +179,12 @@ void TrexWatchDog::block_on_pending(int max_block_time_ms) { * @return int */ int TrexWatchDog::register_monitor(const std::string &name, double timeout_sec) { + if (!m_enable){ + return 0; + } monitor_st monitor; + /* cannot add monitors while active */ assert(m_active == false); @@ -204,6 +224,10 @@ int TrexWatchDog::register_monitor(const std::string &name, double timeout_sec) * */ void TrexWatchDog::disable_monitor(int handle) { + if (!m_enable){ + return ; + } + assert(handle < m_monitors.size()); m_monitors[handle].active = false; @@ -214,7 +238,9 @@ void TrexWatchDog::disable_monitor(int handle) { * */ void TrexWatchDog::tickle(int handle) { - + if (!m_enable){ + return ; + } assert(handle < m_monitors.size()); /* not nesscary but write gets cache invalidate for nothing */ @@ -226,7 +252,6 @@ void TrexWatchDog::tickle(int handle) { } void TrexWatchDog::register_signal() { - /* do this once */ if (g_signal_init) { return; @@ -247,19 +272,15 @@ void TrexWatchDog::register_signal() { void TrexWatchDog::start() { + if (!m_enable){ + return ; + } + block_on_pending(); /* no pending monitors */ assert(m_pending == 0); - /* under GDB - disable the watchdog */ - #ifdef DISABLE_WATCHDOG_ON_GDB - if (ptrace(PTRACE_TRACEME, 0, NULL, 0) == -1) { - printf("\n\n*** GDB detected - disabling watchdog... ***\n\n"); - return; - } - #endif - m_active = true; m_thread = new std::thread(&TrexWatchDog::_main, this); if (!m_thread) { @@ -268,6 +289,10 @@ void TrexWatchDog::start() { } void TrexWatchDog::stop() { + if (!m_enable){ + return ; + } + m_active = false; if (m_thread) { @@ -285,6 +310,8 @@ void TrexWatchDog::stop() { */ void TrexWatchDog::_main() { + assert(m_enable==true); + /* reset all the monitors */ for (auto &monitor : m_monitors) { monitor.tickled = true; diff --git a/src/trex_watchdog.h b/src/trex_watchdog.h index 63255180..0c1969b1 100644 --- a/src/trex_watchdog.h +++ b/src/trex_watchdog.h @@ -37,10 +37,11 @@ public: m_thread = NULL; m_active = false; m_pending = 0; - - register_signal(); + m_enable = false; } + void init(bool enable); + /** * registering a monitor happens from another thread * this make sure that start will be able to block until @@ -119,16 +120,17 @@ public: /* for for a full cacheline */ uint8_t pad[15]; - }; + } __rte_cache_aligned ; private: void register_signal(); void _main(); + std::vector m_monitors __rte_cache_aligned; std::mutex m_lock; - + bool m_enable; volatile bool m_active; std::thread *m_thread; volatile int m_pending; @@ -136,6 +138,6 @@ private: static bool g_signal_init; }; -static_assert(sizeof(TrexWatchDog::monitor_st) >= RTE_CACHE_LINE_SIZE, "sizeof(monitor_st) != RTE_CACHE_LINE_SIZE" ); +static_assert(sizeof(TrexWatchDog::monitor_st) == RTE_CACHE_LINE_SIZE, "sizeof(monitor_st) != RTE_CACHE_LINE_SIZE" ); #endif /* __TREX_WATCHDOG_H__ */ -- cgit 1.2.3-korg From cacad4a8dbafca95b875f1eb619c229d4a7d604d Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Wed, 8 Jun 2016 11:23:07 +0300 Subject: regression: speedup stateless with --skip-clean flag --- scripts/automation/regression/stateful_tests/trex_general_test.py | 6 +++--- scripts/automation/regression/stateless_tests/stl_client_test.py | 2 ++ scripts/automation/regression/stateless_tests/stl_general_test.py | 3 ++- scripts/automation/regression/stateless_tests/stl_rx_test.py | 2 ++ scripts/automation/regression/trex.py | 1 + 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/automation/regression/stateful_tests/trex_general_test.py b/scripts/automation/regression/stateful_tests/trex_general_test.py index 86fe93e7..82b1d9d1 100755 --- a/scripts/automation/regression/stateful_tests/trex_general_test.py +++ b/scripts/automation/regression/stateful_tests/trex_general_test.py @@ -80,9 +80,9 @@ class CTRexGeneral_Test(unittest.TestCase): device_cfg.set_tftp_config(CTRexScenario.router_cfg['tftp_config_dict']) CTRexScenario.router.load_platform_data_from_file(device_cfg) CTRexScenario.router.launch_connection(device_cfg) - running_image = CTRexScenario.router.get_running_image_details()['image'] - print('Current router image: %s' % running_image) if CTRexScenario.router_cfg['forceImageReload']: + running_image = CTRexScenario.router.get_running_image_details()['image'] + print('Current router image: %s' % running_image) needed_image = device_cfg.get_image_name() if not CTRexScenario.router.is_image_matches(needed_image): print('Setting router image: %s' % needed_image) @@ -96,7 +96,7 @@ class CTRexGeneral_Test(unittest.TestCase): self.fail('Unable to set router image: %s, current image is: %s' % (needed_image, running_image)) else: print('Matches needed image: %s' % needed_image) - CTRexScenario.router_image = running_image + CTRexScenario.router_image = running_image if self.modes: print(termstyle.green('\t!!!\tRunning with modes: %s, not suitable tests will be skipped.\t!!!' % list(self.modes))) diff --git a/scripts/automation/regression/stateless_tests/stl_client_test.py b/scripts/automation/regression/stateless_tests/stl_client_test.py index c5e0c3c6..ed125cde 100644 --- a/scripts/automation/regression/stateless_tests/stl_client_test.py +++ b/scripts/automation/regression/stateless_tests/stl_client_test.py @@ -46,6 +46,8 @@ class STLClient_Test(CStlGeneral_Test): @classmethod def tearDownClass(cls): + if CTRexScenario.stl_init_error: + return # connect back at end of tests if not cls.is_connected(): CTRexScenario.stl_trex.connect() diff --git a/scripts/automation/regression/stateless_tests/stl_general_test.py b/scripts/automation/regression/stateless_tests/stl_general_test.py index 4ff1eec9..82738f96 100644 --- a/scripts/automation/regression/stateless_tests/stl_general_test.py +++ b/scripts/automation/regression/stateless_tests/stl_general_test.py @@ -85,7 +85,8 @@ class STLBasic_Test(CStlGeneral_Test): @nottest def test_connectivity(self): if not self.is_loopback: - CTRexScenario.router.load_clean_config() + if CTRexScenario.router_cfg['forceImageReload']: + CTRexScenario.router.load_clean_config() CTRexScenario.router.configure_basic_interfaces() CTRexScenario.router.config_pbr(mode = "config") diff --git a/scripts/automation/regression/stateless_tests/stl_rx_test.py b/scripts/automation/regression/stateless_tests/stl_rx_test.py index 9725e821..80e6bee6 100644 --- a/scripts/automation/regression/stateless_tests/stl_rx_test.py +++ b/scripts/automation/regression/stateless_tests/stl_rx_test.py @@ -41,6 +41,8 @@ class STLRX_Test(CStlGeneral_Test): @classmethod def tearDownClass(cls): + if CTRexScenario.stl_init_error: + return # connect back at end of tests if not cls.is_connected(): CTRexScenario.stl_trex.connect() diff --git a/scripts/automation/regression/trex.py b/scripts/automation/regression/trex.py index a0a1d42d..9541ad76 100644 --- a/scripts/automation/regression/trex.py +++ b/scripts/automation/regression/trex.py @@ -38,6 +38,7 @@ class CTRexScenario: is_copied = False GAManager = None no_daemon = False + router_image = None class CTRexRunner: """This is an instance for generating a CTRexRunner""" -- cgit 1.2.3-korg From b9b4b145d80c31208f7381a406cdada050c6a849 Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Wed, 8 Jun 2016 11:29:56 +0300 Subject: Fix for latency last period max --- src/time_histogram.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_histogram.cpp b/src/time_histogram.cpp index fefa59d6..b36fe164 100755 --- a/src/time_histogram.cpp +++ b/src/time_histogram.cpp @@ -60,13 +60,13 @@ bool CTimeHistogram::Add(dsec_t dt) { period_elem.inc_cnt(); period_elem.update_sum(dt); + period_elem.update_max(dt); // values smaller then certain threshold do not get into the histogram if (dt < m_min_delta) { return false; } period_elem.inc_high_cnt(); - period_elem.update_max(dt); uint32_t d_10usec = (uint32_t)(dt*100000.0); // 1 10-19 usec -- cgit 1.2.3-korg From e5ec923e6d837cc5e2d77b7ac93bd652d2563d92 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Wed, 8 Jun 2016 18:06:07 +0300 Subject: regression: fix representation of errors in setUpClass() --- scripts/automation/regression/trex_unit_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/automation/regression/trex_unit_test.py b/scripts/automation/regression/trex_unit_test.py index 83650164..c6aeee4d 100755 --- a/scripts/automation/regression/trex_unit_test.py +++ b/scripts/automation/regression/trex_unit_test.py @@ -48,6 +48,13 @@ import re import time from distutils.dir_util import mkpath +# override nose's strange representation of setUpClass errors +def __suite_repr__(self): + return "%s.%s" % (nose.suite._strclass(self.context), getattr(self.context, '__name__', self.context)) + +nose.suite.ContextSuite.__repr__ = __suite_repr__ +nose.suite.ContextSuite.__str__ = __suite_repr__ + def check_trex_path(trex_path): if os.path.isfile('%s/trex_daemon_server' % trex_path): return os.path.abspath(trex_path) -- cgit 1.2.3-korg From 07d5732a49bab856ab773e4a4762a7983cb5a538 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Thu, 9 Jun 2016 11:55:31 +0300 Subject: typo (GitHub pull request #14) --- scripts/automation/trex_control_plane/stl/trex_stl_lib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/__init__.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/__init__.py index ba9459c1..c6e14df3 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/__init__.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/__init__.py @@ -1,7 +1,7 @@ import sys if sys.version_info < (2, 7): - print("\n**** TRex STL pacakge requires Python version >= 2.7 ***\n") + print("\n**** TRex STL package requires Python version >= 2.7 ***\n") exit(-1) from . import trex_stl_ext -- cgit 1.2.3-korg From a78ab130e5e344989e2de9c62e061180416bae12 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Thu, 9 Jun 2016 19:42:50 +0300 Subject: fix TRex output not redirected --- scripts/automation/regression/trex_unit_test.py | 1 + .../server/trex_launch_thread.py | 88 +++++++++++----------- .../trex_control_plane/server/trex_server.py | 5 +- 3 files changed, 48 insertions(+), 46 deletions(-) diff --git a/scripts/automation/regression/trex_unit_test.py b/scripts/automation/regression/trex_unit_test.py index c6aeee4d..606556d3 100755 --- a/scripts/automation/regression/trex_unit_test.py +++ b/scripts/automation/regression/trex_unit_test.py @@ -209,6 +209,7 @@ class CTRexTestConfiguringPlugin(Plugin): if not res: print('Could not restart TRex daemon server') sys.exit(-1) + print('Restarted.') if self.kill_running: CTRexScenario.trex.kill_all_trexes() diff --git a/scripts/automation/trex_control_plane/server/trex_launch_thread.py b/scripts/automation/trex_control_plane/server/trex_launch_thread.py index 82a7f996..22606753 100755 --- a/scripts/automation/trex_control_plane/server/trex_launch_thread.py +++ b/scripts/automation/trex_control_plane/server/trex_launch_thread.py @@ -30,49 +30,51 @@ class AsynchronousTRexSession(threading.Thread): self.trexObj.zmq_dump = {} def run (self): - - with open(os.devnull, 'w') as DEVNULL: - self.time_stamps['start'] = self.time_stamps['run_time'] = time.time() - self.session = subprocess.Popen(shlex.split(self.cmd), cwd = self.launch_path, stdin = DEVNULL, stderr = subprocess.PIPE, preexec_fn=os.setsid, close_fds = True) - logger.info("TRex session initialized successfully, Parent process pid is {pid}.".format( pid = self.session.pid )) - while self.session.poll() is None: # subprocess is NOT finished - time.sleep(0.5) - if self.stoprequest.is_set(): - logger.debug("Abort request received by handling thread. Terminating TRex session." ) - os.killpg(self.session.pid, signal.SIGUSR1) - self.trexObj.set_status(TRexStatus.Idle) - self.trexObj.set_verbose_status("TRex is Idle") - break - - self.time_stamps['run_time'] = time.time() - self.time_stamps['start'] - - try: - if self.time_stamps['run_time'] < 5: - logger.error("TRex run failed due to wrong input parameters, or due to readability issues.") - self.trexObj.set_verbose_status("TRex run failed due to wrong input parameters, or due to readability issues.\n\nTRex command: {cmd}\n\nRun output:\n{output}".format( - cmd = self.cmd, output = self.load_trex_output(self.export_path))) - self.trexObj.errcode = -11 - elif (self.session.returncode is not None and self.session.returncode != 0) or ( (self.time_stamps['run_time'] < self.duration) and (not self.stoprequest.is_set()) ): - if (self.session.returncode is not None and self.session.returncode != 0): - logger.debug("Failed TRex run due to session return code ({ret_code})".format( ret_code = self.session.returncode ) ) - elif ( (self.time_stamps['run_time'] < self.duration) and not self.stoprequest.is_set()): - logger.debug("Failed TRex run due to running time ({runtime}) combined with no-stopping request.".format( runtime = self.time_stamps['run_time'] ) ) - - logger.warning("TRex run was terminated unexpectedly by outer process or by the hosting OS") - self.trexObj.set_verbose_status("TRex run was terminated unexpectedly by outer process or by the hosting OS.\n\nRun output:\n{output}".format( - output = self.load_trex_output(self.export_path))) - self.trexObj.errcode = -15 - else: - logger.info("TRex run session finished.") - self.trexObj.set_verbose_status('TRex finished.') - self.trexObj.errcode = None - - finally: - self.trexObj.set_status(TRexStatus.Idle) - logger.info("TRex running state changed to 'Idle'.") - self.trexObj.expect_trex.clear() - logger.debug("Finished handling a single run of TRex.") - self.trexObj.zmq_dump = None + try: + with open(self.export_path, 'w') as output_file: + self.time_stamps['start'] = self.time_stamps['run_time'] = time.time() + self.session = subprocess.Popen(shlex.split(self.cmd), cwd = self.launch_path, stdout = output_file, preexec_fn=os.setsid, close_fds = True) + logger.info("TRex session initialized successfully, Parent process pid is {pid}.".format( pid = self.session.pid )) + while self.session.poll() is None: # subprocess is NOT finished + time.sleep(0.5) + if self.stoprequest.is_set(): + logger.debug("Abort request received by handling thread. Terminating TRex session." ) + os.killpg(self.session.pid, signal.SIGUSR1) + self.trexObj.set_status(TRexStatus.Idle) + self.trexObj.set_verbose_status("TRex is Idle") + break + except Exception as e: + logger.error(e) + + self.time_stamps['run_time'] = time.time() - self.time_stamps['start'] + + try: + if self.time_stamps['run_time'] < 5: + logger.error("TRex run failed due to wrong input parameters, or due to readability issues.") + self.trexObj.set_verbose_status("TRex run failed due to wrong input parameters, or due to readability issues.\n\nTRex command: {cmd}\n\nRun output:\n{output}".format( + cmd = self.cmd, output = self.load_trex_output(self.export_path))) + self.trexObj.errcode = -11 + elif (self.session.returncode is not None and self.session.returncode != 0) or ( (self.time_stamps['run_time'] < self.duration) and (not self.stoprequest.is_set()) ): + if (self.session.returncode is not None and self.session.returncode != 0): + logger.debug("Failed TRex run due to session return code ({ret_code})".format( ret_code = self.session.returncode ) ) + elif ( (self.time_stamps['run_time'] < self.duration) and not self.stoprequest.is_set()): + logger.debug("Failed TRex run due to running time ({runtime}) combined with no-stopping request.".format( runtime = self.time_stamps['run_time'] ) ) + + logger.warning("TRex run was terminated unexpectedly by outer process or by the hosting OS") + self.trexObj.set_verbose_status("TRex run was terminated unexpectedly by outer process or by the hosting OS.\n\nRun output:\n{output}".format( + output = self.load_trex_output(self.export_path))) + self.trexObj.errcode = -15 + else: + logger.info("TRex run session finished.") + self.trexObj.set_verbose_status('TRex finished.') + self.trexObj.errcode = None + + finally: + self.trexObj.set_status(TRexStatus.Idle) + logger.info("TRex running state changed to 'Idle'.") + self.trexObj.expect_trex.clear() + logger.debug("Finished handling a single run of TRex.") + self.trexObj.zmq_dump = None def join (self, timeout = None): self.stoprequest.set() diff --git a/scripts/automation/trex_control_plane/server/trex_server.py b/scripts/automation/trex_control_plane/server/trex_server.py index 8f7e99f0..5e278a74 100755 --- a/scripts/automation/trex_control_plane/server/trex_server.py +++ b/scripts/automation/trex_control_plane/server/trex_server.py @@ -466,12 +466,11 @@ class CTRexServer(object): if 'd' not in kwargs: raise Exception('Argument -d should be specified in stateful command') - cmd = "{nice}{run_command} --iom {io} {cmd_options} --no-key > {export}".format( # -- iom 0 disables the periodic log to the screen (not needed) + cmd = "{nice}{run_command} --iom {io} {cmd_options} --no-key".format( # -- iom 0 disables the periodic log to the screen (not needed) nice = '' if self.trex_nice == 0 else 'nice -n %s ' % self.trex_nice, run_command = self.TREX_START_CMD, cmd_options = trex_cmd_options, - io = iom, - export = export_path ) + io = iom) logger.info("TREX FULL COMMAND: {command}".format(command = cmd) ) -- cgit 1.2.3-korg From 0dc80ee5d7888675db28902a52efacb69dbd3954 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Fri, 10 Jun 2016 00:50:41 +0300 Subject: master daemon logger fixes --- scripts/master_daemon.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/scripts/master_daemon.py b/scripts/master_daemon.py index 390db0a3..3f130bdb 100755 --- a/scripts/master_daemon.py +++ b/scripts/master_daemon.py @@ -12,13 +12,12 @@ from glob import glob import signal sys.path.append(os.path.join('automation', 'trex_control_plane', 'server')) +import CCustomLogger import outer_packages from singleton_daemon import SingletonDaemon, register_socket, run_command from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer import termstyle -logger = logging.getLogger('Master daemon') - ### Server functions ### def check_connectivity(): @@ -90,22 +89,21 @@ def start_master_daemon(): fail(termstyle.red('Master daemon failed to run. Please look in log: %s' % logging_file)) def set_logger(): + log_dir = os.path.dirname(logging_file) + if not os.path.exists(log_dir): + os.makedirs(log_dir) if os.path.exists(logging_file): if os.path.exists(logging_file_bu): os.unlink(logging_file_bu) os.rename(logging_file, logging_file_bu) - hdlr = logging.FileHandler(logging_file) - formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', datefmt = '%Y-%m-%d %H:%M:%S') - hdlr.setFormatter(formatter) - logger.addHandler(hdlr) - logger.setLevel(logging.INFO) + CCustomLogger.setup_daemon_logger('Master daemon', logging_file) def start_master_daemon_func(): try: set_logger() register_socket(master_daemon.tag) server = SimpleJSONRPCServer(('0.0.0.0', master_daemon.port)) - logger.info('Started master daemon (port %s)' % master_daemon.port) + logging.info('Started master daemon (port %s)' % master_daemon.port) server.register_function(add) server.register_function(check_connectivity) server.register_function(get_trex_path) @@ -125,10 +123,10 @@ def start_master_daemon_func(): signal.signal(signal.SIGTERM, stop_handler) server.serve_forever() except Exception as e: - logger.error('Closing due to error: %s' % e) + logging.error('Closing due to error: %s' % e) def stop_handler(*args, **kwargs): - logger.info('Got killed explicitly.') + logging.info('Got killed explicitly.') sys.exit(0) # returns True if given path is under current dir or /tmp -- cgit 1.2.3-korg From e56edd675d810d65e4e565561d83d39daa8354fb Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Tue, 14 Jun 2016 12:32:32 +0300 Subject: disable WD due to crash trex-210 --- src/main_dpdk.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 90d08ab0..7c66cf05 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -4781,7 +4781,8 @@ int main_test(int argc , char * argv[]){ } /* disable WD if needed */ - g_trex.m_watchdog.init(CGlobalInfo::m_options.preview.getWDDisable()?false:true); + //CGlobalInfo::m_options.preview.getWDDisable()?false:true + g_trex.m_watchdog.init(false); /* always disable - due to trex-211 /* this will give us all cores - master + tx + latency */ g_trex.m_watchdog.mark_pending_monitor(g_trex.m_max_cores); -- cgit 1.2.3-korg From 0681152c5dc0c7eda6ec23ccd903188156b4b38c Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Tue, 14 Jun 2016 12:38:08 +0300 Subject: add ef code, not connected yet --- src/common/ef/efence.cpp | 930 +++++++++++++++++++++++++++++++++++++++++++++++ src/common/ef/efence.h | 42 +++ src/common/ef/eftest.c | 219 +++++++++++ src/common/ef/page.cpp | 193 ++++++++++ src/common/ef/print.cpp | 170 +++++++++ src/common/ef/tstheap.c | 61 ++++ 6 files changed, 1615 insertions(+) create mode 100644 src/common/ef/efence.cpp create mode 100644 src/common/ef/efence.h create mode 100644 src/common/ef/eftest.c create mode 100644 src/common/ef/page.cpp create mode 100644 src/common/ef/print.cpp create mode 100644 src/common/ef/tstheap.c diff --git a/src/common/ef/efence.cpp b/src/common/ef/efence.cpp new file mode 100644 index 00000000..1340a12a --- /dev/null +++ b/src/common/ef/efence.cpp @@ -0,0 +1,930 @@ +/* + * Electric Fence - Red-Zone memory allocator. + * Bruce Perens, 1988, 1993 + * + * This is a special version of malloc() and company for debugging software + * that is suspected of overrunning or underrunning the boundaries of a + * malloc buffer, or touching free memory. + * + * It arranges for each malloc buffer to be followed (or preceded) + * in the address space by an inaccessable virtual memory page, + * and for free memory to be inaccessable. If software touches the + * inaccessable page, it will get an immediate segmentation + * fault. It is then trivial to uncover the offending code using a debugger. + * + * An advantage of this product over most malloc debuggers is that this one + * detects reading out of bounds as well as writing, and this one stops on + * the exact instruction that causes the error, rather than waiting until the + * next boundary check. + * + * There is one product that debugs malloc buffer overruns + * better than Electric Fence: "Purify" from Purify Systems, and that's only + * a small part of what Purify does. I'm not affiliated with Purify, I just + * respect a job well done. + * + * This version of malloc() should not be linked into production software, + * since it tremendously increases the time and memory overhead of malloc(). + * Each malloc buffer will consume a minimum of two virtual memory pages, + * this is 16 kilobytes on many systems. On some systems it will be necessary + * to increase the amount of swap space in order to debug large programs that + * perform lots of allocation, because of the per-buffer overhead. + */ +#include "efence.h" +#include +#include +#include +#include +#include +#include +#include + + +extern C_LINKAGE void * ef_malloc(size_t size); +extern C_LINKAGE void ef_free(void * address); +extern C_LINKAGE void * ef_memalign(size_t alignment, size_t userSize); +extern C_LINKAGE void * ef_calloc(size_t nelem, size_t elsize); +extern C_LINKAGE void * ef_valloc (size_t size); +extern C_LINKAGE void * ef_realloc(void * oldBuffer, size_t newSize); +extern C_LINKAGE void ef_init(void); + + + + + +#ifdef malloc +#undef malloc +#endif + +#ifdef calloc +#undef calloc +#endif + +static const char version[] = "\n Electric Fence 2.1" + " Copyright (C) 1987-1998 Bruce Perens.\n"; + +/* + * MEMORY_CREATION_SIZE is the amount of memory to get from the operating + * system at one time. We'll break that memory down into smaller pieces for + * malloc buffers. One megabyte is probably a good value. + */ +#define MEMORY_CREATION_SIZE 10* 1024 * 1024 + +/* + * Enum Mode indicates the status of a malloc buffer. + */ +enum _Mode { + NOT_IN_USE = 0, /* Available to represent a malloc buffer. */ + FREE, /* A free buffer. */ + ALLOCATED, /* A buffer that is in use. */ + PROTECTED, /* A freed buffer that can not be allocated again. */ + INTERNAL_USE /* A buffer used internally by malloc(). */ +}; +typedef enum _Mode Mode; + +/* + * Struct Slot contains all of the information about a malloc buffer except + * for the contents of its memory. + */ +struct _Slot { + void * userAddress; + void * internalAddress; + size_t userSize; + size_t internalSize; + Mode mode; +}; +typedef struct _Slot Slot; + + /* + * EF_DISABLE_BANNER is a global variable used to control whether + * Electric Fence prints its usual startup message. If the value is + * -1, it will be set from the environment default to 0 at run time. + */ +int EF_DISABLE_BANNER = 1; + + +/* + * EF_ALIGNMENT is a global variable used to control the default alignment + * of buffers returned by malloc(), calloc(), and realloc(). It is all-caps + * so that its name matches the name of the environment variable that is used + * to set it. This gives the programmer one less name to remember. + * If the value is -1, it will be set from the environment or sizeof(int) + * at run time. + */ +int EF_ALIGNMENT = 8; + +/* + * EF_PROTECT_FREE is a global variable used to control the disposition of + * memory that is released using free(). It is all-caps so that its name + * matches the name of the environment variable that is used to set it. + * If its value is greater non-zero, memory released by free is made + * inaccessable and never allocated again. Any software that touches free + * memory will then get a segmentation fault. If its value is zero, freed + * memory will be available for reallocation, but will still be inaccessable + * until it is reallocated. + * If the value is -1, it will be set from the environment or to 0 at run-time. + */ +int EF_PROTECT_FREE = -1; + +/* + * EF_PROTECT_BELOW is used to modify the behavior of the allocator. When + * its value is non-zero, the allocator will place an inaccessable page + * immediately _before_ the malloc buffer in the address space, instead + * of _after_ it. Use this to detect malloc buffer under-runs, rather than + * over-runs. It won't detect both at the same time, so you should test your + * software twice, once with this value clear, and once with it set. + * If the value is -1, it will be set from the environment or to zero at + * run-time + */ +int EF_PROTECT_BELOW = -1; + +/* + * EF_ALLOW_MALLOC_0 is set if Electric Fence is to allow malloc(0). I + * trap malloc(0) by default because it is a common source of bugs. + */ +int EF_ALLOW_MALLOC_0 = 0; + +/* + * EF_FREE_WIPES is set if Electric Fence is to wipe the memory content + * of freed blocks. This makes it easier to check if memory is freed or + * not + */ +int EF_FREE_WIPES = 1; + + +static int malloc_init =0; +/* + + * allocationList points to the array of slot structures used to manage the + * malloc arena. + */ +static Slot * allocationList = 0; + +/* + * allocationListSize is the size of the allocation list. This will always + * be a multiple of the page size. + */ +static size_t allocationListSize = 0; + +/* + * slotCount is the number of Slot structures in allocationList. + */ +static size_t slotCount = 0; + +/* + * unUsedSlots is the number of Slot structures that are currently available + * to represent new malloc buffers. When this number gets too low, we will + * create new slots. + */ +static size_t unUsedSlots = 0; + +/* + * slotsPerPage is the number of slot structures that fit in a virtual + * memory page. + */ +static size_t slotsPerPage = 0; + +/* + * internalUse is set when allocating and freeing the allocatior-internal + * data structures. + */ +static int internalUse = 0; + +/* + * noAllocationListProtection is set to tell malloc() and free() not to + * manipulate the protection of the allocation list. This is only set in + * realloc(), which does it to save on slow system calls, and in + * allocateMoreSlots(), which does it because it changes the allocation list. + */ +static int noAllocationListProtection = 0; + +/* + * bytesPerPage is set at run-time to the number of bytes per virtual-memory + * page, as returned by Page_Size(). + */ +static size_t bytesPerPage = 0; + + /* + * mutex to enable multithreaded operation + */ +static pthread_mutex_t mutex ; + + +static void lock() { + /* reentrant mutex -see init */ + pthread_mutex_lock(&mutex); +} + +static void unlock() { + pthread_mutex_unlock(&mutex); +} + + + +/* + * internalError is called for those "shouldn't happen" errors in the + * allocator. + */ +static void +internalError(void) +{ + EF_Abort("Internal error in allocator."); +} + +/* + * initialize sets up the memory allocation arena and the run-time + * configuration information. + */ +static void +initialize(void) +{ + size_t size = MEMORY_CREATION_SIZE; + size_t slack; + char * string; + Slot * slot; + + if ( EF_DISABLE_BANNER == -1 ) { + if ( (string = getenv("EF_DISABLE_BANNER")) != 0 ) + EF_DISABLE_BANNER = atoi(string); + else + EF_DISABLE_BANNER = 0; + } + + if ( EF_DISABLE_BANNER == 0 ) + EF_Print(version); + + /* + * Import the user's environment specification of the default + * alignment for malloc(). We want that alignment to be under + * user control, since smaller alignment lets us catch more bugs, + * however some software will break if malloc() returns a buffer + * that is not word-aligned. + * + * I would like + * alignment to be zero so that we could catch all one-byte + * overruns, however if malloc() is asked to allocate an odd-size + * buffer and returns an address that is not word-aligned, or whose + * size is not a multiple of the word size, software breaks. + * This was the case with the Sun string-handling routines, + * which can do word fetches up to three bytes beyond the end of a + * string. I handle this problem in part by providing + * byte-reference-only versions of the string library functions, but + * there are other functions that break, too. Some in X Windows, one + * in Sam Leffler's TIFF library, and doubtless many others. + */ + if ( EF_ALIGNMENT == -1 ) { + if ( (string = getenv("EF_ALIGNMENT")) != 0 ) + EF_ALIGNMENT = (size_t)atoi(string); + else + EF_ALIGNMENT = sizeof(int); + } + + /* + * See if the user wants to protect the address space below a buffer, + * rather than that above a buffer. + */ + if ( EF_PROTECT_BELOW == -1 ) { + if ( (string = getenv("EF_PROTECT_BELOW")) != 0 ) + EF_PROTECT_BELOW = (atoi(string) != 0); + else + EF_PROTECT_BELOW = 0; + } + + /* + * See if the user wants to protect memory that has been freed until + * the program exits, rather than until it is re-allocated. + */ + if ( EF_PROTECT_FREE == -1 ) { + if ( (string = getenv("EF_PROTECT_FREE")) != 0 ) + EF_PROTECT_FREE = (atoi(string) != 0); + else + EF_PROTECT_FREE = 0; + } + + /* + * See if the user wants to allow malloc(0). + */ + if ( EF_ALLOW_MALLOC_0 == -1 ) { + if ( (string = getenv("EF_ALLOW_MALLOC_0")) != 0 ) + EF_ALLOW_MALLOC_0 = (atoi(string) != 0); + else + EF_ALLOW_MALLOC_0 = 0; + } + + /* + * See if the user wants us to wipe out freed memory. + */ + if ( EF_FREE_WIPES == -1 ) { + if ( (string = getenv("EF_FREE_WIPES")) != 0 ) + EF_FREE_WIPES = (atoi(string) != 0); + else + EF_FREE_WIPES = 0; + } + + /* + * Get the run-time configuration of the virtual memory page size. + */ + bytesPerPage = Page_Size(); + + /* + * Figure out how many Slot structures to allocate at one time. + */ + slotCount = slotsPerPage = bytesPerPage / sizeof(Slot); + allocationListSize = bytesPerPage; + + if ( allocationListSize > size ) + size = allocationListSize; + + if ( (slack = size % bytesPerPage) != 0 ) + size += bytesPerPage - slack; + + /* + * Allocate memory, and break it up into two malloc buffers. The + * first buffer will be used for Slot structures, the second will + * be marked free. + */ + slot = allocationList = (Slot *)Page_Create(size); + memset((char *)allocationList, 0, allocationListSize); + + slot[0].internalSize = slot[0].userSize = allocationListSize; + slot[0].internalAddress = slot[0].userAddress = allocationList; + slot[0].mode = INTERNAL_USE; + if ( size > allocationListSize ) { + slot[1].internalAddress = slot[1].userAddress + = ((char *)slot[0].internalAddress) + slot[0].internalSize; + slot[1].internalSize + = slot[1].userSize = size - slot[0].internalSize; + slot[1].mode = FREE; + } + + /* + * Deny access to the free page, so that we will detect any software + * that treads upon free memory. + */ + Page_DenyAccess(slot[1].internalAddress, slot[1].internalSize); + + /* + * Account for the two slot structures that we've used. + */ + unUsedSlots = slotCount - 2; +} + +/* + * allocateMoreSlots is called when there are only enough slot structures + * left to support the allocation of a single malloc buffer. + */ +static void +allocateMoreSlots(void) +{ + size_t newSize = allocationListSize + bytesPerPage; + void * newAllocation; + void * oldAllocation = allocationList; + + Page_AllowAccess(allocationList, allocationListSize); + noAllocationListProtection = 1; + internalUse = 1; + + newAllocation = ef_malloc(newSize); + memcpy(newAllocation, allocationList, allocationListSize); + memset(&(((char *)newAllocation)[allocationListSize]), 0, bytesPerPage); + + allocationList = (Slot *)newAllocation; + allocationListSize = newSize; + slotCount += slotsPerPage; + unUsedSlots += slotsPerPage; + + ef_free(oldAllocation); + + /* + * Keep access to the allocation list open at this point, because + * I am returning to memalign(), which needs that access. + */ + noAllocationListProtection = 0; + internalUse = 0; +} + +/* + * This is the memory allocator. When asked to allocate a buffer, allocate + * it in such a way that the end of the buffer is followed by an inaccessable + * memory page. If software overruns that buffer, it will touch the bad page + * and get an immediate segmentation fault. It's then easy to zero in on the + * offending code with a debugger. + * + * There are a few complications. If the user asks for an odd-sized buffer, + * we would have to have that buffer start on an odd address if the byte after + * the end of the buffer was to be on the inaccessable page. Unfortunately, + * there is lots of software that asks for odd-sized buffers and then + * requires that the returned address be word-aligned, or the size of the + * buffer be a multiple of the word size. An example are the string-processing + * functions on Sun systems, which do word references to the string memory + * and may refer to memory up to three bytes beyond the end of the string. + * For this reason, I take the alignment requests to memalign() and valloc() + * seriously, and + * + * Electric Fence wastes lots of memory. I do a best-fit allocator here + * so that it won't waste even more. It's slow, but thrashing because your + * working set is too big for a system's RAM is even slower. + */ +extern C_LINKAGE void * +ef_memalign(size_t alignment, size_t userSize) +{ + register Slot * slot; + register size_t count; + Slot * fullSlot = 0; + Slot * emptySlots[2]; + size_t internalSize; + size_t slack; + char * address; + + + if ( userSize == 0 && !EF_ALLOW_MALLOC_0 ) + EF_Abort("Allocating 0 bytes, probably a bug."); + + /* + * If EF_PROTECT_BELOW is set, all addresses returned by malloc() + * and company will be page-aligned. + */ + if ( !EF_PROTECT_BELOW && alignment > 1 ) { + if ( (slack = userSize % alignment) != 0 ) + userSize += alignment - slack; + } + + /* + * The internal size of the buffer is rounded up to the next page-size + * boudary, and then we add another page's worth of memory for the + * dead page. + */ + internalSize = userSize + bytesPerPage; + if ( (slack = internalSize % bytesPerPage) != 0 ) + internalSize += bytesPerPage - slack; + + /* + * These will hold the addresses of two empty Slot structures, that + * can be used to hold information for any memory I create, and any + * memory that I mark free. + */ + emptySlots[0] = 0; + emptySlots[1] = 0; + + /* + * The internal memory used by the allocator is currently + * inaccessable, so that errant programs won't scrawl on the + * allocator's arena. I'll un-protect it here so that I can make + * a new allocation. I'll re-protect it before I return. + */ + if ( !noAllocationListProtection ) + Page_AllowAccess(allocationList, allocationListSize); + + /* + * If I'm running out of empty slots, create some more before + * I don't have enough slots left to make an allocation. + */ + if ( !internalUse && unUsedSlots < 7 ) { + allocateMoreSlots(); + } + + /* + * Iterate through all of the slot structures. Attempt to find a slot + * containing free memory of the exact right size. Accept a slot with + * more memory than we want, if the exact right size is not available. + * Find two slot structures that are not in use. We will need one if + * we split a buffer into free and allocated parts, and the second if + * we have to create new memory and mark it as free. + * + */ + + for ( slot = allocationList, count = slotCount ; count > 0; count-- ) { + if ( slot->mode == FREE + && slot->internalSize >= internalSize ) { + if ( !fullSlot + ||slot->internalSize < fullSlot->internalSize){ + fullSlot = slot; + if ( slot->internalSize == internalSize + && emptySlots[0] ) + break; /* All done, */ + } + } + else if ( slot->mode == NOT_IN_USE ) { + if ( !emptySlots[0] ) + emptySlots[0] = slot; + else if ( !emptySlots[1] ) + emptySlots[1] = slot; + else if ( fullSlot + && fullSlot->internalSize == internalSize ) + break; /* All done. */ + } + slot++; + } + if ( !emptySlots[0] ) + internalError(); + + if ( !fullSlot ) { + /* + * I get here if I haven't been able to find a free buffer + * with all of the memory I need. I'll have to create more + * memory. I'll mark it all as free, and then split it into + * free and allocated portions later. + */ + size_t chunkSize = MEMORY_CREATION_SIZE; + + if ( !emptySlots[1] ) + internalError(); + + if ( chunkSize < internalSize ) + chunkSize = internalSize; + + if ( (slack = chunkSize % bytesPerPage) != 0 ) + chunkSize += bytesPerPage - slack; + + /* Use up one of the empty slots to make the full slot. */ + fullSlot = emptySlots[0]; + emptySlots[0] = emptySlots[1]; + fullSlot->internalAddress = Page_Create(chunkSize); + fullSlot->internalSize = chunkSize; + fullSlot->mode = FREE; + unUsedSlots--; + } + + /* + * If I'm allocating memory for the allocator's own data structures, + * mark it INTERNAL_USE so that no errant software will be able to + * free it. + */ + if ( internalUse ) + fullSlot->mode = INTERNAL_USE; + else + fullSlot->mode = ALLOCATED; + + /* + * If the buffer I've found is larger than I need, split it into + * an allocated buffer with the exact amount of memory I need, and + * a free buffer containing the surplus memory. + */ + if ( fullSlot->internalSize > internalSize ) { + emptySlots[0]->internalSize + = fullSlot->internalSize - internalSize; + emptySlots[0]->internalAddress + = ((char *)fullSlot->internalAddress) + internalSize; + emptySlots[0]->mode = FREE; + fullSlot->internalSize = internalSize; + unUsedSlots--; + } + + if ( !EF_PROTECT_BELOW ) { + /* + * Arrange the buffer so that it is followed by an inaccessable + * memory page. A buffer overrun that touches that page will + * cause a segmentation fault. + */ + address = (char *)fullSlot->internalAddress; + + /* Set up the "live" page. */ + if ( internalSize - bytesPerPage > 0 ) + Page_AllowAccess( + fullSlot->internalAddress + ,internalSize - bytesPerPage); + + address += internalSize - bytesPerPage; + + /* Set up the "dead" page. */ + Page_DenyAccess(address, bytesPerPage); + + /* Figure out what address to give the user. */ + address -= userSize; + } + else { /* EF_PROTECT_BELOW != 0 */ + /* + * Arrange the buffer so that it is preceded by an inaccessable + * memory page. A buffer underrun that touches that page will + * cause a segmentation fault. + */ + address = (char *)fullSlot->internalAddress; + + /* Set up the "dead" page. */ + Page_DenyAccess(address, bytesPerPage); + + address += bytesPerPage; + + /* Set up the "live" page. */ + if ( internalSize - bytesPerPage > 0 ) + Page_AllowAccess(address, internalSize - bytesPerPage); + } + + fullSlot->userAddress = address; + fullSlot->userSize = userSize; + + /* + * Make the pool's internal memory inaccessable, so that the program + * being debugged can't stomp on it. + */ + if ( !internalUse ) + Page_DenyAccess(allocationList, allocationListSize); + + return address; +} + +/* + * Find the slot structure for a user address. + */ +static Slot * +slotForUserAddress(void * address) +{ + register Slot * slot = allocationList; + register size_t count = slotCount; + + for ( ; count > 0; count-- ) { + if ( slot->userAddress == address ) + return slot; + slot++; + } + + return 0; +} + +/* + * Find the slot structure for an internal address. + */ +static Slot * +slotForInternalAddress(void * address) +{ + register Slot * slot = allocationList; + register size_t count = slotCount; + + for ( ; count > 0; count-- ) { + if ( slot->internalAddress == address ) + return slot; + slot++; + } + return 0; +} + +/* + * Given the internal address of a buffer, find the buffer immediately + * before that buffer in the address space. This is used by free() to + * coalesce two free buffers into one. + */ +static Slot * +slotForInternalAddressPreviousTo(void * address) +{ + register Slot * slot = allocationList; + register size_t count = slotCount; + + for ( ; count > 0; count-- ) { + if ( ((char *)slot->internalAddress) + + slot->internalSize == address ) + return slot; + slot++; + } + return 0; +} + +extern C_LINKAGE void +ef_free(void * address) +{ + Slot * slot; + Slot * previousSlot = 0; + Slot * nextSlot = 0; + + //printf(" ::free %p \n",address); + lock(); + + if ( address == 0 ) { + unlock(); + return; + } + + if ( allocationList == 0 ) + EF_Abort("free() called before first malloc()."); + + if ( !noAllocationListProtection ) + Page_AllowAccess(allocationList, allocationListSize); + + slot = slotForUserAddress(address); + + if ( !slot ) + EF_Abort("free(%a): address not from malloc().", address); + + if ( slot->mode != ALLOCATED ) { + if ( internalUse && slot->mode == INTERNAL_USE ) + /* Do nothing. */; + else { + EF_Abort( + "free(%a): freeing free memory." + ,address); + } + } + + if ( EF_PROTECT_FREE ) + slot->mode = PROTECTED; + else + slot->mode = FREE; + + if ( EF_FREE_WIPES ) + memset(slot->userAddress, 0xbd, slot->userSize); + + previousSlot = slotForInternalAddressPreviousTo(slot->internalAddress); + nextSlot = slotForInternalAddress( + ((char *)slot->internalAddress) + slot->internalSize); + + if ( previousSlot + && (previousSlot->mode == FREE || previousSlot->mode == PROTECTED) ) { + /* Coalesce previous slot with this one. */ + previousSlot->internalSize += slot->internalSize; + if ( EF_PROTECT_FREE ) + previousSlot->mode = PROTECTED; + + slot->internalAddress = slot->userAddress = 0; + slot->internalSize = slot->userSize = 0; + slot->mode = NOT_IN_USE; + slot = previousSlot; + unUsedSlots++; + } + if ( nextSlot + && (nextSlot->mode == FREE || nextSlot->mode == PROTECTED) ) { + /* Coalesce next slot with this one. */ + slot->internalSize += nextSlot->internalSize; + nextSlot->internalAddress = nextSlot->userAddress = 0; + nextSlot->internalSize = nextSlot->userSize = 0; + nextSlot->mode = NOT_IN_USE; + unUsedSlots++; + } + + slot->userAddress = slot->internalAddress; + slot->userSize = slot->internalSize; + + /* + * Free memory is _always_ set to deny access. When EF_PROTECT_FREE + * is true, free memory is never reallocated, so it remains access + * denied for the life of the process. When EF_PROTECT_FREE is false, + * the memory may be re-allocated, at which time access to it will be + * allowed again. + */ + Page_DenyAccess(slot->internalAddress, slot->internalSize); + + if ( !noAllocationListProtection ) + Page_DenyAccess(allocationList, allocationListSize); + + unlock(); +} + +extern C_LINKAGE void * +ef_realloc(void * oldBuffer, size_t newSize) +{ + void * newBuffer = ef_malloc(newSize); + + lock(); + + if ( oldBuffer ) { + size_t size; + Slot * slot; + + Page_AllowAccess(allocationList, allocationListSize); + noAllocationListProtection = 1; + + slot = slotForUserAddress(oldBuffer); + + if ( slot == 0 ) + EF_Abort( + "realloc(%a, %d): address not from malloc()." + ,oldBuffer + ,newSize); + + if ( newSize < (size = slot->userSize) ) + size = newSize; + + if ( size > 0 ) + memcpy(newBuffer, oldBuffer, size); + + ef_free(oldBuffer); + noAllocationListProtection = 0; + Page_DenyAccess(allocationList, allocationListSize); + + if ( size < newSize ) + memset(&(((char *)newBuffer)[size]), 0, newSize - size); + + /* Internal memory was re-protected in free() */ + } + unlock(); + + return newBuffer; +} + +extern C_LINKAGE void * +ef_malloc(size_t size) +{ + + if ( malloc_init == 0 ){ + ef_init(); + } + + + void *allocation; + + lock(); + allocation=ef_memalign(EF_ALIGNMENT, size); + + /* put 0xaa into the memset to find uninit issues */ + memset(allocation,0xaa,size); + #if 0 + int i; + uint8_t *p=(uint8_t *)allocation; + for (i=0; i +#include + +/* + * ef_number is the largest unsigned integer we'll need. On systems that + * support 64-bit pointers, this may be "unsigned long long". + */ +#if defined(USE_LONG_LONG) +typedef unsigned long long ef_number; +#else +typedef unsigned long ef_number; +#endif + +/* + * NBBY is the number of bits per byte. Some systems define it in + * . + */ +#ifndef NBBY +#define NBBY 8 +#endif + +/* + * This is used to declare functions with "C" linkage if we are compiling + * with C++ . + */ +#ifdef __cplusplus +#define C_LINKAGE "C" +#else +#define C_LINKAGE +#endif + +void Page_AllowAccess(void * address, size_t size); +void * Page_Create(size_t size); +void Page_Delete(void * address, size_t size); +void Page_DenyAccess(void * address, size_t size); +size_t Page_Size(void); + +void EF_Abort(const char * message, ...); +void EF_Exit(const char * message, ...); +void EF_Print(const char * message, ...); +void EF_Lock(); +void EF_UnLock(); diff --git a/src/common/ef/eftest.c b/src/common/ef/eftest.c new file mode 100644 index 00000000..372ac596 --- /dev/null +++ b/src/common/ef/eftest.c @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include +#include +#include "efence.h" + +/* + * Electric Fence confidence tests. + * Make sure all of the various functions of Electric Fence work correctly. + */ + +#ifndef PAGE_PROTECTION_VIOLATED_SIGNAL +#define PAGE_PROTECTION_VIOLATED_SIGNAL SIGSEGV +#endif + +struct diagnostic { + int (*test)(void); + int expectedStatus; + const char * explanation; +}; + +extern int EF_PROTECT_BELOW; +extern int EF_ALIGNMENT; + +static sigjmp_buf env; + +/* + * There is still too little standardization of the arguments and return + * type of signal handler functions. + */ +static +void +segmentationFaultHandler( +int signalNumber +#if ( defined(_AIX) ) +, ... +#endif +) + { + signal(PAGE_PROTECTION_VIOLATED_SIGNAL, SIG_DFL); + siglongjmp(env, 1); +} + +static int +gotSegmentationFault(int (*test)(void)) +{ + if ( sigsetjmp(env,1) == 0 ) { + int status; + + signal(PAGE_PROTECTION_VIOLATED_SIGNAL + ,segmentationFaultHandler); + status = (*test)(); + signal(PAGE_PROTECTION_VIOLATED_SIGNAL, SIG_DFL); + return status; + } + else + return 1; +} + +static char * allocation; +/* c is global so that assignments to it won't be optimized out. */ +char c; + +static int +testSizes(void) +{ + /* + * If ef_number can't hold all of the bits of a void *, have the user + * add -DUSE_ LONG_LONG to the compiler flags so that ef_number will be + * declared as "unsigned long long" instead of "unsigned long". + */ + return ( sizeof(ef_number) < sizeof(void *) ); +} + +static int +allocateMemory(void) +{ + allocation = (char *)malloc(1); + + if ( allocation != 0 ) + return 0; + else + return 1; +} + +static int +freeMemory(void) +{ + free(allocation); + return 0; +} + +static int +protectBelow(void) +{ + EF_PROTECT_BELOW = 1; + return 0; +} + +static int +read0(void) +{ + c = *allocation; + + return 0; +} + +static int +write0(void) +{ + *allocation = 1; + + return 0; +} + +static int +read1(void) +{ + c = allocation[1]; + + return 0; +} + +static int +readMinus1(void) +{ + c = allocation[-1]; + return 0; +} + +static struct diagnostic diagnostics[] = { + { + testSizes, 0, + "Please add -DLONG_LONG to the compiler flags and recompile." + }, + { + allocateMemory, 0, + "Allocation 1: This test allocates a single byte of memory." + }, + { + read0, 0, + "Read valid memory 1: This test reads the allocated memory." + }, + { + write0, 0, + "Write valid memory 1: This test writes the allocated memory." + }, + { + read1, 1, + "Read overrun: This test reads beyond the end of the buffer." + }, + { + freeMemory, 0, + "Free memory: This test frees the allocated memory." + }, + { + protectBelow, 0, + "Protect below: This sets Electric Fence to protect\n" + "the lower boundary of a malloc buffer, rather than the\n" + "upper boundary." + }, + { + allocateMemory, 0, + "Allocation 2: This allocates memory with the lower boundary" + " protected." + }, + { + read0, 0, + "Read valid memory 2: This test reads the allocated memory." + }, + { + write0, 0, + "Write valid memory 2: This test writes the allocated memory." + }, + { + readMinus1, 1, + "Read underrun: This test reads before the beginning of the" + " buffer." + }, + { + 0, 0, 0 + } +}; + +static const char failedTest[] + = "Electric Fence confidence test failed.\n"; + +static const char newline = '\n'; + +int +main(int argc, char * * argv) +{ + static const struct diagnostic * diag = diagnostics; + + + EF_PROTECT_BELOW = 0; + EF_ALIGNMENT = 0; + + while ( diag->explanation != 0 ) { + int status = gotSegmentationFault(diag->test); + + if ( status != diag->expectedStatus ) { + /* + * Don't use stdio to print here, because stdio + * uses malloc() and we've just proven that malloc() + * is broken. Also, use _exit() instead of exit(), + * because _exit() doesn't flush stdio. + */ + write(2, failedTest, sizeof(failedTest) - 1); + write(2, diag->explanation, strlen(diag->explanation)); + write(2, &newline, 1); + _exit(-1); + } + diag++; + } + return 0; +} diff --git a/src/common/ef/page.cpp b/src/common/ef/page.cpp new file mode 100644 index 00000000..8a5a8f1c --- /dev/null +++ b/src/common/ef/page.cpp @@ -0,0 +1,193 @@ +#include "efence.h" +#include +#include +#include +#include +#include +#include +#include + +/* + * Lots of systems are missing the definition of PROT_NONE. + */ +#ifndef PROT_NONE +#define PROT_NONE 0 +#endif + +/* + * 386 BSD has MAP_ANON instead of MAP_ANONYMOUS. + */ +#if ( !defined(MAP_ANONYMOUS) && defined(MAP_ANON) ) +#define MAP_ANONYMOUS MAP_ANON +#endif + +/* + * For some reason, I can't find mprotect() in any of the headers on + * IRIX or SunOS 4.1.2 + */ +/* extern C_LINKAGE int mprotect(void * addr, size_t len, int prot); */ + + + +//#ifdef _64BIT_PLATFORM + static caddr_t startAddr = (caddr_t) 0xc00000000000; +//#else + //static caddr_t startAddr = (caddr_t) 0; +//#endif + + +#if ( !defined(sgi) && !defined(_AIX) ) +extern int sys_nerr; +/*extern char * sys_errlist[];*/ +#endif + +static const char * +stringErrorReport(void) +{ +#if ( defined(sgi) ) + return strerror(oserror()); +#elif ( defined(_AIX) ) + return strerror(errno); +#else + //if ( errno > 0 && errno < sys_nerr ) + return "Unknown error.\n"; + //return sys_errlist[errno]; + //else + //return "Unknown error.\n"; +#endif +} + +/* + * Create memory. + */ +#if defined(MAP_ANONYMOUS) +void * +Page_Create(size_t size) +{ + caddr_t allocation; + + /* + * In this version, "startAddr" is a _hint_, not a demand. + * When the memory I map here is contiguous with other + * mappings, the allocator can coalesce the memory from two + * or more mappings into one large contiguous chunk, and thus + * might be able to find a fit that would not otherwise have + * been possible. I could _force_ it to be contiguous by using + * the MMAP_FIXED flag, but I don't want to stomp on memory mappings + * generated by other software, etc. + */ + allocation = (caddr_t) mmap( + startAddr + ,size + ,PROT_READ|PROT_WRITE + ,MAP_PRIVATE|MAP_ANONYMOUS + ,-1 + ,0); + +#ifndef __hpux + /* + * Set the "address hint" for the next mmap() so that it will abut + * the mapping we just created. + * + * HP/UX 9.01 has a kernel bug that makes mmap() fail sometimes + * when given a non-zero address hint, so we'll leave the hint set + * to zero on that system. HP recently told me this is now fixed. + * Someone please tell me when it is probable to assume that most + * of those systems that were running 9.01 have been upgraded. + */ + startAddr = allocation + size; +#endif + + if ( allocation == (caddr_t)-1 ) + EF_Exit("mmap() failed: %s", stringErrorReport()); + + return (void *)allocation; +} +#else +void * +Page_Create(size_t size) +{ + static int devZeroFd = -1; + caddr_t allocation; + + if ( devZeroFd == -1 ) { + devZeroFd = open("/dev/zero", O_RDWR); + if ( devZeroFd < 0 ) + EF_Exit( + "open() on /dev/zero failed: %s" + ,stringErrorReport()); + } + + /* + * In this version, "startAddr" is a _hint_, not a demand. + * When the memory I map here is contiguous with other + * mappings, the allocator can coalesce the memory from two + * or more mappings into one large contiguous chunk, and thus + * might be able to find a fit that would not otherwise have + * been possible. I could _force_ it to be contiguous by using + * the MMAP_FIXED flag, but I don't want to stomp on memory mappings + * generated by other software, etc. + */ + allocation = (caddr_t) mmap( + startAddr + ,size + ,PROT_READ|PROT_WRITE + ,MAP_PRIVATE + ,devZeroFd + ,0); + + startAddr = allocation + size; + + if ( allocation == (caddr_t)-1 ) + EF_Exit("mmap() failed: %s", stringErrorReport()); + + return (void *)allocation; +} +#endif + +static void +mprotectFailed(void) +{ + EF_Exit("mprotect() failed: %s", stringErrorReport()); +} + +void +Page_AllowAccess(void * address, size_t size) +{ + if ( mprotect((caddr_t)address, size, PROT_READ|PROT_WRITE) < 0 ) + mprotectFailed(); +} + +void +Page_DenyAccess(void * address, size_t size) +{ + if ( mprotect((caddr_t)address, size, PROT_NONE) < 0 ) + mprotectFailed(); +} + +void +Page_Delete(void * address, size_t size) +{ + Page_DenyAccess(address, size); +} + +#if defined(_SC_PAGESIZE) +size_t +Page_Size(void) +{ + return (size_t)sysconf(_SC_PAGESIZE); +} +#elif defined(_SC_PAGE_SIZE) +size_t +Page_Size(void) +{ + return (size_t)sysconf(_SC_PAGE_SIZE); +} +#else +/* extern int getpagesize(); */ +size_t +Page_Size(void) +{ + return getpagesize(); +} +#endif diff --git a/src/common/ef/print.cpp b/src/common/ef/print.cpp new file mode 100644 index 00000000..c28189e5 --- /dev/null +++ b/src/common/ef/print.cpp @@ -0,0 +1,170 @@ +#include "efence.h" +#include +#include +#include +#include +#include + +/* + * These routines do their printing without using stdio. Stdio can't + * be used because it calls malloc(). Internal routines of a malloc() + * debugger should not re-enter malloc(), so stdio is out. + */ + +/* + * NUMBER_BUFFER_SIZE is the longest character string that could be needed + * to represent an unsigned integer, assuming we might print in base 2. + */ +#define NUMBER_BUFFER_SIZE (sizeof(ef_number) * NBBY) + +static void +printNumber(ef_number number, ef_number base) +{ + char buffer[NUMBER_BUFFER_SIZE]; + char * s = &buffer[NUMBER_BUFFER_SIZE]; + int size; + + do { + ef_number digit; + + if ( --s == buffer ) + EF_Abort("Internal error printing number."); + + digit = number % base; + + if ( digit < 10 ) + *s = '0' + digit; + else + *s = 'a' + digit - 10; + + } while ( (number /= base) > 0 ); + + size = &buffer[NUMBER_BUFFER_SIZE] - s; + + if ( size > 0 ) + write(2, s, size); +} + +static void +vprint(const char * pattern, va_list args) +{ + static const char bad_pattern[] = + "\nBad pattern specifier %%%c in EF_Print().\n"; + const char * s = pattern; + char c; + + while ( (c = *s++) != '\0' ) { + if ( c == '%' ) { + c = *s++; + switch ( c ) { + case '%': + (void) write(2, &c, 1); + break; + case 'a': + /* + * Print an address passed as a void pointer. + * The type of ef_number must be set so that + * it is large enough to contain all of the + * bits of a void pointer. + */ + printNumber( + (ef_number)va_arg(args, void *) + ,0x10); + break; + case 's': + { + const char * string; + size_t length; + + string = va_arg(args, char *); + length = strlen(string); + + (void) write(2, string, length); + } + break; + case 'd': + { + int n = va_arg(args, int); + + if ( n < 0 ) { + char c = '-'; + write(2, &c, 1); + n = -n; + } + printNumber(n, 10); + } + break; + case 'x': + printNumber(va_arg(args, u_int), 0x10); + break; + case 'c': + { /*Cast used, since char gets promoted to int in ... */ + char c = (char) va_arg(args, int); + + (void) write(2, &c, 1); + } + break; + default: + { + EF_Print(bad_pattern, c); + } + + } + } + else + (void) write(2, &c, 1); + } +} + +void +EF_Abort(const char * pattern, ...) +{ + va_list args; + + va_start(args, pattern); + + EF_Print("\nElectricFence Aborting: "); + vprint(pattern, args); + EF_Print("\n"); + + va_end(args); + + /* + * I use kill(getpid(), SIGILL) instead of abort() because some + * mis-guided implementations of abort() flush stdio, which can + * cause malloc() or free() to be called. + */ + kill(getpid(), SIGILL); + /* Just in case something handles SIGILL and returns, exit here. */ + _exit(-1); +} + +void +EF_Exit(const char * pattern, ...) +{ + va_list args; + + va_start(args, pattern); + + EF_Print("\nElectricFence Exiting: "); + vprint(pattern, args); + EF_Print("\n"); + + va_end(args); + + /* + * I use _exit() because the regular exit() flushes stdio, + * which may cause malloc() or free() to be called. + */ + _exit(-1); +} + +void +EF_Print(const char * pattern, ...) +{ + va_list args; + + va_start(args, pattern); + vprint(pattern, args); + va_end(args); +} diff --git a/src/common/ef/tstheap.c b/src/common/ef/tstheap.c new file mode 100644 index 00000000..c712fed5 --- /dev/null +++ b/src/common/ef/tstheap.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include "efence.h" + +/* + * This is a simple program to exercise the allocator. It allocates and frees + * memory in a pseudo-random fashion. It should run silently, using up time + * and resources on your system until you stop it or until it has gone + * through TEST_DURATION (or the argument) iterations of the loop. + */ + +extern C_LINKAGE double drand48(void); /* For pre-ANSI C systems */ + +#define POOL_SIZE 1024 +#define LARGEST_BUFFER 30000 +#define TEST_DURATION 1000000 + +void * pool[POOL_SIZE]; + +#ifdef FAKE_DRAND48 +/* + * Add -DFAKE_DRAND48 to your compile flags if your system doesn't + * provide drand48(). + */ + +#ifndef ULONG_MAX +#define ULONG_MAX ~(1L) +#endif + +double +drand48(void) +{ + return (random() / (double)ULONG_MAX); +} +#endif + +int +main(int argc, char * * argv) +{ + int count = 0; + int duration = TEST_DURATION; + + if ( argc >= 2 ) + duration = atoi(argv[1]); + + for ( ; count < duration; count++ ) { + void * * element = &pool[(int)(drand48() * POOL_SIZE)]; + size_t size = (size_t)(drand48() * (LARGEST_BUFFER + 1)); + + if ( *element ) { + free( *element ); + *element = 0; + } + else if ( size > 0 ) { + *element = malloc(size); + } + } + return 0; +} -- cgit 1.2.3-korg From 73fdde4e6b2d67ae3587a7133975e41deb46e2fd Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Tue, 14 Jun 2016 13:06:21 +0300 Subject: fix typo --- src/main_dpdk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 7c66cf05..1c0f8c80 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -4782,7 +4782,7 @@ int main_test(int argc , char * argv[]){ /* disable WD if needed */ //CGlobalInfo::m_options.preview.getWDDisable()?false:true - g_trex.m_watchdog.init(false); /* always disable - due to trex-211 + g_trex.m_watchdog.init(false); /* always disable - due to trex-211 */ /* this will give us all cores - master + tx + latency */ g_trex.m_watchdog.mark_pending_monitor(g_trex.m_max_cores); -- cgit 1.2.3-korg From 5c659501dd4edad74b0763f656bdf3a12c905153 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Tue, 14 Jun 2016 13:06:38 +0300 Subject: add EF only to debug image in default --- linux_dpdk/ws_main.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py index a13c8fd7..462219f5 100755 --- a/linux_dpdk/ws_main.py +++ b/linux_dpdk/ws_main.py @@ -49,6 +49,7 @@ class SrcGroup: res='' for file in self.src_list: res= res + top+'/'+self.dir+'/'+file+' '; + return res; def __str__ (self): @@ -164,6 +165,15 @@ rpc_server_src = SrcGroup(dir='src/rpc-server/', ]) + +ef_src = SrcGroup(dir='src/common', + src_list=[ + 'ef/efence.cpp', + 'ef/page.cpp', + 'ef/print.cpp' + ]); + + # stateless code stateless_src = SrcGroup(dir='src/stateless/', src_list=['cp/trex_stream.cpp', @@ -698,6 +708,13 @@ def build_prog (bld, build_obj): #for obj in rte_libs: # bld.read_shlib( name=obj , paths=[top+rte_lib_path] ) + # add electric fence only for debug image + debug_file_list=''; + if not build_obj.isRelease (): + #debug + debug_file_list +=ef_src.file_list(top) + + bld.objects( features='c ', includes = dpdk_includes_path, @@ -713,7 +730,7 @@ def build_prog (bld, build_obj): linkflags = build_obj.get_link_flags() , lib=['pthread','dl', 'z'], use =[build_obj.get_dpdk_target(),'zmq'], - source = bp.file_list(top), + source = bp.file_list(top) + debug_file_list, target = build_obj.get_target()) -- cgit 1.2.3-korg From 661d54e1fa7c946757204ce364eb2e5312c5487f Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Tue, 14 Jun 2016 13:43:09 +0300 Subject: add some gdb scripts --- scripts/gdb_script.txt | 3 +++ scripts/gdb_script1.txt | 16 ++++++++++++++++ scripts/t-rex-64-debug-gdb-bt | 12 ++++++++++++ scripts/t-rex-64-debug-gdb-core | 12 ++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 scripts/gdb_script.txt create mode 100644 scripts/gdb_script1.txt create mode 100644 scripts/t-rex-64-debug-gdb-bt create mode 100644 scripts/t-rex-64-debug-gdb-core diff --git a/scripts/gdb_script.txt b/scripts/gdb_script.txt new file mode 100644 index 00000000..d6a7d22c --- /dev/null +++ b/scripts/gdb_script.txt @@ -0,0 +1,3 @@ +run +bt full + diff --git a/scripts/gdb_script1.txt b/scripts/gdb_script1.txt new file mode 100644 index 00000000..b6854743 --- /dev/null +++ b/scripts/gdb_script1.txt @@ -0,0 +1,16 @@ +run +set logging overwrite on +set logging file gdb.bt +set logging on +set pagination off +echo backtrace +bt +bt full +gcore +info registers +set logging off +quit + + + + diff --git a/scripts/t-rex-64-debug-gdb-bt b/scripts/t-rex-64-debug-gdb-bt new file mode 100644 index 00000000..2d64ce62 --- /dev/null +++ b/scripts/t-rex-64-debug-gdb-bt @@ -0,0 +1,12 @@ +#! /bin/bash +export LD_LIBRARY_PATH=`pwd` +/bin/gdb --batch --command=gdb_script1.txt --args ./_t-rex-64-debug $@ +RESULT=$? + +if [ $RESULT -ne 0 ]; then + exit $RESULT +fi + + + + diff --git a/scripts/t-rex-64-debug-gdb-core b/scripts/t-rex-64-debug-gdb-core new file mode 100644 index 00000000..cc790448 --- /dev/null +++ b/scripts/t-rex-64-debug-gdb-core @@ -0,0 +1,12 @@ +#! /bin/bash +export LD_LIBRARY_PATH=`pwd` +/bin/gdb ./_t-rex-64-debug $@ +RESULT=$? + +if [ $RESULT -ne 0 ]; then + exit $RESULT +fi + + + + -- cgit 1.2.3-korg From 14774ed2eabf8a6f218e8674a04ee7d8ce373d64 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Tue, 14 Jun 2016 13:46:59 +0300 Subject: add simple script for testing crash --- scripts/simple_start_server.py | 150 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 scripts/simple_start_server.py diff --git a/scripts/simple_start_server.py b/scripts/simple_start_server.py new file mode 100644 index 00000000..2a3908cb --- /dev/null +++ b/scripts/simple_start_server.py @@ -0,0 +1,150 @@ +#!/usr/bin/python +import os +import sys +from time import time, sleep +import shlex +import threading +import subprocess +import multiprocessing +import tempfile +import fnmatch + + +sys.path.append('automation/trex_control_plane/stl') +from trex_stl_lib.api import * + +def run_server(command): + return subprocess.Popen(shlex.split(command), stdout = subprocess.PIPE, stderr = subprocess.PIPE, close_fds = True) + + +def run_command(command, timeout = 15, cwd = None): + # pipes might stuck, even with timeout + with tempfile.TemporaryFile() as stdout_file, tempfile.TemporaryFile() as stderr_file: + proc = subprocess.Popen(shlex.split(command), stdout = stdout_file, stderr = stderr_file, cwd = cwd, close_fds = True) + if timeout > 0: + poll_rate = 0.1 + for i in range(int(timeout/poll_rate)): + sleep(poll_rate) + if proc.poll() is not None: # process stopped + break + if proc.poll() is None: + proc.kill() # timeout + return (errno.ETIME, '', 'Timeout on running: %s' % command) + else: + proc.wait() + stdout_file.seek(0) + stderr_file.seek(0) + return (proc.returncode, stdout_file.read().decode(errors = 'replace'), stderr_file.read().decode(errors = 'replace')) + +def get_trex_cmds(): + ret_code, stdout, stderr = run_command('ps -u root --format pid,comm,cmd') + if ret_code: + raise Exception('Failed to determine running processes, stderr: %s' % stderr) + trex_cmds_list = [] + for line in stdout.splitlines(): + pid, proc_name, full_cmd = line.strip().split(' ', 2) + pid = pid.strip() + full_cmd = full_cmd.strip() + if proc_name.find('t-rex-64') >= 0: + trex_cmds_list.append((pid, full_cmd)) + else: + if full_cmd.find('t-rex-64') >= 0: + trex_cmds_list.append((pid, full_cmd)) + + return trex_cmds_list + +def is_any_core (): + ret_code, stdout, stderr = run_command('ls') + assert(ret_code==0); + l= stdout.split() + for file in l: + if fnmatch.fnmatch(file, 'core.*'): + return True + return False + + +def kill_all_trexes(): + trex_cmds_list = get_trex_cmds() + if not trex_cmds_list: + return False + for pid, cmd in trex_cmds_list: + run_command('kill %s' % pid) + ret_code_ps, _, _ = run_command('ps -p %s' % pid) + if not ret_code_ps: + run_command('kill -9 %s' % pid) + ret_code_ps, _, _ = run_command('ps -p %s' % pid) + if not ret_code_ps: + pass; + return True + +def term_all_trexes(): + trex_cmds_list = get_trex_cmds() + if not trex_cmds_list: + return False + for pid, cmd in trex_cmds_list: + print pid + run_command('kill -INT %s' % pid) + return True + + + +def run_one_iter (): + try: + server = run_server('./t-rex-64-debug-gdb-bt -i -c 4 --iom 0') + + print "sleep 1 sec" + time.sleep(1); + crash=True; + + if True: + c = STLClient() + print 'Connecting to server' + c.connect() + print 'Connected' + + print 'Mapping' + print 'Map: %s' % stl_map_ports(c) + c.disconnect() + crash=False; + + except Exception as e: + print(e) + finally : + if crash: + print "Crash seen, wait for the info" + # wait the process to make the core file + loop=0; + while True: + if server.poll() is not None: # server ended + print 'Server stopped.\nReturn code: %s\nStderr: %s\nStdout: %s' % (server.returncode, server.stdout.read().decode(errors = 'replace'), server.stderr.read().decode(errors = 'replace')) + break; + time.sleep(1); + loop=loop+1; + if loop >600: + print "Timeout on crash!!" + break; + return 1 + else: + print "kill process ",server.pid + term_all_trexes(); + kill_all_trexes(); + return 0 + + +def loop_inter (): + kill_all_trexes() + cnt=0; + while True: + + print (time.strftime("%H:%M:%S")), + print "Iter",cnt + ret=run_one_iter () + if ret==1: + break; + cnt=cnt+1; + if is_any_core (): + print "stop due to core file" + break; + +loop_inter () + -- cgit 1.2.3-korg From f10425988270f142de60ff02c61cb8d77b9ac03e Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Tue, 14 Jun 2016 18:12:00 +0300 Subject: coverity fixes --- src/bp_sim.cpp | 2 +- src/flow_stat.cpp | 8 +++++--- src/flow_stat.h | 2 +- src/latency.cpp | 14 ++------------ src/latency.h | 2 ++ 5 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index c9171ae5..78ae09d9 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -745,7 +745,7 @@ std::string double_to_human_str(double num, if (etype ==KBYE_1024){ f=1024.0; } - while ((abs_num > f ) && (i< max_cnt)){ + while ((abs_num > f ) && (i < max_cnt - 1)){ abs_num/=f; div*=f; i++; diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp index 98b9494b..71d3a74a 100644 --- a/src/flow_stat.cpp +++ b/src/flow_stat.cpp @@ -227,7 +227,7 @@ CFlowStatUserIdMap::add_user_id(uint32_t user_id, uint8_t proto) { << std::endl; #endif - CFlowStatUserIdInfo *new_id = new CFlowStatUserIdInfo(proto); + CFlowStatUserIdInfo *new_id; if (proto == PAYLOAD_RULE_PROTO) { new_id = new CFlowStatUserIdInfoPayload(proto); @@ -390,7 +390,8 @@ uint16_t CFlowStatUserIdMap::unmap(uint32_t user_id) { /************** class CFlowStatHwIdMap ***************/ CFlowStatHwIdMap::CFlowStatHwIdMap() { - m_map = NULL; + m_map = NULL; // must call create in order to work with the class + m_num_free = 0; // to make coverity happy, init this here too. } CFlowStatHwIdMap::~CFlowStatHwIdMap() { @@ -466,6 +467,7 @@ CFlowStatRuleMgr::CFlowStatRuleMgr() { m_hw_id_map_payload.create(MAX_FLOW_STATS_PAYLOAD); memset(m_rx_cant_count_err, 0, sizeof(m_rx_cant_count_err)); memset(m_tx_cant_count_err, 0, sizeof(m_tx_cant_count_err)); + m_num_ports = 0; // need to call create to init } CFlowStatRuleMgr::~CFlowStatRuleMgr() { @@ -480,7 +482,7 @@ void CFlowStatRuleMgr::create() { m_api = tstateless->get_platform_api(); assert(m_api); m_api->get_interface_stat_info(0, num_counters, cap); - m_api->get_port_num(m_num_ports); + m_api->get_port_num(m_num_ports); // This initialize m_num_ports for (uint8_t port = 0; port < m_num_ports; port++) { assert(m_api->reset_hw_flow_stats(port) == 0); } diff --git a/src/flow_stat.h b/src/flow_stat.h index 8671b228..eae484e7 100644 --- a/src/flow_stat.h +++ b/src/flow_stat.h @@ -472,7 +472,7 @@ class CFlowStatRuleMgr { const CRxCoreStateless *m_rx_core; int m_max_hw_id; // max hw id we ever used int m_max_hw_id_payload; // max hw id we ever used for payload rules - uint32_t m_num_started_streams; // How many started (transmitting) streams we have + int m_num_started_streams; // How many started (transmitting) streams we have CNodeRing *m_ring_to_rx; // handle for sending messages to Rx core CFlowStatParser *m_parser; uint16_t m_cap; // capabilities of the NIC driver we are using diff --git a/src/latency.cpp b/src/latency.cpp index acbe26d4..6e4ce643 100644 --- a/src/latency.cpp +++ b/src/latency.cpp @@ -338,9 +338,7 @@ bool CCPortLatency::dump_packet(rte_mbuf_t * m){ uint16_t pkt_size=rte_pktmbuf_pkt_len(m); utl_DumpBuffer(stdout,p,pkt_size,0); return (0); - - - +#if 0 if (pkt_size < ( sizeof(CRx_check_header)+14+20) ) { assert(0); } @@ -348,16 +346,8 @@ bool CCPortLatency::dump_packet(rte_mbuf_t * m){ lp->dump(stdout); - - uint16_t vlan_offset=0; - if ( unlikely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){ - vlan_offset=4; - } - - (void)vlan_offset; - -// utl_DumpBuffer(stdout,p,pkt_size,0); return (0); +#endif } diff --git a/src/latency.h b/src/latency.h index 2b74f737..6eddb3d7 100644 --- a/src/latency.h +++ b/src/latency.h @@ -85,6 +85,7 @@ public: CSimplePacketParser(rte_mbuf_t * m){ m_m=m; + m_l4 = NULL; } bool Parse(); @@ -269,6 +270,7 @@ public: CLatencyManagerCfg (){ m_max_ports=0; m_cps=0.0; + memset(m_ports, 0, sizeof(m_ports)); m_client_ip.v4=0x10000000; m_server_ip.v4=0x20000000; m_dual_port_mask=0x01000000; -- cgit 1.2.3-korg From 6824df7cf39cfaee127033f48cebf6de3f3e5b56 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Thu, 16 Jun 2016 15:45:20 +0300 Subject: fix python doc strings --- scripts/automation/trex_control_plane/doc_stl/conf.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/scripts/automation/trex_control_plane/doc_stl/conf.py b/scripts/automation/trex_control_plane/doc_stl/conf.py index 45738b6e..c8788ca7 100644 --- a/scripts/automation/trex_control_plane/doc_stl/conf.py +++ b/scripts/automation/trex_control_plane/doc_stl/conf.py @@ -15,6 +15,21 @@ import sys import os import shlex +import functools + +def no_op_wraps(func): + """Replaces functools.wraps in order to undo wrapping. + + Can be used to preserve the decorated function's signature + in the documentation generated by Sphinx. + + """ + def wrapper(decorator): + return func + return wrapper + +functools.wraps = no_op_wraps + # If extensions (or modules to document with autodoc) are in another directory, @@ -309,4 +324,5 @@ autoclass_content = "both" # A workaround for the responsive tables always having annoying scrollbars. def setup(app): - app.add_stylesheet("no_scrollbars.css") \ No newline at end of file + app.add_stylesheet("no_scrollbars.css") + -- cgit 1.2.3-korg From 9b4c1354cb97988983da217c85223e8d0479b4d5 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Fri, 17 Jun 2016 12:33:22 +0300 Subject: XL710/X710 include 4 byte CRC for port stats --- src/main_dpdk.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 1c0f8c80..b41d4f91 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -5494,10 +5494,10 @@ void CTRexExtendedDriverBase40G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFSta stats->ipackets = stats1.ipackets; - stats->ibytes = stats1.ibytes; + stats->ibytes = stats1.ibytes + (stats1.ipackets<<2); stats->opackets = stats1.opackets; - stats->obytes = stats1.obytes; + stats->obytes = stats1.obytes + (stats1.opackets<<2); stats->f_ipackets = 0; stats->f_ibytes = 0; -- cgit 1.2.3-korg From 3207f14a91cc01b44b28ba541e5968f58a7e5ec2 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Fri, 17 Jun 2016 15:39:00 +0300 Subject: add ctrl+c as first try to kill daemons/TRex. master daemon change directory to "/" to deal with case it's directory was deleted and update_trex() was used. remove check connection to daemons as part of init of client (can be done manually per needed daemon) --- .../trex_control_plane/server/singleton_daemon.py | 31 +++++----- .../trex_control_plane/server/trex_server.py | 19 ++---- .../stf/trex_stf_lib/trex_client.py | 67 +++++++++------------- scripts/master_daemon.py | 11 ++-- 4 files changed, 52 insertions(+), 76 deletions(-) diff --git a/scripts/automation/trex_control_plane/server/singleton_daemon.py b/scripts/automation/trex_control_plane/server/singleton_daemon.py index 8fdedc6e..79deace1 100755 --- a/scripts/automation/trex_control_plane/server/singleton_daemon.py +++ b/scripts/automation/trex_control_plane/server/singleton_daemon.py @@ -2,6 +2,7 @@ import errno import os import shlex import socket +import signal import tempfile import types from subprocess import Popen @@ -73,31 +74,27 @@ class SingletonDaemon(object): if pid: return pid - - # kill daemon - def kill(self, timeout = 10): - pid = self.get_pid() - if not pid: - return False - ret_code, stdout, stderr = run_command('kill %s' % pid) # usual kill - if ret_code: - raise Exception('Failed to run kill command for %s: %s' % (self.name, [ret_code, stdout, stderr])) + def kill_by_signal(self, pid, signal_name, timeout): + os.kill(pid, signal_name) poll_rate = 0.1 for i in range(int(timeout / poll_rate)): if not self.is_running(): return True sleep(poll_rate) - ret_code, stdout, stderr = run_command('kill -9 %s' % pid) # unconditional kill - if ret_code: - raise Exception('Failed to run kill -9 command for %s: %s' % (self.name, [ret_code, stdout, stderr])) - for i in range(int(timeout / poll_rate)): - if not self.is_running(): + + # kill daemon, with verification + def kill(self, timeout = 15): + pid = self.get_pid() + if not pid: + return False + # try Ctrl+C, usual kill, kill -9 + for signal_name in [signal.SIGINT, signal.SIGTERM, signal.SIGKILL]: + if self.kill_by_signal(pid, signal_name, timeout): return True - sleep(poll_rate) raise Exception('Could not kill %s, even with -9' % self.name) # try connection as RPC client, return True upon success, False if fail - def check_connectivity(self, timeout = 5): + def check_connectivity(self, timeout = 15): daemon = jsonrpclib.Server('http://127.0.0.1:%s/' % self.port) poll_rate = 0.1 for i in range(int(timeout/poll_rate)): @@ -140,7 +137,7 @@ class SingletonDaemon(object): raise Exception('%s failed to run.' % self.name) # restart the daemon - def restart(self, timeout = 5): + def restart(self, timeout = 15): if self.is_running(): self.kill(timeout) return self.start(timeout) diff --git a/scripts/automation/trex_control_plane/server/trex_server.py b/scripts/automation/trex_control_plane/server/trex_server.py index 5e278a74..3da629ec 100755 --- a/scripts/automation/trex_control_plane/server/trex_server.py +++ b/scripts/automation/trex_control_plane/server/trex_server.py @@ -387,23 +387,14 @@ class CTRexServer(object): return trex_cmds_list - def kill_all_trexes(self): + # Silently tries to kill TRexes with given signal. + # Responsibility of client to verify with get_trex_cmds. + def kill_all_trexes(self, signal_name): logger.info('Processing kill_all_trexes() command.') trex_cmds_list = self.get_trex_cmds() - if not trex_cmds_list: - return False for pid, cmd in trex_cmds_list: - logger.info('Killing process %s %s' % (pid, cmd)) - run_command('kill %s' % pid) - ret_code_ps, _, _ = run_command('ps -p %s' % pid) - if not ret_code_ps: - logger.info('Killing with -9.') - run_command('kill -9 %s' % pid) - ret_code_ps, _, _ = run_command('ps -p %s' % pid) - if not ret_code_ps: - logger.info('Could not kill process.') - raise Exception('Could not kill process %s %s' % (pid, cmd)) - return True + logger.info('Killing with signal %s process %s %s' % (signal_name, pid, cmd)) + os.kill(int(pid), signal_name) def wait_until_kickoff_finish (self, timeout = 40): diff --git a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py index 3b01560a..e1b298db 100755 --- a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py +++ b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py @@ -13,6 +13,7 @@ from distutils.util import strtobool from collections import deque, OrderedDict from json import JSONDecoder import traceback +import signal try: from . import outer_packages @@ -92,42 +93,9 @@ class CTRexClient(object): self.decoder = JSONDecoder() self.history = jsonrpclib.history.History() self.master_daemon_path = "http://{hostname}:{port}/".format( hostname = self.trex_host, port = master_daemon_port ) + self.master_daemon = jsonrpclib.Server(self.master_daemon_path, history = self.history) self.trex_server_path = "http://{hostname}:{port}/".format( hostname = self.trex_host, port = trex_daemon_port ) - self.connect_master() - self.connect_server() - - - def connect_master(self): - ''' - Connects to Master daemon via JsonRPC. - This daemon controls TRex daemon server. - Return true if success, false if fail - ''' - try: - print('Connecting to Master daemon @ %s ...' % self.master_daemon_path) - self.master_daemon = jsonrpclib.Server(self.master_daemon_path, history = self.history) - self.check_master_connectivity() - print('Connected to Master daemon.') - return True - except Exception as e: - print(e) - return False - - def connect_server(self): - ''' - Connects to TRex daemon server via JsonRPC. - This daemon controls TRex. (start/stop) - Return true if success, false if fail - ''' - try: - print('Connecting to TRex daemon server @ %s ...' % self.trex_server_path) - self.server = jsonrpclib.Server(self.trex_server_path, history = self.history) - self.check_server_connectivity() - print('Connected TRex server daemon.') - return True - except Exception as e: - print(e) - return False + self.server = jsonrpclib.Server(self.trex_server_path, history = self.history) def add (self, x, y): @@ -322,18 +290,28 @@ class CTRexClient(object): finally: self.prompt_verbose_data() - def kill_all_trexes(self): + def kill_all_trexes(self, timeout = 15): """ Kills running TRex processes (if exists) on the server, not only owned by current daemon. Raises exception upon error killing. :return: - + **True** if any process killed + + **True** if processes killed/not running + **False** otherwise. """ try: - return self.server.kill_all_trexes() + poll_rate = 0.1 + # try Ctrl+C, usual kill, -9 + for signal_name in [signal.SIGINT, signal.SIGTERM, signal.SIGKILL]: + self.server.kill_all_trexes(signal_name) + for i in range(int(timeout / poll_rate)): + if not self.get_trex_cmds(): + return True + sleep(poll_rate) + if self.get_trex_cmds(): + return False + return True except AppError as err: self._handle_AppError_exception(err.args[0]) finally: @@ -1518,8 +1496,15 @@ class CTRexResult(object): return result - - if __name__ == "__main__": - pass + c = CTRexClient('127.0.0.1') + print('restarting daemon') + c.restart_trex_daemon() + print('kill any running') + c.kill_all_trexes() + print('start') + c.start_stateless() + print('sleep') + time.sleep(5) + print('done') diff --git a/scripts/master_daemon.py b/scripts/master_daemon.py index 3f130bdb..e50d49ee 100755 --- a/scripts/master_daemon.py +++ b/scripts/master_daemon.py @@ -119,14 +119,16 @@ def start_master_daemon_func(): server.register_function(stl_rpc_proxy.start, 'start_stl_rpc_proxy') server.register_function(stl_rpc_proxy.stop, 'stop_stl_rpc_proxy') server.register_function(server.funcs.keys, 'get_methods') # should be last - signal.signal(signal.SIGTSTP, stop_handler) - signal.signal(signal.SIGTERM, stop_handler) + signal.signal(signal.SIGTSTP, stop_handler) # ctrl+z + signal.signal(signal.SIGTERM, stop_handler) # kill server.serve_forever() + except KeyboardInterrupt: + logging.info('Ctrl+C') except Exception as e: logging.error('Closing due to error: %s' % e) -def stop_handler(*args, **kwargs): - logging.info('Got killed explicitly.') +def stop_handler(signalnum, *args, **kwargs): + logging.info('Got signal %s, exiting.' % signalnum) sys.exit(0) # returns True if given path is under current dir or /tmp @@ -191,6 +193,7 @@ master_daemon = SingletonDaemon('Master daemon', 'trex_master_daemon', args tmp_dir = '/tmp/trex-tmp' logging_file = '/var/log/trex/master_daemon.log' logging_file_bu = '/var/log/trex/master_daemon.log_bu' +os.chdir('/') if not _check_path_under_current_or_temp(args.trex_dir): raise Exception('Only allowed to use path under /tmp or current directory') -- cgit 1.2.3-korg From d93a7ff83d3d29fc6c254dd56af235dbe7abacb3 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Fri, 17 Jun 2016 18:47:56 +0300 Subject: master_daemon: show better status of executed command --- .../trex_control_plane/server/singleton_daemon.py | 2 +- scripts/master_daemon.py | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/automation/trex_control_plane/server/singleton_daemon.py b/scripts/automation/trex_control_plane/server/singleton_daemon.py index 79deace1..1784cc42 100755 --- a/scripts/automation/trex_control_plane/server/singleton_daemon.py +++ b/scripts/automation/trex_control_plane/server/singleton_daemon.py @@ -86,7 +86,7 @@ class SingletonDaemon(object): def kill(self, timeout = 15): pid = self.get_pid() if not pid: - return False + raise Exception('%s is not running' % self.name) # try Ctrl+C, usual kill, kill -9 for signal_name in [signal.SIGINT, signal.SIGTERM, signal.SIGKILL]: if self.kill_by_signal(pid, signal_name, timeout): diff --git a/scripts/master_daemon.py b/scripts/master_daemon.py index e50d49ee..aa49f207 100755 --- a/scripts/master_daemon.py +++ b/scripts/master_daemon.py @@ -83,8 +83,7 @@ def start_master_daemon(): proc.start() for i in range(50): if master_daemon.is_running(): - print(termstyle.green('Master daemon is started.')) - os._exit(0) + return True sleep(0.1) fail(termstyle.red('Master daemon failed to run. Please look in log: %s' % logging_file)) @@ -226,9 +225,13 @@ if args.action != 'show': print(termstyle.red(e)) sys.exit(1) -# prints running status -if daemon.is_running(): - print(termstyle.green('%s is running' % daemon.name)) +passive = {'start': 'started', 'restart': 'restarted', 'stop': 'stopped', 'show': 'running'} + +if args.action in ('show', 'start', 'restart') and daemon.is_running() or \ + args.action == 'stop' and not daemon.is_running(): + print(termstyle.green('%s is %s' % (daemon.name, passive[args.action]))) + os._exit(0) else: - print(termstyle.red('%s is NOT running' % daemon.name)) + print(termstyle.red('%s is NOT %s' % (daemon.name, passive[args.action]))) + os._exit(-1) -- cgit 1.2.3-korg From df65f7b829c9520b8814d1540be4bbdd9670c1b5 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Sun, 19 Jun 2016 18:10:12 +0300 Subject: add advance cfg files --- scripts/cfg/trex_advanced_cfg-10g.yaml | 15 ++++++++++++++ scripts/cfg/trex_advanced_dont_use_x710-card1.yaml | 23 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 scripts/cfg/trex_advanced_cfg-10g.yaml create mode 100644 scripts/cfg/trex_advanced_dont_use_x710-card1.yaml diff --git a/scripts/cfg/trex_advanced_cfg-10g.yaml b/scripts/cfg/trex_advanced_cfg-10g.yaml new file mode 100644 index 00000000..d2ddfe15 --- /dev/null +++ b/scripts/cfg/trex_advanced_cfg-10g.yaml @@ -0,0 +1,15 @@ +- port_limit : 2 + version : 2 + #interfaces : ["04:00.0", "04:00.1", "06:00.0", "06:00.1"] # list of the interfaces to bind run ./dpdk_nic_bind.py --status + interfaces : ["04:00.0", "04:00.1"] # list of the interfaces to bind run ./dpdk_nic_bind.py --status + port_info : # set eh mac addr + prefix : setup1 + limit_memory : 1024 + port_info : # set eh mac addr + - dest_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x65] + src_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x64] + - dest_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x64] + src_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x65] + + + diff --git a/scripts/cfg/trex_advanced_dont_use_x710-card1.yaml b/scripts/cfg/trex_advanced_dont_use_x710-card1.yaml new file mode 100644 index 00000000..2a9f1c94 --- /dev/null +++ b/scripts/cfg/trex_advanced_dont_use_x710-card1.yaml @@ -0,0 +1,23 @@ +- port_limit : 2 + version : 2 + interfaces : ["06:00.0", "06:00.1"] + prefix : setup2 # WARNING,WARNING,WARNING DON'T USE THIS IF YOU DON'T KNOW WHAT YOU ARE DOING + limit_memory : 1024 # WARNING,WARNING,WARNING DON'T USE THIS IF YOU DON'T KNOW WHAT YOU ARE DOING + zmq_pub_port : 4510 # WARNING,WARNING,WARNING DON'T USE THIS IF YOU DON'T KNOW WHAT YOU ARE DOING + zmq_rpc_port : 4511 # WARNING,WARNING,WARNING DON'T USE THIS IF YOU DON'T KNOW WHAT YOU ARE DOING + port_info : # set eh mac addr + - dest_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x65] + src_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x64] + - dest_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x64] + src_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x65] + - dest_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x67] + src_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x66] + - dest_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x66] + src_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x67] + platform : + master_thread_id : 4 + latency_thread_id : 7 + dual_if : + - socket : 0 + threads : [5,6] + -- cgit 1.2.3-korg From fed15ec32feda1e79d69040834b5653047b96739 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Sun, 19 Jun 2016 18:10:25 +0300 Subject: update latency profile --- scripts/cfg/trex_advanced_cfg-10g.yaml | 4 ++-- scripts/stl/udp_1pkt_src_ip_split_latency.py | 15 ++++++++++++--- scripts/stl/udp_for_benchmarks.py | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/scripts/cfg/trex_advanced_cfg-10g.yaml b/scripts/cfg/trex_advanced_cfg-10g.yaml index d2ddfe15..4450bb5b 100644 --- a/scripts/cfg/trex_advanced_cfg-10g.yaml +++ b/scripts/cfg/trex_advanced_cfg-10g.yaml @@ -3,8 +3,8 @@ #interfaces : ["04:00.0", "04:00.1", "06:00.0", "06:00.1"] # list of the interfaces to bind run ./dpdk_nic_bind.py --status interfaces : ["04:00.0", "04:00.1"] # list of the interfaces to bind run ./dpdk_nic_bind.py --status port_info : # set eh mac addr - prefix : setup1 - limit_memory : 1024 + prefix : setup1 # WARNING,WARNING,WARNING DON'T USE THIS IF YOU DON'T KNOW WHAT YOU ARE DOING + limit_memory : 1024 # WARNING,WARNING,WARNING DON'T USE THIS IF YOU DON'T KNOW WHAT YOU ARE DOING port_info : # set eh mac addr - dest_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x65] src_mac : [0x00, 0xe0, 0xed, 0x5d, 0x84, 0x64] diff --git a/scripts/stl/udp_1pkt_src_ip_split_latency.py b/scripts/stl/udp_1pkt_src_ip_split_latency.py index af8d4cd7..2d81f756 100644 --- a/scripts/stl/udp_1pkt_src_ip_split_latency.py +++ b/scripts/stl/udp_1pkt_src_ip_split_latency.py @@ -2,11 +2,18 @@ from trex_stl_lib.api import * # split the range of IP to cores +# add tunable by fsize to change the size of the frame +# latency frame is always 64 +# trex>start -f stl/udp_1pkt_src_ip_split_latency.py -t fsize=64 -m 30% --port 0 --force # +# + class STLS1(object): def __init__ (self): self.fsize =64; + self.lfsize =64; + def create_stream (self, dir,port_id): # create a base packet and pad it to size @@ -22,6 +29,7 @@ class STLS1(object): base_pkt = Ether()/IP(src=src_ip,dst=dst_ip)/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' + pad_latency = max(0, (self.lfsize-4) - len(base_pkt)) * 'x' vm = STLScVmRaw( [ STLVmFlowVar ( "ip_src", min_value="10.0.0.1", max_value="10.0.0.255", size=4, step=1,op="inc"), @@ -39,8 +47,7 @@ class STLS1(object): # latency stream - STLStream(packet = STLPktBuilder(pkt = "yaml/udp_64B_no_crc.pcap", - path_relative_to_profile = True), + STLStream(packet = STLPktBuilder(pkt = base_pkt/pad_latency), mode = STLTXCont(pps=1000), flow_stats = STLFlowLatencyStats(pg_id = 12+port_id)) @@ -48,7 +55,9 @@ class STLS1(object): return stream - def get_streams (self, direction = 0, **kwargs): + def get_streams (self, direction = 0, fsize = 64,lfsize = 64, **kwargs): + self.fsize =fsize; + self.lfsize =lfsize return self.create_stream(direction,kwargs['port_id']) diff --git a/scripts/stl/udp_for_benchmarks.py b/scripts/stl/udp_for_benchmarks.py index 2033e80e..956498d0 100644 --- a/scripts/stl/udp_for_benchmarks.py +++ b/scripts/stl/udp_for_benchmarks.py @@ -1,5 +1,23 @@ from trex_stl_lib.api import * +# Tunable example +# +#trex>profile -f stl/udp_for_benchmarks.py +# +#Profile Information: +# +# +#General Information: +#Filename: stl/udp_for_benchmarks.py +#Stream count: 1 +# +#Specific Information: +#Type: Python Module +#Tunables: ['stream_count = 1', 'direction = 0', 'packet_len = 64'] +# +#trex>start -f stl/udp_for_benchmarks.py -t packet_len=128 --port 0 +# + class STLS1(object): ''' Generalization of udp_1pkt_simple, can specify number of streams and packet length -- cgit 1.2.3-korg From d49f3784270f142825fa4bd4ae96730401a2b871 Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Mon, 20 Jun 2016 10:58:10 +0300 Subject: better support for latency with field engine + some order with mbuf functions --- linux/ws_main.py | 2 + linux_dpdk/ws_main.py | 4 +- src/main_dpdk.cpp | 8 ++- src/pal/common/common_mbuf.cpp | 46 +++++++++++++++ src/pal/common/common_mbuf.h | 88 +++++++++++++++++++++++++++++ src/pal/linux/mbuf.cpp | 85 ++++++---------------------- src/pal/linux/mbuf.h | 65 ++++++++------------- src/pal/linux_dpdk/mbuf.cpp | 4 +- src/pal/linux_dpdk/mbuf.h | 57 ++----------------- src/stateless/dp/trex_stateless_dp_core.cpp | 35 ++++++------ 10 files changed, 209 insertions(+), 185 deletions(-) create mode 100644 src/pal/common/common_mbuf.cpp create mode 100644 src/pal/common/common_mbuf.h diff --git a/linux/ws_main.py b/linux/ws_main.py index 3aee05db..6dccf597 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -124,6 +124,7 @@ main_src = SrcGroup(dir='src', 'trex_watchdog.cpp', 'pal/linux/pal_utl.cpp', 'pal/linux/mbuf.cpp', + 'pal/common/common_mbuf.cpp', 'sim/trex_sim_stateless.cpp', 'sim/trex_sim_stateful.cpp' ]); @@ -254,6 +255,7 @@ cxxflags_base =['-DWIN_UCODE_SIM', includes_path =''' ../src/pal/linux/ + ../src/pal/common/ ../src/ ../src/rpc-server/ ../src/stateless/cp/ diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py index 462219f5..dde94dc4 100755 --- a/linux_dpdk/ws_main.py +++ b/linux_dpdk/ws_main.py @@ -119,7 +119,8 @@ main_src = SrcGroup(dir='src', 'msg_manager.cpp', 'publisher/trex_publisher.cpp', 'pal/linux_dpdk/pal_utl.cpp', - 'pal/linux_dpdk/mbuf.cpp' + 'pal/linux_dpdk/mbuf.cpp', + 'pal/common/common_mbuf.cpp' ]); cmn_src = SrcGroup(dir='src/common', @@ -430,6 +431,7 @@ common_flags_old = common_flags + [ includes_path =''' ../src/pal/linux_dpdk/ + ../src/pal/common/ ../src/ ../src/rpc-server/ diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index b41d4f91..b959895d 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -2115,8 +2115,12 @@ int CCoreEthIFStateless::send_node(CGenNode * no) { } if (unlikely(node_sl->is_stat_needed())) { - return send_node_flow_stat(m, node_sl, lp_port, lp_stats, - (node_sl->get_cache_mbuf() || node_sl->is_cache_mbuf_array())? true:false); + if ( unlikely(node_sl->is_cache_mbuf_array()) ) { + // No support for latency + cache. If user asks for cache on latency stream, we change cache to 0. + // assert here just to make sure. + assert(1); + } + return send_node_flow_stat(m, node_sl, lp_port, lp_stats, (node_sl->get_cache_mbuf()) ? true : false); } else { send_pkt(lp_port,m,lp_stats); } diff --git a/src/pal/common/common_mbuf.cpp b/src/pal/common/common_mbuf.cpp new file mode 100644 index 00000000..eba29418 --- /dev/null +++ b/src/pal/common/common_mbuf.cpp @@ -0,0 +1,46 @@ +/* +Copyright (c) 2016-2016 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include +#include +#include "common_mbuf.h" + +/* Dump structure of mbuf chain, without the data */ +void +utl_rte_pktmbuf_dump(const struct rte_mbuf *m) { + while (m) { + printf("(%d %d %d)", m->pkt_len, m->data_len, +#ifdef TREX_SIM + (int)m->refcnt_reserved); +#else + (int)m->refcnt_atomic.cnt); +#endif + if (RTE_MBUF_INDIRECT(m)) { +#ifdef TREX_SIM + struct rte_mbuf *md = RTE_MBUF_FROM_BADDR(m->buf_addr); +#else + struct rte_mbuf *md = rte_mbuf_from_indirect((struct rte_mbuf *)m); +#endif + printf("(direct %d %d %d)", md->pkt_len, md->data_len, +#ifdef TREX_SIM + (int)md->refcnt_reserved); +#else + (int)md->refcnt_atomic.cnt); +#endif + } + m = m->next; + } + printf("\n"); +} diff --git a/src/pal/common/common_mbuf.h b/src/pal/common/common_mbuf.h new file mode 100644 index 00000000..c52842bd --- /dev/null +++ b/src/pal/common/common_mbuf.h @@ -0,0 +1,88 @@ +#ifndef COMMON_MBUF_H +#define COMMON_MBUF_H + +/* +Copyright (c) 2016-2016 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +static inline rte_mbuf_t * utl_rte_pktmbuf_add_after2(rte_mbuf_t *m1,rte_mbuf_t *m2){ + utl_rte_pktmbuf_check(m1); + utl_rte_pktmbuf_check(m2); + + m1->next=m2; + m1->pkt_len += m2->data_len; + m1->nb_segs = m2->nb_segs + 1; + return (m1); +} + +static inline rte_mbuf_t * utl_rte_pktmbuf_add_after(rte_mbuf_t *m1,rte_mbuf_t *m2){ + + utl_rte_pktmbuf_check(m1); + utl_rte_pktmbuf_check(m2); + + rte_mbuf_refcnt_update(m2,1); + m1->next=m2; + m1->pkt_len += m2->data_len; + m1->nb_segs = m2->nb_segs + 1; + return (m1); +} + + +static inline void utl_rte_pktmbuf_add_last(rte_mbuf_t *m,rte_mbuf_t *m_last){ + + //there could be 2 cases supported + //1. one mbuf + //2. two mbug where last is indirect + + if ( m->next == NULL ) { + utl_rte_pktmbuf_add_after2(m,m_last); + }else{ + m->next->next=m_last; + m->pkt_len += m_last->data_len; + m->nb_segs = 3; + } +} + +// Create following m_buf structure: +// base -> indirect -> last +// Read only is the direct of indirect. +static inline rte_mbuf_t * utl_rte_pktmbuf_chain_with_indirect (rte_mbuf_t *base, rte_mbuf_t *indirect + , rte_mbuf_t *read_only, rte_mbuf_t *last) { + rte_pktmbuf_attach(indirect, read_only); + base->next = indirect; + indirect->next = last; + rte_pktmbuf_refcnt_update(read_only, -1); + base->nb_segs = 3; + indirect->nb_segs = 2; + last->nb_segs = 1; + return base; +} + +rte_mempool_t * utl_rte_mempool_create(const char *name, + unsigned n, + unsigned elt_size, + unsigned cache_size, + uint32_t _id , + int socket_id + ); + +rte_mempool_t * utl_rte_mempool_create_non_pkt(const char *name, + unsigned n, + unsigned elt_size, + unsigned cache_size, + uint32_t _id , + int socket_id); + +#endif diff --git a/src/pal/linux/mbuf.cpp b/src/pal/linux/mbuf.cpp index 846c776c..9f568e80 100755 --- a/src/pal/linux/mbuf.cpp +++ b/src/pal/linux/mbuf.cpp @@ -27,31 +27,12 @@ limitations under the License. #include "mbuf.h" #include -#include #include #include #include "sanb_atomic.h" - -#define RTE_MBUF_TO_BADDR(mb) (((struct rte_mbuf *)(mb)) + 1) -#define RTE_MBUF_FROM_BADDR(ba) (((struct rte_mbuf *)(ba)) - 1) - - void rte_pktmbuf_detach(struct rte_mbuf *m); - - -void utl_rte_check(rte_mempool_t * mp){ - assert(mp->magic == MAGIC0); - assert(mp->magic2 == MAGIC2); -} - -void utl_rte_pktmbuf_check(struct rte_mbuf *m){ - utl_rte_check(m->pool); - assert(m->magic == MAGIC0); - assert(m->magic2== MAGIC2); -} - rte_mempool_t * utl_rte_mempool_create_non_pkt(const char *name, unsigned n, unsigned elt_size, @@ -95,8 +76,9 @@ void utl_rte_mempool_delete(rte_mempool_t * & pool){ uint16_t rte_mbuf_refcnt_update(rte_mbuf_t *m, int16_t value) { utl_rte_pktmbuf_check(m); - uint32_t a=sanb_atomic_add_return_32_old(&m->refcnt_reserved, value); - return (a); + m->refcnt_reserved = (uint16_t)(m->refcnt_reserved + value); + assert(m->refcnt_reserved >= 0); + return m->refcnt_reserved; } @@ -109,7 +91,7 @@ void rte_pktmbuf_reset(struct rte_mbuf *m) m->pkt_len = 0; m->nb_segs = 1; m->in_port = 0xff; - m->refcnt_reserved=1; + m->ol_flags = 0; #if RTE_PKTMBUF_HEADROOM > 0 m->data_off = (RTE_PKTMBUF_HEADROOM <= m->buf_len) ? @@ -136,7 +118,7 @@ rte_mbuf_t *rte_pktmbuf_alloc(rte_mempool_t *mp){ m->magic = MAGIC0; m->magic2 = MAGIC2; m->pool = mp; - m->refcnt_reserved =0; + m->refcnt_reserved = 1; m->buf_len = buf_len; m->buf_addr =(char *)((char *)m+sizeof(rte_mbuf_t)+RTE_PKTMBUF_HEADROOM) ; @@ -146,28 +128,26 @@ rte_mbuf_t *rte_pktmbuf_alloc(rte_mempool_t *mp){ return (m); } - -void rte_pktmbuf_free_seg(rte_mbuf_t *m){ +void rte_pktmbuf_free_seg(rte_mbuf_t *m) { utl_rte_pktmbuf_check(m); - uint32_t old=sanb_atomic_dec2zero32(&m->refcnt_reserved); - if (old == 1) { - struct rte_mbuf *md = RTE_MBUF_FROM_BADDR(m->buf_addr); - if ( md != m ) { + if (rte_mbuf_refcnt_update(m, -1) == 0) { + /* if this is an indirect mbuf, then + * - detach mbuf + * - free attached mbuf segment + */ + + if (RTE_MBUF_INDIRECT(m)) { + struct rte_mbuf *md = RTE_MBUF_FROM_BADDR(m->buf_addr); rte_pktmbuf_detach(m); - if (rte_mbuf_refcnt_update(md, -1) == 0) { + if (rte_mbuf_refcnt_update(md, -1) == 0) free(md); - } - } - free(m); } } - - void rte_pktmbuf_free(rte_mbuf_t *m){ rte_mbuf_t *m_next; @@ -331,19 +311,6 @@ rte_pktmbuf_dump(const struct rte_mbuf *m, unsigned dump_len) } } - -rte_mbuf_t * utl_rte_pktmbuf_add_after2(rte_mbuf_t *m1,rte_mbuf_t *m2){ - utl_rte_pktmbuf_check(m1); - utl_rte_pktmbuf_check(m2); - - m1->next=m2; - m1->pkt_len += m2->data_len; - m1->nb_segs = m2->nb_segs + 1; - return (m1); -} - - - void rte_pktmbuf_attach(struct rte_mbuf *mi, struct rte_mbuf *md) { @@ -355,6 +322,7 @@ void rte_pktmbuf_attach(struct rte_mbuf *mi, struct rte_mbuf *md) mi->next = NULL; mi->data_len = md->data_len; mi->pkt_len = mi->data_len; + mi->ol_flags = mi->ol_flags | IND_ATTACHED_MBUF; mi->nb_segs = 1; } @@ -376,33 +344,14 @@ void rte_pktmbuf_detach(struct rte_mbuf *m) m->data_len = 0; + m->ol_flags = 0; } - - - - -rte_mbuf_t * utl_rte_pktmbuf_add_after(rte_mbuf_t *m1,rte_mbuf_t *m2){ - - utl_rte_pktmbuf_check(m1); - utl_rte_pktmbuf_check(m2); - - rte_mbuf_refcnt_update(m2,1); - m1->next=m2; - m1->pkt_len += m2->data_len; - m1->nb_segs = m2->nb_segs + 1; - return (m1); -} - - uint64_t rte_rand(void){ return ( rand() ); } - - - #ifdef ONLY_A_TEST diff --git a/src/pal/linux/mbuf.h b/src/pal/linux/mbuf.h index 174c757d..e7819148 100755 --- a/src/pal/linux/mbuf.h +++ b/src/pal/linux/mbuf.h @@ -24,10 +24,19 @@ limitations under the License. #include #include +#include + +typedef struct rte_mbuf rte_mbuf_t; #define MAGIC0 0xAABBCCDD #define MAGIC2 0x11223344 +#define IND_ATTACHED_MBUF (1ULL << 62) /**< Indirect attached mbuf */ +#define RTE_MBUF_INDIRECT(mb) ((mb)->ol_flags & IND_ATTACHED_MBUF) +#define RTE_MBUF_TO_BADDR(mb) (((struct rte_mbuf *)(mb)) + 1) +#define RTE_MBUF_FROM_BADDR(ba) (((struct rte_mbuf *)(ba)) - 1) + + struct rte_mempool { uint32_t magic; uint32_t elt_size; @@ -36,9 +45,6 @@ struct rte_mempool { int size; }; - - - struct rte_mbuf { uint32_t magic; struct rte_mempool *pool; /**< Pool from which mbuf was allocated. */ @@ -55,33 +61,16 @@ struct rte_mbuf { uint32_t pkt_len; /**< Total pkt len: sum of all segment data_len. */ uint32_t magic2; - uint32_t refcnt_reserved; /**< Do not use this field */ + uint16_t refcnt_reserved; + uint64_t ol_flags; /**< Offload features. */ } ; - -typedef struct rte_mbuf rte_mbuf_t; - typedef struct rte_mempool rte_mempool_t; #define RTE_PKTMBUF_HEADROOM 0 void utl_rte_mempool_delete(rte_mempool_t * &pool); -rte_mempool_t * utl_rte_mempool_create(const char *name, - unsigned n, - unsigned elt_size, - unsigned cache_size, - uint32_t _id , - int socket_id - ); - -rte_mempool_t * utl_rte_mempool_create_non_pkt(const char *name, - unsigned n, - unsigned elt_size, - unsigned cache_size, - uint32_t _id , - int socket_id); - inline unsigned rte_mempool_count(rte_mempool_t *mp){ return (10); } @@ -107,9 +96,6 @@ void rte_pktmbuf_free_seg(rte_mbuf_t *m); uint16_t rte_mbuf_refcnt_update(rte_mbuf_t *m, int16_t value); -rte_mbuf_t * utl_rte_pktmbuf_add_after(rte_mbuf_t *m1,rte_mbuf_t *m2); -rte_mbuf_t * utl_rte_pktmbuf_add_after2(rte_mbuf_t *m1,rte_mbuf_t *m2); - void rte_pktmbuf_dump(const struct rte_mbuf *m, unsigned dump_len); @@ -166,22 +152,6 @@ rte_lcore_to_socket_id(unsigned lcore_id){ uint64_t rte_rand(void); - -static inline void utl_rte_pktmbuf_add_last(rte_mbuf_t *m,rte_mbuf_t *m_last){ - - //there could be 2 cases supported - //1. one mbuf - //2. two mbug where last is indirect - - if ( m->next == NULL ) { - utl_rte_pktmbuf_add_after2(m,m_last); - }else{ - m->next->next=m_last; - m->pkt_len += m_last->data_len; - m->nb_segs = 3; - } -} - static inline void rte_pktmbuf_refcnt_update(struct rte_mbuf *m, int16_t v) { do { @@ -189,8 +159,16 @@ static inline void rte_pktmbuf_refcnt_update(struct rte_mbuf *m, int16_t v) } while ((m = m->next) != NULL); } +static inline void utl_rte_check(rte_mempool_t * mp){ + assert(mp->magic == MAGIC0); + assert(mp->magic2 == MAGIC2); +} - +static inline void utl_rte_pktmbuf_check(struct rte_mbuf *m){ + utl_rte_check(m->pool); + assert(m->magic == MAGIC0); + assert(m->magic2== MAGIC2); +} #define __rte_cache_aligned @@ -199,4 +177,7 @@ static inline void rte_pktmbuf_refcnt_update(struct rte_mbuf *m, int16_t v) #define RTE_CACHE_LINE_SIZE 64 #define SOCKET_ID_ANY 0 +// has to be after the definition of rte_mbuf and other utility functions +#include "common_mbuf.h" + #endif diff --git a/src/pal/linux_dpdk/mbuf.cpp b/src/pal/linux_dpdk/mbuf.cpp index dd78617f..2a405ab1 100755 --- a/src/pal/linux_dpdk/mbuf.cpp +++ b/src/pal/linux_dpdk/mbuf.cpp @@ -6,7 +6,7 @@ */ /* -Copyright (c) 2015-2015 Cisco Systems, Inc. +Copyright (c) 2015-2016 Cisco Systems, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ rte_mempool_t * utl_rte_mempool_create(const char *name, unsigned elt_size, unsigned cache_size, uint32_t _id, - uint32_t socket_id ){ + int socket_id ){ char buffer[100]; sprintf(buffer,"%s-%d",name,socket_id); diff --git a/src/pal/linux_dpdk/mbuf.h b/src/pal/linux_dpdk/mbuf.h index 339c0909..0d9ca8be 100755 --- a/src/pal/linux_dpdk/mbuf.h +++ b/src/pal/linux_dpdk/mbuf.h @@ -6,7 +6,7 @@ */ /* -Copyright (c) 2015-2015 Cisco Systems, Inc. +Copyright (c) 2015-2016 Cisco Systems, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,61 +27,12 @@ limitations under the License. #include typedef struct rte_mbuf rte_mbuf_t; - +inline void utl_rte_pktmbuf_check(struct rte_mbuf *m) {} typedef struct rte_mempool rte_mempool_t; -inline void utl_rte_mempool_delete(rte_mempool_t * & pool){ -} - - -rte_mempool_t * utl_rte_mempool_create(const char *name, - unsigned n, - unsigned elt_size, - unsigned cache_size, - uint32_t _id, - uint32_t socket_id ); +#include "common_mbuf.h" -rte_mempool_t * utl_rte_mempool_create_non_pkt(const char *name, - unsigned n, - unsigned elt_size, - unsigned cache_size, - uint32_t _id , - int socket_id); - - -static inline rte_mbuf_t * utl_rte_pktmbuf_add_after(rte_mbuf_t *m1,rte_mbuf_t *m2){ - - rte_mbuf_refcnt_update(m2,1); - m1->next=m2; - - m1->pkt_len += m2->data_len; - m1->nb_segs = m2->nb_segs + 1; - return (m1); -} - -static inline rte_mbuf_t * utl_rte_pktmbuf_add_after2(rte_mbuf_t *m1,rte_mbuf_t *m2){ - - m1->next=m2; - m1->pkt_len += m2->data_len; - m1->nb_segs = m2->nb_segs + 1; - return (m1); -} - -static inline void utl_rte_pktmbuf_add_last(rte_mbuf_t *m,rte_mbuf_t *m_last){ - - //there could be 2 cases supported - //1. one mbuf - //2. two mbug where last is indirect - - if ( m->next == NULL ) { - utl_rte_pktmbuf_add_after2(m,m_last); - }else{ - m->next->next=m_last; - m->pkt_len += m_last->data_len; - m->nb_segs = 3; - } +inline void utl_rte_mempool_delete(rte_mempool_t * & pool){ } - - #endif diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index fe78c5b2..58d8f21a 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -258,23 +258,20 @@ rte_mbuf_t * CGenNodeStateless::alloc_flow_stat_mbuf(rte_mbuf_t *m, struct flow_ fsp_head = (struct flow_stat_payload_header *)(p + rte_pktmbuf_data_len(m) - fsp_head_size); return m; } else { - // r/w --> read only. Should do something like: - // Alloc indirect,. make r/w->indirect point to read_only) -> new fsp_header - // for the mean time, just copy the entire packet. - m_ret = CGlobalInfo::pktmbuf_alloc( get_socket_id(), rte_pktmbuf_pkt_len(m) ); - assert(m_ret); - char *p_new = rte_pktmbuf_append(m_ret, rte_pktmbuf_pkt_len(m)); - rte_mbuf_t *m_free = m; - while (m != NULL) { - char *p = rte_pktmbuf_mtod(m, char*); - memcpy(p_new, p, m->data_len); - p_new += m->data_len; - m = m->next; - } - p_new = rte_pktmbuf_mtod(m_ret, char*); - fsp_head = (struct flow_stat_payload_header *)(p_new + rte_pktmbuf_data_len(m_ret) - fsp_head_size); - rte_pktmbuf_free(m_free); - return m_ret; + // We have: r/w --> read only. + // Changing to: + // (original) r/w -> (new) indirect (direct is original read_only, after trimming last bytes) -> (new) latency info + rte_mbuf_t *m_read_only = m->next, *m_indirect; + + m_indirect = CGlobalInfo::pktmbuf_alloc_small(get_socket_id()); + assert(m_indirect); + // alloc mbuf just for the latency header + m_lat = CGlobalInfo::pktmbuf_alloc( get_socket_id(), fsp_head_size); + assert(m_lat); + fsp_head = (struct flow_stat_payload_header *)rte_pktmbuf_append(m_lat, fsp_head_size); + utl_rte_pktmbuf_chain_with_indirect(m, m_indirect, m_read_only, m_lat); + m_indirect->data_len = (uint16_t)(m_indirect->data_len - fsp_head_size); + return m; } } } @@ -910,6 +907,10 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port, uint8_t hw_id = stream->m_rx_check.m_hw_id; assert (hw_id < MAX_FLOW_STATS + MAX_FLOW_STATS_PAYLOAD); node->set_stat_hw_id(hw_id); + // no support for cache with flow stat payload rules + if ((TrexPlatformApi::driver_stat_cap_e)stream->m_rx_check.m_rule_type == TrexPlatformApi::IF_STAT_PAYLOAD) { + stream->m_cache_size = 0; + } } /* set socket id */ -- cgit 1.2.3-korg From 1bc9c49fa89a3942d3d1516217635d0c6e6b0c56 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Mon, 20 Jun 2016 11:50:42 +0300 Subject: regression: fix nose represenation of errors in setUpModule --- scripts/automation/regression/trex_unit_test.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/automation/regression/trex_unit_test.py b/scripts/automation/regression/trex_unit_test.py index 606556d3..5eb9e222 100755 --- a/scripts/automation/regression/trex_unit_test.py +++ b/scripts/automation/regression/trex_unit_test.py @@ -50,7 +50,11 @@ from distutils.dir_util import mkpath # override nose's strange representation of setUpClass errors def __suite_repr__(self): - return "%s.%s" % (nose.suite._strclass(self.context), getattr(self.context, '__name__', self.context)) + if hasattr(self.context, '__module__'): # inside class, setUpClass etc. + class_repr = nose.suite._strclass(self.context) + else: # outside of class, setUpModule etc. + class_repr = nose.suite._strclass(self.__class__) + return '%s.%s' % (class_repr, getattr(self.context, '__name__', self.context)) nose.suite.ContextSuite.__repr__ = __suite_repr__ nose.suite.ContextSuite.__str__ = __suite_repr__ -- cgit 1.2.3-korg From 3ca8be805c26eddfe40c254bdca4e5ae71eee792 Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 19 Jun 2016 18:05:54 +0300 Subject: WATCHDOG - refactor due to trex-211 --- src/bp_gtest.cpp | 2 +- src/bp_sim.cpp | 3 - src/bp_sim.h | 7 +- src/latency.cpp | 19 +-- src/latency.h | 5 +- src/main_dpdk.cpp | 33 ++--- src/rpc-server/trex_rpc_req_resp_server.cpp | 7 +- src/rpc-server/trex_rpc_server.cpp | 3 - src/rpc-server/trex_rpc_server_api.h | 9 +- src/sim/trex_sim_stateless.cpp | 2 +- src/stateless/rx/trex_stateless_rx_core.cpp | 13 +- src/stateless/rx/trex_stateless_rx_core.h | 5 +- src/trex_watchdog.cpp | 209 +++++++++------------------- src/trex_watchdog.h | 183 ++++++++++++++++-------- 14 files changed, 234 insertions(+), 266 deletions(-) diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp index b36ac6e1..79ea2458 100755 --- a/src/bp_gtest.cpp +++ b/src/bp_gtest.cpp @@ -897,7 +897,7 @@ TEST_F(basic, latency3) { EXPECT_EQ_UINT32(mg.is_active()?1:0, (uint32_t)0)<< "pass"; - mg.start(8, NULL); + mg.start(8, false); mg.stop(); mg.Dump(stdout); mg.DumpShort(stdout); diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index 78ae09d9..f4eb6f7e 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -3324,9 +3324,6 @@ bool CFlowGenListPerThread::Create(uint32_t thread_id, m_max_threads=max_threads; m_thread_id=thread_id; - m_watchdog = NULL; - m_watchdog_handle = -1; - m_cpu_cp_u.Create(&m_cpu_dp_u); uint32_t socket_id=rte_lcore_to_socket_id(m_core_id); diff --git a/src/bp_sim.h b/src/bp_sim.h index 3c865eac..1f35faba 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -3647,9 +3647,7 @@ public: } void tickle() { - if (m_watchdog) { - m_watchdog->tickle(m_watchdog_handle); - } + m_monitor.tickle(); } /* return the dual port ID this thread is attached to in 4 ports configuration @@ -3774,8 +3772,7 @@ public: CTupleGeneratorSmart m_smart_gen; - TrexWatchDog *m_watchdog; - int m_watchdog_handle; + TrexMonitor m_monitor; public: CNodeGenerator m_node_gen; diff --git a/src/latency.cpp b/src/latency.cpp index 6e4ce643..841913cf 100644 --- a/src/latency.cpp +++ b/src/latency.cpp @@ -555,9 +555,6 @@ bool CLatencyManager::Create(CLatencyManagerCfg * cfg){ m_nat_check_manager.Create(); } - m_watchdog = NULL; - m_watchdog_handle = -1; - return (true); } @@ -708,12 +705,10 @@ void CLatencyManager::reset(){ } void CLatencyManager::tickle() { - if (m_watchdog) { - m_watchdog->tickle(m_watchdog_handle); - } + m_monitor.tickle(); } -void CLatencyManager::start(int iter, TrexWatchDog *watchdog) { +void CLatencyManager::start(int iter, bool activate_watchdog) { m_do_stop =false; m_is_active =false; int cnt=0; @@ -730,9 +725,9 @@ void CLatencyManager::start(int iter, TrexWatchDog *watchdog) { m_p_queue.push(node); bool do_try_rx_queue =CGlobalInfo::m_options.preview.get_vm_one_queue_enable()?true:false; - if (watchdog) { - m_watchdog = watchdog; - m_watchdog_handle = watchdog->register_monitor("STF RX CORE", 1); + if (activate_watchdog) { + m_monitor.create("STF RX CORE", 1); + TrexWatchDog::getInstance().register_monitor(&m_monitor); } while ( !m_p_queue.empty() ) { @@ -802,8 +797,8 @@ void CLatencyManager::start(int iter, TrexWatchDog *watchdog) { } /* disable the monitor */ - if (m_watchdog) { - m_watchdog->disable_monitor(m_watchdog_handle); + if (activate_watchdog) { + m_monitor.disable(); } } diff --git a/src/latency.h b/src/latency.h index 6eddb3d7..724621f0 100644 --- a/src/latency.h +++ b/src/latency.h @@ -341,7 +341,7 @@ public: bool Create(CLatencyManagerCfg * cfg); void Delete(); void reset(); - void start(int iter, TrexWatchDog *watchdog); + void start(int iter, bool activate_watchdog); void stop(); bool is_active(); void set_ip(uint32_t client_ip, @@ -405,8 +405,7 @@ private: CNatRxManager m_nat_check_manager; CCpuUtlDp m_cpu_dp_u; CCpuUtlCp m_cpu_cp_u; - TrexWatchDog *m_watchdog; - int m_watchdog_handle; + TrexMonitor m_monitor; volatile bool m_do_stop __rte_cache_aligned ; }; diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index b959895d..ef1668ab 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -2857,8 +2857,9 @@ private: uint32_t m_stats_cnt; std::mutex m_cp_lock; + TrexMonitor m_monitor; + public: - TrexWatchDog m_watchdog; TrexStateless *m_trex_stateless; }; @@ -3288,8 +3289,7 @@ bool CGlobalTRex::Create(){ TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_TCP, global_platform_cfg_info.m_zmq_rpc_port, - &m_cp_lock, - &m_watchdog); + &m_cp_lock); cfg.m_port_count = CGlobalInfo::m_options.m_expected_portd; cfg.m_rpc_req_resp_cfg = &rpc_req_resp_cfg; @@ -3992,8 +3992,10 @@ int CGlobalTRex::run_in_master() { const int FASTPATH_DELAY_MS = 10; const int SLOWPATH_DELAY_MS = 500; - int handle = m_watchdog.register_monitor("master", 2); - m_watchdog.start(); + m_monitor.create("master", 2); + TrexWatchDog::getInstance().register_monitor(&m_monitor); + + TrexWatchDog::getInstance().start(); while ( true ) { @@ -4016,14 +4018,14 @@ int CGlobalTRex::run_in_master() { slow_path_counter += FASTPATH_DELAY_MS; cp_lock.lock(); - m_watchdog.tickle(handle); + m_monitor.tickle(); } /* on exit release the lock */ cp_lock.unlock(); /* first stop the WD */ - m_watchdog.stop(); + TrexWatchDog::getInstance().stop(); if (!is_all_cores_finished()) { /* probably CLTR-C */ @@ -4047,12 +4049,12 @@ int CGlobalTRex::run_in_rx_core(void){ if (get_is_stateless()) { m_sl_rx_running = true; - m_rx_sl.start(m_watchdog); + m_rx_sl.start(); m_sl_rx_running = false; } else { if ( CGlobalInfo::m_options.is_rx_enabled() ){ m_sl_rx_running = false; - m_mg.start(0, &m_watchdog); + m_mg.start(0, true); } } @@ -4079,9 +4081,8 @@ int CGlobalTRex::run_in_core(virtual_thread_id_t virt_core_id){ lpt = m_fl.m_threads_info[virt_core_id-1]; /* register a watchdog handle on current core */ - lpt->m_watchdog = &m_watchdog; - lpt->m_watchdog_handle = m_watchdog.register_monitor(ss.str(), 1); - + lpt->m_monitor.create(ss.str(), 1); + TrexWatchDog::getInstance().register_monitor(&lpt->m_monitor); if (get_is_stateless()) { lpt->start_stateless_daemon(*lp); @@ -4090,7 +4091,7 @@ int CGlobalTRex::run_in_core(virtual_thread_id_t virt_core_id){ } /* done - remove this from the watchdog (we might wait on join for a long time) */ - lpt->m_watchdog->disable_monitor(lpt->m_watchdog_handle); + lpt->m_monitor.disable(); m_signal[virt_core_id]=1; return (0); @@ -4786,11 +4787,7 @@ int main_test(int argc , char * argv[]){ /* disable WD if needed */ //CGlobalInfo::m_options.preview.getWDDisable()?false:true - g_trex.m_watchdog.init(false); /* always disable - due to trex-211 */ - - /* this will give us all cores - master + tx + latency */ - g_trex.m_watchdog.mark_pending_monitor(g_trex.m_max_cores); - + TrexWatchDog::getInstance().init(true); /* always disable - due to trex-211 */ g_trex.m_sl_rx_running = false; if ( get_is_stateless() ) { diff --git a/src/rpc-server/trex_rpc_req_resp_server.cpp b/src/rpc-server/trex_rpc_req_resp_server.cpp index 033f265c..75eec856 100644 --- a/src/rpc-server/trex_rpc_req_resp_server.cpp +++ b/src/rpc-server/trex_rpc_req_resp_server.cpp @@ -56,7 +56,8 @@ void TrexRpcServerReqRes::_rpc_thread_cb() { std::stringstream ss; int zmq_rc; - m_watchdog_handle = m_watchdog->register_monitor(m_name, 1); + m_monitor.create(m_name, 1); + TrexWatchDog::getInstance().register_monitor(&m_monitor); /* create a socket based on the configuration */ @@ -102,7 +103,7 @@ void TrexRpcServerReqRes::_rpc_thread_cb() { zmq_close(m_socket); /* done */ - m_watchdog->disable_monitor(m_watchdog_handle); + m_monitor.disable(); } bool @@ -115,7 +116,7 @@ TrexRpcServerReqRes::fetch_one_request(std::string &msg) { assert(rc == 0); while (true) { - m_watchdog->tickle(m_watchdog_handle); + m_monitor.tickle(); rc = zmq_msg_recv (&zmq_msg, m_socket, 0); if (rc != -1) { diff --git a/src/rpc-server/trex_rpc_server.cpp b/src/rpc-server/trex_rpc_server.cpp index e4ca95c3..6c323c16 100644 --- a/src/rpc-server/trex_rpc_server.cpp +++ b/src/rpc-server/trex_rpc_server.cpp @@ -36,8 +36,6 @@ TrexRpcServerInterface::TrexRpcServerInterface(const TrexRpcServerConfig &cfg, c m_name = name; m_lock = cfg.m_lock; - m_watchdog = cfg.m_watchdog; - m_watchdog_handle = -1; m_is_running = false; m_is_verbose = false; @@ -78,7 +76,6 @@ void TrexRpcServerInterface::start() { /* prepare for run */ _prepare(); - m_watchdog->mark_pending_monitor(); m_thread = new std::thread(&TrexRpcServerInterface::_rpc_thread_cb, this); if (!m_thread) { throw TrexRpcException("unable to create RPC thread"); diff --git a/src/rpc-server/trex_rpc_server_api.h b/src/rpc-server/trex_rpc_server_api.h index 3d9837ef..6df37b17 100644 --- a/src/rpc-server/trex_rpc_server_api.h +++ b/src/rpc-server/trex_rpc_server_api.h @@ -30,10 +30,10 @@ limitations under the License. #include #include #include +#include "trex_watchdog.h" class TrexRpcServerInterface; class TrexRpcServerReqRes; -class TrexWatchDog; /** * defines a configuration of generic RPC server @@ -48,11 +48,10 @@ public: RPC_PROT_MOCK }; - TrexRpcServerConfig(rpc_prot_e protocol, uint16_t port, std::mutex *lock, TrexWatchDog *watchdog) { + TrexRpcServerConfig(rpc_prot_e protocol, uint16_t port, std::mutex *lock) { m_protocol = protocol; m_port = port; m_lock = lock; - m_watchdog = watchdog; } uint16_t get_port() const { @@ -69,7 +68,6 @@ private: public: std::mutex *m_lock; - TrexWatchDog *m_watchdog; }; /** @@ -142,8 +140,7 @@ protected: std::string m_name; std::mutex *m_lock; std::mutex m_dummy_lock; - TrexWatchDog *m_watchdog; - int m_watchdog_handle; + TrexMonitor m_monitor; }; /** diff --git a/src/sim/trex_sim_stateless.cpp b/src/sim/trex_sim_stateless.cpp index d3981e97..77bd4d70 100644 --- a/src/sim/trex_sim_stateless.cpp +++ b/src/sim/trex_sim_stateless.cpp @@ -200,7 +200,7 @@ SimStateless::prepare_control_plane() { m_publisher = new SimPublisher(); - TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_MOCK, 0, NULL, NULL); + TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_MOCK, 0, NULL); cfg.m_port_count = m_port_count; cfg.m_rpc_req_resp_cfg = &rpc_req_resp_cfg; diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp index b3555c13..847dbc97 100644 --- a/src/stateless/rx/trex_stateless_rx_core.cpp +++ b/src/stateless/rx/trex_stateless_rx_core.cpp @@ -72,9 +72,6 @@ void CRxCoreStateless::create(const CRxSlCfg &cfg) { m_ring_to_cp = cp_rx->getRingDpToCp(0); m_state = STATE_IDLE; - m_watchdog_handle = -1; - m_watchdog = NULL; - for (int i = 0; i < m_max_ports; i++) { CLatencyManagerPerPortStl * lp = &m_ports[i]; lp->m_io = cfg.m_ports[i]; @@ -93,7 +90,7 @@ void CRxCoreStateless::handle_cp_msg(TrexStatelessCpToRxMsgBase *msg) { } void CRxCoreStateless::tickle() { - m_watchdog->tickle(m_watchdog_handle); + m_monitor.tickle(); } bool CRxCoreStateless::periodic_check_for_cp_messages() { @@ -147,14 +144,14 @@ void CRxCoreStateless::idle_state_loop() { } } -void CRxCoreStateless::start(TrexWatchDog &watchdog) { +void CRxCoreStateless::start() { int count = 0; int i = 0; bool do_try_rx_queue =CGlobalInfo::m_options.preview.get_vm_one_queue_enable() ? true : false; /* register a watchdog handle on current core */ - m_watchdog = &watchdog; - m_watchdog_handle = watchdog.register_monitor("STL RX CORE", 1); + m_monitor.create("STL RX CORE", 1); + TrexWatchDog::getInstance().register_monitor(&m_monitor); while (true) { if (m_state == STATE_WORKING) { @@ -179,7 +176,7 @@ void CRxCoreStateless::start(TrexWatchDog &watchdog) { } rte_pause(); - m_watchdog->disable_monitor(m_watchdog_handle); + m_monitor.disable(); } void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *m) { diff --git a/src/stateless/rx/trex_stateless_rx_core.h b/src/stateless/rx/trex_stateless_rx_core.h index ce1bc1ad..dfc56e4d 100644 --- a/src/stateless/rx/trex_stateless_rx_core.h +++ b/src/stateless/rx/trex_stateless_rx_core.h @@ -95,7 +95,7 @@ class CRxCoreStateless { }; public: - void start(TrexWatchDog &watchdog); + void start(); void create(const CRxSlCfg &cfg); void reset_rx_stats(uint8_t port_id); int get_rx_stats(uint8_t port_id, rx_per_flow_t *rx_stats, int min, int max, bool reset @@ -126,8 +126,7 @@ class CRxCoreStateless { private: - TrexWatchDog *m_watchdog; - int m_watchdog_handle; + TrexMonitor m_monitor; uint32_t m_max_ports; bool m_has_streams; diff --git a/src/trex_watchdog.cpp b/src/trex_watchdog.cpp index b320a1b3..79dadb16 100644 --- a/src/trex_watchdog.cpp +++ b/src/trex_watchdog.cpp @@ -37,7 +37,7 @@ limitations under the License. #include -static TrexWatchDog::monitor_st *global_monitor; +static TrexMonitor *global_monitor; const char *get_exe_name(); @@ -113,7 +113,7 @@ static void _callstack_signal_handler(int signr, siginfo_t *info, void *secret) double now = now_sec(); - ss << "WATCHDOG: task '" << global_monitor->name << "' has not responded for more than " << (now - global_monitor->ts) << " seconds - timeout is " << global_monitor->timeout_sec << " seconds"; + ss << "WATCHDOG: task '" << global_monitor->get_name() << "' has not responded for more than " << global_monitor->get_interval(now) << " seconds - timeout is " << global_monitor->get_timeout_sec() << " seconds"; std::string backtrace = Backtrace(); ss << "\n\n*** traceback follows ***\n\n" << backtrace << "\n"; @@ -121,153 +121,65 @@ static void _callstack_signal_handler(int signr, siginfo_t *info, void *secret) throw std::runtime_error(ss.str()); } +/************************************** + * Trex Monitor object + *************************************/ + +void TrexMonitor::create(const std::string &name, double timeout_sec) { + m_active = true; + m_tid = pthread_self(); + m_name = name; + m_timeout_sec = timeout_sec; + m_tickled = true; + m_ts = 0; +} + +/************************************** + * Trex watchdog + *************************************/ void TrexWatchDog::init(bool enable){ - m_enable =enable; + m_enable = enable; if (m_enable) { register_signal(); } } - -void TrexWatchDog::mark_pending_monitor(int count) { - if (!m_enable){ - return; - } - - std::unique_lock lock(m_lock); - m_pending += count; - lock.unlock(); -} - -void TrexWatchDog::block_on_pending(int max_block_time_ms) { - - if (!m_enable){ - return; - } - - int timeout_msec = max_block_time_ms; - - std::unique_lock lock(m_lock); - - while (m_pending > 0) { - - lock.unlock(); - delay(1); - lock.lock(); - - timeout_msec -= 1; - if (timeout_msec == 0) { - throw TrexException("WATCHDOG: block on pending monitors timed out"); - } - } - - /* lock will be released */ -} - /** * register a monitor - * must be called from the relevant thread - * * this function is thread safe * - * @author imarom (01-Jun-16) - * - * @param name - * @param timeout_sec - * - * @return int */ -int TrexWatchDog::register_monitor(const std::string &name, double timeout_sec) { +void TrexWatchDog::register_monitor(TrexMonitor *monitor) { if (!m_enable){ - return 0; + return; } - monitor_st monitor; - - - /* cannot add monitors while active */ - assert(m_active == false); - - monitor.active = true; - monitor.tid = pthread_self(); - monitor.name = name; - monitor.timeout_sec = timeout_sec; - monitor.tickled = true; - monitor.ts = 0; /* critical section start */ std::unique_lock lock(m_lock); - /* make sure no double register */ - for (auto &m : m_monitors) { - if (m.tid == pthread_self()) { + /* sanity - not a must but why not... */ + for (int i = 0; i < m_mon_count; i++) { + if ( (monitor == m_monitors[i]) || (m_monitors[i]->get_tid() == pthread_self()) ) { std::stringstream ss; ss << "WATCHDOG: double register detected\n\n" << Backtrace(); throw TrexException(ss.str()); } } - monitor.handle = m_monitors.size(); - m_monitors.push_back(monitor); + /* check capacity */ + if (m_mon_count == MAX_MONITORS) { + std::stringstream ss; + ss << "WATCHDOG: too many registered monitors\n\n" << Backtrace(); + throw TrexException(ss.str()); + } - assert(m_pending > 0); - m_pending--; + /* add monitor */ + m_monitors[m_mon_count++] = monitor; /* critical section end */ lock.unlock(); - return monitor.handle; -} - -/** - * will disable the monitor - it will no longer be watched - * - */ -void TrexWatchDog::disable_monitor(int handle) { - if (!m_enable){ - return ; - } - - assert(handle < m_monitors.size()); - - m_monitors[handle].active = false; -} - -/** - * thread safe function - * - */ -void TrexWatchDog::tickle(int handle) { - if (!m_enable){ - return ; - } - assert(handle < m_monitors.size()); - - /* not nesscary but write gets cache invalidate for nothing */ - if (m_monitors[handle].tickled) { - return; - } - - m_monitors[handle].tickled = true; -} - -void TrexWatchDog::register_signal() { - /* do this once */ - if (g_signal_init) { - return; - } - - /* register a handler on SIG ALARM */ - struct sigaction sa; - memset (&sa, '\0', sizeof(sa)); - - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = _callstack_signal_handler; - - int rc = sigaction(SIGALRM , &sa, NULL); - assert(rc == 0); - - g_signal_init = true; } void TrexWatchDog::start() { @@ -276,11 +188,6 @@ void TrexWatchDog::start() { return ; } - block_on_pending(); - - /* no pending monitors */ - assert(m_pending == 0); - m_active = true; m_thread = new std::thread(&TrexWatchDog::_main, this); if (!m_thread) { @@ -289,6 +196,7 @@ void TrexWatchDog::start() { } void TrexWatchDog::stop() { + if (!m_enable){ return ; } @@ -310,41 +218,39 @@ void TrexWatchDog::stop() { */ void TrexWatchDog::_main() { - assert(m_enable==true); - - /* reset all the monitors */ - for (auto &monitor : m_monitors) { - monitor.tickled = true; - } + assert(m_enable == true); /* start main loop */ while (m_active) { dsec_t now = now_sec(); - for (auto &monitor : m_monitors) { + /* volatile are slow - read once per iteration */ + int count = m_mon_count; + + for (int i = 0; i < count; i++) { + TrexMonitor *monitor = m_monitors[i]; /* skip non active monitors */ - if (!monitor.active) { + if (!monitor->is_active()) { continue; } /* if its own - turn it off and write down the time */ - if (monitor.tickled) { - monitor.tickled = false; - monitor.ts = now; + if (monitor->is_tickled()) { + monitor->reset(now); continue; } - /* the bit is off - check the time first */ - if ( (now - monitor.ts) > monitor.timeout_sec ) { - global_monitor = &monitor; + /* if the monitor has expired - crash */ + if (monitor->is_expired(now)) { + global_monitor = monitor; - pthread_kill(monitor.tid, SIGALRM); + pthread_kill(monitor->get_tid(), SIGALRM); /* nothing to do more... the other thread will terminate, but if not - we terminate */ sleep(5); - printf("\n\n*** WATCHDOG violation detected on task '%s' which have failed to response to the signal ***\n\n", monitor.name.c_str()); + printf("\n\n*** WATCHDOG violation detected on task '%s' which have failed to response to the signal ***\n\n", monitor->get_name().c_str()); exit(1); } @@ -355,4 +261,25 @@ void TrexWatchDog::_main() { } } + +void TrexWatchDog::register_signal() { + /* do this once */ + if (g_signal_init) { + return; + } + + /* register a handler on SIG ALARM */ + struct sigaction sa; + memset (&sa, '\0', sizeof(sa)); + + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = _callstack_signal_handler; + + int rc = sigaction(SIGALRM , &sa, NULL); + assert(rc == 0); + + g_signal_init = true; +} + bool TrexWatchDog::g_signal_init = false; + diff --git a/src/trex_watchdog.h b/src/trex_watchdog.h index 0c1969b1..1c948d56 100644 --- a/src/trex_watchdog.h +++ b/src/trex_watchdog.h @@ -27,69 +27,142 @@ limitations under the License. #include #include -//#include "rte_memory.h" #include "mbuf.h" #include "os_time.h" -class TrexWatchDog { +/** + * every thread creates its own monitor from its own memory + * + * @author imarom (19-Jun-16) + */ +class TrexMonitor { + public: - TrexWatchDog() { - m_thread = NULL; - m_active = false; - m_pending = 0; - m_enable = false; - } - void init(bool enable); + /** + * create a monitor + * + * @author imarom (31-May-16) + * + * @param name + * @param timeout + * + * @return int + */ + void create(const std::string &name, double timeout_sec); /** - * registering a monitor happens from another thread - * this make sure that start will be able to block until - * all threads has registered + * disable the monitor - it will be ignored * - * @author imarom (01-Jun-16) */ - void mark_pending_monitor(int count = 1); - + void disable() { + m_active = false; + } /** - * blocks while monitors are pending registeration + * tickle the monitor - this should be called from the thread + * to avoid the watchdog from detecting a stuck thread * - * @author imarom (01-Jun-16) + * @author imarom (19-Jun-16) */ - void block_on_pending(int max_block_time_ms = 200); - + void tickle() { + /* to avoid useless writes - first check */ + if (!m_tickled) { + m_tickled = true; + } + } /** - * add a monitor to the watchdog - * this thread will be monitored and if timeout - * has passed without calling tick - an exception will be called - * - * @author imarom (31-May-16) - * - * @param name - * @param timeout + * called by the watchdog to reset the monitor for a new round * - * @return int */ - int register_monitor(const std::string &name, double timeout_sec); + void reset(dsec_t now) { + m_tickled = false; + m_ts = now; + } + + + /* return how much time has passed since last tickle */ + dsec_t get_interval(dsec_t now) const { + return (now - m_ts); + } + + pthread_t get_tid() const { + return m_tid; + } + + const std::string &get_name() const { + return m_name; + } + + dsec_t get_timeout_sec() const { + return m_timeout_sec; + } + + volatile bool is_active() const { + return m_active; + } + volatile bool is_tickled() const { + return m_tickled; + } + + bool is_expired(dsec_t now) const { + return ( get_interval(now) > m_timeout_sec ); + } + + +private: + + /* write fields are first */ + volatile bool m_active; + volatile bool m_tickled; + dsec_t m_ts; + + int m_handle; + double m_timeout_sec; + pthread_t m_tid; + std::string m_name; + + /* for for a full cacheline */ + uint8_t pad[15]; + +} __rte_cache_aligned; + + +/** + * a watchdog is a list of registered monitors + * + * @author imarom (19-Jun-16) + */ +class TrexWatchDog { +public: /** - * disable a monitor - it will no longer be watched + * singleton entry + * + * @author imarom (19-Jun-16) * + * @return TrexWatchDog& */ - void disable_monitor(int handle); + static TrexWatchDog& getInstance() { + static TrexWatchDog instance; + return instance; + } + void init(bool enable); + /** - * should be called by each thread on it's handle + * add a monitor to the watchdog + * from now on this monitor will be watched + * + * @author imarom (19-Jun-16) * - * @author imarom (31-May-16) + * @param monitor - a pointer to the object * - * @param handle */ - void tickle(int handle); + void register_monitor(TrexMonitor *monitor); /** @@ -106,38 +179,30 @@ public: void stop(); - /* should be cache aligned to avoid false sharing */ - struct monitor_st { - /* write fields are first */ - volatile bool active; - volatile bool tickled; - dsec_t ts; - - int handle; - double timeout_sec; - pthread_t tid; - std::string name; - - /* for for a full cacheline */ - uint8_t pad[15]; - } __rte_cache_aligned ; +private: + TrexWatchDog() { + m_thread = NULL; + m_enable = false; + m_active = false; + m_mon_count = 0; + } -private: void register_signal(); void _main(); + static const int MAX_MONITORS = 100; + TrexMonitor *m_monitors[MAX_MONITORS]; + volatile int m_mon_count; + std::mutex m_lock; - std::vector m_monitors __rte_cache_aligned; - std::mutex m_lock; - bool m_enable; - volatile bool m_active; - std::thread *m_thread; - volatile int m_pending; + bool m_enable; + volatile bool m_active; + std::thread *m_thread; - static bool g_signal_init; + static bool g_signal_init; }; -static_assert(sizeof(TrexWatchDog::monitor_st) == RTE_CACHE_LINE_SIZE, "sizeof(monitor_st) != RTE_CACHE_LINE_SIZE" ); +static_assert(sizeof(TrexMonitor) == RTE_CACHE_LINE_SIZE, "sizeof(TrexMonitor) != RTE_CACHE_LINE_SIZE" ); #endif /* __TREX_WATCHDOG_H__ */ -- cgit 1.2.3-korg From b9726ed2056ed2de756e6af702b5ed51101c9674 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 20 Jun 2016 09:27:43 +0300 Subject: only latency streams might get the graph to crash while calculating duration (because latency is considered a fixed DC and not a real event) --- src/stateless/cp/trex_streams_compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index f2296aeb..d2fe416a 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -925,7 +925,7 @@ TrexStreamsGraphObj::find_max_rate() { } /* if not mark as inifite - get the last event time */ - if (m_expected_duration != -1) { + if ( (m_expected_duration != -1) && (m_rate_events.size() > 0) ) { m_expected_duration = m_rate_events.back().time; } -- cgit 1.2.3-korg From 0bcd7377e8d476a0eb8f7d7f55f59e0c6df91f28 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 20 Jun 2016 09:52:43 +0300 Subject: WATCHDOG: using exit() might get stuck because it deallocates memory on an already unstable state - need to use abort or C++ exceptions which uses abort --- src/trex_watchdog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/trex_watchdog.cpp b/src/trex_watchdog.cpp index 79dadb16..c72ce69e 100644 --- a/src/trex_watchdog.cpp +++ b/src/trex_watchdog.cpp @@ -250,8 +250,8 @@ void TrexWatchDog::_main() { /* nothing to do more... the other thread will terminate, but if not - we terminate */ sleep(5); - printf("\n\n*** WATCHDOG violation detected on task '%s' which have failed to response to the signal ***\n\n", monitor->get_name().c_str()); - exit(1); + fprintf(stderr, "\n\n*** WATCHDOG violation detected on task '%s' which have failed to response to the signal ***\n\n", monitor->get_name().c_str()); + abort(); } } -- cgit 1.2.3-korg From 35efdda889977a7b0bf5d1cda213d0e7ffcd4367 Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Mon, 20 Jun 2016 12:56:17 +0300 Subject: Add 4 bytes for each packet rx/tx bytes in flow stats, to artificially count ethernet CRC --- scripts/automation/regression/stateless_tests/stl_rx_test.py | 4 ++-- .../trex_control_plane/stl/examples/stl_flow_latency_stats.py | 2 +- src/main_dpdk.cpp | 2 +- src/stateless/rx/trex_stateless_rx_core.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/automation/regression/stateless_tests/stl_rx_test.py b/scripts/automation/regression/stateless_tests/stl_rx_test.py index 80e6bee6..41eabd65 100644 --- a/scripts/automation/regression/stateless_tests/stl_rx_test.py +++ b/scripts/automation/regression/stateless_tests/stl_rx_test.py @@ -80,7 +80,7 @@ class STLRX_Test(CStlGeneral_Test): tmp = 'TX pkts mismatch - got: {0}, expected: {1}'.format(tx_pkts, total_pkts) assert False, tmp - if tx_bytes != (total_pkts * pkt_len): + if tx_bytes != (total_pkts * (pkt_len + 4)): # + 4 for ethernet CRC pprint.pprint(flow_stats) tmp = 'TX bytes mismatch - got: {0}, expected: {1}'.format(tx_bytes, (total_pkts * pkt_len)) assert False, tmp @@ -92,7 +92,7 @@ class STLRX_Test(CStlGeneral_Test): if "rx_bytes" in self.cap: rx_bytes = flow_stats['rx_bytes'].get(self.rx_port, 0) - if rx_bytes != (total_pkts * pkt_len) and not self.drops_expected: + if rx_bytes != (total_pkts * (pkt_len + 4)) and not self.drops_expected: # +4 for ethernet CRC pprint.pprint(flow_stats) tmp = 'RX bytes mismatch - got: {0}, expected: {1}'.format(rx_bytes, (total_pkts * pkt_len)) assert False, tmp diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_flow_latency_stats.py b/scripts/automation/trex_control_plane/stl/examples/stl_flow_latency_stats.py index 86b91728..ac0e212b 100644 --- a/scripts/automation/trex_control_plane/stl/examples/stl_flow_latency_stats.py +++ b/scripts/automation/trex_control_plane/stl/examples/stl_flow_latency_stats.py @@ -114,7 +114,7 @@ def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len, bw): else: print("TX pkts match - {0}".format(tx_pkts)) - if tx_bytes != (total_pkts * pkt_len): + if tx_bytes != (total_pkts * (pkt_len + 4)): # +4 for ethernet CRC print("TX bytes mismatch - got: {0}, expected: {1}".format(tx_bytes, (total_pkts * pkt_len))) pprint.pprint(flow_stats) return False diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index ef1668ab..3dd020ae 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -2074,7 +2074,7 @@ int CCoreEthIFStateless::send_node_flow_stat(rte_mbuf *m, CGenNodeStateless * no } tx_per_flow_t *lp_s = &lp_stats->m_tx_per_flow[hw_id]; lp_s->add_pkts(1); - lp_s->add_bytes(mi->pkt_len); + lp_s->add_bytes(mi->pkt_len + 4); // We add 4 because of ethernet CRC if (hw_id >= MAX_FLOW_STATS) { fsp_head->time_stamp = os_get_hr_tick_64(); diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp index 847dbc97..a622ee7a 100644 --- a/src/stateless/rx/trex_stateless_rx_core.cpp +++ b/src/stateless/rx/trex_stateless_rx_core.cpp @@ -235,7 +235,7 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t * curr_rfc2544.set_seq(pkt_seq + 1); } lp->m_port.m_rx_pg_stat_payload[hw_id].add_pkts(1); - lp->m_port.m_rx_pg_stat_payload[hw_id].add_bytes(m->pkt_len); + lp->m_port.m_rx_pg_stat_payload[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC uint64_t d = (os_get_hr_tick_64() - fsp_head->time_stamp ); dsec_t ctime = ptime_convert_hr_dsec(d); curr_rfc2544.add_sample(ctime); @@ -243,7 +243,7 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t * } else { hw_id = get_hw_id(ip_id); lp->m_port.m_rx_pg_stat[hw_id].add_pkts(1); - lp->m_port.m_rx_pg_stat[hw_id].add_bytes(m->pkt_len); + lp->m_port.m_rx_pg_stat[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC } } } -- cgit 1.2.3-korg From e058f6e034fbf51bc5e29d449ea806e7a8633b70 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Mon, 20 Jun 2016 13:47:18 +0300 Subject: regression: add flag to run with debug image --- scripts/automation/regression/trex.py | 1 + scripts/automation/regression/trex_unit_test.py | 12 ++++++++++-- scripts/automation/trex_control_plane/server/trex_server.py | 9 +++++---- .../trex_control_plane/stf/trex_stf_lib/trex_client.py | 7 ++++--- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/scripts/automation/regression/trex.py b/scripts/automation/regression/trex.py index 9541ad76..44f2faba 100644 --- a/scripts/automation/regression/trex.py +++ b/scripts/automation/regression/trex.py @@ -39,6 +39,7 @@ class CTRexScenario: GAManager = None no_daemon = False router_image = None + debug_image = False class CTRexRunner: """This is an instance for generating a CTRexRunner""" diff --git a/scripts/automation/regression/trex_unit_test.py b/scripts/automation/regression/trex_unit_test.py index 5eb9e222..11902a1a 100755 --- a/scripts/automation/regression/trex_unit_test.py +++ b/scripts/automation/regression/trex_unit_test.py @@ -143,6 +143,9 @@ class CTRexTestConfiguringPlugin(Plugin): parser.add_option('--no-daemon', action="store_true", default = False, dest="no_daemon", help="Flag that specifies to use running stl server, no need daemons.") + parser.add_option('--debug-image', action="store_true", default = False, + dest="debug_image", + help="Flag that specifies to use t-rex-64-debug as TRex executable.") def configure(self, options, conf): @@ -179,9 +182,11 @@ class CTRexTestConfiguringPlugin(Plugin): CTRexScenario.benchmark = self.benchmark CTRexScenario.modes = set(self.modes) CTRexScenario.server_logs = self.server_logs + CTRexScenario.debug_image = options.debug_image if not self.no_daemon: - CTRexScenario.trex = CTRexClient(trex_host = self.configuration.trex['trex_name'], - verbose = self.json_verbose) + CTRexScenario.trex = CTRexClient(trex_host = self.configuration.trex['trex_name'], + verbose = self.json_verbose, + debug_image = options.debug_image) if not CTRexScenario.trex.check_master_connectivity(): print('Could not connect to master daemon') sys.exit(-1) @@ -267,6 +272,9 @@ def save_setup_info(): setup_info += 'Server: %s, Modes: %s' % (cfg.trex.get('trex_name'), cfg.trex.get('modes')) if cfg.router: setup_info += '\nRouter: Model: %s, Image: %s' % (cfg.router.get('model'), CTRexScenario.router_image) + if CTRexScenario.debug_image: + setup_info += '\nDebug image: %s' % CTRexScenario.debug_image + with open('%s/report_%s.info' % (CTRexScenario.report_dir, CTRexScenario.setup_name), 'w') as f: f.write(setup_info) except Exception as err: diff --git a/scripts/automation/trex_control_plane/server/trex_server.py b/scripts/automation/trex_control_plane/server/trex_server.py index 3da629ec..091b729b 100755 --- a/scripts/automation/trex_control_plane/server/trex_server.py +++ b/scripts/automation/trex_control_plane/server/trex_server.py @@ -310,7 +310,7 @@ class CTRexServer(object): return False - def start_trex(self, trex_cmd_options, user, block_to_success = True, timeout = 40, stateless = False): + def start_trex(self, trex_cmd_options, user, block_to_success = True, timeout = 40, stateless = False, debug_image = False): with self.start_lock: logger.info("Processing start_trex() command.") if self.is_reserved(): @@ -323,7 +323,7 @@ class CTRexServer(object): return Fault(-13, '') # raise at client TRexInUseError try: - server_cmd_data = self.generate_run_cmd(stateless = stateless, **trex_cmd_options) + server_cmd_data = self.generate_run_cmd(stateless = stateless, debug_image = debug_image, **trex_cmd_options) self.zmq_monitor.first_dump = True self.trex.start_trex(self.TREX_PATH, server_cmd_data) logger.info("TRex session has been successfully initiated.") @@ -413,7 +413,7 @@ class CTRexServer(object): return self.trex.get_running_info() - def generate_run_cmd (self, iom = 0, export_path="/tmp/trex.txt", stateless = False, **kwargs): + def generate_run_cmd (self, iom = 0, export_path="/tmp/trex.txt", stateless = False, debug_image = False, **kwargs): """ generate_run_cmd(self, iom, export_path, kwargs) -> str Generates a custom running command for the kick-off of the TRex traffic generator. @@ -457,9 +457,10 @@ class CTRexServer(object): if 'd' not in kwargs: raise Exception('Argument -d should be specified in stateful command') - cmd = "{nice}{run_command} --iom {io} {cmd_options} --no-key".format( # -- iom 0 disables the periodic log to the screen (not needed) + cmd = "{nice}{run_command}{debug_image} --iom {io} {cmd_options} --no-key".format( # -- iom 0 disables the periodic log to the screen (not needed) nice = '' if self.trex_nice == 0 else 'nice -n %s ' % self.trex_nice, run_command = self.TREX_START_CMD, + debug_image = '-debug' if debug_image else '', cmd_options = trex_cmd_options, io = iom) diff --git a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py index e1b298db..91fe2075 100755 --- a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py +++ b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py @@ -40,7 +40,7 @@ class CTRexClient(object): This class defines the client side of the RESTfull interaction with TRex """ - def __init__(self, trex_host, max_history_size = 100, filtered_latency_amount = 0.001, trex_daemon_port = 8090, master_daemon_port = 8091, trex_zmq_port = 4500, verbose = False): + def __init__(self, trex_host, max_history_size = 100, filtered_latency_amount = 0.001, trex_daemon_port = 8090, master_daemon_port = 8091, trex_zmq_port = 4500, verbose = False, debug_image = False): """ Instantiate a TRex client object, and connecting it to listening daemon-server @@ -96,6 +96,7 @@ class CTRexClient(object): self.master_daemon = jsonrpclib.Server(self.master_daemon_path, history = self.history) self.trex_server_path = "http://{hostname}:{port}/".format( hostname = self.trex_host, port = trex_daemon_port ) self.server = jsonrpclib.Server(self.trex_server_path, history = self.history) + self.debug_image = debug_image def add (self, x, y): @@ -159,7 +160,7 @@ class CTRexClient(object): self.result_obj.clear_results() try: issue_time = time.time() - retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout) + retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, self.debug_image) except AppError as err: self._handle_AppError_exception(err.args[0]) except ProtocolError: @@ -205,7 +206,7 @@ class CTRexClient(object): """ try: user = user or self.__default_user - retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, True) + retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, True, self.debug_image) except AppError as err: self._handle_AppError_exception(err.args[0]) except ProtocolError: -- cgit 1.2.3-korg From f1da3b2bf6817a2ddd8abe8546108b43a12d1411 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 20 Jun 2016 13:20:51 +0300 Subject: more granular lock for RPC server avoid a bigger jitter for ASYNC thread because of lock --- src/rpc-server/trex_rpc_req_resp_server.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/rpc-server/trex_rpc_req_resp_server.cpp b/src/rpc-server/trex_rpc_req_resp_server.cpp index 75eec856..e0e7635c 100644 --- a/src/rpc-server/trex_rpc_req_resp_server.cpp +++ b/src/rpc-server/trex_rpc_req_resp_server.cpp @@ -201,23 +201,24 @@ void TrexRpcServerReqRes::process_request_raw(const std::string &request, std::s int index = 0; - /* expcetion safe */ - std::unique_lock lock(*m_lock); - /* for every command parsed - launch it */ for (auto command : commands) { Json::Value single_response; + /* the command itself should be protected */ + std::unique_lock lock(*m_lock); command->execute(single_response); + lock.unlock(); + delete command; response_json[index++] = single_response; + /* batch is like getting all the messages one by one - it should not be considered as stuck thread */ + /* need to think if this is a good thing */ + //m_monitor.tickle(); } - /* done with the lock */ - lock.unlock(); - /* write the JSON to string and sever on ZMQ */ if (response.size() == 1) { -- cgit 1.2.3-korg From 88486da4a095bd7fa7094d4bd9ab54eeafd24a26 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 20 Jun 2016 13:48:27 +0300 Subject: fix: --no-watchdog did not work --- src/main_dpdk.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 3dd020ae..29966932 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -4786,8 +4786,8 @@ int main_test(int argc , char * argv[]){ } /* disable WD if needed */ - //CGlobalInfo::m_options.preview.getWDDisable()?false:true - TrexWatchDog::getInstance().init(true); /* always disable - due to trex-211 */ + bool wd_enable = (CGlobalInfo::m_options.preview.getWDDisable() ? false : true); + TrexWatchDog::getInstance().init(wd_enable); g_trex.m_sl_rx_running = false; if ( get_is_stateless() ) { -- cgit 1.2.3-korg From 7b13e5e5a6ec2dd71f551e61b846b481d5c58205 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Mon, 20 Jun 2016 13:50:10 +0300 Subject: minor remove sim help --- src/main_dpdk.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 3dd020ae..8ae44b02 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -714,20 +714,11 @@ static int usage(){ printf(" --prefix : for multi trex, each instance should have a different name \n"); printf(" --mac-spread : Spread the destination mac-order by this factor. e.g 2 will generate the traffic to 2 devices DEST-MAC ,DEST-MAC+1 \n"); printf(" maximum is up to 128 devices \n"); - printf(" --mbuf-factor : factor for packet memory \n"); - + printf(" \n"); printf(" --no-watchdog : disable watchdog \n"); - - printf("\n simulation mode : \n"); - printf(" Using this mode you can generate the traffic into a pcap file and learn how trex works \n"); - printf(" With this version you must be SUDO to use this mode ( I know this is not normal ) \n"); - printf(" you can use the Linux CEL version of TRex to do it without super user \n"); - printf(" \n"); - printf(" -o [capfile_name] simulate trex into pcap file \n"); - printf(" --pcap export the file in pcap mode \n"); - printf(" bp-sim-64 -d 10 -f cfg.yaml -o my.pcap --pcap # export 10 sec of what Trex will do on real-time to a file my.pcap \n"); - printf(" --vm-sim : simulate vm with driver of one input queue and one output queue \n"); + printf(" \n"); + printf(" --vm-sim : simulate vm with driver of one input queue and one output queue \n"); printf(" \n"); printf(" Examples: "); printf(" basic trex run for 10 sec and multiplier of x10 \n"); -- cgit 1.2.3-korg From 1b1567ac6c2cfcb1625dded30f497339c1519f91 Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Mon, 20 Jun 2016 16:45:21 +0300 Subject: Adding verify_stream in flow_stat.cpp --- src/flow_stat.cpp | 26 ++++++++++++++++++++++---- src/flow_stat.h | 2 ++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp index 71d3a74a..366c3aa8 100644 --- a/src/flow_stat.cpp +++ b/src/flow_stat.cpp @@ -539,7 +539,20 @@ void CFlowStatRuleMgr::init_stream(TrexStream * stream) { stream->m_rx_check.m_hw_id = HW_ID_INIT; } +int CFlowStatRuleMgr::verify_stream(TrexStream * stream) { + return add_stream_internal(stream, false); +} + int CFlowStatRuleMgr::add_stream(TrexStream * stream) { + return add_stream_internal(stream, true); +} + +/* + * Helper function for adding/verifying streams + * stream - stream to act on + * do_action - if false, just verify. Do not change any state, or add to database. + */ +int CFlowStatRuleMgr::add_stream_internal(TrexStream * stream, bool do_action) { #ifdef __DEBUG_FUNC_ENTRY__ std::cout << __METHOD_NAME__ << " user id:" << stream->m_rx_check.m_pg_id << std::endl; stream_dump(stream); @@ -572,7 +585,9 @@ int CFlowStatRuleMgr::add_stream(TrexStream * stream) { } // throws exception if there is error - m_user_id_map.add_stream(stream->m_rx_check.m_pg_id, l4_proto); + if (do_action) { + m_user_id_map.add_stream(stream->m_rx_check.m_pg_id, l4_proto); + } break; case TrexPlatformApi::IF_STAT_PAYLOAD: uint16_t payload_len; @@ -584,14 +599,17 @@ int CFlowStatRuleMgr::add_stream(TrexStream * stream) { + " payload bytes for payload rules. Packet only has " + std::to_string(payload_len) + " bytes" , TrexException::T_FLOW_STAT_PAYLOAD_TOO_SHORT); } - m_user_id_map.add_stream(stream->m_rx_check.m_pg_id, PAYLOAD_RULE_PROTO); + if (do_action) { + m_user_id_map.add_stream(stream->m_rx_check.m_pg_id, PAYLOAD_RULE_PROTO); + } break; default: throw TrexFStatEx("Wrong rule_type", TrexException::T_FLOW_STAT_BAD_RULE_TYPE); break; } - - stream->m_rx_check.m_hw_id = HW_ID_FREE; + if (do_action) { + stream->m_rx_check.m_hw_id = HW_ID_FREE; + } return 0; } diff --git a/src/flow_stat.h b/src/flow_stat.h index eae484e7..a2137198 100644 --- a/src/flow_stat.h +++ b/src/flow_stat.h @@ -450,6 +450,7 @@ class CFlowStatRuleMgr { friend std::ostream& operator<<(std::ostream& os, const CFlowStatRuleMgr& cf); void copy_state(TrexStream * from, TrexStream * to); void init_stream(TrexStream * stream); + int verify_stream(TrexStream * stream); int add_stream(TrexStream * stream); int del_stream(TrexStream * stream); int start_stream(TrexStream * stream); @@ -460,6 +461,7 @@ class CFlowStatRuleMgr { private: void create(); int compile_stream(const TrexStream * stream, CFlowStatParser *parser); + int add_stream_internal(TrexStream * stream, bool do_action); int add_hw_rule(uint16_t hw_id, uint8_t proto); void send_start_stop_msg_to_rx(bool is_start); -- cgit 1.2.3-korg From 0422016ab056245449e0e5bdf0dceef2c4f06e31 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 20 Jun 2016 14:30:46 +0300 Subject: bug: multiplier can be string or unicode --- .../stl/trex_stl_lib/trex_stl_client.py | 41 +++++++++------------- .../stl/trex_stl_lib/trex_stl_exceptions.py | 8 ++++- .../stl/trex_stl_lib/utils/common.py | 1 + .../stl/trex_stl_lib/utils/parsing_opts.py | 4 --- 4 files changed, 25 insertions(+), 29 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 22895a75..4d1125c8 100755 --- 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 @@ -1700,6 +1700,11 @@ class STLClient(object): ports = self._validate_port_list(ports) + validate_type('mult', mult, basestring) + validate_type('force', force, bool) + validate_type('duration', duration, (int, float)) + validate_type('total', total, bool) + # verify multiplier mult_obj = parsing_opts.decode_multiplier(mult, allow_update = False, @@ -1707,17 +1712,6 @@ class STLClient(object): if not mult_obj: raise STLArgumentError('mult', mult) - # some type checkings - - if not type(force) is bool: - raise STLArgumentError('force', force) - - if not isinstance(duration, (int, float)): - raise STLArgumentError('duration', duration) - - if not type(total) is bool: - raise STLArgumentError('total', total) - # verify ports are stopped or force stop them active_ports = list(set(self.get_active_ports()).intersection(ports)) @@ -1762,11 +1756,12 @@ class STLClient(object): """ - ports = ports if ports is not None else self.get_active_ports() - ports = self._validate_port_list(ports) + if ports is None: + ports = self.get_active_ports() + if not ports: + return - if not ports: - return + ports = self._validate_port_list(ports) self.logger.pre_cmd("Stopping traffic on port(s) {0}:".format(ports)) rc = self.__stop(ports) @@ -1815,6 +1810,9 @@ class STLClient(object): ports = ports if ports is not None else self.get_active_ports() ports = self._validate_port_list(ports) + validate_type('mult', mult, basestring) + validate_type('force', force, bool) + validate_type('total', total, bool) # verify multiplier mult_obj = parsing_opts.decode_multiplier(mult, @@ -1823,10 +1821,6 @@ class STLClient(object): if not mult_obj: raise STLArgumentError('mult', mult) - # verify total - if not type(total) is bool: - raise STLArgumentError('total', total) - # call low level functions self.logger.pre_cmd("Updating traffic on port(s) {0}:".format(ports)) @@ -2050,6 +2044,10 @@ class STLClient(object): ports = ports if ports is not None else self.get_acquired_ports() ports = self._validate_port_list(ports) + validate_type('mult', mult, basestring) + validate_type('duration', duration, (int, float)) + validate_type('total', total, bool) + # verify multiplier mult_obj = parsing_opts.decode_multiplier(mult, @@ -2058,11 +2056,6 @@ class STLClient(object): if not mult_obj: raise STLArgumentError('mult', mult) - - if not isinstance(duration, (int, float)): - raise STLArgumentError('duration', duration) - - self.logger.pre_cmd("Validating streams on port(s) {0}:".format(ports)) rc = self.__validate(ports) self.logger.post_cmd(rc) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_exceptions.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_exceptions.py index 3c443ba6..b6fad865 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_exceptions.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_exceptions.py @@ -4,6 +4,11 @@ import linecache from .utils.text_opts import * +try: + basestring +except NameError: + basestring = str + # basic error for API class STLError(Exception): def __init__ (self, msg): @@ -56,7 +61,8 @@ class STLArgumentError(STLError): # raised when argument type is not valid for operation class STLTypeError(STLError): def __init__ (self, arg_name, arg_type, valid_types): - self.msg = "Argument: '%s' invalid type: %s, expecting type(s): %s." % (arg_name, arg_type, valid_types) + self.msg = "Argument: '%s' invalid type: '%s', expecting type(s): %s." % (arg_name, arg_type.__name__, + [t.__name__ for t in valid_types] if isinstance(valid_types, tuple) else valid_types.__name__) # raised when timeout occurs class STLTimeoutError(STLError): diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py index b4903e81..6835ea5f 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py @@ -64,3 +64,4 @@ def list_difference (l1, l2): def is_sub_list (l1, l2): return set(l1) <= set(l2) + 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 98e3ca6a..9ef14612 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 @@ -90,10 +90,6 @@ match_multiplier_help = """Multiplier should be passed in the following format: # value should be divided def decode_multiplier(val, allow_update = False, divide_count = 1): - # must be string - if not isinstance(val, str): - return None - # do we allow updates ? +/- if not allow_update: match = re.match("^(\d+(\.\d+)?)(bps|kbps|mbps|gbps|pps|kpps|mpps|%?)$", val) -- cgit 1.2.3-korg From b4a17c0d02d500a9a08a052b958160791279c023 Mon Sep 17 00:00:00 2001 From: imarom Date: Tue, 21 Jun 2016 09:41:06 +0300 Subject: WATCHDOG: reading the counter for the main loop is probably better with a lock --- src/trex_watchdog.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/trex_watchdog.cpp b/src/trex_watchdog.cpp index c72ce69e..d099933b 100644 --- a/src/trex_watchdog.cpp +++ b/src/trex_watchdog.cpp @@ -225,8 +225,10 @@ void TrexWatchDog::_main() { dsec_t now = now_sec(); - /* volatile are slow - read once per iteration */ + /* to be on the safe side - read the count with a lock */ + std::unique_lock lock(m_lock); int count = m_mon_count; + lock.unlock(); for (int i = 0; i < count; i++) { TrexMonitor *monitor = m_monitors[i]; -- cgit 1.2.3-korg From 131bb55c38c0e59d14043766b0d3a38d5f775771 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Tue, 21 Jun 2016 14:29:22 +0300 Subject: --debug-image flag fix bug --- scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py index 91fe2075..57d19459 100755 --- a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py +++ b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py @@ -160,7 +160,7 @@ class CTRexClient(object): self.result_obj.clear_results() try: issue_time = time.time() - retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, self.debug_image) + retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, False, self.debug_image) except AppError as err: self._handle_AppError_exception(err.args[0]) except ProtocolError: -- cgit 1.2.3-korg From 3bf54917e0d8817dbadaae73a7545a011676cccf Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Tue, 21 Jun 2016 15:30:16 +0300 Subject: profile fixes --- .../stl/trex_stl_lib/utils/parsing_opts.py | 12 +++---- scripts/stl/burst_3st_1000pkt.py | 10 +++--- scripts/stl/burst_3st_600pkt.py | 10 +++--- scripts/stl/burst_3st_loop_x_times.py | 10 +++--- scripts/stl/flow_stats.py | 34 +++++++++++-------- scripts/stl/flow_stats_latency.py | 38 ++++++++++++++-------- scripts/stl/imix.py | 2 +- scripts/stl/multi_burst_2st_1000pkt.py | 8 ++--- scripts/stl/simple_3st.py | 6 ++-- scripts/stl/udp_1pkt.py | 4 +-- scripts/stl/udp_1pkt_1mac.py | 4 +-- scripts/stl/udp_1pkt_1mac_override.py | 4 +-- scripts/stl/udp_1pkt_1mac_step.py | 4 +-- scripts/stl/udp_1pkt_mac.py | 4 +-- scripts/stl/udp_1pkt_mac_mask1.py | 4 +-- scripts/stl/udp_1pkt_mac_mask2.py | 4 +-- scripts/stl/udp_1pkt_mac_mask3.py | 4 +-- scripts/stl/udp_1pkt_mac_mask5.py | 4 +-- scripts/stl/udp_1pkt_mac_step.py | 4 +-- scripts/stl/udp_1pkt_range_clients.py | 4 +-- scripts/stl/udp_1pkt_range_clients_split.py | 4 +-- scripts/stl/udp_1pkt_range_clients_split_garp.py | 2 +- scripts/stl/udp_1pkt_src_ip_split.py | 4 +-- scripts/stl/udp_1pkt_src_ip_split_latency.py | 4 +-- scripts/stl/udp_1pkt_tuple_gen.py | 2 +- scripts/stl/udp_1pkt_tuple_gen_split.py | 4 +-- scripts/stl/udp_3pkt_pcap.py | 6 ++-- 27 files changed, 109 insertions(+), 91 deletions(-) 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 9ef14612..bb28d3af 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 @@ -240,26 +240,24 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'type': int}), PROMISCUOUS: ArgumentPack(['--prom'], - {'help': "sets port promiscuous on", + {'help': "Sets port promiscuous on", 'dest': "prom", 'default': None, 'action': "store_true"}), - TUNABLES: ArgumentPack(['-t'], - {'help': "sets tunable for a profile", + {'help': "Sets tunables for a profile. Example: '-t fsize=100,pg_id=7'", + 'metavar': 'T1=VAL[,T2=VAL ...]', 'dest': "tunables", 'default': None, 'type': decode_tunables}), - NO_PROMISCUOUS: ArgumentPack(['--no_prom'], - {'help': "sets port promiscuous off", + {'help': "Sets port promiscuous off", 'dest': "prom", 'default': None, 'action': "store_false"}), - PORT_LIST: ArgumentPack(['--port', '-p'], {"nargs": '+', 'dest':'ports', @@ -465,4 +463,4 @@ def gen_parser(stateless_client, op_name, description, *args): if __name__ == "__main__": - pass \ No newline at end of file + pass diff --git a/scripts/stl/burst_3st_1000pkt.py b/scripts/stl/burst_3st_1000pkt.py index 8fcdca57..88a30c84 100644 --- a/scripts/stl/burst_3st_1000pkt.py +++ b/scripts/stl/burst_3st_1000pkt.py @@ -10,27 +10,27 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) base_pkt1 = Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025) base_pkt2 = Ether()/IP(src="16.0.0.3",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' - return STLProfile( [ STLStream( isg = 10.0, # star in delay + return STLProfile( [ STLStream( isg = 10.0, # start in delay name ='S0', packet = STLPktBuilder(pkt = base_pkt/pad), mode = STLTXSingleBurst( pps = 10, total_pkts = self.burst_size), next = 'S1'), # point to next stream - STLStream( self_start = False, # stream is disabled enable trow S0 + STLStream( self_start = False, # Stream is disabled. Will run because it is pointed from S0 name ='S1', packet = STLPktBuilder(pkt = base_pkt1/pad), mode = STLTXSingleBurst( pps = 10, total_pkts = self.burst_size), next = 'S2' ), - STLStream( self_start = False, # stream is disabled enable trow S0 + STLStream( self_start = False, # Stream is disabled. Will run because it is pointed from S1 name ='S2', packet = STLPktBuilder(pkt = base_pkt2/pad), mode = STLTXSingleBurst( pps = 10, total_pkts = self.burst_size ) diff --git a/scripts/stl/burst_3st_600pkt.py b/scripts/stl/burst_3st_600pkt.py index 978c8920..b81f256b 100644 --- a/scripts/stl/burst_3st_600pkt.py +++ b/scripts/stl/burst_3st_600pkt.py @@ -9,27 +9,27 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) base_pkt1 = Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025) base_pkt2 = Ether()/IP(src="16.0.0.3",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' - return STLProfile( [ STLStream( isg = 10.0, # star in delay + return STLProfile( [ STLStream( isg = 10.0, # start in delay name ='S0', packet = STLPktBuilder(pkt = base_pkt/pad), mode = STLTXSingleBurst( pps = 10, total_pkts = 10), next = 'S1'), # point to next stream - STLStream( self_start = False, # stream is disabled enable trow S0 + STLStream( self_start = False, # Stream is disabled. Will run because it is pointed from S0 name ='S1', packet = STLPktBuilder(pkt = base_pkt1/pad), mode = STLTXSingleBurst( pps = 10, total_pkts = 20), next = 'S2' ), - STLStream( self_start = False, # stream is disabled enable trow S0 + STLStream( self_start = False, # Stream is disabled. Will run because it is pointed from S1 name ='S2', packet = STLPktBuilder(pkt = base_pkt2/pad), mode = STLTXSingleBurst( pps = 10, total_pkts = 30 ) diff --git a/scripts/stl/burst_3st_loop_x_times.py b/scripts/stl/burst_3st_loop_x_times.py index 175b8315..ec217e9f 100644 --- a/scripts/stl/burst_3st_loop_x_times.py +++ b/scripts/stl/burst_3st_loop_x_times.py @@ -9,27 +9,27 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) base_pkt1 = Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025) base_pkt2 = Ether()/IP(src="16.0.0.3",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' - return STLProfile( [ STLStream( isg = 10.0, # star in delay + return STLProfile( [ STLStream( isg = 10.0, # start in delay name ='S0', packet = STLPktBuilder(pkt = base_pkt/pad), mode = STLTXSingleBurst( pps = 10, total_pkts = 1), next = 'S1'), # point to next stream - STLStream( self_start = False, # stream is disabled enable trow S0 + STLStream( self_start = False, # Stream is disabled. Will run because it is pointed from S0 name ='S1', packet = STLPktBuilder(pkt = base_pkt1/pad), mode = STLTXSingleBurst( pps = 10, total_pkts = 2), next = 'S2' ), - STLStream( self_start = False, # stream is disabled enable trow S0 + STLStream( self_start = False, # Stream is disabled. Will run because it is pointed from S1 name ='S2', packet = STLPktBuilder(pkt = base_pkt2/pad), mode = STLTXSingleBurst( pps = 10, total_pkts = 3 ), diff --git a/scripts/stl/flow_stats.py b/scripts/stl/flow_stats.py index cbb5ac21..a50ba848 100644 --- a/scripts/stl/flow_stats.py +++ b/scripts/stl/flow_stats.py @@ -1,21 +1,29 @@ from trex_stl_lib.api import * -import os - -# stream from pcap file. continues pps 10 in sec -CP = os.path.join(os.path.dirname(__file__)) class STLS1(object): - - def get_streams (self, direction = 0, **kwargs): - return [STLStream(packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_64B_no_crc.pcap")), # path relative to pwd - mode = STLTXCont(pps=1000), - flow_stats = STLFlowStats(pg_id = 7)), - - STLStream(packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_594B_no_crc.pcap")), # path relative to pwd - mode = STLTXCont(pps=5000), - flow_stats = STLFlowStats(pg_id = 12)) + """ + Create flow stat stream of UDP packet. + Can specify using tunables the packet length (fsize) and packet group id (pg_id) + """ + def __init__ (self): + self.fsize = 64 + self.pg_id = 0 + + def _create_stream (self): + size = self.fsize - 4; # HW will add 4 bytes ethernet CRC + base_pkt = Ether() / IP(src = "16.0.0.1", dst = "48.0.0.1") / UDP(dport = 12, sport = 1025) + pad = max(0, size - len(base_pkt)) * 'x' + pkt = STLPktBuilder(pkt = base_pkt/pad) + + return [STLStream(packet = pkt, + mode = STLTXCont(pps=1), + flow_stats = STLFlowStats(pg_id = self.pg_id)) ] + def get_streams (self, fsize = 64, pg_id = 7, **kwargs): + self.fsize = fsize + self.pg_id = pg_id + return self._create_stream() # dynamic load - used for trex console or simulator def register(): diff --git a/scripts/stl/flow_stats_latency.py b/scripts/stl/flow_stats_latency.py index e1541272..8460fcfc 100644 --- a/scripts/stl/flow_stats_latency.py +++ b/scripts/stl/flow_stats_latency.py @@ -1,21 +1,33 @@ from trex_stl_lib.api import * -import os - -# stream from pcap file. continues pps 10 in sec -CP = os.path.join(os.path.dirname(__file__)) class STLS1(object): - - def get_streams (self, direction = 0, **kwargs): - return [STLStream(packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_64B_no_crc.pcap")), # path relative to pwd - mode = STLTXCont(pps=1000), - flow_stats = STLFlowLatencyStats(pg_id = 1 + kwargs['port_id'])), - - STLStream(packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_594B_no_crc.pcap")), # path relative to pwd - mode = STLTXCont(pps=5000), - flow_stats = STLFlowLatencyStats(pg_id = 50 + kwargs['port_id'])) + """ + Create flow stat latency stream of UDP packet. + Can specify using tunables the packet length (fsize) and packet group id (pg_id) + Since we can't have two latency streams with same pg_id, in order to be able to start this profile + on more than one port, we add port_id to the pg_id + """ + + def __init__ (self): + self.fsize = 64 + self.pg_id = 0 + + def _create_stream (self): + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS + base_pkt = Ether() / IP(src = "16.0.0.1", dst = "48.0.0.1") / UDP(dport = 12, sport = 1025) + pad = max(0, size - len(base_pkt)) * 'x' + pkt = STLPktBuilder(pkt = base_pkt/pad) + + return [STLStream(packet = pkt, + mode = STLTXCont(pps=1), + flow_stats = STLFlowLatencyStats(pg_id = self.pg_id)) ] + def get_streams (self, fsize = 64, pg_id = 7, **kwargs): + self.fsize = fsize + self.pg_id = pg_id + kwargs['port_id'] + return self._create_stream() + # dynamic load - used for trex console or simulator def register(): diff --git a/scripts/stl/imix.py b/scripts/stl/imix.py index 82edbfa5..c9b1ff17 100644 --- a/scripts/stl/imix.py +++ b/scripts/stl/imix.py @@ -18,7 +18,7 @@ class STLImix(object): def create_stream (self, size, pps, isg, vm ): - # create a base packet and pad it to size + # Create base packet and pad it to size base_pkt = Ether()/IP()/UDP() pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/multi_burst_2st_1000pkt.py b/scripts/stl/multi_burst_2st_1000pkt.py index 1a43ae96..fe4b4eac 100644 --- a/scripts/stl/multi_burst_2st_1000pkt.py +++ b/scripts/stl/multi_burst_2st_1000pkt.py @@ -10,20 +10,20 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) base_pkt1 = Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' - return STLProfile( [ STLStream( isg = 10.0, # star in delay + return STLProfile( [ STLStream( isg = 10.0, # start in delay name ='S0', packet = STLPktBuilder(pkt = base_pkt/pad), mode = STLTXSingleBurst( pps = 10, total_pkts = self.burst_size), next = 'S1'), # point to next stream - STLStream( self_start = False, # stream is disabled enable trow S0 + STLStream( self_start = False, # Stream is disabled. Will run because it is pointed from S0 name ='S1', packet = STLPktBuilder(pkt = base_pkt1/pad), mode = STLTXMultiBurst( pps = 1000,pkts_per_burst = 4,ibg = 1000000.0,count = 5) diff --git a/scripts/stl/simple_3st.py b/scripts/stl/simple_3st.py index 8979057c..ae388f13 100644 --- a/scripts/stl/simple_3st.py +++ b/scripts/stl/simple_3st.py @@ -8,15 +8,15 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) base_pkt1 = Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025) base_pkt2 = Ether()/IP(src="16.0.0.3",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' - return STLProfile( [ STLStream( isg = 1.0, # star in delay in usec + return STLProfile( [ STLStream( isg = 1.0, # start in delay in usec packet = STLPktBuilder(pkt = base_pkt/pad), mode = STLTXCont( pps = 10), ), diff --git a/scripts/stl/udp_1pkt.py b/scripts/stl/udp_1pkt.py index 13516ecd..f2601d79 100644 --- a/scripts/stl/udp_1pkt.py +++ b/scripts/stl/udp_1pkt.py @@ -18,8 +18,8 @@ class STLS1(object): return t[self.mode] def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = self.create_pkt_base () diff --git a/scripts/stl/udp_1pkt_1mac.py b/scripts/stl/udp_1pkt_1mac.py index 4adffd7a..ade5b592 100644 --- a/scripts/stl/udp_1pkt_1mac.py +++ b/scripts/stl/udp_1pkt_1mac.py @@ -8,8 +8,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/udp_1pkt_1mac_override.py b/scripts/stl/udp_1pkt_1mac_override.py index 04700420..410c2630 100644 --- a/scripts/stl/udp_1pkt_1mac_override.py +++ b/scripts/stl/udp_1pkt_1mac_override.py @@ -10,8 +10,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS # Ether(src="00:bb:12:34:56:01") this will tell TRex to take the src-mac from packet and not from config file base_pkt = Ether(src="00:bb:12:34:56:01")/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) diff --git a/scripts/stl/udp_1pkt_1mac_step.py b/scripts/stl/udp_1pkt_1mac_step.py index 1e5e4bd8..69a84d67 100644 --- a/scripts/stl/udp_1pkt_1mac_step.py +++ b/scripts/stl/udp_1pkt_1mac_step.py @@ -9,8 +9,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/udp_1pkt_mac.py b/scripts/stl/udp_1pkt_mac.py index 598e2074..93376aff 100644 --- a/scripts/stl/udp_1pkt_mac.py +++ b/scripts/stl/udp_1pkt_mac.py @@ -9,8 +9,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/udp_1pkt_mac_mask1.py b/scripts/stl/udp_1pkt_mac_mask1.py index efb45da7..9a4862a9 100644 --- a/scripts/stl/udp_1pkt_mac_mask1.py +++ b/scripts/stl/udp_1pkt_mac_mask1.py @@ -9,8 +9,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/udp_1pkt_mac_mask2.py b/scripts/stl/udp_1pkt_mac_mask2.py index b95a32e3..748ddbb1 100644 --- a/scripts/stl/udp_1pkt_mac_mask2.py +++ b/scripts/stl/udp_1pkt_mac_mask2.py @@ -9,8 +9,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/udp_1pkt_mac_mask3.py b/scripts/stl/udp_1pkt_mac_mask3.py index 7a5d2864..f3593ccb 100644 --- a/scripts/stl/udp_1pkt_mac_mask3.py +++ b/scripts/stl/udp_1pkt_mac_mask3.py @@ -9,8 +9,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/udp_1pkt_mac_mask5.py b/scripts/stl/udp_1pkt_mac_mask5.py index 75f9bbf1..901c2d98 100644 --- a/scripts/stl/udp_1pkt_mac_mask5.py +++ b/scripts/stl/udp_1pkt_mac_mask5.py @@ -9,8 +9,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/udp_1pkt_mac_step.py b/scripts/stl/udp_1pkt_mac_step.py index 0ebd035d..a2444905 100644 --- a/scripts/stl/udp_1pkt_mac_step.py +++ b/scripts/stl/udp_1pkt_mac_step.py @@ -9,8 +9,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/udp_1pkt_range_clients.py b/scripts/stl/udp_1pkt_range_clients.py index 9bd3c335..f1fc57f4 100644 --- a/scripts/stl/udp_1pkt_range_clients.py +++ b/scripts/stl/udp_1pkt_range_clients.py @@ -16,8 +16,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether(src="00:00:dd:dd:00:01")/IP(src="55.55.1.1",dst="58.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/udp_1pkt_range_clients_split.py b/scripts/stl/udp_1pkt_range_clients_split.py index a8c71c0a..9bf09ba4 100644 --- a/scripts/stl/udp_1pkt_range_clients_split.py +++ b/scripts/stl/udp_1pkt_range_clients_split.py @@ -16,8 +16,8 @@ class STLS1(object): def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether(src="00:00:dd:dd:00:01")/IP(src="55.55.1.1",dst="58.0.0.1")/UDP(dport=12,sport=1025) pad = max(0, size - len(base_pkt)) * 'x' diff --git a/scripts/stl/udp_1pkt_range_clients_split_garp.py b/scripts/stl/udp_1pkt_range_clients_split_garp.py index d7f48ed7..4bad8afd 100644 --- a/scripts/stl/udp_1pkt_range_clients_split_garp.py +++ b/scripts/stl/udp_1pkt_range_clients_split_garp.py @@ -10,7 +10,7 @@ class STLS1(object): self.num_clients =3000; # max is 16bit def create_stream (self): - # create a base packet and pad it to size + # Create base packet and pad it to size base_pkt = Ether(src="00:00:dd:dd:00:01",dst="ff:ff:ff:ff:ff:ff")/ARP(psrc="55.55.1.1",hwsrc="00:00:dd:dd:00:01", hwdst="00:00:dd:dd:00:01", pdst="55.55.1.1") vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src", min_value=1, max_value=self.num_clients, size=2, op="inc"), diff --git a/scripts/stl/udp_1pkt_src_ip_split.py b/scripts/stl/udp_1pkt_src_ip_split.py index 778ccf54..48e02433 100644 --- a/scripts/stl/udp_1pkt_src_ip_split.py +++ b/scripts/stl/udp_1pkt_src_ip_split.py @@ -9,8 +9,8 @@ class STLS1(object): self.fsize =64; def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) diff --git a/scripts/stl/udp_1pkt_src_ip_split_latency.py b/scripts/stl/udp_1pkt_src_ip_split_latency.py index 2d81f756..4b297d70 100644 --- a/scripts/stl/udp_1pkt_src_ip_split_latency.py +++ b/scripts/stl/udp_1pkt_src_ip_split_latency.py @@ -16,8 +16,8 @@ class STLS1(object): def create_stream (self, dir,port_id): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS if dir==0: src_ip="16.0.0.1" diff --git a/scripts/stl/udp_1pkt_tuple_gen.py b/scripts/stl/udp_1pkt_tuple_gen.py index 4e9ab12d..733d511b 100644 --- a/scripts/stl/udp_1pkt_tuple_gen.py +++ b/scripts/stl/udp_1pkt_tuple_gen.py @@ -3,7 +3,7 @@ from trex_stl_lib.api import * class STLS1(object): def create_stream (self, packet_len): - # create a base packet and pad it to size + # Create base packet and pad it to size base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) diff --git a/scripts/stl/udp_1pkt_tuple_gen_split.py b/scripts/stl/udp_1pkt_tuple_gen_split.py index e7a33b22..cc9eb5fc 100644 --- a/scripts/stl/udp_1pkt_tuple_gen_split.py +++ b/scripts/stl/udp_1pkt_tuple_gen_split.py @@ -9,8 +9,8 @@ class STLS1(object): self.fsize =64; def create_stream (self): - # create a base packet and pad it to size - size = self.fsize - 4; # no FCS + # Create base packet and pad it to size + size = self.fsize - 4; # HW will add 4 bytes ethernet FCS base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025) diff --git a/scripts/stl/udp_3pkt_pcap.py b/scripts/stl/udp_3pkt_pcap.py index 19ff46bc..2983f9a1 100644 --- a/scripts/stl/udp_3pkt_pcap.py +++ b/scripts/stl/udp_3pkt_pcap.py @@ -9,19 +9,19 @@ class STLS1(object): def create_stream (self): - return STLProfile( [ STLStream( isg = 10.0, # star in delay + return STLProfile( [ STLStream( isg = 10.0, # start in delay name ='S0', packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_64B_no_crc.pcap")), mode = STLTXSingleBurst( pps = 10, total_pkts = 10), next = 'S1'), # point to next stream - STLStream( self_start = False, # stream is disabled enable trow S0 + STLStream( self_start = False, # Stream is disabled. Will run because it is pointed from S0 name ='S1', packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_594B_no_crc.pcap")), mode = STLTXSingleBurst( pps = 10, total_pkts = 20), next = 'S2' ), - STLStream( self_start = False, # stream is disabled enable trow S0 + STLStream( self_start = False, # Stream is disabled. Will run because it is pointed from S1 name ='S2', packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_1518B_no_crc.pcap")), mode = STLTXSingleBurst( pps = 10, total_pkts = 30 ) -- cgit 1.2.3-korg From 365826c5db225f21283c48eebc8de62b89fbfa24 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Tue, 21 Jun 2016 17:35:32 +0300 Subject: fix i40e Intel latency issue using 2 Qset and BW limit to 99.9% see more trex-214 issue --- src/dpdk22/drivers/net/i40e/i40e_ethdev.c | 54 +++++++++++++++++++++++++++++++ src/dpdk22/drivers/net/i40e/i40e_ethdev.h | 1 + src/dpdk22/drivers/net/i40e/i40e_rxtx.c | 37 +++++++++++++++++++-- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/dpdk22/drivers/net/i40e/i40e_ethdev.c b/src/dpdk22/drivers/net/i40e/i40e_ethdev.c index ae195683..b73eedf1 100644 --- a/src/dpdk22/drivers/net/i40e/i40e_ethdev.c +++ b/src/dpdk22/drivers/net/i40e/i40e_ethdev.c @@ -3868,6 +3868,26 @@ i40e_update_default_filter_setting(struct i40e_vsi *vsi) return i40e_vsi_add_mac(vsi, &filter); } +static int +i40e_vsi_update_tc_max_bw(struct i40e_vsi *vsi, u16 credit){ + struct i40e_hw *hw = I40E_VSI_TO_HW(vsi); + int ret; + + if (!vsi->seid) { + PMD_DRV_LOG(ERR, "seid not valid"); + return -EINVAL; + } + + ret = i40e_aq_config_vsi_bw_limit(hw, vsi->seid, credit,0, NULL); + if (ret != I40E_SUCCESS) { + PMD_DRV_LOG(ERR, "Failed to configure TC BW"); + return ret; + } + return (0); +} + + + #define I40E_3_BIT_MASK 0x7 /* * i40e_vsi_get_bw_config - Query VSI BW Information @@ -4426,6 +4446,40 @@ i40e_pf_setup(struct i40e_pf *pf) } pf->main_vsi = vsi; + +#define LOW_LATENCY_WORKAROUND +#ifdef LOW_LATENCY_WORKAROUND + + /* + Workaround for low latency issue. + It seems RR does not work as expected both from same QSet and from different QSet + Quanta could be very high and this creates very high latency, especially with long packet size (9K) + This is a workaround limit the main (bulk) VSI to 99% of the BW and by that support low latency (suggested by Intel) + ETS with with strict priority and 127 credit does not work . + + */ + + if (hw->phy.link_info.link_speed == I40E_LINK_SPEED_10GB) { + i40e_vsi_update_tc_max_bw(vsi,199); + }else{ + if (hw->phy.link_info.link_speed == I40E_LINK_SPEED_40GB) { + i40e_vsi_update_tc_max_bw(vsi,799); + }else{ + PMD_DRV_LOG(ERR, "Unknown phy speed %d",hw->phy.link_info.link_speed); + } + } + + /* add for low latency a new VSI for Queue set */ + vsi = i40e_vsi_setup(pf, I40E_VSI_VMDQ2, vsi, 0); + if (!vsi) { + PMD_DRV_LOG(ERR, "Setup of low latency vsi failed"); + return I40E_ERR_NOT_READY; + } + + pf->ll_vsi = vsi; + +#endif + /* Configure filter control */ memset(&settings, 0, sizeof(settings)); if (hw->func_caps.rss_table_size == ETH_RSS_RETA_SIZE_128) diff --git a/src/dpdk22/drivers/net/i40e/i40e_ethdev.h b/src/dpdk22/drivers/net/i40e/i40e_ethdev.h index 1f9792b3..44082dfa 100644 --- a/src/dpdk22/drivers/net/i40e/i40e_ethdev.h +++ b/src/dpdk22/drivers/net/i40e/i40e_ethdev.h @@ -396,6 +396,7 @@ TAILQ_HEAD(i40e_mirror_rule_list, i40e_mirror_rule); struct i40e_pf { struct i40e_adapter *adapter; /* The adapter this PF associate to */ struct i40e_vsi *main_vsi; /* pointer to main VSI structure */ + struct i40e_vsi * ll_vsi; uint16_t mac_seid; /* The seid of the MAC of this PF */ uint16_t main_vsi_seid; /* The seid of the main VSI */ uint16_t max_num_vsi; diff --git a/src/dpdk22/drivers/net/i40e/i40e_rxtx.c b/src/dpdk22/drivers/net/i40e/i40e_rxtx.c index 39d94eca..d3ef00f8 100644 --- a/src/dpdk22/drivers/net/i40e/i40e_rxtx.c +++ b/src/dpdk22/drivers/net/i40e/i40e_rxtx.c @@ -1923,6 +1923,31 @@ i40e_xmit_pkts_simple(void *tx_queue, return nb_tx; } + +static struct i40e_vsi* +i40e_pf_tx_get_vsi_by_qindex(struct i40e_pf *pf, uint16_t queue_idx) +{ + /* the queue in MAIN VSI range */ + if (queue_idx == pf->dev_data->nb_tx_queues-1) { + return pf->ll_vsi; + } + + if (queue_idx < pf->dev_data->nb_tx_queues) + return pf->main_vsi; + + + queue_idx -= pf->main_vsi->nb_qps; + + /* queue_idx is greater than VMDQ VSIs range */ + if (queue_idx > pf->nb_cfg_vmdq_vsi * pf->vmdq_nb_qps - 1) { + PMD_INIT_LOG(ERR, "queue_idx out of range. VMDQ configured?"); + return NULL; + } + + return pf->vmdq[queue_idx / pf->vmdq_nb_qps].vsi; +} + + /* * Find the VSI the queue belongs to. 'queue_idx' is the queue index * application used, which assume having sequential ones. But from driver's @@ -2314,6 +2339,8 @@ i40e_dev_rx_descriptor_done(void *rx_queue, uint16_t offset) return ret; } +#define LOW_LATENCY_WORKAROUND + int i40e_dev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx, @@ -2334,8 +2361,14 @@ i40e_dev_tx_queue_setup(struct rte_eth_dev *dev, struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private); vsi = &vf->vsi; - } else - vsi = i40e_pf_get_vsi_by_qindex(pf, queue_idx); + } else{ + #ifdef LOW_LATENCY_WORKAROUND + vsi = i40e_pf_tx_get_vsi_by_qindex(pf, queue_idx); + #else + vsi = i40e_pf_get_vsi_by_qindex(pf, queue_idx); + #endif + } + if (vsi == NULL) { PMD_DRV_LOG(ERR, "VSI is NULL, or queue index (%u) " -- cgit 1.2.3-korg From ddbed4330eee8b4c40d8ca83535dbf5ac69bb81f Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Tue, 21 Jun 2016 18:17:55 +0300 Subject: api: add passing of additional arguments to TRex --- scripts/automation/regression/trex_unit_test.py | 6 +++++- scripts/automation/trex_control_plane/server/trex_server.py | 8 +++++--- .../automation/trex_control_plane/stf/trex_stf_lib/trex_client.py | 7 ++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/scripts/automation/regression/trex_unit_test.py b/scripts/automation/regression/trex_unit_test.py index 11902a1a..915cd682 100755 --- a/scripts/automation/regression/trex_unit_test.py +++ b/scripts/automation/regression/trex_unit_test.py @@ -146,6 +146,9 @@ class CTRexTestConfiguringPlugin(Plugin): parser.add_option('--debug-image', action="store_true", default = False, dest="debug_image", help="Flag that specifies to use t-rex-64-debug as TRex executable.") + parser.add_option('--trex-args', action='store', default = '', + dest="trex_args", + help="Additional TRex arguments (--no-watchdog etc.).") def configure(self, options, conf): @@ -186,7 +189,8 @@ class CTRexTestConfiguringPlugin(Plugin): if not self.no_daemon: CTRexScenario.trex = CTRexClient(trex_host = self.configuration.trex['trex_name'], verbose = self.json_verbose, - debug_image = options.debug_image) + debug_image = options.debug_image, + trex_args = options.trex_args) if not CTRexScenario.trex.check_master_connectivity(): print('Could not connect to master daemon') sys.exit(-1) diff --git a/scripts/automation/trex_control_plane/server/trex_server.py b/scripts/automation/trex_control_plane/server/trex_server.py index 091b729b..9fe7d70b 100755 --- a/scripts/automation/trex_control_plane/server/trex_server.py +++ b/scripts/automation/trex_control_plane/server/trex_server.py @@ -310,7 +310,7 @@ class CTRexServer(object): return False - def start_trex(self, trex_cmd_options, user, block_to_success = True, timeout = 40, stateless = False, debug_image = False): + def start_trex(self, trex_cmd_options, user, block_to_success = True, timeout = 40, stateless = False, debug_image = False, trex_args = ''): with self.start_lock: logger.info("Processing start_trex() command.") if self.is_reserved(): @@ -323,7 +323,7 @@ class CTRexServer(object): return Fault(-13, '') # raise at client TRexInUseError try: - server_cmd_data = self.generate_run_cmd(stateless = stateless, debug_image = debug_image, **trex_cmd_options) + server_cmd_data = self.generate_run_cmd(stateless = stateless, debug_image = debug_image, trex_args = trex_args, **trex_cmd_options) self.zmq_monitor.first_dump = True self.trex.start_trex(self.TREX_PATH, server_cmd_data) logger.info("TRex session has been successfully initiated.") @@ -413,7 +413,7 @@ class CTRexServer(object): return self.trex.get_running_info() - def generate_run_cmd (self, iom = 0, export_path="/tmp/trex.txt", stateless = False, debug_image = False, **kwargs): + def generate_run_cmd (self, iom = 0, export_path="/tmp/trex.txt", stateless = False, debug_image = False, trex_args = '', **kwargs): """ generate_run_cmd(self, iom, export_path, kwargs) -> str Generates a custom running command for the kick-off of the TRex traffic generator. @@ -450,6 +450,8 @@ class CTRexServer(object): continue else: trex_cmd_options += (dash + '{k} {val}'.format( k = tmp_key, val = value )) + if trex_args: + trex_cmd_options += ' %s' % trex_args if not stateless: if 'f' not in kwargs: diff --git a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py index 57d19459..d3362d0d 100755 --- a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py +++ b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py @@ -40,7 +40,7 @@ class CTRexClient(object): This class defines the client side of the RESTfull interaction with TRex """ - def __init__(self, trex_host, max_history_size = 100, filtered_latency_amount = 0.001, trex_daemon_port = 8090, master_daemon_port = 8091, trex_zmq_port = 4500, verbose = False, debug_image = False): + def __init__(self, trex_host, max_history_size = 100, filtered_latency_amount = 0.001, trex_daemon_port = 8090, master_daemon_port = 8091, trex_zmq_port = 4500, verbose = False, debug_image = False, trex_args = ''): """ Instantiate a TRex client object, and connecting it to listening daemon-server @@ -97,6 +97,7 @@ class CTRexClient(object): self.trex_server_path = "http://{hostname}:{port}/".format( hostname = self.trex_host, port = trex_daemon_port ) self.server = jsonrpclib.Server(self.trex_server_path, history = self.history) self.debug_image = debug_image + self.trex_args = trex_args def add (self, x, y): @@ -160,7 +161,7 @@ class CTRexClient(object): self.result_obj.clear_results() try: issue_time = time.time() - retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, False, self.debug_image) + retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, self.debug_image, self.trex_args) except AppError as err: self._handle_AppError_exception(err.args[0]) except ProtocolError: @@ -206,7 +207,7 @@ class CTRexClient(object): """ try: user = user or self.__default_user - retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, True, self.debug_image) + retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, True, self.debug_image, self.trex_args) except AppError as err: self._handle_AppError_exception(err.args[0]) except ProtocolError: -- cgit 1.2.3-korg From a5d8474b3f5598561298efc6e696378f584011c9 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Wed, 22 Jun 2016 00:14:17 +0300 Subject: typo at last commit --- scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py index d3362d0d..a13fe31f 100755 --- a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py +++ b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py @@ -161,7 +161,7 @@ class CTRexClient(object): self.result_obj.clear_results() try: issue_time = time.time() - retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, self.debug_image, self.trex_args) + retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, False, self.debug_image, self.trex_args) except AppError as err: self._handle_AppError_exception(err.args[0]) except ProtocolError: -- cgit 1.2.3-korg From 9f641b7c0b7d99cf868f563b83cb047ced8cb275 Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Wed, 22 Jun 2016 10:58:17 +0300 Subject: adding flow stat profiles to simulator tests --- .../regression/functional_tests/stl_basic_tests.py | 2 ++ scripts/exp/flow_stats.pcap | Bin 0 -> 100 bytes scripts/exp/flow_stats_latency.pcap | Bin 0 -> 136 bytes src/bp_sim.cpp | 28 ++++++++++----------- src/flow_stat.cpp | 10 ++++++++ 5 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 scripts/exp/flow_stats.pcap create mode 100644 scripts/exp/flow_stats_latency.pcap diff --git a/scripts/automation/regression/functional_tests/stl_basic_tests.py b/scripts/automation/regression/functional_tests/stl_basic_tests.py index 863307f1..a4e28ca9 100644 --- a/scripts/automation/regression/functional_tests/stl_basic_tests.py +++ b/scripts/automation/regression/functional_tests/stl_basic_tests.py @@ -201,6 +201,8 @@ class CStlBasic_Test(functional_general_test.CGeneralFunctional_Test): ["multi_burst_2st_1000pkt.py","-m 1 -l 100",True], ["pcap.py", "-m 1", True], ["pcap_with_vm.py", "-m 1", True], + ["flow_stats.py", "-m 1 -l 1", True], + ["flow_stats_latency.py", "-m 1 -l 1", True], # YAML test ["yaml/burst_1000_pkt.yaml","-m 1 -l 100",True], diff --git a/scripts/exp/flow_stats.pcap b/scripts/exp/flow_stats.pcap new file mode 100644 index 00000000..267eeaab Binary files /dev/null and b/scripts/exp/flow_stats.pcap differ diff --git a/scripts/exp/flow_stats_latency.pcap b/scripts/exp/flow_stats_latency.pcap new file mode 100644 index 00000000..89d27701 Binary files /dev/null and b/scripts/exp/flow_stats_latency.pcap differ diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index f4eb6f7e..f9e96b6b 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -4991,29 +4991,27 @@ int CErfIFStl::send_sl_node(CGenNodeStateless *node_sl) { bool is_const = false; if (m) { is_const = true; + rte_pktmbuf_refcnt_update(m,1); }else{ m=node_sl->alloc_node_with_vm(); assert(m); } - if (node_sl->is_stat_needed()) { + if (node_sl->is_stat_needed() && (node_sl->get_stat_hw_id() >= MAX_FLOW_STATS) ) { + /* latency packet. flow stat without latency handled like normal packet in simulation */ uint16_t hw_id = node_sl->get_stat_hw_id(); - if (hw_id >= MAX_FLOW_STATS) { - rte_mbuf_t *mi; - struct flow_stat_payload_header *fsp_head; - mi = node_sl->alloc_flow_stat_mbuf(m, fsp_head, is_const); - fsp_head->seq = 0x12345678; - fsp_head->hw_id = hw_id - MAX_FLOW_STATS; - fsp_head->magic = FLOW_STAT_PAYLOAD_MAGIC; - fsp_head->time_stamp = 0x8899aabbccddeeff; - fill_raw_packet(m,(CGenNode *)node_sl,dir); - rte_pktmbuf_free(mi); - } + rte_mbuf_t *mi; + struct flow_stat_payload_header *fsp_head; + mi = node_sl->alloc_flow_stat_mbuf(m, fsp_head, is_const); + fsp_head->seq = 0x12345678; + fsp_head->hw_id = hw_id - MAX_FLOW_STATS; + fsp_head->magic = FLOW_STAT_PAYLOAD_MAGIC; + fsp_head->time_stamp = 0x8899aabbccddeeff; + fill_raw_packet(mi, (CGenNode *)node_sl, dir); + rte_pktmbuf_free(mi); } else { fill_raw_packet(m,(CGenNode *)node_sl,dir); - if (! is_const) { - rte_pktmbuf_free(m); - } + rte_pktmbuf_free(m); } } /* check that we have mbuf */ diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp index 366c3aa8..cb7a1bf9 100644 --- a/src/flow_stat.cpp +++ b/src/flow_stat.cpp @@ -472,6 +472,16 @@ CFlowStatRuleMgr::CFlowStatRuleMgr() { CFlowStatRuleMgr::~CFlowStatRuleMgr() { delete m_parser; +#ifdef TREX_SIM + // In simulator, nobody handles the messages to RX, so need to free them to have clean valgrind run. + if (m_ring_to_rx) { + CGenNode *msg = NULL; + while (! m_ring_to_rx->isEmpty()) { + m_ring_to_rx->Dequeue(msg); + delete msg; + } + } +#endif } void CFlowStatRuleMgr::create() { -- cgit 1.2.3-korg From 9a1356bc05d663555b9b62971aff6219e17a767c Mon Sep 17 00:00:00 2001 From: imarom Date: Tue, 21 Jun 2016 09:54:04 +0300 Subject: FLOW_STATS: extract start_stream from the compiler to start_traffic --- .../trex_control_plane/common/text_opts.py | 3 + .../stl/trex_stl_lib/utils/text_opts.py | 3 + src/stateless/cp/trex_stateless_port.cpp | 73 ++++++++++++++++++++-- src/stateless/cp/trex_streams_compiler.cpp | 31 +++++---- src/stateless/cp/trex_streams_compiler.h | 4 +- 5 files changed, 91 insertions(+), 23 deletions(-) diff --git a/scripts/automation/trex_control_plane/common/text_opts.py b/scripts/automation/trex_control_plane/common/text_opts.py index 78a0ab1f..ab0fd2f2 100755 --- a/scripts/automation/trex_control_plane/common/text_opts.py +++ b/scripts/automation/trex_control_plane/common/text_opts.py @@ -61,6 +61,9 @@ def format_time (t_sec): if t_sec < 0: return "infinite" + if t_sec == 0: + return "zero" + if t_sec < 1: # low numbers for unit in ['ms', 'usec', 'ns']: diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_opts.py index 7e0bf9e4..26e64dae 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_opts.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_opts.py @@ -61,6 +61,9 @@ def format_time (t_sec): if t_sec < 0: return "infinite" + if t_sec == 0: + return "zero" + if t_sec < 1: # low numbers for unit in ['ms', 'usec', 'ns']: diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 4dc3e449..d736d09e 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -87,6 +87,68 @@ protected: } }; +/************************************* + * Streams Feeder + * A class that holds a temporary + * clone of streams that can be + * manipulated + * + * this is a RAII object meant for + * graceful cleanup + ************************************/ +class StreamsFeeder { +public: + StreamsFeeder(TrexStatelessPort *port) { + + /* start pesimistic */ + m_success = false; + + /* fetch the original streams */ + port->get_object_list(m_in_streams); + + for (const TrexStream *in_stream : m_in_streams) { + TrexStream *out_stream = in_stream->clone(true); + + get_stateless_obj()->m_rx_flow_stat.start_stream(out_stream); + + m_out_streams.push_back(out_stream); + } + } + + void set_status(bool status) { + m_success = status; + } + + vector &get_streams() { + return m_out_streams; + } + + /** + * RAII + */ + ~StreamsFeeder() { + for (int i = 0; i < m_out_streams.size(); i++) { + TrexStream *out_stream = m_out_streams[i]; + TrexStream *in_stream = m_in_streams[i]; + + if (m_success) { + /* success path */ + get_stateless_obj()->m_rx_flow_stat.copy_state(out_stream, in_stream); + } else { + /* fail path */ + get_stateless_obj()->m_rx_flow_stat.stop_stream(out_stream); + } + delete out_stream; + } + } + +private: + vector m_in_streams; + vector m_out_streams; + bool m_success; +}; + + /*************************** * trex stateless port * @@ -193,10 +255,7 @@ TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration, /* caclulate the effective factor for DP */ double factor = calculate_effective_factor(mul, force); - /* fetch all the streams from the table */ - vector streams; - get_object_list(streams); - + StreamsFeeder feeder(this); /* compiler it */ std::vector compiled_objs; @@ -204,15 +263,19 @@ TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration, TrexStreamsCompiler compiler; bool rc = compiler.compile(m_port_id, - streams, + feeder.get_streams(), compiled_objs, get_dp_core_count(), factor, &fail_msg); + if (!rc) { + feeder.set_status(false); throw TrexException(fail_msg); } + feeder.set_status(true); + /* generate a message to all the relevant DP cores to start transmitting */ assert(m_pending_async_stop_event == TrexDpPortEvents::INVALID_ID); m_pending_async_stop_event = m_dp_events.create_event(new AsyncStopEvent()); diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index d2fe416a..e54c5f9c 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -382,7 +382,13 @@ TrexStreamsCompiler::compile(uint8_t port_id, assert(dp_core_count > 0); try { - return compile_internal(port_id,streams,objs,dp_core_count,factor,fail_msg); + return compile_internal(port_id, + streams, + objs, + dp_core_count, + factor, + fail_msg); + } catch (const TrexException &ex) { if (fail_msg) { *fail_msg = ex.what(); @@ -411,7 +417,6 @@ TrexStreamsCompiler::compile_internal(uint8_t por GraphNodeMap nodes; - /* compile checks */ pre_compile_check(streams, nodes); @@ -474,7 +479,7 @@ TrexStreamsCompiler::compile_on_single_core(uint8_t } /* compile all the streams */ - for (auto stream : streams) { + for (auto const stream : streams) { /* skip non-enabled streams */ if (!stream->m_enabled) { @@ -507,7 +512,7 @@ TrexStreamsCompiler::compile_on_all_cores(uint8_t } /* compile all the streams */ - for (auto stream : streams) { + for (auto const stream : streams) { /* skip non-enabled streams */ if (!stream->m_enabled) { @@ -527,7 +532,7 @@ TrexStreamsCompiler::compile_on_all_cores(uint8_t * */ void -TrexStreamsCompiler::compile_stream(TrexStream *stream, +TrexStreamsCompiler::compile_stream(const TrexStream *stream, double factor, uint8_t dp_core_count, std::vector &objs, @@ -543,31 +548,25 @@ TrexStreamsCompiler::compile_stream(TrexStream *stream, new_next_id = nodes.get(stream->m_next_stream_id)->m_compressed_stream_id; } - TrexStream *fixed_rx_flow_stat_stream = stream->clone(true); - - get_stateless_obj()->m_rx_flow_stat.start_stream(fixed_rx_flow_stat_stream); - // CFlowStatRuleMgr keeps state of the stream object. We duplicated the stream here (in order not - // change the packet kept in the stream). We want the state to be saved in the original stream. - get_stateless_obj()->m_rx_flow_stat.copy_state(fixed_rx_flow_stat_stream, stream); - - fixed_rx_flow_stat_stream->update_rate_factor(factor); + /* we clone because we alter the stream now */ + std::unique_ptr tmp_stream(stream->clone(true)); + tmp_stream->update_rate_factor(factor); /* can this stream be split to many cores ? */ if ( (dp_core_count == 1) || (!stream->is_splitable(dp_core_count)) ) { - compile_stream_on_single_core(fixed_rx_flow_stat_stream, + compile_stream_on_single_core(tmp_stream.get(), dp_core_count, objs, new_id, new_next_id); } else { - compile_stream_on_all_cores(fixed_rx_flow_stat_stream, + compile_stream_on_all_cores(tmp_stream.get(), dp_core_count, objs, new_id, new_next_id); } - delete fixed_rx_flow_stat_stream; } /** diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 0ce71b49..7e674364 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -141,7 +141,7 @@ private: bool all_continues); - void compile_stream(TrexStream *stream, + void compile_stream(const TrexStream *stream, double factor, uint8_t dp_core_count, std::vector &objs, @@ -244,7 +244,7 @@ public: } double get_factor_pps(double req_pps) const { - if ( (req_pps - m_fixed.m_pps) <= 0 ) { + if ( (req_pps - m_fixed.m_pps) < 0 ) { std::stringstream ss; ss << "current stream configuration enforces a minimum rate of '" << m_fixed.m_pps << "' pps"; throw TrexException(ss.str()); -- cgit 1.2.3-korg From 0e5be9c8cef5dfa5dd8f9dc4910d675aa006fafc Mon Sep 17 00:00:00 2001 From: imarom Date: Wed, 22 Jun 2016 14:13:31 +0300 Subject: REGRESSION: disable electric fence for now --- linux_dpdk/ws_main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py index dde94dc4..12a2fd89 100755 --- a/linux_dpdk/ws_main.py +++ b/linux_dpdk/ws_main.py @@ -714,7 +714,8 @@ def build_prog (bld, build_obj): debug_file_list=''; if not build_obj.isRelease (): #debug - debug_file_list +=ef_src.file_list(top) + #debug_file_list +=ef_src.file_list(top) + pass bld.objects( -- cgit 1.2.3-korg From 9249859480c57960905f37282e9fa8047cf17484 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Wed, 22 Jun 2016 14:22:54 +0300 Subject: STL Python API stats - add histogram key if it's absent --- scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py index 0ec98a0d..88a94865 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py @@ -1036,6 +1036,7 @@ class CLatencyStats(CTRexStats): output[int_pg_id]['latency']['total_min'] = min_val else: output[int_pg_id]['latency']['total_min'] = StatNotAvailable('total_min') + output[int_pg_id]['latency']['histogram'] = {} self.latest_stats = output return True -- cgit 1.2.3-korg From d97b7b7159c8c7f37f45cd2c98de042b1c7b5d69 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Wed, 22 Jun 2016 16:05:54 +0300 Subject: add latency regression test - XL710/82599 setups --- .../regression/stateless_tests/stl_rx_test.py | 131 ++++++++++++++++++++- 1 file changed, 129 insertions(+), 2 deletions(-) diff --git a/scripts/automation/regression/stateless_tests/stl_rx_test.py b/scripts/automation/regression/stateless_tests/stl_rx_test.py index 41eabd65..9e275118 100644 --- a/scripts/automation/regression/stateless_tests/stl_rx_test.py +++ b/scripts/automation/regression/stateless_tests/stl_rx_test.py @@ -3,6 +3,8 @@ from .stl_general_test import CStlGeneral_Test, CTRexScenario from trex_stl_lib.api import * import os, sys +ERROR_LATENCY_TOO_HIGH = 1 + class STLRX_Test(CStlGeneral_Test): """Tests for RX feature""" @@ -11,8 +13,8 @@ class STLRX_Test(CStlGeneral_Test): # self.skip('This test makes trex08 and trex09 sick. Fix those ASAP.') if self.is_virt_nics: self.skip('Skip this for virtual NICs for now') - per_driver_params = {"rte_vmxnet3_pmd": [1, 50, 1], "rte_ixgbe_pmd": [30, 5000, 1], "rte_i40e_pmd": [80, 5000, 1], - "rte_igb_pmd": [80, 500, 1], "rte_em_pmd": [1, 50, 1], "rte_virtio_pmd": [1, 50, 1]} + per_driver_params = {"rte_vmxnet3_pmd": [1, 50, 1,False], "rte_ixgbe_pmd": [30, 5000, 1,True,200,400], "rte_i40e_pmd": [80, 5000, 1,True,100,250], + "rte_igb_pmd": [80, 500, 1,False], "rte_em_pmd": [1, 50, 1,False], "rte_virtio_pmd": [1, 50, 1,False]} CStlGeneral_Test.setUp(self) assert 'bi' in CTRexScenario.stl_ports_map @@ -38,6 +40,15 @@ class STLRX_Test(CStlGeneral_Test): self.pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('Your_paylaod_comes_here')) self.large_pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('a'*1000)) + self.pkt_9k = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('a'*9000)) + + + drv_name=port_info['driver'] + self.latency_9k_enable=per_driver_params[drv_name][3] + + self.latency_9k_max_average = per_driver_params[drv_name][4] + self.latency_9k_max_latency = per_driver_params[drv_name][5] + @classmethod def tearDownClass(cls): @@ -48,6 +59,36 @@ class STLRX_Test(CStlGeneral_Test): CTRexScenario.stl_trex.connect() + def __verify_latency (self, latency_stats,max_latency,max_average): + + error=0; + err_latency = latency_stats['err_cntrs'] + latency = latency_stats['latency'] + + for key in err_latency : + error +=err_latency[key] + if error !=0 : + pprint.pprint(err_latency) + tmp = 'RX pkts ERROR - one of the error is on' + print(tmp) + #assert False, tmp + + if latency['average']> max_average: + pprint.pprint(latency_stats) + tmp = 'Average latency is too high {0} {1} '.format(latency['average'], max_average) + print(tmp) + return ERROR_LATENCY_TOO_HIGH + + if latency['total_max']> max_latency: + pprint.pprint(latency_stats) + tmp = 'Max latency is too high {0} {1} '.format(latency['total_max'], max_latency) + print(tmp) + return ERROR_LATENCY_TOO_HIGH + + return 0 + + + def __verify_flow (self, pg_id, total_pkts, pkt_len, stats): flow_stats = stats['flow_stats'].get(pg_id) latency_stats = stats['latency'].get(pg_id) @@ -216,6 +257,92 @@ class STLRX_Test(CStlGeneral_Test): assert False , '{0}'.format(e) + + def __test_9k_stream(self,pgid,ports,precet,max_latency,avg_latency,duration,pkt_size): + my_pg_id=pgid + s_ports=ports; + all_ports=list(CTRexScenario.stl_ports_map['map'].keys()); + if ports == None: + s_ports=all_ports + assert( type(s_ports)==list) + + stream_pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('a'*pkt_size)) + + try: + # reset all ports + self.c.reset(ports = all_ports) + + + for pid in s_ports: + s1 = STLStream(name = 'rx', + packet = self.pkt, + flow_stats = STLFlowLatencyStats(pg_id = my_pg_id+pid), + mode = STLTXCont(pps = 1000)) + + s2 = STLStream(name = 'bulk', + packet = stream_pkt, + mode = STLTXCont(percentage =precet)) + + + # add both streams to ports + self.c.add_streams([s1,s2], ports = [pid]) + + self.c.clear_stats() + + self.c.start(ports = s_ports,duration = duration) + self.c.wait_on_traffic(ports = s_ports,timeout = duration+10,rx_delay_ms = 100) + stats = self.c.get_stats() + + for pid in s_ports: + latency_stats = stats['latency'].get(my_pg_id+pid) + #pprint.pprint(latency_stats) + if self.__verify_latency (latency_stats,max_latency,avg_latency) !=0: + return (ERROR_LATENCY_TOO_HIGH); + + return 0 + + except STLError as e: + assert False , '{0}'.format(e) + + + + + + # check low latency when you have stream of 9K stream + def test_9k_stream(self): + + if self.latency_9k_enable == False: + print("SKIP") + return + + for i in range(0,5): + print("Iteration {0}".format(i)); + duration=random.randint(10, 70); + pgid=random.randint(1, 65000); + pkt_size=random.randint(1000, 9000); + all_ports = list(CTRexScenario.stl_ports_map['map'].keys()); + s_port=random.sample(all_ports, random.randint(1, len(all_ports)) ) + s_port=sorted(s_port) + error=1; + for j in range(0,5): + print(" {4} - duration {0} pgid {1} pkt_size {2} s_port {3} ".format(duration,pgid,pkt_size,s_port,j)); + if self.__test_9k_stream(pgid, + s_port,90, + self.latency_9k_max_latency, + self.latency_9k_max_average, + duration, + pkt_size)==0: + error=0; + break; + + if error: + assert False , "Latency too high" + else: + print("===>Iteration {0} PASS {1}".format(i,j)); + + + + # this test adds more and more latency streams and re-test with incremental def test_incremental_latency_streams (self): -- cgit 1.2.3-korg From 06b5ac67155c1c0bbe5d779755f9b3ff759cb8ad Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Wed, 22 Jun 2016 19:13:25 +0300 Subject: fix 9k regression test for XL710 DA2 NIC --- .../regression/stateless_tests/stl_rx_test.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/scripts/automation/regression/stateless_tests/stl_rx_test.py b/scripts/automation/regression/stateless_tests/stl_rx_test.py index 9e275118..bf46bc20 100644 --- a/scripts/automation/regression/stateless_tests/stl_rx_test.py +++ b/scripts/automation/regression/stateless_tests/stl_rx_test.py @@ -24,6 +24,9 @@ class STLRX_Test(CStlGeneral_Test): self.tx_port, self.rx_port = CTRexScenario.stl_ports_map['bi'][0] port_info = self.c.get_port_info(ports = self.rx_port)[0] + self.speed = port_info['speed'] + + cap = port_info['rx']['caps'] if "flow_stats" not in cap or "latency" not in cap: self.skip('port {0} does not support RX'.format(self.rx_port)) @@ -45,9 +48,9 @@ class STLRX_Test(CStlGeneral_Test): drv_name=port_info['driver'] self.latency_9k_enable=per_driver_params[drv_name][3] - - self.latency_9k_max_average = per_driver_params[drv_name][4] - self.latency_9k_max_latency = per_driver_params[drv_name][5] + if self.latency_9k_enable: + self.latency_9k_max_average = per_driver_params[drv_name][4] + self.latency_9k_max_latency = per_driver_params[drv_name][5] @classmethod @@ -321,8 +324,20 @@ class STLRX_Test(CStlGeneral_Test): pgid=random.randint(1, 65000); pkt_size=random.randint(1000, 9000); all_ports = list(CTRexScenario.stl_ports_map['map'].keys()); + + s_port=random.sample(all_ports, random.randint(1, len(all_ports)) ) s_port=sorted(s_port) + if self.speed == 40 : + # the NIC does not support all full rate in case both port works let's + tmp_l=[] + for port in s_port: + if ((int(port) % 2) ==0): + tmp_l.append(port); + s_port=tmp_l; + if len(s_port)==0: + s_port=[0]; + error=1; for j in range(0,5): print(" {4} - duration {0} pgid {1} pkt_size {2} s_port {3} ".format(duration,pgid,pkt_size,s_port,j)); -- cgit 1.2.3-korg From 776aff59c30d204a953e5b3a42172e828f030da6 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Wed, 22 Jun 2016 19:16:05 +0300 Subject: minor --- scripts/automation/regression/stateless_tests/stl_rx_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/automation/regression/stateless_tests/stl_rx_test.py b/scripts/automation/regression/stateless_tests/stl_rx_test.py index bf46bc20..84f32081 100644 --- a/scripts/automation/regression/stateless_tests/stl_rx_test.py +++ b/scripts/automation/regression/stateless_tests/stl_rx_test.py @@ -329,7 +329,7 @@ class STLRX_Test(CStlGeneral_Test): s_port=random.sample(all_ports, random.randint(1, len(all_ports)) ) s_port=sorted(s_port) if self.speed == 40 : - # the NIC does not support all full rate in case both port works let's + # the NIC does not support all full rate in case both port works let's filter odd ports tmp_l=[] for port in s_port: if ((int(port) % 2) ==0): -- cgit 1.2.3-korg From 24c22cf22f429c5214b1f1beba5145e7c4a2c4a8 Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Thu, 23 Jun 2016 09:19:54 +0300 Subject: get_stats documentation --- .../stl/trex_stl_lib/trex_stl_client.py | 153 ++++++++++++++++++++- scripts/stl/flow_stats_latency.py | 4 +- 2 files changed, 151 insertions(+), 6 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 4d1125c8..6dec6fa7 100755 --- 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 @@ -1254,18 +1254,161 @@ class STLClient(object): # get stats - def get_stats (self, ports = None, async_barrier = True): + def get_stats (self, ports = None, sync_now = True): + """ + Return dictionary containing statistics information gathered from the server. + + :parameters: + + ports - List of ports to retreive stats on. + If None, assume the request is for all acquired ports. + + sync_now - Boolean - If true, create a call to the server to get latest stats, and wait for result to arrive. Otherwise, return last stats saved in client cache. + Downside of putting True is a slight delay (few 10th msecs) in getting the result. For practical uses, value should be True. + :return: + Statistics dictionary of dictionaries with the following format: + + =============================== =============== + key Meaning + =============================== =============== + :ref:`numbers (0,1,..` Statistcs per port number + :ref:`total ` Sum of port statistics + :ref:`flow_stats ` Per flow statistics + :ref:`global ` Global statistics + :ref:`latency ` Per flow statistics regarding flow latency + =============================== =============== + + Below is description of each of the inner dictionaries. + + .. _total: + + **total** and per port statistics contain dictionary with following format. + + =============================== =============== + key Meaning + =============================== =============== + ibytes Number of input bytes + ierrors Number of input errors + ipackets Number of input packets + obytes Number of output bytes + oerrors Number of output errors + opackets Number of output packets + rx_bps Receive bytes per second rate + rx_pps Receive packet per second rate + tx_bps Transmit bytes per second rate + tx_pps Transmit packet per second rate + =============================== =============== + + .. _flow_stats: + + **flow_stats** contains dictionaries per packet group id (pg id). Each one with the following structure. + + ================= =============== + key Meaning + ================= =============== + rx_bps Receivd bytes per second rate + rx_bps_l1 Receivd bytes per second rate, including layer one + rx_bytes Total number of received bytes + rx_pkts Total number of received packets + rx_pps Received packets per second + tx_bps Transmitted bytes per second rate + tx_bps_l1 Transmitted bytes per second rate, including layer one + tx_bytes Total number of sent bytes + tx_pkts Total number of sent packets + tx_pps Transmit packets per second + ================= =============== + + .. _global: + + **global** + + ================= =============== + key Meaning + ================= =============== + bw_per_core Estimated byte rate Trex can support per core. This is calculated by extrapolation of current rate and load on transmitting cores. + cpu_util Estimate of the average utilization percentage of the transimitting cores + queue_full Total number of packets we could not transmit because NIC TX queue was full. This usually indicates that the rate we trying to transmit is too high for this port + rx_cpu_util Estimate of the utilization percentage of the core handling RX traffic + rx_drop_bps Received bytes per second drop rate + rx_bps Received bytes per second rate + rx_pps Received packets per second rate + tx_bps Transmit bytes per second rate + tx_pps Transmit packets per second rate + ================= =============== + + .. _latency: + + **latency** contains dictionary per packet group id (pg id). Each one with the following structure. + + =========================== =============== + key Meaning + =========================== =============== + :ref:`err_cntrs` Counters describing errors that occured with this pg id + :ref:`latency` Information regarding packet latency + =========================== =============== + + Following are the inner dictionaries of latency + + .. _err-cntrs: + + **err-cntrs** + + ================= =============== + key Meaning (see better explanation below the table) + ================= =============== + dropped How many packets were dropped. + dup How many packets were duplicated. + out_of_order How many packets we received out of order. + seq_too_high How many events of packet with sequence number too high we saw. + seq_too_low How many events of packet with sequence number too low we saw. + ================= =============== + + For calculating packet error events, we add sequence number to each packet's payload. We decide what went wrong only according to sequence number + of last packet received and that of the previous packet. 'seq_too_low' and 'seq_too_high' count events we see. 'dup', 'out_of_order' and 'dropped' + are heuristics we apply to try and understand what happened. They will be accurate in common error scenarios. + We describe few scenarios below to help understand this. + + Scenario 1: Received packet with seq num 10, and another one with seq num 10. We increment 'dup' and 'seq_too_low' by 1. + + Scenario 2: Received pacekt with seq num 10 and then packet with seq num 15. We assume 4 packets were dropped, and increment 'dropped' by 4, and 'seq_too_high' by 1. + We expect next packet to arrive with sequence number 16. + + Scenario 2 continue: Received packet with seq num 11. We increment 'seq_too_low' by 1. We increment 'out_of_order' by 1. We *decrement* 'dropped' by 1. + (We assume here that one of the packets we considered as dropped before, actually arrived out of order). + + + .. _lat_inner: + + **latency** + + ================= =============== + key Meaning + ================= =============== + average Average latency over the stream lifetime (usec). Total average is computed each sampling period by following formula: = /2 + /2 + histogram Dictionary describing logarithmic distribution histogram of packet latencies. Keys in the dictionary represent range of latencies (in usec). Values are the total number of packets received in this latency range. For example, an entry {100:13} would mean that we saw 13 packets with latency in the range between 100 and 200 usec. + jitter Jitter of latency samples, computed as described in :rfc:`3550#appendix-A.8` + last_max Maximum latency measured between last two data reads from server. + total_max Maximum latency measured over the stream lifetime (in usec). + total_min Minimum latency measured over the stream lifetime (in usec). + ================= =============== + + + + :raises: + None + + """ # by default use all acquired ports ports = ports if ports is not None else self.get_acquired_ports() ports = self._validate_port_list(ports) # check async barrier - if not type(async_barrier) is bool: - raise STLArgumentError('async_barrier', async_barrier) + if not type(sync_now) is bool: + raise STLArgumentError('sync_now', sync_now) # if the user requested a barrier - use it - if async_barrier: + if sync_now: rc = self.async_client.barrier() if not rc: raise STLError(rc) @@ -1279,7 +1422,7 @@ class STLClient(object): :parameters: ev_type_filter - 'info', 'warning' or a list of those - default is no filter + default: no filter :return: logged events diff --git a/scripts/stl/flow_stats_latency.py b/scripts/stl/flow_stats_latency.py index 8460fcfc..e053549e 100644 --- a/scripts/stl/flow_stats_latency.py +++ b/scripts/stl/flow_stats_latency.py @@ -6,6 +6,8 @@ class STLS1(object): Can specify using tunables the packet length (fsize) and packet group id (pg_id) Since we can't have two latency streams with same pg_id, in order to be able to start this profile on more than one port, we add port_id to the pg_id + Notice that for perfomance reasons, latency streams are not affected by -m flag, so + you can only change the pps value by editing the code. """ def __init__ (self): @@ -19,7 +21,7 @@ class STLS1(object): pkt = STLPktBuilder(pkt = base_pkt/pad) return [STLStream(packet = pkt, - mode = STLTXCont(pps=1), + mode = STLTXCont(pps=1000), flow_stats = STLFlowLatencyStats(pg_id = self.pg_id)) ] -- cgit 1.2.3-korg From c9b97a6012e4b74e85fde4868437780722f5b326 Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Thu, 23 Jun 2016 09:48:50 +0300 Subject: small changes to 365826c5db225f21283c48eebc8de62b89fbfa24, so it will be easy to merge with later DPDK versions --- src/dpdk22/drivers/net/i40e/i40e_ethdev.c | 21 +++++++++------- src/dpdk22/drivers/net/i40e/i40e_ethdev.h | 2 +- src/dpdk22/drivers/net/i40e/i40e_rxtx.c | 42 ++++++++++++++++--------------- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/dpdk22/drivers/net/i40e/i40e_ethdev.c b/src/dpdk22/drivers/net/i40e/i40e_ethdev.c index b73eedf1..5646eb53 100644 --- a/src/dpdk22/drivers/net/i40e/i40e_ethdev.c +++ b/src/dpdk22/drivers/net/i40e/i40e_ethdev.c @@ -3868,6 +3868,9 @@ i40e_update_default_filter_setting(struct i40e_vsi *vsi) return i40e_vsi_add_mac(vsi, &filter); } +#ifdef TREX_PATCH +#define LOW_LATENCY_WORKAROUND +#ifdef LOW_LATENCY_WORKAROUND static int i40e_vsi_update_tc_max_bw(struct i40e_vsi *vsi, u16 credit){ struct i40e_hw *hw = I40E_VSI_TO_HW(vsi); @@ -3885,7 +3888,8 @@ i40e_vsi_update_tc_max_bw(struct i40e_vsi *vsi, u16 credit){ } return (0); } - +#endif +#endif #define I40E_3_BIT_MASK 0x7 @@ -4447,18 +4451,16 @@ i40e_pf_setup(struct i40e_pf *pf) pf->main_vsi = vsi; -#define LOW_LATENCY_WORKAROUND +#ifdef TREX_PATCH #ifdef LOW_LATENCY_WORKAROUND - - /* - Workaround for low latency issue. - It seems RR does not work as expected both from same QSet and from different QSet - Quanta could be very high and this creates very high latency, especially with long packet size (9K) + /* + Workaround for low latency issue. + It seems RR does not work as expected both from same QSet and from different QSet + Quanta could be very high and this creates very high latency, especially with long packet size (9K) This is a workaround limit the main (bulk) VSI to 99% of the BW and by that support low latency (suggested by Intel) ETS with with strict priority and 127 credit does not work . - */ - + if (hw->phy.link_info.link_speed == I40E_LINK_SPEED_10GB) { i40e_vsi_update_tc_max_bw(vsi,199); }else{ @@ -4478,6 +4480,7 @@ i40e_pf_setup(struct i40e_pf *pf) pf->ll_vsi = vsi; +#endif #endif /* Configure filter control */ diff --git a/src/dpdk22/drivers/net/i40e/i40e_ethdev.h b/src/dpdk22/drivers/net/i40e/i40e_ethdev.h index 44082dfa..53d6afdd 100644 --- a/src/dpdk22/drivers/net/i40e/i40e_ethdev.h +++ b/src/dpdk22/drivers/net/i40e/i40e_ethdev.h @@ -396,7 +396,7 @@ TAILQ_HEAD(i40e_mirror_rule_list, i40e_mirror_rule); struct i40e_pf { struct i40e_adapter *adapter; /* The adapter this PF associate to */ struct i40e_vsi *main_vsi; /* pointer to main VSI structure */ - struct i40e_vsi * ll_vsi; + struct i40e_vsi * ll_vsi; // TREX_PATCH uint16_t mac_seid; /* The seid of the MAC of this PF */ uint16_t main_vsi_seid; /* The seid of the main VSI */ uint16_t max_num_vsi; diff --git a/src/dpdk22/drivers/net/i40e/i40e_rxtx.c b/src/dpdk22/drivers/net/i40e/i40e_rxtx.c index d3ef00f8..ee3c3c1a 100644 --- a/src/dpdk22/drivers/net/i40e/i40e_rxtx.c +++ b/src/dpdk22/drivers/net/i40e/i40e_rxtx.c @@ -1923,30 +1923,34 @@ i40e_xmit_pkts_simple(void *tx_queue, return nb_tx; } - +// TREX_PATCH +// Based on i40e_pf_get_vsi_by_qindex. Return low latency VSI one queue. +#define LOW_LATENCY_WORKAROUND +#ifdef LOW_LATENCY_WORKAROUND static struct i40e_vsi* i40e_pf_tx_get_vsi_by_qindex(struct i40e_pf *pf, uint16_t queue_idx) { - /* the queue in MAIN VSI range */ + // For last queue index, return low latency VSI if (queue_idx == pf->dev_data->nb_tx_queues-1) { return pf->ll_vsi; } - if (queue_idx < pf->dev_data->nb_tx_queues) - return pf->main_vsi; + /* the queue in MAIN VSI range */ + if (queue_idx < pf->dev_data->nb_tx_queues) + return pf->main_vsi; - queue_idx -= pf->main_vsi->nb_qps; + queue_idx -= pf->main_vsi->nb_qps; - /* queue_idx is greater than VMDQ VSIs range */ - if (queue_idx > pf->nb_cfg_vmdq_vsi * pf->vmdq_nb_qps - 1) { - PMD_INIT_LOG(ERR, "queue_idx out of range. VMDQ configured?"); - return NULL; - } + /* queue_idx is greater than VMDQ VSIs range */ + if (queue_idx > pf->nb_cfg_vmdq_vsi * pf->vmdq_nb_qps - 1) { + PMD_INIT_LOG(ERR, "queue_idx out of range. VMDQ configured?"); + return NULL; + } - return pf->vmdq[queue_idx / pf->vmdq_nb_qps].vsi; + return pf->vmdq[queue_idx / pf->vmdq_nb_qps].vsi; } - +#endif /* * Find the VSI the queue belongs to. 'queue_idx' is the queue index @@ -2339,8 +2343,6 @@ i40e_dev_rx_descriptor_done(void *rx_queue, uint16_t offset) return ret; } -#define LOW_LATENCY_WORKAROUND - int i40e_dev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx, @@ -2361,14 +2363,14 @@ i40e_dev_tx_queue_setup(struct rte_eth_dev *dev, struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private); vsi = &vf->vsi; - } else{ - #ifdef LOW_LATENCY_WORKAROUND + } else { +// TREX_PATCH +#ifdef LOW_LATENCY_WORKAROUND vsi = i40e_pf_tx_get_vsi_by_qindex(pf, queue_idx); - #else - vsi = i40e_pf_get_vsi_by_qindex(pf, queue_idx); - #endif +#else + vsi = i40e_pf_get_vsi_by_qindex(pf, queue_idx); +#endif } - if (vsi == NULL) { PMD_DRV_LOG(ERR, "VSI is NULL, or queue index (%u) " -- cgit 1.2.3-korg From d04442ab671f768a1b645fb887d4a9cd575c7852 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Thu, 23 Jun 2016 09:56:30 +0300 Subject: daemons logger: create log dir if does not exist --- scripts/automation/trex_control_plane/server/CCustomLogger.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/automation/trex_control_plane/server/CCustomLogger.py b/scripts/automation/trex_control_plane/server/CCustomLogger.py index a8823cea..6d3974a6 100755 --- a/scripts/automation/trex_control_plane/server/CCustomLogger.py +++ b/scripts/automation/trex_control_plane/server/CCustomLogger.py @@ -3,15 +3,13 @@ import sys import os import logging +def prepare_dir(log_path): + log_dir = os.path.dirname(log_path) + if not os.path.exists(log_dir): + os.makedirs(log_dir) def setup_custom_logger(name, log_path = None): # first make sure path availabe -# if log_path is None: -# log_path = os.getcwd()+'/trex_log.log' -# else: -# directory = os.path.dirname(log_path) -# if not os.path.exists(directory): -# os.makedirs(directory) logging.basicConfig(level = logging.INFO, format = '%(asctime)s %(name)-10s %(module)-20s %(levelname)-8s %(message)s', datefmt = '%m-%d %H:%M') @@ -31,6 +29,7 @@ def setup_custom_logger(name, log_path = None): def setup_daemon_logger (name, log_path = None): # first make sure path availabe + prepare_dir(log_path) try: os.unlink(log_path) except: -- cgit 1.2.3-korg