summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Barnea <ibarnea@cisco.com>2016-06-29 16:18:13 +0300
committerIdo Barnea <ibarnea@cisco.com>2016-06-29 16:18:13 +0300
commit7772d0893579d0627c10515aeb6d9c9c8204316d (patch)
treea4336a4aae83331dffe7608207dd39f21f7e1315
parent7e4ec3d452e0a3d8517147b2bec45d4abdbc041d (diff)
flow stat/latency error counters code + documentation
-rw-r--r--scripts/automation/trex_control_plane/stl/examples/stl_flow_latency_stats.py25
-rw-r--r--scripts/automation/trex_control_plane/stl/examples/stl_flow_stats.py45
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py51
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py18
-rw-r--r--src/flow_stat.cpp26
-rw-r--r--src/internal_api/trex_platform_api.h3
-rw-r--r--src/main_dpdk.cpp4
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.cpp12
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.h26
9 files changed, 161 insertions, 49 deletions
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 ac0e212b..d8a99479 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
@@ -1,10 +1,12 @@
+# Example showing how to define stream for latency measurement, and how to parse the latency information
+
import stl_path
from trex_stl_lib.api import *
import time
import pprint
-def rx_example (tx_port, rx_port, burst_size, bw):
+def rx_example (tx_port, rx_port, burst_size, pps):
print("\nGoing to inject {0} packets on port {1} - checking RX stats on port {2}\n".format(burst_size, tx_port, rx_port))
@@ -19,7 +21,7 @@ def rx_example (tx_port, rx_port, burst_size, bw):
packet = pkt,
flow_stats = STLFlowLatencyStats(pg_id = 5),
mode = STLTXSingleBurst(total_pkts = total_pkts,
- percentage = bw))
+ pps = pps))
# connect to server
c.connect()
@@ -32,7 +34,7 @@ def rx_example (tx_port, rx_port, burst_size, bw):
print("\nInjecting {0} packets on port {1}\n".format(total_pkts, tx_port))
- rc = rx_iteration(c, tx_port, rx_port, total_pkts, pkt.get_pkt_len(), bw)
+ rc = rx_iteration(c, tx_port, rx_port, total_pkts, pkt.get_pkt_len())
if not rc:
passed = False
@@ -44,12 +46,12 @@ def rx_example (tx_port, rx_port, burst_size, bw):
c.disconnect()
if passed:
- print("\nTest has passed :-)\n")
+ print("\nTest passed :-)\n")
else:
- print("\nTest has failed :-(\n")
+ print("\nTest failed :-(\n")
# RX one iteration
-def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len, bw):
+def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len):
c.clear_stats()
@@ -58,7 +60,8 @@ def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len, bw):
stats = c.get_stats()
flow_stats = stats['flow_stats'].get(5)
- lat_stats = stats['latency'].get(5)
+ global_lat_stats = stats['latency']
+ lat_stats = global_lat_stats.get(5)
if not flow_stats:
print("no flow stats available")
return False
@@ -74,6 +77,8 @@ def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len, bw):
dup = lat_stats['err_cntrs']['dup']
sth = lat_stats['err_cntrs']['seq_too_high']
stl = lat_stats['err_cntrs']['seq_too_low']
+ old_flow = global_lat_stats['global']['old_flow']
+ bad_hdr = global_lat_stats['global']['bad_hdr']
lat = lat_stats['latency']
jitter = lat['jitter']
avg = lat['average']
@@ -89,6 +94,10 @@ def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len, bw):
return False
print('Error counters: dropped:{0}, ooo:{1} dup:{2} seq too high:{3} seq too low:{4}'.format(drops, ooo, dup, sth, stl))
+ if old_flow:
+ print ('Packets arriving too late after flow stopped: {0}'.format(old_flow))
+ if bad_hdr:
+ print ('Latency packets with corrupted info: {0}'.format(bad_hdr))
print('Latency info:')
print(" Maximum latency(usec): {0}".format(tot_max))
print(" Minimum latency(usec): {0}".format(tot_min))
@@ -131,5 +140,5 @@ def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len, bw):
return True
# run the tests
-rx_example(tx_port = 1, rx_port = 0, burst_size = 500000, bw = 50)
+rx_example(tx_port = 0, rx_port = 1, burst_size = 1000, pps = 1000)
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 ed4902fa..3c630ece 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
@@ -1,3 +1,5 @@
+# Example showing how to define stream for getting per flow statistics, and how to parse the received statistics
+
import stl_path
from trex_stl_lib.api import *
@@ -27,18 +29,14 @@ def rx_example (tx_port, rx_port, burst_size, bw):
# prepare our ports
c.reset(ports = [tx_port, rx_port])
- # add both streams to ports
+ # add stream to port
c.add_streams([s1], ports = [tx_port])
- print("\ninjecting {0} packets on port {1}\n".format(total_pkts, tx_port))
-
- 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(), bw)
- if not rc:
- passed = False
- break
+ print("\ngoing to inject {0} packets on port {1}\n".format(total_pkts, tx_port))
+ rc = rx_iteration(c, tx_port, rx_port, total_pkts, s1.get_pkt_len())
+ if not rc:
+ passed = False
except STLError as e:
passed = False
@@ -48,19 +46,21 @@ def rx_example (tx_port, rx_port, burst_size, bw):
c.disconnect()
if passed:
- print("\nTest has passed :-)\n")
+ print("\nTest passed :-)\n")
else:
- print("\nTest has failed :-(\n")
+ print("\nTest failed :-(\n")
# RX one iteration
-def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len, bw):
-
+def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len):
+ ret = True
+
c.clear_stats()
c.start(ports = [tx_port])
c.wait_on_traffic(ports = [tx_port])
- flow_stats = c.get_stats()['flow_stats'].get(5)
+ global_flow_stats = c.get_stats()['flow_stats']
+ flow_stats = global_flow_stats.get(5)
if not flow_stats:
print("no flow stats available")
return False
@@ -78,26 +78,33 @@ def rx_iteration (c, tx_port, rx_port, total_pkts, pkt_len, bw):
if tx_pkts != total_pkts:
print("TX pkts mismatch - got: {0}, expected: {1}".format(tx_pkts, total_pkts))
pprint.pprint(flow_stats)
- return False
+ ret = False
else:
print("TX pkts match - {0}".format(tx_pkts))
if tx_bytes != (total_pkts * pkt_len):
print("TX bytes mismatch - got: {0}, expected: {1}".format(tx_bytes, (total_pkts * pkt_len)))
pprint.pprint(flow_stats)
- return False
+ ret = False
else:
print("TX bytes match - {0}".format(tx_bytes))
if rx_pkts != total_pkts:
print("RX pkts mismatch - got: {0}, expected: {1}".format(rx_pkts, total_pkts))
pprint.pprint(flow_stats)
- return False
+ ret = False
else:
print("RX pkts match - {0}".format(rx_pkts))
- return True
+
+ for field in ['rx_err', 'tx_err']:
+ for port in global_flow_stats['global'][field].keys():
+ if global_flow_stats['global'][field][port] != 0:
+ print ("\n{0} on port {1}: {2} - You should consider increasing rx_delay_ms value in wait_on_traffic"
+ .format(field, port, global_flow_stats['global'][field][port]))
+
+ return ret
# run the tests
-rx_example(tx_port = 1, rx_port = 2, burst_size = 500000, bw = 50)
+rx_example(tx_port = 0, rx_port = 1, burst_size = 500, bw = 50)
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 c1833754..acedf24f 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
@@ -1284,7 +1284,7 @@ class STLClient(object):
**total** and per port statistics contain dictionary with following format.
- Most of the bytes counters (unless specified otherwise) are in L2 layer including the FCS. e.g. minimum packet size in 64 bytes
+ Most of the bytes counters (unless specified otherwise) are in L2 layer, including the Ethernet FCS. e.g. minimum packet size is 64 bytes
=============================== ===============
key Meaning
@@ -1303,21 +1303,34 @@ class STLClient(object):
.. _flow_stats:
- **flow_stats** contains dictionaries per packet group id (pg id). Each one with the following structure.
+ **flow_stats** contains :ref:`global dictionary <flow_stats_global>`, and dictionaries per packet group id (pg id). See structures below.
+
+ **per pg_id flow stat** dictionaries have following structure:
================= ===============
key Meaning
================= ===============
- rx_bps Receivd bytes per second rate
- rx_bps_l1 Receivd bytes per second rate, including layer one
+ rx_bps Received bytes per second rate
+ rx_bps_l1 Received 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_bps Transmit bytes per second rate
+ tx_bps_l1 Transmit 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
+ tx_pps Transmit packets per second rate
+ ================= ===============
+
+ .. _flow_stats_global:
+
+ **global flow stats** dictionary has the following structure:
+
+ ================= ===============
+ key Meaning
+ ================= ===============
+ rx_err Number of flow statistics packets received that we could not associate to any pg_id. This can happen if latency on the used setup is large. See :ref:`wait_on_traffic <wait_on_traffic>` rx_delay_ms parameter for details.
+ tx_err Number of flow statistics packets transmitted that we could not associate to any pg_id. This is never expected. If you see this different than 0, please report.
================= ===============
.. _global:
@@ -1340,7 +1353,9 @@ class STLClient(object):
.. _latency:
- **latency** contains dictionary per packet group id (pg id). Each one with the following structure.
+ **latency** contains :ref:`global dictionary <lat_stats_global>`, and dictionaries per packet group id (pg id). Each one with the following structure.
+
+ **per pg_id latency stat** dictionaries have following structure:
=========================== ===============
key Meaning
@@ -1394,7 +1409,16 @@ class STLClient(object):
total_min Minimum latency measured over the stream lifetime (in usec).
================= ===============
+ .. _lat_stats_global:
+ **global latency stats** dictionary has the following structure:
+
+ ================= ===============
+ key Meaning
+ ================= ===============
+ old_flow Number of latency statistics packets received that we could not associate to any pg_id. This can happen if latency on the used setup is large. See :ref:`wait_on_traffic <wait_on_traffic>` rx_delay_ms parameter for details.
+ bad_hdr Number of latency packets received with bad latency data. This can happen becuase of garbage packets in the network, or if the DUT causes packet corruption.
+ ================= ===============
:raises:
None
@@ -2274,6 +2298,8 @@ class STLClient(object):
@__api_check(True)
def wait_on_traffic (self, ports = None, timeout = 60, rx_delay_ms = 10):
"""
+ .. _wait_on_traffic:
+
Block until traffic on specified port(s) has ended
:parameters:
@@ -2284,12 +2310,11 @@ class STLClient(object):
timeout in seconds
rx_delay_ms : int
- time to wait until RX filters are removed
- this value should reflect the time it takes
- packets which were transmitted to arrive
+ Time to wait (in milliseconds) after last packet was sent, until RX filters used for
+ measuring flow statistics and latency are removed.
+ This value should reflect the time it takes packets which were transmitted to arrive
to the destination.
- after this time the RX filters will be removed
-
+ After this time, RX filters will be removed, and packets arriving for per flow statistics feature and latency flows will be counted as errors.
:raises:
+ :exc:`STLTimeoutError` - in case timeout has expired
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 3effa1f0..f74c8fa5 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
@@ -1010,6 +1010,13 @@ class CLatencyStats(CTRexStats):
snapshot = {}
output = {}
+ output['global'] = {}
+ for field in ['bad_hdr', 'old_flow']:
+ if 'global' in snapshot and field in snapshot['global']:
+ output['global'][field] = snapshot['global'][field]
+ else:
+ output['global'][field] = 0
+
# we care only about the current active keys
pg_ids = list(filter(is_intable, snapshot.keys()))
@@ -1107,6 +1114,14 @@ class CRxStats(CTRexStats):
# copy timestamp field
output['ts'] = current['ts']
+ # global (not per pg_id) error counters
+ output['global'] = {}
+ for field in ['rx_err', 'tx_err']:
+ output['global'][field] = {}
+ if 'global' in current and field in current['global']:
+ for port in current['global'][field]:
+ output['global'][field][int(port)] = current['global'][field][port]
+
# we care only about the current active keys
pg_ids = list(filter(is_intable, current.keys()))
@@ -1254,6 +1269,9 @@ class CRxStats(CTRexStats):
for pg_id, value in self.latest_stats.items():
# skip non ints
if not is_intable(pg_id):
+ # 'global' stats are in the same level of the pg_ids. We do want them to go to the user
+ if pg_id == 'global':
+ stats[pg_id] = value
continue
# bare counters
stats[int(pg_id)] = {}
diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp
index 5503434f..8c2f2566 100644
--- a/src/flow_stat.cpp
+++ b/src/flow_stat.cpp
@@ -796,6 +796,9 @@ int CFlowStatRuleMgr::start_stream(TrexStream * stream) {
if (m_num_started_streams == 0) {
send_start_stop_msg_to_rx(true); // First transmitting stream. Rx core should start reading packets;
+ //also good time to zero global counters
+ 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));
// wait to make sure that message is acknowledged. RX core might be in deep sleep mode, and we want to
// start transmitting packets only after it is working, otherwise, packets will get lost.
@@ -910,7 +913,7 @@ int CFlowStatRuleMgr::stop_stream(TrexStream * stream) {
m_num_started_streams--;
assert (m_num_started_streams >= 0);
if (m_num_started_streams == 0) {
- send_start_stop_msg_to_rx(false); // No more transmittig streams. Rx core shoulde get into idle loop.
+ send_start_stop_msg_to_rx(false); // No more transmittig streams. Rx core should get into idle loop.
}
return 0;
}
@@ -947,6 +950,7 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo
tx_per_flow_t tx_stats[MAX_FLOW_STATS];
tx_per_flow_t tx_stats_payload[MAX_FLOW_STATS_PAYLOAD];
rfc2544_info_t rfc2544_info[MAX_FLOW_STATS_PAYLOAD];
+ CRxCoreErrCntrs rx_err_cntrs;
Json::FastWriter writer;
Json::Value s_root;
Json::Value l_root;
@@ -973,6 +977,7 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo
}
m_api->get_rfc2544_info(rfc2544_info, 0, m_max_hw_id_payload, false);
+ m_api->get_rx_err_cntrs(&rx_err_cntrs);
// read hw counters, and update
for (uint8_t port = 0; port < m_num_ports; port++) {
@@ -1046,10 +1051,21 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo
// general per port data
for (uint8_t port = 0; port < m_num_ports; port++) {
std::string str_port = static_cast<std::ostringstream*>( &(std::ostringstream() << int(port) ) )->str();
- if (m_rx_cant_count_err[port] != 0)
- s_data_section["port_data"][str_port]["rx_err"] = m_rx_cant_count_err[port];
- if (m_tx_cant_count_err[port] != 0)
- s_data_section["port_data"][str_port]["tx_err"] = m_tx_cant_count_err[port];
+ if ((m_rx_cant_count_err[port] != 0) || baseline)
+ s_data_section["global"]["rx_err"][str_port] = m_rx_cant_count_err[port];
+ if ((m_tx_cant_count_err[port] != 0) || baseline)
+ s_data_section["global"]["tx_err"][str_port] = m_tx_cant_count_err[port];
+ }
+
+ // payload rules rx errors
+ uint64_t tmp_cnt;
+ tmp_cnt = rx_err_cntrs.get_bad_header();
+ if (tmp_cnt || baseline) {
+ l_data_section["global"]["bad_hdr"] = Json::Value::UInt64(tmp_cnt);
+ }
+ tmp_cnt = rx_err_cntrs.get_old_flow();
+ if (tmp_cnt || baseline) {
+ l_data_section["global"]["old_flow"] = Json::Value::UInt64(tmp_cnt);
}
flow_stat_user_id_map_it_t it;
diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h
index a52f9e60..4f19ec9d 100644
--- a/src/internal_api/trex_platform_api.h
+++ b/src/internal_api/trex_platform_api.h
@@ -148,6 +148,7 @@ public:
virtual int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset
, TrexPlatformApi::driver_stat_cap_e type) const = 0;
virtual int get_rfc2544_info(void *rfc2544_info, int min, int max, bool reset) const = 0;
+ virtual int get_rx_err_cntrs(void *rx_err_cntrs) const = 0;
virtual int reset_hw_flow_stats(uint8_t port_id) const = 0;
virtual void get_port_num(uint8_t &port_num) const = 0;
virtual int add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const = 0;
@@ -180,6 +181,7 @@ public:
int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset
, TrexPlatformApi::driver_stat_cap_e type) const;
int get_rfc2544_info(void *rfc2544_info, int min, int max, bool reset) const;
+ int get_rx_err_cntrs(void *rx_err_cntrs) const;
int reset_hw_flow_stats(uint8_t port_id) const;
void get_port_num(uint8_t &port_num) const;
int add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const;
@@ -237,6 +239,7 @@ public:
int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset
, TrexPlatformApi::driver_stat_cap_e type) const {return 0;};
virtual int get_rfc2544_info(void *rfc2544_info, int min, int max, bool reset) const {return 0;};
+ virtual int get_rx_err_cntrs(void *rx_err_cntrs) const {return 0;};
virtual int reset_hw_flow_stats(uint8_t port_id) const {return 0;};
virtual void get_port_num(uint8_t &port_num) const {port_num = 2;};
virtual int add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const {return 0;}
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 45e46810..941612b1 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -5760,6 +5760,10 @@ int TrexDpdkPlatformApi::get_rfc2544_info(void *rfc2544_info, int min, int max,
return g_trex.m_rx_sl.get_rfc2544_info((rfc2544_info_t *)rfc2544_info, min, max, reset);
}
+int TrexDpdkPlatformApi::get_rx_err_cntrs(void *rx_err_cntrs) const {
+ return g_trex.m_rx_sl.get_rx_err_cntrs((CRxCoreErrCntrs *)rx_err_cntrs);
+}
+
int TrexDpdkPlatformApi::reset_hw_flow_stats(uint8_t port_id) const {
return g_trex.m_ports[port_id].reset_hw_flow_stats();
}
diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp
index 0bd601b6..853fc868 100644
--- a/src/stateless/rx/trex_stateless_rx_core.cpp
+++ b/src/stateless/rx/trex_stateless_rx_core.cpp
@@ -206,6 +206,7 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *
if (unlikely(fsp_head->magic != FLOW_STAT_PAYLOAD_MAGIC) || hw_id >= MAX_FLOW_STATS_PAYLOAD) {
good_packet = false;
+ m_err_cntrs.m_bad_header++;
} else {
curr_rfc2544 = &m_rfc2544[hw_id];
@@ -216,6 +217,7 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *
if (fsp_head->flow_seq == curr_rfc2544->get_prev_flow_seq()) {
// packet from previous flow using this hw_id that arrived late
good_packet = false;
+ m_err_cntrs.m_old_flow++;
} else {
if (curr_rfc2544->no_flow_seq()) {
// first packet we see from this flow
@@ -224,6 +226,7 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *
} else {
// garbage packet
good_packet = false;
+ m_err_cntrs.m_bad_header++;
}
}
}
@@ -278,9 +281,7 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *
}
} else {
hw_id = get_hw_id(ip_id);
- if (hw_id >= MAX_FLOW_STATS) {
- // increase some error counter
- } else {
+ if (hw_id < MAX_FLOW_STATS) {
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 + 4); // +4 for ethernet CRC
}
@@ -444,6 +445,11 @@ int CRxCoreStateless::get_rfc2544_info(rfc2544_info_t *rfc2544_info, int min, in
return 0;
}
+int CRxCoreStateless::get_rx_err_cntrs(CRxCoreErrCntrs *rx_err) {
+ *rx_err = m_err_cntrs;
+ return 0;
+}
+
void CRxCoreStateless::set_working_msg_ack(bool val) {
sanb_smp_memory_barrier();
m_ack_start_work_msg = val;
diff --git a/src/stateless/rx/trex_stateless_rx_core.h b/src/stateless/rx/trex_stateless_rx_core.h
index 209dc29f..fc66704e 100644
--- a/src/stateless/rx/trex_stateless_rx_core.h
+++ b/src/stateless/rx/trex_stateless_rx_core.h
@@ -95,6 +95,25 @@ class CRFC2544Info {
uint16_t m_prev_flow_seq;
};
+class CRxCoreErrCntrs {
+ friend CRxCoreStateless;
+
+ public:
+ uint64_t get_bad_header() {return m_bad_header;}
+ uint64_t get_old_flow() {return m_old_flow;}
+ CRxCoreErrCntrs() {
+ reset();
+ }
+ void reset() {
+ m_bad_header = 0;
+ m_old_flow = 0;
+ }
+
+ private:
+ uint64_t m_bad_header;
+ uint64_t m_old_flow;
+};
+
class CRxCoreStateless {
enum state_e {
STATE_IDLE,
@@ -109,7 +128,11 @@ class CRxCoreStateless {
int get_rx_stats(uint8_t port_id, rx_per_flow_t *rx_stats, int min, int max, bool reset
, TrexPlatformApi::driver_stat_cap_e type);
int get_rfc2544_info(rfc2544_info_t *rfc2544_info, int min, int max, bool reset);
- void work() {m_state = STATE_WORKING;}
+ int get_rx_err_cntrs(CRxCoreErrCntrs *rx_err);
+ void work() {
+ m_state = STATE_WORKING;
+ m_err_cntrs.reset(); // When starting to work, reset global counters
+ }
void idle() {m_state = STATE_IDLE;}
void quit() {m_state = STATE_QUIT;}
bool is_working() const {return (m_ack_start_work_msg == true);}
@@ -146,6 +169,7 @@ class CRxCoreStateless {
CCpuUtlCp m_cpu_cp_u;
// Used for acking "work" (go out of idle) messages from cp
volatile bool m_ack_start_work_msg __rte_cache_aligned;
+ CRxCoreErrCntrs m_err_cntrs;
CRFC2544Info m_rfc2544[MAX_FLOW_STATS_PAYLOAD];
};
#endif