summaryrefslogtreecommitdiffstats
path: root/src/sim
diff options
context:
space:
mode:
authorYaroslav Brustinov <ybrustin@cisco.com>2016-01-05 15:24:33 +0200
committerYaroslav Brustinov <ybrustin@cisco.com>2016-01-05 15:24:33 +0200
commit349d47374639465d58bac37f6e93045a1f9bb718 (patch)
treeba493401f9892105e51d3a3a6f3f7b561e2987b8 /src/sim
parent823b8294539f2e55db09795a7fff03d7be6b6346 (diff)
parent857bdcf05a920b99e1cf180c700176b04801da00 (diff)
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'src/sim')
-rw-r--r--src/sim/trex_sim.h146
-rw-r--r--src/sim/trex_sim_stateful.cpp600
-rw-r--r--src/sim/trex_sim_stateless.cpp318
3 files changed, 1064 insertions, 0 deletions
diff --git a/src/sim/trex_sim.h b/src/sim/trex_sim.h
new file mode 100644
index 00000000..cc02fd75
--- /dev/null
+++ b/src/sim/trex_sim.h
@@ -0,0 +1,146 @@
+/*
+ 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 <string>
+#include <os_time.h>
+#include <bp_sim.h>
+#include <json/json.h>
+
+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);
+ }
+
+ 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) {
+ assert( CMsgIns::Ins()->Create(4) );
+ 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,
+ int port_count,
+ int dp_core_count,
+ int dp_core_index);
+
+ 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 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);
+
+ 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;
+
+ 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
new file mode 100644
index 00000000..88698cd1
--- /dev/null
+++ b/src/sim/trex_sim_stateful.cpp
@@ -0,0 +1,600 @@
+/*
+ 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 <pthread.h>
+
+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; i<cores; i++) {
+ lpt=fl.m_threads_info[i];
+ test_t_info1 * obj = new test_t_info1();
+ obj->preview_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; i<cores; i++) {
+ /* wait for all of them to stop */
+ assert(pthread_join((pthread_t)tr_info[i].tid,NULL )==0);
+ }
+
+ printf("compare files \n");
+ for (i=1; i<cores; i++) {
+
+ CErfCmp cmp;
+ char buf[100];
+ sprintf(buf,"my%d.erf",i);
+ char buf1[100];
+ sprintf(buf1,"my%d.erf",0);
+ if ( cmp.compare(std::string(buf),std::string(buf1)) != true ) {
+ printf(" ERROR cap file is not ex !! \n");
+ assert(0);
+ }
+ printf(" thread %d is ok \n",i);
+ }
+
+ fl.Delete();
+}
+
+
+#endif
+
+/*************************************************************/
+void test_load_list_of_cap_files(CParserOption * op){
+
+ CFlowGenList fl;
+ CNullIF erf_vif;
+
+ fl.Create();
+
+ #define NUM 1
+
+ fl.load_from_yaml(op->cfg_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; i<NUM; i++) {
+ lpt=fl.m_threads_info[i];
+ char buf[100];
+ sprintf(buf,"my%d.erf",i);
+ lpt->start_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 <valgrind/callgrind.h>
+#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; i<s; i++) {
+
+ pkt=obj->GetPacket(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; i<s; i++) {
+ uint32_t seq;
+ uint32_t ack;
+
+ pkt=obj->GetPacket(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<MERGE_CAP_FILES; i++) {
+ m[i].Dump(stdout,i);
+ }
+ fprintf(stdout," --------------\n");
+
+ bool valid = false;
+ for (i=0; i<MERGE_CAP_FILES; i++) {
+ double t1;
+ if ( m[i].GetCurPacket(t1) == false ){
+ /* not in stop */
+ if (!valid) {
+ min_time = t1;
+ min_index = i;
+ valid=true;
+ }else{
+ if (t1 < min_time) {
+ min_time=t1;
+ min_index = i;
+ }
+ }
+
+ }
+ }
+
+ /* nothing to do */
+ if (valid==false) {
+ fprintf(stdout,"nothing to do \n");
+ break;
+ }
+
+ cnt++;
+ fprintf(stdout," choose id %d \n",min_index);
+ append(min_index);
+ m[min_index].IncPacket();
+ };
+
+ m_results.save_to_erf(to_cap_file,1);
+
+ return (true);
+}
+
+
+
+int merge_3_cap_files() {
+ time_init();
+ CGlobalInfo::init_pools(1000);
+
+ CMergeCapFile merger;
+ merger.Create();
+ merger.m[0].Create("exp/c.pcap",0.001);
+ merger.m[1].Create("avl/delay_10_rtp_160k_0.pcap",0.31);
+ merger.m[2].Create("avl/delay_10_rtp_160k_1.pcap",0.311);
+
+ //merger.m[1].Create("avl/delay_10_rtp_250k_0_0.pcap",0.31);
+ //merger.m[1].m_limit_number_of_packets =6;
+ //merger.m[2].Create("avl/delay_10_rtp_250k_1_0.pcap",0.311);
+ //merger.m[2].m_limit_number_of_packets =6;
+
+ merger.run_merge("exp/delay_10_rtp_160k_full.pcap");
+
+ return (0);
+}
+
+int merge_2_cap_files_sip() {
+ time_init();
+ CGlobalInfo::init_pools(1000);
+
+ CMergeCapFile merger;
+ merger.Create();
+ merger.m[0].Create("exp/delay_sip_0_fixed_1.pcap",0.001);
+ merger.m[1].Create("avl/delay_video_call_rtp_0.pcap",0.51);
+ //merger.m[1].m_limit_number_of_packets=7;
+
+ //merger.m[1].Create("avl/delay_10_rtp_250k_0_0.pcap",0.31);
+ //merger.m[1].m_limit_number_of_packets =6;
+ //merger.m[2].Create("avl/delay_10_rtp_250k_1_0.pcap",0.311);
+ //merger.m[2].m_limit_number_of_packets =6;
+
+ merger.run_merge("avl/delay_10_sip_video_call_full.pcap");
+
+ return (0);
+}
+
+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
new file mode 100644
index 00000000..2821644f
--- /dev/null
+++ b/src/sim/trex_sim_stateless.cpp
@@ -0,0 +1,318 @@
+/*
+ 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"
+#include <trex_stateless.h>
+#include <trex_stateless_messaging.h>
+#include <trex_rpc_cmd_api.h>
+#include <json/json.h>
+#include <stdexcept>
+#include <sstream>
+
+using namespace std;
+
+TrexStateless * get_stateless_obj() {
+ return SimStateless::get_instance().get_stateless_obj();
+}
+
+
+class SimRunException : public std::runtime_error
+{
+public:
+ SimRunException() : std::runtime_error("") {
+
+ }
+ SimRunException(const std::string &what) : std::runtime_error(what) {
+ }
+};
+
+/*************** 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<std::pair<uint8_t, uint8_t>> &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
+ *
+ * @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;
+ m_dp_core_count = -1;
+ m_dp_core_index = -1;
+ m_port_count = -1;
+
+ /* override ownership checks */
+ TrexRpcCommand::test_set_override_ownership(true);
+}
+
+
+int
+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();
+
+ try {
+ execute_json(json_filename);
+ } catch (const SimRunException &e) {
+ std::cout << "*** test failed ***\n\n" << e.what() << "\n";
+ return (-1);
+ }
+
+ run_dp(out_filename);
+
+ 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 = 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 SimPlatformApi(m_dp_core_count);
+ 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() {
+
+ 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(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);
+ }
+}
+
+
+
+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";
+ }
+
+ 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) {
+
+ 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_core(core_index);
+}
+
+
+void
+SimStateless::flush_dp_to_cp_messages_core(int core_index) {
+
+ CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(core_index);
+
+ 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;
+ }
+}