summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xdoc/trex_stateless.asciidoc2
-rw-r--r--scripts/automation/regression/stateless_tests/stl_rx_test.py389
-rwxr-xr-xsrc/bp_sim.cpp4
-rwxr-xr-xsrc/bp_sim.h10
-rw-r--r--src/debug.cpp2
-rw-r--r--src/flow_stat.cpp84
-rw-r--r--src/flow_stat.h10
-rw-r--r--src/flow_stat_parser.cpp29
-rw-r--r--src/flow_stat_parser.h6
-rw-r--r--src/internal_api/trex_platform_api.h9
-rw-r--r--src/main_dpdk.cpp119
-rw-r--r--src/pkt_gen.cpp4
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp2
-rw-r--r--src/stateless/cp/trex_exception.h1
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp3
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.cpp2
-rw-r--r--src/stateless/dp/trex_stream_node.h8
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.cpp16
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.h10
-rw-r--r--src/trex_defs.h6
20 files changed, 487 insertions, 229 deletions
diff --git a/doc/trex_stateless.asciidoc b/doc/trex_stateless.asciidoc
index 1ca07a02..1a5c62b7 100755
--- a/doc/trex_stateless.asciidoc
+++ b/doc/trex_stateless.asciidoc
@@ -2839,7 +2839,7 @@ trex>
** IPv6 with one VLAN tag (except 82599 which does not support this type of packet).
** Since version 2.21, also QinQ (two vlan tags) is supported if using ``--software'' command line argument. Details link:trex_manual.html#_command_line_options[here].
-* Maximum number of concurrent streams (with different pg_id) on which statistics may be collected: 127
+* Maximum number of concurrent streams (with different pg_id) on which statistics may be collected: 127. Since version 2.23, if using --software command line flag, maximum supported streams is 1023.
* On x710/xl710 cards, all rx bytes counters (rx-bps, rx-bps-L1, ...) are not supported. This is because we use hardware
counters which support only packets count on these cards. +
Starting from version 2.21, you can specify ``--no-hw-flow-stat'' command line argument in order to make x710 behave like other
diff --git a/scripts/automation/regression/stateless_tests/stl_rx_test.py b/scripts/automation/regression/stateless_tests/stl_rx_test.py
index a71322f5..ea379242 100644
--- a/scripts/automation/regression/stateless_tests/stl_rx_test.py
+++ b/scripts/automation/regression/stateless_tests/stl_rx_test.py
@@ -2,6 +2,7 @@
from .stl_general_test import CStlGeneral_Test, CTRexScenario
from trex_stl_lib.api import *
import os, sys
+import copy
ERROR_LATENCY_TOO_HIGH = 1
@@ -10,79 +11,96 @@ class STLRX_Test(CStlGeneral_Test):
def setUp(self):
per_driver_params = {
- 'net_vmxnet3': {
- 'rate_percent': 1,
- 'total_pkts': 50,
- 'rate_latency': 1,
- 'latency_9k_enable': False,
- },
- 'net_ixgbe': {
- 'rate_percent': 30,
- 'total_pkts': 1000,
- 'rate_latency': 1,
- 'latency_9k_enable': True,
- 'latency_9k_max_average': 300,
- 'latency_9k_max_latency': 400,
- },
- 'net_ixgbe_vf': {
- 'rate_percent': 20,
- 'total_pkts': 1000,
- 'rate_latency': 1,
- 'latency_9k_enable': False,
- },
-
- 'net_i40e': {
- 'rate_percent': 80,
- 'total_pkts': 1000,
- 'rate_latency': 1,
- 'latency_9k_enable': True,
- 'latency_9k_max_average': 100,
- 'latency_9k_max_latency': 250,
- },
- 'net_i40e_vf': {
- 'rate_percent': 10,
- 'total_pkts': 1000,
- 'rate_latency': 1,
- 'latency_9k_enable': False,
- },
- 'net_e1000_igb': {
- 'rate_percent': 80,
- 'total_pkts': 500,
- 'rate_latency': 1,
- 'latency_9k_enable': False,
- },
- 'net_e1000_em': {
- 'rate_percent': 1,
- 'total_pkts': 50,
- 'rate_latency': 1,
- 'latency_9k_enable': False,
- },
- 'net_virtio': {
- 'rate_percent': 1,
- 'total_pkts': 50,
- 'rate_latency': 1,
- 'latency_9k_enable': False,
- 'allow_packets_drop_num': 1, # allow 1 pkt drop
- },
-
- 'net_mlx5': {
- 'rate_percent': 80 if self.is_vf_nics else 5,
- 'total_pkts': 1000,
- 'rate_latency': 1,
- 'latency_9k_enable': False if self.is_vf_nics else True,
- 'latency_9k_max_average': 100,
- 'latency_9k_max_latency': 450, #see latency issue trex-261
- },
-
- 'net_enic': {
- 'rate_percent': 1,
- 'total_pkts': 50,
- 'rate_latency': 1,
- 'latency_9k_enable': False,
- },
-
-
- }
+ 'net_vmxnet3': {
+ 'rate_percent': 1,
+ 'total_pkts': 50,
+ 'rate_latency': 1,
+ 'latency_9k_enable': False,
+ 'no_vlan_even_in_software_mode': True,
+ },
+ 'net_ixgbe': {
+ 'rate_percent': 30,
+ 'total_pkts': 1000,
+ 'rate_latency': 1,
+ 'latency_9k_enable': True,
+ 'latency_9k_max_average': 300,
+ 'latency_9k_max_latency': 400,
+ 'no_vlan': True,
+ 'no_ipv6': True,
+ },
+ 'net_ixgbe_vf': {
+ 'rate_percent': 30,
+ 'total_pkts': 1000,
+ 'rate_latency': 1,
+ 'latency_9k_enable': False,
+ 'no_vlan': True,
+ 'no_ipv6': True,
+ 'no_vlan_even_in_software_mode': True,
+ 'max_pkt_size': 2000, # temporary, until we fix this
+ },
+
+ 'net_i40e': {
+ 'rate_percent': 80,
+ 'rate_percent_soft': 10,
+ 'total_pkts': 1000,
+ 'rate_latency': 1,
+ 'latency_9k_enable': True,
+ 'latency_9k_max_average': 100,
+ 'latency_9k_max_latency': 250,
+ },
+ 'net_i40e_vf': {
+ 'rate_percent': 80,
+ 'rate_percent_soft': 1,
+ 'total_pkts': 1000,
+ 'rate_latency': 1,
+ 'latency_9k_enable': False,
+ 'no_vlan_even_in_software_mode': True,
+ 'max_pkt_size': 2000, # temporary, until we fix this
+ 'allow_packets_drop_num': 5, # todo: fix
+ },
+ 'net_e1000_igb': {
+ 'rate_percent': 80,
+ 'total_pkts': 500,
+ 'rate_latency': 1,
+ 'latency_9k_enable': False,
+
+ },
+ 'net_e1000_em': {
+ 'rate_percent': 1,
+ 'total_pkts': 50,
+ 'rate_latency': 1,
+ 'latency_9k_enable': False,
+ 'no_vlan_even_in_software_mode': True,
+ },
+ 'net_virtio': {
+ 'rate_percent': 1,
+ 'total_pkts': 50,
+ 'rate_latency': 1,
+ 'latency_9k_enable': False,
+ 'allow_packets_drop_num': 1, # allow 1 pkt drop
+ },
+
+ 'net_mlx5': {
+ 'rate_percent': 80,
+ 'total_pkts': 1000,
+ 'rate_latency': 1,
+ 'latency_9k_enable': False if self.is_vf_nics else True,
+ 'latency_9k_max_average': 100,
+ 'latency_9k_max_latency': 450, #see latency issue trex-261
+ 'no_vlan_even_in_software_mode': True, # todo: fix - We see 1 or 2 packet drops from time to time with vlan
+ 'no_ipv6': True, #todo: fix - same issue with ipv6
+ 'allow_packets_drop_num': 15, # todo - remove
+ },
+
+ 'net_enic': {
+ 'rate_percent': 1,
+ 'total_pkts': 50,
+ 'rate_latency': 1,
+ 'latency_9k_enable': False,
+ 'rx_bytes_fix': True,
+ 'no_vlan_even_in_software_mode': True,
+ },
+ }
CStlGeneral_Test.setUp(self)
assert 'bi' in CTRexScenario.stl_ports_map
@@ -99,23 +117,62 @@ class STLRX_Test(CStlGeneral_Test):
self.skip('port {0} does not support RX'.format(self.rx_port))
self.cap = cap
+ self.max_flow_stats = port_info['rx']['counters']
+ if self.max_flow_stats == 1023:
+ # hack - to identify if --software flag was used on server
+ software_mode = True
+ else:
+ software_mode = False
+
+ software_mode = False # fix: need good way to identify software_mode
+
drv_name = port_info['driver']
self.drv_name = drv_name
- if drv_name == 'net_ixgbe':
+ if 'no_vlan' in per_driver_params[drv_name] and not software_mode:
+ self.vlan_support = False
+ else:
+ self.vlan_support = True
+
+ if 'no_ipv6' in per_driver_params[drv_name] and not software_mode:
self.ipv6_support = False
else:
self.ipv6_support = True
+
+ if 'max_pkt_size' in per_driver_params[drv_name]:
+ self.max_pkt_size = per_driver_params[drv_name]['max_pkt_size']
+ else:
+ self.max_pkt_size = 9000
+
self.rate_percent = per_driver_params[drv_name]['rate_percent']
self.total_pkts = per_driver_params[drv_name]['total_pkts']
self.rate_lat = per_driver_params[drv_name].get('rate_latency', self.rate_percent)
+ self.rate_fstat = per_driver_params[drv_name].get('rate_percent_soft', self.rate_percent)
self.latency_9k_enable = per_driver_params[drv_name]['latency_9k_enable']
self.latency_9k_max_average = per_driver_params[drv_name].get('latency_9k_max_average')
self.latency_9k_max_latency = per_driver_params[drv_name].get('latency_9k_max_latency')
self.allow_drop = per_driver_params[drv_name].get('allow_packets_drop_num', 0)
-
self.lat_pps = 1000
self.drops_expected = False
self.c.reset(ports = [self.tx_port, self.rx_port])
+ if 'rx_bytes_fix' in per_driver_params[drv_name] and per_driver_params[drv_name]['rx_bytes_fix'] == True:
+ self.fix_rx_byte_count = True
+ else:
+ self.fix_rx_byte_count = False
+
+ if software_mode:
+ self.qinq_support = True
+ else:
+ self.qinq_support = False
+
+ # hack for enic
+ if 'no_vlan_even_in_software_mode' in per_driver_params[drv_name]:
+ self.vlan_support = False
+ self.qinq_support = False
+
+ #trex25 has router which does not pass vlan
+ if CTRexScenario.setup_name == 'trex25':
+ self.vlan_support = False
+ self.qinq_support = False
vm = STLScVmRaw( [ STLVmFlowVar ( "ip_src", min_value="10.0.0.1",
max_value="10.0.0.255", size=4, step=1,op="inc"),
@@ -128,6 +185,8 @@ class STLRX_Test(CStlGeneral_Test):
);
self.pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('Your_paylaod_comes_here'))
+ self.vlan_pkt = STLPktBuilder(pkt = Ether()/Dot1Q()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('Your_paylaod_comes_here'))
+ self.qinq_pkt = STLPktBuilder(pkt = Ether(type=0x88A8)/Dot1Q(vlan=19)/Dot1Q(vlan=11)/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('Your_paylaod_comes_here'))
self.ipv6pkt = STLPktBuilder(pkt = Ether()/IPv6(dst="2001:0:4137:9350:8000:f12a:b9c8:2815",src="2001:4860:0:2001::68")
/UDP(dport=12,sport=1025)/('Your_paylaod_comes_here'))
self.large_pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('a'*1000))
@@ -180,8 +239,13 @@ class STLRX_Test(CStlGeneral_Test):
return 0
+ def __exit_with_error(self, stats, err, pkt_len=0, pkt_type=""):
+ if pkt_len != 0:
+ print("Failed with packet: type {0}, len {1}".format(pkt_type, pkt_len))
+ pprint.pprint(stats)
+ assert False, err
- def __verify_flow (self, pg_id, total_pkts, pkt_len, stats):
+ def __verify_flow (self, pg_id, total_pkts, pkt_len, pkt_type, stats):
flow_stats = stats['flow_stats'].get(pg_id)
latency_stats = stats['latency'].get(pg_id)
@@ -189,6 +253,9 @@ class STLRX_Test(CStlGeneral_Test):
assert False, "no flow stats available"
tx_pkts = flow_stats['tx_pkts'].get(self.tx_port, 0)
+ # for continues tests, we do not know how many packets were sent
+ if total_pkts == 0:
+ total_pkts = tx_pkts
tx_bytes = flow_stats['tx_bytes'].get(self.tx_port, 0)
rx_pkts = flow_stats['rx_pkts'].get(self.rx_port, 0)
if latency_stats is not None:
@@ -199,49 +266,62 @@ class STLRX_Test(CStlGeneral_Test):
stl = latency_stats['err_cntrs']['seq_too_low']
lat = latency_stats['latency']
if ooo != 0 or dup != 0 or stl != 0:
- pprint.pprint(latency_stats)
- tmp='Error packets - dropped:{0}, ooo:{1} dup:{2} seq too high:{3} seq too low:{4}'.format(drops, ooo, dup, sth, stl)
- assert False, tmp
+ self.__exit_with_error(latency_stats,
+ 'Error packets - dropped:{0}, ooo:{1} dup:{2} seq too high:{3} seq too low:{4}'.format(drops, ooo, dup, sth, stl)
+ , pkt_len, pkt_type)
- if (drops > self.allow_drop or sth != 0) and not self.drops_expected:
- pprint.pprint(latency_stats)
- tmp='Error packets - dropped:{0}, ooo:{1} dup:{2} seq too high:{3} seq too low:{4}'.format(drops, ooo, dup, sth, stl)
- assert False, tmp
+ if (drops > self.allow_drop or sth > self.allow_drop) and not self.drops_expected:
+ self.__exit_with_error(latency_stats,
+ 'Error packets - dropped:{0}, ooo:{1} dup:{2} seq too high:{3} seq too low:{4}'.format(drops, ooo, dup, sth, stl)
+ , pkt_len, pkt_type)
if tx_pkts != total_pkts:
pprint.pprint(flow_stats)
- tmp = 'TX pkts mismatch - got: {0}, expected: {1}'.format(tx_pkts, total_pkts)
- assert False, tmp
+ self.__exit_with_error(flow_stats
+ , 'TX pkts mismatch - got: {0}, expected: {1}'.format(tx_pkts, total_pkts)
+ , pkt_len, pkt_type)
if tx_bytes != (total_pkts * pkt_len):
- pprint.pprint(flow_stats)
- tmp = 'TX bytes mismatch - got: {0}, expected: {1}'.format(tx_bytes, (total_pkts * pkt_len))
- assert False, tmp
+ self.__exit_with_error(flow_stats
+ , 'TX bytes mismatch - got: {0}, expected: {1}'.format(tx_bytes, (total_pkts * pkt_len))
+ , pkt_len, pkt_type)
if abs(total_pkts - rx_pkts) > self.allow_drop and not self.drops_expected:
- pprint.pprint(flow_stats)
- tmp = 'RX pkts mismatch - got: {0}, expected: {1}'.format(rx_pkts, total_pkts)
- assert False, tmp
+ self.__exit_with_error(flow_stats
+ , 'RX pkts mismatch - got: {0}, expected: {1}'.format(rx_pkts, total_pkts)
+ , pkt_len, pkt_type)
+
+ rx_pkt_len = pkt_len
+ if self.fix_rx_byte_count:
+ # Patch. Vic card always add vlan, so we should expect 4 extra bytes in each packet
+ rx_pkt_len += 4
if "rx_bytes" in self.cap:
rx_bytes = flow_stats['rx_bytes'].get(self.rx_port, 0)
- if abs(rx_bytes / pkt_len - total_pkts ) > self.allow_drop and not self.drops_expected:
- pprint.pprint(flow_stats)
- tmp = 'RX bytes mismatch - got: {0}, expected: {1}'.format(rx_bytes, (total_pkts * pkt_len))
- assert False, tmp
-
+ if abs(rx_bytes / rx_pkt_len - total_pkts ) > self.allow_drop and not self.drops_expected:
+ self.__exit_with_error(flow_stats
+ , 'RX bytes mismatch - got: {0}, expected: {1}'.format(rx_bytes, (total_pkts * rx_pkt_len))
+ , pkt_len, pkt_type)
# RX itreation
- def __rx_iteration (self, exp_list):
+ def __rx_iteration (self, exp_list, duration=0):
self.c.clear_stats()
- self.c.start(ports = [self.tx_port])
- self.c.wait_on_traffic(ports = [self.tx_port])
+ if duration != 0:
+ self.c.start(ports = [self.tx_port], duration=duration)
+ self.c.wait_on_traffic(ports = [self.tx_port],timeout = duration+10,rx_delay_ms = 100)
+ else:
+ self.c.start(ports = [self.tx_port])
+ self.c.wait_on_traffic(ports = [self.tx_port])
stats = self.c.get_stats()
for exp in exp_list:
- self.__verify_flow(exp['pg_id'], exp['total_pkts'], exp['pkt_len'], stats)
+ if 'pkt_type' in exp:
+ pkt_type = exp['pkt_type']
+ else:
+ pkt_type = "not specified"
+ self.__verify_flow(exp['pg_id'], exp['total_pkts'], exp['pkt_len'], pkt_type, stats)
# one stream on TX --> RX
@@ -271,42 +351,97 @@ class STLRX_Test(CStlGeneral_Test):
def test_multiple_streams(self):
+ self._test_multiple_streams(False)
+
+ def test_multiple_streams_random(self):
+ if self.drv_name == 'net_mlx5' or self.drv_name == 'net_i40e_vf':
+ self.skip('Not running on Mellanox cards currently')
+ self._test_multiple_streams(True)
+
+ def _test_multiple_streams(self, is_random):
if self.is_virt_nics:
self.skip('Skip this for virtual NICs')
- num_latency_streams = 128
- num_flow_stat_streams = 127
+ if is_random:
+ num_latency_streams = random.randint(1, 128);
+ num_flow_stat_streams = random.randint(1, self.max_flow_stats);
+ all_pkts = [self.pkt]
+ if self.ipv6_support:
+ all_pkts.append(self.ipv6pkt)
+ if self.vlan_support:
+ all_pkts.append(self.vlan_pkt)
+ if self.qinq_support:
+ all_pkts.append(self.qinq_pkt)
+ else:
+ num_latency_streams = 128
+ num_flow_stat_streams = self.max_flow_stats
total_pkts = int(self.total_pkts / (num_latency_streams + num_flow_stat_streams))
if total_pkts == 0:
total_pkts = 1
- percent = float(self.rate_lat) / (num_latency_streams + num_flow_stat_streams)
+ percent_lat = float(self.rate_lat) / num_latency_streams
+ percent_fstat = float(self.rate_fstat) / num_flow_stat_streams
+
+ print("num_latency_streams:{0}".format(num_latency_streams))
+ if is_random:
+ print(" total percent:{0} ({1} per stream)".format(percent_lat * num_latency_streams, percent_lat))
+
+ print("num_flow_stat_streams:{0}".format(num_flow_stat_streams))
+ if is_random:
+ print(" total percent:{0} ({1} per stream)".format(percent_fstat * num_flow_stat_streams, percent_fstat))
try:
streams = []
exp = []
- # 10 identical streams
for pg_id in range(1, num_latency_streams):
+ if is_random:
+ pkt = copy.deepcopy(all_pkts[random.randint(0, len(all_pkts) - 1)])
+ pkt.set_packet(pkt.pkt / ('a' * random.randint(0, self.max_pkt_size - len(pkt.pkt))))
+ send_mode = STLTXCont(percentage = percent_lat)
+ else:
+ pkt = self.pkt
+ send_mode = STLTXSingleBurst(total_pkts = total_pkts+pg_id, percentage = percent_lat)
+
streams.append(STLStream(name = 'rx {0}'.format(pg_id),
- packet = self.pkt,
+ packet = pkt,
flow_stats = STLFlowLatencyStats(pg_id = pg_id),
- mode = STLTXSingleBurst(total_pkts = total_pkts+pg_id, percentage = percent)))
+ mode = send_mode))
- exp.append({'pg_id': pg_id, 'total_pkts': total_pkts+pg_id, 'pkt_len': streams[-1].get_pkt_len()})
+ if is_random:
+ exp.append({'pg_id': pg_id, 'total_pkts': 0, 'pkt_len': streams[-1].get_pkt_len()
+ , 'pkt_type': pkt.pkt.sprintf("%Ether.type%")})
+ else:
+ exp.append({'pg_id': pg_id, 'total_pkts': total_pkts+pg_id, 'pkt_len': streams[-1].get_pkt_len()})
for pg_id in range(num_latency_streams + 1, num_latency_streams + num_flow_stat_streams):
+ if is_random:
+ pkt = copy.deepcopy(all_pkts[random.randint(0, len(all_pkts) - 1)])
+ pkt.set_packet(pkt.pkt / ('a' * random.randint(0, self.max_pkt_size - len(pkt.pkt))))
+ send_mode = STLTXCont(percentage = percent_fstat)
+ else:
+ pkt = self.pkt
+ send_mode = STLTXSingleBurst(total_pkts = total_pkts+pg_id, percentage = percent_fstat)
+
streams.append(STLStream(name = 'rx {0}'.format(pg_id),
- packet = self.pkt,
+ packet = pkt,
flow_stats = STLFlowStats(pg_id = pg_id),
- mode = STLTXSingleBurst(total_pkts = total_pkts+pg_id, percentage = percent)))
-
- exp.append({'pg_id': pg_id, 'total_pkts': total_pkts+pg_id, 'pkt_len': streams[-1].get_pkt_len()})
+ mode = send_mode))
+ if is_random:
+ exp.append({'pg_id': pg_id, 'total_pkts': 0, 'pkt_len': streams[-1].get_pkt_len()
+ , 'pkt_type': pkt.pkt.sprintf("%Ether.type%")})
+ else:
+ exp.append({'pg_id': pg_id, 'total_pkts': total_pkts+pg_id, 'pkt_len': streams[-1].get_pkt_len()})
# add both streams to ports
self.c.add_streams(streams, ports = [self.tx_port])
- self.__rx_iteration(exp)
+ if is_random:
+ duration = 60
+ print("Duration: {0}".format(duration))
+ else:
+ duration = 0
+ self.__rx_iteration(exp, duration = duration)
except STLError as e:
@@ -321,7 +456,15 @@ class STLRX_Test(CStlGeneral_Test):
{'name': 'Latency, no field engine', 'pkt': self.pkt, 'lat': True},
{'name': 'Latency, short packet with field engine', 'pkt': self.vm_pkt, 'lat': True},
{'name': 'Latency, large packet field engine', 'pkt': self.vm_large_pkt, 'lat': True}
+
+ # add here more stream types
]
+ if self.vlan_support:
+ streams_data.append({'name': 'Flow stat with vlan. No latency', 'pkt': self.vlan_pkt, 'lat': False})
+
+ if self.qinq_support:
+ streams_data.append({'name': 'Flow stat qinq. No latency', 'pkt': self.qinq_pkt, 'lat': False})
+
if self.latency_9k_enable:
streams_data.append({'name': 'Latency, 9k packet with field engine', 'pkt': self.vm_9k_pkt, 'lat': True})
@@ -410,10 +553,7 @@ class STLRX_Test(CStlGeneral_Test):
assert False , '{0}'.format(e)
-
-
-
- # check low latency when you have stream of 9K stream
+ # Verify that there is low latency with random packet size,duration and ports
def test_9k_stream(self):
if self.is_virt_nics:
self.skip('Skip this for virtual NICs')
@@ -428,8 +568,6 @@ class STLRX_Test(CStlGeneral_Test):
pgid=random.randint(1, 65000);
pkt_size=random.randint(1000, 9000);
all_ports = list(CTRexScenario.stl_ports_map['map'].keys());
-
-
s_port=random.sample(all_ports, random.randint(1, len(all_ports)) )
s_port=sorted(s_port)
@@ -515,7 +653,7 @@ class STLRX_Test(CStlGeneral_Test):
self.check_stats(ops["obytes"], bytes, "stats[%s][obytes]" % c_port)
self.check_stats(ops["opackets"], pkts, "stats[%s][opackets]" % c_port)
-
+
self.check_stats(ips["ibytes"], bytes, "stats[%s][ibytes]" % s_port)
self.check_stats(ips["ipackets"], pkts, "stats[%s][ipackets]" % s_port)
@@ -523,10 +661,10 @@ class STLRX_Test(CStlGeneral_Test):
ls = stats['flow_stats'][5 + c_port]
self.check_stats(ls['rx_pkts']['total'], pkts, "ls['rx_pkts']['total']")
self.check_stats(ls['rx_pkts'][s_port], pkts, "ls['rx_pkts'][%s]" % s_port)
-
+
self.check_stats(ls['tx_pkts']['total'], pkts, "ls['tx_pkts']['total']")
self.check_stats(ls['tx_pkts'][c_port], pkts, "ls['tx_pkts'][%s]" % c_port)
-
+
self.check_stats(ls['tx_bytes']['total'], bytes, "ls['tx_bytes']['total']")
self.check_stats(ls['tx_bytes'][c_port], bytes, "ls['tx_bytes'][%s]" % c_port)
@@ -556,9 +694,11 @@ class STLRX_Test(CStlGeneral_Test):
# this test sends 1 64 byte packet with latency and check that all counters are reported as 64 bytes
def test_fcs_stream(self):
-
- # in case of VM and vSwitch there are drop of packets in some cases, let retry number of times
- # in this case we just want to check functionality that packet of 64 is reported as 64 in all levels
+ if CTRexScenario.setup_name == 'trex19':
+ # todo: - fix
+ self.skip('Test does not run on trex19')
+ # In case of VM and vSwitch there is packet drop in some cases, so we retry few of times
+ # In this case we just want to check that packet of 64 bytes is reported correctly as 64 everywhere.
is_vm = self.is_virt_nics or self.is_vf_nics
tries = 1
@@ -639,4 +779,3 @@ class STLRX_Test(CStlGeneral_Test):
exp = {'pg_id': 5, 'total_pkts': total_pkts, 'pkt_len': s1.get_pkt_len()}
self.__rx_iteration( [exp] )
-
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index 43cfed93..9dfb7c3d 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -1687,7 +1687,7 @@ void CFlowPktInfo::do_generate_new_mbuf_rxcheck(rte_mbuf_t * m,
uint8_t save_header= ipv6->getNextHdr();
ipv6->setNextHdr(RX_CHECK_V6_OPT_TYPE);
ipv6->setHopLimit(TTL_RESERVE_DUPLICATE);
- ipv6->setTrafficClass(ipv6->getTrafficClass()|TOS_TTL_RESERVE_DUPLICATE);
+ ipv6->setTrafficClass(ipv6->getTrafficClass() | TOS_GO_TO_CPU);
ipv6->setPayloadLen( ipv6->getPayloadLen() +
sizeof(CRx_check_header));
rxhdr->m_option_type = save_header;
@@ -1697,7 +1697,7 @@ void CFlowPktInfo::do_generate_new_mbuf_rxcheck(rte_mbuf_t * m,
ipv4->setHeaderLength(current_opt_len+opt_len);
ipv4->setTotalLength(ipv4->getTotalLength()+opt_len);
ipv4->setTimeToLive(TTL_RESERVE_DUPLICATE);
- ipv4->setTOS(ipv4->getTOS()|TOS_TTL_RESERVE_DUPLICATE);
+ ipv4->setTOS(ipv4->getTOS() | TOS_GO_TO_CPU);
rxhdr->m_option_type = RX_CHECK_V4_OPT_TYPE;
rxhdr->m_option_len = RX_CHECK_V4_OPT_LEN;
diff --git a/src/bp_sim.h b/src/bp_sim.h
index fd4e6627..c524723a 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -78,7 +78,7 @@ class CGenNodePCAP;
/* reserve both 0xFF and 0xFE , router will -1 FF */
#define TTL_RESERVE_DUPLICATE 0xff
-#define TOS_TTL_RESERVE_DUPLICATE 0x1
+#define TOS_GO_TO_CPU 0x1
/*
* Length of string needed to hold the largest port (16-bit) address
*/
@@ -2832,18 +2832,18 @@ public:
void setTOSReserve(){
BP_ASSERT(l3.m_ipv4);
if (is_ipv6()) {
- l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass() | TOS_TTL_RESERVE_DUPLICATE );
+ l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass() | TOS_GO_TO_CPU );
}else{
- l3.m_ipv4->setTOS(l3.m_ipv4->getTOS()| TOS_TTL_RESERVE_DUPLICATE );
+ l3.m_ipv4->setTOS(l3.m_ipv4->getTOS()| TOS_GO_TO_CPU );
}
}
void clearTOSReserve(){
BP_ASSERT(l3.m_ipv4);
if (is_ipv6()) {
- l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass()& (~TOS_TTL_RESERVE_DUPLICATE) );
+ l3.m_ipv6->setTrafficClass(l3.m_ipv6->getTrafficClass()& (~TOS_GO_TO_CPU) );
}else{
- l3.m_ipv4->setTOS(l3.m_ipv4->getTOS() & (~TOS_TTL_RESERVE_DUPLICATE) );
+ l3.m_ipv4->setTOS(l3.m_ipv4->getTOS() & (~TOS_GO_TO_CPU) );
}
}
diff --git a/src/debug.cpp b/src/debug.cpp
index ccef8499..d20721bf 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -399,7 +399,7 @@ int CTrexDebug::verify_hw_rules(bool recv_all) {
memset(pkt_per_q, 0, sizeof(pkt_per_q));
// We don't know which interfaces connected where, so sum all queue 1 and all queue 0
for (int port = 0; port < m_max_ports; port++) {
- for(int queue_id = 0; queue_id <= m_rx_q_num; queue_id++) {
+ for(int queue_id = 0; queue_id < m_rx_q_num; queue_id++) {
lp = &m_ports[port];
uint16_t cnt = lp->rx_burst(queue_id, rx_pkts, 32);
pkt_per_q[queue_id] += cnt;
diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp
index 58d08c44..8d33bf3c 100644
--- a/src/flow_stat.cpp
+++ b/src/flow_stat.cpp
@@ -63,7 +63,7 @@ stream_del: HW_ID_INIT
static const uint16_t HW_ID_INIT = UINT16_MAX;
static const uint16_t HW_ID_FREE = UINT16_MAX - 1;
static const uint8_t PAYLOAD_RULE_PROTO = 255;
-const uint32_t FLOW_STAT_PAYLOAD_IP_ID = IP_ID_RESERVE_BASE + MAX_FLOW_STATS;
+const uint32_t FLOW_STAT_PAYLOAD_IP_ID = UINT16_MAX;
inline std::string methodName(const std::string& prettyFunction)
{
@@ -457,8 +457,6 @@ CFlowStatRuleMgr::CFlowStatRuleMgr() {
m_parser_ipid = NULL;
m_parser_pl = NULL;
m_rx_core = NULL;
- m_hw_id_map.create(MAX_FLOW_STATS);
- m_hw_id_map_payload.create(MAX_FLOW_STATS_PAYLOAD);
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));
m_num_ports = 0; // need to call create to init
@@ -481,21 +479,24 @@ CFlowStatRuleMgr::~CFlowStatRuleMgr() {
}
void CFlowStatRuleMgr::create() {
- uint16_t num_counters, cap;
+ uint16_t num_counters, cap, ip_id_base;
TrexStateless *tstateless = get_stateless_obj();
assert(tstateless);
m_api = tstateless->get_platform_api();
assert(m_api);
- m_api->get_interface_stat_info(0, num_counters, cap);
+ m_api->get_interface_stat_info(0, num_counters, cap, ip_id_base);
m_api->get_port_num(m_num_ports); // This initialize m_num_ports
for (uint8_t port = 0; port < m_num_ports; port++) {
assert(m_api->reset_hw_flow_stats(port) == 0);
}
+ m_hw_id_map.create(num_counters);
+ m_hw_id_map_payload.create(MAX_FLOW_STATS_PAYLOAD);
m_ring_to_rx = CMsgIns::Ins()->getCpRx()->getRingCpToDp(0);
assert(m_ring_to_rx);
m_rx_core = get_rx_sl_core_obj();
m_cap = cap;
+ m_ip_id_reserve_base = ip_id_base;
if ((CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE)
|| (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS)) {
@@ -662,6 +663,11 @@ int CFlowStatRuleMgr::del_stream(TrexStream * stream) {
return 0;
}
m_user_id_map.del_stream(stream->m_rx_check.m_pg_id); // Throws exception in case of error
+ if (m_user_id_map.is_empty()) {
+ m_max_hw_id = 0;
+ m_max_hw_id_payload = 0;
+ }
+
stream->m_rx_check.m_hw_id = HW_ID_INIT;
return 0;
@@ -695,16 +701,13 @@ int CFlowStatRuleMgr::start_stream(TrexStream * stream) {
return 0;
}
- uint32_t ip_id;
+ uint32_t ip_id; // 32 bit, since this also supports IPv6
if (m_parser_ipid->get_ip_id(ip_id) < 0) {
return 0; // if we could not find the ip id, no need to fix
}
// verify no reserved IP_ID used, and change if needed
- if (ip_id >= IP_ID_RESERVE_BASE) {
- if (m_parser_ipid->set_ip_id(ip_id & 0xefff) < 0) {
- throw TrexFStatEx("Stream IP ID in reserved range. Failed changing it"
- , TrexException::T_FLOW_STAT_FAILED_CHANGE_IP_ID);
- }
+ if (ip_id >= m_ip_id_reserve_base) {
+ m_parser_ipid->set_ip_id(ip_id & 0x0000efff);
}
return 0;
}
@@ -789,10 +792,12 @@ int CFlowStatRuleMgr::start_stream(TrexStream * stream) {
// saving given hw_id on stream for use by tx statistics count
if (rule_type == TrexPlatformApi::IF_STAT_IPV4_ID) {
- m_parser_ipid->set_ip_id(IP_ID_RESERVE_BASE + hw_id);
+ m_parser_ipid->set_ip_id(m_ip_id_reserve_base + hw_id);
+ m_parser_ipid->set_tos_to_cpu();
stream->m_rx_check.m_hw_id = hw_id;
} else {
m_parser_pl->set_ip_id(FLOW_STAT_PAYLOAD_IP_ID);
+ m_parser_pl->set_tos_to_cpu();
// for payload rules, we use the range right after ip id rules
stream->m_rx_check.m_hw_id = hw_id + MAX_FLOW_STATS;
}
@@ -1001,7 +1006,9 @@ void CFlowStatRuleMgr::send_start_stop_msg_to_rx(bool is_start) {
// s_json - flow statistics json
// l_json - latency data json
// baseline - If true, send flow statistics fields even if they were not changed since last run
-bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, bool baseline) {
+// send_all - If true, send data for all pg_ids. This is used for getting statistics in automation API.
+// If false, send small amount of pg ids. Used for async interface, for displaying in console
+bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, bool baseline, bool send_all) {
rx_per_flow_t rx_stats[MAX_FLOW_STATS];
rx_per_flow_t rx_stats_payload[MAX_FLOW_STATS];
tx_per_flow_t tx_stats[MAX_FLOW_STATS];
@@ -1036,13 +1043,39 @@ 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);
+
+#if 0
+ // If we want to send all PG_IDs, in groups of 128, enable this, and remove the restrication
+ // of sending only 8 in loop of building json message below
+ static int min_to_send = 0;
+ static int max_to_send = m_max_hw_id;
+
+ min_to_send += 128;
+ if (min_to_send > m_max_hw_id) {
+ min_to_send = 0;
+ }
+ max_to_send = min_to_send + 128;
+ if (max_to_send > m_max_hw_id) {
+ max_to_send = m_max_hw_id;
+ }
+
+ // If asking for "baseline", send everything always.
+ if (baseline || send_all) {
+ min_to_send = 0;
+ max_to_send = m_max_hw_id;
+ }
+#endif
+
+ int min_to_send = 0;
+ int max_to_send = m_max_hw_id;
+
// read hw counters, and update
for (uint8_t port = 0; port < m_num_ports; port++) {
- m_api->get_flow_stats(port, rx_stats, (void *)tx_stats, 0, m_max_hw_id, false, TrexPlatformApi::IF_STAT_IPV4_ID);
- for (int i = 0; i <= m_max_hw_id; i++) {
+ m_api->get_flow_stats(port, rx_stats, (void *)tx_stats, min_to_send, max_to_send, false, TrexPlatformApi::IF_STAT_IPV4_ID);
+ for (int i = 0; i <= max_to_send - min_to_send; i++) {
if (rx_stats[i].get_pkts() != 0) {
rx_per_flow_t rx_pkts = rx_stats[i];
- CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i));
+ CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i + min_to_send));
if (likely(p_user_id != NULL)) {
if (p_user_id->get_rx_cntr(port) != rx_pkts) {
p_user_id->set_rx_cntr(port, rx_pkts);
@@ -1056,7 +1089,7 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo
}
if (tx_stats[i].get_pkts() != 0) {
tx_per_flow_t tx_pkts = tx_stats[i];
- CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i));
+ CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i + min_to_send));
if (likely(p_user_id != NULL)) {
if (p_user_id->get_tx_cntr(port) != tx_pkts) {
p_user_id->set_tx_cntr(port, tx_pkts);
@@ -1125,8 +1158,25 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo
l_data_section["global"]["old_flow"] = Json::Value::UInt64(tmp_cnt);
}
+ // TUI only present 4 PG_IDs today, so we send everything only when explicit request comes
+ // (probably from automation API)
+ uint16_t max_pg_ids_to_send = 8;
+ static int times_send_all = 0;
+ if (send_all) {
+ times_send_all = 20;
+ }
+ if (baseline || (times_send_all > 0)) {
+ if (times_send_all > 0)
+ times_send_all--;
+ max_pg_ids_to_send = UINT16_MAX;
+ }
+
flow_stat_user_id_map_it_t it;
for (it = m_user_id_map.begin(); it != m_user_id_map.end(); it++) {
+ if (max_pg_ids_to_send == 0) {
+ break;
+ }
+ max_pg_ids_to_send--;
bool send_empty = true;
CFlowStatUserIdInfo *user_id_info = it->second;
uint32_t user_id = it->first;
diff --git a/src/flow_stat.h b/src/flow_stat.h
index 25bf421c..b155b917 100644
--- a/src/flow_stat.h
+++ b/src/flow_stat.h
@@ -32,9 +32,10 @@
#include "internal_api/trex_platform_api.h"
// range reserved for rx stat measurement is from IP_ID_RESERVE_BASE to 0xffff
-// Do not change this value. In i350 cards, we filter according to first byte of IP ID
-// In other places, we identify packets by if (ip_id > IP_ID_RESERVE_BASE)
-#define IP_ID_RESERVE_BASE 0xff00
+// This value is used by all NICs, except i350, where value of 0xff00 is used.
+// We identify if packet needs handling as flow stat, by: "if (ip_id > IP_ID_RESERVE_BASE)"
+#define IP_ID_RESERVE_BASE (0xffff - MAX_FLOW_STATS)
+
#define FLOW_STAT_PAYLOAD_MAGIC 0xAB
#define FLOW_STAT_PAYLOAD_INITIAL_FLOW_SEQ 0x01
extern const uint32_t FLOW_STAT_PAYLOAD_IP_ID;
@@ -469,7 +470,7 @@ class CFlowStatRuleMgr {
int stop_stream(TrexStream * stream);
int get_active_pgids(flow_stat_active_t &result);
int set_mode(enum flow_stat_mode_e mode);
- bool dump_json(std::string & s_json, std::string & l_json, bool baseline);
+ bool dump_json(std::string & s_json, std::string & l_json, bool baseline, bool send_all);
private:
void create();
@@ -493,6 +494,7 @@ class CFlowStatRuleMgr {
CFlowStatParser *m_parser_pl; // for payload rules (latency)
enum flow_stat_mode_e m_mode;
uint16_t m_cap; // capabilities of the NIC driver we are using
+ uint16_t m_ip_id_reserve_base; // lowest IP ID we use for our needs
uint32_t m_rx_cant_count_err[TREX_MAX_PORTS];
uint32_t m_tx_cant_count_err[TREX_MAX_PORTS];
};
diff --git a/src/flow_stat_parser.cpp b/src/flow_stat_parser.cpp
index f9ac8c9b..ef9a120b 100644
--- a/src/flow_stat_parser.cpp
+++ b/src/flow_stat_parser.cpp
@@ -150,6 +150,7 @@ CFlowStatParser_err_t CFlowStatParser::parse(uint8_t *p, uint16_t len) {
return FSTAT_PARSER_E_OK;
}
+// arg is uint32_t in below two functions because we want same function to work for IPv4 and IPv6
int CFlowStatParser::get_ip_id(uint32_t &ip_id) {
if (m_ipv4) {
ip_id = m_ipv4->getId();
@@ -164,24 +165,34 @@ int CFlowStatParser::get_ip_id(uint32_t &ip_id) {
return -1;
}
-int CFlowStatParser::set_ip_id(uint32_t new_id) {
+void CFlowStatParser::set_ip_id(uint32_t new_id) {
if (m_ipv4) {
+ uint16_t ipv4_ip_id = (uint16_t) new_id;
// Updating checksum, not recalculating, so if someone put bad checksum on purpose, it will stay bad
- m_ipv4->updateCheckSum(PKT_NTOHS(m_ipv4->getFirstWord()), PKT_NTOHS(m_ipv4->getFirstWord() |TOS_TTL_RESERVE_DUPLICATE));
- m_ipv4->updateCheckSum(PKT_NTOHS(m_ipv4->getId()), PKT_NTOHS(new_id));
- m_ipv4->setId(new_id);
- m_ipv4->setTOS(m_ipv4->getTOS()|TOS_TTL_RESERVE_DUPLICATE);
- return 0;
+ m_ipv4->updateCheckSum(PKT_NTOHS(m_ipv4->getId()), PKT_NTOHS(ipv4_ip_id));
+ m_ipv4->setId(ipv4_ip_id);
}
if (m_ipv6) {
- m_ipv6->setTrafficClass(m_ipv6->getTrafficClass()|TOS_TTL_RESERVE_DUPLICATE);
m_ipv6->setFlowLabel(new_id);
- return 0;
}
- return -1;
}
+// In Mellanox and VIC cards, we use TOS to mark packets to go to CPU
+void CFlowStatParser::set_tos_to_cpu() {
+ if (m_ipv4) {
+ // Updating checksum, not recalculating, so if someone put bad checksum on purpose, it will stay bad
+ m_ipv4->updateCheckSum(PKT_NTOHS(m_ipv4->getFirstWord()), PKT_NTOHS(m_ipv4->getFirstWord()
+ | TOS_GO_TO_CPU));
+ m_ipv4->setTOS(m_ipv4->getTOS() | TOS_GO_TO_CPU);
+ }
+
+ if (m_ipv6) {
+ m_ipv6->setTrafficClass(m_ipv6->getTrafficClass() | TOS_GO_TO_CPU);
+ }
+}
+
+
int CFlowStatParser::get_l3_proto(uint16_t &proto) {
if (m_ipv4) {
proto = EthernetHeader::Protocol::IP;
diff --git a/src/flow_stat_parser.h b/src/flow_stat_parser.h
index c00d7e33..a6e43e0d 100644
--- a/src/flow_stat_parser.h
+++ b/src/flow_stat_parser.h
@@ -65,7 +65,8 @@ class CFlowStatParser {
std::string get_error_str(CFlowStatParser_err_t err);
virtual CFlowStatParser_err_t parse(uint8_t *pkt, uint16_t len);
virtual int get_ip_id(uint32_t &ip_id);
- virtual int set_ip_id(uint32_t ip_id);
+ virtual void set_ip_id(uint32_t ip_id);
+ virtual void set_tos_to_cpu();
virtual int get_l3_proto(uint16_t &proto);
virtual int get_l4_proto(uint8_t &proto);
virtual int get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload_len);
@@ -129,8 +130,9 @@ class CPassAllParser : public CFlowStatParser {
public:
CPassAllParser() : CFlowStatParser (CFlowStatParser::FLOW_STAT_PARSER_MODE_SW) {}
virtual CFlowStatParser_err_t parse(uint8_t *pkt, uint16_t len);
+ void set_tos_to_cpu() {}
virtual int get_ip_id(uint32_t &ip_id) { ip_id = 0; return 0;}
- virtual int set_ip_id(uint32_t ip_id){return 0;}
+ virtual void set_ip_id(uint32_t ip_id){}
virtual int get_l3_proto(uint16_t &proto){proto = 0; return 0;}
virtual int get_l4_proto(uint8_t &proto) {proto = 0; return 0;}
virtual int get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload_len) {payload_len = m_len; return 0;}
diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h
index 16752652..6cb68690 100644
--- a/src/internal_api/trex_platform_api.h
+++ b/src/internal_api/trex_platform_api.h
@@ -133,7 +133,8 @@ public:
virtual void publish_async_data_now(uint32_t key, bool baseline) const = 0;
virtual void publish_async_port_attr_changed(uint8_t port_id) const = 0;
virtual uint8_t get_dp_core_count() const = 0;
- virtual void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const =0;
+ virtual void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities
+ , uint16_t &ip_id_base) const =0;
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;
@@ -174,7 +175,8 @@ public:
void publish_async_data_now(uint32_t key, bool baseline) const;
void publish_async_port_attr_changed(uint8_t port_id) const;
uint8_t get_dp_core_count() const;
- void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const;
+ void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities
+ , uint16_t &ip_id_base) const;
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;
@@ -232,7 +234,8 @@ public:
virtual void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const {
}
- virtual void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const {num_counters=128; capabilities=TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD; }
+ virtual void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities
+ , uint16_t &ip_id_base) const {num_counters=128; capabilities=TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD; ip_id_base = 0xff00;}
virtual void port_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list) const {
for (int i = 0; i < m_dp_core_count; i++) {
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 434254a2..c26188d0 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -173,8 +173,7 @@ public:
, int min, int max) {return -1;}
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;}
+ virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) = 0;
virtual int verify_fw_ver(int i) {return 0;}
virtual CFlowStatParser *get_flow_stat_parser();
virtual int set_rcv_all(CPhyEthIF * _if, bool set_on)=0;
@@ -230,10 +229,20 @@ public:
virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
virtual void clear_extended_stats(CPhyEthIF * _if);
virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd) {return 0;}
- virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
- virtual int get_rx_stat_capabilities() {
- return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
+ virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) {
+ flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
| TrexPlatformApi::IF_STAT_PAYLOAD;
+
+ if (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE
+ || CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) {
+ num_counters = MAX_FLOW_STATS;
+ base_ip_id = IP_ID_RESERVE_BASE;
+ } else {
+ num_counters = UINT8_MAX;
+ // Must be 0xff00, since we configure HW filter for the 0xff byte
+ // The filter must catch all flow stat packets, and latency packets (having 0xffff in IP ID)
+ base_ip_id = 0xff00;
+ }
}
virtual int wait_for_stable_link();
virtual void wait_after_link_up();
@@ -268,11 +277,13 @@ public:
virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats)=0;
virtual void clear_extended_stats(CPhyEthIF * _if);
virtual int wait_for_stable_link();
- virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
- virtual int get_rx_stat_capabilities() {
- return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
+ virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) {
+ flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
| TrexPlatformApi::IF_STAT_PAYLOAD;
+ num_counters = MAX_FLOW_STATS;
+ base_ip_id = IP_ID_RESERVE_BASE;
}
+
virtual int set_rcv_all(CPhyEthIF * _if, bool set_on) {return 0;}
CFlowStatParser *get_flow_stat_parser();
};
@@ -376,10 +387,16 @@ public:
virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
virtual void clear_extended_stats(CPhyEthIF * _if);
virtual int wait_for_stable_link();
- virtual int get_stat_counters_num() {return MAX_FLOW_STATS;}
- virtual int get_rx_stat_capabilities() {
- return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
+ virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) {
+ flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
| TrexPlatformApi::IF_STAT_PAYLOAD;
+ if ((CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS)
+ || (CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE)) {
+ num_counters = MAX_FLOW_STATS;
+ } else {
+ num_counters = 127;
+ }
+ base_ip_id = IP_ID_RESERVE_BASE;
}
virtual CFlowStatParser *get_flow_stat_parser();
int add_del_eth_filter(CPhyEthIF * _if, bool is_add, uint16_t ethertype);
@@ -389,10 +406,11 @@ public:
class CTRexExtendedDriverBase40G : public CTRexExtendedDriverBase {
public:
CTRexExtendedDriverBase40G(){
- // Since we support only 128 counters per if, it is OK to configure here 4 statically.
+ // 4 will make us support 127 flow stat counters
// If we want to support more counters in case of card having less interfaces, we
// Will have to identify the number of interfaces dynamically.
m_if_per_card = 4;
+
m_cap = TREX_DRV_CAP_DROP_Q | TREX_DRV_CAP_MAC_ADDR_CHG | TREX_DRV_CAP_DROP_PKTS_IF_LNK_DOWN;
}
@@ -419,16 +437,23 @@ public:
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;}
- virtual int get_rx_stat_capabilities() {
- uint32_t ret = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD;
+ virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) {
+ flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD;
// HW counters on x710 does not support coutning bytes.
if ( CGlobalInfo::m_options.preview.get_disable_hw_flow_stat()
|| CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_ONE_QUEUE
|| CGlobalInfo::get_queues_mode() == CGlobalInfo::Q_MODE_RSS) {
- ret |= TrexPlatformApi::IF_STAT_RX_BYTES_COUNT;
+ flags |= TrexPlatformApi::IF_STAT_RX_BYTES_COUNT;
+ num_counters = MAX_FLOW_STATS;
+ } else {
+ if (m_if_per_card == 4) {
+ num_counters = MAX_FLOW_STATS_X710;
+ } else {
+ num_counters = MAX_FLOW_STATS_XL710;
+ }
}
- return ret;
+ base_ip_id = IP_ID_RESERVE_BASE;
+ m_max_flow_stats = num_counters;
}
virtual int wait_for_stable_link();
virtual bool hw_rx_stat_supported(){
@@ -452,6 +477,7 @@ private:
private:
uint8_t m_if_per_card;
+ uint16_t m_max_flow_stats;
};
class CTRexExtendedDriverBaseVIC : public CTRexExtendedDriverBase {
@@ -484,9 +510,13 @@ public:
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 get_stat_counters_num() {return MAX_FLOW_STATS;}
- virtual int get_rx_stat_capabilities() {
- return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD;
+ virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) {
+ flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
+ | TrexPlatformApi::IF_STAT_PAYLOAD;
+ num_counters = MAX_FLOW_STATS;
+ base_ip_id = IP_ID_RESERVE_BASE;
}
+
virtual CFlowStatParser *get_flow_stat_parser();
virtual int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd);
virtual int set_rcv_all(CPhyEthIF * _if, bool set_on);
@@ -541,9 +571,11 @@ public:
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;}
- virtual int get_rx_stat_capabilities() {
- return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD;
+ virtual void get_rx_stat_capabilities(uint16_t &flags, uint16_t &num_counters, uint16_t &base_ip_id) {
+ flags = TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_RX_BYTES_COUNT
+ | TrexPlatformApi::IF_STAT_PAYLOAD;
+ num_counters = 127; //With MAX_FLOW_STATS we saw packet failures in rx_test. Need to check.
+ base_ip_id = IP_ID_RESERVE_BASE;
}
virtual int wait_for_stable_link();
// disabling flow control on 40G using DPDK API causes the interface to malfunction
@@ -1503,12 +1535,6 @@ void CPhyEthIF::dump_stats_extended(FILE *fd){
}
}
-int CPhyEthIF::get_rx_stat_capabilities() {
- return get_ex_drv()->get_rx_stat_capabilities();
-}
-
-
-
void CPhyEthIF::configure(uint16_t nb_rx_queue,
uint16_t nb_tx_queue,
const struct rte_eth_conf *eth_conf){
@@ -4561,7 +4587,7 @@ CGlobalTRex::publish_async_data(bool sync_now, bool baseline) {
if (get_is_stateless()) {
std::string stat_json;
std::string latency_json;
- if (m_trex_stateless->m_rx_flow_stat.dump_json(stat_json, latency_json, baseline)) {
+ if (m_trex_stateless->m_rx_flow_stat.dump_json(stat_json, latency_json, baseline, sync_now)) {
m_zmq_publisher.publish_json(stat_json);
m_zmq_publisher.publish_json(latency_json);
}
@@ -6371,19 +6397,26 @@ int CTRexExtendedDriverBase10G::configure_rx_filter_rules(CPhyEthIF * _if) {
int CTRexExtendedDriverBase10G::configure_rx_filter_rules_stateless(CPhyEthIF * _if) {
uint8_t port_id = _if->get_rte_port_id();
- int ip_id_lsb;
+ uint8_t ip_id_lsb;
- // 0..MAX_FLOW_STATS-1 is for rules using ip_id.
- // MAX_FLOW_STATS rule is for the payload rules. Meaning counter value is in the payload
- for (ip_id_lsb = 0; ip_id_lsb <= MAX_FLOW_STATS; ip_id_lsb++ ) {
+ // 0..128-1 is for rules using ip_id.
+ // 128 rule is for the payload rules. Meaning counter value is in the payload
+ for (ip_id_lsb = 0; ip_id_lsb <= 128; ip_id_lsb++ ) {
struct rte_eth_fdir_filter fdir_filter;
int res = 0;
memset(&fdir_filter,0,sizeof(fdir_filter));
fdir_filter.input.flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_OTHER;
fdir_filter.soft_id = ip_id_lsb; // We can use the ip_id_lsb also as filter soft_id
- fdir_filter.input.flow_ext.flexbytes[0] = 0xff;
- fdir_filter.input.flow_ext.flexbytes[1] = ip_id_lsb;
+ if (ip_id_lsb == 128) {
+ // payload rule is for 0xffff
+ fdir_filter.input.flow_ext.flexbytes[0] = 0xff;
+ fdir_filter.input.flow_ext.flexbytes[1] = 0xff;
+ } else {
+ // less than 255 flow stats, so only byte 1 changes
+ fdir_filter.input.flow_ext.flexbytes[0] = 0xff & (IP_ID_RESERVE_BASE >> 8);
+ fdir_filter.input.flow_ext.flexbytes[1] = ip_id_lsb;
+ }
fdir_filter.action.rx_queue = 1;
fdir_filter.action.behavior = RTE_ETH_FDIR_ACCEPT;
fdir_filter.action.report_status = RTE_ETH_FDIR_NO_REPORT_STATUS;
@@ -6664,10 +6697,10 @@ extern "C" int rte_eth_fdir_stats_reset(uint8_t port_id, uint32_t *stats, uint32
// 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
+// id - Counter id in HW. We assume it is in the range 0..m_max_flow_stats
int CTRexExtendedDriverBase40G::add_del_rx_flow_stat_rule(uint8_t port_id, enum rte_filter_op op, uint16_t l3_proto
, uint8_t l4_proto, uint8_t ipv6_next_h, uint16_t id) {
- uint32_t rule_id = (port_id % m_if_per_card) * MAX_FLOW_STATS + id;
+ uint32_t rule_id = (port_id % m_if_per_card) * m_max_flow_stats + id;
uint16_t rte_type = RTE_ETH_FLOW_NONFRAG_IPV4_OTHER;
uint8_t next_proto;
@@ -6765,7 +6798,7 @@ int CTRexExtendedDriverBase40G::configure_rx_filter_rules(CPhyEthIF * _if) {
void CTRexExtendedDriverBase40G::reset_rx_stats(CPhyEthIF * _if, uint32_t *stats, int min, int len) {
uint32_t port_id = _if->get_port_id();
- uint32_t rule_id = (port_id % m_if_per_card) * MAX_FLOW_STATS + min;
+ uint32_t rule_id = (port_id % m_if_per_card) * m_max_flow_stats + min;
// 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
@@ -6786,9 +6819,9 @@ extern "C" int rte_eth_fdir_stats_get(uint8_t port_id, uint32_t *stats, uint32_t
// bytes and prev_bytes are not used. X710 fdir filters do not support byte count.
int CTRexExtendedDriverBase40G::get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts
,uint32_t *bytes, uint32_t *prev_bytes, int min, int max) {
- uint32_t hw_stats[MAX_FLOW_STATS];
+ uint32_t hw_stats[MAX_FLOW_STATS_XL710];
uint32_t port_id = _if->get_port_id();
- uint32_t start = (port_id % m_if_per_card) * MAX_FLOW_STATS + min;
+ uint32_t start = (port_id % m_if_per_card) * m_max_flow_stats + min;
uint32_t len = max - min + 1;
uint32_t loop_start = min;
@@ -7494,9 +7527,9 @@ TrexDpdkPlatformApi::publish_async_port_attr_changed(uint8_t port_id) const {
}
void
-TrexDpdkPlatformApi::get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const {
- num_counters = CTRexExtendedDriverDb::Ins()->get_drv()->get_stat_counters_num();
- capabilities = CTRexExtendedDriverDb::Ins()->get_drv()->get_rx_stat_capabilities();
+TrexDpdkPlatformApi::get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities
+ , uint16_t &ip_id_base) const {
+ CTRexExtendedDriverDb::Ins()->get_drv()->get_rx_stat_capabilities(capabilities, num_counters ,ip_id_base);
}
int TrexDpdkPlatformApi::get_flow_stats(uint8 port_id, void *rx_stats, void *tx_stats, int min, int max, bool reset
diff --git a/src/pkt_gen.cpp b/src/pkt_gen.cpp
index 9dc5ade1..e95398d4 100644
--- a/src/pkt_gen.cpp
+++ b/src/pkt_gen.cpp
@@ -236,7 +236,7 @@ char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t
case EthernetHeader::Protocol::IP:
ip->setTimeToLive(ttl);
if (flags & DPF_TOS_1) {
- ip->setTOS(TOS_TTL_RESERVE_DUPLICATE);
+ ip->setTOS(TOS_GO_TO_CPU);
}else{
ip->setTOS(0x2);
}
@@ -246,7 +246,7 @@ char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t
case EthernetHeader::Protocol::IPv6:
ipv6->setHopLimit(ttl);
if (flags & DPF_TOS_1) {
- ipv6->setTrafficClass(TOS_TTL_RESERVE_DUPLICATE);
+ ipv6->setTrafficClass(TOS_GO_TO_CPU);
}else{
ipv6->setTrafficClass(0x2);
}
diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
index 836dc5de..54945f1c 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -72,7 +72,7 @@ TrexRpcCmdAddStream::_run(const Json::Value &params, Json::Value &result) {
/* check packet size */
if ( (pkt_binary.size() < TrexStream::MIN_PKT_SIZE_BYTES) || (pkt_binary.size() > TrexStream::MAX_PKT_SIZE_BYTES) ) {
std::stringstream ss;
- ss << "bad packet size provided: should be between " << TrexStream::MIN_PKT_SIZE_BYTES << " and " << TrexStream::MAX_PKT_SIZE_BYTES;
+ ss << "Bad packet size provided: " << pkt_binary.size() << ". Should be between " << TrexStream::MIN_PKT_SIZE_BYTES << " and " << TrexStream::MAX_PKT_SIZE_BYTES;
generate_execute_err(result, ss.str());
}
diff --git a/src/stateless/cp/trex_exception.h b/src/stateless/cp/trex_exception.h
index ffc2f734..f4d7195a 100644
--- a/src/stateless/cp/trex_exception.h
+++ b/src/stateless/cp/trex_exception.h
@@ -51,7 +51,6 @@ class TrexException : public std::runtime_error
T_FLOW_STAT_NO_STREAMS_EXIST,
T_FLOW_STAT_ALREADY_STARTED,
T_FLOW_STAT_ALREADY_EXIST,
- T_FLOW_STAT_FAILED_CHANGE_IP_ID,
T_FLOW_STAT_NO_FREE_HW_ID,
T_FLOW_STAT_RX_CORE_START_FAIL,
T_FLOW_STAT_BAD_HW_ID,
diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp
index 423cd443..8aa45753 100644
--- a/src/stateless/cp/trex_stateless_port.cpp
+++ b/src/stateless/cp/trex_stateless_port.cpp
@@ -174,7 +174,8 @@ TrexStatelessPort::TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api
api->get_interface_info(port_id, m_api_info);
/* get RX caps */
- api->get_interface_stat_info(port_id, m_rx_count_num, m_rx_caps);
+ uint16_t ip_id_base;
+ api->get_interface_stat_info(port_id, m_rx_count_num, m_rx_caps, ip_id_base);
/* get the DP cores belonging to this port */
api->port_id_to_cores(m_port_id, core_pair_list);
diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp
index b6aa15be..dd5282b8 100644
--- a/src/stateless/dp/trex_stateless_dp_core.cpp
+++ b/src/stateless/dp/trex_stateless_dp_core.cpp
@@ -998,7 +998,7 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port,
if (stream->m_rx_check.m_enabled) {
node->set_stat_needed();
- uint8_t hw_id = stream->m_rx_check.m_hw_id;
+ uint16_t hw_id = stream->m_rx_check.m_hw_id;
assert (hw_id < MAX_FLOW_STATS + MAX_FLOW_STATS_PAYLOAD);
node->set_stat_hw_id(hw_id);
// no support for cache with flow stat payload rules
diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h
index b74e0f62..9accc3f2 100644
--- a/src/stateless/dp/trex_stream_node.h
+++ b/src/stateless/dp/trex_stream_node.h
@@ -100,10 +100,10 @@ private:
double m_next_time_offset; /* in sec */
uint16_t m_action_counter;
- uint8_t m_stat_hw_id; // hw id used to count rx and tx stats
- uint8_t m_null_stream;
+ uint16_t m_stat_hw_id; // hw id used to count rx and tx stats
uint16_t m_cache_array_cnt;
- uint16_t m_pad12;
+ uint8_t m_null_stream;
+ uint8_t m_pad12;
stream_state_t m_state;
uint8_t m_port_id;
@@ -301,7 +301,7 @@ public:
m_stat_hw_id = hw_id;
}
- socket_id_t get_stat_hw_id() {
+ uint16_t get_stat_hw_id() {
return ( m_stat_hw_id );
}
diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
index 0beeae69..17aecb03 100644
--- a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
@@ -24,6 +24,7 @@
#include "common/Network/Packet/Arp.h"
#include "pkt_gen.h"
#include "trex_stateless_capture.h"
+#include "stateless/cp/trex_stateless.h"
/**************************************
* latency RX feature
@@ -36,6 +37,8 @@ RXLatency::RXLatency() {
for (int i = 0; i < MAX_FLOW_STATS; i++) {
m_rx_pg_stat[i].clear();
+ }
+ for (int i = 0; i < MAX_FLOW_STATS_PAYLOAD; i++) {
m_rx_pg_stat_payload[i].clear();
}
}
@@ -50,6 +53,15 @@ RXLatency::create(CRFC2544Info *rfc2544, CRxCoreErrCntrs *err_cntrs) {
} else {
m_rcv_all = false;
}
+
+ uint16_t num_counters, cap, ip_id_base;
+ TrexStateless *tstateless = get_stateless_obj();
+ assert(tstateless);
+
+ const TrexPlatformApi *api = tstateless->get_platform_api();
+ assert(api);
+ api->get_interface_stat_info(0, num_counters, cap, ip_id_base);
+ m_ip_id_base = ip_id_base;
}
void
@@ -58,7 +70,7 @@ RXLatency::handle_pkt(const rte_mbuf_t *m) {
int ret = parser.parse(rte_pktmbuf_mtod(m, uint8_t *), m->pkt_len);
if (m_rcv_all || (ret == 0)) {
- uint32_t ip_id;
+ uint32_t ip_id = 0;
int ret2 = parser.get_ip_id(ip_id);
if (m_rcv_all || ( ret2 == 0)) {
if (m_rcv_all || is_flow_stat_id(ip_id)) {
@@ -157,7 +169,7 @@ RXLatency::handle_pkt(const rte_mbuf_t *m) {
curr_rfc2544->add_sample(ctime);
}
} else {
- hw_id = get_hw_id(ip_id);
+ hw_id = get_hw_id((uint16_t)ip_id);
if (hw_id < MAX_FLOW_STATS) {
m_rx_pg_stat[hw_id].add_pkts(1);
m_rx_pg_stat[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC
diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.h b/src/stateless/rx/trex_stateless_rx_port_mngr.h
index ea360490..b6d929ed 100644
--- a/src/stateless/rx/trex_stateless_rx_port_mngr.h
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.h
@@ -55,9 +55,12 @@ public:
void reset_stats();
private:
+ // below functions for both IP v4 and v6, so they need uint32_t id
bool is_flow_stat_id(uint32_t id) {
- if ((id & 0x000fff00) == IP_ID_RESERVE_BASE) return true;
- return false;
+ if ((uint16_t) id >= m_ip_id_base)
+ return true;
+ else
+ return false;
}
bool is_flow_stat_payload_id(uint32_t id) {
@@ -66,7 +69,7 @@ private:
}
uint16_t get_hw_id(uint16_t id) {
- return (0x00ff & id);
+ return (~m_ip_id_base & (uint16_t )id);
}
public:
@@ -77,6 +80,7 @@ public:
bool m_rcv_all;
CRFC2544Info *m_rfc2544;
CRxCoreErrCntrs *m_err_cntrs;
+ uint16_t m_ip_id_base;
};
diff --git a/src/trex_defs.h b/src/trex_defs.h
index 60a60df9..c4d6531e 100644
--- a/src/trex_defs.h
+++ b/src/trex_defs.h
@@ -23,8 +23,10 @@ limitations under the License.
#define TREX_MAX_PORTS 16
-// maximum number of IP ID type flow stats we support
-#define MAX_FLOW_STATS 127
+// maximum number of IP ID type flow stats we support. Must be in the form 2^x - 1
+#define MAX_FLOW_STATS 1023
+#define MAX_FLOW_STATS_X710 127
+#define MAX_FLOW_STATS_XL710 255
// maximum number of payload type flow stats we support
#define MAX_FLOW_STATS_PAYLOAD 128