summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHanoh Haim <hhaim@cisco.com>2016-02-24 14:55:59 +0200
committerHanoh Haim <hhaim@cisco.com>2016-02-24 14:55:59 +0200
commit5a844c9d72411435842e5a0674c6fdc04e5d4e84 (patch)
treedc2738fe0638ac0ed856c70564bc7096bb33868e
parent9e616d8eecaefbf538174328edfce8fd96336ce6 (diff)
parent3eb4f868ef5bc728a46c8012c914f6a9381f4cdb (diff)
Merge GARP example
-rwxr-xr-xlinux/ws_main.py6
-rwxr-xr-xlinux_dpdk/ws_main.py2
-rwxr-xr-xscripts/automation/regression/unit_tests/functional_tests/hltapi_stream_builder_test.py34
-rw-r--r--scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows.py4
-rw-r--r--scripts/automation/trex_control_plane/stl/examples/stl_run_udp_simple.py4
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py40
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py95
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py27
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py3
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py106
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py4
-rw-r--r--scripts/exp/hlt_david1.pcapbin8140 -> 4192 bytes
-rw-r--r--scripts/exp/hlt_david2.pcapbin8118 -> 4158 bytes
-rw-r--r--scripts/exp/hlt_david3.pcapbin10264 -> 10264 bytes
-rw-r--r--scripts/exp/hlt_david4.pcapbin1624 -> 1624 bytes
-rwxr-xr-xscripts/stl/hlt/hlt_david1.py2
-rwxr-xr-xscripts/stl/hlt/hlt_david3.py2
-rwxr-xr-xscripts/stl/hlt/hlt_tcp_ranges.py1
-rwxr-xr-xscripts/stl/hlt/hlt_udp_inc_dec_len_9k.py2
-rw-r--r--scripts/stl/rx_stats.py19
-rw-r--r--scripts/stl/yaml/imix_1pkt_2.yaml10
-rwxr-xr-xscripts/t-rex-6410
-rwxr-xr-xsrc/bp_sim.h3
-rwxr-xr-xsrc/common/Network/Packet/IPHeader.h2
-rwxr-xr-xsrc/common/Network/Packet/IPHeader.inl6
-rw-r--r--src/debug.cpp285
-rw-r--r--src/debug.h2
-rw-r--r--src/dpdk22/drivers/net/i40e/i40e_ethdev.c34
-rw-r--r--src/dpdk22/drivers/net/i40e/i40e_fdir.c9
-rw-r--r--src/dpdk22/lib/librte_ether/rte_eth_ctrl.h6
-rw-r--r--src/dpdk22/lib/librte_ether/rte_ethdev.c17
-rw-r--r--src/flow_stat.cpp619
-rw-r--r--src/flow_stat.h139
-rw-r--r--src/flow_stat_parser.cpp137
-rw-r--r--src/flow_stat_parser.h37
-rw-r--r--src/gtest/trex_stateless_gtest.cpp16
-rw-r--r--src/internal_api/trex_platform_api.h45
-rw-r--r--[-rwxr-xr-x]src/main_dpdk.cpp378
-rw-r--r--src/main_dpdk.h91
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp13
-rw-r--r--src/rpc-server/commands/trex_rpc_cmds.h2
-rw-r--r--src/sim/trex_sim.h11
-rw-r--r--src/sim/trex_sim_stateless.cpp1
-rw-r--r--src/stateless/cp/trex_stateless.h3
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp73
-rw-r--r--src/stateless/cp/trex_stateless_port.h50
-rw-r--r--src/stateless/cp/trex_stream.cpp21
-rw-r--r--src/stateless/cp/trex_stream.h37
-rw-r--r--src/stateless/cp/trex_stream_vm.cpp8
-rw-r--r--src/stateless/cp/trex_stream_vm.h2
-rw-r--r--src/stateless/cp/trex_streams_compiler.cpp8
-rw-r--r--src/stateless/cp/trex_vm_splitter.cpp2
-rw-r--r--src/trex_defs.h31
53 files changed, 2026 insertions, 433 deletions
diff --git a/linux/ws_main.py b/linux/ws_main.py
index ce7140b9..9e4ac4d4 100755
--- a/linux/ws_main.py
+++ b/linux/ws_main.py
@@ -118,8 +118,10 @@ main_src = SrcGroup(dir='src',
'utl_cpuu.cpp',
'msg_manager.cpp',
'publisher/trex_publisher.cpp',
- 'latency.cpp',
-
+ 'latency.cpp',
+ 'flow_stat.cpp',
+ 'flow_stat_parser.cpp',
+
'pal/linux/pal_utl.cpp',
'pal/linux/mbuf.cpp',
'sim/trex_sim_stateless.cpp',
diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py
index b533004a..0d96cfae 100755
--- a/linux_dpdk/ws_main.py
+++ b/linux_dpdk/ws_main.py
@@ -99,6 +99,8 @@ main_src = SrcGroup(dir='src',
'global_io_mode.cpp',
'main_dpdk.cpp',
'debug.cpp',
+ 'flow_stat.cpp',
+ 'flow_stat_parser.cpp',
'bp_sim.cpp',
'latency.cpp',
'platform_cfg.cpp',
diff --git a/scripts/automation/regression/unit_tests/functional_tests/hltapi_stream_builder_test.py b/scripts/automation/regression/unit_tests/functional_tests/hltapi_stream_builder_test.py
index 297034db..30a9f6f8 100755
--- a/scripts/automation/regression/unit_tests/functional_tests/hltapi_stream_builder_test.py
+++ b/scripts/automation/regression/unit_tests/functional_tests/hltapi_stream_builder_test.py
@@ -47,7 +47,7 @@ class CTRexHltApi_Test(unittest.TestCase):
flags: 3
isg: 0.0
mode:
- pps: 1
+ percentage: 10.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABCABFAAAyAAAAAEAGusUAAAAAwAAAAQQAAFAAAAABAAAAAVAAD+U1/QAAISEhISEhISEhIQ==
@@ -92,7 +92,8 @@ TBD
ip_dst_addr = '5.5.5.5',
ip_dst_count = 2,
ip_dst_mode = 'random',
- name = 'test_ip_ranges')
+ name = 'test_ip_ranges',
+ rate_pps = 1)
self.test_yaml = test_stream.dump_to_yaml(self.yaml_save_location())
self.golden_yaml = '''
- name: test_ip_ranges
@@ -102,7 +103,7 @@ TBD
flags: 3
isg: 0.0
mode:
- pps: 1
+ pps: 1.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABCABFAAAyAAAAAEAGrxPAqAEBBQUFBQQAAFAAAAABAAAAAVAAD+UqSwAAISEhISEhISEhIQ==
@@ -150,7 +151,8 @@ TBD
tcp_dst_port_mode = 'random',
tcp_dst_port_count = 10,
tcp_dst_port = 1234,
- name = 'test_tcp_ranges')
+ name = 'test_tcp_ranges',
+ rate_pps = '2')
self.test_yaml = test_stream.dump_to_yaml(self.yaml_save_location())
self.golden_yaml = '''
- name: test_tcp_ranges
@@ -160,7 +162,7 @@ TBD
flags: 3
isg: 0.0
mode:
- pps: 1
+ pps: 2.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABCABFAAAyAAAAAEAGusUAAAAAwAAAAQQABNIAAAABAAAAAVAAD+UxewAAISEhISEhISEhIQ==
@@ -227,7 +229,8 @@ TBD
udp_dst_port_mode = 'increment',
udp_dst_port_count = 10,
udp_dst_port = 1234,
- name = 'test_udp_ranges')
+ name = 'test_udp_ranges',
+ rate_percent = 20,)
self.test_yaml = test_stream.dump_to_yaml(self.yaml_save_location())
self.golden_yaml = '''
- name: test_udp_ranges
@@ -237,7 +240,7 @@ TBD
flags: 3
isg: 0.0
mode:
- pps: 1
+ percentage: 20.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABCABFAAAyAAAAAEARuroAAAAAwAAAAQTSBNIAHsmgISEhISEhISEhISEhISEhISEhISEhIQ==
@@ -287,7 +290,8 @@ TBD
test_stream = STLHltStream(length_mode = 'decrement',
frame_size_min = 100,
frame_size_max = 3000,
- name = 'test_pkt_len_by_framesize')
+ name = 'test_pkt_len_by_framesize',
+ rate_bps = 1000)
self.test_yaml = test_stream.dump_to_yaml(self.yaml_save_location())
self.golden_yaml = '''
- name: test_pkt_len_by_framesize
@@ -297,7 +301,7 @@ TBD
flags: 3
isg: 0.0
mode:
- pps: 1
+ bps_L2: 1000.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABCABFAAuqAAAAAEAGr00AAAAAwAAAAQQAAFAAAAABAAAAAVAAD+UwiwAAISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEh
@@ -343,7 +347,7 @@ TBD
flags: 3
isg: 0.0
mode:
- pps: 1
+ percentage: 10.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABCABFAAGQAAAAAEARuVwAAAAAwAAAAQQAAFABfCaTISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEh
@@ -397,7 +401,7 @@ TBD
flags: 3
isg: 0.0
mode:
- pps: 1
+ percentage: 10.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABgQAwAAgARQAALgAAAABABrrJAAAAAMAAAAEEAABQAAAAAQAAAAFQAA/leEMAACEhISEhIQ==
@@ -429,7 +433,7 @@ TBD
flags: 3
isg: 0.0
mode:
- pps: 1
+ percentage: 10.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABgQAwAYEAMAKBADADgQAwBAgARQAARgAAAABABrqxAAAAAMAAAAEEAABQAAAAAQAAAAFQAA/l6p0AACEhISEhISEhISEhISEhISEhISEhISEhISEhISEhIQ==
@@ -461,7 +465,7 @@ TBD
flags: 3
isg: 0.0
mode:
- pps: 1
+ percentage: 10.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABgQAwAYEAMAKBADPogQAwBIEAMAUIAEUAAEIAAAAAQAa6tQAAAADAAAABBAAAUAAAAAEAAAABUAAP5SzkAAAhISEhISEhISEhISEhISEhISEhISEhISEhIQ==
@@ -540,7 +544,7 @@ TBD
flags: 3
isg: 0.0
mode:
- pps: 1
+ percentage: 10.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABht1gAAAAAG4GQP6AAAAAAAAAAAAAAAAAABL+gAAAAAAAAAAAAAAAAAAiBAAAUAAAAAEAAAABUAAP5ctLAAAhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISE=
@@ -570,7 +574,7 @@ TBD
flags: 3
isg: 0.0
mode:
- pps: 1
+ percentage: 10.0
type: continuous
packet:
binary: AAAAAAAAAAABAAABht1gAAAAAG4RQBERIiIzM0REVVVmZnd3iIgRERERERERERERERERERERBAAAUABucjohISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISE=
diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows.py b/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows.py
index 2382f2f4..7e90e264 100644
--- a/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows.py
+++ b/scripts/automation/trex_control_plane/stl/examples/stl_bi_dir_flows.py
@@ -20,11 +20,11 @@ def create_pkt (size, direction):
vm = [
# src
STLVmFlowVar(name="src",min_value=src['start'],max_value=src['end'],size=4,op="inc"),
- STLVmWriteFlowVar(fv_name="src",pkt_offset= "IP.src"),
+ STLVmWrFlowVar(fv_name="src",pkt_offset= "IP.src"),
# dst
STLVmFlowVar(name="dst",min_value=dst['start'],max_value=dst['end'],size=4,op="inc"),
- STLVmWriteFlowVar(fv_name="dst",pkt_offset= "IP.dst"),
+ STLVmWrFlowVar(fv_name="dst",pkt_offset= "IP.dst"),
# checksum
STLVmFixIpv4(offset = "IP")
diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_run_udp_simple.py b/scripts/automation/trex_control_plane/stl/examples/stl_run_udp_simple.py
index 388e42e7..db005608 100644
--- a/scripts/automation/trex_control_plane/stl/examples/stl_run_udp_simple.py
+++ b/scripts/automation/trex_control_plane/stl/examples/stl_run_udp_simple.py
@@ -47,11 +47,11 @@ def create_pkt (frame_size = 9000, direction=0):
vm = [
# src
STLVmFlowVar(name="src",min_value=src['start'],max_value=src['end'],size=4,op="inc"),
- STLVmWriteFlowVar(fv_name="src",pkt_offset= "IP.src"),
+ STLVmWrFlowVar(fv_name="src",pkt_offset= "IP.src"),
# dst
STLVmFlowVar(name="dst",min_value=dst['start'],max_value=dst['end'],size=4,op="inc"),
- STLVmWriteFlowVar(fv_name="dst",pkt_offset= "IP.dst"),
+ STLVmWrFlowVar(fv_name="dst",pkt_offset= "IP.dst"),
# checksum
STLVmFixIpv4(offset = "IP")
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py
index 581ea418..593c4c47 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py
@@ -27,9 +27,9 @@ traffic_config_kwargs = {
'port_handle2': None,
# stream builder parameters
'transmit_mode': 'continuous', # ( continuous | multi_burst | single_burst )
- 'rate_pps': 1, # TODO: support bps and percent once stateless API will, use rate_percent by default
+ 'rate_pps': None,
'rate_bps': None,
- 'rate_percent': 100,
+ 'rate_percent': 10,
'stream_id': None,
'name': None,
'bidirectional': 0,
@@ -663,55 +663,67 @@ class CTRexHltApi(object):
def STLHltStream(**user_kwargs):
kwargs = merge_kwargs(traffic_config_kwargs, user_kwargs)
+ # verify rate is given by at most one arg
+ rate_args = set(['rate_pps', 'rate_bps', 'rate_percent'])
+ intersect_rate_args = list(rate_args & set(user_kwargs.keys()))
+ if len(intersect_rate_args) > 1:
+ raise STLError('More than one rate argument specified: %s' % intersect_rate_args)
+ try:
+ rate_key = intersect_rate_args[0]
+ except IndexError:
+ rate_key = 'rate_percent'
+
if kwargs['length_mode'] == 'imix': # several streams with given length
streams_arr = []
user_kwargs['length_mode'] = 'fixed'
if kwargs['l3_imix1_size'] < 32 or kwargs['l3_imix2_size'] < 32 or kwargs['l3_imix3_size'] < 32 or kwargs['l3_imix4_size'] < 32:
raise STLError('l3_imix*_size should be at least 32')
- total_rate = kwargs['l3_imix1_ratio'] + kwargs['l3_imix2_ratio'] + kwargs['l3_imix3_ratio'] + kwargs['l3_imix4_ratio']
- if total_rate == 0:
+ total_ratio = kwargs['l3_imix1_ratio'] + kwargs['l3_imix2_ratio'] + kwargs['l3_imix3_ratio'] + kwargs['l3_imix4_ratio']
+ if total_ratio == 0:
raise STLError('Used length_mode imix, but all the ratios are 0')
save_to_yaml = kwargs.get('save_to_yaml')
- rate_pps = float(kwargs['rate_pps'])
+ total_rate = float(kwargs[rate_key])
if kwargs['l3_imix1_ratio'] > 0:
if save_to_yaml and type(save_to_yaml) is str:
user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix1.yaml')
user_kwargs['frame_size'] = kwargs['l3_imix1_size']
- user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix1_ratio'] / total_rate
+ user_kwargs[rate_key] = total_rate * kwargs['l3_imix1_ratio'] / total_ratio
streams_arr.append(STLHltStream(**user_kwargs))
if kwargs['l3_imix2_ratio'] > 0:
if save_to_yaml and type(save_to_yaml) is str:
user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix2.yaml')
user_kwargs['frame_size'] = kwargs['l3_imix2_size']
- user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix2_ratio'] / total_rate
+ user_kwargs[rate_key] = total_rate * kwargs['l3_imix2_ratio'] / total_ratio
streams_arr.append(STLHltStream(**user_kwargs))
if kwargs['l3_imix3_ratio'] > 0:
if save_to_yaml and type(save_to_yaml) is str:
user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix3.yaml')
user_kwargs['frame_size'] = kwargs['l3_imix3_size']
- user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix3_ratio'] / total_rate
+ user_kwargs[rate_key] = total_rate * kwargs['l3_imix3_ratio'] / total_ratio
streams_arr.append(STLHltStream(**user_kwargs))
if kwargs['l3_imix4_ratio'] > 0:
if save_to_yaml and type(save_to_yaml) is str:
user_kwargs['save_to_yaml'] = save_to_yaml.replace('.yaml', '_imix4.yaml')
user_kwargs['frame_size'] = kwargs['l3_imix4_size']
- user_kwargs['rate_pps'] = rate_pps * kwargs['l3_imix4_ratio'] / total_rate
+ user_kwargs[rate_key] = total_rate * kwargs['l3_imix4_ratio'] / total_ratio
streams_arr.append(STLHltStream(**user_kwargs))
return streams_arr
# packet generation
packet = generate_packet(**user_kwargs)
try:
+ # TODO: verify if bps is L1 or L2, use L2 for now
+ rate_types_dict = {'rate_pps': 'pps', 'rate_bps': 'bps_L2', 'rate_percent': 'percentage'}
+ rate_stateless = {rate_types_dict[rate_key]: float(kwargs[rate_key])}
transmit_mode = kwargs['transmit_mode']
- rate_pps = kwargs['rate_pps']
pkts_per_burst = kwargs['pkts_per_burst']
if transmit_mode == 'continuous':
- transmit_mode_class = STLTXCont(pps = rate_pps)
+ transmit_mode_class = STLTXCont(**rate_stateless)
elif transmit_mode == 'single_burst':
- transmit_mode_class = STLTXSingleBurst(pps = rate_pps, total_pkts = pkts_per_burst)
+ transmit_mode_class = STLTXSingleBurst(total_pkts = pkts_per_burst, **rate_stateless)
elif transmit_mode == 'multi_burst':
- transmit_mode_class = STLTXMultiBurst(pps = rate_pps, total_pkts = pkts_per_burst,
- count = int(kwargs['burst_loop_count']), ibg = kwargs['inter_burst_gap'])
+ transmit_mode_class = STLTXMultiBurst(total_pkts = pkts_per_burst, count = int(kwargs['burst_loop_count']),
+ ibg = kwargs['inter_burst_gap'], **rate_stateless)
else:
raise STLError('transmit_mode %s not supported/implemented')
except Exception as e:
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
index 29bad041..4dd07a13 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
@@ -1,6 +1,9 @@
from collections import namedtuple, OrderedDict
+from trex_stl_packet_builder_scapy import CScapyTRexPktBuilder
+from trex_stl_streams import STLStream
+import base64
import trex_stl_stats
from trex_stl_types import *
import time
@@ -132,10 +135,23 @@ class Port(object):
else:
raise Exception("port {0}: bad state received from server '{1}'".format(self.port_id, port_state))
- # TODO: handle syncing the streams into stream_db
self.next_available_id = long(rc.data()['max_stream_id']) + 1
+ # sync the streams
+ params = {"port_id": self.port_id}
+
+ command = RpcCmdData("get_all_streams", params)
+ rc = self.transmit(command.method, command.params)
+ if rc.bad():
+ return self.err(rc.err())
+
+ for k, v in rc.data()['streams'].iteritems():
+ self.streams[k] = {'next_id': v['next_stream_id'],
+ 'pkt' : base64.b64decode(v['packet']['binary']),
+ 'mode' : v['mode']['type'],
+ 'rate' : STLStream.get_rate_from_field(v['mode']['rate'])}
+
return self.ok()
@@ -161,55 +177,64 @@ class Port(object):
return self.err("Please stop port before attempting to add streams")
# listify
- streams_list = copy.deepcopy(streams_list if isinstance(streams_list, list) else [streams_list])
+ streams_list = streams_list if isinstance(streams_list, list) else [streams_list]
lookup = {}
# allocate IDs
for stream in streams_list:
- if stream.get_id() == None:
- stream.set_id(self.__allocate_stream_id())
- lookup[stream.get_name()] = stream.get_id()
+ # allocate stream id
+ stream_id = stream.get_id() if stream.get_id() is not None else self.__allocate_stream_id()
+ if stream_id in self.streams:
+ return self.err('Stream ID: {0} already exists'.format(stream_id))
- batch = []
+ # name
+ name = stream.get_name() if stream.get_name() is not None else id(stream)
+ if name in lookup:
+ return self.err("multiple streams with duplicate name: '{0}'".format(name))
+ lookup[name] = stream_id
-
+ batch = []
for stream in streams_list:
+ name = stream.get_name() if stream.get_name() is not None else id(stream)
+ stream_id = lookup[name]
next_id = -1
+
next = stream.get_next()
if next:
if not next in lookup:
return self.err("stream dependency error - unable to find '{0}'".format(next))
next_id = lookup[next]
-
- stream.set_next_id(next_id)
-
-
stream_json = stream.to_json()
- stream_json['next_stream_id'] = stream.get_next_id()
+ stream_json['next_stream_id'] = next_id
params = {"handler": self.handler,
"port_id": self.port_id,
- "stream_id": stream.get_id(),
+ "stream_id": stream_id,
"stream": stream_json}
cmd = RpcCmdData('add_stream', params)
batch.append(cmd)
- self.streams[stream.get_id()] = stream
rc = self.transmit_batch(batch)
- if not rc:
- return self.err(str(rc))
+ for i, single_rc in enumerate(rc):
+ if single_rc:
+ stream_id = batch[i].params['stream_id']
+ next_id = batch[i].params['stream']['next_stream_id']
+ self.streams[stream_id] = {'next_id' : next_id,
+ 'pkt' : streams_list[i].get_pkt(),
+ 'mode' : streams_list[i].get_mode(),
+ 'rate' : streams_list[i].get_rate()}
- # the only valid state now
- self.state = self.STATE_STREAMS
- return self.ok()
+ self.state = self.STATE_STREAMS if (len(self.streams) > 0) else self.STATE_IDLE
+
+ return self.ok() if rc else self.err(str(rc))
@@ -239,16 +264,16 @@ class Port(object):
cmd = RpcCmdData('remove_stream', params)
batch.append(cmd)
- del self.streams[stream_id]
-
rc = self.transmit_batch(batch)
- if not rc:
- return self.err(rc.err())
+ for i, single_rc in enumerate(rc):
+ if single_rc:
+ id = batch[i].params['stream_id']
+ del self.streams[stream_id]
self.state = self.STATE_STREAMS if (len(self.streams) > 0) else self.STATE_IDLE
- return self.ok()
+ return self.ok() if rc else self.err(rc.err())
# remove all the streams
@@ -273,6 +298,7 @@ class Port(object):
return self.ok()
+
# get a specific stream
def get_stream (self, stream_id):
if stream_id in self.streams:
@@ -283,6 +309,7 @@ class Port(object):
def get_all_streams (self):
return self.streams
+
# start traffic
def start (self, mul, duration, force):
if not self.is_acquired():
@@ -324,7 +351,6 @@ class Port(object):
return self.ok()
-
params = {"handler": self.handler,
"port_id": self.port_id}
@@ -421,6 +447,7 @@ class Port(object):
return self.ok()
+
def get_profile (self):
return self.profile
@@ -496,18 +523,24 @@ class Port(object):
return {}
data = {}
- for id, stream in self.streams.iteritems():
+ for id, obj in self.streams.iteritems():
+
+ # lazy build scapy repr.
+ if not 'pkt_type' in obj:
+ obj['pkt_type'] = CScapyTRexPktBuilder.pkt_layers_desc_from_buffer(obj['pkt'])
+
data[id] = OrderedDict([ ('id', id),
- ('packet_type', stream.get_pkt_type()),
- ('L2 len', stream.get_pkt_len()),
- ('mode' , stream.get_mode()),
- ('rate_pps', stream.get_pps()),
- ('next_stream', stream.get_next_id())
+ ('packet_type', obj['pkt_type']),
+ ('L2 len', len(obj['pkt']) + 4),
+ ('mode', obj['mode']),
+ ('rate', obj['rate']),
+ ('next_stream', obj['next_id'])
])
return {"streams" : OrderedDict(sorted(data.items())) }
+
################# events handler ######################
def async_event_port_stopped (self):
self.state = self.STATE_STREAMS
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py
index 907125e9..54d699d8 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_sim.py
@@ -152,19 +152,29 @@ class STLSim(object):
# load streams
cmds_json = []
- id = 1
+ id_counter = 1
lookup = {}
+
# allocate IDs
for stream in stream_list:
- if stream.get_id() == None:
- stream.set_id(id)
- id += 1
+ if stream.get_id() is not None:
+ stream_id = stream.get_id()
+ else:
+ stream_id = id_counter
+ id_counter += 1
- lookup[stream.get_name()] = stream.get_id()
+ name = stream.get_name() if stream.get_name() is not None else id(stream)
+ if name in lookup:
+ raise STLError("multiple streams with name: '{0}'".format(name))
+ lookup[name] = stream_id
# resolve names
for stream in stream_list:
+
+ name = stream.get_name() if stream.get_name() is not None else id(stream)
+ stream_id = lookup[name]
+
next_id = -1
next = stream.get_next()
if next:
@@ -172,19 +182,16 @@ class STLSim(object):
raise STLError("stream dependency error - unable to find '{0}'".format(next))
next_id = lookup[next]
- stream.set_next_id(next_id)
-
- for stream in stream_list:
stream_json = stream.to_json()
- stream_json['next_stream_id'] = stream.get_next_id()
+ stream_json['next_stream_id'] = next_id
cmd = {"id":1,
"jsonrpc": "2.0",
"method": "add_stream",
"params": {"handler": self.handler,
"port_id": self.port_id,
- "stream_id": stream.get_id(),
+ "stream_id": stream_id,
"stream": stream_json}
}
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py
index 34c7a857..ebc686f8 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py
@@ -224,13 +224,12 @@ class CTRexInfoGenerator(object):
p_type_field_len = 0
for stream_id, stream_id_sum in return_streams_data['streams'].iteritems():
- stream_id_sum['rate_pps'] = format_num(stream_id_sum['rate_pps'], suffix='pps')
stream_id_sum['packet_type'] = self._trim_packet_headers(stream_id_sum['packet_type'], 30)
p_type_field_len = max(p_type_field_len, len(stream_id_sum['packet_type']))
info_table = text_tables.TRexTextTable()
info_table.set_cols_align(["c"] + ["l"] + ["r"] + ["c"] + ["r"] + ["c"])
- info_table.set_cols_width([10] + [p_type_field_len] + [8] + [16] + [10] + [12])
+ info_table.set_cols_width([10] + [p_type_field_len] + [8] + [16] + [15] + [12])
info_table.set_cols_dtype(["t"] + ["t"] + ["t"] + ["t"] + ["t"] + ["t"])
info_table.add_rows([v.values()
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py
index f79d25c3..127d1669 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py
@@ -64,9 +64,9 @@ class STLTXMode(object):
# continuous mode
class STLTXCont(STLTXMode):
- def __init__ (self, pps = None, bps_L1 = None, bps_L2 = None, percentage = None):
+ def __init__ (self, **kwargs):
- super(STLTXCont, self).__init__(pps, bps_L1, bps_L2, percentage)
+ super(STLTXCont, self).__init__(**kwargs)
self.fields['type'] = 'continuous'
@@ -76,12 +76,12 @@ class STLTXCont(STLTXMode):
# single burst mode
class STLTXSingleBurst(STLTXMode):
- def __init__ (self, total_pkts = 1, pps = None, bps_L1 = None, bps_L2 = None, percentage = None):
+ def __init__ (self, total_pkts = 1, **kwargs):
if not isinstance(total_pkts, int):
raise STLArgumentError('total_pkts', total_pkts)
- super(STLTXSingleBurst, self).__init__(pps, bps_L1, bps_L2, percentage)
+ super(STLTXSingleBurst, self).__init__(**kwargs)
self.fields['type'] = 'single_burst'
self.fields['total_pkts'] = total_pkts
@@ -96,10 +96,7 @@ class STLTXMultiBurst(STLTXMode):
pkts_per_burst = 1,
ibg = 0.0, # usec not SEC
count = 1,
- pps = None,
- bps_L1 = None,
- bps_L2 = None,
- percentage = None):
+ **kwargs):
if not isinstance(pkts_per_burst, int):
raise STLArgumentError('pkts_per_burst', pkts_per_burst)
@@ -110,7 +107,7 @@ class STLTXMultiBurst(STLTXMode):
if not isinstance(count, int):
raise STLArgumentError('count', count)
- super(STLTXMultiBurst, self).__init__(pps, bps_L1, bps_L2, percentage)
+ super(STLTXMultiBurst, self).__init__(**kwargs)
self.fields['type'] = 'multi_burst'
self.fields['pkts_per_burst'] = pkts_per_burst
@@ -124,8 +121,24 @@ STLStreamDstMAC_CFG_FILE=0
STLStreamDstMAC_PKT =1
STLStreamDstMAC_ARP =2
+# RX stats class
+class STLRxStats(object):
+ def __init__ (self, user_id):
+ self.fields = {}
+
+ self.fields['enabled'] = True
+ self.fields['stream_id'] = user_id
+ self.fields['seq_enabled'] = False
+ self.fields['latency_enabled'] = False
+ def to_json (self):
+ return dict(self.fields)
+
+ @staticmethod
+ def defaults ():
+ return {'enabled' : False}
+
class STLStream(object):
def __init__ (self,
@@ -158,9 +171,7 @@ class STLStream(object):
self.name = name
self.next = next
- # ID
- self.set_id(stream_id)
- self.set_next_id(None)
+ self.id = stream_id
self.fields = {}
@@ -221,10 +232,9 @@ class STLStream(object):
self.packet_desc = None
if not rx_stats:
- self.fields['rx_stats'] = {}
- self.fields['rx_stats']['enabled'] = False
+ self.fields['rx_stats'] = STLRxStats.defaults()
else:
- self.fields['rx_stats'] = rx_stats
+ self.fields['rx_stats'] = rx_stats.to_json()
def __str__ (self):
@@ -239,14 +249,6 @@ class STLStream(object):
def get_id (self):
return self.id
- def set_id (self, id):
- self.id = id
-
- def get_next_id (self):
- return self.next_id
-
- def set_next_id (self, next_id):
- self.next_id = next_id
def get_name (self):
return self.name
@@ -254,26 +256,44 @@ class STLStream(object):
def get_next (self):
return self.next
- def get_pkt_type (self):
- if self.packet_desc == None:
- self.packet_desc = CScapyTRexPktBuilder.pkt_layers_desc_from_buffer(self.get_pkt())
-
- return self.packet_desc
def get_pkt (self):
return self.pkt
def get_pkt_len (self, count_crc = True):
- pkt_len = len(base64.b64decode(self.get_pkt()))
+ pkt_len = len(self.get_pkt())
if count_crc:
pkt_len += 4
return pkt_len
+ def get_pkt_type (self):
+ if self.packet_desc == None:
+ self.packet_desc = CScapyTRexPktBuilder.pkt_layers_desc_from_buffer(self.get_pkt())
+
+ return self.packet_desc
+
def get_mode (self):
return self.mode_desc
+ @staticmethod
+ def get_rate_from_field (rate_json):
+ t = rate_json['type']
+ v = rate_json['value']
+
+ if t == "pps":
+ return format_num(v, suffix = "pps")
+ elif t == "bps_L1":
+ return format_num(v, suffix = "bps (L1)")
+ elif t == "bps_L2":
+ return format_num(v, suffix = "bps (L2)")
+ elif t == "percentage":
+ return format_num(v, suffix = "%")
+
+ def get_rate (self):
+ return self.get_rate_from_field(self.fields['mode']['rate'])
+
def to_yaml (self):
y = {}
@@ -338,6 +358,8 @@ class YAMLLoader(object):
def __parse_mode (self, mode_obj):
+ if not mode_obj:
+ return None
rate_parser = set(mode_obj).intersection(['pps', 'bps_L1', 'bps_L2', 'percentage'])
if len(rate_parser) != 1:
@@ -371,6 +393,18 @@ class YAMLLoader(object):
+ def __parse_rx_stats (self, rx_stats_obj):
+
+ # no such object
+ if not rx_stats_obj or rx_stats_obj.get('enabled') == False:
+ return None
+
+ user_id = rx_stats_obj.get('stream_id')
+ if user_id == None:
+ raise STLError("enabled RX stats section must contain 'stream_id' field")
+
+ return STLRxStats(user_id = user_id)
+
def __parse_stream (self, yaml_object):
s_obj = yaml_object['stream']
@@ -384,23 +418,21 @@ class YAMLLoader(object):
# mode
- mode_obj = s_obj.get('mode')
- if not mode_obj:
- raise STLError("YAML file must contain 'mode' field")
-
- mode = self.__parse_mode(mode_obj)
+ mode = self.__parse_mode(s_obj.get('mode'))
+ # rx stats
+ rx_stats = self.__parse_rx_stats(s_obj.get('rx_stats'))
- defaults = STLStream()
+ defaults = STLStream()
# create the stream
stream = STLStream(name = yaml_object.get('name'),
packet = builder,
mode = mode,
+ rx_stats = rx_stats,
enabled = s_obj.get('enabled', defaults.fields['enabled']),
self_start = s_obj.get('self_start', defaults.fields['self_start']),
isg = s_obj.get('isg', defaults.fields['isg']),
- rx_stats = s_obj.get('rx_stats', defaults.fields['rx_stats']),
next = yaml_object.get('next'),
action_count = s_obj.get('action_count', defaults.fields['action_count']),
mac_src_override_by_pkt = s_obj.get('mac_src_override_by_pkt', 0),
@@ -523,7 +555,7 @@ class STLProfile(object):
streams.append(STLStream(name = i,
packet = CScapyTRexPktBuilder(pkt_buffer = cap, vm = vm),
- mode = STLTXSingleBurst(total_pkts = 1),
+ mode = STLTXSingleBurst(total_pkts = 1, percentage = 100),
self_start = True if (i == 1) else False,
isg = (ts_usec - last_ts_usec), # seconds to usec
action_count = action_count,
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py
index d4ad8bd2..496bea13 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_types.py
@@ -54,6 +54,10 @@ class RC():
s += format_text("\n{0}".format(x.data), 'bold')
return s
+ def __iter__(self):
+ return self.rc_list.__iter__()
+
+
def prn_func (self, msg, newline = True):
if newline:
print msg
diff --git a/scripts/exp/hlt_david1.pcap b/scripts/exp/hlt_david1.pcap
index 54013ae8..6c9a1cc8 100644
--- a/scripts/exp/hlt_david1.pcap
+++ b/scripts/exp/hlt_david1.pcap
Binary files differ
diff --git a/scripts/exp/hlt_david2.pcap b/scripts/exp/hlt_david2.pcap
index 8a75dd01..2c76a8a8 100644
--- a/scripts/exp/hlt_david2.pcap
+++ b/scripts/exp/hlt_david2.pcap
Binary files differ
diff --git a/scripts/exp/hlt_david3.pcap b/scripts/exp/hlt_david3.pcap
index 2044d2f3..d7c43f2b 100644
--- a/scripts/exp/hlt_david3.pcap
+++ b/scripts/exp/hlt_david3.pcap
Binary files differ
diff --git a/scripts/exp/hlt_david4.pcap b/scripts/exp/hlt_david4.pcap
index 46995494..a28d8ab1 100644
--- a/scripts/exp/hlt_david4.pcap
+++ b/scripts/exp/hlt_david4.pcap
Binary files differ
diff --git a/scripts/stl/hlt/hlt_david1.py b/scripts/stl/hlt/hlt_david1.py
index 879ea527..922bb632 100755
--- a/scripts/stl/hlt/hlt_david1.py
+++ b/scripts/stl/hlt/hlt_david1.py
@@ -26,7 +26,7 @@ class STLS1(object):
mac_src = '00.00.c0.a8.00.03',
mac_src2 = '00.00.c0.a8.01.03',
pkts_per_burst = '200000',
- #rate_percent = '0.4', # not supported yet
+ rate_percent = '0.4',
transmit_mode = 'continuous',
vlan_id = '1',
direction = direction,
diff --git a/scripts/stl/hlt/hlt_david3.py b/scripts/stl/hlt/hlt_david3.py
index 01bf2431..af41b3d4 100755
--- a/scripts/stl/hlt/hlt_david3.py
+++ b/scripts/stl/hlt/hlt_david3.py
@@ -16,7 +16,7 @@ class STLS1(object):
ip_dst_count = 1,
l3_length = 474,
ip_dscp = 10,
- #rate_bps = 256000000, # not supported yet
+ rate_bps = 256000000,
mac_src_mode = 'fixed',
mac_src_step = 1,
mac_src_count = 1,
diff --git a/scripts/stl/hlt/hlt_tcp_ranges.py b/scripts/stl/hlt/hlt_tcp_ranges.py
index 31edc61a..b720e1e2 100755
--- a/scripts/stl/hlt/hlt_tcp_ranges.py
+++ b/scripts/stl/hlt/hlt_tcp_ranges.py
@@ -12,6 +12,7 @@ class STLS1(object):
tcp_dst_port = 1234,
name = 'test_tcp_ranges',
direction = direction,
+ rate_pps = 1,
),
]
diff --git a/scripts/stl/hlt/hlt_udp_inc_dec_len_9k.py b/scripts/stl/hlt/hlt_udp_inc_dec_len_9k.py
index e7ee5b3d..e8766da4 100755
--- a/scripts/stl/hlt/hlt_udp_inc_dec_len_9k.py
+++ b/scripts/stl/hlt/hlt_udp_inc_dec_len_9k.py
@@ -11,6 +11,7 @@ class STLS1(object):
l4_protocol = 'udp',
udp_src_port = 1025,
udp_dst_port = 12,
+ rate_pps = 1,
),
STLHltStream(length_mode = 'decrement',
frame_size_max = 9*1024,
@@ -19,6 +20,7 @@ class STLS1(object):
l4_protocol = 'udp',
udp_src_port = 1025,
udp_dst_port = 12,
+ rate_pps = 1,
)
]
diff --git a/scripts/stl/rx_stats.py b/scripts/stl/rx_stats.py
new file mode 100644
index 00000000..892fe1a0
--- /dev/null
+++ b/scripts/stl/rx_stats.py
@@ -0,0 +1,19 @@
+from trex_stl_lib.api import *
+
+# stream from pcap file. continues pps 10 in sec
+
+class STLS1(object):
+
+ def get_streams (self, direction = 0):
+ return [STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_64B_no_crc.pcap"), # path relative to pwd
+ mode = STLTXCont(pps=10),
+ rx_stats = STLRxStats(user_id = 7))
+ ]
+
+
+# dynamic load - used for trex console or simulator
+def register():
+ return STLS1()
+
+
+
diff --git a/scripts/stl/yaml/imix_1pkt_2.yaml b/scripts/stl/yaml/imix_1pkt_2.yaml
index 07fd481d..dc1a457b 100644
--- a/scripts/stl/yaml/imix_1pkt_2.yaml
+++ b/scripts/stl/yaml/imix_1pkt_2.yaml
@@ -1,6 +1,6 @@
### Single stream UDP packet, 64B ###
#####################################
-- name: udp_64B
+- name: udp_64B_1
stream:
self_start: True
packet:
@@ -10,7 +10,7 @@
pps: 100
rx_stats: []
vm: []
-- name: udp_64B
+- name: udp_64B_2
stream:
self_start: True
packet:
@@ -20,7 +20,7 @@
pps: 100
rx_stats: []
vm: []
-- name: udp_64B
+- name: udp_64B_3
stream:
self_start: True
packet:
@@ -30,7 +30,7 @@
pps: 100
rx_stats: []
vm: []
-- name: udp_64B
+- name: udp_64B_4
stream:
self_start: True
packet:
@@ -39,4 +39,4 @@
type: continuous
pps: 100
rx_stats: []
- vm: [] \ No newline at end of file
+ vm: []
diff --git a/scripts/t-rex-64 b/scripts/t-rex-64
index 1cf82489..0516d7da 100755
--- a/scripts/t-rex-64
+++ b/scripts/t-rex-64
@@ -4,7 +4,9 @@ if [ $USER != 'root' ]; then
exit -1
fi
-./trex-cfg $@
+INPUT_ARGS=${@//[–—]/-} # replace bizarre minuses with normal one
+
+./trex-cfg $INPUT_ARGS
RESULT=$?
if [ $RESULT -ne 0 ]; then
exit $RESULT
@@ -16,15 +18,15 @@ export LD_LIBRARY_PATH=$PWD
saveterm="$(stty -g)"
# if we have a new core run optimized trex
if cat /proc/cpuinfo | grep -q avx ; then
- ./_$(basename $0) $@
+ ./_$(basename $0) $INPUT_ARGS
if [ $? -eq 132 ]; then
echo " WARNING this program is optimized for the new Intel processors. "
echo " try the ./t-rex-64-o application that should work for any Intel processor but might be slower. "
echo " try to run t-rex-64-o .. "
- ./_t-rex-64-o $@
+ ./_t-rex-64-o $INPUT_ARGS
fi
else
- ./_t-rex-64-o $@
+ ./_t-rex-64-o $INPUT_ARGS
fi
stty $saveterm
diff --git a/src/bp_sim.h b/src/bp_sim.h
index a51a520d..c9550dcf 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -43,6 +43,7 @@ limitations under the License.
#include <math.h>
#include <common/bitMan.h>
#include <yaml-cpp/yaml.h>
+#include "trex_defs.h"
#include "os_time.h"
#include "pal_utl.h"
#include "rx_check_header.h"
@@ -69,7 +70,7 @@ usec_to_sec(double usec) {
#define FORCE_NO_INLINE __attribute__ ((noinline))
-#define MAX_LATENCY_PORTS 12
+#define MAX_LATENCY_PORTS TREX_MAX_PORTS
/* IP address, last 32-bits of IPv6 remaps IPv4 */
typedef struct {
diff --git a/src/common/Network/Packet/IPHeader.h b/src/common/Network/Packet/IPHeader.h
index 5dfd03d8..b9ef8a2e 100755
--- a/src/common/Network/Packet/IPHeader.h
+++ b/src/common/Network/Packet/IPHeader.h
@@ -134,7 +134,7 @@ public:
inline void updateIpDst(uint32_t ipsrc);
-
+ inline void updateCheckSum(uint16_t old_val, uint16_t new_val);
inline void updateCheckSum ();
inline void updateCheckSum2(uint8_t* data1, uint16_t len1, uint8_t* data2 , uint16_t len2);
diff --git a/src/common/Network/Packet/IPHeader.inl b/src/common/Network/Packet/IPHeader.inl
index e7b87f06..26ea551a 100755
--- a/src/common/Network/Packet/IPHeader.inl
+++ b/src/common/Network/Packet/IPHeader.inl
@@ -258,6 +258,12 @@ inline void IPHeader::updateTotalLength(uint16_t newlen)
myChecksum = pkt_UpdateInetChecksum(myChecksum,oldLen,myLength);
}
+// updating checksum after changing old val to new
+inline void IPHeader::updateCheckSum(uint16_t old_val, uint16_t new_val)
+{
+ myChecksum = pkt_UpdateInetChecksum(myChecksum, old_val, new_val);
+}
+
inline void IPHeader::updateCheckSum()
{
myChecksum = 0;
diff --git a/src/debug.cpp b/src/debug.cpp
index ed4900f9..0ca34545 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -14,10 +14,10 @@
limitations under the License.
*/
-// DPDK c++ issue
+// DPDK c++ issue
#define UINT8_MAX 255
#define UINT16_MAX 0xFFFF
-// DPDK c++ issue
+// DPDK c++ issue
#include <stdio.h>
#include <unistd.h>
@@ -30,22 +30,22 @@
#include "main_dpdk.h"
#include "debug.h"
-const uint8_t udp_pkt[] = {
+const uint8_t udp_pkt[] = {
0x00,0x00,0x00,0x01,0x00,0x00,
0x00,0x00,0x00,0x01,0x00,0x00,
0x08,0x00,
-
+
0x45,0x00,0x00,0x81,
0xaf,0x7e,0x00,0x00,
0xfe,0x06,0xd9,0x23,
0x01,0x01,0x01,0x01,
0x3d,0xad,0x72,0x1b,
-
+
+ 0x11,0x11,
0x11,0x11,
- 0x11,0x11,
0x00,0x6d,
0x00,0x00,
-
+
0x64,0x31,0x3a,0x61,
0x64,0x32,0x3a,0x69,0x64,
0x32,0x30,0x3a,0xd0,0x0e,
@@ -63,9 +63,9 @@ const uint8_t udp_pkt[] = {
};
CTrexDebug::CTrexDebug(CPhyEthIF m_ports_arg[12], int max_ports) {
- m_test = NULL;
- m_ports = m_ports_arg;
- m_max_ports = max_ports;
+ m_test = NULL;
+ m_ports = m_ports_arg;
+ m_max_ports = max_ports;
}
int CTrexDebug::rcv_send(int port, int queue_id) {
@@ -86,6 +86,7 @@ int CTrexDebug::rcv_send(int port, int queue_id) {
return 0;
}
+// receive packets on queue_id
int CTrexDebug::rcv_send_all(int queue_id) {
int i;
for (i=0; i<m_max_ports; i++) {
@@ -95,76 +96,82 @@ int CTrexDebug::rcv_send_all(int queue_id) {
}
// For playing around, and testing packet sending in debug mode
-rte_mbuf_t *CTrexDebug::create_test_pkt(int pkt_type) {
+rte_mbuf_t *CTrexDebug::create_test_pkt(int pkt_type, uint8_t ttl, uint16_t ip_id) {
uint8_t proto;
int pkt_size = 0;
// ASA 2
- uint8_t dst_mac[6] = {0x74, 0xa2, 0xe6, 0xd5, 0x39, 0x25};
- uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02};
- // ASA 1
- // uint8_t dst_mac[6] = {0xd4, 0x8c, 0xb5, 0xc9, 0x54, 0x2b};
- // uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x0};
+ uint8_t dst_mac[6] = {0x74, 0xa2, 0xe6, 0xd5, 0x39, 0x25};
+ uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02};
+ // ASA 1
+ // uint8_t dst_mac[6] = {0xd4, 0x8c, 0xb5, 0xc9, 0x54, 0x2b};
+ // uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x0};
+ //#define VLAN
+#ifdef VLAN
+ uint16_t l2_proto = 0x0081;
+ uint8_t vlan_header[4] = {0x0a, 0xbc, 0x08, 0x00};
+#else
uint16_t l2_proto = 0x0008;
+#endif
uint8_t ip_header[] = {
- 0x45,0x02,0x00,0x30,
- 0x00,0x00,0x40,0x00,
- 0xff,0x01,0xbd,0x04,
- 0x10,0x0,0x0,0x1, //SIP
- 0x30,0x0,0x0,0x1, //DIP
- // 0x82, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // IP option. change 45 to 48 (header len) if using it.
+ 0x45,0x02,0x00,0x30,
+ 0x00,0x00,0x40,0x00,
+ 0xff,0x01,0xbd,0x04,
+ 0x10,0x0,0x0,0x1, //SIP
+ 0x30,0x0,0x0,0x1, //DIP
+ // 0x82, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // IP option. change 45 to 48 (header len) if using it.
};
uint8_t udp_header[] = {0x11, 0x11, 0x11,0x11, 0x00, 0x6d, 0x00, 0x00};
uint8_t udp_data[] = {0x64,0x31,0x3a,0x61,
- 0x64,0x32,0x3a,0x69,0x64,
- 0x32,0x30,0x3a,0xd0,0x0e,
- 0xa1,0x4b,0x7b,0xbd,0xbd,
- 0x16,0xc6,0xdb,0xc4,0xbb,0x43,
- 0xf9,0x4b,0x51,0x68,0x33,0x72,
- 0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f,
- 0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3,
- 0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f,
- 0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39,
- 0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31,
- 0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d,
- 0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d,
- 0xe7
+ 0x64,0x32,0x3a,0x69,0x64,
+ 0x32,0x30,0x3a,0xd0,0x0e,
+ 0xa1,0x4b,0x7b,0xbd,0xbd,
+ 0x16,0xc6,0xdb,0xc4,0xbb,0x43,
+ 0xf9,0x4b,0x51,0x68,0x33,0x72,
+ 0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f,
+ 0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3,
+ 0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f,
+ 0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39,
+ 0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31,
+ 0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d,
+ 0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d,
+ 0xe7
};
uint8_t tcp_header[] = {0xab, 0xcd, 0x00, 0x80, // src, dst ports
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // seq num, ack num
- 0x50, 0x00, 0xff, 0xff, // Header size, flags, window size
- 0x00, 0x00, 0x00, 0x00, // checksum ,urgent pointer
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // seq num, ack num
+ 0x50, 0x00, 0xff, 0xff, // Header size, flags, window size
+ 0x00, 0x00, 0x00, 0x00, // checksum ,urgent pointer
};
uint8_t tcp_data[] = {0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5};
uint8_t icmp_header[] = {
- 0x08, 0x00,
- 0xb8, 0x21, //checksum
- 0xaa, 0xbb, // id
- 0x00, 0x01, // Sequence number
+ 0x08, 0x00,
+ 0xb8, 0x21, //checksum
+ 0xaa, 0xbb, // id
+ 0x00, 0x01, // Sequence number
};
uint8_t icmp_data[] = {
- 0xd6, 0x6e, 0x64, 0x34, // magic
- 0x6a, 0xad, 0x0f, 0x00, //64 bit counter
- 0x00, 0x56, 0x34, 0x12,
- 0x78, 0x56, 0x34, 0x12, 0x00, 0x00 // seq
+ 0xd6, 0x6e, 0x64, 0x34, // magic
+ 0x6a, 0xad, 0x0f, 0x00, //64 bit counter
+ 0x00, 0x56, 0x34, 0x12,
+ 0x78, 0x56, 0x34, 0x12, 0x00, 0x00 // seq
};
switch (pkt_type) {
case 1:
- proto = IPPROTO_ICMP;
- pkt_size = 14 + sizeof(ip_header) + sizeof(icmp_header) + sizeof (icmp_data);
- break;
+ proto = IPPROTO_ICMP;
+ pkt_size = 14 + sizeof(ip_header) + sizeof(icmp_header) + sizeof (icmp_data);
+ break;
case 2:
- proto = IPPROTO_UDP;
- pkt_size = 14 + sizeof(ip_header) + sizeof(udp_header) + sizeof (udp_data);
- break;
+ proto = IPPROTO_UDP;
+ pkt_size = 14 + sizeof(ip_header) + sizeof(udp_header) + sizeof (udp_data);
+ break;
case 3:
- proto = IPPROTO_TCP;
- pkt_size = 14 + sizeof(ip_header) + sizeof(tcp_header) + sizeof (tcp_data);
- break;
+ proto = IPPROTO_TCP;
+ pkt_size = 14 + sizeof(ip_header) + sizeof(tcp_header) + sizeof (tcp_data);
+ break;
default:
- return NULL;
+ return NULL;
}
rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(0, pkt_size);
@@ -179,34 +186,39 @@ rte_mbuf_t *CTrexDebug::create_test_pkt(int pkt_type) {
memcpy(p, dst_mac, sizeof(dst_mac)); p += sizeof(dst_mac);
memcpy(p, src_mac, sizeof(src_mac)); p += sizeof(src_mac);
memcpy(p, &l2_proto, sizeof(l2_proto)); p += sizeof(l2_proto);
+#ifdef VLAN
+ memcpy(p, &vlan_header, sizeof(vlan_header)); p += sizeof(vlan_header);
+#endif
struct IPHeader *ip = (IPHeader *)p;
memcpy(p, ip_header, sizeof(ip_header)); p += sizeof(ip_header);
ip->setProtocol(proto);
ip->setTotalLength(pkt_size - 14);
+ ip->setId(ip_id);
- struct TCPHeader *tcp = (TCPHeader *)p;
+ struct TCPHeader *tcp = (TCPHeader *)p;
struct ICMPHeader *icmp= (ICMPHeader *)p;
switch (pkt_type) {
case 1:
- memcpy(p, icmp_header, sizeof(icmp_header)); p += sizeof(icmp_header);
- memcpy(p, icmp_data, sizeof(icmp_data)); p += sizeof(icmp_data);
- icmp->updateCheckSum(sizeof(icmp_header) + sizeof(icmp_data));
- break;
+ memcpy(p, icmp_header, sizeof(icmp_header)); p += sizeof(icmp_header);
+ memcpy(p, icmp_data, sizeof(icmp_data)); p += sizeof(icmp_data);
+ icmp->updateCheckSum(sizeof(icmp_header) + sizeof(icmp_data));
+ break;
case 2:
- memcpy(p, udp_header, sizeof(udp_header)); p += sizeof(udp_header);
- memcpy(p, udp_data, sizeof(udp_data)); p += sizeof(udp_data);
- break;
+ memcpy(p, udp_header, sizeof(udp_header)); p += sizeof(udp_header);
+ memcpy(p, udp_data, sizeof(udp_data)); p += sizeof(udp_data);
+ break;
case 3:
- memcpy(p, tcp_header, sizeof(tcp_header)); p += sizeof(tcp_header);
- memcpy(p, tcp_data, sizeof(tcp_data)); p += sizeof(tcp_data);
- tcp->setSynFlag(true);
- printf("Sending TCP header:");
- tcp->dump(stdout);
- break;
+ memcpy(p, tcp_header, sizeof(tcp_header)); p += sizeof(tcp_header);
+ memcpy(p, tcp_data, sizeof(tcp_data)); p += sizeof(tcp_data);
+ tcp->setSynFlag(true);
+ printf("Sending TCP header:");
+ tcp->dump(stdout);
+ break;
default:
- return NULL;
+ return NULL;
}
+ ip->setTimeToLive(ttl);
ip->updateCheckSum();
return m;
}
@@ -276,25 +288,81 @@ int CTrexDebug::set_promisc_all(bool enable) {
return 0;
}
+static void rte_stat_dump_array(const uint64_t *c, const char *name, int size) {
+ int i;
+
+ // dont print anything if all values are 0
+ for (i = 0; i < size; i++) {
+ if (c[i] != 0)
+ break;
+ }
+ if (i == size)
+ return;
+
+ printf("%s:", name);
+ for (i = 0; i < size; i++) {
+ if (((i % 32) == 0) && (size > 32)) {
+ printf ("\n %4d:", i);
+ }
+ printf(" %2ld", c[i]);
+ }
+ printf("\n");
+}
+
+static void rte_stat_dump_one(uint64_t c, const char *name) {
+ if (c != 0)
+ printf("%s:%ld\n", name, c);
+}
+
+static void rte_stats_dump(const struct rte_eth_stats &stats) {
+ rte_stat_dump_one(stats.ipackets, "ipackets");
+ rte_stat_dump_one(stats.opackets, "opackets");
+ rte_stat_dump_one(stats.ibytes, "ibytes");
+ rte_stat_dump_one(stats.obytes, "obytes");
+ rte_stat_dump_one(stats.imissed, "imissed");
+ rte_stat_dump_one(stats.ierrors, "ierrors");
+ rte_stat_dump_one(stats.oerrors, "oerrors");
+ rte_stat_dump_one(stats.rx_nombuf, "rx_nombuf");
+ rte_stat_dump_array(stats.q_ipackets, "queue rx", RTE_ETHDEV_QUEUE_STAT_CNTRS);
+ rte_stat_dump_array(stats.q_opackets, "queue tx", RTE_ETHDEV_QUEUE_STAT_CNTRS);
+ rte_stat_dump_array(stats.q_ibytes, "queue rx bytes", RTE_ETHDEV_QUEUE_STAT_CNTRS);
+ rte_stat_dump_array(stats.q_obytes, "queue tx bytes", RTE_ETHDEV_QUEUE_STAT_CNTRS);
+ rte_stat_dump_array(stats.q_errors, "queue dropped", RTE_ETHDEV_QUEUE_STAT_CNTRS);
+ rte_stat_dump_one(stats.ilbpackets, "rx loopback");
+ rte_stat_dump_one(stats.olbpackets, "tx loopback");
+ rte_stat_dump_one(stats.ilbbytes, "rx bytes loopback");
+ rte_stat_dump_one(stats.olbbytes, "tx bytes loopback");
+}
+
int CTrexDebug::test_send(uint pkt_type) {
+ int port_id;
+
set_promisc_all(true);
- rte_mbuf_t *m, *d;
+ rte_mbuf_t *m, *d, *d2=NULL, *d3=NULL;
if (pkt_type < 1 || pkt_type > 4) {
- printf("Unsupported packet type %d\n", pkt_type);
- printf("Supported packet types are: %d(ICMP), %d(UDP), %d(TCP) %d(9k UDP)\n", 1, 2, 3, 4);
- exit(-1);
+ printf("Unsupported packet type %d\n", pkt_type);
+ printf("Supported packet types are: %d(ICMP), %d(UDP), %d(TCP) %d(9k UDP)\n", 1, 2, 3, 4);
+ exit(-1);
}
if (pkt_type == 4) {
- m = create_udp_9k_pkt();
- assert (m);
- d = create_pkt_indirect(m, 9*1024+18);
+ m = create_udp_9k_pkt();
+ assert (m);
+ d = create_pkt_indirect(m, 9*1024+18);
} else {
- d = create_test_pkt(pkt_type);
+ d = create_test_pkt(pkt_type, 255, 0xff35);
+ // d2 = create_test_pkt(pkt_type, 253, 0xfe01);
+ // d3 = create_test_pkt(pkt_type, 251, 0xfe02);
}
if (d == NULL) {
- printf("Packet creation failed\n");
- exit(-1);
+ printf("Packet creation failed\n");
+ exit(-1);
+ }
+
+ // read first time to zero statistics
+ for (port_id = 0; port_id < m_max_ports; port_id++) {
+ CPhyEthIF * lp=&m_ports[port_id];
+ lp->get_rx_stats(NULL, -1, true);
}
printf("Sending packet:\n");
@@ -302,32 +370,51 @@ int CTrexDebug::test_send(uint pkt_type) {
test_send_pkts(d, 0, 2, 0);
test_send_pkts(d, 0, 1, 1);
+ if (d2) {
+ test_send_pkts(d2, 0, 4, 0);
+ test_send_pkts(d2, 0, 3, 1);
+ }
+ if (d3) {
+ test_send_pkts(d3, 0, 6, 0);
+ test_send_pkts(d3, 0, 5, 1);
+ }
delay(1000);
- printf(" ---------\n");
- printf(" rx queue 0 \n");
- printf(" ---------\n");
- rcv_send_all(0);
- printf("\n\n");
-
- printf(" ---------\n");
- printf(" rx queue 1 \n");
- printf(" ---------\n");
- rcv_send_all(1);
- printf(" ---------\n");
+ int j=0;
+ for (j = 0; j < 2; j++) {
+ printf(" =========\n");
+ printf(" rx queue %d \n", j);
+ printf(" =========\n");
+ rcv_send_all(j);
+ printf("\n\n");
+ }
delay(1000);
- int j=0;
- for (j=0; j<m_max_ports; j++) {
- CPhyEthIF * lp=&m_ports[j];
- printf(" port : %d \n",j);
- printf(" ----------\n");
- lp->update_counters();
- lp->get_stats().Dump(stdout);
+ struct rte_eth_stats stats;
+ for (port_id = 0; port_id < m_max_ports; port_id++) {
+ CPhyEthIF * lp=&m_ports[port_id];
+ std::cout << "=====================\n";
+ std::cout << "Statistics for port " << port_id << std::endl;
+ std::cout << "=====================\n";
+
+ if (rte_eth_stats_get(port_id, &stats) == 0) {
+ rte_stats_dump(stats);
+ } else {
+ // For NICs which does not support rte_eth_stats_get, we have our own implementation.
+ lp->update_counters();
+ lp->get_stats().Dump(stdout);
+ }
+
lp->dump_stats_extended(stdout);
}
+ for (port_id = 0; port_id < m_max_ports; port_id++) {
+ uint64_t fdir_stat[TREX_FDIR_STAT_SIZE];
+ CPhyEthIF *lp = &m_ports[port_id];
+ if (lp->get_rx_stats(fdir_stat, -1, false) == 0)
+ rte_stat_dump_array(fdir_stat, "FDIR stat", TREX_FDIR_STAT_SIZE);
+ }
return (0);
}
diff --git a/src/debug.h b/src/debug.h
index fe37c186..4fc23d93 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -32,7 +32,7 @@ class CTrexDebug {
rte_mbuf_t *create_udp_9k_pkt();
int set_promisc_all(bool enable);
int test_send_pkts(rte_mbuf_t *, uint16_t queue_id, int pkt, int port);
- rte_mbuf_t *create_test_pkt(int proto);
+ rte_mbuf_t *create_test_pkt(int proto, uint8_t ttl, uint16_t ip_id);
public:
CTrexDebug(CPhyEthIF *m_ports_arg, int max_ports);
diff --git a/src/dpdk22/drivers/net/i40e/i40e_ethdev.c b/src/dpdk22/drivers/net/i40e/i40e_ethdev.c
index 0a1e9efc..510a98cd 100644
--- a/src/dpdk22/drivers/net/i40e/i40e_ethdev.c
+++ b/src/dpdk22/drivers/net/i40e/i40e_ethdev.c
@@ -695,6 +695,12 @@ static inline void i40e_flex_payload_reg_init(struct i40e_hw *hw)
#define I40E_PRTQF_FD_INSET(_i, _j) (0x00250000 + ((_i) * 64 + (_j) * 32))
#define I40E_GLQF_FD_MSK(_i, _j) (0x00267200 + ((_i) * 4 + (_j) * 8))
+// 0 - statfull mode. 1 stateless.
+static int trex_mode=0;
+void i40e_set_trex_mode(int mode) {
+ trex_mode = mode;
+}
+
static void i40e_dump_filter_regs(struct i40e_hw *hw)
{
int reg_nums[] = {31, 33, 34, 35, 41, 43};
@@ -716,9 +722,7 @@ static inline void i40e_filter_fields_reg_init(struct i40e_hw *hw)
I40E_WRITE_REG(hw, I40E_GLQF_ORT(12), 0x00000062);
I40E_WRITE_REG(hw, I40E_GLQF_PIT(2), 0x000024A0);
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(31, 0), 0);
- I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(31, 1), 0x00040000);
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(33, 0), 0);
- I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(33, 1), 0x00040000);
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(41, 0), 0);
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(41, 1), 0x00080000);
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(43, 0), 0);
@@ -727,7 +731,15 @@ static inline void i40e_filter_fields_reg_init(struct i40e_hw *hw)
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(34, 1), 0x00040000);
// filter IP according to ttl and L4 protocol
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(35, 0), 0);
- I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(35, 1), 0x00040000);
+ if (trex_mode == 1) {
+ I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(35, 1), 0x00100000);
+ I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(31, 1), 0x00100000);
+ I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(33, 1), 0x00100000);
+ } else {
+ I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(35, 1), 0x00040000);
+ I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(31, 1), 0x00040000);
+ I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(33, 1), 0x00040000);
+ }
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(44, 0), 0);
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(44, 1), 0x00080000);
I40E_WRITE_REG(hw, I40E_GLQF_FD_MSK(0, 34), 0x000DFF00);
@@ -2059,9 +2071,12 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
I40E_GLPRT_PTC9522L(hw->port),
pf->offset_loaded, &os->tx_size_big,
&ns->tx_size_big);
+#ifndef TREX_PATCH
i40e_stat_update_32(hw, I40E_GLQF_PCNT(pf->fdir.match_counter_index),
pf->offset_loaded,
&os->fd_sb_match, &ns->fd_sb_match);
+#endif
+
/* GLPRT_MSPDC not supported */
/* GLPRT_XEC not supported */
@@ -2084,6 +2099,19 @@ i40e_trex_get_speed(struct rte_eth_dev *dev)
}
}
+//TREX_PATCH
+// fill stats array with fdir rules match count statistics
+void
+i40e_trex_fdir_stats_get(struct rte_eth_dev *dev, uint32_t *stats, uint32_t start, uint32_t len)
+{
+ int i;
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ for (i = 0; i < len; i++) {
+ stats[i] = I40E_READ_REG(hw, I40E_GLQF_PCNT(i + start));
+ }
+}
+
/* Get all statistics of a port */
static void
i40e_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
diff --git a/src/dpdk22/drivers/net/i40e/i40e_fdir.c b/src/dpdk22/drivers/net/i40e/i40e_fdir.c
index 194f8629..f644ef3d 100644
--- a/src/dpdk22/drivers/net/i40e/i40e_fdir.c
+++ b/src/dpdk22/drivers/net/i40e/i40e_fdir.c
@@ -78,6 +78,7 @@
#define I40E_FDIR_FLUSH_RETRY 50
#define I40E_FDIR_FLUSH_INTERVAL_MS 5
+#define TREX_PATCH
#define I40E_COUNTER_PF 2
/* Statistic counter index for one pf */
#define I40E_COUNTER_INDEX_FDIR(pf_id) (0 + (pf_id) * I40E_COUNTER_PF)
@@ -719,8 +720,10 @@ i40e_fdir_fill_eth_ip_head(const struct rte_eth_fdir_input *fdir_input,
ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL;
/* set len to by default */
ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN);
- // TREX_PATCH
+#ifdef TREX_PATCH
ip->time_to_live = fdir_input->flow.ip4_flow.ttl;
+ ip->packet_id = rte_cpu_to_be_16(fdir_input->flow.ip4_flow.ip_id);
+#endif
/*
* The source and destination fields in the transmitted packet
* need to be presented in a reversed order with respect
@@ -1145,7 +1148,11 @@ i40e_fdir_filter_programming(struct i40e_pf *pf,
fdirdp->dtype_cmd_cntindex |=
rte_cpu_to_le_32(I40E_TXD_FLTR_QW1_CNT_ENA_MASK);
fdirdp->dtype_cmd_cntindex |=
+#ifdef TREX_PATCH
+ rte_cpu_to_le_32((fdir_action->stat_count_index <<
+#else
rte_cpu_to_le_32((pf->fdir.match_counter_index <<
+#endif
I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
I40E_TXD_FLTR_QW1_CNTINDEX_MASK);
diff --git a/src/dpdk22/lib/librte_ether/rte_eth_ctrl.h b/src/dpdk22/lib/librte_ether/rte_eth_ctrl.h
index dc26439d..419ca90e 100644
--- a/src/dpdk22/lib/librte_ether/rte_eth_ctrl.h
+++ b/src/dpdk22/lib/librte_ether/rte_eth_ctrl.h
@@ -407,8 +407,9 @@ struct rte_eth_l2_flow {
struct rte_eth_ipv4_flow {
uint32_t src_ip; /**< IPv4 source address to match. */
uint32_t dst_ip; /**< IPv4 destination address to match. */
- // TREX_PATCH
+ // TREX_PATCH (ttl and ip_id)
uint8_t ttl; /**< IPv4 ttl to match */
+ uint16_t ip_id; /**< IPv4 IP ID to match */
uint8_t l4_protocol; /**< IPv4 l4 protocol to match */
};
@@ -575,6 +576,9 @@ struct rte_eth_fdir_action {
/**< If report_status is RTE_ETH_FDIR_REPORT_ID_FLEX_4 or
RTE_ETH_FDIR_REPORT_FLEX_8, flex_off specifies where the reported
flex bytes start from in flexible payload. */
+ // TREX_PATCH
+ // Index for statistics counter that will count FDIR matches.
+ uint16_t stat_count_index;
};
/**
diff --git a/src/dpdk22/lib/librte_ether/rte_ethdev.c b/src/dpdk22/lib/librte_ether/rte_ethdev.c
index 43ec0265..383ad120 100644
--- a/src/dpdk22/lib/librte_ether/rte_ethdev.c
+++ b/src/dpdk22/lib/librte_ether/rte_ethdev.c
@@ -1445,6 +1445,23 @@ rte_eth_get_speed(uint8_t port_id, int *speed)
return 0;
}
+// TREX_PATCH
+// return in stats, statistics starting from start, for len counters.
+int
+rte_eth_fdir_stats_get(uint8_t port_id, uint32_t *stats, uint32_t start, uint32_t len)
+{
+ struct rte_eth_dev *dev;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+
+ dev = &rte_eth_devices[port_id];
+
+ // Only xl710 support this
+ i40e_trex_fdir_stats_get(dev, stats, start, len);
+
+ return 0;
+}
+
int
rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats)
{
diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp
new file mode 100644
index 00000000..298bcb52
--- /dev/null
+++ b/src/flow_stat.cpp
@@ -0,0 +1,619 @@
+/*
+ Ido Barnea
+ Cisco Systems, Inc.
+*/
+
+/*
+ Copyright (c) 2015-2016 Cisco Systems, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+#include <sstream>
+#include <string>
+#include <iostream>
+#include <assert.h>
+#include <os_time.h>
+#include <internal_api/trex_platform_api.h>
+#include "trex_stateless.h"
+#include "trex_stream.h"
+#include "flow_stat_parser.h"
+#include "flow_stat.h"
+
+
+#define FLOW_STAT_ADD_ALL_PORTS 255
+
+static const uint16_t FREE_HW_ID = UINT16_MAX;
+
+#ifdef __DEBUG_FUNC_ENTRY__
+inline std::string methodName(const std::string& prettyFunction)
+{
+ size_t colons = prettyFunction.find("::");
+ size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1;
+ size_t end = prettyFunction.rfind("(") - begin;
+
+ return prettyFunction.substr(begin,end) + "()";
+}
+
+#define __METHOD_NAME__ methodName(__PRETTY_FUNCTION__)
+#define FUNC_ENTRY (std::cout << __METHOD_NAME__ << std::endl);
+#else
+#define FUNC_ENTRY
+#endif
+
+/************** class CFlowStatUserIdInfo ***************/
+CFlowStatUserIdInfo::CFlowStatUserIdInfo(uint8_t proto) {
+ memset(m_rx_counter, 0, sizeof(m_rx_counter));
+ memset(m_rx_counter_base, 0, sizeof(m_rx_counter));
+ memset(m_tx_counter, 0, sizeof(m_tx_counter));
+ memset(m_tx_counter_base, 0, sizeof(m_tx_counter));
+ m_hw_id = UINT16_MAX;
+ m_proto = proto;
+ m_ref_count = 1;
+ m_trans_ref_count = 0;
+}
+
+std::ostream& operator<<(std::ostream& os, const class CFlowStatUserIdInfo& cf) {
+ os << "hw_id:" << cf.m_hw_id << " proto:" << (uint16_t) cf.m_proto << " ref("
+ << (uint16_t) cf.m_ref_count << "," << (uint16_t) cf.m_trans_ref_count << ")";
+ os << " rx count (";
+ os << cf.m_rx_counter[0];
+ for (int i = 1; i < TREX_MAX_PORTS; i++) {
+ os << "," << cf.m_rx_counter[i];
+ }
+ os << ")";
+ os << " rx count base(";
+ os << cf.m_rx_counter_base[0];
+ for (int i = 1; i < TREX_MAX_PORTS; i++) {
+ os << "," << cf.m_rx_counter_base[i];
+ }
+ os << ")";
+
+ os << " tx count (";
+ os << cf.m_tx_counter[0];
+ for (int i = 1; i < TREX_MAX_PORTS; i++) {
+ os << "," << cf.m_tx_counter[i];
+ }
+ os << ")";
+ os << " tx count base(";
+ os << cf.m_tx_counter_base[0];
+ for (int i = 1; i < TREX_MAX_PORTS; i++) {
+ os << "," << cf.m_tx_counter_base[i];
+ }
+ os << ")";
+
+ return os;
+}
+
+int CFlowStatUserIdInfo::add_stream(uint8_t proto) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " proto:" << (uint16_t)proto << std::endl;
+#endif
+
+ if (proto != m_proto)
+ return -1;
+
+ m_ref_count++;
+
+ return 0;
+}
+
+void CFlowStatUserIdInfo::reset_hw_id() {
+ FUNC_ENTRY;
+
+ m_hw_id = UINT16_MAX;
+ // we are not attached to hw. Save packet count of session.
+ // Next session will start counting from 0.
+ for (int i = 0; i < TREX_MAX_PORTS; i++) {
+ m_rx_counter_base[i] += m_rx_counter[i];
+ m_rx_counter[i] = 0;
+ m_tx_counter_base[i] += m_tx_counter[i];
+ m_tx_counter[i] = 0;
+ }
+}
+/************** class CFlowStatUserIdMap ***************/
+CFlowStatUserIdMap::CFlowStatUserIdMap() {
+
+}
+
+std::ostream& operator<<(std::ostream& os, const CFlowStatUserIdMap& cf) {
+ std::map<unsigned int, CFlowStatUserIdInfo*>::const_iterator it;
+ for (it = cf.m_map.begin(); it != cf.m_map.end(); it++) {
+ CFlowStatUserIdInfo *user_id_info = it->second;
+ uint32_t user_id = it->first;
+ os << "Flow stat user id info:\n";
+ os << " " << user_id << ":" << *user_id_info << std::endl;
+ }
+ return os;
+}
+
+uint16_t CFlowStatUserIdMap::get_hw_id(uint32_t user_id) {
+ class CFlowStatUserIdInfo *cf = find_user_id(user_id);
+
+ if (cf == NULL) {
+ return FREE_HW_ID;
+ } else {
+ return cf->get_hw_id();
+ }
+}
+
+class CFlowStatUserIdInfo *
+CFlowStatUserIdMap::find_user_id(uint32_t user_id) {
+ flow_stat_user_id_map_it_t it = m_map.find(user_id);
+
+ if (it == m_map.end()) {
+ return NULL;
+ } else {
+ return it->second;
+ }
+}
+
+class CFlowStatUserIdInfo *
+CFlowStatUserIdMap::add_user_id(uint32_t user_id, uint8_t proto) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << user_id << " proto:" << (uint16_t)proto
+ << std::endl;
+#endif
+
+ class CFlowStatUserIdInfo *new_id = new CFlowStatUserIdInfo(proto);
+ if (new_id != NULL) {
+ std::pair<flow_stat_user_id_map_it_t, bool> ret;
+ ret = m_map.insert(std::pair<uint32_t, class CFlowStatUserIdInfo *>(user_id, new_id));
+ if (ret.second == false) {
+ printf("%s Error: Trying to add user id %d which already exist\n", __func__, user_id);
+ delete new_id;
+ return NULL;
+ }
+ return new_id;
+ } else {
+ return NULL;
+ }
+}
+
+int CFlowStatUserIdMap::add_stream(uint32_t user_id, uint8_t proto) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << user_id << " proto:" << (uint16_t)proto
+ << std::endl;
+#endif
+
+ class CFlowStatUserIdInfo *c_user_id;
+
+ c_user_id = find_user_id(user_id);
+ if (! c_user_id) {
+ c_user_id = add_user_id(user_id, proto);
+ if (! c_user_id)
+ return -1;
+ return 0;
+ } else {
+ return c_user_id->add_stream(proto);
+ }
+}
+
+int CFlowStatUserIdMap::del_stream(uint32_t user_id) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << user_id << std::endl;
+#endif
+
+ class CFlowStatUserIdInfo *c_user_id;
+
+ c_user_id = find_user_id(user_id);
+ if (! c_user_id) {
+ return -1;
+ }
+
+ if (c_user_id->del_stream() == 0) {
+ // ref count of this port became 0. can release this entry.
+ m_map.erase(user_id);
+ delete c_user_id;
+ }
+
+ return 0;
+}
+
+int CFlowStatUserIdMap::start_stream(uint32_t user_id, uint16_t hw_id) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << user_id << " hw_id:" << hw_id << std::endl;
+#endif
+
+ class CFlowStatUserIdInfo *c_user_id;
+
+ c_user_id = find_user_id(user_id);
+ if (! c_user_id) {
+ fprintf(stderr, "%s Error: Trying to associate hw id %d to user_id %d but it does not exist\n"
+ , __func__, hw_id, user_id);
+ return -1;
+ }
+
+ if (c_user_id->is_hw_id()) {
+ fprintf(stderr, "%s Error: Trying to associate hw id %d to user_id %d but it is already associate to %ld\n"
+ , __func__, hw_id, user_id, c_user_id->get_hw_id());
+ return -1;
+ }
+ c_user_id->set_hw_id(hw_id);
+ c_user_id->add_started_stream();
+
+ return 0;
+}
+
+int CFlowStatUserIdMap::start_stream(uint32_t user_id) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << user_id << std::endl;
+#endif
+
+ class CFlowStatUserIdInfo *c_user_id;
+
+ c_user_id = find_user_id(user_id);
+ if (! c_user_id) {
+ fprintf(stderr, "%s Error: Trying to start stream on user_id %d but it does not exist\n"
+ , __func__, user_id);
+ return -1;
+ }
+
+ c_user_id->add_started_stream();
+
+ return 0;
+}
+
+// return: negative number in case of error.
+// Number of started streams attached to used_id otherwise.
+int CFlowStatUserIdMap::stop_stream(uint32_t user_id) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << user_id << std::endl;
+#endif
+
+ class CFlowStatUserIdInfo *c_user_id;
+
+ c_user_id = find_user_id(user_id);
+ if (! c_user_id) {
+ fprintf(stderr, "%s Error: Trying to stop stream on user_id %d but it does not exist\n"
+ , __func__, user_id);
+ return -1;
+ }
+
+ return c_user_id->stop_started_stream();
+}
+
+bool CFlowStatUserIdMap::is_started(uint32_t user_id) {
+ class CFlowStatUserIdInfo *c_user_id;
+
+ c_user_id = find_user_id(user_id);
+ if (! c_user_id) {
+ return false;
+ }
+
+ return c_user_id->is_started();
+}
+
+uint8_t CFlowStatUserIdMap::l4_proto(uint32_t user_id) {
+ class CFlowStatUserIdInfo *c_user_id;
+
+ c_user_id = find_user_id(user_id);
+ if (! c_user_id) {
+ return 0;
+ }
+
+ return c_user_id->get_proto();
+}
+
+uint16_t CFlowStatUserIdMap::unmap(uint32_t user_id) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << user_id << std::endl;
+#endif
+
+ class CFlowStatUserIdInfo *c_user_id;
+
+ c_user_id = find_user_id(user_id);
+ if (! c_user_id) {
+ return UINT16_MAX;
+ }
+ uint16_t old_hw_id = c_user_id->get_hw_id();
+ c_user_id->reset_hw_id();
+
+ return old_hw_id;
+}
+
+/************** class CFlowStatHwIdMap ***************/
+CFlowStatHwIdMap::CFlowStatHwIdMap() {
+ m_num_free = MAX_FLOW_STATS;
+ for (int i = 0; i < MAX_FLOW_STATS; i++) {
+ m_map[i] = FREE_HW_ID;
+ }
+}
+
+std::ostream& operator<<(std::ostream& os, const CFlowStatHwIdMap& cf) {
+ int count = 0;
+
+ os << "HW id map:\n";
+ os << " num free:" << cf.m_num_free << std::endl;
+ for (int i = 0; i < MAX_FLOW_STATS; i++) {
+ if (cf.m_map[i] != 0) {
+ count++;
+ os << "(" << i << ":" << cf.m_map[i] << ")";
+ if (count == 10) {
+ os << std::endl;
+ count = 0;
+ }
+ }
+ }
+
+ return os;
+}
+
+uint16_t CFlowStatHwIdMap::find_free_hw_id() {
+ for (int i = 0; i < MAX_FLOW_STATS; i++) {
+ if (m_map[i] == FREE_HW_ID)
+ return i;
+ }
+
+ return FREE_HW_ID;
+}
+
+void CFlowStatHwIdMap::map(uint16_t hw_id, uint32_t user_id) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " hw id:" << hw_id << " user id:" << user_id << std::endl;
+#endif
+
+ m_map[hw_id] = user_id;
+ m_num_free--;
+}
+
+void CFlowStatHwIdMap::unmap(uint16_t hw_id) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " hw id:" << hw_id << std::endl;
+#endif
+
+ m_map[hw_id] = FREE_HW_ID;
+ m_num_free++;
+}
+
+/************** class CFlowStatRuleMgr ***************/
+CFlowStatRuleMgr::CFlowStatRuleMgr() {
+ m_api = NULL;
+}
+
+std::ostream& operator<<(std::ostream& os, const CFlowStatRuleMgr& cf) {
+ os << "Flow stat rule mgr (" << cf.m_num_ports << ") ports:" << std::endl;
+ os << cf.m_hw_id_map;
+ os << cf.m_user_id_map;
+ return os;
+}
+
+int CFlowStatRuleMgr::compile_stream(const TrexStream * stream, Cxl710Parser &parser) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << stream->m_rx_check.m_user_id << " en:";
+ std::cout << stream->m_rx_check.m_enabled << std::endl;
+#endif
+
+ // currently we support only IP ID rule types
+ // all our ports are the same type, so testing port 0 is enough
+ uint16_t num_counters, capabilities;
+ m_api->get_interface_stat_info(0, num_counters, capabilities);
+ if ((capabilities & TrexPlatformApi::IF_STAT_IPV4_ID) == 0) {
+ return -2;
+ }
+
+ if (parser.parse(stream->m_pkt.binary, stream->m_pkt.len) != 0) {
+ // if we could not parse the packet, but no stat count needed, it is probably OK.
+ if (stream->m_rx_check.m_enabled) {
+ fprintf(stderr, "Error: %s - Compilation failed\n", __func__);
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ if (!parser.is_fdir_supported()) {
+ if (stream->m_stream_id <= 0) {
+ // rx stat not needed. Do nothing.
+ return 0;
+ } else {
+ // rx stat needed, but packet format is not supported
+ fprintf(stderr, "Error: %s - Unsupported packet format for rx stat\n", __func__);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int CFlowStatRuleMgr::add_stream(const TrexStream * stream) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << stream->m_rx_check.m_user_id << std::endl;
+#endif
+
+ if (! m_api ) {
+ TrexStateless *tstateless = get_stateless_obj();
+ m_api = tstateless->get_platform_api();
+ // m_api = get_stateless_obj()->get_platform_api();
+ m_api->get_port_num(m_num_ports);
+ }
+
+ Cxl710Parser parser;
+ int ret;
+
+ if (! stream->m_rx_check.m_enabled) {
+ return 0;
+ }
+
+ if ((ret = compile_stream(stream, parser)) < 0)
+ return ret;
+
+ uint8_t l4_proto;
+ if (parser.get_l4_proto(l4_proto) < 0) {
+ printf("Error: %s failed finding l4 proto\n", __func__);
+ return -1;
+ }
+
+ return m_user_id_map.add_stream(stream->m_rx_check.m_user_id, l4_proto);
+}
+
+int CFlowStatRuleMgr::del_stream(const TrexStream * stream) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << stream->m_rx_check.m_user_id << std::endl;
+#endif
+
+ if (! stream->m_rx_check.m_enabled) {
+ return 0;
+ }
+
+ return m_user_id_map.del_stream(stream->m_rx_check.m_user_id);
+}
+
+// called on all streams, when stream start to transmit
+// If stream need flow stat counting, make sure the type of packet is supported, and
+// embed needed info in packet.
+// If stream does not need flow stat counting, make sure it does not interfere with
+// other streams that do need stat counting.
+// Might change the IP ID of the stream packet
+int CFlowStatRuleMgr::start_stream(TrexStream * stream) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << stream->m_rx_check.m_user_id << std::endl;
+#endif
+
+ Cxl710Parser parser;
+ int ret;
+
+ if (! m_api ) {
+ return 0;
+ }
+
+ if ((ret = compile_stream(stream, parser)) < 0)
+ return ret;
+
+ // first handle streams that do not need rx stat
+ if (! stream->m_rx_check.m_enabled) {
+ // no need for stat count
+ uint16_t ip_id;
+ if (parser.get_ip_id(ip_id) < 0) {
+ return 0; // if we could not find and ip id, no need to fix
+ }
+ // verify no reserved IP_ID used, and change if needed
+ if (ip_id >= IP_ID_RESERVE_BASE) {
+ if (parser.set_ip_id(ip_id & 0xefff) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ // from here, we know the stream need rx stat
+ if (m_user_id_map.is_started(stream->m_rx_check.m_user_id)) {
+ m_user_id_map.start_stream(stream->m_rx_check.m_user_id); // just increase ref count;
+ } else {
+ uint16_t hw_id = m_hw_id_map.find_free_hw_id();
+ if (hw_id == FREE_HW_ID) {
+ printf("Error: %s failed finding free hw_id\n", __func__);
+ return -1;
+ } else {
+ uint32_t user_id = stream->m_rx_check.m_user_id;
+ m_user_id_map.start_stream(user_id, hw_id);
+ m_hw_id_map.map(hw_id, user_id);
+ add_hw_rule(hw_id, m_user_id_map.l4_proto(user_id));
+ }
+ }
+
+ uint16_t hw_id = m_user_id_map.get_hw_id(stream->m_rx_check.m_user_id); // can't fail if we got here
+ parser.set_ip_id(IP_ID_RESERVE_BASE + hw_id);
+
+ return 0;
+}
+
+int CFlowStatRuleMgr::add_hw_rule(uint16_t hw_id, uint8_t proto) {
+ for (int port = 0; port < m_num_ports; port++) {
+ m_api->add_rx_flow_stat_rule(port, FLOW_STAT_RULE_TYPE_IPV4_ID, proto, hw_id);
+ }
+
+ return 0;
+}
+
+int CFlowStatRuleMgr::stop_stream(const TrexStream * stream) {
+#ifdef __DEBUG_FUNC_ENTRY__
+ std::cout << __METHOD_NAME__ << " user id:" << stream->m_rx_check.m_user_id << std::endl;
+#endif
+ if (! stream->m_rx_check.m_enabled) {
+ return 0;
+ }
+ if (! m_api ) {
+ return 0;
+ }
+
+ if (m_user_id_map.stop_stream(stream->m_rx_check.m_user_id) == 0) {
+ // last stream associated with the entry stopped transmittig.
+ // remove user_id <--> hw_id mapping
+ uint8_t proto = m_user_id_map.l4_proto(stream->m_rx_check.m_user_id);
+ uint16_t hw_id = m_user_id_map.unmap(stream->m_rx_check.m_user_id);
+ if (hw_id >= MAX_FLOW_STATS) {
+ fprintf(stderr, "Error: %s got wrong hw_id %d from unmap\n", __func__, hw_id);
+ return -1;
+ } else {
+ // update counters, and reset before unmapping
+ class CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(hw_id));
+ assert(p_user_id != NULL);
+ uint64_t counter;
+ for (uint8_t port = 0; port < m_num_ports; port++) {
+ m_api->del_rx_flow_stat_rule(port, FLOW_STAT_RULE_TYPE_IPV4_ID, proto, hw_id);
+ m_api->get_rx_stats(port, &counter, hw_id, true);
+ p_user_id->set_rx_counter(port, counter);
+ p_user_id->set_tx_counter(port, counter); //??? until tx work, just set for same value
+ }
+ m_hw_id_map.unmap(hw_id);
+ }
+ }
+ return 0;
+}
+
+// return false if no counters changed since last run. true otherwise
+bool CFlowStatRuleMgr::dump_json(std::string & json) {
+ uint64_t stats[TREX_FDIR_STAT_SIZE];
+ Json::FastWriter writer;
+ Json::Value root;
+ bool ret = false;
+
+ if (! m_api ) {
+ return false;
+ }
+ root["name"] = "rx-stats";
+ root["type"] = 0;
+ Json::Value &data_section = root["data"];
+
+ // read hw counters, and update
+ data_section["timestamp"] = Json::Value::UInt64(os_get_hr_tick_64());
+ for (uint8_t port = 0; port < m_num_ports; port++) {
+ m_api->get_rx_stats(port, stats, -1, false);
+ for (int i = 0; i < TREX_FDIR_STAT_SIZE; i++) {
+ if (stats[i] != 0) {
+ m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i))->set_rx_counter(port, stats[i]);
+ m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i))->set_tx_counter(port, stats[i]); //??? until tx work, just set for same value
+ }
+ }
+ }
+
+ // build json report
+ flow_stat_user_id_map_it_t it;
+ for (it = m_user_id_map.begin(); it != m_user_id_map.end(); it++) {
+ CFlowStatUserIdInfo *user_id_info = it->second;
+ uint32_t user_id = it->first;
+ std::string str_user_id = static_cast<std::ostringstream*>( &(std::ostringstream()
+ << user_id) )->str();
+ for (uint8_t port = 0; port < m_num_ports; port++) {
+ if ((user_id_info->get_tx_counter(port) != 0) || (user_id_info->get_rx_counter(port) != 0)) {
+ std::string str_port = static_cast<std::ostringstream*>( &(std::ostringstream()
+ << port) )->str();
+ data_section[str_user_id]["rx"][str_port] = Json::Value::UInt64(user_id_info->get_rx_counter(port));
+ data_section[str_user_id]["tx"][str_port] = Json::Value::UInt64(user_id_info->get_tx_counter(port));
+ ret = true;
+ }
+ }
+ }
+
+ json = writer.write(root);
+ return ret;
+}
diff --git a/src/flow_stat.h b/src/flow_stat.h
new file mode 100644
index 00000000..444daab0
--- /dev/null
+++ b/src/flow_stat.h
@@ -0,0 +1,139 @@
+/*
+ Ido Barnea
+ Cisco Systems, Inc.
+*/
+
+/*
+ Copyright (c) 2015-2016 Cisco Systems, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef __FLOW_STAT_H__
+#define __FLOW_STAT_H__
+#include <stdio.h>
+#include <string>
+#include <map>
+#include "trex_defs.h"
+
+#define MAX_FLOW_STATS 128
+// 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
+
+typedef std::map<uint32_t, uint16_t> flow_stat_map_t;
+typedef std::map<uint32_t, uint16_t>::iterator flow_stat_map_it_t;
+
+class CPhyEthIF;
+class Cxl710Parser;
+
+class CFlowStatUserIdInfo {
+ public:
+ CFlowStatUserIdInfo(uint8_t proto);
+ friend std::ostream& operator<<(std::ostream& os, const CFlowStatUserIdInfo& cf);
+ void set_rx_counter(uint8_t port, uint64_t val) {m_rx_counter[port] = val;}
+ uint64_t get_rx_counter(uint8_t port) {return m_rx_counter[port] + m_rx_counter_base[port];}
+ void set_tx_counter(uint8_t port, uint64_t val) {m_tx_counter[port] = val;}
+ uint64_t get_tx_counter(uint8_t port) {return m_tx_counter[port] + m_tx_counter_base[port];}
+ void set_hw_id(uint16_t hw_id) {m_hw_id = hw_id;}
+ uint64_t get_hw_id() {return m_hw_id;}
+ void reset_hw_id();
+ bool is_hw_id() {return (m_hw_id != UINT16_MAX);}
+ uint64_t get_proto() {return m_proto;}
+ uint8_t get_ref_count() {return m_ref_count;}
+ int add_stream(uint8_t proto);
+ int del_stream() {m_ref_count--; return m_ref_count;}
+ void add_started_stream() {m_trans_ref_count++;}
+ int stop_started_stream() {m_trans_ref_count--; return m_trans_ref_count;}
+ bool is_started() {return (m_trans_ref_count != 0);}
+
+ private:
+ uint64_t m_rx_counter[TREX_MAX_PORTS]; // How many packets received with this user id since stream start
+ // How many packets received with this user id, since stream creation, before stream start.
+ uint64_t m_rx_counter_base[TREX_MAX_PORTS];
+ uint64_t m_tx_counter[TREX_MAX_PORTS]; // How many packets transmitted with this user id since stream start
+ // How many packets transmitted with this user id, since stream creation, before stream start.
+ uint64_t m_tx_counter_base[TREX_MAX_PORTS];
+ uint16_t m_hw_id; // Associated hw id. UINT16_MAX if no associated hw id.
+ uint8_t m_proto; // protocol (UDP, TCP, other), associated with this user id.
+ uint8_t m_ref_count; // How many streams with this ref count exists
+ uint8_t m_trans_ref_count; // How many streams with this ref count currently transmit
+};
+
+typedef std::map<uint32_t, class CFlowStatUserIdInfo *> flow_stat_user_id_map_t;
+typedef std::map<uint32_t, class CFlowStatUserIdInfo *>::iterator flow_stat_user_id_map_it_t;
+
+class CFlowStatUserIdMap {
+ public:
+ CFlowStatUserIdMap();
+ friend std::ostream& operator<<(std::ostream& os, const CFlowStatUserIdMap& cf);
+ uint16_t get_hw_id(uint32_t user_id);
+ class CFlowStatUserIdInfo * find_user_id(uint32_t user_id);
+ class CFlowStatUserIdInfo * add_user_id(uint32_t user_id, uint8_t proto);
+ int add_stream(uint32_t user_id, uint8_t proto);
+ int del_stream(uint32_t user_id);
+ int start_stream(uint32_t user_id, uint16_t hw_id);
+ int start_stream(uint32_t user_id);
+ int stop_stream(uint32_t user_id);
+ bool is_started(uint32_t user_id);
+ uint8_t l4_proto(uint32_t user_id);
+ uint16_t unmap(uint32_t user_id);
+ flow_stat_user_id_map_it_t begin() {return m_map.begin();}
+ flow_stat_user_id_map_it_t end() {return m_map.end();}
+ private:
+ flow_stat_user_id_map_t m_map;
+};
+
+class CFlowStatHwIdMap {
+ public:
+ CFlowStatHwIdMap();
+ friend std::ostream& operator<<(std::ostream& os, const CFlowStatHwIdMap& cf);
+ uint16_t find_free_hw_id();
+ void map(uint16_t hw_id, uint32_t user_id);
+ void unmap(uint16_t hw_id);
+ uint32_t get_user_id(uint16_t hw_id) {return m_map[hw_id];};
+ private:
+ uint32_t m_map[MAX_FLOW_STATS]; // translation from hw id to user id
+ uint16_t m_num_free; // How many free entries in the m_rules array
+};
+
+class CFlowStatRuleMgr {
+ public:
+ enum flow_stat_rule_types_e {
+ FLOW_STAT_RULE_TYPE_NONE,
+ FLOW_STAT_RULE_TYPE_IPV4_ID,
+ FLOW_STAT_RULE_TYPE_PAYLOAD,
+ FLOW_STAT_RULE_TYPE_IPV6_FLOW_LABEL,
+ };
+
+ CFlowStatRuleMgr();
+ friend std::ostream& operator<<(std::ostream& os, const CFlowStatRuleMgr& cf);
+ int add_stream(const TrexStream * stream);
+ int del_stream(const TrexStream * stream);
+ int start_stream(TrexStream * stream);
+ int stop_stream(const TrexStream * stream);
+ bool dump_json(std::string & json);
+
+ private:
+ int compile_stream(const TrexStream * stream, Cxl710Parser &parser);
+ int add_hw_rule(uint16_t hw_id, uint8_t proto);
+
+ private:
+ class CFlowStatHwIdMap m_hw_id_map; // map hw ids to user ids
+ class CFlowStatUserIdMap m_user_id_map; // map user ids to hw ids
+ uint8_t m_num_ports; // How many ports are being used
+ const TrexPlatformApi *m_api;
+};
+
+#endif
diff --git a/src/flow_stat_parser.cpp b/src/flow_stat_parser.cpp
new file mode 100644
index 00000000..52824f73
--- /dev/null
+++ b/src/flow_stat_parser.cpp
@@ -0,0 +1,137 @@
+/*
+ Ido Barnea
+ Cisco Systems, Inc.
+*/
+
+/*
+ Copyright (c) 2016-2016 Cisco Systems, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include <common/basic_utils.h>
+#include <common/Network/Packet/IPHeader.h>
+#include <common/Network/Packet/IPv6Header.h>
+#include <common/Network/Packet/EthernetHeader.h>
+#include <flow_stat_parser.h>
+
+Cxl710Parser::Cxl710Parser() {
+ reset();
+}
+
+void Cxl710Parser::reset() {
+ m_ipv4 = 0;
+ m_l4_proto = 0;
+ m_fdir_supported = false;
+}
+
+int Cxl710Parser::parse(uint8_t *p, uint16_t len) {
+ EthernetHeader *ether = (EthernetHeader *)p;
+
+ switch( ether->getNextProtocol() ) {
+ case EthernetHeader::Protocol::IP :
+ m_ipv4 = (IPHeader *)(p + 14);
+ m_fdir_supported = true;
+ break;
+ case EthernetHeader::Protocol::VLAN :
+ switch ( ether->getVlanProtocol() ){
+ case EthernetHeader::Protocol::IP:
+ m_ipv4 = (IPHeader *)(p + 18);
+ m_fdir_supported = true;
+ break;
+ default:
+ m_fdir_supported = false;
+ return -1;
+ }
+
+ break;
+ default:
+ m_fdir_supported = false;
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+int Cxl710Parser::get_ip_id(uint16_t &ip_id) {
+ if (! m_ipv4)
+ return -1;
+
+ ip_id = m_ipv4->getId();
+
+ return 0;
+}
+
+int Cxl710Parser::set_ip_id(uint16_t new_id) {
+ if (! m_ipv4)
+ return -1;
+
+ // Updating checksum, not recalculating, so if someone put bad checksum on purpose, it will stay bad
+ m_ipv4->updateCheckSum(m_ipv4->getId(), PKT_NTOHS(new_id));
+ m_ipv4->setId(new_id);
+
+ return 0;
+}
+
+int Cxl710Parser::get_l4_proto(uint8_t &proto) {
+ if (! m_ipv4)
+ return -1;
+
+ proto = m_ipv4->getProtocol();
+
+ return 0;
+}
+
+static const uint16_t TEST_IP_ID = 0xabcd;
+static const uint8_t TEST_L4_PROTO = 0x11;
+
+int Cxl710Parser::test() {
+ uint16_t ip_id = 0;
+ uint8_t l4_proto;
+ uint8_t test_pkt[] = {
+ // ether header
+ 0x74, 0xa2, 0xe6, 0xd5, 0x39, 0x25,
+ 0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02,
+ 0x81, 0x00,
+ 0x0a, 0xbc, 0x08, 0x00, // vlan
+ // IP header
+ 0x45,0x02,0x00,0x30,
+ 0x00,0x00,0x40,0x00,
+ 0xff, TEST_L4_PROTO, 0xbd,0x04,
+ 0x10,0x0,0x0,0x1,
+ 0x30,0x0,0x0,0x1,
+ };
+
+ // good packet
+ assert (parse(test_pkt, sizeof(test_pkt)) == 0);
+ m_ipv4->updateCheckSum();
+ assert(m_ipv4->isChecksumOK() == true);
+ set_ip_id(TEST_IP_ID);
+ // utl_DumpBuffer(stdout, test_pkt, sizeof(test_pkt), 0);
+ get_ip_id(ip_id);
+ assert(ip_id == TEST_IP_ID);
+ assert(m_ipv4->isChecksumOK() == true);
+ assert(get_l4_proto(l4_proto) == 0);
+ assert(l4_proto == TEST_L4_PROTO);
+ assert(m_fdir_supported == true);
+
+ reset();
+
+ // bad packet
+ test_pkt[16] = 0xaa;
+ assert (parse(test_pkt, sizeof(test_pkt)) == -1);
+ assert(m_fdir_supported == false);
+
+ return 0;
+}
diff --git a/src/flow_stat_parser.h b/src/flow_stat_parser.h
new file mode 100644
index 00000000..606a1bec
--- /dev/null
+++ b/src/flow_stat_parser.h
@@ -0,0 +1,37 @@
+/*
+ Ido Barnea
+ Cisco Systems, Inc.
+*/
+
+/*
+ Copyright (c) 2016-2016 Cisco Systems, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+class Cxl710Parser {
+ public:
+ Cxl710Parser();
+ void reset();
+ int parse(uint8_t *pkt, uint16_t len);
+ bool is_fdir_supported() {return m_fdir_supported == true;};
+ int get_ip_id(uint16_t &ip_id);
+ int set_ip_id(uint16_t ip_id);
+ int get_l4_proto(uint8_t &proto);
+ int test();
+
+ private:
+ IPHeader *m_ipv4;
+ bool m_fdir_supported;
+ uint8_t m_l4_proto;
+};
diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp
index 576f7d6e..e946f5d5 100644
--- a/src/gtest/trex_stateless_gtest.cpp
+++ b/src/gtest/trex_stateless_gtest.cpp
@@ -20,6 +20,7 @@ limitations under the License.
*/
#include "bp_sim.h"
+#include "flow_stat_parser.h"
#include <common/gtest.h>
#include <common/basic_utils.h>
#include <trex_stateless.h>
@@ -3570,3 +3571,18 @@ TEST_F(basic_stl, vm_split_client_var) {
}
/********************************************* Itay Tests End *************************************/
+class rx_stat_pkt_parse : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+ virtual void TearDown() {
+ }
+ public:
+};
+
+
+TEST_F(rx_stat_pkt_parse, x710_parser) {
+ Cxl710Parser parser;
+
+ parser.test();
+}
diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h
index f8bc10d5..831fd778 100644
--- a/src/internal_api/trex_platform_api.h
+++ b/src/internal_api/trex_platform_api.h
@@ -31,6 +31,7 @@ limitations under the License.
*
* @author imarom (06-Oct-15)
*/
+
class TrexPlatformGlobalStats {
public:
TrexPlatformGlobalStats() {
@@ -98,7 +99,12 @@ public:
class TrexPlatformApi {
public:
-
+ enum driver_stat_capabilities_e {
+ IF_STAT_IPV4_ID = 1,
+ IF_STAT_PAYLOAD = 2,
+ IF_STAT_IPV6_FLOW_LABEL = 4,
+ };
+
enum driver_speed_e {
SPEED_INVALID,
SPEED_1G,
@@ -109,9 +115,18 @@ public:
virtual void port_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list) const = 0;
virtual void get_global_stats(TrexPlatformGlobalStats &stats) const = 0;
virtual void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const = 0;
- virtual void get_interface_info(uint8_t interface_id, std::string &driver_name, driver_speed_e &speed) const = 0;
+
+ virtual void get_interface_info(uint8_t interface_id, std::string &driver_name,
+ driver_speed_e &speed,
+ bool &has_crc) const = 0;
+
virtual void publish_async_data_now(uint32_t key) 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 int get_rx_stats(uint8_t port_id, uint64_t *stats, int index, bool reset) const = 0;
+ virtual void get_port_num(uint8_t &port_num) const = 0;
+ virtual int add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const = 0;
+ virtual int del_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const = 0;
virtual ~TrexPlatformApi() {}
};
@@ -127,10 +142,19 @@ public:
void port_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list) const;
void get_global_stats(TrexPlatformGlobalStats &stats) const;
void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const;
- void get_interface_info(uint8_t interface_id, std::string &driver_name, driver_speed_e &speed) const;
+
+ void get_interface_info(uint8_t interface_id,
+ std::string &driver_name,
+ driver_speed_e &speed,
+ bool &has_crc) const;
+
void publish_async_data_now(uint32_t key) 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;
+ int get_rx_stats(uint8_t port_id, uint64_t *stats, int index, bool reset) const;
+ void get_port_num(uint8_t &port_num) const;
+ int add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const;
+ int del_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const;
};
/**
@@ -143,13 +167,24 @@ public:
void port_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list) const;
void get_global_stats(TrexPlatformGlobalStats &stats) const;
void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const;
- void get_interface_info(uint8_t interface_id, std::string &driver_name, driver_speed_e &speed) const {
+
+ void get_interface_info(uint8_t interface_id,
+ std::string &driver_name,
+ driver_speed_e &speed,
+ bool &has_crc) const {
driver_name = "MOCK";
speed = SPEED_INVALID;
+ has_crc = false;
}
void publish_async_data_now(uint32_t key) 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
+ {num_counters = 0; capabilities = 0;}
+ int get_rx_stats(uint8_t port_id, uint64_t *stats, int index, bool reset) const {return 0;}
+ void get_port_num(uint8_t &port_num) const {port_num = 2;};
+ int add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const {return 0;}
+ int del_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const {return 0;}
};
#endif /* __TREX_PLATFORM_API_H__ */
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 701ae13e..8cc94e7d 100755..100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -107,7 +107,7 @@ extern "C" {
typedef struct rte_mbuf * (*rte_mbuf_convert_to_one_seg_t)(struct rte_mbuf *m);
struct rte_mbuf * rte_mbuf_convert_to_one_seg(struct rte_mbuf *m);
-extern "C" int vmxnet3_xmit_set_callback(rte_mbuf_convert_to_one_seg_t cb);
+extern "C" void i40e_set_trex_mode(int mode);
#define RTE_TEST_TX_DESC_DEFAULT 512
#define RTE_TEST_RX_DESC_DROP 0
@@ -127,6 +127,11 @@ public:
virtual TrexPlatformApi::driver_speed_e get_driver_speed(uint8_t port_id) = 0;
+ /* by default NIC driver adds CRC */
+ virtual bool has_crc_added() {
+ return true;
+ }
+
virtual int get_min_sample_rate(void)=0;
virtual void update_configuration(port_cfg_t * cfg)=0;
virtual void update_global_config_fdir(port_cfg_t * cfg)=0;
@@ -135,7 +140,7 @@ public:
return(false);
}
virtual int configure_rx_filter_rules(CPhyEthIF * _if)=0;
-
+ virtual int add_del_rx_flow_stat_rule(uint8_t port_id, enum rte_filter_op op, uint8_t type, uint16_t proto, uint16_t id) {return -1;};
virtual bool is_hardware_support_drop_queue(){
return(false);
}
@@ -146,6 +151,10 @@ public:
virtual int wait_for_stable_link()=0;
virtual void wait_after_link_up(){};
virtual bool flow_control_disable_supported(){return true;}
+ virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *stats, uint32_t *prev_stats, int index) {return -1;}
+ 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;}
};
@@ -176,7 +185,9 @@ public:
virtual int configure_drop_queue(CPhyEthIF * _if);
virtual int configure_rx_filter_rules(CPhyEthIF * _if);
-
+ int configure_rx_filter_rules_statefull(CPhyEthIF * _if);
+ int configure_rx_filter_rules_stateless(CPhyEthIF * _if);
+
virtual bool is_hardware_support_drop_queue(){
return(true);
}
@@ -201,6 +212,10 @@ public:
return TrexPlatformApi::SPEED_1G;
}
+ virtual bool has_crc_added() {
+ return false;
+ }
+
static CTRexExtendedDriverBase * create(){
return ( new CTRexExtendedDriverBase1GVm() );
}
@@ -272,6 +287,10 @@ public:
class CTRexExtendedDriverBase40G : public CTRexExtendedDriverBase10G {
public:
CTRexExtendedDriverBase40G(){
+ // Since we support only 128 counters per if, it is OK to configure here 4 statically.
+ // If we want to support more counters in case in case of card having less interfaces, we
+ // Will have to identify the number of interfaces dynamically.
+ m_if_per_card = 4;
}
TrexPlatformApi::driver_speed_e get_driver_speed(uint8_t port_id) {
@@ -295,7 +314,7 @@ public:
virtual void update_configuration(port_cfg_t * cfg);
virtual int configure_rx_filter_rules(CPhyEthIF * _if);
-
+ virtual int add_del_rx_flow_stat_rule(uint8_t port_id, enum rte_filter_op op, uint8_t type, uint16_t proto, uint16_t id);
virtual bool is_hardware_filter_is_supported(){
return (true);
}
@@ -305,13 +324,18 @@ public:
}
virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
virtual void clear_extended_stats(CPhyEthIF * _if);
+ int get_rx_stats(CPhyEthIF * _if, uint32_t *stats, uint32_t *prev_stats, int index);
+ int dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd);
+ int get_stat_counters_num() {return TREX_FDIR_STAT_SIZE;}
+ int get_rx_stat_capabilities() {return TrexPlatformApi::IF_STAT_IPV4_ID;}
virtual int wait_for_stable_link();
// disabling flow control on 40G using DPDK API causes the interface to malfunction
bool flow_control_disable_supported(){return false;}
+private:
+ void add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint8_t ttl, uint16_t ip_id, int queue, uint16_t stat_idx);
+ virtual int configure_rx_filter_rules_statfull(CPhyEthIF * _if);
private:
- void add_rules(CPhyEthIF * _if,
- uint16_t type,
- uint8_t ttl);
+ uint8_t m_if_per_card;
};
class CTRexExtendedDriverBaseVIC : public CTRexExtendedDriverBase40G {
@@ -330,7 +354,6 @@ public:
bool flow_control_disable_supported(){return false;}
virtual void update_configuration(port_cfg_t * cfg);
-
};
@@ -1168,20 +1191,18 @@ typedef struct cnt_name_ {
#define MY_REG(a) {a,(char *)#a}
void CPhyEthIFStats::Clear(){
-
- ipackets =0;
- ibytes =0 ;
-
- f_ipackets=0;
- f_ibytes=0;
-
- opackets=0;
- obytes=0;
-
- ierrors=0;
- oerrors=0;
- imcasts=0;
- rx_nombuf=0;
+ ipackets = 0;
+ ibytes = 0;
+ f_ipackets = 0;
+ f_ibytes = 0;
+ opackets = 0;
+ obytes = 0;
+ ierrors = 0;
+ oerrors = 0;
+ imcasts = 0;
+ rx_nombuf = 0;
+ memset(m_rx_per_flow, 0, sizeof(m_rx_per_flow));
+ m_fdir_stats_first_time = true;
}
@@ -1280,18 +1301,21 @@ void CPhyEthIF::dump_stats_extended(FILE *fd){
MY_REG(IXGBE_FDIRMISS )
};
- fprintf (fd," externded counter \n");
+ fprintf (fd," extended counters \n");
int i;
for (i=0; i<sizeof(reg)/sizeof(reg[0]); i++) {
cnt_name_t *lp=&reg[i];
uint32_t c=pci_reg_read(lp->offset);
- if (c) {
+ // xl710 bug. Counter values are -559038737 when they should be 0
+ if (c && c != -559038737 ) {
fprintf (fd," %s : %d \n",lp->name,c);
}
}
}
-
+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,
@@ -1542,16 +1566,55 @@ void CPhyEthIF::get_stats_1g(CPhyEthIFStats *stats){
}
-void CPhyEthIF::get_stats(CPhyEthIFStats *stats){
+int CPhyEthIF::dump_fdir_global_stats(FILE *fd) {
+ return get_ex_drv()->dump_fdir_global_stats(this, fd);
+}
- get_ex_drv()->get_extended_stats(this,stats);
+// get/reset flow director counters
+// return 0 if OK. -1 if operation not supported.
+// stats - If not NULL, returning counter numbers in it.
+// index - If non negative, get only counter with this index
+// reset - If true, reset counter value after reading
+int CPhyEthIF::get_rx_stats(uint64_t *stats, int index, bool reset) {
+ uint32_t diff_stats[TREX_FDIR_STAT_SIZE];
+ int start, len;
- m_last_tx_rate = m_bw_tx.add(stats->obytes);
- m_last_rx_rate = m_bw_rx.add(stats->ibytes);
- m_last_tx_pps = m_pps_tx.add(stats->opackets);
- m_last_rx_pps = m_pps_rx.add(stats->ipackets);
-}
+ if (index >= 0) {
+ start = index;
+ len = 1;
+ } else {
+ start = 0;
+ len = TREX_FDIR_STAT_SIZE;
+ }
+
+ if (get_ex_drv()->get_rx_stats(this, diff_stats, m_stats.m_fdir_prev_stats, index) < 0) {
+ return -1;
+ }
+ // First time, just syncing the counters
+ if (m_stats.m_fdir_stats_first_time) {
+ m_stats.m_fdir_stats_first_time = false;
+ if (stats) {
+ memset(stats, 0, sizeof(uint64_t) * TREX_FDIR_STAT_SIZE);
+ }
+ return 0;
+ }
+
+ for (int i = start; i < (start + len); i++) {
+ if ( reset ) {
+ // return value so far, and reset
+ stats[i] = m_stats.m_rx_per_flow[i] + diff_stats[i];
+ m_stats.m_rx_per_flow[i] = 0;
+ } else {
+ m_stats.m_rx_per_flow[i] += diff_stats[i];
+ if (stats != NULL) {
+ stats[i] = m_stats.m_rx_per_flow[i];
+ }
+ }
+ }
+
+ return 0;
+}
void dump_hw_state(FILE *fd,struct ixgbe_hw_stats *hs ){
@@ -1642,7 +1705,12 @@ void dump_hw_state(FILE *fd,struct ixgbe_hw_stats *hs ){
void CPhyEthIF::update_counters(){
- get_stats(&m_stats);
+ get_ex_drv()->get_extended_stats(this, &m_stats);
+
+ m_last_tx_rate = m_bw_tx.add(m_stats.obytes);
+ m_last_rx_rate = m_bw_rx.add(m_stats.ibytes);
+ m_last_tx_pps = m_pps_tx.add(m_stats.opackets);
+ m_last_rx_pps = m_pps_rx.add(m_stats.ipackets);
}
void CPhyEthIF::dump_stats(FILE *fd){
@@ -2579,7 +2647,7 @@ private:
void check_for_dp_messages();
public:
- int start_send_master();
+ int start_master_statefull();
int start_master_stateless();
int run_in_core(virtual_thread_id_t virt_core_id);
int stop_core(virtual_thread_id_t virt_core_id);
@@ -3530,9 +3598,10 @@ CGlobalTRex::publish_async_data() {
m_mg.dump_json_v2(json );
m_zmq_publisher.publish_json(json);
- /* stateless info - nothing for now */
- //m_trex_stateless->generate_publish_snapshot(json);
- //m_zmq_publisher.publish_json(json);
+ if (get_is_stateless()) {
+ if (m_trex_stateless->m_rx_flow_stat.dump_json(json))
+ m_zmq_publisher.publish_json(json);
+ }
}
void
@@ -3795,10 +3864,7 @@ int CGlobalTRex::start_master_stateless(){
return (0);
}
-
-
-
-int CGlobalTRex::start_send_master(){
+int CGlobalTRex::start_master_statefull() {
int i;
for (i=0; i<BP_MAX_CORES; i++) {
m_signal[i]=0;
@@ -4235,7 +4301,8 @@ int main_test(int argc , char * argv[]){
return (-1);
}
-
+ // We init i40e fdir registers differently in case of stateless. Must set this before rte_eal_init which initiates the registers
+ i40e_set_trex_mode(get_is_stateless() ? 1:0 );
ret = rte_eal_init(global_dpdk_args_num, (char **)global_dpdk_args);
if (ret < 0){
@@ -4279,7 +4346,7 @@ int main_test(int argc , char * argv[]){
g_trex.start_master_stateless();
}else{
- g_trex.start_send_master();
+ g_trex.start_master_statefull();
}
if (CGlobalInfo::m_options.m_debug_pkt_proto != 0) {
@@ -4369,8 +4436,18 @@ int CTRexExtendedDriverBase1G::configure_drop_queue(CPhyEthIF * _if) {
return 0;
}
+
int CTRexExtendedDriverBase1G::configure_rx_filter_rules(CPhyEthIF * _if){
+ if ( get_is_stateless() ) {
+ return configure_rx_filter_rules_stateless(_if);
+ } else {
+ return configure_rx_filter_rules_statefull(_if);
+ }
+ return 0;
+}
+
+int CTRexExtendedDriverBase1G::configure_rx_filter_rules_statefull(CPhyEthIF * _if) {
uint16_t hops = get_rx_check_hops();
uint16_t v4_hops = (hops << 8)&0xff00;
uint8_t protocol;
@@ -4462,6 +4539,54 @@ int CTRexExtendedDriverBase1G::configure_rx_filter_rules(CPhyEthIF * _if){
return (0);
}
+// Sadly, DPDK has no support for i350 filters, so we need to implement by writing to registers.
+int CTRexExtendedDriverBase1G::configure_rx_filter_rules_stateless(CPhyEthIF * _if) {
+ /* enable filter to pass packet to rx queue 1 */
+ _if->pci_reg_write( E1000_IMIR(0), 0x00020000);
+ _if->pci_reg_write( E1000_IMIREXT(0), 0x00081000);
+
+ uint8_t len = 24;
+ uint32_t mask = 0x1 | 0x2; // first two rules
+ int rule_id;
+
+ // clear rules 0, 1 registers
+ for (rule_id = 0 ; rule_id < 2; rule_id++) {
+ for (int i=0; i<0xff; i+=4) {
+ _if->pci_reg_write( (E1000_FHFT(rule_id)+i) , 0);
+ }
+ }
+
+ rule_id = 0;
+ // filter for byte 18 of packet (lsb of IP ID) should equal ff
+ _if->pci_reg_write( (E1000_FHFT(rule_id)+(2*16)) , 0x00ff0000);
+ _if->pci_reg_write( (E1000_FHFT(rule_id)+(2*16) + 8) , 0x04); /* MASK */
+ // + bytes 12 + 13 (ether type) should indicate IP.
+ _if->pci_reg_write( (E1000_FHFT(rule_id)+(1*16) + 4) , 0x00000008);
+ _if->pci_reg_write( (E1000_FHFT(rule_id)+(1*16) + 8) , 0x30); /* MASK */
+ // FLEX_PRIO[[18:16] = 1, RQUEUE[10:8] = 1
+ _if->pci_reg_write( (E1000_FHFT(rule_id) + 0xFC) , (1 << 16) | (1 << 8) | len);
+
+ // same like 0, but with vlan. type should be vlan. Inside vlan, should be IP with lsb of IP ID equals 0xff
+ rule_id = 1;
+ // filter for byte 22 of packet (msb of IP ID) should equal ff
+ _if->pci_reg_write( (E1000_FHFT(rule_id)+(2*16) + 4) , 0x00ff0000);
+ _if->pci_reg_write( (E1000_FHFT(rule_id)+(2*16) + 8) , 0x40 | 0x03); /* MASK */
+ // + bytes 12 + 13 (ether type) should indicate VLAN.
+ _if->pci_reg_write( (E1000_FHFT(rule_id)+(1*16) + 4) , 0x00000081);
+ _if->pci_reg_write( (E1000_FHFT(rule_id)+(1*16) + 8) , 0x30); /* MASK */
+ // + bytes 16 + 17 (vlan type) should indicate IP.
+ _if->pci_reg_write( (E1000_FHFT(rule_id)+(2*16) ) , 0x00000080);
+ // Was written together with IP ID filter
+ // _if->pci_reg_write( (E1000_FHFT(rule_id)+(2*16) + 8) , 0x03); /* MASK */
+ // FLEX_PRIO[[18:16] = 1, RQUEUE[10:8] = 1
+ _if->pci_reg_write( (E1000_FHFT(rule_id) + 0xFC) , (1 << 16) | (1 << 8) | len);
+
+ /* enable rules */
+ _if->pci_reg_write(E1000_WUFC, (mask << 16) | (1 << 14) );
+
+ return (0);
+}
+
void CTRexExtendedDriverBase1G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){
@@ -4632,15 +4757,10 @@ int CTRexExtendedDriverBase10G::wait_for_stable_link(){
}
////////////////////////////////////////////////////////////////////////////////
-
-
void CTRexExtendedDriverBase40G::clear_extended_stats(CPhyEthIF * _if){
-
rte_eth_stats_reset(_if->get_port_id());
-
}
-
void CTRexExtendedDriverBaseVIC::update_configuration(port_cfg_t * cfg){
cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH;
cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH;
@@ -4655,15 +4775,14 @@ void CTRexExtendedDriverBase40G::update_configuration(port_cfg_t * cfg){
cfg->update_global_config_fdir_40g();
}
-
/* Add rule to send packets with protocol 'type', and ttl 'ttl' to rx queue 1 */
-void CTRexExtendedDriverBase40G::add_rules(CPhyEthIF * _if,
- uint16_t type,
- uint8_t ttl){
- uint8_t port_id = _if->get_port_id();
+// ttl is used in statefull mode, and ip_id in stateless. We configure the driver registers so that only one of them applies.
+// So, the rule will apply if packet has either the correct ttl or IP ID, depending if we are in statfull or stateless.
+void CTRexExtendedDriverBase40G::add_del_rules(enum rte_filter_op op, uint8_t port_id, uint16_t type, uint8_t ttl, uint16_t ip_id, int queue, uint16_t stat_idx) {
int ret=rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
+ static int filter_soft_id = 0;
- if ( ret !=0 ){
+ if ( ret != 0 ){
rte_exit(EXIT_FAILURE, "rte_eth_dev_filter_supported "
"err=%d, port=%u \n",
ret, port_id);
@@ -4673,21 +4792,29 @@ void CTRexExtendedDriverBase40G::add_rules(CPhyEthIF * _if,
memset(&filter,0,sizeof(struct rte_eth_fdir_filter));
- filter.action.rx_queue =1;
+#if 0
+ printf("40g::%s rules: port:%d, type:%d ttl:%d, ip_id:%x, q:%d hw index:%d\n", (op == RTE_ETH_FILTER_ADD) ? "add" : "del"
+ , port_id, type, ttl, ip_id, queue, stat_idx);
+#endif
+
+ filter.action.rx_queue = queue;
filter.action.behavior =RTE_ETH_FDIR_ACCEPT;
filter.action.report_status =RTE_ETH_FDIR_NO_REPORT_STATUS;
- filter.soft_id=0;
-
+ filter.action.stat_count_index = stat_idx;
+ filter.soft_id = filter_soft_id++;
filter.input.flow_type = type;
+
switch (type) {
case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
filter.input.flow.ip4_flow.ttl=ttl;
+ filter.input.flow.ip4_flow.ip_id = ip_id;
filter.input.flow.ip4_flow.l4_protocol = IPPROTO_ICMP; // In this case we want filter for icmp packets
break;
case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP:
filter.input.flow.ip4_flow.ttl=ttl;
+ filter.input.flow.ip4_flow.ip_id = ip_id;
break;
case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
@@ -4699,9 +4826,8 @@ void CTRexExtendedDriverBase40G::add_rules(CPhyEthIF * _if,
break;
}
- /* We want to place latency packets in queue 1 */
ret=rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR,
- RTE_ETH_FILTER_ADD, (void*)&filter);
+ op, (void*)&filter);
if ( ret !=0 ){
rte_exit(EXIT_FAILURE, "rte_eth_dev_filter_ctrl"
@@ -4710,25 +4836,107 @@ void CTRexExtendedDriverBase40G::add_rules(CPhyEthIF * _if,
}
}
+// 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..TREX_FDIR_STAT_SIZE
+int CTRexExtendedDriverBase40G::add_del_rx_flow_stat_rule(uint8_t port_id, enum rte_filter_op op, uint8_t type, uint16_t proto, uint16_t id) {
+ uint32_t rule_id = (port_id % m_if_per_card) * TREX_FDIR_STAT_SIZE + id;
+ uint16_t rte_type = RTE_ETH_FLOW_NONFRAG_IPV4_OTHER;
+
+ switch(proto) {
+ case IPPROTO_TCP:
+ rte_type = RTE_ETH_FLOW_NONFRAG_IPV4_TCP;
+ break;
+ case IPPROTO_UDP:
+ rte_type = RTE_ETH_FLOW_NONFRAG_IPV4_UDP;
+ break;
+ default:
+ rte_type = RTE_ETH_FLOW_NONFRAG_IPV4_OTHER;
+ break;
+ }
+ add_del_rules(op, port_id, rte_type, 0, IP_ID_RESERVE_BASE + id, MAIN_DPDK_DATA_Q, rule_id);
+ return 0;
+}
-int CTRexExtendedDriverBase40G::configure_rx_filter_rules(CPhyEthIF * _if){
+int CTRexExtendedDriverBase40G::configure_rx_filter_rules_statfull(CPhyEthIF * _if) {
+ uint32_t port_id = _if->get_port_id();
uint16_t hops = get_rx_check_hops();
int i;
- for (i=0; i<2; i++) {
- uint8_t ttl=0xff-i-hops;
- add_rules(_if,RTE_ETH_FLOW_NONFRAG_IPV4_UDP, ttl);
- add_rules(_if,RTE_ETH_FLOW_NONFRAG_IPV4_TCP, ttl);
- add_rules(_if,RTE_ETH_FLOW_NONFRAG_IPV6_UDP, ttl);
- add_rules(_if,RTE_ETH_FLOW_NONFRAG_IPV6_TCP, ttl);
+
+ for (i = 0; i < 2; i++) {
+ uint8_t ttl = TTL_RESERVE_DUPLICATE - i - hops;
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, ttl, 0, MAIN_DPDK_RX_Q, 0);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_TCP, ttl, 0, MAIN_DPDK_RX_Q, 0);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, ttl, 0, MAIN_DPDK_RX_Q, 0);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV6_TCP, ttl, 0, MAIN_DPDK_RX_Q, 0);
}
- /* Configure queue for latency packets */
- add_rules(_if,RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, 255);
- add_rules(_if,RTE_ETH_FLOW_NONFRAG_IPV4_SCTP, 255);
+ /* Configure rules for latency measurement packets */
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, TTL_RESERVE_DUPLICATE - hops, 0, MAIN_DPDK_RX_Q, 0);
+ add_del_rules(RTE_ETH_FILTER_ADD, port_id, RTE_ETH_FLOW_NONFRAG_IPV4_SCTP, TTL_RESERVE_DUPLICATE - hops, 0, MAIN_DPDK_RX_Q, 0);
- return (0);
+ return 0;
+}
+
+int CTRexExtendedDriverBase40G::configure_rx_filter_rules(CPhyEthIF * _if) {
+ if (get_is_stateless()) {
+ return 0; // Rules are configured dynamically in stateless
+ } else {
+ return configure_rx_filter_rules_statfull(_if);
+ }
+}
+
+// instead of adding this to rte_ethdev.h
+extern "C" int rte_eth_fdir_stats_get(uint8_t port_id, uint32_t *stats, uint32_t start, uint32_t len);
+int CTRexExtendedDriverBase40G::get_rx_stats(CPhyEthIF * _if, uint32_t *stats, uint32_t *prev_stats, int index) {
+ uint32_t hw_stats[TREX_FDIR_STAT_SIZE];
+ uint32_t port_id = _if->get_port_id();
+ uint32_t len, start, loop_start;
+
+ if (index >= 0) {
+ len = 1;
+ start = (port_id % m_if_per_card) * TREX_FDIR_STAT_SIZE + index;
+ loop_start = index;
+ } else {
+ start = (port_id % m_if_per_card) * TREX_FDIR_STAT_SIZE;
+ len = TREX_FDIR_STAT_SIZE;
+ loop_start = 0;
+ }
+
+ rte_eth_fdir_stats_get(port_id, hw_stats, start, len);
+ for (int i = loop_start; i < loop_start + len; i++) {
+ if (hw_stats[i] >= prev_stats[i]) {
+ stats[i] = (uint64_t)(hw_stats[i] - prev_stats[i]);
+ } else {
+ // Wrap around
+ stats[i] = (uint64_t)((hw_stats[i] + ((uint64_t)1 << 32)) - prev_stats[i]);
+ }
+ prev_stats[i] = hw_stats[i];
+ }
+
+ return 0;
}
+// if fd != NULL, dump fdir stats of _if
+// return num of filters
+int CTRexExtendedDriverBase40G::dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd)
+{
+ uint32_t port_id = _if->get_port_id();
+ struct rte_eth_fdir_stats stat;
+ int ret;
+
+ ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR, RTE_ETH_FILTER_STATS, (void*)&stat);
+ if (ret == 0) {
+ if (fd)
+ fprintf(fd, "Num filters on guarant poll:%d, best effort poll:%d\n", stat.guarant_cnt, stat.best_cnt);
+ return (stat.guarant_cnt + stat.best_cnt);
+ } else {
+ if (fd)
+ fprintf(fd, "Failed reading fdir statistics\n");
+ return -1;
+ }
+}
+
void CTRexExtendedDriverBase40G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){
struct rte_eth_stats stats1;
@@ -4872,12 +5080,15 @@ struct rte_mbuf * rte_mbuf_convert_to_one_seg(struct rte_mbuf *m){
return(r);
}
-
/***********************************************************
* platfrom API object
* TODO: REMOVE THIS TO A SEPERATE FILE
*
**********************************************************/
+void TrexDpdkPlatformApi::get_port_num(uint8_t &port_num) const {
+ port_num = g_trex.m_max_ports;
+}
+
void
TrexDpdkPlatformApi::get_global_stats(TrexPlatformGlobalStats &stats) const {
CGlobalStats trex_stats;
@@ -4927,10 +5138,12 @@ TrexDpdkPlatformApi::port_id_to_cores(uint8_t port_id, std::vector<std::pair<uin
void
TrexDpdkPlatformApi::get_interface_info(uint8_t port_id,
std::string &driver_name,
- driver_speed_e &speed) const {
+ driver_speed_e &speed,
+ bool &has_crc) const {
driver_name = CTRexExtendedDriverDb::Ins()->get_driver_name();
- speed = CTRexExtendedDriverDb::Ins()->get_drv()->get_driver_speed(port_id);
+ speed = CTRexExtendedDriverDb::Ins()->get_drv()->get_driver_speed(port_id);
+ has_crc = CTRexExtendedDriverDb::Ins()->get_drv()->has_crc_added();
}
void
@@ -4939,3 +5152,22 @@ TrexDpdkPlatformApi::publish_async_data_now(uint32_t key) const {
g_trex.publish_async_barrier(key);
}
+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();
+}
+
+int TrexDpdkPlatformApi::get_rx_stats(uint8 port_id, uint64_t *stats, int index, bool reset) const {
+ return g_trex.m_ports[port_id].get_rx_stats(stats, index, reset);
+}
+
+int TrexDpdkPlatformApi::add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const {
+ return CTRexExtendedDriverDb::Ins()->get_drv()
+ ->add_del_rx_flow_stat_rule(port_id, RTE_ETH_FILTER_ADD, type, proto, id);
+}
+
+int TrexDpdkPlatformApi::del_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const {
+ return CTRexExtendedDriverDb::Ins()->get_drv()
+ ->add_del_rx_flow_stat_rule(port_id, RTE_ETH_FILTER_DELETE, type, proto, id);
+}
diff --git a/src/main_dpdk.h b/src/main_dpdk.h
index e2c0cdb2..7357c0f4 100644
--- a/src/main_dpdk.h
+++ b/src/main_dpdk.h
@@ -1,27 +1,33 @@
/*
-Copyright (c) 2015-2016 Cisco Systems, Inc.
+ Copyright (c) 2015-2016 Cisco Systems, Inc.
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
*/
#ifndef MAIN_DPDK_H
#define MAIN_DPDK_H
+#include <rte_ethdev.h>
#include "bp_sim.h"
+enum {
+ MAIN_DPDK_DATA_Q = 0,
+ MAIN_DPDK_RX_Q = 1,
+};
+
class CPhyEthIFStats {
-public:
+ public:
uint64_t ipackets; /**< Total number of successfully received packets. */
uint64_t ibytes; /**< Total number of successfully received bytes. */
uint64_t f_ipackets; /**< Total number of successfully received packets - filter SCTP*/
@@ -32,18 +38,22 @@ public:
uint64_t oerrors; /**< Total number of failed transmitted packets. */
uint64_t imcasts; /**< Total number of multicast received packets. */
uint64_t rx_nombuf; /**< Total number of RX mbuf allocation failures. */
-
-public:
+ uint64_t m_rx_per_flow [TREX_FDIR_STAT_SIZE]; // Per flow RX statistics
+ // Previous fdir stats values read from HW. Since on xl710 this is 32 bit, we save old value, to handle wrap around.
+ uint32_t m_fdir_prev_stats [TREX_FDIR_STAT_SIZE];
+ bool m_fdir_stats_first_time;
+ public:
void Clear();
void Dump(FILE *fd);
void DumpAll(FILE *fd);
};
class CPhyEthIF {
-public:
+ public:
CPhyEthIF (){
m_port_id=0;
m_rx_queue=0;
+ m_stats.m_fdir_stats_first_time = true;
}
bool Create(uint8_t portid){
m_port_id = portid;
@@ -59,18 +69,20 @@ public:
}
void configure(uint16_t nb_rx_queue,
- uint16_t nb_tx_queue,
- const struct rte_eth_conf *eth_conf);
+ uint16_t nb_tx_queue,
+ const struct rte_eth_conf *eth_conf);
void macaddr_get(struct ether_addr *mac_addr);
void get_stats(CPhyEthIFStats *stats);
+ int dump_fdir_global_stats(FILE *fd);
+ int get_rx_stats(uint64_t *stats, int index, bool reset);
void get_stats_1g(CPhyEthIFStats *stats);
void rx_queue_setup(uint16_t rx_queue_id,
- uint16_t nb_rx_desc,
+ uint16_t nb_rx_desc,
unsigned int socket_id,
const struct rte_eth_rxconf *rx_conf,
struct rte_mempool *mb_pool);
void tx_queue_setup(uint16_t tx_queue_id,
- uint16_t nb_tx_desc,
+ uint16_t nb_tx_desc,
unsigned int socket_id,
const struct rte_eth_txconf *tx_conf);
void configure_rx_drop_queue();
@@ -90,7 +102,7 @@ public:
void update_counters();
void stats_clear();
uint8_t get_port_id(){
- return (m_port_id);
+ return (m_port_id);
}
float get_last_tx_rate(){
return (m_last_tx_rate);
@@ -105,11 +117,11 @@ public:
return (m_last_rx_pps);
}
CPhyEthIFStats & get_stats(){
- return ( m_stats );
+ return ( m_stats );
}
void flush_rx_queue(void);
-
-public:
+ int add_rx_flow_stat_rule(uint8_t type, uint16_t proto, uint16_t id);
+ int del_rx_flow_stat_rule(uint8_t type, uint16_t proto, uint16_t id);
inline uint16_t tx_burst(uint16_t queue_id, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) {
return rte_eth_tx_burst(m_port_id, queue_id, tx_pkts, nb_pkts);
}
@@ -117,26 +129,27 @@ public:
return rte_eth_rx_burst(m_port_id, queue_id, rx_pkts, nb_pkts);
}
inline uint32_t pci_reg_read(uint32_t reg_off) {
- void *reg_addr;
- uint32_t reg_v;
- reg_addr = (void *)((char *)m_dev_info.pci_dev->mem_resource[0].addr +
- reg_off);
+ void *reg_addr;
+ uint32_t reg_v;
+ reg_addr = (void *)((char *)m_dev_info.pci_dev->mem_resource[0].addr +
+ reg_off);
reg_v = *((volatile uint32_t *)reg_addr);
return rte_le_to_cpu_32(reg_v);
}
- inline void pci_reg_write(uint32_t reg_off,
+ inline void pci_reg_write(uint32_t reg_off,
uint32_t reg_v) {
- void *reg_addr;
-
- reg_addr = (void *)((char *)m_dev_info.pci_dev->mem_resource[0].addr +
- reg_off);
- *((volatile uint32_t *)reg_addr) = rte_cpu_to_le_32(reg_v);
+ void *reg_addr;
+
+ reg_addr = (void *)((char *)m_dev_info.pci_dev->mem_resource[0].addr +
+ reg_off);
+ *((volatile uint32_t *)reg_addr) = rte_cpu_to_le_32(reg_v);
}
void dump_stats_extended(FILE *fd);
uint8_t get_rte_port_id(void) {
- return m_port_id;
+ return m_port_id;
}
-private:
+ int get_rx_stat_capabilities();
+ private:
uint8_t m_port_id;
uint8_t m_rx_queue;
struct rte_eth_link m_link;
@@ -151,8 +164,14 @@ private:
float m_last_rx_rate;
float m_last_tx_pps;
float m_last_rx_pps;
-public:
- struct rte_eth_dev_info m_dev_info;
+ public:
+ struct rte_eth_dev_info m_dev_info;
+};
+
+// Because it is difficult to move CGlobalTRex into this h file, defining interface class to it
+class CGlobalTRexInterface {
+ public:
+ CPhyEthIF *get_ports(uint8_t &port_num);
};
#endif
diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
index 93a680c9..d2cb4ce6 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -103,11 +103,11 @@ TrexRpcCmdAddStream::_run(const Json::Value &params, Json::Value &result) {
/* parse RX info */
const Json::Value &rx = parse_object(section, "rx_stats", result);
- stream->m_rx_check.m_enable = parse_bool(rx, "enabled", result);
+ stream->m_rx_check.m_enabled = parse_bool(rx, "enabled", result);
/* if it is enabled - we need more fields */
- if (stream->m_rx_check.m_enable) {
- stream->m_rx_check.m_stream_id = parse_int(rx, "stream_id", result);
+ if (stream->m_rx_check.m_enabled) {
+ stream->m_rx_check.m_user_id = parse_int(rx, "stream_id", result);
stream->m_rx_check.m_seq_enabled = parse_bool(rx, "seq_enabled", result);
stream->m_rx_check.m_latency = parse_bool(rx, "latency_enabled", result);
}
@@ -590,8 +590,6 @@ TrexRpcCmdGetAllStreams::_run(const Json::Value &params, Json::Value &result) {
uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
- bool get_pkt = parse_bool(params, "get_pkt", result);
-
std::vector <TrexStream *> streams;
port->get_object_list(streams);
@@ -600,11 +598,6 @@ TrexRpcCmdGetAllStreams::_run(const Json::Value &params, Json::Value &result) {
Json::Value j = stream->get_stream_json();
- /* should we include the packet as well ? */
- if (!get_pkt) {
- j.removeMember("packet");
- }
-
std::stringstream ss;
ss << stream->m_stream_id;
diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h
index d90d880e..9545e585 100644
--- a/src/rpc-server/commands/trex_rpc_cmds.h
+++ b/src/rpc-server/commands/trex_rpc_cmds.h
@@ -107,7 +107,7 @@ void parse_vm_instr_write_mask_flow_var(const Json::Value &inst, std::unique_ptr
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStreamList, "get_stream_list", 1, false);
-TREX_RPC_CMD_DEFINE(TrexRpcCmdGetAllStreams, "get_all_streams", 2, false);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetAllStreams, "get_all_streams", 1, false);
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStream, "get_stream", 3, false);
diff --git a/src/sim/trex_sim.h b/src/sim/trex_sim.h
index 21498978..6e842eb7 100644
--- a/src/sim/trex_sim.h
+++ b/src/sim/trex_sim.h
@@ -54,13 +54,18 @@ public:
virtual void get_global_stats(TrexPlatformGlobalStats &stats) const {
}
- virtual void get_interface_info(uint8_t interface_id, std::string &driver_name, driver_speed_e &speed) const {
+ virtual void get_interface_info(uint8_t interface_id,
+ std::string &driver_name,
+ driver_speed_e &speed,
+ bool &has_crc) const {
driver_name = "TEST";
speed = TrexPlatformApi::SPEED_10G;
+ has_crc = true;
}
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=0; }
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++) {
@@ -71,6 +76,10 @@ public:
virtual void publish_async_data_now(uint32_t key) const {
}
+ virtual int get_rx_stats(uint8_t port_id, uint64_t *stats, int index, bool reset) const {return 0;}
+ virtual void get_port_num(uint8_t &port_num) const {port_num = 2;};
+ virtual int add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const {return 0;}
+ virtual int del_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const {return 0;}
private:
int m_dp_core_count;
diff --git a/src/sim/trex_sim_stateless.cpp b/src/sim/trex_sim_stateless.cpp
index a8316034..30d60b15 100644
--- a/src/sim/trex_sim_stateless.cpp
+++ b/src/sim/trex_sim_stateless.cpp
@@ -65,7 +65,6 @@ public:
}
};
-
/**
* handler for DP to CP messages
*
diff --git a/src/stateless/cp/trex_stateless.h b/src/stateless/cp/trex_stateless.h
index 59be9241..cc47da6b 100644
--- a/src/stateless/cp/trex_stateless.h
+++ b/src/stateless/cp/trex_stateless.h
@@ -32,6 +32,7 @@ limitations under the License.
#include <trex_rpc_server_api.h>
#include <publisher/trex_publisher.h>
+#include <flow_stat.h>
#include <internal_api/trex_platform_api.h>
/**
@@ -165,6 +166,8 @@ public:
return m_rpc_server;
}
+ CFlowStatRuleMgr m_rx_flow_stat;
+
protected:
/* no copy or assignment */
diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp
index 99b6565c..88c38112 100644
--- a/src/stateless/cp/trex_stateless_port.cpp
+++ b/src/stateless/cp/trex_stateless_port.cpp
@@ -59,7 +59,7 @@ TrexStatelessPort::TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api
m_port_state = PORT_STATE_IDLE;
/* get the platform specific data */
- api->get_interface_info(port_id, m_driver_name, m_speed);
+ api->get_interface_info(port_id, m_driver_name, m_speed, m_has_crc);
/* get the DP cores belonging to this port */
api->port_id_to_cores(m_port_id, core_pair_list);
@@ -179,7 +179,6 @@ TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration,
m_last_duration = duration;
change_state(PORT_STATE_TX);
-
/* update the DP - messages will be freed by the DP */
int index = 0;
for (auto core_id : m_cores_id_list) {
@@ -231,12 +230,32 @@ TrexStatelessPort::stop_traffic(void) {
send_message_to_all_dp(stop_msg);
+ /* continue to general actions */
+ common_port_stop_actions(false);
+
+}
+
+/**
+ * when a port stops, perform various actions
+ *
+ */
+void
+TrexStatelessPort::common_port_stop_actions(bool event_triggered) {
+
change_state(PORT_STATE_STREAMS);
Json::Value data;
data["port_id"] = m_port_id;
- get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_STOPPED, data);
+ if (event_triggered) {
+ get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_STOPPED, data);
+ } else {
+ get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_FINISHED_TX, data);
+ }
+
+ for (auto entry : m_stream_table) {
+ get_stateless_obj()->m_rx_flow_stat.stop_stream(entry.second);
+ }
}
void
@@ -428,12 +447,7 @@ TrexStatelessPort::on_dp_event_occured(TrexDpPortEvent::event_e event_type) {
switch (event_type) {
case TrexDpPortEvent::EVENT_STOP:
- /* set a stop event */
- change_state(PORT_STATE_STREAMS);
- /* send a ZMQ event */
-
- data["port_id"] = m_port_id;
- get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_FINISHED_TX, data);
+ common_port_stop_actions(true);
break;
default:
@@ -651,6 +665,47 @@ TrexStatelessPort::get_port_effective_rate(double &pps,
}
+void
+TrexStatelessPort::add_stream(TrexStream *stream) {
+
+ verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS);
+
+ m_stream_table.add_stream(stream);
+ delete_streams_graph();
+
+ get_stateless_obj()->m_rx_flow_stat.add_stream(stream);
+
+ change_state(PORT_STATE_STREAMS);
+}
+
+void
+TrexStatelessPort::remove_stream(TrexStream *stream) {
+
+ verify_state(PORT_STATE_STREAMS);
+
+ get_stateless_obj()->m_rx_flow_stat.del_stream(stream);
+
+ m_stream_table.remove_stream(stream);
+ delete_streams_graph();
+
+ if (m_stream_table.size() == 0) {
+ change_state(PORT_STATE_IDLE);
+ }
+}
+
+void
+TrexStatelessPort::remove_and_delete_all_streams() {
+ verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS);
+
+ vector<TrexStream *> streams;
+ get_object_list(streams);
+
+ for (auto stream : streams) {
+ remove_stream(stream);
+ delete stream;
+ }
+}
+
/************* Trex Port Owner **************/
TrexPortOwner::TrexPortOwner() {
diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h
index 49e69757..434181c4 100644
--- a/src/stateless/cp/trex_stateless_port.h
+++ b/src/stateless/cp/trex_stateless_port.h
@@ -236,34 +236,9 @@ public:
*
*/
- void add_stream(TrexStream *stream) {
- verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS);
-
- m_stream_table.add_stream(stream);
- delete_streams_graph();
-
- change_state(PORT_STATE_STREAMS);
- }
-
- void remove_stream(TrexStream *stream) {
- verify_state(PORT_STATE_STREAMS);
-
- m_stream_table.remove_stream(stream);
- delete_streams_graph();
-
- if (m_stream_table.size() == 0) {
- change_state(PORT_STATE_IDLE);
- }
- }
-
- void remove_and_delete_all_streams() {
- verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS);
-
- m_stream_table.remove_and_delete_all_streams();
- delete_streams_graph();
-
- change_state(PORT_STATE_IDLE);
- }
+ void add_stream(TrexStream *stream);
+ void remove_stream(TrexStream *stream);
+ void remove_and_delete_all_streams();
TrexStream * get_stream_by_id(uint32_t stream_id) {
return m_stream_table.get_stream_by_id(stream_id);
@@ -308,6 +283,18 @@ public:
*/
uint64_t get_port_speed_bps() const;
+ /**
+ * return true if port adds CRC to a packet (not occurs for
+ * VNICs)
+ *
+ * @author imarom (24-Feb-16)
+ *
+ * @return bool
+ */
+ bool has_crc_added() const {
+ return m_has_crc;
+ }
+
TrexPortOwner & get_owner() {
return m_owner;
}
@@ -357,6 +344,12 @@ private:
/**
+ * when a port stops, perform various actions
+ *
+ */
+ void common_port_stop_actions(bool event_triggered);
+
+ /**
* calculate effective M per core
*
*/
@@ -382,6 +375,7 @@ private:
uint8_t m_port_id;
port_state_e m_port_state;
std::string m_driver_name;
+ bool m_has_crc;
TrexPlatformApi::driver_speed_e m_speed;
diff --git a/src/stateless/cp/trex_stream.cpp b/src/stateless/cp/trex_stream.cpp
index f1c93a11..9c7898a8 100644
--- a/src/stateless/cp/trex_stream.cpp
+++ b/src/stateless/cp/trex_stream.cpp
@@ -130,7 +130,7 @@ TrexStream::TrexStream(uint8_t type,
m_pkt.len = 0;
m_expected_pkt_len = 0;
- m_rx_check.m_enable = false;
+ m_rx_check.m_enabled = false;
m_burst_total_pkts=0;
@@ -191,15 +191,6 @@ void TrexStreamTable::remove_stream(TrexStream *stream) {
}
-void TrexStreamTable::remove_and_delete_all_streams() {
-
- for (auto stream : m_stream_table) {
- delete stream.second;
- }
-
- m_stream_table.clear();
-}
-
TrexStream * TrexStreamTable::get_stream_by_id(uint32_t stream_id) {
auto search = m_stream_table.find(stream_id);
@@ -254,5 +245,13 @@ TrexStreamRate::get_line_speed_bps() {
double
TrexStreamRate::get_pkt_size() {
- return m_stream.get_pkt_size();
+ TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(m_stream.m_port_id);
+
+ double pkt_size = m_stream.get_pkt_size();
+
+ if (port->has_crc_added()) {
+ pkt_size += 4;
+ }
+
+ return pkt_size;
}
diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h
index cc05c198..36f9d407 100644
--- a/src/stateless/cp/trex_stream.h
+++ b/src/stateless/cp/trex_stream.h
@@ -244,29 +244,29 @@ private:
double get_pkt_size();
void calculate_from_pps() {
- m_bps_L1 = m_pps * (get_pkt_size() + 24) * 8;
- m_bps_L2 = m_pps * (get_pkt_size() + 4) * 8;
+ m_bps_L1 = m_pps * (get_pkt_size() + 20) * 8;
+ m_bps_L2 = m_pps * get_pkt_size() * 8;
m_percentage = (m_bps_L1 / get_line_speed_bps()) * 100.0;
}
void calculate_from_bps_L1() {
- m_bps_L2 = m_bps_L1 * ( (get_pkt_size() + 4.0) / (get_pkt_size() + 24.0) );
- m_pps = m_bps_L2 / (8 * (get_pkt_size() + 4));
+ m_bps_L2 = m_bps_L1 * ( get_pkt_size() / (get_pkt_size() + 20.0) );
+ m_pps = m_bps_L2 / (8 * get_pkt_size());
m_percentage = (m_bps_L1 / get_line_speed_bps()) * 100.0;
}
void calculate_from_bps_L2() {
- m_bps_L1 = m_bps_L2 * ( (get_pkt_size() + 24.0) / (get_pkt_size() + 4.0));
- m_pps = m_bps_L2 / (8 * (get_pkt_size() + 4));
+ m_bps_L1 = m_bps_L2 * ( (get_pkt_size() + 20.0) / get_pkt_size());
+ m_pps = m_bps_L2 / (8 * get_pkt_size());
m_percentage = (m_bps_L1 / get_line_speed_bps()) * 100.0;
}
void calculate_from_percentage() {
m_bps_L1 = (m_percentage / 100.0) * get_line_speed_bps();
- m_bps_L2 = m_bps_L1 * ( (get_pkt_size() + 4.0) / (get_pkt_size() + 24.0) );
- m_pps = m_bps_L2 / (8 * (get_pkt_size() + 4));
+ m_bps_L2 = m_bps_L1 * ( get_pkt_size() / (get_pkt_size() + 20.0) );
+ m_pps = m_bps_L2 / (8 * get_pkt_size());
}
@@ -394,11 +394,19 @@ public:
}
/* create new stream */
- TrexStream * clone() const {
+ TrexStream * clone(bool full = false) const {
/* not all fields will be cloned */
TrexStream *dp = new TrexStream(m_type,m_port_id,m_stream_id);
+
+ /* on full clone we copy also VM */
+ if (full) {
+ m_vm.clone(dp->m_vm);
+
+ }
+
+ /* copy VM DP product */
if (m_vm_dp) {
dp->m_vm_dp = m_vm_dp->clone();
} else {
@@ -500,10 +508,10 @@ public:
/* RX check */
struct {
- bool m_enable;
+ bool m_enabled;
bool m_seq_enabled;
bool m_latency;
- uint32_t m_stream_id;
+ uint32_t m_user_id;
} m_rx_check;
@@ -559,12 +567,7 @@ public:
*/
void remove_stream(TrexStream *stream);
- /**
- * remove all streams on the table
- * memory will be deleted
- */
- void remove_and_delete_all_streams();
-
+
/**
* fetch a stream if exists
* o.w NULL
diff --git a/src/stateless/cp/trex_stream_vm.cpp b/src/stateless/cp/trex_stream_vm.cpp
index d8395ba4..7a1dc122 100644
--- a/src/stateless/cp/trex_stream_vm.cpp
+++ b/src/stateless/cp/trex_stream_vm.cpp
@@ -887,14 +887,14 @@ StreamVm::set_split_instruction(StreamVmInstructionVar *instr) {
}
/**
- * copy instructions from this VM to 'other'
+ * clone VM from this VM to 'other'
*
* @author imarom (22-Dec-15)
*
* @param other
*/
void
-StreamVm::copy_instructions(StreamVm &other) const {
+StreamVm::clone(StreamVm &other) const {
/* clear previous if any exists */
for (auto instr : other.m_inst_list) {
delete instr;
@@ -904,6 +904,7 @@ StreamVm::copy_instructions(StreamVm &other) const {
for (auto instr : m_inst_list) {
StreamVmInstruction *new_instr = instr->clone();
+
other.m_inst_list.push_back(new_instr);
/* for the split instruction - find the right one */
@@ -914,6 +915,7 @@ StreamVm::copy_instructions(StreamVm &other) const {
}
}
+ other.m_is_random_var = m_is_random_var;
}
/**
@@ -974,7 +976,7 @@ StreamVm::calc_expected_pkt_size(uint16_t regular_pkt_size) const {
StreamVm dummy;
- this->copy_instructions(dummy);
+ this->clone(dummy);
dummy.compile(regular_pkt_size);
assert(dummy.m_expected_pkt_size != 0);
diff --git a/src/stateless/cp/trex_stream_vm.h b/src/stateless/cp/trex_stream_vm.h
index f5d58edd..c1db090d 100644
--- a/src/stateless/cp/trex_stream_vm.h
+++ b/src/stateless/cp/trex_stream_vm.h
@@ -1456,7 +1456,7 @@ public:
* clone VM instructions
*
*/
- void copy_instructions(StreamVm &other) const;
+ void clone(StreamVm &other) const;
bool is_vm_empty() const {
diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp
index aca74498..7c91754c 100644
--- a/src/stateless/cp/trex_streams_compiler.cpp
+++ b/src/stateless/cp/trex_streams_compiler.cpp
@@ -475,16 +475,18 @@ TrexStreamsCompiler::compile_stream(TrexStream *stream,
new_next_id = nodes.get(stream->m_next_stream_id)->m_compressed_stream_id;
}
+ TrexStream *fixed_rx_flow_stat_stream = stream->clone(true);
+ get_stateless_obj()->m_rx_flow_stat.start_stream(fixed_rx_flow_stat_stream);
/* can this stream be split to many cores ? */
if (!stream->is_splitable(dp_core_count)) {
- compile_stream_on_single_core(stream,
+ compile_stream_on_single_core(fixed_rx_flow_stat_stream,
factor,
objs[0],
new_id,
new_next_id);
} else {
- compile_stream_on_all_cores(stream,
+ compile_stream_on_all_cores(fixed_rx_flow_stat_stream,
factor,
dp_core_count,
objs,
@@ -492,7 +494,7 @@ TrexStreamsCompiler::compile_stream(TrexStream *stream,
new_next_id);
}
-
+ delete fixed_rx_flow_stat_stream;
}
/**
diff --git a/src/stateless/cp/trex_vm_splitter.cpp b/src/stateless/cp/trex_vm_splitter.cpp
index 5e6d4fbd..963b4525 100644
--- a/src/stateless/cp/trex_vm_splitter.cpp
+++ b/src/stateless/cp/trex_vm_splitter.cpp
@@ -190,7 +190,7 @@ void
TrexVmSplitter::duplicate_vm() {
/* for each core - duplicate the instructions */
for (TrexStream *core_stream : *m_core_streams) {
- m_stream->m_vm.copy_instructions(core_stream->m_vm);
+ m_stream->m_vm.clone(core_stream->m_vm);
}
}
diff --git a/src/trex_defs.h b/src/trex_defs.h
new file mode 100644
index 00000000..bb8510fa
--- /dev/null
+++ b/src/trex_defs.h
@@ -0,0 +1,31 @@
+/*
+Copyright (c) 2015-2016 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#ifndef __TREX_DEFS_H__
+#define __TREX_DEFS_H__
+
+#define TREX_MAX_PORTS 12
+#define TREX_FDIR_STAT_SIZE 128
+
+#ifndef UINT8_MAX
+ #define UINT8_MAX 255
+#endif
+
+#ifndef UINT16_MAX
+ #define UINT16_MAX 0xFFFF
+#endif
+
+
+#endif