diff options
author | 2016-06-29 16:18:13 +0300 | |
---|---|---|
committer | 2016-06-29 16:18:13 +0300 | |
commit | 7772d0893579d0627c10515aeb6d9c9c8204316d (patch) | |
tree | a4336a4aae83331dffe7608207dd39f21f7e1315 | |
parent | 7e4ec3d452e0a3d8517147b2bec45d4abdbc041d (diff) |
flow stat/latency error counters code + documentation
-rw-r--r-- | scripts/automation/trex_control_plane/stl/examples/stl_flow_latency_stats.py | 25 | ||||
-rw-r--r-- | scripts/automation/trex_control_plane/stl/examples/stl_flow_stats.py | 45 | ||||
-rwxr-xr-x | scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py | 51 | ||||
-rw-r--r-- | scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py | 18 | ||||
-rw-r--r-- | src/flow_stat.cpp | 26 | ||||
-rw-r--r-- | src/internal_api/trex_platform_api.h | 3 | ||||
-rw-r--r-- | src/main_dpdk.cpp | 4 | ||||
-rw-r--r-- | src/stateless/rx/trex_stateless_rx_core.cpp | 12 | ||||
-rw-r--r-- | src/stateless/rx/trex_stateless_rx_core.h | 26 |
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 |