From 9ade0a9af71faa83ad26291a7f5c13733d2e66ec Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Sat, 9 Apr 2016 02:36:36 +0300 Subject: regression: allow 0.01% errors in rx_check in kiwi02, add 1 more core to trex-dan at nbar --- scripts/automation/regression/setups/kiwi02/benchmark.yaml | 5 +++++ scripts/automation/regression/setups/trex-dan/benchmark.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'scripts/automation') diff --git a/scripts/automation/regression/setups/kiwi02/benchmark.yaml b/scripts/automation/regression/setups/kiwi02/benchmark.yaml index 2d47f8f8..60febc8f 100644 --- a/scripts/automation/regression/setups/kiwi02/benchmark.yaml +++ b/scripts/automation/regression/setups/kiwi02/benchmark.yaml @@ -122,26 +122,31 @@ test_rx_check_sfr: multiplier : 25 cores : 4 rx_sample_rate : 32 + error_tolerance : 0.01 test_rx_check_http: multiplier : 40000 cores : 2 rx_sample_rate : 32 + error_tolerance : 0.01 test_rx_check_sfr_ipv6: multiplier : 25 cores : 4 rx_sample_rate : 32 + error_tolerance : 0.01 test_rx_check_http_ipv6: multiplier : 40000 cores : 2 rx_sample_rate : 32 + error_tolerance : 0.01 test_rx_check_http_negative: multiplier : 40000 cores : 2 rx_sample_rate : 32 + error_tolerance : 0.01 test_jumbo: multiplier : 55 diff --git a/scripts/automation/regression/setups/trex-dan/benchmark.yaml b/scripts/automation/regression/setups/trex-dan/benchmark.yaml index 4b47bd8e..a31d070c 100644 --- a/scripts/automation/regression/setups/trex-dan/benchmark.yaml +++ b/scripts/automation/regression/setups/trex-dan/benchmark.yaml @@ -4,7 +4,7 @@ test_nbar_simple : multiplier : 1.5 - cores : 1 + cores : 2 exp_gbps : 0.5 cpu_to_core_ratio : 20800000 cpu2core_custom_dev: YES -- cgit 1.2.3-korg From 1d62dfca8a6c7a3a54c8c08ef1a1332582ba38cb Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 4 Apr 2016 14:30:07 +0300 Subject: activate client tests on all setups with restrictions --- .../regression/stateless_tests/stl_client_test.py | 26 +++++++++++++--------- .../stl/trex_stl_lib/trex_stl_streams.py | 9 ++++++++ 2 files changed, 25 insertions(+), 10 deletions(-) (limited to 'scripts/automation') diff --git a/scripts/automation/regression/stateless_tests/stl_client_test.py b/scripts/automation/regression/stateless_tests/stl_client_test.py index 01a90250..3ef4713f 100644 --- a/scripts/automation/regression/stateless_tests/stl_client_test.py +++ b/scripts/automation/regression/stateless_tests/stl_client_test.py @@ -240,22 +240,29 @@ class STLClient_Test(CStlGeneral_Test): def test_all_profiles (self): - # need promiscious for this one... - if self.is_virt_nics or not self.is_loopback: - self.skip('skipping profile tests for virtual NICs') - return try: - self.c.set_port_attr(ports = [self.tx_port, self.rx_port], promiscuous = True) - + for profile in self.profiles: + print("now testing profile {0}...\n").format(profile) p1 = STLProfile.load(profile, port_id = self.tx_port) p2 = STLProfile.load(profile, port_id = self.rx_port) + # if profile contains custom MAC addrs we need promiscuous mode + # but virtual NICs does not support promiscuous mode + self.c.set_port_attr(ports = [self.tx_port, self.rx_port], promiscuous = False) + + if p1.has_custom_mac_addr(): + if not self.is_virt_nics: + self.c.set_port_attr(ports = [self.tx_port, self.rx_port], promiscuous = True) + else: + print("\n*** profile needs promiscuous mode but running on virtual NICs - skipping... ***\n") + continue + if p1.has_flow_stats(): - print("profile needs RX caps - skipping...") + print("\n*** profile needs RX caps - skipping... ***\n") continue self.c.add_streams(p1, ports = self.tx_port) @@ -280,9 +287,8 @@ class STLClient_Test(CStlGeneral_Test): assert self.tx_port in stats, '{0} - no stats for TX port'.format(profile) assert self.rx_port in stats, '{0} - no stats for RX port'.format(profile) - assert stats[self.tx_port]['opackets'] == stats[self.rx_port]['ipackets'], '{0} - number of TX packets differ from RX packets'.format(profile) - - assert stats[self.rx_port]['opackets'] == stats[self.tx_port]['ipackets'], '{0} - number of TX packets differ from RX packets'.format(profile) + self.verify(stats[self.tx_port]['opackets'], stats[self.rx_port]['ipackets']) + self.verify(stats[self.rx_port]['opackets'], stats[self.tx_port]['ipackets']) self.c.remove_all_streams(ports = [self.tx_port, self.rx_port]) 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 3ce876ad..165942d8 100755 --- 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 @@ -361,6 +361,8 @@ class STLStream(object): int_mac_dst_override_mode = int(mac_dst_override_mode); + self.is_default_mac = not (int_mac_src_override_by_pkt or int_mac_dst_override_mode) + self.fields['flags'] = (int_mac_src_override_by_pkt&1) + ((int_mac_dst_override_mode&3)<<1) self.fields['action_count'] = action_count @@ -421,6 +423,10 @@ class STLStream(object): return self.id + def has_custom_mac_addr (self): + """ Return True if src or dst MAC were set as custom """ + return not self.is_default_mac + def get_name (self): """ Get the stream name """ return self.name @@ -835,6 +841,9 @@ class STLProfile(object): def is_pauseable (self): return all([x.get_mode() == "Continuous" for x in self.get_streams()]) + def has_custom_mac_addr (self): + return any([x.has_custom_mac_addr() for x in self.get_streams()]) + def has_flow_stats (self): return any([x.has_flow_stats() for x in self.get_streams()]) -- cgit 1.2.3-korg From c48c89a97ad070b8f79ac746b6b83aab1cc6f177 Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 10 Apr 2016 10:15:54 +0300 Subject: multicore scheduling --- .../stl/trex_stl_lib/trex_stl_sim.py | 141 +++++++++++++++++++-- src/stateless/cp/trex_stream.cpp | 3 +- src/stateless/cp/trex_stream.h | 13 +- src/stateless/cp/trex_streams_compiler.cpp | 43 ++++--- src/stateless/dp/trex_stateless_dp_core.cpp | 2 +- src/stateless/dp/trex_stream_node.h | 7 +- 6 files changed, 169 insertions(+), 40 deletions(-) (limited to 'scripts/automation') 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 1d89a599..2f6b1571 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 @@ -22,6 +22,7 @@ from .trex_stl_streams import * from .utils import parsing_opts from .trex_stl_client import STLClient from .utils import pcap +from trex_stl_lib.trex_stl_packet_builder_scapy import RawPcapReader, RawPcapWriter, hexdump from yaml import YAMLError @@ -291,13 +292,13 @@ class STLSim(object): return - print("Mering cores output to a single pcap file...\n") + if not self.silent: + print("Mering cores output to a single pcap file...\n") inputs = ["{0}-{1}".format(self.outfile, index) for index in range(0, self.dp_core_count)] pcap.merge_cap_files(inputs, self.outfile, delete_src = True) - def is_valid_file(filename): if not os.path.isfile(filename): raise argparse.ArgumentTypeError("The file '%s' does not exist" % filename) @@ -421,6 +422,11 @@ def setParserOptions(): action = "store_true", default = False) + group.add_argument("--test_multi_core", + help = "runs the profile with c=1-8", + action = "store_true", + default = False) + return parser @@ -435,6 +441,110 @@ def validate_args (parser, options): parser.error("limit cannot be lower than number of DP cores") +# a more flexible check +def compare_caps (cap1, cap2, max_diff_sec = (5 * 1e-6)): + pkts1 = list(RawPcapReader(cap1)) + pkts2 = list(RawPcapReader(cap2)) + + if len(pkts1) != len(pkts2): + print('{0} contains {1} packets vs. {1} contains {2} packets'.format(cap1, len(pkts1), cap2, len(pkts2))) + return False + + # to be less strict we define equality if all packets from cap1 exists and in cap2 + # and vice versa + # 'exists' means the same packet with abs(TS1-TS2) < 5nsec + # its O(n^2) but who cares, right ? + for i, pkt1 in enumerate(pkts1): + ts1 = float(pkt1[1][0]) + (float(pkt1[1][1]) / 1e6) + found = None + for j, pkt2 in enumerate(pkts2): + ts2 = float(pkt2[1][0]) + (float(pkt2[1][1]) / 1e6) + + if abs(ts1-ts2) > max_diff_sec: + break + + if pkt1[0] == pkt2[0]: + found = j + break + + + if found is None: + print(format_text("cannot find packet #{0} from {1} in {2}\n".format(i, cap1, cap2), 'bold')) + return False + else: + del pkts2[found] + + return True + + + + +# a more strict comparsion 1 <--> 1 +def compare_caps_strict (cap1, cap2, max_diff_sec = (5 * 1e-6)): + pkts1 = list(RawPcapReader(cap1)) + pkts2 = list(RawPcapReader(cap2)) + + if len(pkts1) != len(pkts2): + print('{0} contains {1} packets vs. {1} contains {2} packets'.format(cap1, len(pkts1), cap2, len(pkts2))) + return False + + # a strict check + for pkt1, pkt2, i in zip(pkts1, pkts2, range(1, len(pkts1))): + ts1 = float(pkt1[1][0]) + (float(pkt1[1][1]) / 1e6) + ts2 = float(pkt2[1][0]) + (float(pkt2[1][1]) / 1e6) + + if abs(ts1-ts2) > 0.000005: # 5 nsec + print(format_text("TS error: cap files '{0}', '{1}' differ in cap #{2} - '{3}' vs. '{4}'\n".format(cap1, cap2, i, ts1, ts2), 'bold')) + return False + + if pkt1[0] != pkt2[0]: + print(format_text("RAW error: cap files '{0}', '{1}' differ in cap #{2}\n".format(cap1, cap2, i), 'bold')) + print(hexdump(pkt1[0])) + print("") + print(hexdump(pkt2[0])) + print("") + return False + + return True + +# +def test_multi_core (r, options): + + for core_count in [1, 2, 4, 6, 8]: + r.run(input_list = options.input_file, + outfile = '{0}.cap'.format(core_count), + dp_core_count = core_count, + is_debug = (not options.release), + pkt_limit = options.limit, + mult = options.mult, + duration = options.duration, + mode = 'none', + silent = True, + tunables = options.tunables) + + print("") + + print(format_text("comparing 2 cores to 1 core:\n", 'underline')) + rc = compare_caps('1.cap', '2.cap') + if rc: + print("[Passed]\n") + + print(format_text("comparing 4 cores to 1 core:\n", 'underline')) + rc = compare_caps('1.cap', '4.cap') + if rc: + print("[Passed]\n") + + print(format_text("comparing 6 cores to 1 core:\n", 'underline')) + rc = compare_caps('1.cap', '6.cap') + if rc: + print("[Passed]\n") + + print(format_text("comparing 8 cores to 1 core:\n", 'underline')) + rc = compare_caps('1.cap', '8.cap') + if rc: + print("[Passed]\n") + + def main (args = None): parser = setParserOptions() options = parser.parse_args(args = args) @@ -455,23 +565,28 @@ def main (args = None): mode = 'native' elif options.pkt: mode = 'pkt' + elif options.test_multi_core: + mode = 'test_multi_core' else: mode = 'none' try: r = STLSim(bp_sim_path = options.bp_sim_path, port_id = options.port_id) - r.run(input_list = options.input_file, - outfile = options.output_file, - dp_core_count = options.dp_core_count, - dp_core_index = options.dp_core_index, - is_debug = (not options.release), - pkt_limit = options.limit, - mult = options.mult, - duration = options.duration, - mode = mode, - silent = options.silent, - tunables = options.tunables) + if mode == 'test_multi_core': + test_multi_core(r, options) + else: + r.run(input_list = options.input_file, + outfile = options.output_file, + dp_core_count = options.dp_core_count, + dp_core_index = options.dp_core_index, + is_debug = (not options.release), + pkt_limit = options.limit, + mult = options.mult, + duration = options.duration, + mode = mode, + silent = options.silent, + tunables = options.tunables) except KeyboardInterrupt as e: print("\n\n*** Caught Ctrl + C... Exiting...\n\n") diff --git a/src/stateless/cp/trex_stream.cpp b/src/stateless/cp/trex_stream.cpp index 6e4478d6..4325858c 100644 --- a/src/stateless/cp/trex_stream.cpp +++ b/src/stateless/cp/trex_stream.cpp @@ -135,7 +135,8 @@ TrexStream::TrexStream(uint8_t type, m_enabled = false; m_self_start = false; - m_delay_next_stream_sec = 0; + m_mc_phase_pre_sec = 0; + m_mc_phase_post_sec = 0; m_pkt.binary = NULL; m_pkt.len = 0; diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index e4ce914e..1914026b 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -401,6 +401,7 @@ public: set_multi_burst(burst_total_pkts,1,0.0); } + /* create new stream */ TrexStream * clone(bool full = false) const { @@ -422,7 +423,11 @@ public: } dp->m_isg_usec = m_isg_usec; - dp->m_delay_next_stream_sec = m_delay_next_stream_sec; + + /* multi core phase paramters */ + dp->m_mc_phase_pre_sec = m_mc_phase_pre_sec; + dp->m_mc_phase_post_sec = m_mc_phase_post_sec; + dp->m_next_stream_id = m_next_stream_id; dp->m_enabled = m_enabled; @@ -457,7 +462,7 @@ public: return ( (m_burst_total_pkts / get_pps()) * 1000 * 1000); } - double get_ipg() { + double get_ipg_sec() { return (1.0 / get_pps()); } @@ -502,7 +507,9 @@ public: /* config fields */ - double m_delay_next_stream_sec; + double m_mc_phase_pre_sec; + double m_mc_phase_post_sec; + double m_isg_usec; int m_next_stream_id; diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index da2b9c9b..c4ae0bed 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -586,6 +586,11 @@ TrexStreamsCompiler::compile_stream_on_all_cores(TrexStream *stream, int per_core_burst_total_pkts = (stream->m_burst_total_pkts / dp_core_count); int burst_remainder = (stream->m_burst_total_pkts % dp_core_count); + bool has_remainder = (burst_remainder > 0); + int remainder_left = burst_remainder; + + double base_ipg_sec = factor * stream->get_ipg_sec(); + /* for each core - creates its own version of the stream */ for (uint8_t i = 0; i < dp_core_count; i++) { @@ -594,30 +599,32 @@ TrexStreamsCompiler::compile_stream_on_all_cores(TrexStream *stream, /* fix stream ID */ dp_stream->fix_dp_stream_id(new_id, new_next_id); + /* some phase */ + dp_stream->m_mc_phase_pre_sec = base_ipg_sec * i; + /* each core gets a share of the packets */ dp_stream->m_burst_total_pkts = per_core_burst_total_pkts; + + /* rate is slower * dp_core_count */ + dp_stream->update_rate_factor(factor / dp_core_count); + - /* core 0 also gets the remainder */ - if (i == 0) { - dp_stream->m_burst_total_pkts += burst_remainder; - } - - /* for continous the rate is divided by the cores */ - if (stream->m_type == TrexStream::stCONTINUOUS) { - dp_stream->update_rate_factor(factor / dp_core_count); + /* allocate the rest of the packets */ + if (has_remainder) { + if (remainder_left > 0) { + dp_stream->m_burst_total_pkts++; + remainder_left--; + dp_stream->m_mc_phase_post_sec = base_ipg_sec * remainder_left; + } else { + /* a delay slot if no packets left */ + dp_stream->m_mc_phase_post_sec = base_ipg_sec * (dp_core_count - 1 - i + burst_remainder); + } + } else { - /* rate is according to the share of the packetes the core got */ - dp_stream->update_rate_factor(factor * (dp_stream->m_burst_total_pkts / double(stream->m_burst_total_pkts))); + /* if no remainder (or continous) simply add a reverse phase */ + dp_stream->m_mc_phase_post_sec = base_ipg_sec * (dp_core_count - 1 - i); } - - - //dp_stream->m_pkt.binary[14 + 20] = 0; - //dp_stream->m_pkt.binary[14 + 21] = i; - - /* some phase */ - dp_stream->m_isg_usec += (stream->get_ipg() * i) * 1e6; - dp_stream->m_delay_next_stream_sec = stream->get_ipg() * (dp_core_count - 1 - i); core_streams[i] = dp_stream; } diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 42ff9e24..2a4a384b 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -602,7 +602,7 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port, node->m_state =CGenNodeStateless::ss_INACTIVE; } - node->m_time = m_core->m_cur_time_sec + usec_to_sec(stream->m_isg_usec); + node->m_time = m_core->m_cur_time_sec + usec_to_sec(stream->m_isg_usec) + stream->m_mc_phase_pre_sec; pkt_dir_t dir = m_core->m_node_gen.m_v_if->port_id_to_dir(stream->m_port_id); node->m_flags = 0; diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index fa6fd8bd..d756ba43 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -144,7 +144,7 @@ public: /* we restart the stream, schedule it using stream isg */ inline void update_refresh_time(double cur_time){ - m_time = cur_time + usec_to_sec(m_ref_stream_info->m_isg_usec); + m_time = cur_time + usec_to_sec(m_ref_stream_info->m_isg_usec) + m_ref_stream_info->m_mc_phase_pre_sec; } inline bool is_mask_for_free(){ @@ -236,8 +236,7 @@ public: set_state(CGenNodeStateless::ss_INACTIVE); if ( thread->set_stateless_next_node(this,m_next_stream) ){ /* update the next stream time using isg */ - //m_next_stream->update_refresh_time(m_time + m_next_time_offset); - m_next_stream->update_refresh_time(m_time + m_ref_stream_info->m_delay_next_stream_sec); + m_next_stream->update_refresh_time(m_time + m_ref_stream_info->m_mc_phase_post_sec); thread->m_node_gen.m_p_queue.push( (CGenNode *)m_next_stream); }else{ @@ -246,7 +245,7 @@ public: } }else{ - m_time += get_multi_ibg_sec(); + m_time += get_multi_ibg_sec() + m_ref_stream_info->m_mc_phase_post_sec + m_ref_stream_info->m_mc_phase_pre_sec; m_single_burst = m_single_burst_refill; thread->m_node_gen.m_p_queue.push( (CGenNode *)this); } -- cgit 1.2.3-korg From 8ac45c1c3b2d10d4679fd2c662b6a78c2c2c27a5 Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 10 Apr 2016 10:44:23 +0300 Subject: added tests for multi core --- .../regression/functional_tests/stl_basic_tests.py | 11 +++++ scripts/stl/tests/many_streams.py | 50 ++++++++++++++++++++++ scripts/stl/tests/multi_burst.py | 17 ++++++++ scripts/stl/tests/single_burst.py | 17 ++++++++ scripts/stl/tests/single_cont.py | 17 ++++++++ 5 files changed, 112 insertions(+) create mode 100644 scripts/stl/tests/many_streams.py create mode 100644 scripts/stl/tests/multi_burst.py create mode 100644 scripts/stl/tests/single_burst.py create mode 100644 scripts/stl/tests/single_cont.py (limited to 'scripts/automation') diff --git a/scripts/automation/regression/functional_tests/stl_basic_tests.py b/scripts/automation/regression/functional_tests/stl_basic_tests.py index 2bf97307..8b8f2097 100644 --- a/scripts/automation/regression/functional_tests/stl_basic_tests.py +++ b/scripts/automation/regression/functional_tests/stl_basic_tests.py @@ -262,3 +262,14 @@ class CStlBasic_Test(functional_general_test.CGeneralFunctional_Test): + def test_multicore_scheduling (self): + mc_tests = ['stl/tests/single_cont.py', + 'stl/tests/single_burst.py', + 'stl/tests/multi_burst.py', + 'stl/tests/many_streams.py', + ] + + for mc_test in mc_tests: + rc = self.run_sim(mc_test, output = None, options = '--test_multi_core --limit=3840', silent = True) + assert_equal(rc, True) + diff --git a/scripts/stl/tests/many_streams.py b/scripts/stl/tests/many_streams.py new file mode 100644 index 00000000..eace7640 --- /dev/null +++ b/scripts/stl/tests/many_streams.py @@ -0,0 +1,50 @@ +from trex_stl_lib.api import * + +class STLS1(object): + + def get_streams (self, direction = 0, **kwargs): + s1 = STLStream(name = 's1', + packet = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/(10*'x')), + mode = STLTXSingleBurst(pps = 100, total_pkts = 7), + next = 's2' + + ) + s2 = STLStream(name = 's2', + self_start = False, + packet = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.2")/UDP(dport=12,sport=1025)/(10*'x')), + mode = STLTXSingleBurst(pps = 317, total_pkts = 13), + next = 's3' + ) + + + s3 = STLStream(name = 's3', + self_start = False, + packet = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.3")/UDP(dport=12,sport=1025)/(10*'x')), + mode = STLTXMultiBurst(pps = 57, pkts_per_burst = 9, count = 5, ibg = 12), + next = 's4' + ) + + s4 = STLStream(name = 's4', + self_start = False, + packet = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.3")/UDP(dport=12,sport=1025)/(10*'x')), + mode = STLTXSingleBurst(pps = 4, total_pkts = 22), + next = 's5' + ) + + s5 = STLStream(name = 's5', + self_start = False, + packet = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.3")/UDP(dport=12,sport=1025)/(10*'x')), + mode = STLTXSingleBurst(pps = 17, total_pkts = 27), + action_count = 17, + next = 's1' + ) + + return [ s1, s2, s3, s4, s5 ] + + +# dynamic load - used for trex console or simulator +def register(): + return STLS1() + + + diff --git a/scripts/stl/tests/multi_burst.py b/scripts/stl/tests/multi_burst.py new file mode 100644 index 00000000..68a239f5 --- /dev/null +++ b/scripts/stl/tests/multi_burst.py @@ -0,0 +1,17 @@ +from trex_stl_lib.api import * + +class STLS1(object): + + def get_streams (self, direction = 0, **kwargs): + s1 = STLStream(packet = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/(10*'x')), + mode = STLTXMultiBurst(pkts_per_burst = 9, count = 2, ibg = 13)) + + return [s1] + + +# dynamic load - used for trex console or simulator +def register(): + return STLS1() + + + diff --git a/scripts/stl/tests/single_burst.py b/scripts/stl/tests/single_burst.py new file mode 100644 index 00000000..c46ebf87 --- /dev/null +++ b/scripts/stl/tests/single_burst.py @@ -0,0 +1,17 @@ +from trex_stl_lib.api import * + +class STLS1(object): + + def get_streams (self, direction = 0, **kwargs): + s1 = STLStream(packet = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/(10*'x')), + mode = STLTXSingleBurst(total_pkts = 27)) + + return [s1] + + +# dynamic load - used for trex console or simulator +def register(): + return STLS1() + + + diff --git a/scripts/stl/tests/single_cont.py b/scripts/stl/tests/single_cont.py new file mode 100644 index 00000000..19563105 --- /dev/null +++ b/scripts/stl/tests/single_cont.py @@ -0,0 +1,17 @@ +from trex_stl_lib.api import * + +class STLS1(object): + + def get_streams (self, direction = 0, **kwargs): + s1 = STLStream(packet = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/(10*'x')), + mode = STLTXCont(pps = 2000)) + + return [s1] + + +# dynamic load - used for trex console or simulator +def register(): + return STLS1() + + + -- cgit 1.2.3-korg From 9823cf0a2acfa3eed27613bf357d82c241889cba Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 10 Apr 2016 11:01:24 +0300 Subject: multicore tests new goldens (because of phase) --- .../stl/trex_stl_lib/trex_stl_sim.py | 2 +- scripts/exp/imix_3pkt.pcap | Bin 8162 -> 5118 bytes scripts/exp/imix_3pkt_vm.pcap | Bin 4588 -> 4058 bytes scripts/exp/udp_1pkt_range_clients_split.pcap | Bin 7624 -> 7624 bytes scripts/exp/udp_1pkt_tuple_gen_split.pcap | Bin 7624 -> 7624 bytes src/stateless/cp/trex_stream.h | 4 --- src/stateless/cp/trex_streams_compiler.cpp | 32 ++++++++------------- src/stateless/dp/trex_stream_node.h | 7 ++--- 8 files changed, 15 insertions(+), 30 deletions(-) (limited to 'scripts/automation') 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 2f6b1571..11e80b9a 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 @@ -447,7 +447,7 @@ def compare_caps (cap1, cap2, max_diff_sec = (5 * 1e-6)): pkts2 = list(RawPcapReader(cap2)) if len(pkts1) != len(pkts2): - print('{0} contains {1} packets vs. {1} contains {2} packets'.format(cap1, len(pkts1), cap2, len(pkts2))) + print('{0} contains {1} packets vs. {2} contains {3} packets'.format(cap1, len(pkts1), cap2, len(pkts2))) return False # to be less strict we define equality if all packets from cap1 exists and in cap2 diff --git a/scripts/exp/imix_3pkt.pcap b/scripts/exp/imix_3pkt.pcap index d36fbe97..13a6e87f 100644 Binary files a/scripts/exp/imix_3pkt.pcap and b/scripts/exp/imix_3pkt.pcap differ diff --git a/scripts/exp/imix_3pkt_vm.pcap b/scripts/exp/imix_3pkt_vm.pcap index de78d575..3ec1bfbb 100644 Binary files a/scripts/exp/imix_3pkt_vm.pcap and b/scripts/exp/imix_3pkt_vm.pcap differ diff --git a/scripts/exp/udp_1pkt_range_clients_split.pcap b/scripts/exp/udp_1pkt_range_clients_split.pcap index 203de6eb..fb5037cc 100644 Binary files a/scripts/exp/udp_1pkt_range_clients_split.pcap and b/scripts/exp/udp_1pkt_range_clients_split.pcap differ diff --git a/scripts/exp/udp_1pkt_tuple_gen_split.pcap b/scripts/exp/udp_1pkt_tuple_gen_split.pcap index 2b7c7976..873ab47f 100644 Binary files a/scripts/exp/udp_1pkt_tuple_gen_split.pcap and b/scripts/exp/udp_1pkt_tuple_gen_split.pcap differ diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index 1914026b..eba5fed0 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -360,10 +360,6 @@ public: m_null_stream = enable; } - bool get_null_stream() { - return m_null_stream; - } - uint8_t get_type(void) const { return ( m_type ); } diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index c4ae0bed..520868c4 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -481,7 +481,7 @@ TrexStreamsCompiler::compile_on_single_core(uint8_t continue; } - /* compile a single stream to all cores */ + /* compile the stream for only one core */ compile_stream(stream, factor, 1, objs, nodes); } } @@ -585,10 +585,10 @@ TrexStreamsCompiler::compile_stream_on_all_cores(TrexStream *stream, std::vector core_streams(dp_core_count); int per_core_burst_total_pkts = (stream->m_burst_total_pkts / dp_core_count); - int burst_remainder = (stream->m_burst_total_pkts % dp_core_count); - bool has_remainder = (burst_remainder > 0); + const int burst_remainder = (stream->m_burst_total_pkts % dp_core_count); int remainder_left = burst_remainder; + /* this is the stream base IPG (pre split) */ double base_ipg_sec = factor * stream->get_ipg_sec(); @@ -599,7 +599,7 @@ TrexStreamsCompiler::compile_stream_on_all_cores(TrexStream *stream, /* fix stream ID */ dp_stream->fix_dp_stream_id(new_id, new_next_id); - /* some phase */ + /* some phase is added to avoid all the cores TXing at once */ dp_stream->m_mc_phase_pre_sec = base_ipg_sec * i; @@ -610,22 +610,17 @@ TrexStreamsCompiler::compile_stream_on_all_cores(TrexStream *stream, dp_stream->update_rate_factor(factor / dp_core_count); - /* allocate the rest of the packets */ - if (has_remainder) { - if (remainder_left > 0) { - dp_stream->m_burst_total_pkts++; - remainder_left--; - dp_stream->m_mc_phase_post_sec = base_ipg_sec * remainder_left; - } else { - /* a delay slot if no packets left */ - dp_stream->m_mc_phase_post_sec = base_ipg_sec * (dp_core_count - 1 - i + burst_remainder); - } - + if (remainder_left > 0) { + dp_stream->m_burst_total_pkts++; + remainder_left--; + /* this core needs to wait to the rest of the cores that will participate in the last round */ + dp_stream->m_mc_phase_post_sec = base_ipg_sec * remainder_left; } else { - /* if no remainder (or continous) simply add a reverse phase */ - dp_stream->m_mc_phase_post_sec = base_ipg_sec * (dp_core_count - 1 - i); + /* this core did not participate in the last round so it will wait its current round's left + burst_remainder */ + dp_stream->m_mc_phase_post_sec = base_ipg_sec * (dp_core_count - 1 - i + burst_remainder); } + core_streams[i] = dp_stream; } @@ -663,9 +658,6 @@ TrexStreamsCompiler::compile_stream_on_single_core(TrexStream *stream, dp_stream->m_vm_dp = stream->m_vm_dp->clone(); } - //dp_stream->m_pkt.binary[14 + 20] = 0; - //dp_stream->m_pkt.binary[14 + 21] = 0; - /* update core 0 with the real stream */ objs[0]->add_compiled_stream(dp_stream); diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index d756ba43..19a27350 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -175,10 +175,6 @@ public: return ((m_pause | m_null_stream) == 0); } - bool is_null_stream() { - return (m_null_stream == 1); - } - inline uint8_t get_stream_type(){ return (m_stream_type); } @@ -235,7 +231,7 @@ public: if ( m_multi_bursts == 0 ) { set_state(CGenNodeStateless::ss_INACTIVE); if ( thread->set_stateless_next_node(this,m_next_stream) ){ - /* update the next stream time using isg */ + /* update the next stream time using isg and post phase */ m_next_stream->update_refresh_time(m_time + m_ref_stream_info->m_mc_phase_post_sec); thread->m_node_gen.m_p_queue.push( (CGenNode *)m_next_stream); @@ -245,6 +241,7 @@ public: } }else{ + /* next burst is like starting a new stream - add pre and post phase */ m_time += get_multi_ibg_sec() + m_ref_stream_info->m_mc_phase_post_sec + m_ref_stream_info->m_mc_phase_pre_sec; m_single_burst = m_single_burst_refill; thread->m_node_gen.m_p_queue.push( (CGenNode *)this); -- cgit 1.2.3-korg From a561b3767f8701a729b2d6668b4b5721fd74a5ec Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 10 Apr 2016 14:04:33 +0300 Subject: fixed 10.0.0.X / 8.0.0.X to 16.0.0.X / 48.0.0.X --- .../regression/functional_tests/stl_basic_tests.py | 47 ++++++++++++++++++--- scripts/exp/imix.pcap | Bin 39396 -> 39396 bytes scripts/exp/pcap_with_vm.pcap | Bin 2284 -> 2284 bytes scripts/exp/udp_1pkt_simple_test.pcap | Bin 1474 -> 1474 bytes scripts/exp/udp_1pkt_simple_test2.pcap | Bin 1474 -> 1474 bytes scripts/stl/imix.py | 4 +- scripts/stl/pcap_with_vm.py | 2 +- scripts/stl/udp_1pkt_simple_test.py | 2 +- scripts/stl/udp_1pkt_simple_test2.py | 2 +- 9 files changed, 46 insertions(+), 11 deletions(-) (limited to 'scripts/automation') diff --git a/scripts/automation/regression/functional_tests/stl_basic_tests.py b/scripts/automation/regression/functional_tests/stl_basic_tests.py index 8b8f2097..c8a51f6a 100644 --- a/scripts/automation/regression/functional_tests/stl_basic_tests.py +++ b/scripts/automation/regression/functional_tests/stl_basic_tests.py @@ -9,8 +9,16 @@ from nose.plugins.attrib import attr from trex import CTRexScenario from trex_stl_lib import trex_stl_sim from trex_stl_lib.trex_stl_streams import STLProfile -from trex_stl_lib.trex_stl_packet_builder_scapy import RawPcapReader, RawPcapWriter +from trex_stl_lib.trex_stl_packet_builder_scapy import RawPcapReader, RawPcapWriter, Ether +from trex_stl_lib.utils.text_opts import * + import sys + +if sys.version_info > (3,0): + from io import StringIO +else: + from cStringIO import StringIO + import os import subprocess import shlex @@ -64,9 +72,18 @@ class CStlBasic_Test(functional_general_test.CGeneralFunctional_Test): raise Exception("cannot find '{0}'".format(name)) - def compare_caps (self, cap1, cap2, max_diff_sec = 0.01): - pkts1 = list(RawPcapReader(cap1)) - pkts2 = list(RawPcapReader(cap2)) + def scapy_pkt_show_to_str (self, scapy_pkt): + capture = StringIO() + save_stdout = sys.stdout + sys.stdout = capture + scapy_pkt.show() + sys.stdout = save_stdout + return capture.getvalue() + + + def compare_caps (self, output, golden, max_diff_sec = 0.01): + pkts1 = list(RawPcapReader(output)) + pkts2 = list(RawPcapReader(golden)) assert_equal(len(pkts1), len(pkts2)) @@ -75,11 +92,29 @@ class CStlBasic_Test(functional_general_test.CGeneralFunctional_Test): ts2 = float(pkt2[1][0]) + (float(pkt2[1][1]) / 1e6) if abs(ts1-ts2) > 0.000005: # 5 nsec - raise AssertionError("TS error: cap files '{0}', '{1}' differ in cap #{2} - '{3}' vs. '{4}'".format(cap1, cap2, i, ts1, ts2)) + raise AssertionError("TS error: cap files '{0}', '{1}' differ in cap #{2} - '{3}' vs. '{4}'".format(output, golden, i, ts1, ts2)) if pkt1[0] != pkt2[0]: - raise AssertionError("RAW error: cap files '{0}', '{1}' differ in cap #{2}".format(cap1, cap2, i)) + errmsg = "RAW error: output file '{0}', differs from golden '{1}' in cap #{2}".format(output, golden, i) + print(errmsg) + + print(format_text("\ndifferent fields for packet #{0}:".format(i), 'underline')) + + scapy_pkt1_info = self.scapy_pkt_show_to_str(Ether(pkt1[0])).split('\n') + scapy_pkt2_info = self.scapy_pkt_show_to_str(Ether(pkt2[0])).split('\n') + + print(format_text("\nGot:\n", 'bold', 'underline')) + for line, ref in zip(scapy_pkt1_info, scapy_pkt2_info): + if line != ref: + print(format_text(line, 'bold')) + + print(format_text("\nExpected:\n", 'bold', 'underline')) + for line, ref in zip(scapy_pkt2_info, scapy_pkt1_info): + if line != ref: + print(format_text(line, 'bold')) + print("\n") + raise AssertionError(errmsg) def run_sim (self, yaml, output, options = "", silent = False, obj = None): diff --git a/scripts/exp/imix.pcap b/scripts/exp/imix.pcap index aec8dac8..dff21f25 100644 Binary files a/scripts/exp/imix.pcap and b/scripts/exp/imix.pcap differ diff --git a/scripts/exp/pcap_with_vm.pcap b/scripts/exp/pcap_with_vm.pcap index b9476261..afc4bbef 100644 Binary files a/scripts/exp/pcap_with_vm.pcap and b/scripts/exp/pcap_with_vm.pcap differ diff --git a/scripts/exp/udp_1pkt_simple_test.pcap b/scripts/exp/udp_1pkt_simple_test.pcap index 2eeec462..a1d3a2e0 100644 Binary files a/scripts/exp/udp_1pkt_simple_test.pcap and b/scripts/exp/udp_1pkt_simple_test.pcap differ diff --git a/scripts/exp/udp_1pkt_simple_test2.pcap b/scripts/exp/udp_1pkt_simple_test2.pcap index 002d77dc..2cf16a8f 100644 Binary files a/scripts/exp/udp_1pkt_simple_test2.pcap and b/scripts/exp/udp_1pkt_simple_test2.pcap differ diff --git a/scripts/stl/imix.py b/scripts/stl/imix.py index 65e35108..82edbfa5 100644 --- a/scripts/stl/imix.py +++ b/scripts/stl/imix.py @@ -8,8 +8,8 @@ class STLImix(object): def __init__ (self): # default IP range - self.ip_range = {'src': {'start': "10.0.0.1", 'end': "10.0.0.254"}, - 'dst': {'start': "8.0.0.1", 'end': "8.0.0.254"}} + self.ip_range = {'src': {'start': "16.0.0.1", 'end': "16.0.0.254"}, + 'dst': {'start': "48.0.0.1", 'end': "48.0.0.254"}} # default IMIX properties self.imix_table = [ {'size': 60, 'pps': 28, 'isg':0 }, diff --git a/scripts/stl/pcap_with_vm.py b/scripts/stl/pcap_with_vm.py index 7cf2906b..4e85bdf4 100644 --- a/scripts/stl/pcap_with_vm.py +++ b/scripts/stl/pcap_with_vm.py @@ -34,7 +34,7 @@ class STLPcap(object): ipg_usec = 10.0, loop_count = 5, ip_src_range = None, - ip_dst_range = {'start' : '10.0.0.1', 'end': '10.0.0.254'}, + ip_dst_range = {'start' : '16.0.0.1', 'end': '16.0.0.254'}, **kwargs): vm = self.create_vm(ip_src_range, ip_dst_range) diff --git a/scripts/stl/udp_1pkt_simple_test.py b/scripts/stl/udp_1pkt_simple_test.py index 3915412d..5f08af9d 100644 --- a/scripts/stl/udp_1pkt_simple_test.py +++ b/scripts/stl/udp_1pkt_simple_test.py @@ -15,7 +15,7 @@ class STLS1(object): base_pkt_a = Ether()/IP(dst="48.0.0.1",options=IPOption(b'\x01\x01\x01\x00'))/UDP(dport=12,sport=1025) vm1 = STLScVmRaw([ - STLVmFlowVar(name="src",min_value="10.0.0.1",max_value="10.0.0.10",size=4,op="inc"), + STLVmFlowVar(name="src",min_value="16.0.0.1",max_value="16.0.0.10",size=4,op="inc"), STLVmWrFlowVar(fv_name="src",pkt_offset= "IP.src"), # checksum STLVmFixIpv4(offset = "IP") diff --git a/scripts/stl/udp_1pkt_simple_test2.py b/scripts/stl/udp_1pkt_simple_test2.py index 617d98b3..190e5439 100644 --- a/scripts/stl/udp_1pkt_simple_test2.py +++ b/scripts/stl/udp_1pkt_simple_test2.py @@ -15,7 +15,7 @@ class STLS1(object): base_pkt_a = Ether()/IP()/IPv6()/IP(dst="48.0.0.1",options=IPOption(b'\x01\x01\x01\x00'))/UDP(dport=12,sport=1025) vm1 = STLScVmRaw([ - STLVmFlowVar(name="src",min_value="10.0.0.1",max_value="10.0.0.10",size=4,op="inc"), + STLVmFlowVar(name="src",min_value="16.0.0.1",max_value="16.0.0.10",size=4,op="inc"), STLVmWrFlowVar(fv_name="src",pkt_offset= "IP:1.src"), # checksum STLVmFixIpv4(offset = "IP:1") -- cgit 1.2.3-korg From 6cc14297a730765a83691a2efcf6a6b18a864405 Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 10 Apr 2016 16:03:30 +0300 Subject: factor was broken --- .../automation/regression/functional_tests/stl_basic_tests.py | 2 +- src/stateless/cp/trex_streams_compiler.cpp | 10 ++++------ src/stateless/cp/trex_streams_compiler.h | 2 -- 3 files changed, 5 insertions(+), 9 deletions(-) (limited to 'scripts/automation') diff --git a/scripts/automation/regression/functional_tests/stl_basic_tests.py b/scripts/automation/regression/functional_tests/stl_basic_tests.py index c8a51f6a..ecb7b465 100644 --- a/scripts/automation/regression/functional_tests/stl_basic_tests.py +++ b/scripts/automation/regression/functional_tests/stl_basic_tests.py @@ -305,6 +305,6 @@ class CStlBasic_Test(functional_general_test.CGeneralFunctional_Test): ] for mc_test in mc_tests: - rc = self.run_sim(mc_test, output = None, options = '--test_multi_core --limit=3840', silent = True) + rc = self.run_sim(mc_test, output = None, options = '--test_multi_core --limit=3840 -m 27kpps', silent = True) assert_equal(rc, True) diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index 520868c4..d1cffbb7 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -550,17 +550,17 @@ TrexStreamsCompiler::compile_stream(TrexStream *stream, // change the packet kept in the stream). We want the state to be saved in the original stream. get_stateless_obj()->m_rx_flow_stat.copy_state(fixed_rx_flow_stat_stream, stream); + fixed_rx_flow_stat_stream->update_rate_factor(factor); + /* can this stream be split to many cores ? */ if ( (dp_core_count == 1) || (!stream->is_splitable(dp_core_count)) ) { compile_stream_on_single_core(fixed_rx_flow_stat_stream, - factor, dp_core_count, objs, new_id, new_next_id); } else { compile_stream_on_all_cores(fixed_rx_flow_stat_stream, - factor, dp_core_count, objs, new_id, @@ -576,7 +576,6 @@ TrexStreamsCompiler::compile_stream(TrexStream *stream, */ void TrexStreamsCompiler::compile_stream_on_all_cores(TrexStream *stream, - double factor, uint8_t dp_core_count, std::vector &objs, int new_id, @@ -589,7 +588,7 @@ TrexStreamsCompiler::compile_stream_on_all_cores(TrexStream *stream, int remainder_left = burst_remainder; /* this is the stream base IPG (pre split) */ - double base_ipg_sec = factor * stream->get_ipg_sec(); + double base_ipg_sec = stream->get_ipg_sec(); /* for each core - creates its own version of the stream */ @@ -607,7 +606,7 @@ TrexStreamsCompiler::compile_stream_on_all_cores(TrexStream *stream, dp_stream->m_burst_total_pkts = per_core_burst_total_pkts; /* rate is slower * dp_core_count */ - dp_stream->update_rate_factor(factor / dp_core_count); + dp_stream->update_rate_factor(1.0 / dp_core_count); if (remainder_left > 0) { @@ -641,7 +640,6 @@ TrexStreamsCompiler::compile_stream_on_all_cores(TrexStream *stream, */ void TrexStreamsCompiler::compile_stream_on_single_core(TrexStream *stream, - double factor, uint8_t dp_core_count, std::vector &objs, int new_id, diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index d910f216..23b06d06 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -147,14 +147,12 @@ private: GraphNodeMap &nodes); void compile_stream_on_single_core(TrexStream *stream, - double factor, uint8_t dp_core_count, std::vector &objs, int new_id, int new_next_id); void compile_stream_on_all_cores(TrexStream *stream, - double factor, uint8_t dp_core_count, std::vector &objs, int new_id, -- cgit 1.2.3-korg