From 82e65a02d2f9bdab552521a4859795937821f1be Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 3 Jan 2016 07:09:23 -0500 Subject: simulation end to end --- src/sim/trex_sim.h | 132 +++++++++ src/sim/trex_sim_stateful.cpp | 599 +++++++++++++++++++++++++++++++++++++++++ src/sim/trex_sim_stateless.cpp | 210 +++++++++++++++ 3 files changed, 941 insertions(+) create mode 100644 src/sim/trex_sim.h create mode 100644 src/sim/trex_sim_stateful.cpp create mode 100644 src/sim/trex_sim_stateless.cpp (limited to 'src/sim') diff --git a/src/sim/trex_sim.h b/src/sim/trex_sim.h new file mode 100644 index 00000000..d997e2f5 --- /dev/null +++ b/src/sim/trex_sim.h @@ -0,0 +1,132 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 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_SIM_H__ +#define __TREX_SIM_H__ + +#include +#include +#include + +int gtest_main(int argc, char **argv); + +class TrexStateless; +class TrexPublisher; +class DpToCpHandler; + +/** + * interface for a sim target + * + */ +class SimInterface { +public: + + SimInterface() { + + time_init(); + CGlobalInfo::m_socket.Create(0); + CGlobalInfo::init_pools(1000); + assert( CMsgIns::Ins()->Create(4) ); + } + + virtual ~SimInterface() { + + CMsgIns::Ins()->Free(); + CGlobalInfo::free_pools(); + CGlobalInfo::m_socket.Delete(); + } + + +}; + +/** + * gtest target + * + * @author imarom (28-Dec-15) + */ +class SimGtest : public SimInterface { +public: + + int run(int argc, char **argv) { + return gtest_main(argc, argv); + } +}; + + + +/** + * stateful target + * + */ +class SimStateful : public SimInterface { + +public: + int run(); +}; + + + +/** + * target for sim stateless + * + * @author imarom (28-Dec-15) + */ +class SimStateless : public SimInterface { + +public: + static SimStateless& get_instance() { + static SimStateless instance; + return instance; + } + + + int run(const std::string &json_filename, const std::string &out_filename); + + TrexStateless * get_stateless_obj() { + return m_trex_stateless; + } + + void set_verbose(bool enable) { + m_verbose = enable; + } + +private: + SimStateless(); + ~SimStateless(); + + 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(); + + bool is_verbose() { + return m_verbose; + } + + TrexStateless *m_trex_stateless; + DpToCpHandler *m_dp_to_cp_handler; + TrexPublisher *m_publisher; + CFlowGenList m_fl; + CErfIFStl m_erf_vif; + bool m_verbose; +}; + +#endif /* __TREX_SIM_H__ */ diff --git a/src/sim/trex_sim_stateful.cpp b/src/sim/trex_sim_stateful.cpp new file mode 100644 index 00000000..35c17d6e --- /dev/null +++ b/src/sim/trex_sim_stateful.cpp @@ -0,0 +1,599 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 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 "trex_sim.h" + +static int cores = 1; + +#ifdef LINUX + + + +#include + +struct per_thread_t { + pthread_t tid; +}; + +#define MAX_THREADS 200 +static per_thread_t tr_info[MAX_THREADS]; + + +////////////// + +struct test_t_info1 { + CPreviewMode * preview_info; + CFlowGenListPerThread * thread_info; + uint32_t thread_id; +}; + +void * thread_task(void *info){ + + test_t_info1 * obj =(test_t_info1 *)info; + + CFlowGenListPerThread * lpt=obj->thread_info; + + printf("start thread %d \n",obj->thread_id); + //delay(obj->thread_id *3000); + printf("-->start thread %d \n",obj->thread_id); + if (1/*obj->thread_id ==3*/) { + + char buf[100]; + sprintf(buf,"my%d.erf",obj->thread_id); + lpt->start_generate_stateful(buf,*obj->preview_info); + lpt->m_node_gen.DumpHist(stdout); + printf("end thread %d \n",obj->thread_id); + } + + return (NULL); +} + + +void test_load_list_of_cap_files_linux(CParserOption * op){ + + CFlowGenList fl; + //CNullIF erf_vif; + //CErfIF erf_vif; + + fl.Create(); + + fl.load_from_yaml(op->cfg_file,cores); + fl.DumpPktSize(); + + + fl.generate_p_thread_info(cores); + CFlowGenListPerThread * lpt; + + /* set the ERF file */ + //fl.set_vif_all(&erf_vif); + + int i; + for (i=0; ipreview_info =&op->preview; + obj->thread_info = fl.m_threads_info[i]; + obj->thread_id = i; + CNullIF * erf_vif = new CNullIF(); + //CErfIF * erf_vif = new CErfIF(); + + lpt->set_vif(erf_vif); + + assert(pthread_create( &tr_info[i].tid, NULL, thread_task, obj)==0); + } + + for (i=0; icfg_file,NUM); + fl.DumpPktSize(); + + + fl.generate_p_thread_info(NUM); + CFlowGenListPerThread * lpt; + + /* set the ERF file */ + //fl.set_vif_all(&erf_vif); + + int i; + for (i=0; istart_generate_stateful(buf,op->preview); + lpt->m_node_gen.DumpHist(stdout); + } + //sprintf(buf,"my%d.erf",7); + //lpt=fl.m_threads_info[7]; + + //fl.Dump(stdout); + fl.Delete(); +} + +int load_list_of_cap_files(CParserOption * op){ + CFlowGenList fl; + fl.Create(); + fl.load_from_yaml(op->cfg_file,1); + if ( op->preview.getVMode() >0 ) { + fl.DumpCsv(stdout); + } + uint32_t start= os_get_time_msec(); + + CErfIF erf_vif; + //CNullIF erf_vif; + + fl.generate_p_thread_info(1); + CFlowGenListPerThread * lpt; + lpt=fl.m_threads_info[0]; + lpt->set_vif(&erf_vif); + + if ( (op->preview.getVMode() >1) || op->preview.getFileWrite() ) { + lpt->start_generate_stateful(op->out_file,op->preview); + } + + lpt->m_node_gen.DumpHist(stdout); + + uint32_t stop= os_get_time_msec(); + printf(" d time = %ul %ul \n",stop-start,os_get_time_freq()); + fl.Delete(); + return (0); +} + + +int test_dns(){ + + time_init(); + CGlobalInfo::init_pools(1000); + + CParserOption po ; + + //po.cfg_file = "cap2/dns.yaml"; + //po.cfg_file = "cap2/sfr3.yaml"; + po.cfg_file = "cap2/sfr.yaml"; + + po.preview.setVMode(0); + po.preview.setFileWrite(true); + #ifdef LINUX + test_load_list_of_cap_files_linux(&po); + #else + test_load_list_of_cap_files(&po); + #endif + return (0); +} + +void test_pkt_mbuf(void); + +void test_compare_files(void); + +#if 0 +static int b=0; +static int c=0; +static int d=0; + +int test_instructions(){ + int i; + for (i=0; i<100000;i++) { + b+=b+1; + c+=+b+c+1; + d+=+(b*2+1); + } + return (b+c+d); +} + +#include +#endif + + +void update_tcp_seq_num(CCapFileFlowInfo * obj, + int pkt_id, + int size_change){ + CFlowPktInfo * pkt=obj->GetPacket(pkt_id); + if ( pkt->m_pkt_indication.m_desc.IsUdp() ){ + /* nothing to do */ + return; + } + + bool o_init=pkt->m_pkt_indication.m_desc.IsInitSide(); + TCPHeader * tcp ; + int s= (int)obj->Size(); + int i; + + for (i=pkt_id+1; iGetPacket(i); + tcp=pkt->m_pkt_indication.l4.m_tcp; + bool init=pkt->m_pkt_indication.m_desc.IsInitSide(); + if (init == o_init) { + /* same dir update the seq number */ + tcp->setSeqNumber (tcp->getSeqNumber ()+size_change); + + }else{ + /* update the ack number */ + tcp->setAckNumber (tcp->getAckNumber ()+size_change); + } + } +} + + + +void change_pkt_len(CCapFileFlowInfo * obj,int pkt_id, int size ){ + CFlowPktInfo * pkt=obj->GetPacket(pkt_id); + + /* enlarge the packet size by 9 */ + + char * p=pkt->m_packet->append(size); + /* set it to 0xaa*/ + memmove(p+size-4,p-4,4); /* CRCbytes */ + memset(p-4,0x0a,size); + + /* refresh the pointers */ + pkt->m_pkt_indication.RefreshPointers(); + + IPHeader * ipv4 = pkt->m_pkt_indication.l3.m_ipv4; + ipv4->updateTotalLength (ipv4->getTotalLength()+size ); + + /* update seq numbers if needed */ + update_tcp_seq_num(obj,pkt_id,size); +} + +void dump_tcp_seq_num_(CCapFileFlowInfo * obj){ + int s= (int)obj->Size(); + int i; + uint32_t i_seq; + uint32_t r_seq; + + CFlowPktInfo * pkt=obj->GetPacket(0); + TCPHeader * tcp = pkt->m_pkt_indication.l4.m_tcp; + i_seq=tcp->getSeqNumber (); + + pkt=obj->GetPacket(1); + tcp = pkt->m_pkt_indication.l4.m_tcp; + r_seq=tcp->getSeqNumber (); + + for (i=2; iGetPacket(i); + tcp=pkt->m_pkt_indication.l4.m_tcp; + bool init=pkt->m_pkt_indication.m_desc.IsInitSide(); + seq=tcp->getSeqNumber (); + ack=tcp->getAckNumber (); + if (init) { + seq=seq-i_seq; + ack=ack-r_seq; + }else{ + seq=seq-r_seq; + ack=ack-i_seq; + } + printf(" %4d ",i); + if (!init) { + printf(" "); + } + printf(" %s seq: %4d ack : %4d \n",init?"I":"R",seq,ack); + } +} + + +int manipolate_capfile() { + time_init(); + CGlobalInfo::init_pools(1000); + + CCapFileFlowInfo flow_info; + flow_info.Create(); + + flow_info.load_cap_file("avl/delay_10_rtsp_0.pcap",0,0); + + change_pkt_len(&flow_info,4-1 ,6); + change_pkt_len(&flow_info,5-1 ,6); + change_pkt_len(&flow_info,6-1 ,6+2); + change_pkt_len(&flow_info,7-1 ,4); + change_pkt_len(&flow_info,8-1 ,6+2); + change_pkt_len(&flow_info,9-1 ,4); + change_pkt_len(&flow_info,10-1,6); + change_pkt_len(&flow_info,13-1,6); + change_pkt_len(&flow_info,16-1,6); + change_pkt_len(&flow_info,19-1,6); + + flow_info.save_to_erf("exp/c.pcap",1); + + return (1); +} + +int manipolate_capfile_sip() { + time_init(); + CGlobalInfo::init_pools(1000); + + CCapFileFlowInfo flow_info; + flow_info.Create(); + + flow_info.load_cap_file("avl/delay_10_sip_0.pcap",0,0); + + change_pkt_len(&flow_info,1-1 ,6+6); + change_pkt_len(&flow_info,2-1 ,6+6); + + flow_info.save_to_erf("exp/delay_10_sip_0_fixed.pcap",1); + + return (1); +} + +int manipolate_capfile_sip1() { + time_init(); + CGlobalInfo::init_pools(1000); + + CCapFileFlowInfo flow_info; + flow_info.Create(); + + flow_info.load_cap_file("avl/delay_sip_0.pcap",0,0); + flow_info.GetPacket(1); + + change_pkt_len(&flow_info,1-1 ,6+6+10); + + change_pkt_len(&flow_info,2-1 ,6+6+10); + + flow_info.save_to_erf("exp/delay_sip_0_fixed_1.pcap",1); + + return (1); +} + + +class CMergeCapFileRec { +public: + + CCapFileFlowInfo m_cap; + + int m_index; + int m_limit_number_of_packets; /* limit number of packets */ + bool m_stop; /* Do we have more packets */ + + double m_offset; /* offset should be positive */ + double m_start_time; + +public: + bool Create(std::string cap_file,double offset); + void Delete(); + void IncPacket(); + bool GetCurPacket(double & time); + CPacketIndication * GetUpdatedPacket(); + + void Dump(FILE *fd,int _id); +}; + + +void CMergeCapFileRec::Dump(FILE *fd,int _id){ + double time = 0.0; + bool stop=GetCurPacket(time); + fprintf (fd," id:%2d stop : %d index:%4d %3.4f \n",_id,stop?1:0,m_index,time); +} + + +CPacketIndication * CMergeCapFileRec::GetUpdatedPacket(){ + double t1; + assert(GetCurPacket(t1)==false); + CFlowPktInfo * pkt = m_cap.GetPacket(m_index); + pkt->m_pkt_indication.m_packet->set_new_time(t1); + return (&pkt->m_pkt_indication); +} + + +bool CMergeCapFileRec::GetCurPacket(double & time){ + if (m_stop) { + return(true); + } + CFlowPktInfo * pkt = m_cap.GetPacket(m_index); + time= (pkt->m_packet->get_time() -m_start_time + m_offset); + return (false); +} + +void CMergeCapFileRec::IncPacket(){ + m_index++; + if ( (m_limit_number_of_packets) && (m_index > m_limit_number_of_packets ) ) { + m_stop=true; + return; + } + + if ( m_index == (int)m_cap.Size() ) { + m_stop=true; + } +} + +void CMergeCapFileRec::Delete(){ + m_cap.Delete(); +} + +bool CMergeCapFileRec::Create(std::string cap_file, + double offset){ + m_cap.Create(); + m_cap.load_cap_file(cap_file,0,0); + CFlowPktInfo * pkt = m_cap.GetPacket(0); + + m_index=0; + m_stop=false; + m_limit_number_of_packets =0; + m_start_time = pkt->m_packet->get_time() ; + m_offset = offset; + + return (true); +} + + + +#define MERGE_CAP_FILES (2) + +class CMergeCapFile { +public: + bool Create(); + void Delete(); + bool run_merge(std::string to_cap_file); +private: + void append(int _cap_id); + +public: + CMergeCapFileRec m[MERGE_CAP_FILES]; + CCapFileFlowInfo m_results; +}; + +bool CMergeCapFile::Create(){ + m_results.Create(); + return(true); +} + +void CMergeCapFile::Delete(){ + m_results.Delete(); +} + +void CMergeCapFile::append(int _cap_id){ + CPacketIndication * lp=m[_cap_id].GetUpdatedPacket(); + lp->m_packet->Dump(stdout,0); + m_results.Append(lp); +} + + +bool CMergeCapFile::run_merge(std::string to_cap_file){ + + int i=0; + int cnt=0; + while ( true ) { + int min_index=0; + double min_time; + + fprintf(stdout," --------------\n"); + fprintf(stdout," pkt : %d \n",cnt); + for (i=0; i +#include +#include +#include + +using namespace std; + +TrexStateless * get_stateless_obj() { + return SimStateless::get_instance().get_stateless_obj(); +} + + +/** + * handler for DP to CP messages + * + * @author imarom (19-Nov-15) + */ +class DpToCpHandler { +public: + virtual void handle(TrexStatelessDpToCpMsgBase *msg) = 0; +}; + +/************************ + * + * stateless sim object + * +************************/ +class SimPublisher : public TrexPublisher { +public: + + /* override create */ + bool Create(uint16_t port, bool disable) { + return true; + } + + void Delete() { + + } + + void publish_json(const std::string &s) { + } + + virtual ~SimPublisher() { + } +}; + +/************************ + * + * stateless sim object + * +************************/ + +SimStateless::SimStateless() { + m_trex_stateless = NULL; + m_publisher = NULL; + m_dp_to_cp_handler = NULL; + m_verbose = false; + + /* override ownership checks */ + TrexRpcCommand::test_set_override_ownership(true); +} + + +int +SimStateless::run(const string &json_filename, const string &out_filename) { + prepare_dataplane(); + prepare_control_plane(); + + execute_json(json_filename); + run_dp(out_filename); + + flush_dp_to_cp_messages(); + + return 0; +} + + +SimStateless::~SimStateless() { + if (m_trex_stateless) { + delete m_trex_stateless; + m_trex_stateless = NULL; + } + + if (m_publisher) { + delete m_publisher; + m_publisher = NULL; + } + + m_fl.Delete(); +} + +/** + * prepare control plane for test + * + * @author imarom (28-Dec-15) + */ +void +SimStateless::prepare_control_plane() { + TrexStatelessCfg cfg; + + m_publisher = new SimPublisher(); + + TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_MOCK, 0); + + cfg.m_port_count = 4; + 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_publisher = m_publisher; + + m_trex_stateless = new TrexStateless(cfg); + + m_trex_stateless->launch_control_plane(); + + for (auto &port : m_trex_stateless->get_port_list()) { + port->acquire("test", 0, true); + } + +} + + +/** + * prepare the data plane for test + * + */ +void +SimStateless::prepare_dataplane() { + + m_fl.Create(); + m_fl.generate_p_thread_info(1); + m_fl.m_threads_info[0]->set_vif(&m_erf_vif); +} + + + +void +SimStateless::execute_json(const std::string &json_filename) { + + std::ifstream test(json_filename); + std::stringstream buffer; + buffer << test.rdbuf(); + + std::string rep = m_trex_stateless->get_rpc_server()->test_inject_request(buffer.str()); + + Json::Value root; + Json::Reader reader; + reader.parse(rep, root, false); + + if (is_verbose()) { + std::cout << "server response: \n\n" << root << "\n\n"; + } +} + +void +SimStateless::run_dp(const std::string &out_filename) { + + CFlowGenListPerThread *lpt = m_fl.m_threads_info[0]; + + 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"; +} + +void +SimStateless::flush_dp_to_cp_messages() { + + CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(0); + + while ( true ) { + CGenNode * node = NULL; + if (ring->Dequeue(node) != 0) { + break; + } + assert(node); + + TrexStatelessDpToCpMsgBase * msg = (TrexStatelessDpToCpMsgBase *)node; + if (m_dp_to_cp_handler) { + m_dp_to_cp_handler->handle(msg); + } + + delete msg; + } + +} -- cgit From e134270a3bcf3c9498a2926ffea1d7bb0d4960eb Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 4 Jan 2016 06:57:45 -0500 Subject: a script to inject simulation stateless files --- src/sim/trex_sim.h | 3 +++ src/sim/trex_sim_stateless.cpp | 45 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) (limited to 'src/sim') diff --git a/src/sim/trex_sim.h b/src/sim/trex_sim.h index d997e2f5..02f62d79 100644 --- a/src/sim/trex_sim.h +++ b/src/sim/trex_sim.h @@ -24,6 +24,7 @@ limitations under the License. #include #include #include +#include int gtest_main(int argc, char **argv); @@ -117,6 +118,8 @@ private: void run_dp(const std::string &out_filename); void flush_dp_to_cp_messages(); + void validate_response(const Json::Value &resp); + bool is_verbose() { return m_verbose; } diff --git a/src/sim/trex_sim_stateless.cpp b/src/sim/trex_sim_stateless.cpp index dd81a591..9803ccbc 100644 --- a/src/sim/trex_sim_stateless.cpp +++ b/src/sim/trex_sim_stateless.cpp @@ -24,6 +24,8 @@ limitations under the License. #include #include #include +#include +#include using namespace std; @@ -32,6 +34,17 @@ TrexStateless * get_stateless_obj() { } +class SimRunException : public std::runtime_error +{ +public: + SimRunException() : std::runtime_error("") { + + } + SimRunException(const std::string &what) : std::runtime_error(what) { + } +}; + + /** * handler for DP to CP messages * @@ -88,7 +101,13 @@ SimStateless::run(const string &json_filename, const string &out_filename) { prepare_dataplane(); prepare_control_plane(); - execute_json(json_filename); + try { + execute_json(json_filename); + } catch (const SimRunException &e) { + std::cout << "*** test failed ***\n\n" << e.what() << "\n"; + exit(-1); + } + run_dp(out_filename); flush_dp_to_cp_messages(); @@ -172,8 +191,32 @@ SimStateless::execute_json(const std::string &json_filename) { if (is_verbose()) { std::cout << "server response: \n\n" << root << "\n\n"; } + + validate_response(root); + } +void +SimStateless::validate_response(const Json::Value &resp) { + std::stringstream ss; + + if (resp.isArray()) { + for (const auto &single : resp) { + if (single["error"] != Json::nullValue) { + ss << "failed with:\n\n" << single["error"] << "\n\n"; + throw SimRunException(ss.str()); + } + } + } else { + if (resp["error"] != Json::nullValue) { + ss << "failed with:\n\n" << resp["error"] << "\n\n"; + throw SimRunException(ss.str()); + } + } + +} + + void SimStateless::run_dp(const std::string &out_filename) { -- cgit 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 --- src/sim/trex_sim.h | 17 ++++++-- src/sim/trex_sim_stateful.cpp | 1 + src/sim/trex_sim_stateless.cpp | 97 +++++++++++++++++++++++++++++++++++------- 3 files changed, 96 insertions(+), 19 deletions(-) (limited to 'src/sim') 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; } - } -- cgit