summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYaroslav Brustinov <ybrustin@cisco.com>2016-07-04 12:55:42 +0300
committerYaroslav Brustinov <ybrustin@cisco.com>2016-07-04 12:55:42 +0300
commit7f58dadbd502f6fe504170c443505c7ad2eb3785 (patch)
tree1f86a439d24565332a7a286841913d080fb0be74
parenta76479bc269cad96475f9c71381b4f826d47709f (diff)
parent582e6dddb5693d5fa7576c19b0ef7c1c0723ff59 (diff)
Merge branch 'master' into cpu_per_core
-rwxr-xr-xVERSION3
-rwxr-xr-xlinux_dpdk/ws_main.py3
-rw-r--r--scripts/automation/regression/stateless_tests/stl_rx_test.py107
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py22
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py16
-rwxr-xr-xscripts/run_regression9
-rwxr-xr-xsrc/bp_sim.h32
-rwxr-xr-xsrc/common/basic_utils.cpp38
-rwxr-xr-xsrc/common/basic_utils.h10
-rw-r--r--src/main_dpdk.cpp54
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.cpp47
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.h11
12 files changed, 288 insertions, 64 deletions
diff --git a/VERSION b/VERSION
index f85ec405..d73be704 100755
--- a/VERSION
+++ b/VERSION
@@ -1,4 +1,5 @@
-v2.03
+v2.04
+
diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py
index 12a2fd89..dde94dc4 100755
--- a/linux_dpdk/ws_main.py
+++ b/linux_dpdk/ws_main.py
@@ -714,8 +714,7 @@ def build_prog (bld, build_obj):
debug_file_list='';
if not build_obj.isRelease ():
#debug
- #debug_file_list +=ef_src.file_list(top)
- pass
+ debug_file_list +=ef_src.file_list(top)
bld.objects(
diff --git a/scripts/automation/regression/stateless_tests/stl_rx_test.py b/scripts/automation/regression/stateless_tests/stl_rx_test.py
index 84f32081..23ebf081 100644
--- a/scripts/automation/regression/stateless_tests/stl_rx_test.py
+++ b/scripts/automation/regression/stateless_tests/stl_rx_test.py
@@ -74,7 +74,7 @@ class STLRX_Test(CStlGeneral_Test):
pprint.pprint(err_latency)
tmp = 'RX pkts ERROR - one of the error is on'
print(tmp)
- #assert False, tmp
+ assert False, tmp
if latency['average']> max_average:
pprint.pprint(latency_stats)
@@ -261,7 +261,7 @@ class STLRX_Test(CStlGeneral_Test):
- def __test_9k_stream(self,pgid,ports,precet,max_latency,avg_latency,duration,pkt_size):
+ def __9k_stream(self,pgid,ports,precet,max_latency,avg_latency,duration,pkt_size):
my_pg_id=pgid
s_ports=ports;
all_ports=list(CTRexScenario.stl_ports_map['map'].keys());
@@ -314,6 +314,8 @@ class STLRX_Test(CStlGeneral_Test):
# check low latency when you have stream of 9K stream
def test_9k_stream(self):
+ #self.skip('Skip due to bug trex-215')
+
if self.latency_9k_enable == False:
print("SKIP")
return
@@ -330,18 +332,14 @@ class STLRX_Test(CStlGeneral_Test):
s_port=sorted(s_port)
if self.speed == 40 :
# the NIC does not support all full rate in case both port works let's filter odd ports
- tmp_l=[]
- for port in s_port:
- if ((int(port) % 2) ==0):
- tmp_l.append(port);
- s_port=tmp_l;
+ s_port=list(filter(lambda x: x % 2==0, s_port))
if len(s_port)==0:
s_port=[0];
error=1;
for j in range(0,5):
print(" {4} - duration {0} pgid {1} pkt_size {2} s_port {3} ".format(duration,pgid,pkt_size,s_port,j));
- if self.__test_9k_stream(pgid,
+ if self.__9k_stream(pgid,
s_port,90,
self.latency_9k_max_latency,
self.latency_9k_max_average,
@@ -356,7 +354,100 @@ class STLRX_Test(CStlGeneral_Test):
print("===>Iteration {0} PASS {1}".format(i,j));
+ def check_stats (self,stats,a,b,err):
+ if a != b:
+ tmp = 'ERROR field : {0}, read : {1} != expected : {2} '.format(err,a,b)
+ pprint.pprint(stats)
+ assert False,tmp
+
+
+
+ def send_1_burst(self,from_port,is_latency,pkts):
+
+ pid = from_port
+ base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+
+ pad = (60 - len(base_pkt)) * 'x'
+
+ stream_pkt = STLPktBuilder(pkt = base_pkt/pad)
+
+ all_ports=list(CTRexScenario.stl_ports_map['map'].keys());
+
+ dpid = CTRexScenario.stl_ports_map['map'][pid]
+
+ s_ports =[pid]
+ try:
+ # reset all ports
+ self.c.reset(ports = all_ports)
+
+
+ for pid in s_ports:
+ if is_latency:
+ s1 = STLStream(name = 'rx',
+ packet = stream_pkt,
+ flow_stats = STLFlowLatencyStats(pg_id = 5 + pid),
+ mode = STLTXSingleBurst(total_pkts = pkts,pps = 1000))
+ else:
+ s1 = STLStream(name = 'rx',
+ packet = stream_pkt,
+ mode = STLTXSingleBurst(total_pkts = pkts,pps = 1000))
+
+
+ # add both streams to ports
+ self.c.add_streams(s1, ports = [pid])
+
+ self.c.clear_stats()
+
+ self.c.start(ports = s_ports)
+ self.c.wait_on_traffic(ports = s_ports)
+
+ stats = self.c.get_stats()
+
+ ips = stats[dpid]
+ ops = stats[pid]
+ tps = stats['total']
+ tbytes = pkts*64
+
+ self.check_stats (stats,ops["obytes"], tbytes,"ops[obytes]")
+ self.check_stats (stats,ops["opackets"], pkts,"ops[opackets]")
+
+ self.check_stats (stats,ips["ibytes"], tbytes,"ips[ibytes]")
+ self.check_stats (stats,ips["ipackets"], pkts,"ips[ipackets]")
+
+ self.check_stats (stats,tps['ibytes'], tbytes,"tps[ibytes]")
+ self.check_stats (stats,tps['obytes'], tbytes,"tps[obytes]")
+ self.check_stats (stats,tps['ipackets'], pkts,"tps[ipackets]")
+ self.check_stats (stats,tps['opackets'], pkts,"tps[opackets]")
+
+ if is_latency:
+ ls=stats['flow_stats'][5+ pid]
+ self.check_stats (stats,ls['rx_pkts']['total'], pkts,"ls['rx_pkts']['total']")
+ self.check_stats (stats,ls['rx_pkts'][dpid], pkts,"ls['rx_pkts'][dpid]")
+
+ self.check_stats (stats,ls['tx_pkts']['total'], pkts,"ls['tx_pkts']['total']")
+ self.check_stats (stats,ls['tx_pkts'][pid], pkts,"ls['tx_pkts'][pid]")
+
+ self.check_stats (stats,ls['tx_bytes']['total'], tbytes,"ls['tx_bytes']['total']")
+ self.check_stats (stats,ls['tx_bytes'][pid], pkts+1,"ls['tx_bytes'][pid]")
+
+
+ return 0
+
+ except STLError as e:
+ assert False , '{0}'.format(e)
+
+
+
+ def test_fcs_stream(self):
+ """ this test send 1 64 byte packet with latency and check that all counters are reported as 64 bytes"""
+ #self.skip('Skip due to bug trex-213')
+
+ all_ports=list(CTRexScenario.stl_ports_map['map'].keys());
+ for port in all_ports:
+ for l in [True,False]:
+ print(" test port {0} latency : {1} ".format(port,l))
+ self.send_1_burst(port,False,100)
# this test adds more and more latency streams and re-test with incremental
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 38a18d16..dc0035b3 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
@@ -1287,18 +1287,20 @@ 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
+
=============================== ===============
key Meaning
=============================== ===============
- ibytes Number of input bytes
+ ibytes Number of input bytes
ierrors Number of input errors
- ipackets Number of input packets
- obytes Number of output bytes
+ ipackets Number of input packets
+ obytes Number of output bytes
oerrors Number of output errors
opackets Number of output packets
- rx_bps Receive bytes per second rate
+ rx_bps Receive bytes per second rate (L2 layer)
rx_pps Receive packet per second rate
- tx_bps Transmit bytes per second rate
+ tx_bps Transmit bytes per second rate (L2 layer)
tx_pps Transmit packet per second rate
=============================== ===============
@@ -1330,8 +1332,8 @@ class STLClient(object):
================= ===============
bw_per_core Estimated byte rate Trex can support per core. This is calculated by extrapolation of current rate and load on transmitting cores.
cpu_util Estimate of the average utilization percentage of the transimitting cores
- queue_full Total number of packets we could not transmit because NIC TX queue was full. This usually indicates that the rate we trying to transmit is too high for this port
- rx_cpu_util Estimate of the utilization percentage of the core handling RX traffic
+ queue_full Total number of packets transmitted while the NIC TX queue was full. The packets will be transmitted, eventually, but will create high CPU%due to polling the queue. This usually indicates that the rate we trying to transmit is too high for this port.
+ rx_cpu_util Estimate of the utilization percentage of the core handling RX traffic. Too high value of this CPU utilization could cause drop of latency streams.
rx_drop_bps Received bytes per second drop rate
rx_bps Received bytes per second rate
rx_pps Received packets per second rate
@@ -1359,7 +1361,7 @@ class STLClient(object):
================= ===============
key Meaning (see better explanation below the table)
================= ===============
- dropped How many packets were dropped.
+ dropped How many packets were dropped (estimation)
dup How many packets were duplicated.
out_of_order How many packets we received out of order.
seq_too_high How many events of packet with sequence number too high we saw.
@@ -1387,10 +1389,10 @@ class STLClient(object):
================= ===============
key Meaning
================= ===============
- average Average latency over the stream lifetime (usec). Total average is computed each sampling period by following formula: <average> = <prev average>/2 + <last sampling period average>/2
+ average Average latency over the stream lifetime (usec).Low pass filter is applied to the last window average.It is computed each sampling period by following formula: <average> = <prev average>/2 + <last sampling period average>/2
histogram Dictionary describing logarithmic distribution histogram of packet latencies. Keys in the dictionary represent range of latencies (in usec). Values are the total number of packets received in this latency range. For example, an entry {100:13} would mean that we saw 13 packets with latency in the range between 100 and 200 usec.
jitter Jitter of latency samples, computed as described in :rfc:`3550#appendix-A.8`
- last_max Maximum latency measured between last two data reads from server.
+ last_max Maximum latency measured between last two data reads from server (0.5 sec window).
total_max Maximum latency measured over the stream lifetime (in usec).
total_min Minimum latency measured over the stream lifetime (in usec).
================= ===============
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 8e8388fd..678adb4e 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
@@ -1130,12 +1130,7 @@ class CRxStats(CTRexStats):
def __init__(self, ports):
super(CRxStats, self).__init__()
self.ports = ports
- self.ports_speed = {}
- def get_ports_speed(self):
- for port in self.ports:
- self.ports_speed[str(port)] = self.ports[port].get_speed_bps()
- self.ports_speed['total'] = sum(self.ports_speed.values())
# calculates a diff between previous snapshot
# and current one
@@ -1253,8 +1248,8 @@ class CRxStats(CTRexStats):
return
# TX
- self.get_ports_speed()
for port in pg_current['tx_pkts'].keys():
+
prev_tx_pps = pg_prev['tx_pps'].get(port)
now_tx_pkts = pg_current['tx_pkts'].get(port)
prev_tx_pkts = pg_prev['tx_pkts'].get(port)
@@ -1263,19 +1258,20 @@ class CRxStats(CTRexStats):
prev_tx_bps = pg_prev['tx_bps'].get(port)
now_tx_bytes = pg_current['tx_bytes'].get(port)
prev_tx_bytes = pg_prev['tx_bytes'].get(port)
+
pg_current['tx_bps'][port], pg_current['tx_bps_lpf'][port] = self.calc_bps(prev_tx_bps, now_tx_bytes, prev_tx_bytes, diff_sec)
if pg_current['tx_bps'].get(port) != None and pg_current['tx_pps'].get(port) != None:
pg_current['tx_bps_L1'][port] = calc_bps_L1(pg_current['tx_bps'][port], pg_current['tx_pps'][port])
pg_current['tx_bps_L1_lpf'][port] = calc_bps_L1(pg_current['tx_bps_lpf'][port], pg_current['tx_pps_lpf'][port])
- pg_current['tx_line_util'][port] = 100.0 * pg_current['tx_bps_L1'][port] / self.ports_speed[port]
else:
pg_current['tx_bps_L1'][port] = None
pg_current['tx_bps_L1_lpf'][port] = None
- pg_current['tx_line_util'][port] = None
+
# RX
for port in pg_current['rx_pkts'].keys():
+
prev_rx_pps = pg_prev['rx_pps'].get(port)
now_rx_pkts = pg_current['rx_pkts'].get(port)
prev_rx_pkts = pg_prev['rx_pkts'].get(port)
@@ -1288,11 +1284,9 @@ class CRxStats(CTRexStats):
if pg_current['rx_bps'].get(port) != None and pg_current['rx_pps'].get(port) != None:
pg_current['rx_bps_L1'][port] = calc_bps_L1(pg_current['rx_bps'][port], pg_current['rx_pps'][port])
pg_current['rx_bps_L1_lpf'][port] = calc_bps_L1(pg_current['rx_bps_lpf'][port], pg_current['rx_pps_lpf'][port])
- pg_current['rx_line_util'][port] = 100.0 * pg_current['rx_bps_L1'][port] / self.ports_speed[port]
else:
pg_current['rx_bps_L1'][port] = None
pg_current['rx_bps_L1_lpf'][port] = None
- pg_current['rx_line_util'][port] = None
def calc_pps (self, prev_bw, now, prev, diff_sec):
@@ -1355,7 +1349,7 @@ class CRxStats(CTRexStats):
stats[int(pg_id)][field][int(port)] = val if val != 'N/A' else StatNotAvailable(field)
# BW values
- for field in ['tx_pps', 'tx_bps', 'tx_bps_L1', 'rx_pps', 'rx_bps', 'rx_bps_L1', 'tx_line_util', 'rx_line_util']:
+ for field in ['tx_pps', 'tx_bps', 'tx_bps_L1', 'rx_pps', 'rx_bps', 'rx_bps_L1']:
val = self.get([pg_id, field, 'total'])
stats[int(pg_id)][field] = {'total': val if val != 'N/A' else StatNotAvailable(field)}
for port in value[field].keys():
diff --git a/scripts/run_regression b/scripts/run_regression
index bdc2f185..407b7f84 100755
--- a/scripts/run_regression
+++ b/scripts/run_regression
@@ -1,6 +1,9 @@
#!/bin/bash
-INPUT_ARGS=${@//--python[23]/}
+ARGS=()
+for var in "$@"; do
+ [[ "$var" != '--python2' && "$var" != '--python3' ]] && ARGS+=("$var")
+done
if [[ $@ =~ '--python2' || ! $@ =~ '--python3' ]]; then
source find_python.sh --python2
@@ -8,7 +11,7 @@ if [[ $@ =~ '--python2' || ! $@ =~ '--python3' ]]; then
# Python 2
echo Python2 test
- $PYTHON trex_unit_test.py $INPUT_ARGS
+ $PYTHON trex_unit_test.py "${ARGS[@]}"
if [ $? -eq 0 ]; then
printf "\n$PYTHON test succeeded\n\n"
else
@@ -24,7 +27,7 @@ if [[ $@ =~ '--python3' ]]; then
# Python 3
echo Python3 test
- $PYTHON trex_unit_test.py $INPUT_ARGS
+ $PYTHON trex_unit_test.py "${ARGS[@]}"
if [ $? -eq 0 ]; then
printf "\n$PYTHON test succeeded\n\n"
else
diff --git a/src/bp_sim.h b/src/bp_sim.h
index 8a38beb7..05900351 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -256,7 +256,23 @@ void on_node_last(uint8_t plugin_id,CGenNode * node);
rte_mbuf_t * on_node_generate_mbuf(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info);
class CPreviewMode ;
-struct CGenNode;
+
+class CLatencyPktData {
+ public:
+ CLatencyPktData() {m_magic = 0xaa;}
+ inline uint32_t get_seq_num() {return m_seq_num;}
+ inline void inc_seq_num() {m_seq_num++;}
+ inline uint32_t get_magic() {return m_magic;}
+ void reset() {
+ m_seq_num = UINT32_MAX - 1; // catch wrap around issues early
+ m_magic++;
+ }
+
+ private:
+ uint32_t m_seq_num; // seq num to put in packet for payload rules
+ uint16_t m_magic; // magic to put in packet for payload rules
+};
+
/* represent the virtual interface
*/
@@ -275,7 +291,7 @@ public:
uint64_t m_tx_queue_full;
uint64_t m_tx_alloc_error;
tx_per_flow_t m_tx_per_flow[MAX_FLOW_STATS + MAX_FLOW_STATS_PAYLOAD];
- uint32_t m_seq_num[MAX_FLOW_STATS_PAYLOAD]; // seq num to put in packet for payload rules
+ CLatencyPktData m_lat_data[MAX_FLOW_STATS_PAYLOAD];
CPerTxthreadTemplateInfo m_template;
public:
@@ -299,12 +315,14 @@ public:
m_tx_queue_full=0;
m_template.Clear();
for (int i = 0; i < MAX_FLOW_STATS_PAYLOAD; i++) {
- m_seq_num[i] = UINT32_MAX - 1; // catch wrap around issues early
+ m_lat_data[i].reset();
+ }
+ for (int i = 0; i < sizeof(m_tx_per_flow) / sizeof(m_tx_per_flow[0]); i++) {
+ m_tx_per_flow[i].clear();
}
}
inline void Dump(FILE *fd);
-
};
@@ -679,7 +697,13 @@ public:
return (btGetMaskBit32(m_flags1,6,6) ? true:false);
}
+ void setCoreDumpEnable(bool enable) {
+ btSetMaskBit32(m_flags1, 7, 7, (enable ? 1 : 0) );
+ }
+ bool getCoreDumpEnable(){
+ return (btGetMaskBit32(m_flags1, 7, 7) ? true : false);
+ }
public:
void Dump(FILE *fd);
diff --git a/src/common/basic_utils.cpp b/src/common/basic_utils.cpp
index 4f5578a6..b2277697 100755
--- a/src/common/basic_utils.cpp
+++ b/src/common/basic_utils.cpp
@@ -18,6 +18,7 @@ limitations under the License.
#include <stdio.h>
#include <string>
#include <sstream>
+#include <sys/resource.h>
bool utl_is_file_exists (const std::string& name) {
if (FILE *file = fopen(name.c_str(), "r")) {
@@ -198,3 +199,40 @@ utl_generate_random_str(unsigned int &seed, int len) {
return (ss.str());
}
+/**
+ * define the coredump size
+ * allowed when crashing
+ *
+ * @param size - -1 means unlimited
+ * @param map_huge_pages - should the core map the huge TLB
+ * pages
+ */
+void utl_set_coredump_size(long size, bool map_huge_pages) {
+ int mask;
+ struct rlimit core_limits;
+
+ if (size == -1) {
+ core_limits.rlim_cur = core_limits.rlim_max = RLIM_INFINITY;
+ } else {
+ core_limits.rlim_cur = core_limits.rlim_max = size;
+ }
+
+ setrlimit(RLIMIT_CORE, &core_limits);
+
+ /* set core dump mask */
+ FILE *fp = fopen("/proc/self/coredump_filter", "wb");
+ if (!fp) {
+ printf("failed to open /proc/self/coredump_filter\n");
+ exit(-1);
+ }
+
+ /* huge pages is the 5th bit */
+ if (map_huge_pages) {
+ mask = 0x33;
+ } else {
+ mask = 0x13;
+ }
+
+ fprintf(fp, "%08x\n", mask);
+ fclose(fp);
+}
diff --git a/src/common/basic_utils.h b/src/common/basic_utils.h
index 63e858ab..1884e896 100755
--- a/src/common/basic_utils.h
+++ b/src/common/basic_utils.h
@@ -87,6 +87,16 @@ void utl_macaddr_to_str(const uint8_t *macaddr, std::string &output);
std::string utl_generate_random_str(unsigned int &seed, int len);
+/**
+ * define the coredump size
+ * allowed when crashing
+ *
+ * @param size - -1 means unlimited
+ * @param map_huge_pages - should the core map the huge TLB
+ * pages
+ */
+void utl_set_coredump_size(long size, bool map_huge_pages = false);
+
#endif
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index eb65ede3..e98c2305 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -50,6 +50,7 @@
#include <rte_mbuf.h>
#include <rte_random.h>
#include <rte_version.h>
+
#include "bp_sim.h"
#include "os_time.h"
#include "common/arg/SimpleGlob.h"
@@ -553,7 +554,9 @@ enum { OPT_HELP,
OPT_PREFIX,
OPT_MAC_SPLIT,
OPT_SEND_DEBUG_PKT,
- OPT_NO_WATCHDOG
+ OPT_NO_WATCHDOG,
+ OPT_ALLOW_COREDUMP
+
};
@@ -615,7 +618,8 @@ static CSimpleOpt::SOption parser_options[] =
{ OPT_MAC_SPLIT, "--mac-spread", SO_REQ_SEP },
{ OPT_SEND_DEBUG_PKT, "--send-debug-pkt", SO_REQ_SEP },
{ OPT_MBUF_FACTOR , "--mbuf-factor", SO_REQ_SEP },
- { OPT_NO_WATCHDOG , "--no-watchdog", SO_NONE },
+ { OPT_NO_WATCHDOG , "--no-watchdog", SO_NONE },
+ { OPT_ALLOW_COREDUMP , "--allow-coredump", SO_NONE },
SO_END_OF_OPTIONS
@@ -718,6 +722,8 @@ static int usage(){
printf(" \n");
printf(" --no-watchdog : disable watchdog \n");
printf(" \n");
+ printf(" --allow-coredump : allow a creation of core dump \n");
+ printf(" \n");
printf(" --vm-sim : simulate vm with driver of one input queue and one output queue \n");
printf(" \n");
printf(" Examples: ");
@@ -935,6 +941,10 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
po->preview.setWDDisable(true);
break;
+ case OPT_ALLOW_COREDUMP :
+ po->preview.setCoreDumpEnable(true);
+ break;
+
case OPT_LATENCY_PREVIEW :
sscanf(args.OptionArg(),"%d", &po->m_latency_prev);
break;
@@ -2043,17 +2053,17 @@ int CCoreEthIFStateless::send_node_flow_stat(rte_mbuf *m, CGenNodeStateless * no
}
mi = node_sl->alloc_flow_stat_mbuf(m, fsp_head, is_const);
- fsp_head->seq = lp_stats->m_seq_num[hw_id_payload];
+ fsp_head->seq = lp_stats->m_lat_data[hw_id_payload].get_seq_num();
fsp_head->hw_id = hw_id_payload;
- fsp_head->magic = FLOW_STAT_PAYLOAD_MAGIC;
+ fsp_head->magic = lp_stats->m_lat_data[hw_id_payload].get_magic();
- lp_stats->m_seq_num[hw_id_payload]++;
+ lp_stats->m_lat_data[hw_id_payload].inc_seq_num();
#ifdef ERR_CNTRS_TEST
if (temp % 10 == 0) {
- fsp_head->seq = lp_stats->m_seq_num[hw_id_payload]++;
+ fsp_head->seq = lp_stats->m_lat_data[hw_id_payload].inc_seq_num();
}
if ((temp - 1) % 100 == 0) {
- fsp_head->seq = lp_stats->m_seq_num[hw_id_payload] - 4;
+ fsp_head->seq = lp_stats->m_lat_data[hw_id_payload].get_seq_num() - 4;
}
#endif
} else {
@@ -2803,7 +2813,7 @@ public:
bool sanity_check();
void update_stats(void);
tx_per_flow_t get_flow_tx_stats(uint8_t port, uint16_t hw_id);
- tx_per_flow_t clear_flow_tx_stats(uint8_t port, uint16_t index);
+ tx_per_flow_t clear_flow_tx_stats(uint8_t port, uint16_t index, bool is_lat);
void get_stats(CGlobalStats & stats);
void dump_post_test_stats(FILE *fd);
void dump_config(FILE *fd);
@@ -2847,7 +2857,7 @@ private:
std::mutex m_cp_lock;
TrexMonitor m_monitor;
-
+
public:
TrexStateless *m_trex_stateless;
@@ -3524,7 +3534,7 @@ tx_per_flow_t CGlobalTRex::get_flow_tx_stats(uint8_t port, uint16_t index) {
}
// read stats. Return read value, and clear.
-tx_per_flow_t CGlobalTRex::clear_flow_tx_stats(uint8_t port, uint16_t index) {
+tx_per_flow_t CGlobalTRex::clear_flow_tx_stats(uint8_t port, uint16_t index, bool is_lat) {
uint8_t port0;
CFlowGenListPerThread * lpt;
tx_per_flow_t ret;
@@ -3534,12 +3544,11 @@ tx_per_flow_t CGlobalTRex::clear_flow_tx_stats(uint8_t port, uint16_t index) {
for (int i=0; i < get_cores_tx(); i++) {
lpt = m_fl.m_threads_info[i];
port0 = lpt->getDualPortId() * 2;
- if (port == port0) {
- m_stats.m_port[port0].m_tx_per_flow[index] +=
- lpt->m_node_gen.m_v_if->m_stats[0].m_tx_per_flow[index];
- } else if (port == port0 + 1) {
- m_stats.m_port[port0 + 1].m_tx_per_flow[index] +=
- lpt->m_node_gen.m_v_if->m_stats[1].m_tx_per_flow[index];
+ if ((port == port0) || (port == port0 + 1)) {
+ m_stats.m_port[port].m_tx_per_flow[index] +=
+ lpt->m_node_gen.m_v_if->m_stats[port - port0].m_tx_per_flow[index];
+ if (is_lat)
+ lpt->m_node_gen.m_v_if->m_stats[port - port0].m_lat_data[index - MAX_FLOW_STATS].reset();
}
}
@@ -4282,7 +4291,7 @@ int CPhyEthIF::get_flow_stats(rx_per_flow_t *rx_stats, tx_per_flow_t *tx_stats,
}
if (tx_stats != NULL) {
- tx_stats[i - min] = g_trex.clear_flow_tx_stats(m_port_id, i);
+ tx_stats[i - min] = g_trex.clear_flow_tx_stats(m_port_id, i, false);
}
} else {
if (hw_rx_stat_supported) {
@@ -4307,7 +4316,7 @@ int CPhyEthIF::get_flow_stats_payload(rx_per_flow_t *rx_stats, tx_per_flow_t *tx
for (int i = min; i <= max; i++) {
if ( reset ) {
if (tx_stats != NULL) {
- tx_stats[i - min] = g_trex.clear_flow_tx_stats(m_port_id, i + MAX_FLOW_STATS);
+ tx_stats[i - min] = g_trex.clear_flow_tx_stats(m_port_id, i + MAX_FLOW_STATS, true);
}
} else {
if (tx_stats != NULL) {
@@ -4702,6 +4711,15 @@ int main_test(int argc , char * argv[]){
exit(-1);
}
+ /* enable core dump if requested */
+ if (CGlobalInfo::m_options.preview.getCoreDumpEnable()) {
+ utl_set_coredump_size(-1);
+ }
+ else {
+ utl_set_coredump_size(0);
+ }
+
+
update_global_info_from_platform_file();
/* It is not a mistake. Give the user higher priorty over the configuration file */
diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp
index a622ee7a..e5831129 100644
--- a/src/stateless/rx/trex_stateless_rx_core.cpp
+++ b/src/stateless/rx/trex_stateless_rx_core.cpp
@@ -29,13 +29,21 @@
void CRFC2544Info::create() {
m_latency.Create();
- // This is the seq num value we expect next packet to have.
- // Init value should match m_seq_num in CVirtualIFPerSideStats
- m_seq = UINT32_MAX - 1; // catch wrap around issues early
+ m_exp_magic = 0;
+ m_prev_magic = 0;
reset();
}
+// after calling stop, packets still arriving will be considered error
+void CRFC2544Info::stop() {
+ m_prev_magic = m_exp_magic;
+ m_exp_magic = FLOW_STAT_PAYLOAD_MAGIC_NONE;
+}
+
void CRFC2544Info::reset() {
+ // This is the seq num value we expect next packet to have.
+ // Init value should match m_seq_num in CVirtualIFPerSideStats
+ m_seq = UINT32_MAX - 1; // catch wrap around issues early
m_seq_err = 0;
m_seq_err_events_too_big = 0;
m_seq_err_events_too_low = 0;
@@ -97,7 +105,7 @@ bool CRxCoreStateless::periodic_check_for_cp_messages() {
/* tickle the watchdog */
tickle();
-
+
/* fast path */
if ( likely ( m_ring_from_cp->isEmpty() ) ) {
return false;
@@ -187,13 +195,32 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *
if (parser.get_ip_id(ip_id) == 0) {
if (is_flow_stat_id(ip_id)) {
uint16_t hw_id;
+ bool good_packet = true;
if (is_flow_stat_payload_id(ip_id)) {
uint8_t *p = rte_pktmbuf_mtod(m, uint8_t*);
struct flow_stat_payload_header *fsp_head = (struct flow_stat_payload_header *)
(p + m->pkt_len - sizeof(struct flow_stat_payload_header));
- if (fsp_head->magic == FLOW_STAT_PAYLOAD_MAGIC) {
- hw_id = fsp_head->hw_id;
- CRFC2544Info &curr_rfc2544 = m_rfc2544[hw_id];
+ hw_id = fsp_head->hw_id;
+ CRFC2544Info &curr_rfc2544 = m_rfc2544[hw_id];
+ if (unlikely(fsp_head->magic != curr_rfc2544.get_exp_magic())) {
+ // bad magic.
+ // Might be the first packet of a new flow, packet from an old flow or just garbage.
+ if (fsp_head->magic == curr_rfc2544.get_prev_magic()) {
+ // packet from previous flow using this hw_id that arrived late
+ good_packet = false;
+ } else {
+ if (curr_rfc2544.no_magic()) {
+ // first packet we see from this flow
+ good_packet = true;
+ curr_rfc2544.set_exp_magic(fsp_head->magic);
+ } else {
+ // garbage packet
+ good_packet = false;
+ }
+ }
+ }
+
+ if (good_packet) {
uint32_t pkt_seq = fsp_head->seq;
uint32_t exp_seq = curr_rfc2544.get_seq();
if (unlikely(pkt_seq != exp_seq)) {
@@ -388,6 +415,12 @@ int CRxCoreStateless::get_rx_stats(uint8_t port_id, rx_per_flow_t *rx_stats, int
int CRxCoreStateless::get_rfc2544_info(rfc2544_info_t *rfc2544_info, int min, int max, bool reset) {
for (int hw_id = min; hw_id <= max; hw_id++) {
CRFC2544Info &curr_rfc2544 = m_rfc2544[hw_id];
+
+ if (reset) {
+ // need to stop first, so count will be consistent
+ curr_rfc2544.stop();
+ }
+
curr_rfc2544.sample_period_end();
curr_rfc2544.export_data(rfc2544_info[hw_id - min]);
diff --git a/src/stateless/rx/trex_stateless_rx_core.h b/src/stateless/rx/trex_stateless_rx_core.h
index dfc56e4d..140fedf4 100644
--- a/src/stateless/rx/trex_stateless_rx_core.h
+++ b/src/stateless/rx/trex_stateless_rx_core.h
@@ -59,6 +59,7 @@ class CRxSlCfg {
class CRFC2544Info {
public:
void create();
+ void stop();
void reset();
void export_data(rfc2544_info_t_ &obj);
inline void add_sample(double stime) {
@@ -76,7 +77,14 @@ class CRFC2544Info {
inline void inc_seq_err_too_low() {m_seq_err_events_too_low++;}
inline void inc_dup() {m_dup++;}
inline void inc_ooo() {m_ooo++;}
+ inline uint16_t get_exp_magic() {return m_exp_magic;}
+ inline void set_exp_magic(uint16_t magic) {m_exp_magic = magic;}
+ inline uint16_t get_prev_magic() {return m_prev_magic;}
+ inline bool no_magic() {return (m_exp_magic == FLOW_STAT_PAYLOAD_MAGIC_NONE) ? true : false;}
private:
+ enum payload_e {
+ FLOW_STAT_PAYLOAD_MAGIC_NONE = 0
+ };
uint32_t m_seq; // expected next seq num
CTimeHistogram m_latency; // latency info
CJitter m_jitter;
@@ -85,6 +93,9 @@ class CRFC2544Info {
uint64_t m_seq_err_events_too_low; // How many packet seq num lower than expected events we had
uint64_t m_ooo; // Packets we got with seq num lower than expected (We guess they are out of order)
uint64_t m_dup; // Packets we got with same seq num
+ uint16_t m_exp_magic; // magic number we should see in latency header
+ // magic number previously used with this id. We use this to catch packets arriving late from old flow
+ uint16_t m_prev_magic;
};
class CRxCoreStateless {