Supporting more flows in stateless flow stats, according to NIC type, and running...
authorIdo Barnea <[email protected]>
Mon, 27 Mar 2017 12:37:21 +0000 (15:37 +0300)
committerIdo Barnea <[email protected]>
Thu, 30 Mar 2017 15:04:15 +0000 (18:04 +0300)
Signed-off-by: Ido Barnea <[email protected]>
20 files changed:
doc/trex_stateless.asciidoc
scripts/automation/regression/stateless_tests/stl_rx_test.py
src/bp_sim.cpp
src/bp_sim.h
src/debug.cpp
src/flow_stat.cpp
src/flow_stat.h
src/flow_stat_parser.cpp
src/flow_stat_parser.h
src/internal_api/trex_platform_api.h
src/main_dpdk.cpp
src/pkt_gen.cpp
src/rpc-server/commands/trex_rpc_cmd_stream.cpp
src/stateless/cp/trex_exception.h
src/stateless/cp/trex_stateless_port.cpp
src/stateless/dp/trex_stateless_dp_core.cpp
src/stateless/dp/trex_stream_node.h
src/stateless/rx/trex_stateless_rx_port_mngr.cpp
src/stateless/rx/trex_stateless_rx_port_mngr.h
src/trex_defs.h

index 1ca07a0..1a5c62b 100755 (executable)
@@ -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
index a71322f..ea37924 100644 (file)
@@ -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] )
-
index 43cfed9..9dfb7c3 100755 (executable)
@@ -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;
index fd4e662..c524723 100755 (executable)
@@ -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) );
         }
     }
 
index ccef849..d20721b 100644 (file)
@@ -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;
index 58d08c4..8d33bf3 100644 (file)
@@ -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;
index 25bf421..b155b91 100644 (file)
 #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];
 };
index f9ac8c9..ef9a120 100644 (file)
@@ -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;
index c00d7e3..a6e43e0 100644 (file)
@@ -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;}
index 1675265..6cb6869 100644 (file)
@@ -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++) {
index 434254a..c26188d 100644 (file)
@@ -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
index 9dc5ade..e95398d 100644 (file)
@@ -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);
         }
index 836dc5d..54945f1 100644 (file)
@@ -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()); 
     }
 
index ffc2f73..f4d7195 100644 (file)
@@ -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,
index 423cd44..8aa4575 100644 (file)
@@ -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);
index b6aa15b..dd5282b 100644 (file)
@@ -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
index b74e0f6..9accc3f 100644 (file)
@@ -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 );
     }
 
index 0beeae6..17aecb0 100644 (file)
@@ -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
index ea36049..b6d929e 100644 (file)
@@ -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;
 };
 
 
index 60a60df..c4d6531 100644 (file)
@@ -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