From 857bdcf05a920b99e1cf180c700176b04801da00 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 4 Jan 2016 09:49:37 -0500 Subject: some additions to the stateless simulation mode --- .../client/trex_stateless_sim.py | 32 ++++++- scripts/stl/burst_1pkt_vm.yaml | 34 ++++++++ src/main.cpp | 69 +++++++++++---- src/sim/trex_sim.h | 17 +++- src/sim/trex_sim_stateful.cpp | 1 + src/sim/trex_sim_stateless.cpp | 97 ++++++++++++++++++---- src/stateless/dp/trex_stateless_dp_core.cpp | 7 +- src/stateless/dp/trex_stateless_dp_core.h | 6 +- 8 files changed, 221 insertions(+), 42 deletions(-) create mode 100644 scripts/stl/burst_1pkt_vm.yaml diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_sim.py b/scripts/automation/trex_control_plane/client/trex_stateless_sim.py index 7829af60..7655b27c 100644 --- a/scripts/automation/trex_control_plane/client/trex_stateless_sim.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_sim.py @@ -38,13 +38,15 @@ import os class SimRun(object): - def __init__ (self, yaml_file, dp_core_count, core_index, packet_limit, output_filename): + def __init__ (self, yaml_file, dp_core_count, core_index, packet_limit, output_filename, is_valgrind, is_gdb): self.yaml_file = yaml_file self.output_filename = output_filename self.dp_core_count = dp_core_count self.core_index = core_index self.packet_limit = packet_limit + self.is_valgrind = is_valgrind + self.is_gdb = is_gdb # dummies self.handler = 0 @@ -97,7 +99,14 @@ class SimRun(object): f.close() try: - subprocess.call(['bp-sim-64-debug', '--sl', '-f', f.name, '-o', self.output_filename]) + cmd = ['bp-sim-64-debug', '--sl', '--cores', str(self.dp_core_count), '--core_index', str(self.core_index), '-f', f.name, '-o', self.output_filename] + if self.is_valgrind: + cmd = ['valgrind', '--leak-check=full'] + cmd + elif self.is_gdb: + cmd = ['gdb', '--args'] + cmd + + subprocess.call(cmd) + finally: os.unlink(f.name) @@ -149,6 +158,17 @@ def setParserOptions(): type = unsigned_int) + group = parser.add_mutually_exclusive_group() + + group.add_argument("-x", "--valgrind", + help = "run under valgrind [default is False]", + action = "store_true", + default = False) + + group.add_argument("-g", "--gdb", + help = "run under GDB [default is False]", + action = "store_true", + default = False) return parser @@ -165,7 +185,13 @@ def main (): validate_args(parser, options) - r = SimRun(options.input_file, options.cores, options.core_index, options.limit, options.output_file) + r = SimRun(options.input_file, + options.cores, + options.core_index, + options.limit, + options.output_file, + options.valgrind, + options.gdb) r.run() diff --git a/scripts/stl/burst_1pkt_vm.yaml b/scripts/stl/burst_1pkt_vm.yaml new file mode 100644 index 00000000..e202b42d --- /dev/null +++ b/scripts/stl/burst_1pkt_vm.yaml @@ -0,0 +1,34 @@ +### Single stream UDP packet, 64B ### +##################################### +- name: udp_64B + stream: + self_start: True + packet: + binary: stl/udp_64B_no_crc.pcap # pcap should not include CRC + mode: + type: single_burst + total_pkts: 100 + pps: 100 + rx_stats: [] + + vm: + instructions: [ + { + "init_value" : 100, + "max_value" : 5000, + "min_value" : 100, + "name" : "l3_src", + "op" : "inc", + "size" : 2, + "type" : "flow_var" + }, + { + "add_value" : 1, + "is_big_endian" : true, + "name" : "l3_src", + "pkt_offset" : 34, + "type" : "write_flow_var" + } + ] + split_by_var: "l3_src" + diff --git a/src/main.cpp b/src/main.cpp index 3fa7c7c3..ba6e258a 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,7 +35,7 @@ using namespace std; // An enum for all the option types enum { OPT_HELP, OPT_CFG, OPT_NODE_DUMP, OP_STATS, OPT_FILE_OUT, OPT_UT, OPT_PCAP, OPT_IPV6, OPT_MAC_FILE, - OPT_SL}; + OPT_SL, OPT_DP_CORE_COUNT, OPT_DP_CORE_INDEX}; @@ -59,18 +59,21 @@ typedef enum { */ static CSimpleOpt::SOption parser_options[] = { - { OPT_HELP, "-?", SO_NONE }, - { OPT_HELP, "-h", SO_NONE }, - { OPT_HELP, "--help", SO_NONE }, - { OPT_UT, "--ut", SO_NONE }, - { OP_STATS, "-s", SO_NONE }, - { OPT_CFG, "-f", SO_REQ_SEP}, - { OPT_MAC_FILE, "--mac", SO_REQ_SEP}, - { OPT_FILE_OUT , "-o", SO_REQ_SEP }, - { OPT_NODE_DUMP , "-v", SO_REQ_SEP }, - { OPT_PCAP, "--pcap", SO_NONE }, - { OPT_IPV6, "--ipv6", SO_NONE }, - { OPT_SL, "--sl", SO_NONE }, + { OPT_HELP, "-?", SO_NONE }, + { OPT_HELP, "-h", SO_NONE }, + { OPT_HELP, "--help", SO_NONE }, + { OPT_UT, "--ut", SO_NONE }, + { OP_STATS, "-s", SO_NONE }, + { OPT_CFG, "-f", SO_REQ_SEP }, + { OPT_MAC_FILE, "--mac", SO_REQ_SEP }, + { OPT_FILE_OUT , "-o", SO_REQ_SEP }, + { OPT_NODE_DUMP , "-v", SO_REQ_SEP }, + { OPT_PCAP, "--pcap", SO_NONE }, + { OPT_IPV6, "--ipv6", SO_NONE }, + { OPT_SL, "--sl", SO_NONE }, + { OPT_DP_CORE_COUNT, "--cores", SO_REQ_SEP }, + { OPT_DP_CORE_INDEX, "--core_index", SO_REQ_SEP }, + SO_END_OF_OPTIONS }; @@ -113,7 +116,13 @@ static int usage(){ } -static int parse_options(int argc, char *argv[], CParserOption* po, opt_type_e &type) { +static int parse_options(int argc, + char *argv[], + CParserOption* po, + opt_type_e &type, + int &dp_core_count, + int &dp_core_index) { + CSimpleOpt args(argc, argv, parser_options); int a=0; @@ -124,6 +133,9 @@ static int parse_options(int argc, char *argv[], CParserOption* po, opt_type_e & /* by default - type is stateful */ type = OPT_TYPE_SF; + dp_core_count = 1; + dp_core_index = 0; + while ( args.Next() ){ if (args.LastError() == SO_SUCCESS) { switch (args.OptionId()) { @@ -166,6 +178,14 @@ static int parse_options(int argc, char *argv[], CParserOption* po, opt_type_e & po->preview.set_pcap_mode_enable(true); break; + case OPT_DP_CORE_COUNT: + dp_core_count = atoi(args.OptionArg()); + break; + + case OPT_DP_CORE_INDEX: + dp_core_index = atoi(args.OptionArg()); + break; + default: usage(); return -1; @@ -194,6 +214,21 @@ static int parse_options(int argc, char *argv[], CParserOption* po, opt_type_e & return -1; } } + + if (dp_core_count != -1) { + if ( (dp_core_count < 1) || (dp_core_count > 8) ) { + printf("dp core count must be a value between 1 and 8\n"); + return (-1); + } + } + + if (dp_core_index != -1) { + if ( (dp_core_index < 0) || (dp_core_index >= dp_core_count) ) { + printf("dp core count must be a value between 0 and cores - 1\n"); + return (-1); + } + } + return 0; } @@ -201,8 +236,10 @@ static int parse_options(int argc, char *argv[], CParserOption* po, opt_type_e & int main(int argc , char * argv[]){ opt_type_e type; + int dp_core_count; + int dp_core_index; - if ( parse_options(argc, argv, &CGlobalInfo::m_options , type) != 0) { + if ( parse_options(argc, argv, &CGlobalInfo::m_options , type, dp_core_count, dp_core_index) != 0) { exit(-1); } @@ -222,7 +259,7 @@ int main(int argc , char * argv[]){ case OPT_TYPE_SL: { SimStateless &st = SimStateless::get_instance(); - return st.run(CGlobalInfo::m_options.cfg_file, CGlobalInfo::m_options.out_file); + return st.run(CGlobalInfo::m_options.cfg_file, CGlobalInfo::m_options.out_file, 2, dp_core_count, dp_core_index); } } } diff --git a/src/sim/trex_sim.h b/src/sim/trex_sim.h index 02f62d79..cc02fd75 100644 --- a/src/sim/trex_sim.h +++ b/src/sim/trex_sim.h @@ -44,7 +44,6 @@ public: time_init(); CGlobalInfo::m_socket.Create(0); CGlobalInfo::init_pools(1000); - assert( CMsgIns::Ins()->Create(4) ); } virtual ~SimInterface() { @@ -66,6 +65,7 @@ class SimGtest : public SimInterface { public: int run(int argc, char **argv) { + assert( CMsgIns::Ins()->Create(4) ); return gtest_main(argc, argv); } }; @@ -98,7 +98,11 @@ public: } - int run(const std::string &json_filename, const std::string &out_filename); + int run(const std::string &json_filename, + const std::string &out_filename, + int port_count, + int dp_core_count, + int dp_core_index); TrexStateless * get_stateless_obj() { return m_trex_stateless; @@ -115,8 +119,11 @@ private: void prepare_control_plane(); void prepare_dataplane(); void execute_json(const std::string &json_filename); + void run_dp(const std::string &out_filename); - void flush_dp_to_cp_messages(); + void run_dp_core(int core_index, const std::string &out_filename); + + void flush_dp_to_cp_messages_core(int core_index); void validate_response(const Json::Value &resp); @@ -130,6 +137,10 @@ private: CFlowGenList m_fl; CErfIFStl m_erf_vif; bool m_verbose; + + int m_port_count; + int m_dp_core_count; + int m_dp_core_index; }; #endif /* __TREX_SIM_H__ */ diff --git a/src/sim/trex_sim_stateful.cpp b/src/sim/trex_sim_stateful.cpp index 35c17d6e..88698cd1 100644 --- a/src/sim/trex_sim_stateful.cpp +++ b/src/sim/trex_sim_stateful.cpp @@ -595,5 +595,6 @@ int merge_2_cap_files_sip() { int SimStateful::run() { + assert( CMsgIns::Ins()->Create(4) ); return load_list_of_cap_files(&CGlobalInfo::m_options); } diff --git a/src/sim/trex_sim_stateless.cpp b/src/sim/trex_sim_stateless.cpp index 9803ccbc..2821644f 100644 --- a/src/sim/trex_sim_stateless.cpp +++ b/src/sim/trex_sim_stateless.cpp @@ -44,6 +44,33 @@ public: } }; +/*************** hook for platform API **************/ +class SimPlatformApi : public TrexPlatformApi { +public: + SimPlatformApi(int dp_core_count) { + m_dp_core_count = dp_core_count; + } + + virtual uint8_t get_dp_core_count() const { + return m_dp_core_count; + } + + 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_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const { + } + + virtual void port_id_to_cores(uint8_t port_id, std::vector> &cores_id_list) const { + for (int i = 0; i < m_dp_core_count; i++) { + cores_id_list.push_back(std::make_pair(i, 0)); + } + } + +private: + int m_dp_core_count; +}; /** * handler for DP to CP messages @@ -90,6 +117,9 @@ SimStateless::SimStateless() { m_publisher = NULL; m_dp_to_cp_handler = NULL; m_verbose = false; + m_dp_core_count = -1; + m_dp_core_index = -1; + m_port_count = -1; /* override ownership checks */ TrexRpcCommand::test_set_override_ownership(true); @@ -97,7 +127,20 @@ SimStateless::SimStateless() { int -SimStateless::run(const string &json_filename, const string &out_filename) { +SimStateless::run(const string &json_filename, + const string &out_filename, + int port_count, + int dp_core_count, + int dp_core_index) { + + assert(dp_core_count > 0); + assert(dp_core_index >= 0); + assert(dp_core_index < dp_core_count); + + m_dp_core_count = dp_core_count; + m_dp_core_index = dp_core_index; + m_port_count = port_count; + prepare_dataplane(); prepare_control_plane(); @@ -105,13 +148,11 @@ SimStateless::run(const string &json_filename, const string &out_filename) { execute_json(json_filename); } catch (const SimRunException &e) { std::cout << "*** test failed ***\n\n" << e.what() << "\n"; - exit(-1); + return (-1); } run_dp(out_filename); - flush_dp_to_cp_messages(); - return 0; } @@ -143,11 +184,11 @@ SimStateless::prepare_control_plane() { TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_MOCK, 0); - cfg.m_port_count = 4; + cfg.m_port_count = m_port_count; cfg.m_rpc_req_resp_cfg = &rpc_req_resp_cfg; cfg.m_rpc_async_cfg = NULL; cfg.m_rpc_server_verbose = false; - cfg.m_platform_api = new TrexMockPlatformApi(); + cfg.m_platform_api = new SimPlatformApi(m_dp_core_count); cfg.m_publisher = m_publisher; m_trex_stateless = new TrexStateless(cfg); @@ -168,9 +209,15 @@ SimStateless::prepare_control_plane() { void SimStateless::prepare_dataplane() { + CGlobalInfo::m_options.m_expected_portd = m_port_count; + + assert(CMsgIns::Ins()->Create(m_dp_core_count)); m_fl.Create(); - m_fl.generate_p_thread_info(1); - m_fl.m_threads_info[0]->set_vif(&m_erf_vif); + m_fl.generate_p_thread_info(m_dp_core_count); + + for (int i = 0; i < m_dp_core_count; i++) { + m_fl.m_threads_info[i]->set_vif(&m_erf_vif); + } } @@ -220,20 +267,39 @@ SimStateless::validate_response(const Json::Value &resp) { void SimStateless::run_dp(const std::string &out_filename) { - CFlowGenListPerThread *lpt = m_fl.m_threads_info[0]; - + for (int i = 0; i < m_dp_core_count; i++) { + if (i == m_dp_core_index) { + run_dp_core(i, out_filename); + } else { + run_dp_core(i, "/dev/null"); + } + } + + CFlowGenListPerThread *lpt = m_fl.m_threads_info[m_dp_core_index]; + + std::cout << "\n"; + std::cout << "ports: " << m_port_count << "\n"; + std::cout << "cores: " << m_dp_core_count << "\n"; + std::cout << "core index: " << m_dp_core_index << "\n"; + std::cout << "\nwritten " << lpt->m_node_gen.m_cnt << " packets " << "to '" << out_filename << "'\n\n"; +} + +void +SimStateless::run_dp_core(int core_index, const std::string &out_filename) { + + CFlowGenListPerThread *lpt = m_fl.m_threads_info[core_index]; + lpt->start_stateless_simulation_file((std::string)out_filename, CGlobalInfo::m_options.preview); lpt->start_stateless_daemon_simulation(); - flush_dp_to_cp_messages(); - - std::cout << "\nwritten " << lpt->m_node_gen.m_cnt << " packets " << "to '" << out_filename << "'\n\n"; + flush_dp_to_cp_messages_core(core_index); } + void -SimStateless::flush_dp_to_cp_messages() { +SimStateless::flush_dp_to_cp_messages_core(int core_index) { - CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(0); + CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(core_index); while ( true ) { CGenNode * node = NULL; @@ -249,5 +315,4 @@ SimStateless::flush_dp_to_cp_messages() { delete msg; } - } diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index c211b9f5..0a9a88ab 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -353,8 +353,11 @@ void TrexStatelessDpCore::idle_state_loop() { while (m_state == STATE_IDLE) { - periodic_check_for_cp_messages(); - delay(200); + bool had_msg = periodic_check_for_cp_messages(); + /* if no message - backoff for some time */ + if (!had_msg) { + delay(200); + } } } diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index 7dc4a2b2..efdb364c 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -185,12 +185,12 @@ public: * * @author imarom (27-Oct-15) */ - void periodic_check_for_cp_messages() { + bool periodic_check_for_cp_messages() { // doing this inline for performance reasons /* fast path */ if ( likely ( m_ring_from_cp->isEmpty() ) ) { - return; + return false; } while ( true ) { @@ -204,6 +204,8 @@ public: handle_cp_msg(msg); } + return true; + } /* quit the main loop, work in both stateless in stateful, don't free memory trigger from master */ -- cgit 1.2.3-korg