summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rwxr-xr-xscripts/automation/trex_control_plane/stl/console/trex_console.py25
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_async_client.py6
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py176
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py45
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py5
-rw-r--r--src/main_dpdk.cpp1
-rw-r--r--src/stateless/cp/trex_api_class.h30
-rw-r--r--src/stateless/cp/trex_stateless.cpp2
9 files changed, 233 insertions, 61 deletions
diff --git a/.gitignore b/.gitignore
index 0b02fb21..80456922 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,6 +27,10 @@ scripts/automation/trex_control_plane/doc/_build/*
scripts/automation/trex_control_plane/doc_stl/_build/*
scripts/a.pcap
+scripts/exp/stl_vm_split_client_var.erf-0.erf
+scripts/exp/stl_vm_split_flow_var_big_range.erf-0.erf
+scripts/exp/stl_vm_split_flow_var_inc.erf-0.erf
+scripts/exp/stl_vm_split_flow_var_small_range.erf-0.erf
scripts/exp/http1_with_option_ipv6.pcap
scripts/exp/http1_with_option.pcap
scripts/stl/exportedFile.pcap
diff --git a/scripts/automation/trex_control_plane/stl/console/trex_console.py b/scripts/automation/trex_control_plane/stl/console/trex_console.py
index aade572f..94cb4009 100755
--- a/scripts/automation/trex_control_plane/stl/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py
@@ -538,28 +538,7 @@ class TRexConsole(TRexGeneralCmd):
def do_events (self, line):
'''shows events recieved from server\n'''
-
- x = parsing_opts.ArgumentPack(['-c','--clear'],
- {'action' : "store_true",
- 'default': False,
- 'help': "clear the events log"})
-
- parser = parsing_opts.gen_parser(self,
- "events",
- self.do_events.__doc__,
- x)
-
- opts = parser.parse_args(line.split())
- if opts is None:
- return
-
- events = self.stateless_client.get_events()
- for ev in events:
- print(ev)
-
- if opts.clear:
- self.stateless_client.clear_events()
- print(format_text("\n\nEvent log was cleared\n\n"))
+ return self.stateless_client.get_events_line(line)
def complete_profile(self, text, line, begidx, endidx):
@@ -591,7 +570,7 @@ class TRexConsole(TRexGeneralCmd):
info = self.stateless_client.get_connection_info()
exe = './trex-console --top -t -q -s {0} -p {1} --async_port {2}'.format(info['server'], info['sync_port'], info['async_port'])
- cmd = ['/usr/bin/xterm', '-geometry', '111x47', '-sl', '0', '-title', 'trex_tui', '-e', exe]
+ cmd = ['/usr/bin/xterm', '-geometry', '111x48', '-sl', '0', '-title', 'trex_tui', '-e', exe]
self.terminal = subprocess.Popen(cmd)
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_async_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_async_client.py
index 0f0fe83e..022077a9 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_async_client.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_async_client.py
@@ -275,18 +275,18 @@ class CTRexAsyncClient():
# stats
if name == "trex-global":
- self.event_handler.handle_async_stats_update(data, baseline)
+ self.event_handler.on_async_stats_update(data, baseline)
# events
elif name == "trex-event":
- self.event_handler.handle_async_event(type, data)
+ self.event_handler.on_async_event(type, data)
# barriers
elif name == "trex-barrier":
self.handle_async_barrier(type, data)
elif name == "flow_stats":
- self.event_handler.handle_async_rx_stats_event(data, baseline)
+ self.event_handler.on_async_rx_stats_event(data, baseline)
else:
pass
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 1c4984eb..120f4d10 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
@@ -125,8 +125,26 @@ class DefaultLogger(LoggerApi):
############################ #############################
############################ #############################
+# an event
+class Event(object):
+
+ def __init__ (self, origin, ev_type, msg):
+ self.origin = origin
+ self.ev_type = ev_type
+ self.msg = msg
+
+ self.ts = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S')
+
+ def __str__ (self):
+
+ prefix = "[{:^}][{:^}]".format(self.origin, self.ev_type)
+
+ return "{:<10} - {:18} - {:}".format(self.ts, prefix, format_text(self.msg, 'bold'))
+
+
# handles different async events given to the client
-class AsyncEventHandler(object):
+class EventsHandler(object):
+
def __init__ (self, client):
self.client = client
@@ -136,31 +154,41 @@ class AsyncEventHandler(object):
# public functions
- def get_events (self):
- return self.events
+ def get_events (self, ev_type_filter = None):
+ if ev_type_filter:
+ return [ev for ev in self.events if ev.ev_type in listify(ev_type_filter)]
+ else:
+ return [ev for ev in self.events]
def clear_events (self):
self.events = []
+ def log_warning (self, msg, show = True):
+ self.__add_event_log('local', 'warning', msg, show)
+
+
+ # events called internally
+
def on_async_dead (self):
if self.client.connected:
msg = 'Lost connection to server'
- self.__add_event_log(msg, 'local', True)
+ self.__add_event_log('local', 'info', msg, True)
self.client.connected = False
def on_async_alive (self):
pass
+
- def handle_async_rx_stats_event (self, data, baseline):
+ def on_async_rx_stats_event (self, data, baseline):
self.client.flow_stats.update(data, baseline)
# handles an async stats update from the subscriber
- def handle_async_stats_update(self, dump_data, baseline):
+ def on_async_stats_update(self, dump_data, baseline):
global_stats = {}
port_stats = {}
@@ -189,8 +217,9 @@ class AsyncEventHandler(object):
self.client.ports[port_id].port_stats.update(data, baseline)
+
# dispatcher for server async events (port started, port stopped and etc.)
- def handle_async_event (self, type, data):
+ def on_async_event (self, type, data):
# DP stopped
show_event = False
@@ -263,7 +292,7 @@ class AsyncEventHandler(object):
return
- self.__add_event_log(ev, 'server', show_event)
+ self.__add_event_log('server', 'info', ev, show_event)
# private functions
@@ -296,19 +325,12 @@ class AsyncEventHandler(object):
# add event to log
- def __add_event_log (self, msg, ev_type, show = False):
-
- if ev_type == "server":
- prefix = "[server]"
- elif ev_type == "local":
- prefix = "[local]"
-
- ts = time.time()
- st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
- self.events.append("{:<10} - {:^8} - {:}".format(st, prefix, format_text(msg, 'bold')))
+ def __add_event_log (self, origin, ev_type, msg, show = False):
+ event = Event(origin, ev_type, msg)
+ self.events.append(event)
if show:
- self.logger.async_log(format_text("\n\n{:^8} - {:}".format(prefix, format_text(msg, 'bold'))))
+ self.logger.async_log("\n\n{0}".format(str(event)))
@@ -452,7 +474,7 @@ class STLClient(object):
self)
# async event handler manager
- self.event_handler = AsyncEventHandler(self)
+ self.event_handler = EventsHandler(self)
# async subscriber level
self.async_client = CTRexAsyncClient(server,
@@ -472,7 +494,8 @@ class STLClient(object):
self.global_stats = trex_stl_stats.CGlobalStats(self.connection_info,
self.server_version,
- self.ports)
+ self.ports,
+ self.event_handler)
self.flow_stats = trex_stl_stats.CRxStats(self.ports)
@@ -482,7 +505,7 @@ class STLClient(object):
# API classes
- self.api_vers = [ {'type': 'core', 'major': 1, 'minor':0 }
+ self.api_vers = [ {'type': 'core', 'major': 1, 'minor':1 }
]
self.api_h = {'core': None}
@@ -1155,9 +1178,58 @@ class STLClient(object):
return self.__get_stats(ports)
- # return all async events
- def get_events (self):
- return self.event_handler.get_events()
+
+ def get_events (self, ev_type_filter = None):
+ """
+ returns all the logged events
+
+ :parameters:
+ ev_type_filter - 'info', 'warning' or a list of those
+ default is no filter
+
+ :return:
+ logged events
+
+ :raises:
+ None
+
+ """
+ return self.event_handler.get_events(ev_type_filter)
+
+
+ def get_warnings (self):
+ """
+ returns all the warnings logged events
+
+ :parameters:
+ None
+
+ :return:
+ warning logged events
+
+ :raises:
+ None
+
+ """
+ return self.get_events(ev_type_filter = 'warning')
+
+
+ def get_info (self):
+ """
+ returns all the info logged events
+
+ :parameters:
+ None
+
+ :return:
+ warning logged events
+
+ :raises:
+ None
+
+ """
+ return self.get_events(ev_type_filter = 'info')
+
# get port(s) info as a list of dicts
@__api_check(True)
@@ -2212,7 +2284,7 @@ class STLClient(object):
mask = self.__get_mask_keys(**self.__filter_namespace_args(opts, trex_stl_stats.ALL_STATS_OPTS))
if not mask:
# set to show all stats if no filter was given
- mask = trex_stl_stats.ALL_STATS_OPTS
+ mask = trex_stl_stats.COMPACT
stats_opts = common.list_intersect(trex_stl_stats.ALL_STATS_OPTS, mask)
@@ -2371,3 +2443,55 @@ class STLClient(object):
self.logger.log("")
+
+ @__console
+ def get_events_line (self, line):
+ '''shows events recieved from server\n'''
+
+ x = [parsing_opts.ArgumentPack(['-c','--clear'],
+ {'action' : "store_true",
+ 'default': False,
+ 'help': "clear the events log"}),
+
+ parsing_opts.ArgumentPack(['-i','--info'],
+ {'action' : "store_true",
+ 'default': False,
+ 'help': "show info events"}),
+
+ parsing_opts.ArgumentPack(['-w','--warn'],
+ {'action' : "store_true",
+ 'default': False,
+ 'help': "show warning events"}),
+
+ ]
+
+
+ parser = parsing_opts.gen_parser(self,
+ "events",
+ self.get_events_line.__doc__,
+ *x)
+
+ opts = parser.parse_args(line.split())
+ if opts is None:
+ return
+
+
+ ev_type_filter = []
+
+ if opts.info:
+ ev_type_filter.append('info')
+
+ if opts.warn:
+ ev_type_filter.append('warning')
+
+ if not ev_type_filter:
+ ev_type_filter = None
+
+ events = self.get_events(ev_type_filter)
+ for ev in events:
+ self.logger.log(ev)
+
+ if opts.clear:
+ self.clear_events()
+ self.logger.log(format_text("\nEvent log was cleared\n"))
+
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 dd597648..48111433 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
@@ -91,6 +91,30 @@ def calculate_diff_raw (samples):
return total
+# a simple object to keep a watch over a field
+class WatchedField(object):
+
+ def __init__ (self, name, suffix, high_th, low_th, events_handler):
+ self.name = name
+ self.suffix = suffix
+ self.high_th = high_th
+ self.low_th = low_th
+ self.events_handler = events_handler
+
+ self.hot = False
+ self.current = None
+
+ def update (self, value):
+ if value > self.high_th and not self.hot:
+ self.events_handler.log_warning("{0} is high: {1}{2}".format(self.name, value, self.suffix))
+ self.hot = True
+
+ if value < self.low_th and self.hot:
+ self.hot = False
+
+ self.current = value
+
+
class CTRexInfoGenerator(object):
"""
@@ -540,17 +564,24 @@ class CTRexStats(object):
class CGlobalStats(CTRexStats):
- def __init__(self, connection_info, server_version, ports_dict_ref):
+ def __init__(self, connection_info, server_version, ports_dict_ref, events_handler):
super(CGlobalStats, self).__init__()
+
self.connection_info = connection_info
- self.server_version = server_version
- self._ports_dict = ports_dict_ref
+ self.server_version = server_version
+ self._ports_dict = ports_dict_ref
+ self.events_handler = events_handler
+
+ self.watched_cpu_util = WatchedField('CPU util.', '%', 85, 60, events_handler)
+ self.watched_rx_cpu_util = WatchedField('RX core util.', '%', 85, 60, events_handler)
def get_stats (self):
stats = {}
# absolute
- stats['cpu_util'] = self.get("m_cpu_util")
+ stats['cpu_util'] = self.get("m_cpu_util")
+ stats['rx_cpu_util'] = self.get("m_rx_cpu_util")
+
stats['tx_bps'] = self.get("m_tx_bps")
stats['tx_pps'] = self.get("m_tx_pps")
@@ -576,6 +607,9 @@ class CGlobalStats(CTRexStats):
# simple...
self.latest_stats = snapshot
+ self.watched_cpu_util.update(snapshot['m_cpu_util'])
+ self.watched_rx_cpu_util.update(snapshot['m_rx_cpu_util'])
+
return True
@@ -588,6 +622,9 @@ class CGlobalStats(CTRexStats):
("cpu_util", "{0}% {1}".format( format_threshold(self.get("m_cpu_util"), [85, 100], [0, 85]),
self.get_trend_gui("m_cpu_util", use_raw = True))),
+ ("rx_cpu_util", "{0}% {1}".format( format_threshold(self.get("m_rx_cpu_util"), [85, 100], [0, 85]),
+ self.get_trend_gui("m_rx_cpu_util", use_raw = True))),
+
(" ", ""),
("total_tx_L2", "{0} {1}".format( self.get("m_tx_bps", format=True, suffix="b/sec"),
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py
index f3ac5c65..f6718fda 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py
@@ -140,6 +140,11 @@ def verify_exclusive_arg (args_list):
if not (len(list(filter(lambda x: x is not None, args_list))) == 1):
raise STLError('exactly one parameter from {0} should be provided'.format(args_list))
+def listify (x):
+ if isinstance(x, list):
+ return x
+ else:
+ return [x]
# shows as 'N/A', but does not let any compares for user to not mistake in automation
class StatNotAvailable(object):
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 652e6947..131e87ac 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -2368,6 +2368,7 @@ void CGlobalStats::dump_json(std::string & json, bool baseline,uint32_t stats_ti
#define GET_FIELD_PORT(p,f) get_field_port(p,std::string(#f),lp->f)
json+=GET_FIELD(m_cpu_util);
+ json+=GET_FIELD(m_rx_cpu_util);
json+=GET_FIELD(m_platform_factor);
json+=GET_FIELD(m_tx_bps);
json+=GET_FIELD(m_rx_bps);
diff --git a/src/stateless/cp/trex_api_class.h b/src/stateless/cp/trex_api_class.h
index 78933d23..748d1478 100644
--- a/src/stateless/cp/trex_api_class.h
+++ b/src/stateless/cp/trex_api_class.h
@@ -75,20 +75,42 @@ public:
m_handler = utl_generate_random_str(seed, 8);
}
+ std::string ver(int major, int minor) {
+ std::stringstream ss;
+ ss << major << "." << minor;
+ return ss.str();
+ }
+
+ std::string get_server_ver() {
+ return ver(m_major, m_major);
+ }
+
std::string & verify_api(int major, int minor) {
std::stringstream ss;
ss << "API type '" << type_to_name(m_type) << "': ";
-
+
assert(m_type < API_CLASS_TYPE_MAX);
+ bool fail = false;
+
/* for now a simple major check */
if (major < m_major) {
- ss << "server has a major newer API version - server: '" << m_major << "', client: '" << major << "'";
- throw TrexAPIException(ss.str());
+ ss << "server has a newer major API version";
+ fail = true;
}
if (major > m_major) {
- ss << "server has an older API version - server: '" << m_major << "', client: '" << major << "'";
+ ss << "server has an older major API version";
+ fail = true;
+ }
+
+ if (minor > m_minor) {
+ ss << "client revision API is newer than server";
+ fail = true;
+ }
+
+ if (fail) {
+ ss << " - server: '" << get_server_ver() << "', client: '" << ver(major, minor) << "'";
throw TrexAPIException(ss.str());
}
diff --git a/src/stateless/cp/trex_stateless.cpp b/src/stateless/cp/trex_stateless.cpp
index f6f81b96..c86c5f65 100644
--- a/src/stateless/cp/trex_stateless.cpp
+++ b/src/stateless/cp/trex_stateless.cpp
@@ -54,7 +54,7 @@ TrexStateless::TrexStateless(const TrexStatelessCfg &cfg) {
m_publisher = cfg.m_publisher;
/* API core version */
- m_api_classes[APIClass::API_CLASS_TYPE_CORE].init(APIClass::API_CLASS_TYPE_CORE, 1, 0);
+ m_api_classes[APIClass::API_CLASS_TYPE_CORE].init(APIClass::API_CLASS_TYPE_CORE, 1, 1);
}
/**