summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rwxr-xr-xscripts/automation/trex_control_plane/stl/console/trex_console.py93
-rw-r--r--scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows.py44
-rw-r--r--scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows1.py114
-rw-r--r--scripts/automation/trex_control_plane/stl/examples/stl_flow_stats.py18
-rw-r--r--scripts/automation/trex_control_plane/stl/examples/stl_imix.py7
-rw-r--r--scripts/automation/trex_control_plane/stl/examples/stl_simple_burst.py31
-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.py246
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py11
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py50
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py5
-rw-r--r--scripts/exp/stl_vm_split_client_var.erf-0.erfbin11000 -> 11000 bytes
-rw-r--r--scripts/exp/stl_vm_split_flow_var_big_range.erf-0.erfbin11000 -> 11000 bytes
-rw-r--r--scripts/exp/stl_vm_split_flow_var_inc.erf-0.erfbin11000 -> 11000 bytes
-rw-r--r--scripts/exp/stl_vm_split_flow_var_small_range.erf-0.erfbin11000 -> 11000 bytes
-rw-r--r--src/dpdk22/drivers/net/i40e/i40e_ethdev.c24
-rw-r--r--src/dpdk22/lib/librte_ether/rte_ethdev.c17
-rw-r--r--src/main_dpdk.cpp50
-rw-r--r--src/stateless/cp/trex_api_class.h30
-rw-r--r--src/stateless/cp/trex_stateless.cpp2
21 files changed, 491 insertions, 261 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..a095541e 100755
--- a/scripts/automation/trex_control_plane/stl/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py
@@ -47,7 +47,7 @@ except:
from functools import wraps
-__version__ = "1.1"
+__version__ = "2.0"
# console custom logger
class ConsoleLogger(LoggerApi):
@@ -267,17 +267,19 @@ class TRexConsole(TRexGeneralCmd):
if not self.stateless_client.is_connected():
self.prompt = "trex(offline)>"
self.supported_rpc = None
- return stop
- if self.stateless_client.is_all_ports_acquired():
+ elif not self.stateless_client.get_acquired_ports():
self.prompt = "trex(read-only)>"
- return stop
+ elif self.stateless_client.is_all_ports_acquired():
+ self.prompt = "trex>"
- self.prompt = "trex>"
+ else:
+ self.prompt = "trex {0}>".format(self.stateless_client.get_acquired_ports())
return stop
+
def default(self, line):
print("'{0}' is an unrecognized command. type 'help' or '?' for a list\n".format(line))
@@ -416,17 +418,35 @@ class TRexConsole(TRexGeneralCmd):
############### connect
def do_connect (self, line):
- '''Connects to the server\n'''
+ '''Connects to the server and acquire ports\n'''
self.stateless_client.connect_line(line)
+ def help_connect (self):
+ self.do_connect("-h")
def do_disconnect (self, line):
'''Disconnect from the server\n'''
self.stateless_client.disconnect_line(line)
+
+ def do_acquire (self, line):
+ '''Acquire ports\n'''
+
+ self.stateless_client.acquire_line(line)
+ def help_acquire (self):
+ self.do_acquire("-h")
+
+ def do_release (self, line):
+ '''Release ports\n'''
+
+ self.stateless_client.release_line(line)
+
+ def help_release (self):
+ self.do_release("-h")
+
############### start
def complete_start(self, text, line, begidx, endidx):
@@ -538,28 +558,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,9 +590,10 @@ 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)
+ # detach child
+ self.terminal = subprocess.Popen(cmd, preexec_fn = os.setpgrp)
return
@@ -750,9 +750,24 @@ def setParserOptions():
default = False)
- parser.add_argument("--no_acquire", dest="acquire",
- action="store_false", help="Acquire all ports on connect. Default is: ON.",
- default = True)
+ group = parser.add_mutually_exclusive_group()
+
+ group.add_argument("-a", "--acquire", dest="acquire",
+ nargs = '+',
+ type = int,
+ help="Acquire ports on connect. default is all available ports",
+ default = None)
+
+ group.add_argument("-r", "--readonly", dest="readonly",
+ action="store_true",
+ help="Starts console in a read only mode",
+ default = False)
+
+
+ parser.add_argument("-f", "--force", dest="force",
+ action="store_true",
+ help="Force acquire the requested ports",
+ default = False)
parser.add_argument("--batch", dest="batch",
nargs = 1,
@@ -815,15 +830,19 @@ def main():
logger.log("Log:\n" + format_text(e.brief() + "\n", 'bold'))
return
- if not options.tui and options.acquire:
+ if not options.tui and not options.readonly:
try:
# acquire all ports
- stateless_client.acquire()
+ stateless_client.acquire(options.acquire, force = options.force)
except STLError as e:
logger.log("Log:\n" + format_text(e.brief() + "\n", 'bold'))
- logger.log(format_text("\nSwitching to read only mode - only few commands will be available", 'bold'))
+
+ logger.log("\n*** Failed to acquire all required ports ***\n")
+ return
+
+ if options.readonly:
+ logger.log(format_text("\nRead only mode - only few commands will be available", 'bold'))
-
# a script mode
if options.batch:
cont = run_script_file(options.batch[0], stateless_client)
diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows.py b/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows.py
index d4661b1a..9977fa3e 100644
--- a/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows.py
+++ b/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows.py
@@ -38,7 +38,7 @@ def create_pkt (size, direction):
vm = vm)
-def simple_burst ():
+def simple_burst (port_a, port_b, pkt_size, rate):
# create client
@@ -50,11 +50,11 @@ def simple_burst ():
#c.set_verbose("high")
# create two streams
- s1 = STLStream(packet = create_pkt(200, 0),
+ s1 = STLStream(packet = create_pkt(pkt_size, 0),
mode = STLTXCont(pps = 100))
# second stream with a phase of 1ms (inter stream gap)
- s2 = STLStream(packet = create_pkt(200, 1),
+ s2 = STLStream(packet = create_pkt(pkt_size, 1),
isg = 1000,
mode = STLTXCont(pps = 100))
@@ -62,36 +62,41 @@ def simple_burst ():
# connect to server
c.connect()
- # prepare our ports (my machine has 0 <--> 1 with static route)
- c.reset(ports = [0, 1])
+ # prepare our ports
+ c.reset(ports = [port_a, port_b])
# add both streams to ports
- c.add_streams(s1, ports = [0])
- c.add_streams(s2, ports = [1])
+ c.add_streams(s1, ports = [port_a])
+ c.add_streams(s2, ports = [port_b])
# clear the stats before injecting
c.clear_stats()
- # choose rate and start traffic for 10 seconds on 5 mpps
- print("Running 100 Mbps on ports 0, 1 for 10 seconds...")
- c.start(ports = [0, 1], mult = "100mbps", duration = 10)
+ # here we multiply the traffic lineaer to whatever given in rate
+ print("Running {:} on ports {:}, {:} for 10 seconds...".format(rate, port_a, port_b))
+ c.start(ports = [port_a, port_b], mult = rate, duration = 10)
# block until done
- c.wait_on_traffic(ports = [0, 1])
+ c.wait_on_traffic(ports = [port_a, port_b])
# read the stats after the test
stats = c.get_stats()
- print(json.dumps(stats[0], indent = 4, separators=(',', ': '), sort_keys = True))
- print(json.dumps(stats[1], indent = 4, separators=(',', ': '), sort_keys = True))
+ print(json.dumps(stats[port_a], indent = 4, separators=(',', ': '), sort_keys = True))
+ print(json.dumps(stats[port_b], indent = 4, separators=(',', ': '), sort_keys = True))
- lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
- lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
+ lost_a = stats[port_a]["opackets"] - stats[port_b]["ipackets"]
+ lost_b = stats[port_b]["opackets"] - stats[port_a]["ipackets"]
- print("\npackets lost from 0 --> 1: {0} pkts".format(lost_a))
- print("packets lost from 1 --> 0: {0} pkts".format(lost_b))
+ print("\npackets lost from {0} --> {1}: {2} pkts".format(port_a, port_b, lost_a))
+ print("packets lost from {0} --> {1}: {2} pkts".format(port_b, port_a, lost_b))
- if (lost_a == 0) and (lost_b == 0):
+ if c.get_warnings():
+ print("\n\n*** test had warnings ****\n\n")
+ for w in c.get_warnings():
+ print(w)
+
+ if (lost_a == 0) and (lost_b == 0) and not c.get_warnings():
passed = True
else:
passed = False
@@ -108,7 +113,6 @@ def simple_burst ():
else:
print("\nTest has failed :-(\n")
-while True:
# run the tests
- simple_burst()
+simple_burst(0, 3, 64, "10gbps")
diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows1.py b/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows1.py
deleted file mode 100644
index c9cab8e9..00000000
--- a/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows1.py
+++ /dev/null
@@ -1,114 +0,0 @@
-import stl_path
-from trex_stl_lib.api import *
-
-import time
-import json
-
-# simple packet creation
-def create_pkt (size, direction):
-
- ip_range = {'src': {'start': "10.0.0.1", 'end': "10.0.0.254"},
- 'dst': {'start': "8.0.0.1", 'end': "8.0.0.254"}}
-
- if (direction == 0):
- src = ip_range['src']
- dst = ip_range['dst']
- else:
- src = ip_range['dst']
- dst = ip_range['src']
-
- vm = [
- # src
- STLVmFlowVar(name="src",min_value=src['start'],max_value=src['end'],size=4,op="inc"),
- STLVmWrFlowVar(fv_name="src",pkt_offset= "IP.src"),
-
- # dst
- STLVmFlowVar(name="dst",min_value=dst['start'],max_value=dst['end'],size=4,op="inc"),
- STLVmWrFlowVar(fv_name="dst",pkt_offset= "IP.dst"),
-
- # checksum
- STLVmFixIpv4(offset = "IP")
- ]
-
-
- base = Ether()/IP()/UDP()
- pad = max(0, size-len(base)) * 'x'
-
- return STLPktBuilder(pkt = base/pad,
- vm = vm)
-
-
-def simple_burst ():
-
-
- # create client
- c = STLClient()
- passed = True
-
- try:
- # turn this on for some information
- #c.set_verbose("high")
-
- # create two streams
- s1 = STLStream(packet = create_pkt(200, 0),
- mode = STLTXCont(pps = 100))
-
- # second stream with a phase of 1ms (inter stream gap)
- s2 = STLStream(packet = create_pkt(200, 1),
- isg = 1000,
- mode = STLTXCont(pps = 100))
-
-
- # connect to server
- c.connect()
-
- # prepare our ports (my machine has 0 <--> 1 with static route)
- c.reset(ports = [2, 3])
-
- # add both streams to ports
- c.add_streams(s1, ports = [2])
- c.add_streams(s2, ports = [3])
-
- # clear the stats before injecting
- c.clear_stats()
-
- # choose rate and start traffic for 10 seconds on 5 mpps
- print("Running 5 Mpps on ports 0, 1 for 10 seconds...")
- c.start(ports = [2, 3], mult = "5mpps", duration = 10)
-
- # block until done
- c.wait_on_traffic(ports = [2, 3])
-
- # read the stats after the test
- stats = c.get_stats()
-
- print(json.dumps(stats[2], indent = 4, separators=(',', ': '), sort_keys = True))
- print(json.dumps(stats[3], indent = 4, separators=(',', ': '), sort_keys = True))
-
- lost_a = stats[2]["opackets"] - stats[3]["ipackets"]
- lost_b = stats[3]["opackets"] - stats[2]["ipackets"]
-
- print("\npackets lost from 0 --> 1: {0} pkts".format(lost_a))
- print("packets lost from 1 --> 0: {0} pkts".format(lost_b))
-
- if (lost_a == 0) and (lost_b == 0):
- passed = True
- else:
- passed = False
-
- except STLError as e:
- passed = False
- print(e)
-
- finally:
- c.disconnect()
-
- if passed:
- print("\nTest has passed :-)\n")
- else:
- print("\nTest has failed :-(\n")
-
-while True :
- # run the tests
- simple_burst()
-
diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_flow_stats.py b/scripts/automation/trex_control_plane/stl/examples/stl_flow_stats.py
index d938852e..ed4902fa 100644
--- a/scripts/automation/trex_control_plane/stl/examples/stl_flow_stats.py
+++ b/scripts/automation/trex_control_plane/stl/examples/stl_flow_stats.py
@@ -4,7 +4,7 @@ from trex_stl_lib.api import *
import time
import pprint
-def rx_example (tx_port, rx_port, burst_size):
+def rx_example (tx_port, rx_port, burst_size, bw):
print("\nGoing to inject {0} packets on port {1} - checking RX stats on port {2}\n".format(burst_size, tx_port, rx_port))
@@ -19,9 +19,7 @@ def rx_example (tx_port, rx_port, burst_size):
packet = pkt,
flow_stats = STLFlowStats(pg_id = 5),
mode = STLTXSingleBurst(total_pkts = total_pkts,
- #pps = total_pkts
- percentage = 80
- ))
+ percentage = bw))
# connect to server
c.connect()
@@ -36,7 +34,7 @@ def rx_example (tx_port, rx_port, burst_size):
for i in range(0, 10):
print("\nStarting iteration: {0}:".format(i))
- rc = rx_iteration(c, tx_port, rx_port, total_pkts, pkt.get_pkt_len())
+ rc = rx_iteration(c, tx_port, rx_port, total_pkts, pkt.get_pkt_len(), bw)
if not rc:
passed = False
break
@@ -55,7 +53,7 @@ def rx_example (tx_port, rx_port, burst_size):
print("\nTest has failed :-(\n")
# RX one iteration
-def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len):
+def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len, bw):
c.clear_stats()
@@ -71,6 +69,12 @@ def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len):
tx_bytes = flow_stats['tx_bytes'].get(tx_port, 0)
rx_pkts = flow_stats['rx_pkts'].get(rx_port, 0)
+ if c.get_warnings():
+ print("\n\n*** test had warnings ****\n\n")
+ for w in c.get_warnings():
+ print(w)
+ return False
+
if tx_pkts != total_pkts:
print("TX pkts mismatch - got: {0}, expected: {1}".format(tx_pkts, total_pkts))
pprint.pprint(flow_stats)
@@ -95,5 +99,5 @@ def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len):
return True
# run the tests
-rx_example(tx_port = 1, rx_port = 2, burst_size = 500000)
+rx_example(tx_port = 1, rx_port = 2, burst_size = 500000, bw = 50)
diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_imix.py b/scripts/automation/trex_control_plane/stl/examples/stl_imix.py
index bc7990aa..46d86b2b 100644
--- a/scripts/automation/trex_control_plane/stl/examples/stl_imix.py
+++ b/scripts/automation/trex_control_plane/stl/examples/stl_imix.py
@@ -83,7 +83,12 @@ def imix_test (server, mult):
print("\npackets lost from {0} --> {1}: {2:,} pkts".format(dir_0, dir_0, lost_0))
print("packets lost from {0} --> {1}: {2:,} pkts".format(dir_1, dir_1, lost_1))
- if (lost_0 <= 0) and (lost_1 <= 0): # less or equal because we might have incoming arps etc.
+ if c.get_warnings():
+ print("\n\n*** test had warnings ****\n\n")
+ for w in c.get_warnings():
+ print(w)
+
+ if (lost_0 <= 0) and (lost_1 <= 0) and not c.get_warnings(): # less or equal because we might have incoming arps etc.
passed = True
else:
passed = False
diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_simple_burst.py b/scripts/automation/trex_control_plane/stl/examples/stl_simple_burst.py
index 29341674..4bd9fd4c 100644
--- a/scripts/automation/trex_control_plane/stl/examples/stl_simple_burst.py
+++ b/scripts/automation/trex_control_plane/stl/examples/stl_simple_burst.py
@@ -3,47 +3,49 @@ from trex_stl_lib.api import *
import time
-def simple_burst ():
+def simple_burst (port_a, port_b, pkt_size, burst_size, rate):
# create client
c = STLClient()
passed = True
try:
- pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/IP()/'a_payload_example')
+ pkt_base = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/IP()
+ pad = max(0, pkt_size - len(pkt_base)) * 'x'
+ pkt = STLPktBuilder(pkt = pkt_base / pad)
# create two bursts and link them
s1 = STLStream(name = 'A',
packet = pkt,
- mode = STLTXSingleBurst(total_pkts = 5000),
+ mode = STLTXSingleBurst(total_pkts = burst_size),
next = 'B')
s2 = STLStream(name = 'B',
self_start = False,
packet = pkt,
- mode = STLTXSingleBurst(total_pkts = 3000))
+ mode = STLTXSingleBurst(total_pkts = burst_size))
# connect to server
c.connect()
# prepare our ports
- c.reset(ports = [0, 3])
+ c.reset(ports = [port_a, port_b])
# add both streams to ports
- stream_ids = c.add_streams([s1, s2], ports = [0, 3])
+ stream_ids = c.add_streams([s1, s2], ports = [port_a, port_b])
# run 5 times
for i in range(1, 6):
c.clear_stats()
- c.start(ports = [0, 3], mult = "1gbps")
- c.wait_on_traffic(ports = [0, 3])
+ c.start(ports = [port_a, port_b], mult = rate)
+ c.wait_on_traffic(ports = [port_a, port_b])
stats = c.get_stats()
ipackets = stats['total']['ipackets']
print("Test iteration {0} - Packets Received: {1} ".format(i, ipackets))
- # (5000 + 3000) * 2 ports = 16,000
- if (ipackets != (16000)):
+ # two streams X 2 ports
+ if (ipackets != (burst_size * 2 * 2)):
passed = False
except STLError as e:
@@ -53,12 +55,17 @@ def simple_burst ():
finally:
c.disconnect()
- if passed:
+ if c.get_warnings():
+ print("\n\n*** test had warnings ****\n\n")
+ for w in c.get_warnings():
+ print(w)
+
+ if passed and not c.get_warnings():
print("\nTest has passed :-)\n")
else:
print("\nTest has failed :-(\n")
# run the tests
-simple_burst()
+simple_burst(0, 3, 256, 50000, "80%")
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..98f3fe3a 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
@@ -248,7 +277,7 @@ class AsyncEventHandler(object):
ev = "Port {0} was forcely taken by '{1}'".format(port_id, who)
# call the handler
- self.__async_event_port_forced_acquired(port_id)
+ self.__async_event_port_forced_acquired(port_id, who)
show_event = True
# server stopped
@@ -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
@@ -287,8 +316,8 @@ class AsyncEventHandler(object):
self.client.ports[port_id].async_event_port_resumed()
- def __async_event_port_forced_acquired (self, port_id):
- self.client.ports[port_id].async_event_forced_acquired()
+ def __async_event_port_forced_acquired (self, port_id, who):
+ self.client.ports[port_id].async_event_forced_acquired(who)
def __async_event_server_stopped (self):
@@ -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}
@@ -977,7 +1000,8 @@ class STLClient(object):
"""
- return not (self.get_all_ports() == self.get_acquired_ports())
+ return (self.get_all_ports() == self.get_acquired_ports())
+
# is the client connected ?
def is_connected (self):
@@ -1155,9 +1179,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)
@@ -1951,11 +2024,11 @@ class STLClient(object):
@__console
def connect_line (self, line):
- '''Connects to the TRex server'''
- # define a parser
+ '''Connects to the TRex server and acquire ports'''
parser = parsing_opts.gen_parser(self,
"connect",
self.connect_line.__doc__,
+ parsing_opts.PORT_LIST_WITH_ALL,
parsing_opts.FORCE)
opts = parser.parse_args(line.split())
@@ -1963,9 +2036,62 @@ class STLClient(object):
if opts is None:
return
- # call the API
self.connect()
- self.acquire(force = opts.force)
+ self.acquire(ports = opts.ports, force = opts.force)
+
+ # true means print time
+ return True
+
+ @__console
+ def acquire_line (self, line):
+ '''Acquire ports\n'''
+
+ # define a parser
+ parser = parsing_opts.gen_parser(self,
+ "acquire",
+ self.acquire_line.__doc__,
+ parsing_opts.PORT_LIST_WITH_ALL,
+ parsing_opts.FORCE)
+
+ opts = parser.parse_args(line.split())
+
+ if opts is None:
+ return
+
+ # call the API
+ ports = [x for x in opts.ports if x not in self.get_acquired_ports()]
+ if not ports:
+ self.logger.log("Port(s) {0} are already acquired\n".format(opts.ports))
+ return
+
+ self.acquire(ports = ports, force = opts.force)
+
+ # true means print time
+ return True
+
+
+ #
+ @__console
+ def release_line (self, line):
+ '''Release ports\n'''
+
+ parser = parsing_opts.gen_parser(self,
+ "release",
+ self.release_line.__doc__,
+ parsing_opts.PORT_LIST_WITH_ALL)
+
+ opts = parser.parse_args(line.split())
+
+ if opts is None:
+ return
+
+ # call the API
+ ports = [x for x in opts.ports if x in self.get_acquired_ports()]
+ if not ports:
+ self.logger.log("Port(s) {0} are not owned by you\n".format(opts.ports))
+ return
+
+ self.release(ports = ports)
# true means print time
return True
@@ -2212,7 +2338,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 +2497,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_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
index 87f7b437..6f6f50b1 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
@@ -64,6 +64,8 @@ class Port(object):
self.tx_stopped_ts = None
self.has_rx_streams = False
+ self.owner = ''
+
def err(self, msg):
return RC_ERR("port {0} : {1}\n".format(self.port_id, msg))
@@ -113,6 +115,11 @@ class Port(object):
def is_paused (self):
return (self.state == self.STATE_PAUSE)
+ def get_owner (self):
+ if self.is_acquired():
+ return self.user
+ else:
+ return self.owner
def sync(self):
params = {"port_id": self.port_id}
@@ -137,6 +144,7 @@ class Port(object):
else:
raise Exception("port {0}: bad state received from server '{1}'".format(self.port_id, port_state))
+ self.owner = rc.data()['owner']
self.next_available_id = int(rc.data()['max_stream_id']) + 1
@@ -671,6 +679,7 @@ class Port(object):
if not self.is_acquired():
self.state = self.STATE_TX
- def async_event_forced_acquired (self):
+ def async_event_forced_acquired (self, who):
self.handler = None
+ self.owner = who
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..f0ac5c33 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,33 @@ 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 is None:
+ return
+
+ 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 +567,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 +610,9 @@ class CGlobalStats(CTRexStats):
# simple...
self.latest_stats = snapshot
+ self.watched_cpu_util.update(snapshot.get('m_cpu_util'))
+ self.watched_rx_cpu_util.update(snapshot.get('m_rx_cpu_util'))
+
return True
@@ -588,6 +625,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"),
@@ -707,7 +747,7 @@ class CPortStats(CTRexStats):
state = format_text(state, 'bold')
- return {"owner": self._port_obj.user if self._port_obj else "",
+ return {"owner": self._port_obj.get_owner() if self._port_obj else "",
"state": "{0}".format(state),
"--": " ",
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/scripts/exp/stl_vm_split_client_var.erf-0.erf b/scripts/exp/stl_vm_split_client_var.erf-0.erf
index 25b2a2bd..f156bfe5 100644
--- a/scripts/exp/stl_vm_split_client_var.erf-0.erf
+++ b/scripts/exp/stl_vm_split_client_var.erf-0.erf
Binary files differ
diff --git a/scripts/exp/stl_vm_split_flow_var_big_range.erf-0.erf b/scripts/exp/stl_vm_split_flow_var_big_range.erf-0.erf
index d5ad29d8..9a386724 100644
--- a/scripts/exp/stl_vm_split_flow_var_big_range.erf-0.erf
+++ b/scripts/exp/stl_vm_split_flow_var_big_range.erf-0.erf
Binary files differ
diff --git a/scripts/exp/stl_vm_split_flow_var_inc.erf-0.erf b/scripts/exp/stl_vm_split_flow_var_inc.erf-0.erf
index a938b37c..e6b9b85b 100644
--- a/scripts/exp/stl_vm_split_flow_var_inc.erf-0.erf
+++ b/scripts/exp/stl_vm_split_flow_var_inc.erf-0.erf
Binary files differ
diff --git a/scripts/exp/stl_vm_split_flow_var_small_range.erf-0.erf b/scripts/exp/stl_vm_split_flow_var_small_range.erf-0.erf
index 94e493fe..0a13e822 100644
--- a/scripts/exp/stl_vm_split_flow_var_small_range.erf-0.erf
+++ b/scripts/exp/stl_vm_split_flow_var_small_range.erf-0.erf
Binary files differ
diff --git a/src/dpdk22/drivers/net/i40e/i40e_ethdev.c b/src/dpdk22/drivers/net/i40e/i40e_ethdev.c
index dff4ec3c..ae195683 100644
--- a/src/dpdk22/drivers/net/i40e/i40e_ethdev.c
+++ b/src/dpdk22/drivers/net/i40e/i40e_ethdev.c
@@ -2114,6 +2114,21 @@ i40e_trex_fdir_stats_get(struct rte_eth_dev *dev, uint32_t *stats, uint32_t star
}
}
+// TREX_PATCH
+void
+i40e_trex_fdir_stats_reset(struct rte_eth_dev *dev, uint32_t *stats, uint32_t start, uint32_t len)
+{
+ int i;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ for (i = 0; i < len; i++) {
+ if (stats) {
+ stats[i] = I40E_READ_REG(hw, I40E_GLQF_PCNT(i + start));
+ }
+ I40E_WRITE_REG(hw, I40E_GLQF_PCNT(i + start), 0xffffffff);
+ }
+}
+
/* Get all statistics of a port */
static void
i40e_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
@@ -8413,6 +8428,7 @@ i40e_dcb_hw_configure(struct i40e_pf *pf,
*
* Returns 0 on success, negative value on failure
*/
+//TREX_PATCH - changed all ERR to INFO in below func
static int
i40e_dcb_init_configure(struct rte_eth_dev *dev, bool sw_dcb)
{
@@ -8421,7 +8437,7 @@ i40e_dcb_init_configure(struct rte_eth_dev *dev, bool sw_dcb)
int ret = 0;
if ((pf->flags & I40E_FLAG_DCB) == 0) {
- PMD_INIT_LOG(ERR, "HW doesn't support DCB");
+ PMD_INIT_LOG(INFO, "HW doesn't support DCB");
return -ENOTSUP;
}
@@ -8463,7 +8479,7 @@ i40e_dcb_init_configure(struct rte_eth_dev *dev, bool sw_dcb)
I40E_APP_PROTOID_FCOE;
ret = i40e_set_dcb_config(hw);
if (ret) {
- PMD_INIT_LOG(ERR, "default dcb config fails."
+ PMD_INIT_LOG(INFO, "default dcb config fails."
" err = %d, aq_err = %d.", ret,
hw->aq.asq_last_status);
return -ENOSYS;
@@ -8482,12 +8498,12 @@ i40e_dcb_init_configure(struct rte_eth_dev *dev, bool sw_dcb)
ret = i40e_init_dcb(hw);
if (!ret) {
if (hw->dcbx_status == I40E_DCBX_STATUS_DISABLED) {
- PMD_INIT_LOG(ERR, "HW doesn't support"
+ PMD_INIT_LOG(INFO, "HW doesn't support"
" DCBX offload.");
return -ENOTSUP;
}
} else {
- PMD_INIT_LOG(ERR, "DCBX configuration failed, err = %d,"
+ PMD_INIT_LOG(INFO, "DCBX configuration failed, err = %d,"
" aq_err = %d.", ret,
hw->aq.asq_last_status);
return -ENOTSUP;
diff --git a/src/dpdk22/lib/librte_ether/rte_ethdev.c b/src/dpdk22/lib/librte_ether/rte_ethdev.c
index 383ad120..44b4b640 100644
--- a/src/dpdk22/lib/librte_ether/rte_ethdev.c
+++ b/src/dpdk22/lib/librte_ether/rte_ethdev.c
@@ -1462,6 +1462,23 @@ rte_eth_fdir_stats_get(uint8_t port_id, uint32_t *stats, uint32_t start, uint32_
return 0;
}
+// TREX_PATCH
+// zero statistics counters, starting from start, for len counters.
+int
+rte_eth_fdir_stats_reset(uint8_t port_id, uint32_t *stats, uint32_t start, uint32_t len)
+{
+ struct rte_eth_dev *dev;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+
+ dev = &rte_eth_devices[port_id];
+
+ // Only xl710 support this
+ i40e_trex_fdir_stats_reset(dev, stats, start, len);
+
+ return 0;
+}
+
int
rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats)
{
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 652e6947..e20221d9 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -144,7 +144,7 @@ public:
virtual bool hw_rx_stat_supported(){return false;}
virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes
, int min, int max) {return -1;}
- virtual int reset_rx_stats(CPhyEthIF * _if, uint32_t *stats) {return 0;}
+ virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len) {}
virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd) { return -1;}
virtual int get_stat_counters_num() {return 0;}
virtual int get_rx_stat_capabilities() {return 0;}
@@ -325,7 +325,7 @@ public:
}
virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
virtual void clear_extended_stats(CPhyEthIF * _if);
- virtual int reset_rx_stats(CPhyEthIF * _if, uint32_t *stats);
+ virtual void reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len);
virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes, int min, int max);
virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd);
virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
@@ -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);
@@ -4008,9 +4009,7 @@ static CGlobalTRex g_trex;
int CPhyEthIF::reset_hw_flow_stats() {
if (get_ex_drv()->hw_rx_stat_supported()) {
- if (get_ex_drv()->reset_rx_stats(this, m_stats.m_fdir_prev_pkts) < 0) {
- return -1;
- }
+ get_ex_drv()->reset_rx_stats(this, m_stats.m_fdir_prev_pkts, 0, MAX_FLOW_STATS);
} else {
g_trex.m_rx_sl.reset_rx_stats(get_port_id());
}
@@ -4046,6 +4045,8 @@ int CPhyEthIF::get_flow_stats(rx_per_flow_t *rx_stats, tx_per_flow_t *tx_stats,
}
m_stats.m_rx_per_flow_pkts[i] = 0;
m_stats.m_rx_per_flow_bytes[i] = 0;
+ get_ex_drv()->reset_rx_stats(this, &m_stats.m_fdir_prev_pkts[i], i, 1);
+
}
if (tx_stats != NULL) {
tx_stats[i - min] = g_trex.clear_flow_tx_stats(m_port_id, i);
@@ -5058,6 +5059,8 @@ void CTRexExtendedDriverBase40G::add_del_rules(enum rte_filter_op op, uint8_t po
}
}
+extern "C" int rte_eth_fdir_stats_reset(uint8_t port_id, uint32_t *stats, uint32_t start, uint32_t len);
+
// type - rule type. Currently we only support rules in IP ID.
// proto - Packet protocol: UDP or TCP
// id - Counter id in HW. We assume it is in the range 0..MAX_FLOW_STATS
@@ -5085,6 +5088,7 @@ int CTRexExtendedDriverBase40G::configure_rx_filter_rules_statfull(CPhyEthIF * _
uint16_t hops = get_rx_check_hops();
int i;
+ rte_eth_fdir_stats_reset(port_id, NULL, 0, 1);
for (i = 0; i < 2; i++) {
uint8_t ttl = TTL_RESERVE_DUPLICATE - i - hops;
add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, ttl, 0, MAIN_DPDK_RX_Q, 0);
@@ -5108,18 +5112,24 @@ int CTRexExtendedDriverBase40G::configure_rx_filter_rules(CPhyEthIF * _if) {
}
}
-int CTRexExtendedDriverBase40G::reset_rx_stats(CPhyEthIF * _if, uint32_t *stats) {
- uint32_t diff_stats[MAX_FLOW_STATS];
- uint32_t diff_bytes[MAX_FLOW_STATS];
-
- // The HW counters start from some random values. The driver give us the diffs from previous,
- // each time we do get_rx_stats. We need to make one first call, at system startup,
- // and ignore the returned diffs
- return get_rx_stats(_if, diff_stats, stats, diff_bytes, NULL, 0, MAX_FLOW_STATS - 1);
+void CTRexExtendedDriverBase40G::reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len) {
+ uint32_t port_id = _if->get_port_id();
+ // Since the xl710 fdir counter stuck at 0xffffffff issue, we zero the HW counters, so should zero here also.
+ for (int i = min; i <= min - len + 1; i++) {
+ uint32_t rule_id = (port_id % m_if_per_card) * MAX_FLOW_STATS + i;
+ stats[i - min] = 0;
+ // Since flow dir counters are not wrapped around as promised in the data sheet, but rather get stuck at 0xffffffff
+ // we reset the HW value
+ rte_eth_fdir_stats_reset(port_id, NULL, rule_id, 1);
+ }
}
// instead of adding this to rte_ethdev.h
extern "C" int rte_eth_fdir_stats_get(uint8_t port_id, uint32_t *stats, uint32_t start, uint32_t len);
+// we read every 0.5 second. We want to catch the counter when it approach the maximum (where it will stuck,
+// and we will start losing packets).
+const uint32_t X710_FDIR_RESET_THRESHOLD = 0xffffffff - 1000000000/8/64*40;
+
// get rx stats on _if, between min and max
// prev_pkts should be the previous values read from the hardware.
// Getting changed to be equal to current HW values.
@@ -5135,13 +5145,17 @@ int CTRexExtendedDriverBase40G::get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, ui
rte_eth_fdir_stats_get(port_id, hw_stats, start, len);
for (int i = loop_start; i < loop_start + len; i++) {
- if (hw_stats[i - min] >= prev_pkts[i]) {
- pkts[i] = (uint64_t)(hw_stats[i - min] - prev_pkts[i]);
+ if (unlikely(hw_stats[i - min] > X710_FDIR_RESET_THRESHOLD)) {
+ // read again, and reset. Trying to lose minimal amount of packets.
+ // better solution is on its way - see trex-199 for details
+ uint32_t counter;
+ rte_eth_fdir_stats_reset(port_id, &counter, start + i, 1);
+ pkts[i] = counter - prev_pkts[i];
+ prev_pkts[i] = 0;
} else {
- // Wrap around
- pkts[i] = (uint64_t)((hw_stats[i - min] + ((uint64_t)1 << 32)) - prev_pkts[i]);
+ pkts[i] = hw_stats[i - min] - prev_pkts[i];
+ prev_pkts[i] = hw_stats[i - min];
}
- prev_pkts[i] = hw_stats[i - min];
bytes[i] = 0;
}
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);
}
/**