From b77fef12a08d6d964e522eea6b2d846dfcc98b08 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 26 Oct 2015 18:13:18 +0200 Subject: RPC control plane now integarted with DPDK --- src/gtest/rpc_test.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/gtest') diff --git a/src/gtest/rpc_test.cpp b/src/gtest/rpc_test.cpp index 250d5342..6b8e3eff 100644 --- a/src/gtest/rpc_test.cpp +++ b/src/gtest/rpc_test.cpp @@ -30,6 +30,8 @@ limitations under the License. using namespace std; +uint16_t gtest_get_mock_server_port(); + class RpcTest : public testing::Test { protected: @@ -44,7 +46,12 @@ protected: m_context = zmq_ctx_new (); m_socket = zmq_socket (m_context, ZMQ_REQ); - zmq_connect (m_socket, "tcp://localhost:5050"); + + std::stringstream ss; + ss << "tcp://localhost:"; + ss << gtest_get_mock_server_port(); + + zmq_connect (m_socket, ss.str().c_str()); } -- cgit 1.2.3-korg From 38dc2db83370ee9d2483a09f4451a5c0f1167cee Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 8 Nov 2015 15:08:07 +0200 Subject: fixed all warnings now compiles with -Wall -Werror --- linux/ws_main.py | 8 ++-- src/bp_gtest.cpp | 17 ++++--- src/bp_sim.cpp | 82 ++++++++++++++++++--------------- src/bp_sim.h | 7 ++- src/common/Network/Packet/IPHeader.cpp | 2 +- src/common/Network/Packet/TCPHeader.cpp | 2 +- src/common/c_common.h | 2 +- src/gtest/trex_stateless_gtest.cpp | 6 +-- src/gtest/tuple_gen_test.cpp | 8 ---- src/main.cpp | 21 +++++---- src/nat_check.cpp | 4 +- src/platform_cfg.cpp | 6 +-- src/rx_check.cpp | 24 ++++++---- src/rx_check_header.cpp | 10 ++-- src/time_histogram.cpp | 6 +-- src/tuple_gen.h | 3 ++ src/utl_json.cpp | 4 +- src/utl_yaml.cpp | 2 + 18 files changed, 119 insertions(+), 95 deletions(-) (limited to 'src/gtest') diff --git a/linux/ws_main.py b/linux/ws_main.py index 951d89b1..d020411a 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -393,11 +393,13 @@ class build_option: build_types = [ - build_option(name = "bp-sim", src = bp, debug_mode= DEBUG_, platform = PLATFORM_64, is_pie = False), - build_option(name = "bp-sim", src = bp, debug_mode= RELEASE_,platform = PLATFORM_64, is_pie = False), + build_option(name = "bp-sim", src = bp, debug_mode= DEBUG_, platform = PLATFORM_64, is_pie = False, + flags = ['-Wall', '-Werror', '-Wno-sign-compare', '-Wno-strict-aliasing']), + build_option(name = "bp-sim", src = bp, debug_mode= RELEASE_,platform = PLATFORM_64, is_pie = False, + flags = ['-Wall', '-Werror', '-Wno-sign-compare', '-Wno-strict-aliasing']), build_option(name = "mock-rpc-server", use = ['zmq'], src = rpc_server_mock, debug_mode= DEBUG_,platform = PLATFORM_64, is_pie = False, - flags = ['-DTREX_RPC_MOCK_SERVER', '-Wall', '-Wno-sign-compare'], + flags = ['-DTREX_RPC_MOCK_SERVER', '-Wall', '-Werror', '-Wno-sign-compare'], rpath = ['.']), ] diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp index e3145f2a..03ab74bd 100755 --- a/src/bp_gtest.cpp +++ b/src/bp_gtest.cpp @@ -66,7 +66,7 @@ int test_priorty_queue(void){ int i; for (i=0; i<10; i++) { node = new CGenNode(); - printf(" +%x \n",node); + printf(" +%p \n",node); node->m_flow_id = 10-i; node->m_pkt_info = (CFlowPktInfo *)(uintptr_t)i; node->m_time = (double)i+0.1; @@ -74,7 +74,7 @@ int test_priorty_queue(void){ } while (!p_queue.empty()) { node = p_queue.top(); - printf(" -->%x \n",node); + printf(" -->%p \n",node); //node->Dump(stdout); p_queue.pop(); //delete node; @@ -159,7 +159,7 @@ public: bool init(void){ - uint16 * ports; + uint16 * ports = NULL; CTupleBase tuple; CErfIF erf_vif; @@ -663,6 +663,7 @@ TEST_F(basic, latency1) { po->preview.setFileWrite(true); uint8_t mac[]={0,0,0,1,0,0}; + (void)mac; CErfIF erf_vif; erf_vif.set_review_mode(&CGlobalInfo::m_options.preview); @@ -714,6 +715,7 @@ TEST_F(basic, latency2) { uint8_t mac[]={0,0,0,1,0,0}; + (void)mac; mac[0]=0; mac[1]=0; @@ -728,14 +730,13 @@ TEST_F(basic, latency2) { int i; for (i=0; i<100; i++) { - uint8_t *p; rte_mbuf_t * m=l.generate_pkt(0); - p=rte_pktmbuf_mtod(m, uint8_t*); + rte_pktmbuf_mtod(m, uint8_t*); //utl_DumpBuffer(stdout,p,l.get_pkt_size(),0); port0.update_packet(m); - p=rte_pktmbuf_mtod(m, uint8_t*); + rte_pktmbuf_mtod(m, uint8_t*); //utl_DumpBuffer(stdout,p,l.get_pkt_size(),0); //printf("offset is : %d \n",l.get_payload_offset()); @@ -763,6 +764,7 @@ TEST_F(basic, latency3) { uint8_t mac[]={0,0,0,1,0,0}; + (void)mac; mac[0]=0; @@ -850,6 +852,7 @@ public: TEST_F(basic, latency4) { uint8_t mac[]={0,0,0,1,0,0}; + (void)mac; mac[0]=0; mac[1]=0; @@ -2125,7 +2128,7 @@ class CRxCheck1 : public CRxCheckCallbackBase { public: virtual void handle_packet(rte_mbuf_t * m){ - char *mp=rte_pktmbuf_mtod(m, char*); + rte_pktmbuf_mtod(m, char*); CRx_check_header * rx_p; rte_mbuf_t * m2 = m->next; rx_p=(CRx_check_header *)rte_pktmbuf_mtod(m2, char*); diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index d59da900..65dba06d 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -72,11 +72,11 @@ void CGlobalMemory::Dump(FILE *fd){ c_size=c_size*2; } - fprintf(fd," %-40s : %lu \n",names[i].c_str(),m_mbuf[i]); + fprintf(fd," %-40s : %lu \n",names[i].c_str(),(ulong)m_mbuf[i]); } c_total += (m_mbuf[MBUF_DP_FLOWS] * sizeof(CGenNode)); - fprintf(fd," %-40s : %lu \n","get_each_core_dp_flows",get_each_core_dp_flows()); + fprintf(fd," %-40s : %lu \n","get_each_core_dp_flows",(ulong)get_each_core_dp_flows()); fprintf(fd," %-40s : %s \n","Total memory",double_to_human_str(c_total,"bytes",KBYE_1024).c_str() ); } @@ -240,7 +240,7 @@ bool CPlatformSocketInfoConfig::init(){ } if ( m_thread_phy_to_virtual[phy_thread] ){ - printf("ERROR physical thread %d defined twice %d \n",phy_thread); + printf("ERROR physical thread %d defined twice\n",phy_thread); exit(1); } m_thread_phy_to_virtual[phy_thread]=virt_thread; @@ -269,7 +269,7 @@ bool CPlatformSocketInfoConfig::init(){ void CPlatformSocketInfoConfig::dump(FILE *fd){ - fprintf(fd," core_mask %x \n",get_cores_mask()); + fprintf(fd," core_mask %llx \n",(unsigned long long)get_cores_mask()); fprintf(fd," sockets :"); int i; for (i=0; i> (const YAML::Node& node, CFlowYamlInfo & fi) { if ( node.FindValue("dyn_pyload") ){ - int i; const YAML::Node& dyn_pyload = node["dyn_pyload"]; for(unsigned i=0;im_pkt_indication.m_packet->pkt_cnt, - m_pkt_info->m_pkt_indication.m_packet->pkt_len, - m_pkt_info->m_pkt_indication.m_desc.getId(), - (m_pkt_info->m_pkt_indication.m_desc.IsInitSide()?1:0), - m_pkt_info->m_pkt_indication.m_desc.IsLastPkt(), + fprintf(fd,"%.6f,%llx,%p,%llu,%d,%d,%d,%d,%d,%d,%x,%x,%d\n", + m_time, + (unsigned long long)m_flow_id, + m_pkt_info, + (unsigned long long)m_pkt_info->m_pkt_indication.m_packet->pkt_cnt, + m_pkt_info->m_pkt_indication.m_packet->pkt_len, + m_pkt_info->m_pkt_indication.m_desc.getId(), + (m_pkt_info->m_pkt_indication.m_desc.IsInitSide()?1:0), + m_pkt_info->m_pkt_indication.m_desc.IsLastPkt(), m_type, m_thread_id, m_src_ip, m_dest_ip, - m_src_port - - - - ); + m_src_port); } @@ -3118,7 +3126,7 @@ int CNodeGenerator::close_file(CFlowGenListPerThread * thread){ int CNodeGenerator::update_stats(CGenNode * node){ if ( m_preview_mode.getVMode() >2 ){ - fprintf(stdout," %llu ,",m_cnt); + fprintf(stdout," %llu ,", (unsigned long long)m_cnt); node->Dump(stdout); m_cnt++; } @@ -4520,9 +4528,12 @@ void CTupleTemplateGenerator::Generate(){ #endif +static uint32_t get_rand_32(uint32_t MinimumRange, + uint32_t MaximumRange) __attribute__ ((unused)); + +static uint32_t get_rand_32(uint32_t MinimumRange, + uint32_t MaximumRange) { -static uint32_t get_rand_32(uint32_t MinimumRange , - uint32_t MaximumRange ){ enum {RANDS_NUM = 2 , RAND_MAX_BITS = 0xf , UNSIGNED_INT_BITS = 0x20 , TWO_BITS_MASK = 0x3}; const double TWO_POWER_32_BITS = 0x10000000 * (double)0x10; @@ -4755,7 +4766,6 @@ void CCPortLatency::reset(){ static uint8_t nat_is_port_can_send(uint8_t port_id){ - uint8_t offset= ((port_id>>1)<<1); uint8_t client_index = (port_id %2); return (client_index ==0 ?1:0); } @@ -4877,7 +4887,7 @@ void CCPortLatency::dump_counters_json(std::string & json ){ } void CCPortLatency::DumpCounters(FILE *fd){ - #define DP_A1(f) if (f) fprintf(fd," %-40s : %llu \n",#f,f) + #define DP_A1(f) if (f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)f) fprintf(fd," counter \n"); fprintf(fd," -----------\n"); @@ -4896,7 +4906,7 @@ void CCPortLatency::DumpCounters(FILE *fd){ fprintf(fd," -----------\n"); m_hist.Dump(fd); - fprintf(fd," %-40s : %llu \n","jitter",get_jitter_usec()); + fprintf(fd," %-40s : %lu \n","jitter", (ulong)get_jitter_usec()); } bool CCPortLatency::dump_packet(rte_mbuf_t * m){ @@ -4920,6 +4930,9 @@ bool CCPortLatency::dump_packet(rte_mbuf_t * m){ if ( unlikely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){ vlan_offset=4; } + + (void)vlan_offset; + // utl_DumpBuffer(stdout,p,pkt_size,0); return (0); @@ -4955,9 +4968,7 @@ bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p){ uint16_t vlan_offset=parser.m_vlan_offset; uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); - rx_p=(CRx_check_header *)0; - bool managed_by_ip_options=false; - bool is_rx_check=true; + rx_p = (CRx_check_header *)0; if ( !parser.IsLatencyPkt() ){ @@ -5074,7 +5085,7 @@ void CLatencyManager::Delete(){ static uint8_t swap_port(uint8_t port_id){ uint8_t offset= ((port_id>>1)<<1); uint8_t client_index = (port_id %2); - return (offset+client_index^1); + return (offset + (client_index ^ 1)); } @@ -5197,8 +5208,6 @@ void CLatencyManager::run_rx_queue_msgs(uint8_t thread_id, CGenNodeMsgBase * msg=(CGenNodeMsgBase *)node; - CGenNodeLatencyPktInfo * msg1=(CGenNodeLatencyPktInfo *)msg; - uint8_t msg_type = msg->m_msg_type; switch (msg_type ) { case CGenNodeMsgBase::LATENCY_PKT: @@ -5321,7 +5330,7 @@ void CLatencyManager::start(int iter){ } if ( iter>0 ){ if ( ( cnt>iter) ){ - printf("stop due iter %d %d \n",iter); + printf("stop due iter %d\n",iter); break; } } @@ -5490,8 +5499,8 @@ void CLatencyManager::DumpRxCheckVerification(FILE *fd, fprintf(fd," rx_checker is disabled \n"); return; } - fprintf(fd," rx_check Tx : %u \n",total_tx_rx_check); - fprintf(fd," rx_check Rx : %u \n",m_rx_check_manager.getTotalRx() ); + fprintf(fd," rx_check Tx : %llu \n", (unsigned long long)total_tx_rx_check); + fprintf(fd," rx_check Rx : %llu \n", (unsigned long long)m_rx_check_manager.getTotalRx() ); fprintf(fd," rx_check verification :" ); if (m_rx_check_manager.getTotalRx() == total_tx_rx_check) { fprintf(fd," OK \n" ); @@ -6744,7 +6753,6 @@ bool CSimplePacketParser::Parse(){ EthernetHeader *m_ether = (EthernetHeader *)p; IPHeader * ipv4=0; IPv6Header * ipv6=0; - uint16_t pkt_size=rte_pktmbuf_pkt_len(m); m_vlan_offset=0; m_option_offset=0; diff --git a/src/bp_sim.h b/src/bp_sim.h index c201cd20..36595581 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -894,6 +894,8 @@ public: /* number of main active sockets. socket #0 is always used */ virtual socket_id_t max_num_active_sockets()=0; + virtual ~CPlatformSocketInfoBase() {} + public: /* which socket to allocate memory to each port */ virtual socket_id_t port_to_socket(port_id_t port)=0; @@ -1337,8 +1339,8 @@ public: -#define DP(f) if (f) printf(" %-40s: %llu \n",#f,f) -#define DP_name(n,f) if (f) printf(" %-40s: %llu \n",n,f) +#define DP(f) if (f) printf(" %-40s: %llu \n",#f,(unsigned long long)f) +#define DP_name(n,f) if (f) printf(" %-40s: %llu \n",n,(unsigned long long)f) #define DP_S(f,f_s) if (f) printf(" %-40s: %s \n",#f,f_s.c_str()) @@ -2380,6 +2382,7 @@ public: return (uint32_t)((uintptr_t)( ((char *)l3.m_ipv4)-getBasePtr()) ); }else{ BP_ASSERT(0); + return (0); } } diff --git a/src/common/Network/Packet/IPHeader.cpp b/src/common/Network/Packet/IPHeader.cpp index 3b90a1aa..c3363603 100755 --- a/src/common/Network/Packet/IPHeader.cpp +++ b/src/common/Network/Packet/IPHeader.cpp @@ -52,7 +52,7 @@ void IPHeader::dump(FILE *fd) { fprintf(fd, "\nIPHeader"); fprintf(fd, "\nSource 0x%.8lX, Destination 0x%.8lX, Protocol 0x%.1X", - getSourceIp(), getDestIp(), getProtocol()); + (ulong)getSourceIp(), (ulong)getDestIp(), (uint)getProtocol()); fprintf(fd, "\nTTL : %d, Id : 0x%.2X, Ver %d, Header Length %d, Total Length %d", getTimeToLive(), getId(), getVersion(), getHeaderLength(), getTotalLength()); if(isFragmented()) diff --git a/src/common/Network/Packet/TCPHeader.cpp b/src/common/Network/Packet/TCPHeader.cpp index bf28db2e..1826cef8 100755 --- a/src/common/Network/Packet/TCPHeader.cpp +++ b/src/common/Network/Packet/TCPHeader.cpp @@ -25,7 +25,7 @@ void TCPHeader::dump(FILE *fd) fprintf(fd, "\nSourcePort 0x%.4X, DestPort 0x%.4X", getSourcePort(), getDestPort()); fprintf(fd, "\nSeqNum 0x%.8lX, AckNum 0x%.8lX, Window %d", - getSeqNumber(), getAckNumber(), getWindowSize()); + (ulong)getSeqNumber(), (ulong)getAckNumber(), getWindowSize()); fprintf(fd, "\nHeader Length : %d, Checksum : 0x%.4X", getHeaderLength(), getChecksum()); fprintf(fd, "\nFlags : SYN - %d, FIN - %d, ACK - %d, URG - %d, RST - %d, PSH - %d", diff --git a/src/common/c_common.h b/src/common/c_common.h index d8320aaa..3e43644f 100755 --- a/src/common/c_common.h +++ b/src/common/c_common.h @@ -46,7 +46,7 @@ typedef void* c_pvoid; #ifdef _DEBUG #define BP_ASSERT(a) assert(a) #else - #define BP_ASSERT(a) + #define BP_ASSERT(a) (void (a)) #endif #endif diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 0341516c..2bab4dff 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -82,7 +82,7 @@ private: void CTRexDpStreamModeSingleBurst::dump(FILE *fd){ fprintf (fd," pps : %f \n",m_pps); - fprintf (fd," total_packets : %llu \n",m_total_packets); + fprintf (fd," total_packets : %llu \n", (unsigned long long)m_total_packets); } @@ -130,9 +130,9 @@ private: void CTRexDpStreamModeMultiBurst::dump(FILE *fd){ fprintf (fd," pps : %f \n",m_pps); - fprintf (fd," total_packets : %llu \n",m_pkts_per_burst); + fprintf (fd," total_packets : %llu \n", (unsigned long long)m_pkts_per_burst); fprintf (fd," ibg : %f \n",m_ibg); - fprintf (fd," num_of_bursts : %llu \n",m_number_of_bursts); + fprintf (fd," num_of_bursts : %lu \n", (ulong)m_number_of_bursts); } diff --git a/src/gtest/tuple_gen_test.cpp b/src/gtest/tuple_gen_test.cpp index 8a774e38..f3b9fa1e 100755 --- a/src/gtest/tuple_gen_test.cpp +++ b/src/gtest/tuple_gen_test.cpp @@ -161,7 +161,6 @@ TEST(tuple_gen,clientPoolL) { 0,0); CTupleBase result; uint32_t result_src; - uint32_t result_dest; uint16_t result_port; for(int i=0;i<10;i++) { @@ -186,7 +185,6 @@ TEST(tuple_gen,clientPool) { 0,0); CTupleBase result; uint32_t result_src; - uint32_t result_dest; uint16_t result_port; for(int i=0;i<10;i++) { @@ -436,7 +434,6 @@ TEST(tuple_gen,template1) { template_1.GenerateTuple(result); uint32_t result_src = result.getClient(); uint32_t result_dest = result.getServer(); - uint16_t result_port = result.getClientPort(); //printf(" %x %x %x \n",result_src,result_dest,result_port); EXPECT_EQ(result_src, (uint32_t)(0x10000001+i)); EXPECT_EQ(result_dest, (uint32_t)(((0x12121212)) )); @@ -489,9 +486,6 @@ TEST(tuple_gen,no_free) { int i; for (i=0; i<65557; i++) { template_1.GenerateTuple(result); - uint32_t result_src = result.getClient(); - uint32_t result_dest = result.getServer(); - uint16_t result_port = result.getClientPort(); } // should have error EXPECT_TRUE((gen.getErrorAllocationCounter()>0)?true:false); @@ -514,8 +508,6 @@ TEST(tuple_gen,try_to_free) { int i; for (i=0; i<65557; i++) { template_1.GenerateTuple(result); - uint32_t result_src = result.getClient(); - uint32_t result_dest = result.getServer(); uint16_t result_port = result.getClientPort(); gen.FreePort(0,result.getClientId(),result_port); } diff --git a/src/main.cpp b/src/main.cpp index bd64c5a4..03f5d6ed 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -214,11 +214,12 @@ void * thread_task(void *info){ char buf[100]; sprintf(buf,"my%d.erf",obj->thread_id); - volatile int i; lpt->start_generate_stateful(buf,*obj->preview_info); lpt->m_node_gen.DumpHist(stdout); printf("end thread %d \n",obj->thread_id); } + + return (NULL); } @@ -405,8 +406,6 @@ void update_tcp_seq_num(CCapFileFlowInfo * obj, int i; for (i=pkt_id+1; iGetPacket(i); tcp=pkt->m_pkt_indication.l4.m_tcp; @@ -490,7 +489,7 @@ int manipolate_capfile() { CCapFileFlowInfo flow_info; flow_info.Create(); - int res=flow_info.load_cap_file("avl/delay_10_rtsp_0.pcap",0,0); + 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); @@ -515,7 +514,7 @@ int manipolate_capfile_sip() { CCapFileFlowInfo flow_info; flow_info.Create(); - int res=flow_info.load_cap_file("avl/delay_10_sip_0.pcap",0,0); + 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); @@ -532,8 +531,8 @@ int manipolate_capfile_sip1() { CCapFileFlowInfo flow_info; flow_info.Create(); - int res=flow_info.load_cap_file("avl/delay_sip_0.pcap",0,0); - CFlowPktInfo * pkt=flow_info.GetPacket(1); + 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); @@ -620,6 +619,8 @@ bool CMergeCapFileRec::Create(std::string cap_file, m_limit_number_of_packets =0; m_start_time = pkt->m_packet->get_time() ; m_offset = offset; + + return (true); } @@ -663,12 +664,12 @@ bool CMergeCapFile::run_merge(std::string to_cap_file){ int min_index=0; double min_time; - fprintf(stdout," --------------\n",cnt); + fprintf(stdout," --------------\n"); fprintf(stdout," pkt : %d \n",cnt); for (i=0; isecond; - printf ("flow_id: %d \n",lp->m_flow_id); + printf ("flow_id: %llu \n",(unsigned long long)lp->m_flow_id); } } @@ -208,7 +208,7 @@ std::string CPerTxthreadTemplateInfo::dump_as_json(std::string name){ int i; for (i=0;iget_error_counter(),lp->get_rx_counter()); + fprintf(fd,"[id:%2d val:%8llu,rx:%8llu], ",i, (unsigned long long)lp->get_error_counter(), (unsigned long long)lp->get_rx_counter()); cnt++; if (cnt>5) { cnt=0; @@ -500,7 +500,11 @@ void RxCheckManager::DumpTemplateFull(FILE *fd){ int i; for (i=0; iget_error_counter(),lp->get_jitter_usec(),lp->get_rx_counter() ); + fprintf(fd," template_id_%2d , errors:%8llu, jitter: %llu rx : %llu \n", + i, + (unsigned long long)lp->get_error_counter(), + (unsigned long long)lp->get_jitter_usec(), + (unsigned long long)lp->get_rx_counter() ); } } @@ -514,7 +518,11 @@ void RxCheckManager::DumpShort(FILE *fd){ DumpTemplate(fd,false); fprintf(fd,"\n"); fprintf(fd,"---\n"); - fprintf(fd," active flows: %8d, fif: %8d, drop: %8d, errors: %8d \n",m_stats.m_active,m_stats.m_fif,m_stats.m_err_drop,m_stats.get_total_err()); + fprintf(fd," active flows: %8llu, fif: %8llu, drop: %8llu, errors: %8llu \n", + (unsigned long long)m_stats.m_active, + (unsigned long long)m_stats.m_fif, + (unsigned long long)m_stats.m_err_drop, + (unsigned long long)m_stats.get_total_err()); fprintf(fd,"------------------------------------------------------------------------------------------------------------\n"); } diff --git a/src/rx_check_header.cpp b/src/rx_check_header.cpp index 8ee580db..5934ee15 100755 --- a/src/rx_check_header.cpp +++ b/src/rx_check_header.cpp @@ -42,11 +42,11 @@ void CRx_check_header::dump(FILE *fd){ void CNatOption::dump(FILE *fd){ - fprintf(fd," op : %lx \n",get_option_type()); - fprintf(fd," ol : %lx \n",get_option_len()); - fprintf(fd," thread_id : %lx \n",get_thread_id()); - fprintf(fd," magic : %lx \n",get_magic()); - fprintf(fd," fid : %lx \n",get_fid()); + fprintf(fd," op : %x \n",get_option_type()); + fprintf(fd," ol : %x \n",get_option_len()); + fprintf(fd," thread_id : %x \n",get_thread_id()); + fprintf(fd," magic : %x \n",get_magic()); + fprintf(fd," fid : %x \n",get_fid()); utl_DumpBuffer(stdout,(void *)&u.m_data[0],8,0); } diff --git a/src/time_histogram.cpp b/src/time_histogram.cpp index f1b47e59..96796bfc 100755 --- a/src/time_histogram.cpp +++ b/src/time_histogram.cpp @@ -182,10 +182,10 @@ void CTimeHistogram::DumpWinMax(FILE *fd){ } void CTimeHistogram::Dump(FILE *fd){ - fprintf (fd," min_delta : %lu usec \n",get_usec(m_min_delta)); + fprintf (fd," min_delta : %lu usec \n", (ulong)get_usec(m_min_delta)); fprintf (fd," cnt : %lu \n",m_cnt); fprintf (fd," high_cnt : %lu \n",m_high_cnt); - fprintf (fd," max_d_time : %lu usec\n",get_usec(m_max_dt)); + fprintf (fd," max_d_time : %lu usec\n", (ulong)get_usec(m_max_dt)); //fprintf (fd," average : %.0f usec\n", get_total_average()); fprintf (fd," sliding_average : %.0f usec\n", get_average_latency()); fprintf (fd," precent : %.1f %%\n",(100.0*(double)m_high_cnt/(double)m_cnt)); @@ -198,7 +198,7 @@ void CTimeHistogram::Dump(FILE *fd){ for (j=0; j0 ) { - fprintf (fd," h[%lu] : %lu \n",(base*(i+1)),m_hcnt[j][i]); + fprintf (fd," h[%u] : %llu \n",(base*(i+1)),(unsigned long long)m_hcnt[j][i]); } } base=base*10; diff --git a/src/tuple_gen.h b/src/tuple_gen.h index 29adbd69..d34e27bc 100755 --- a/src/tuple_gen.h +++ b/src/tuple_gen.h @@ -553,6 +553,9 @@ public: class CServerPoolBase { public: + + virtual ~CServerPoolBase() {} + virtual void GenerateTuple(CTupleBase& tuple) = 0; virtual uint16_t GenerateOnePort(uint32_t idx) = 0; virtual void Delete() = 0; diff --git a/src/utl_json.cpp b/src/utl_json.cpp index 990346f5..fb55be0a 100755 --- a/src/utl_json.cpp +++ b/src/utl_json.cpp @@ -25,7 +25,7 @@ limitations under the License. std::string add_json(std::string name, uint32_t counter,bool last){ char buff[200]; - sprintf(buff,"\"%s\":%lu",name.c_str(),counter); + sprintf(buff,"\"%s\":%lu",name.c_str(), (ulong)counter); std::string s= std::string(buff); if (!last) { s+=","; @@ -35,7 +35,7 @@ std::string add_json(std::string name, uint32_t counter,bool last){ std::string add_json(std::string name, uint64_t counter,bool last){ char buff[200]; - sprintf(buff,"\"%s\":%llu",name.c_str(),counter); + sprintf(buff,"\"%s\":%llu",name.c_str(), (unsigned long long)counter); std::string s= std::string(buff); if (!last) { s+=","; diff --git a/src/utl_yaml.cpp b/src/utl_yaml.cpp index 5f3ca735..828817e4 100755 --- a/src/utl_yaml.cpp +++ b/src/utl_yaml.cpp @@ -104,6 +104,8 @@ bool utl_yaml_read_uint16(const YAML::Node& node, val = (uint16_t)val_tmp; res=true; } + + return (res); } bool utl_yaml_read_bool(const YAML::Node& node, -- cgit 1.2.3-korg From 9c32c36b6006d2a81e1a5658a1fb1616eff650f3 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 9 Nov 2015 17:10:24 +0200 Subject: moved logic to the port class also implemented the state machine for CP port --- .../trex_control_plane/console/trex_console.py | 3 + src/gtest/rpc_test.cpp | 101 +++++++++++++ src/rpc-server/commands/trex_rpc_cmd_general.cpp | 28 ++-- src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 160 ++++++++++++++++----- src/rpc-server/commands/trex_rpc_cmds.h | 8 +- src/rpc-server/trex_rpc_cmds_table.cpp | 3 + src/stateless/cp/trex_stateless_port.cpp | 143 +++++++++++++----- src/stateless/cp/trex_stateless_port.h | 128 +++++++++++++---- 8 files changed, 468 insertions(+), 106 deletions(-) (limited to 'src/gtest') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index a2c738ab..68050fc0 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -778,6 +778,9 @@ class TRexConsole(cmd.Cmd): return else: port_list = self.stateless_client.get_active_ports() + if not port_list: + print magenta("no active ports - operation aborted\n") + return else: port_list = self.extract_port_ids_from_line(line) diff --git a/src/gtest/rpc_test.cpp b/src/gtest/rpc_test.cpp index 6b8e3eff..34bb02a8 100644 --- a/src/gtest/rpc_test.cpp +++ b/src/gtest/rpc_test.cpp @@ -478,6 +478,7 @@ TEST_F(RpcTestOwned, add_remove_stream) { create_request(request, "get_stream", 1, 1); request["params"]["stream_id"] = 5; + request["params"]["get_pkt"] = true; send_request(request, response); @@ -501,6 +502,7 @@ TEST_F(RpcTestOwned, add_remove_stream) { create_request(request, "get_stream", 1, 1); request["params"]["stream_id"] = 5; + request["params"]["get_pkt"] = true; send_request(request, response); @@ -607,17 +609,21 @@ TEST_F(RpcTestOwned, start_stop_traffic) { /* start port 1 */ create_request(request, "start_traffic", 1, 1); + request["params"]["mul"] = 1.0; send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); /* start port 3 */ create_request(request, "start_traffic", 1, 3); + request["params"]["mul"] = 1.0; send_request(request, response); EXPECT_EQ(response["result"], "ACK"); /* start not configured port */ create_request(request, "start_traffic", 1, 2); + request["params"]["mul"] = 1.0; send_request(request, response); EXPECT_EQ(response["error"]["code"], -32000); @@ -633,11 +639,13 @@ TEST_F(RpcTestOwned, start_stop_traffic) { /* start 1 again */ create_request(request, "start_traffic", 1, 1); + request["params"]["mul"] = 1.0; send_request(request, response); EXPECT_EQ(response["result"], "ACK"); /* start 1 twice (error) */ create_request(request, "start_traffic", 1, 1); + request["params"]["mul"] = 1.0; send_request(request, response); EXPECT_EQ(response["error"]["code"], -32000); @@ -657,3 +665,96 @@ TEST_F(RpcTestOwned, start_stop_traffic) { EXPECT_EQ(response["result"], "ACK"); } + + +TEST_F(RpcTestOwned, states_check) { + Json::Value request; + Json::Value response; + + /* add stream #1 */ + create_request(request, "add_stream", 1, 1); + request["params"]["stream_id"] = 5; + + Json::Value stream; + create_simple_stream(stream); + + request["params"]["stream"] = stream; + + send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); + + /* start traffic */ + create_request(request, "start_traffic", 1, 1); + request["params"]["mul"] = 1.0; + send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); + + /* now we cannot add streams */ + create_request(request, "add_stream", 1, 1); + request["params"]["stream_id"] = 15; + + create_simple_stream(stream); + + request["params"]["stream"] = stream; + + send_request(request, response); + EXPECT_EQ(response["error"]["code"], -32000); + + /* we cannot remove streams */ + create_request(request, "remove_stream", 1, 1); + request["params"]["stream_id"] = 15; + send_request(request, response); + EXPECT_EQ(response["error"]["code"], -32000); + + /* cannot start again */ + create_request(request, "start_traffic", 1, 1); + request["params"]["mul"] = 1.0; + send_request(request, response); + EXPECT_EQ(response["error"]["code"], -32000); + + /* we can stop and add stream / remove */ + + create_request(request, "stop_traffic", 1, 1); + send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); + + create_request(request, "add_stream", 1, 1); + request["params"]["stream_id"] = 328; + + create_simple_stream(stream); + + request["params"]["stream"] = stream; + + send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); + + + create_request(request, "remove_stream", 1, 1); + request["params"]["stream_id"] = 15; + send_request(request, response); + EXPECT_EQ(response["error"]["code"], -32000); + + /* we cannot pause now */ + create_request(request, "pause_traffic", 1, 1); + send_request(request, response); + EXPECT_EQ(response["error"]["code"], -32000); + + + /* start */ + create_request(request, "start_traffic", 1, 1); + request["params"]["mul"] = 1.0; + send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); + + /* now can pause */ + create_request(request, "pause_traffic", 1, 1); + send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); + + /* also we can resume*/ + create_request(request, "resume_traffic", 1, 1); + send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); + + +} diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index b40e996f..b6d06cfc 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -222,12 +222,12 @@ TrexRpcCmdAcquire::_run(const Json::Value ¶ms, Json::Value &result) { /* if not free and not you and not force - fail */ TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - if ( (!port->is_free_to_aquire()) && (port->get_owner() != new_owner) && (!force)) { - generate_execute_err(result, "port is already taken by '" + port->get_owner() + "'"); + try { + port->acquire(new_owner, force); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); } - port->set_owner(new_owner); - result["result"] = port->get_owner_handler(); return (TREX_RPC_CMD_OK); @@ -244,12 +244,12 @@ TrexRpcCmdRelease::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - if (port->get_state() == TrexStatelessPort::PORT_STATE_TRANSMITTING) { - generate_execute_err(result, "cannot release a port during transmission"); + try { + port->release(); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); } - port->clear_owner(); - result["result"] = "ACK"; return (TREX_RPC_CMD_OK); @@ -266,13 +266,13 @@ TrexRpcCmdGetPortStats::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - if (port->get_state() == TrexStatelessPort::PORT_STATE_DOWN) { - generate_execute_err(result, "cannot get stats - port is down"); - } - result["result"]["status"] = port->get_state_as_string(); - port->encode_stats(result["result"]); + try { + port->encode_stats(result["result"]); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); + } return (TREX_RPC_CMD_OK); } @@ -303,7 +303,7 @@ TrexRpcCmdSyncUser::_run(const Json::Value ¶ms, Json::Value &result) { owned_port["streams"] = Json::arrayValue; std::vector streams; - port->get_stream_table()->get_object_list(streams); + port->get_object_list(streams); for (auto stream : streams) { owned_port["streams"].append(stream->get_stream_json()); diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index 4fa0956d..fffc800a 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -115,7 +115,12 @@ TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &result) { validate_stream(stream, result); TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(stream->m_port_id); - port->get_stream_table()->add_stream(stream); + + try { + port->add_stream(stream); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); + } result["result"] = "ACK"; @@ -293,7 +298,7 @@ TrexRpcCmdAddStream::validate_stream(const TrexStream *stream, Json::Value &resu TrexStatelessPort * port = get_stateless_obj()->get_port_by_id(stream->m_port_id); /* does such a stream exists ? */ - if (port->get_stream_table()->get_stream_by_id(stream->m_stream_id)) { + if (port->get_stream_by_id(stream->m_stream_id)) { std::stringstream ss; ss << "stream " << stream->m_stream_id << " already exists"; delete stream; @@ -319,7 +324,7 @@ TrexRpcCmdRemoveStream::_run(const Json::Value ¶ms, Json::Value &result) { } TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - TrexStream *stream = port->get_stream_table()->get_stream_by_id(stream_id); + TrexStream *stream = port->get_stream_by_id(stream_id); if (!stream) { std::stringstream ss; @@ -327,7 +332,12 @@ TrexRpcCmdRemoveStream::_run(const Json::Value ¶ms, Json::Value &result) { generate_execute_err(result, ss.str()); } - port->get_stream_table()->remove_stream(stream); + try { + port->remove_stream(stream); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); + } + delete stream; result["result"] = "ACK"; @@ -350,12 +360,18 @@ TrexRpcCmdRemoveAllStreams::_run(const Json::Value ¶ms, Json::Value &result) generate_execute_err(result, ss.str()); } - TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - port->get_stream_table()->remove_and_delete_all_streams(); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - result["result"] = "ACK"; + try { + port->remove_and_delete_all_streams(); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); + } - return (TREX_RPC_CMD_OK); + + result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); } /*************************** @@ -377,7 +393,7 @@ TrexRpcCmdGetStreamList::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - port->get_stream_table()->get_id_list(stream_list); + port->get_id_list(stream_list); Json::Value json_list = Json::arrayValue; @@ -409,7 +425,7 @@ TrexRpcCmdGetStream::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - TrexStream *stream = port->get_stream_table()->get_stream_by_id(stream_id); + TrexStream *stream = port->get_stream_by_id(stream_id); if (!stream) { std::stringstream ss; @@ -447,32 +463,19 @@ TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - TrexStatelessPort::rc_e rc = port->start_traffic(mul); - - if (rc == TrexStatelessPort::RC_OK) { - result["result"] = "ACK"; - } else { - std::stringstream ss; - switch (rc) { - case TrexStatelessPort::RC_ERR_BAD_STATE_FOR_OP: - ss << "bad state for operations: port is either transmitting traffic or down"; - break; - case TrexStatelessPort::RC_ERR_NO_STREAMS: - ss << "no active streams on that port"; - break; - default: - ss << "failed to start traffic"; - break; - } - - generate_execute_err(result, ss.str()); + try { + port->start_traffic(mul); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); } - return (TREX_RPC_CMD_OK); + result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); } /*************************** - * start traffic on port + * stop traffic on port * **************************/ trex_rpc_cmd_rc_e @@ -487,7 +490,12 @@ TrexRpcCmdStopTraffic::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - port->stop_traffic(); + try { + port->stop_traffic(); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); + } + result["result"] = "ACK"; return (TREX_RPC_CMD_OK); @@ -511,7 +519,7 @@ TrexRpcCmdGetAllStreams::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); std::vector streams; - port->get_stream_table()->get_object_list(streams); + port->get_object_list(streams); Json::Value streams_json = Json::objectValue; for (auto stream : streams) { @@ -533,3 +541,89 @@ TrexRpcCmdGetAllStreams::_run(const Json::Value ¶ms, Json::Value &result) { return (TREX_RPC_CMD_OK); } + +/*************************** + * pause traffic + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdPauseTraffic::_run(const Json::Value ¶ms, Json::Value &result) { + + uint8_t port_id = parse_byte(params, "port_id", result); + + if (port_id >= get_stateless_obj()->get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); + + try { + port->pause_traffic(); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); + } + + result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); +} + +/*************************** + * resume traffic + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdResumeTraffic::_run(const Json::Value ¶ms, Json::Value &result) { + + uint8_t port_id = parse_byte(params, "port_id", result); + + if (port_id >= get_stateless_obj()->get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); + + try { + port->resume_traffic(); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); + } + + result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); +} + +/*************************** + * update traffic + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdUpdateTraffic::_run(const Json::Value ¶ms, Json::Value &result) { + + uint8_t port_id = parse_byte(params, "port_id", result); + double mul = parse_double(params, "mul", result); + + if (port_id >= get_stateless_obj()->get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); + + try { + port->update_traffic(mul); + } catch (const TrexRpcException &ex) { + generate_execute_err(result, ex.what()); + } + + result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); +} + diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h index a604d9a1..8b173cb9 100644 --- a/src/rpc-server/commands/trex_rpc_cmds.h +++ b/src/rpc-server/commands/trex_rpc_cmds.h @@ -105,8 +105,12 @@ TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStream, "get_stream", 3, true); -TREX_RPC_CMD_DEFINE(TrexRpcCmdStartTraffic, "start_traffic", 2, true); -TREX_RPC_CMD_DEFINE(TrexRpcCmdStopTraffic, "stop_traffic", 1, true); +TREX_RPC_CMD_DEFINE(TrexRpcCmdStartTraffic, "start_traffic", 2, true); +TREX_RPC_CMD_DEFINE(TrexRpcCmdStopTraffic, "stop_traffic", 1, true); +TREX_RPC_CMD_DEFINE(TrexRpcCmdPauseTraffic, "pause_traffic", 1, true); +TREX_RPC_CMD_DEFINE(TrexRpcCmdResumeTraffic, "resume_traffic", 1, true); + +TREX_RPC_CMD_DEFINE(TrexRpcCmdUpdateTraffic, "update_traffic", 1, true); TREX_RPC_CMD_DEFINE(TrexRpcCmdSyncUser, "sync_user", 2, false); diff --git a/src/rpc-server/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp index e3bd7848..f38b4df4 100644 --- a/src/rpc-server/trex_rpc_cmds_table.cpp +++ b/src/rpc-server/trex_rpc_cmds_table.cpp @@ -51,8 +51,11 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() { register_command(new TrexRpcCmdGetStreamList()); register_command(new TrexRpcCmdGetStream()); register_command(new TrexRpcCmdGetAllStreams()); + register_command(new TrexRpcCmdStartTraffic()); register_command(new TrexRpcCmdStopTraffic()); + register_command(new TrexRpcCmdPauseTraffic()); + register_command(new TrexRpcCmdResumeTraffic()); } TrexRpcCommandsTable::~TrexRpcCommandsTable() { diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index cb6fcc0e..b9206775 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -53,29 +53,47 @@ using namespace std; * **************************/ TrexStatelessPort::TrexStatelessPort(uint8_t port_id) : m_port_id(port_id) { - m_port_state = PORT_STATE_UP_IDLE; + m_port_state = PORT_STATE_IDLE; clear_owner(); } +/** + * acquire the port + * + * @author imarom (09-Nov-15) + * + * @param user + * @param force + */ +void +TrexStatelessPort::acquire(const std::string &user, bool force) { + if ( (!is_free_to_aquire()) && (get_owner() != user) && (!force)) { + throw TrexRpcException("port is already taken by '" + get_owner() + "'"); + } + + set_owner(user); +} + +void +TrexStatelessPort::release(void) { + verify_state( ~(PORT_STATE_TX | PORT_STATE_PAUSE) ); + clear_owner(); +} + /** * starts the traffic on the port * */ -TrexStatelessPort::rc_e +void TrexStatelessPort::start_traffic(double mul) { - if (m_port_state != PORT_STATE_UP_IDLE) { - return (RC_ERR_BAD_STATE_FOR_OP); - } - - if (get_stream_table()->size() == 0) { - return (RC_ERR_NO_STREAMS); - } + /* command allowed only on state stream */ + verify_state(PORT_STATE_STREAMS); /* fetch all the streams from the table */ vector streams; - get_stream_table()->get_object_list(streams); + get_object_list(streams); /* compiler it */ TrexStreamsCompiler compiler; @@ -83,7 +101,7 @@ TrexStatelessPort::start_traffic(double mul) { bool rc = compiler.compile(streams, *compiled_obj); if (!rc) { - return (RC_ERR_FAILED_TO_COMPILE_STREAMS); + throw TrexRpcException("Failed to compile streams"); } /* generate a message to all the relevant DP cores to start transmitting */ @@ -91,51 +109,94 @@ TrexStatelessPort::start_traffic(double mul) { send_message_to_dp(start_msg); - /* move the state to transmiting */ - m_port_state = PORT_STATE_TRANSMITTING; - - return (RC_OK); + change_state(PORT_STATE_TX); } -TrexStatelessPort::rc_e +/** + * stop traffic on port + * + * @author imarom (09-Nov-15) + * + * @return TrexStatelessPort::rc_e + */ +void TrexStatelessPort::stop_traffic(void) { - /* real code goes here */ - if (m_port_state != PORT_STATE_TRANSMITTING) { - return (RC_ERR_BAD_STATE_FOR_OP); - } + verify_state(PORT_STATE_TX); /* generate a message to all the relevant DP cores to start transmitting */ TrexStatelessCpToDpMsgBase *stop_msg = new TrexStatelessDpStop(m_port_id); send_message_to_dp(stop_msg); - m_port_state = PORT_STATE_UP_IDLE; + change_state(PORT_STATE_STREAMS); +} + +void +TrexStatelessPort::pause_traffic(void) { + + verify_state(PORT_STATE_TX); + + #if 0 + /* generate a message to all the relevant DP cores to start transmitting */ + TrexStatelessCpToDpMsgBase *stop_msg = new TrexStatelessDpStop(m_port_id); - return (RC_OK); + send_message_to_dp(stop_msg); + + m_port_state = PORT_STATE_UP_IDLE; + #endif + change_state(PORT_STATE_PAUSE); } -/** -* access the stream table -* -*/ -TrexStreamTable * TrexStatelessPort::get_stream_table() { - return &m_stream_table; +void +TrexStatelessPort::resume_traffic(void) { + + verify_state(PORT_STATE_PAUSE); + + #if 0 + /* generate a message to all the relevant DP cores to start transmitting */ + TrexStatelessCpToDpMsgBase *stop_msg = new TrexStatelessDpStop(m_port_id); + + send_message_to_dp(stop_msg); + + m_port_state = PORT_STATE_UP_IDLE; + #endif + change_state(PORT_STATE_TX); } +void +TrexStatelessPort::update_traffic(double mul) { + + verify_state(PORT_STATE_STREAMS | PORT_STATE_TX | PORT_STATE_PAUSE); + + #if 0 + /* generate a message to all the relevant DP cores to start transmitting */ + TrexStatelessCpToDpMsgBase *stop_msg = new TrexStatelessDpStop(m_port_id); + + send_message_to_dp(stop_msg); + + m_port_state = PORT_STATE_UP_IDLE; + #endif +} std::string -TrexStatelessPort::get_state_as_string() { +TrexStatelessPort::get_state_as_string() const { switch (get_state()) { case PORT_STATE_DOWN: return "down"; - case PORT_STATE_UP_IDLE: - return "idle"; + case PORT_STATE_IDLE: + return "no streams"; + + case PORT_STATE_STREAMS: + return "with streams, idle"; - case PORT_STATE_TRANSMITTING: + case PORT_STATE_TX: return "transmitting"; + + case PORT_STATE_PAUSE: + return "paused"; } return "unknown"; @@ -149,6 +210,24 @@ TrexStatelessPort::get_properties(string &driver, string &speed) { speed = "1 Gbps"; } +bool +TrexStatelessPort::verify_state(int state, bool should_throw) const { + if ( (state & m_port_state) == 0 ) { + if (should_throw) { + throw TrexRpcException("command cannot be executed on current state: '" + get_state_as_string() + "'"); + } else { + return false; + } + } + + return true; +} + +void +TrexStatelessPort::change_state(port_state_e new_state) { + + m_port_state = new_state; +} /** * generate a random connection handler diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 09183768..90bf936e 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -37,9 +37,11 @@ public: * port state */ enum port_state_e { - PORT_STATE_DOWN, - PORT_STATE_UP_IDLE, - PORT_STATE_TRANSMITTING + PORT_STATE_DOWN = 0x1, + PORT_STATE_IDLE = 0x2, + PORT_STATE_STREAMS = 0x4, + PORT_STATE_TX = 0x8, + PORT_STATE_PAUSE = 0x10, }; /** @@ -53,30 +55,54 @@ public: }; TrexStatelessPort(uint8_t port_id); + + /** + * acquire port + * throws TrexException in case of an error + */ + void acquire(const std::string &user, bool force = false); + + /** + * release the port from the current user + * throws TrexException in case of an error + */ + void release(void); /** * start traffic - * + * throws TrexException in case of an error */ - rc_e start_traffic(double mul); + void start_traffic(double mul); /** * stop traffic - * + * throws TrexException in case of an error + */ + void stop_traffic(void); + + /** + * pause traffic + * throws TrexException in case of an error */ - rc_e stop_traffic(void); + void pause_traffic(void); /** - * access the stream table + * resume traffic + * throws TrexException in case of an error + */ + void resume_traffic(void); + + /** + * update current traffic on port * */ - TrexStreamTable *get_stream_table(); + void update_traffic(double mul); /** * get the port state * */ - port_state_e get_state() { + port_state_e get_state() const { return m_port_state; } @@ -84,7 +110,7 @@ public: * port state as string * */ - std::string get_state_as_string(); + std::string get_state_as_string() const; /** * fill up properties of the port @@ -96,6 +122,7 @@ public: */ void get_properties(std::string &driver, std::string &speed); + /** * query for ownership * @@ -113,10 +140,69 @@ public: return m_owner_handler; } - bool is_free_to_aquire() { - return (m_owner == "none"); + + bool verify_owner_handler(const std::string &handler) { + + return ( (m_owner != "none") && (m_owner_handler == handler) ); + } + /** + * encode stats as JSON + */ + void encode_stats(Json::Value &port); + + uint8_t get_port_id() { + return m_port_id; + } + + /** + * delegators + * + */ + + void add_stream(TrexStream *stream) { + verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS); + + m_stream_table.add_stream(stream); + + change_state(PORT_STATE_STREAMS); + } + + void remove_stream(TrexStream *stream) { + verify_state(PORT_STATE_STREAMS); + + m_stream_table.remove_stream(stream); + + if (m_stream_table.size() == 0) { + change_state(PORT_STATE_IDLE); + } + } + + void remove_and_delete_all_streams() { + verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS); + + m_stream_table.remove_and_delete_all_streams(); + + change_state(PORT_STATE_IDLE); + } + + TrexStream * get_stream_by_id(uint32_t stream_id) { + return m_stream_table.get_stream_by_id(stream_id); + } + + void get_id_list(std::vector &id_list) { + m_stream_table.get_id_list(id_list); + } + + void get_object_list(std::vector &object_list) { + m_stream_table.get_object_list(object_list); + } + +private: + + + /** * take ownership of the server array * this is static @@ -133,22 +219,14 @@ public: m_owner_handler = ""; } - bool verify_owner_handler(const std::string &handler) { - - return ( (m_owner != "none") && (m_owner_handler == handler) ); - + bool is_free_to_aquire() { + return (m_owner == "none"); } - /** - * encode stats as JSON - */ - void encode_stats(Json::Value &port); - uint8_t get_port_id() { - return m_port_id; - } + bool verify_state(int state, bool should_throw = true) const; -private: + void change_state(port_state_e new_state); std::string generate_handler(); -- cgit 1.2.3-korg From cc352e04fd45913132f3e1ddc86d88571c926879 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Wed, 11 Nov 2015 15:37:46 +0200 Subject: add first stl test and cleanup valgrind --- linux/ws_main.py | 19 +- src/bp_gtest.cpp | 18 -- src/bp_sim.cpp | 174 +++++++--- src/bp_sim.h | 46 ++- src/gtest/trex_stateless_gtest.cpp | 360 ++++++--------------- src/main.cpp | 47 ++- src/msg_manager.cpp | 26 +- src/msg_manager.h | 1 + src/pal/linux/mbuf.cpp | 7 + src/pal/linux/mbuf.h | 2 + src/pal/linux_dpdk/mbuf.h | 4 + src/stateless/cp/trex_stream.h | 4 +- src/stateless/cp/trex_streams_compiler.cpp | 2 +- src/stateless/dp/trex_stateless_dp_core.cpp | 44 ++- src/stateless/dp/trex_stateless_dp_core.h | 10 + src/stateless/dp/trex_stream_node.h | 10 +- src/stateless/messaging/trex_stateless_messaging.h | 1 + 17 files changed, 426 insertions(+), 349 deletions(-) (limited to 'src/gtest') diff --git a/linux/ws_main.py b/linux/ws_main.py index d020411a..65ca4522 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -238,9 +238,15 @@ bp =SrcGroups([ bp_sim_gtest, main_src, cmn_src , + net_src , yaml_src, - bp_hack_for_compile, + json_src, + stateless_src, + rpc_server_src + #rpc_server_mock_src, + + #bp_hack_for_compile, ]); @@ -393,10 +399,13 @@ class build_option: build_types = [ - build_option(name = "bp-sim", src = bp, debug_mode= DEBUG_, platform = PLATFORM_64, is_pie = False, - flags = ['-Wall', '-Werror', '-Wno-sign-compare', '-Wno-strict-aliasing']), - build_option(name = "bp-sim", src = bp, debug_mode= RELEASE_,platform = PLATFORM_64, is_pie = False, - flags = ['-Wall', '-Werror', '-Wno-sign-compare', '-Wno-strict-aliasing']), + build_option(name = "bp-sim", src = bp, use = ['zmq'],debug_mode= DEBUG_, platform = PLATFORM_64, is_pie = False, + flags = ['-Wall', '-Werror', '-Wno-sign-compare', '-Wno-strict-aliasing'], + rpath = ['.']), + + build_option(name = "bp-sim", src = bp, use = ['zmq'],debug_mode= RELEASE_,platform = PLATFORM_64, is_pie = False, + flags = ['-Wall', '-Werror', '-Wno-sign-compare', '-Wno-strict-aliasing'], + rpath = ['.']), build_option(name = "mock-rpc-server", use = ['zmq'], src = rpc_server_mock, debug_mode= DEBUG_,platform = PLATFORM_64, is_pie = False, flags = ['-DTREX_RPC_MOCK_SERVER', '-Wall', '-Werror', '-Wno-sign-compare'], diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp index 03ab74bd..a94c2d37 100755 --- a/src/bp_gtest.cpp +++ b/src/bp_gtest.cpp @@ -131,16 +131,6 @@ int test_human_p(){ -static bool was_init=false; - -void gtest_init_once(){ - - if ( !was_init ){ - CGlobalInfo::init_pools(1000); - time_init(); - was_init=true; - } -} @@ -259,7 +249,6 @@ public: class basic : public testing::Test { protected: virtual void SetUp() { - gtest_init_once(); } virtual void TearDown() { } @@ -269,7 +258,6 @@ public: class cpu : public testing::Test { protected: virtual void SetUp() { - gtest_init_once(); } virtual void TearDown() { } @@ -1199,7 +1187,6 @@ TEST_F(cpu, cpu3) { class timerwl : public testing::Test { protected: virtual void SetUp() { - gtest_init_once(); } virtual void TearDown() { } @@ -1450,7 +1437,6 @@ TEST_F(timerwl, many_timers_with_stop) { class rx_check : public testing::Test { protected: virtual void SetUp() { - gtest_init_once(); m_rx_check.Create(); } @@ -2142,7 +2128,6 @@ public: class rx_check_system : public testing::Test { protected: virtual void SetUp() { - gtest_init_once(); m_rx_check.m_callback=&m_callback; m_callback.mg =&m_mg; @@ -2420,8 +2405,6 @@ public: class nat_check_system : public testing::Test { protected: virtual void SetUp() { - gtest_init_once(); - m_rx_check.m_callback=&m_callback; m_callback.mg =&m_mg; m_mg.Create(); @@ -2467,7 +2450,6 @@ class file_flow_info : public testing::Test { protected: virtual void SetUp() { - gtest_init_once(); assert(m_flow_info.Create()); } diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index 0c0cbb75..c63ad1af 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -496,6 +496,26 @@ void CRteMemPool::dump(FILE *fd){ } //////////////////////////////////////// + +void CGlobalInfo::free_pools(){ + CPlatformSocketInfo * lpSocket =&m_socket; + CRteMemPool * lpmem; + int i; + for (i=0; i<(int)MAX_SOCKETS_SUPPORTED; i++) { + if (lpSocket->is_sockets_enable((socket_id_t)i)) { + lpmem= &m_mem_pool[i]; + utl_rte_mempool_delete(lpmem->m_big_mbuf_pool); + utl_rte_mempool_delete(lpmem->m_small_mbuf_pool); + utl_rte_mempool_delete(lpmem->m_mbuf_pool_128); + utl_rte_mempool_delete(lpmem->m_mbuf_pool_256); + utl_rte_mempool_delete(lpmem->m_mbuf_pool_512); + utl_rte_mempool_delete(lpmem->m_mbuf_pool_1024); + } + utl_rte_mempool_delete(m_mem_pool[0].m_mbuf_global_nodes); + } +} + + void CGlobalInfo::init_pools(uint32_t rx_buffers){ /* this include the pkt from 64- */ CGlobalMemory * lp=&CGlobalInfo::m_memory_cfg; @@ -748,9 +768,7 @@ int CErfIF::write_pkt(CCapPktRaw *pkt_raw){ int CErfIF::close_file(void){ BP_ASSERT(m_raw); - m_raw->raw=0; delete m_raw; - if ( m_preview_mode->getFileWrite() ){ BP_ASSERT(m_writer); delete m_writer; @@ -3054,6 +3072,16 @@ void CGenNode::DumpHeader(FILE *fd){ fprintf(fd," pkt_id,time,fid,pkt_info,pkt,len,type,is_init,is_last,type,thread_id,src_ip,dest_ip,src_port \n"); } + +void CGenNode::free_gen_node(){ + rte_mbuf_t * m=get_cache_mbuf(); + if ( unlikely(m != NULL) ) { + rte_pktmbuf_free(m); + m_plugin_info=0; + } +} + + void CGenNode::Dump(FILE *fd){ fprintf(fd,"%.6f,%llx,%p,%llu,%d,%d,%d,%d,%d,%d,%x,%x,%d\n", m_time, @@ -3123,6 +3151,15 @@ int CNodeGenerator::close_file(CFlowGenListPerThread * thread){ return (0); } +int CNodeGenerator::update_stl_stats(CGenNodeStateless *node_sl){ + if ( m_preview_mode.getVMode() >2 ){ + fprintf(stdout," %llu ,", (unsigned long long)m_cnt); + node_sl->Dump(stdout); + m_cnt++; + } + return (0); +} + int CNodeGenerator::update_stats(CGenNode * node){ if ( m_preview_mode.getVMode() >2 ){ @@ -3361,6 +3398,7 @@ void CFlowGenListPerThread::Delete(){ Clean(); m_cpu_cp_u.Delete(); + utl_rte_mempool_delete(m_node_pool); } @@ -3462,9 +3500,9 @@ int CNodeGenerator::flush_file(dsec_t max_time, } } - #ifndef RTE_DPDK - thread->check_msgs(); - #endif + //#ifndef RTE_DPDK + //thread->check_msgs(); + //#endif uint8_t type=node->m_type; @@ -3472,9 +3510,14 @@ int CNodeGenerator::flush_file(dsec_t max_time, m_p_queue.pop(); CGenNodeStateless *node_sl = (CGenNodeStateless *)node; + #ifdef _DEBUG + update_stl_stats(node_sl); + #endif + /* if the stream has been deactivated - end */ if (unlikely(!node_sl->is_active())) { thread->free_node(node); + } else { node_sl->handle(thread); } @@ -3899,41 +3942,26 @@ void CFlowGenListPerThread::check_msgs(void) { } } -void delay(int msec); +//void delay(int msec); -const uint8_t test_udp_pkt[]={ - 0x00,0x00,0x00,0x01,0x00,0x00, - 0x00,0x00,0x00,0x01,0x00,0x00, - 0x08,0x00, - 0x45,0x00,0x00,0x81, - 0xaf,0x7e,0x00,0x00, - 0x12,0x11,0xd9,0x23, - 0x01,0x01,0x01,0x01, - 0x3d,0xad,0x72,0x1b, - - 0x11,0x11, - 0x11,0x11, - - 0x00,0x6d, - 0x00,0x00, - - 0x64,0x31,0x3a,0x61, - 0x64,0x32,0x3a,0x69,0x64, - 0x32,0x30,0x3a,0xd0,0x0e, - 0xa1,0x4b,0x7b,0xbd,0xbd, - 0x16,0xc6,0xdb,0xc4,0xbb,0x43, - 0xf9,0x4b,0x51,0x68,0x33,0x72, - 0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f, - 0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3, - 0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f, - 0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39, - 0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31, - 0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d, - 0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d, - 0xe7 -}; +void CFlowGenListPerThread::start_stateless_simulation_file(std::string erf_file_name, + CPreviewMode &preview){ + m_preview_mode = preview; + m_node_gen.open_file(erf_file_name,&m_preview_mode); +} + +void CFlowGenListPerThread::stop_stateless_simulation_file(){ + m_node_gen.close_file(this); +} + +void CFlowGenListPerThread::start_stateless_daemon_simulation(){ + + m_cur_time_sec = 0; + m_stateless_dp_info.run_once(); + +} void CFlowGenListPerThread::start_stateless_daemon(){ m_cur_time_sec = 0; @@ -4002,6 +4030,12 @@ void CFlowGenListPerThread::start_generate_stateful(std::string erf_file_name, m_node_gen.close_file(this); } +void CFlowGenList::Delete(){ + clean_p_thread_info(); + Clean(); + delete CPluginCallback::callback; +} + bool CFlowGenList::Create(){ check_objects_sizes(); @@ -4033,10 +4067,6 @@ void CFlowGenList::clean_p_thread_info(void){ } -void CFlowGenList::Delete(){ - clean_p_thread_info(); - Clean(); -} int CFlowGenList::load_from_mac_file(std::string file_name) { if ( !utl_is_file_exists (file_name) ){ @@ -4570,24 +4600,54 @@ int CNullIF::send_node(CGenNode * node){ } -int CErfIF::send_node(CGenNode * node){ - if ( m_preview_mode->getFileWrite() ){ - CFlowPktInfo * lp=node->m_pkt_info; - rte_mbuf_t * m=lp->generate_new_mbuf(node); +void CErfIF::fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir){ fill_pkt(m_raw,m); + CPktNsecTimeStamp t_c(node->m_time); m_raw->time_nsec = t_c.m_time_nsec; m_raw->time_sec = t_c.m_time_sec; - - pkt_dir_t dir=node->cur_interface_dir(); uint8_t p_id = (uint8_t)dir; - m_raw->setInterface(p_id); +} + + +int CErfIFStl::send_node(CGenNode * _no_to_use){ + + if ( m_preview_mode->getFileWrite() ){ + + CGenNodeStateless * node_sl=(CGenNodeStateless *) _no_to_use; + + /* check that we have mbuf */ + rte_mbuf_t * m=node_sl->get_cache_mbuf(); + assert( m ); + pkt_dir_t dir=(pkt_dir_t)node_sl->get_mbuf_cache_dir(); + + fill_raw_packet(m,_no_to_use,dir); + BP_ASSERT(m_writer); + bool res=m_writer->write_packet(m_raw); + + + BP_ASSERT(res); + } + return (0); +} + + +int CErfIF::send_node(CGenNode * node){ + + if ( m_preview_mode->getFileWrite() ){ + + CFlowPktInfo * lp=node->m_pkt_info; + rte_mbuf_t * m=lp->generate_new_mbuf(node); + pkt_dir_t dir=node->cur_interface_dir(); + + fill_raw_packet(m,node,dir); /* update mac addr dest/src 12 bytes */ uint8_t *p=(uint8_t *)m_raw->raw; + int p_id=(int)dir; memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12); /* If vlan is enabled, add vlan header */ @@ -6807,6 +6867,24 @@ bool CSimplePacketParser::Parse(){ } +/* free the right object. + it is classic to use virtual function but we can't do it here and we don't even want to use callback function + as we want to save space and in most cases there is nothing to free. + this might be changed in the future + */ +void CGenNodeBase::free_base(){ + if ( m_type == FLOW_PKT ) { + CGenNode* p=(CGenNode*)this; + p->free_gen_node(); + return; + } + if (m_type==STATELESS_PKT) { + CGenNodeStateless* p=(CGenNodeStateless*)this; + p->free_stl_node(); + return; + } +} + diff --git a/src/bp_sim.h b/src/bp_sim.h index 36595581..eef5576b 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -328,6 +328,9 @@ public: CVirtualIF (){ m_preview_mode =NULL; } + + virtual ~CVirtualIF(){ + } public: virtual int open_file(std::string file_name)=0; @@ -1140,6 +1143,9 @@ public: class CGlobalInfo { public: static void init_pools(uint32_t rx_buffers); + /* for simulation */ + static void free_pools(); + static inline rte_mbuf_t * pktmbuf_alloc_small(socket_id_t socket){ return ( m_mem_pool[socket].pktmbuf_alloc_small() ); @@ -1376,7 +1382,9 @@ public: FLOW_PKT_NAT =3, FLOW_SYNC =4, /* called evey 1 msec */ STATELESS_PKT =5, - EXIT_SCHED =6 + EXIT_SCHED =6, + EXIT_PORT_SCHED =7 + }; @@ -1432,6 +1440,7 @@ public: } + void free_base(); }; @@ -1466,6 +1475,9 @@ public: uint32_t m_dest_idx; uint32_t m_end_of_cache_line[6]; + +public: + void free_gen_node(); public: void Dump(FILE *fd); @@ -1652,6 +1664,8 @@ public: + + #if __x86_64__ /* size of 64 bytes */ #define DEFER_CLIENTS_NUM (16) @@ -1802,11 +1816,24 @@ public: virtual int flush_tx_queue(void); -private: +protected: + + void fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir); + CFileWriterBase * m_writer; CCapPktRaw * m_raw; }; +/* for stateless we have a small changes in case we send the packets for optimization */ +class CErfIFStl : public CErfIF { + +public: + + virtual int send_node(CGenNode * node); +}; + + + static inline int fill_pkt(CCapPktRaw * raw,rte_mbuf_t * m){ raw->pkt_len = m->pkt_len; char *p=raw->raw; @@ -1903,6 +1930,8 @@ private: return (m_v_if->send_node(node)); } int update_stats(CGenNode * node); + int update_stl_stats(CGenNodeStateless *node_sl); + FORCE_NO_INLINE bool handle_slow_messages(uint8_t type, CGenNode * node, @@ -3412,6 +3441,14 @@ public: void start_generate_stateful(std::string erf_file_name,CPreviewMode &preview); void start_stateless_daemon(); + void start_stateless_daemon_simulation(); + + /* open a file for simulation */ + void start_stateless_simulation_file(std::string erf_file_name,CPreviewMode &preview); + /* close a file for simulation */ + void stop_stateless_simulation_file(); + + void Dump(FILE *fd); void DumpCsv(FILE *fd); @@ -3519,7 +3556,10 @@ inline CGenNode * CFlowGenListPerThread::create_node(void){ return (res); } + + inline void CFlowGenListPerThread::free_node(CGenNode *p){ + p->free_base(); rte_mempool_sp_put(m_node_pool, p); } @@ -4033,6 +4073,8 @@ enum MINVM_PLUGIN_ID{ class CPluginCallback { public: + virtual ~CPluginCallback(){ + } virtual void on_node_first(uint8_t plugin_id,CGenNode * node,CFlowYamlInfo * template_info, CTupleTemplateGeneratorSmart * tuple_gen,CFlowGenListPerThread * flow_gen) =0; virtual void on_node_last(uint8_t plugin_id,CGenNode * node)=0; virtual rte_mbuf_t * on_node_generate_mbuf(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info)=0; diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 2bab4dff..36e48f6e 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -22,332 +22,180 @@ limitations under the License. #include "bp_sim.h" #include #include +#include +#include +#include +#include +#include +#include +#include #define EXPECT_EQ_UINT32(a,b) EXPECT_EQ((uint32_t)(a),(uint32_t)(b)) -// one stream info with const packet , no VM -class CTRexDpStatelessVM { -}; - -//- add dump function -// - check one object -// create frame work -class CTRexDpStreamModeContinues{ +/* basic stateless test */ +class basic_stl : public testing::Test { + protected: + virtual void SetUp() { + } + virtual void TearDown() { + } public: - void set_pps(double pps){ - m_pps=pps; - } - double get_pps(){ - return (m_pps); - } - - void dump(FILE *fd); -private: - double m_pps; }; -void CTRexDpStreamModeContinues::dump(FILE *fd){ - fprintf (fd," pps : %f \n",m_pps); -} +class CBasicStl { - -class CTRexDpStreamModeSingleBurst{ public: - void set_pps(double pps){ - m_pps=pps; - } - double get_pps(){ - return (m_pps); - } - - void set_total_packets(uint64_t total_packets){ - m_total_packets =total_packets; - } - - uint64_t get_total_packets(){ - return (m_total_packets); + CBasicStl(){ + m_time_diff=0.001; + m_threads=1; } - void dump(FILE *fd); - -private: - double m_pps; - uint64_t m_total_packets; -}; - - -void CTRexDpStreamModeSingleBurst::dump(FILE *fd){ - fprintf (fd," pps : %f \n",m_pps); - fprintf (fd," total_packets : %llu \n", (unsigned long long)m_total_packets); -} - + bool init(void){ -class CTRexDpStreamModeMultiBurst{ -public: - void set_pps(double pps){ - m_pps=pps; - } - double get_pps(){ - return (m_pps); - } + CErfIFStl erf_vif; + fl.Create(); + fl.generate_p_thread_info(1); + CFlowGenListPerThread * lpt; - void set_pkts_per_burst(uint64_t pkts_per_burst){ - m_pkts_per_burst =pkts_per_burst; - } + fl.m_threads_info[0]->set_vif(&erf_vif); - uint64_t get_pkts_per_burst(){ - return (m_pkts_per_burst); - } + CErfCmp cmp; + cmp.dump=1; - void set_ibg(double ibg){ - m_ibg = ibg; - } + CMessagingManager * cp_dp = CMsgIns::Ins()->getCpDp(); - double get_ibg(){ - return ( m_ibg ); - } + m_ring_from_cp = cp_dp->getRingCpToDp(0); - void set_number_of_bursts(uint32_t number_of_bursts){ - m_number_of_bursts = number_of_bursts; - } - uint32_t get_number_of_bursts(){ - return (m_number_of_bursts); - } + bool res=true; - void dump(FILE *fd); + lpt=fl.m_threads_info[0]; -private: - double m_pps; - double m_ibg; // inter burst gap - uint64_t m_pkts_per_burst; - uint32_t m_number_of_bursts; -}; + char buf[100]; + char buf_ex[100]; + sprintf(buf,"%s-%d.erf",CGlobalInfo::m_options.out_file.c_str(),0); + sprintf(buf_ex,"%s-%d-ex.erf",CGlobalInfo::m_options.out_file.c_str(),0); -void CTRexDpStreamModeMultiBurst::dump(FILE *fd){ - fprintf (fd," pps : %f \n",m_pps); - fprintf (fd," total_packets : %llu \n", (unsigned long long)m_pkts_per_burst); - fprintf (fd," ibg : %f \n",m_ibg); - fprintf (fd," num_of_bursts : %lu \n", (ulong)m_number_of_bursts); -} + lpt->start_stateless_simulation_file(buf,CGlobalInfo::m_options.preview); + /* add stream to the queue */ + assert(m_msg); + assert(m_ring_from_cp->Enqueue((CGenNode *)m_msg)==0); -class CTRexDpStreamMode { -public: - enum MODES { - moCONTINUES = 0x0, - moSINGLE_BURST = 0x1, - moMULTI_BURST = 0x2 - } ; - typedef uint8_t MODE_TYPE_t; + lpt->start_stateless_daemon_simulation(); - void reset(); + #if 0 + lpt->m_node_gen.DumpHist(stdout); - void set_mode(MODE_TYPE_t mode ){ - m_type = mode; - } - MODE_TYPE_t get_mode(){ - return (m_type); - } + cmp.d_sec = m_time_diff; + if ( cmp.compare(std::string(buf),std::string(buf_ex)) != true ) { + res=false; + } - CTRexDpStreamModeContinues & cont(void){ - return (m_data.m_cont); - } - CTRexDpStreamModeSingleBurst & single_burst(void){ - return (m_data.m_signle_burst); - } + if ( m_dump_json ){ + printf(" dump json ...........\n"); + std::string s; + fl.m_threads_info[0]->m_node_gen.dump_json(s); + printf(" %s \n",s.c_str()); + } + #endif - CTRexDpStreamModeMultiBurst & multi_burst(void){ - return (m_data.m_multi_burst); + fl.Delete(); + return (res); } - void dump(FILE *fd); -private: - uint8_t m_type; - union Data { - CTRexDpStreamModeContinues m_cont; - CTRexDpStreamModeSingleBurst m_signle_burst; - CTRexDpStreamModeMultiBurst m_multi_burst; - } m_data; +public: + int m_threads; + double m_time_diff; + bool m_dump_json; + TrexStatelessCpToDpMsgBase * m_msg; + CNodeRing *m_ring_from_cp; + CFlowGenList fl; }; -void CTRexDpStreamMode::reset(){ - m_type =CTRexDpStreamMode::moCONTINUES; - memset(&m_data,0,sizeof(m_data)); -} - -void CTRexDpStreamMode::dump(FILE *fd){ - const char * table[3] = {"CONTINUES","SINGLE_BURST","MULTI_BURST"}; - - fprintf(fd," mode : %s \n", (char*)table[m_type]); - switch (m_type) { - case CTRexDpStreamMode::moCONTINUES : - cont().dump(fd); - break; - case CTRexDpStreamMode::moSINGLE_BURST : - single_burst().dump(fd); - break; - case CTRexDpStreamMode::moMULTI_BURST : - multi_burst().dump(fd); - break; - default: - fprintf(fd," ERROR type if not valid %d \n",m_type); - break; - } -} +const uint8_t my_test_pkt[]={ + 0x00,0x04,0x96,0x08,0xe0,0x40, + 0x00,0x0e,0x2e,0x24,0x37,0x5f, + 0x08,0x00, + 0x45,0x02,0x00,0x30, + 0x00,0x00,0x40,0x00, + 0x40,0x84,0xbd,0x04, + 0x9b,0xe6,0x18,0x9b, //sIP + 0xcb,0xff,0xfc,0xc2, //DIP -class CTRexDpStatelessStream { + 0x80,0x44,//SPORT + 0x00,0x50,//DPORT -public: - enum FLAGS_0{ - _ENABLE = 0, - _SELF_START = 1, - _VM_ENABLE =2, - _END_STREAM =-1 - }; - - CTRexDpStatelessStream(){ - reset(); - } + 0x00,0x00,0x00,0x00, //checksum - void reset(){ - m_packet =0; - m_vm=0; - m_flags=0; - m_isg_sec=0.0; - m_next_stream = CTRexDpStatelessStream::_END_STREAM ; // END - m_mode.reset(); - } + 0x11,0x22,0x33,0x44, // magic + 0x00,0x00,0x00,0x00, //64 bit counter + 0x00,0x00,0x00,0x00, + 0x00,0x01,0xa0,0x00, //seq + 0x00,0x00,0x00,0x00, +}; - void set_enable(bool enable){ - btSetMaskBit32(m_flags,_ENABLE,_ENABLE,enable?1:0); - } - bool get_enabled(){ - return (btGetMaskBit32(m_flags,_ENABLE,_ENABLE)?true:false); - } - void set_self_start(bool enable){ - btSetMaskBit32(m_flags,_SELF_START,_SELF_START,enable?1:0); - } - bool get_self_start(bool enable){ - return (btGetMaskBit32(m_flags,_SELF_START,_SELF_START)?true:false); - } +TEST_F(basic_stl, limit_single_pkt) { - /* if we don't have VM we could just replicate the mbuf and allocate it once */ - void set_vm_enable(bool enable){ - btSetMaskBit32(m_flags,_VM_ENABLE,_VM_ENABLE,enable?1:0); - } + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(0); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_single_sctp_pkt"; - bool get_vm_enabled(bool enable){ - return (btGetMaskBit32(m_flags,_VM_ENABLE,_VM_ENABLE)?true:false); - } + TrexStreamsCompiler compile; - void set_inter_stream_gap(double isg_sec){ - m_isg_sec =isg_sec; - } - double get_inter_stream_gap(){ - return (m_isg_sec); - } + std::vector streams; - CTRexDpStreamMode & get_mode(); + TrexStream * stream1 = new TrexStreamContinuous(0,0,1.0); + stream1->m_enabled = true; + stream1->m_self_start = true; + uint8_t *binary = new uint8_t[sizeof(my_test_pkt)]; + memcpy(binary,my_test_pkt,sizeof(my_test_pkt)); - // CTRexDpStatelessStream::_END_STREAM for END - void set_next_stream(int32_t next_stream){ - m_next_stream =next_stream; - } + stream1->m_pkt.binary = binary; + stream1->m_pkt.len = sizeof(my_test_pkt); - int32_t get_next_stream(void){ - return ( m_next_stream ); - } - void dump(FILE *fd); + streams.push_back(stream1); -private: - char * m_packet; - CTRexDpStatelessVM * m_vm; - uint32_t m_flags; - double m_isg_sec; // in second - CTRexDpStreamMode m_mode; - int32_t m_next_stream; // next stream id -}; + // stream - clean -//- list of streams info with const packet , no VM -// - object that include the stream /scheduler/ packet allocation / need to create an object for one thread that works for test -// generate pcap file and compare it - -#if 0 -void CTRexDpStatelessStream::dump(FILE *fd){ - - fprintf(fd," enabled : %d \n",get_enabled()?1:0); - fprintf(fd," self_start : %d \n",get_self_start()?1:0); - fprintf(fd," vm : %d \n",get_vm_enabled()?1:0); - fprintf(" isg : %f \n",m_isg_sec); - m_mode.dump(fd); - if (m_next_stream == CTRexDpStatelessStream::_END_STREAM ) { - fprintf(fd," action : End of Stream \n"); - }else{ - fprintf(" next : %d \n",m_next_stream); - } -} + TrexStreamsCompiledObj comp_obj(0,1.0); + assert(compile.compile(streams, comp_obj) ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); -class CTRexStatelessBasic { - -public: - CTRexStatelessBasic(){ - m_threads=1; - } - - bool init(void){ - return (true); - } - -public: - bool m_threads; -}; + t1.m_msg = lpstart; + bool res=t1.init(); -/* stateless basic */ -class dp_sl_basic : public testing::Test { - protected: - virtual void SetUp() { - } - virtual void TearDown() { - } -public: -}; - + delete stream1 ; - -TEST_F(dp_sl_basic, test1) { - CTRexDpStatelessStream s1; - s1.set_enable(true); - s1.set_self_start(true); - s1.set_inter_stream_gap(0.77); - s1.get_mode().set_mode(CTRexDpStreamMode::moCONTINUES); - s1.get_mode().cont().set_pps(100.2); - s1.dump(stdout); + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; } + #endif diff --git a/src/main.cpp b/src/main.cpp index df9d8b40..64547d57 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,8 @@ limitations under the License. #include #include +#include + // An enum for all the option types enum { OPT_HELP, OPT_CFG, OPT_NODE_DUMP, OP_STATS, @@ -94,21 +96,20 @@ static int usage(){ int gtest_main(int argc, char **argv) ; -static int parse_options(int argc, char *argv[], CParserOption* po ) { +static int parse_options(int argc, char *argv[], CParserOption* po, bool & is_gtest ) { CSimpleOpt args(argc, argv, parser_options); int a=0; int node_dump=0; po->preview.clean(); po->preview.setFileWrite(true); - int res1; while ( args.Next() ){ if (args.LastError() == SO_SUCCESS) { switch (args.OptionId()) { case OPT_UT : - res1=gtest_main(argc, argv); - exit(res1); + is_gtest=true; + return (0); break; case OPT_HELP: usage(); @@ -749,18 +750,50 @@ int merge_2_cap_files_sip() { return (0); } +static TrexStateless *g_trex_stateless; + + +TrexStateless * get_stateless_obj() { + return g_trex_stateless; +} + +extern "C" const char * get_build_date(void){ + return (__DATE__); +} + +extern "C" const char * get_build_time(void){ + return (__TIME__ ); +} + + int main(int argc , char * argv[]){ + int res=0; time_init(); CGlobalInfo::m_socket.Create(0); - CGlobalInfo::init_pools(1000); assert( CMsgIns::Ins()->Create(4) ); - if ( parse_options(argc, argv, &CGlobalInfo::m_options ) != 0){ + + bool is_gtest=false; + + if ( parse_options(argc, argv, &CGlobalInfo::m_options , is_gtest) != 0){ exit(-1); } - return (load_list_of_cap_files(&CGlobalInfo::m_options)); + + if ( is_gtest ) { + res = gtest_main(argc, argv); + }else{ + res = load_list_of_cap_files(&CGlobalInfo::m_options); + } + + CMsgIns::Ins()->Free(); + CGlobalInfo::free_pools(); + CGlobalInfo::m_socket.Delete(); + + + return (res); + } diff --git a/src/msg_manager.cpp b/src/msg_manager.cpp index 9f41d08c..5fe44771 100755 --- a/src/msg_manager.cpp +++ b/src/msg_manager.cpp @@ -51,15 +51,20 @@ bool CMessagingManager::Create(uint8_t num_dp_threads,std::string a_name){ return (true); } void CMessagingManager::Delete(){ - if (m_dp_to_cp) { - m_dp_to_cp->Delete(); - delete []m_dp_to_cp; - } - if (m_cp_to_dp) { - m_cp_to_dp->Delete(); - delete []m_cp_to_dp; + + assert(m_cp_to_dp); + assert(m_dp_to_cp); + int i; + for (i=0; iDelete(); + lp=getRingDpToCp(i); + lp->Delete(); } + delete []m_dp_to_cp; + delete []m_cp_to_dp; } CNodeRing * CMessagingManager::getRingCpToDp(uint8_t thread_id){ @@ -76,6 +81,7 @@ CNodeRing * CMessagingManager::getRingDpToCp(uint8_t thread_id){ void CMsgIns::Free(){ if (m_ins) { + m_ins->Delete(); delete m_ins; } } @@ -98,6 +104,12 @@ bool CMsgIns::Create(uint8_t num_threads){ } +void CMsgIns::Delete(){ + m_cp_dp.Delete(); + m_rx_dp.Delete(); +} + + CMsgIns * CMsgIns::m_ins=0; diff --git a/src/msg_manager.h b/src/msg_manager.h index 8958f826..0390ce10 100755 --- a/src/msg_manager.h +++ b/src/msg_manager.h @@ -98,6 +98,7 @@ public: static CMsgIns * Ins(); static void Free(); bool Create(uint8_t num_threads); + void Delete(); public: CMessagingManager * getRxDp(){ return (&m_rx_dp); diff --git a/src/pal/linux/mbuf.cpp b/src/pal/linux/mbuf.cpp index 7eca8fd5..26a54fe9 100755 --- a/src/pal/linux/mbuf.cpp +++ b/src/pal/linux/mbuf.cpp @@ -78,6 +78,13 @@ rte_mempool_t * utl_rte_mempool_create(const char *name, return p; } +void utl_rte_mempool_delete(rte_mempool_t * & pool){ + if (pool) { + delete pool; + pool=0; + } +} + uint16_t rte_mbuf_refcnt_update(rte_mbuf_t *m, int16_t value) { diff --git a/src/pal/linux/mbuf.h b/src/pal/linux/mbuf.h index 35a442bf..4132f842 100755 --- a/src/pal/linux/mbuf.h +++ b/src/pal/linux/mbuf.h @@ -65,6 +65,8 @@ typedef struct rte_mempool rte_mempool_t; #define RTE_PKTMBUF_HEADROOM 0 +void utl_rte_mempool_delete(rte_mempool_t * &pool); + rte_mempool_t * utl_rte_mempool_create(const char *name, unsigned n, unsigned elt_size, diff --git a/src/pal/linux_dpdk/mbuf.h b/src/pal/linux_dpdk/mbuf.h index cde01077..339c0909 100755 --- a/src/pal/linux_dpdk/mbuf.h +++ b/src/pal/linux_dpdk/mbuf.h @@ -30,6 +30,10 @@ typedef struct rte_mbuf rte_mbuf_t; typedef struct rte_mempool rte_mempool_t; +inline void utl_rte_mempool_delete(rte_mempool_t * & pool){ +} + + rte_mempool_t * utl_rte_mempool_create(const char *name, unsigned n, unsigned elt_size, diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index c8a15240..d1a44909 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -40,7 +40,7 @@ class TrexStream { public: TrexStream(uint8_t port_id, uint32_t stream_id); - virtual ~TrexStream() = 0; + virtual ~TrexStream(); /* defines the min max per packet supported */ static const uint32_t MIN_PKT_SIZE_BYTES = 1; @@ -88,6 +88,8 @@ public: /* original template provided by requester */ Json::Value m_stream_json; + + }; /** diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index 06c0119a..667da158 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -31,7 +31,7 @@ TrexStreamsCompiledObj::TrexStreamsCompiledObj(uint8_t port_id, double mul) : m_ TrexStreamsCompiledObj::~TrexStreamsCompiledObj() { for (auto &obj : m_objs) { - delete obj.m_pkt; + delete [] obj.m_pkt; } m_objs.clear(); } diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index b2bd0152..c9e47090 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -31,6 +31,18 @@ usec_to_sec(double usec) { } + +void CGenNodeStateless::free_stl_node(){ + /* if we have cache mbuf free it */ + rte_mbuf_t * m=get_cache_mbuf(); + if (m) { + rte_pktmbuf_free(m); + m_cache_mbuf=0; + } +} + + + void TrexStatelessDpCore::create(uint8_t thread_id, CFlowGenListPerThread *core) { m_thread_id = thread_id; @@ -79,16 +91,41 @@ TrexStatelessDpCore::start_scheduler() { m_core->m_node_gen.close_file(m_core); } + +void +TrexStatelessDpCore::run_once(){ + + idle_state_loop(); + start_scheduler(); +} + + void TrexStatelessDpCore::start() { while (true) { - idle_state_loop(); + run_once(); + } +} + +void +TrexStatelessDpCore::add_duration(uint8_t port_id, + double duration){ + if (duration > 0.0) { + + CGenNode *node = m_core->create_node() ; + + node->m_type = CGenNode::EXIT_SCHED; + + /* make sure it will be scheduled after the current node */ + node->m_time = m_core->m_cur_time_sec + duration ; + + m_core->m_node_gen.add_node(node); - start_scheduler(); } } + void TrexStatelessDpCore::add_cont_stream(uint8_t port_id, double isg_usec, @@ -155,6 +192,9 @@ TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj) { single_stream.m_pkt, single_stream.m_pkt_len); } + + /* TBD need to fix this */ + add_duration(0,10.0); } void diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index f4dbad08..a23e81c9 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -45,6 +45,7 @@ public: TrexStatelessDpCore() { m_thread_id = 0; m_core = NULL; + m_duration = -1; } /** @@ -61,6 +62,10 @@ public: */ void start(); + + /* exit after batch of commands */ + void run_once(); + /** * dummy traffic creator * @@ -126,6 +131,9 @@ private: */ void handle_cp_msg(TrexStatelessCpToDpMsgBase *msg); + void add_duration(uint8_t port_id, + double duration); + void add_cont_stream(uint8_t dir, double isg, double pps, @@ -142,6 +150,8 @@ private: /* pointer to the main object */ CFlowGenListPerThread *m_core; + + double m_duration; }; #endif /* __TREX_STATELESS_DP_CORE_H__ */ diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index 92b428ab..2ffe04c3 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -22,6 +22,7 @@ limitations under the License. #define __TREX_STREAM_NODE_H__ #include +#include class TrexStatelessDpCore; @@ -42,6 +43,7 @@ private: public: + inline bool is_active() { return m_is_stream_active; } @@ -82,8 +84,6 @@ public: return ((pkt_dir_t)( m_flags &1)); } - - inline void set_cache_mbuf(rte_mbuf_t * m){ m_cache_mbuf=(void *)m; m_flags |= NODE_FLAGS_MBUF_CACHE; @@ -97,6 +97,12 @@ public: } } + void free_stl_node(); + + + void Dump(FILE *fd){ + fprintf(fd," %f, %lu, %lu \n",m_time,(ulong)m_port_id,(ulong)get_mbuf_cache_dir()); + } } __rte_cache_aligned; diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index 7978b7f9..d288fc83 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -74,6 +74,7 @@ public: virtual TrexStatelessCpToDpMsgBase * clone(); + private: TrexStreamsCompiledObj *m_obj; }; -- cgit 1.2.3-korg From d5361e483d135e60b1b40a05b283cf704697504a Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Wed, 11 Nov 2015 15:48:44 +0200 Subject: remove default duration --- src/gtest/trex_stateless_gtest.cpp | 3 ++- src/stateless/dp/trex_stateless_dp_core.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/gtest') diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 36e48f6e..9634d01f 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -46,6 +46,7 @@ public: }; + class CBasicStl { public: @@ -198,4 +199,4 @@ TEST_F(basic_stl, limit_single_pkt) { -#endif + diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index c9e47090..480606e8 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -194,7 +194,7 @@ TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj) { } /* TBD need to fix this */ - add_duration(0,10.0); + //add_duration(0,10.0); } void -- cgit 1.2.3-korg From 6294136db42a3327049c67c12eab4684c4abbe47 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Wed, 11 Nov 2015 16:14:28 +0200 Subject: fix duration for stl tests --- scripts/exp/stl_single_sctp_pkt-0-ex.erf | Bin 0 -> 880 bytes src/gtest/trex_stateless_gtest.cpp | 8 ++++---- src/stateless/cp/trex_streams_compiler.cpp | 4 +++- src/stateless/cp/trex_streams_compiler.h | 8 ++++++++ src/stateless/dp/trex_stateless_dp_core.cpp | 13 +++++++------ src/stateless/dp/trex_stateless_dp_core.h | 4 ++-- 6 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 scripts/exp/stl_single_sctp_pkt-0-ex.erf (limited to 'src/gtest') diff --git a/scripts/exp/stl_single_sctp_pkt-0-ex.erf b/scripts/exp/stl_single_sctp_pkt-0-ex.erf new file mode 100644 index 00000000..5b991b8f Binary files /dev/null and b/scripts/exp/stl_single_sctp_pkt-0-ex.erf differ diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 9634d01f..7850e8da 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -53,6 +53,7 @@ public: CBasicStl(){ m_time_diff=0.001; m_threads=1; + m_dump_json=false; } bool init(void){ @@ -90,7 +91,6 @@ public: lpt->start_stateless_daemon_simulation(); - #if 0 lpt->m_node_gen.DumpHist(stdout); @@ -99,14 +99,12 @@ public: res=false; } - if ( m_dump_json ){ printf(" dump json ...........\n"); std::string s; fl.m_threads_info[0]->m_node_gen.dump_json(s); printf(" %s \n",s.c_str()); } - #endif fl.Delete(); return (res); @@ -156,7 +154,7 @@ TEST_F(basic_stl, limit_single_pkt) { CBasicStl t1; CParserOption * po =&CGlobalInfo::m_options; - po->preview.setVMode(0); + po->preview.setVMode(7); po->preview.setFileWrite(true); po->out_file ="exp/stl_single_sctp_pkt"; @@ -182,10 +180,12 @@ TEST_F(basic_stl, limit_single_pkt) { TrexStreamsCompiledObj comp_obj(0,1.0); + comp_obj.set_simulation_duration( 10.0); assert(compile.compile(streams, comp_obj) ); TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); + t1.m_msg = lpstart; bool res=t1.init(); diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index 8238bac7..7891077b 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -34,6 +34,7 @@ TrexStreamsCompiledObj::~TrexStreamsCompiledObj() { delete [] obj.m_pkt; } m_objs.clear(); + m_duration_sim=-1.0; } void @@ -67,9 +68,10 @@ TrexStreamsCompiledObj::clone() { obj.m_pkt_len); } - /* fix the multiplier */ new_compiled_obj->m_mul = m_mul; + new_compiled_obj->m_duration_sim = m_duration_sim; + return new_compiled_obj; } diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 404fdd21..d86d16c6 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -51,6 +51,13 @@ public: return m_objs; } + void set_simulation_duration(double duration){ + m_duration_sim=duration; + } + + double get_simulation_duration(){ + return (m_duration_sim); + } /** * clone the compiled object * @@ -63,6 +70,7 @@ private: uint8_t m_port_id; double m_mul; + double m_duration_sim; /* duration for all simulation */ }; class TrexStreamsCompiler { diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 480606e8..e1664bd9 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -109,10 +109,8 @@ TrexStatelessDpCore::start() { } void -TrexStatelessDpCore::add_duration(uint8_t port_id, - double duration){ +TrexStatelessDpCore::add_duration(double duration){ if (duration > 0.0) { - CGenNode *node = m_core->create_node() ; node->m_type = CGenNode::EXIT_SCHED; @@ -121,7 +119,6 @@ TrexStatelessDpCore::add_duration(uint8_t port_id, node->m_time = m_core->m_cur_time_sec + duration ; m_core->m_node_gen.add_node(node); - } } @@ -193,8 +190,12 @@ TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj) { single_stream.m_pkt_len); } - /* TBD need to fix this */ - //add_duration(0,10.0); + double duration=obj->get_simulation_duration(); + printf("duration %f \n",duration); + + if ( duration >0.0){ + add_duration( duration ); + } } void diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index a23e81c9..51f882b2 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -131,8 +131,8 @@ private: */ void handle_cp_msg(TrexStatelessCpToDpMsgBase *msg); - void add_duration(uint8_t port_id, - double duration); + /* add global exit */ + void add_duration(double duration); void add_cont_stream(uint8_t dir, double isg, -- cgit 1.2.3-korg From 151266e34245b99ce4cac70d82be79bfb5a3ebf9 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Wed, 11 Nov 2015 22:10:05 +0200 Subject: add support for multi-burst --- scripts/exp/stl_multi_burst1-0-ex.erf | Bin 0 -> 1320 bytes scripts/exp/stl_multi_pkt1-0-ex.erf | Bin 0 -> 2640 bytes scripts/exp/stl_multi_pkt2-0-ex.erf | Bin 0 -> 4488 bytes scripts/exp/stl_single_pkt_burst1-0-ex.erf | Bin 0 -> 440 bytes scripts/exp/stl_single_stream-0-ex.erf | Bin 0 -> 880 bytes src/bp_sim.cpp | 1 - src/gtest/trex_stateless_gtest.cpp | 324 +++++++++++++++++++++++++--- src/stateless/cp/trex_stream.h | 42 ++-- src/stateless/cp/trex_streams_compiler.cpp | 29 +-- src/stateless/cp/trex_streams_compiler.h | 13 +- src/stateless/dp/trex_stateless_dp_core.cpp | 61 ++++-- src/stateless/dp/trex_stateless_dp_core.h | 7 +- src/stateless/dp/trex_stream_node.h | 90 +++++++- 13 files changed, 464 insertions(+), 103 deletions(-) create mode 100644 scripts/exp/stl_multi_burst1-0-ex.erf create mode 100644 scripts/exp/stl_multi_pkt1-0-ex.erf create mode 100644 scripts/exp/stl_multi_pkt2-0-ex.erf create mode 100644 scripts/exp/stl_single_pkt_burst1-0-ex.erf create mode 100644 scripts/exp/stl_single_stream-0-ex.erf (limited to 'src/gtest') diff --git a/scripts/exp/stl_multi_burst1-0-ex.erf b/scripts/exp/stl_multi_burst1-0-ex.erf new file mode 100644 index 00000000..c5cc7484 Binary files /dev/null and b/scripts/exp/stl_multi_burst1-0-ex.erf differ diff --git a/scripts/exp/stl_multi_pkt1-0-ex.erf b/scripts/exp/stl_multi_pkt1-0-ex.erf new file mode 100644 index 00000000..de109191 Binary files /dev/null and b/scripts/exp/stl_multi_pkt1-0-ex.erf differ diff --git a/scripts/exp/stl_multi_pkt2-0-ex.erf b/scripts/exp/stl_multi_pkt2-0-ex.erf new file mode 100644 index 00000000..eec33117 Binary files /dev/null and b/scripts/exp/stl_multi_pkt2-0-ex.erf differ diff --git a/scripts/exp/stl_single_pkt_burst1-0-ex.erf b/scripts/exp/stl_single_pkt_burst1-0-ex.erf new file mode 100644 index 00000000..08afdf4b Binary files /dev/null and b/scripts/exp/stl_single_pkt_burst1-0-ex.erf differ diff --git a/scripts/exp/stl_single_stream-0-ex.erf b/scripts/exp/stl_single_stream-0-ex.erf new file mode 100644 index 00000000..92883717 Binary files /dev/null and b/scripts/exp/stl_single_stream-0-ex.erf differ diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index c63ad1af..39d46d16 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -3517,7 +3517,6 @@ int CNodeGenerator::flush_file(dsec_t max_time, /* if the stream has been deactivated - end */ if (unlikely(!node_sl->is_active())) { thread->free_node(node); - } else { node_sl->handle(thread); } diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 7850e8da..1ea0373c 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -91,8 +91,7 @@ public: lpt->start_stateless_daemon_simulation(); - lpt->m_node_gen.DumpHist(stdout); - + //lpt->m_node_gen.DumpHist(stdout); cmp.d_sec = m_time_diff; if ( cmp.compare(std::string(buf),std::string(buf_ex)) != true ) { @@ -121,42 +120,161 @@ public: }; +class CPcapLoader { +public: + CPcapLoader(); + ~CPcapLoader(); + + +public: + bool load_pcap_file(std::string file,int pkt_id=0); + void update_ip_src(uint32_t ip_addr); + void clone_packet_into_stream(TrexStream * stream); + void dump_packet(); + +public: + bool m_valid; + CCapPktRaw m_raw; + CPacketIndication m_pkt_indication; +}; + +CPcapLoader::~CPcapLoader(){ +} -const uint8_t my_test_pkt[]={ +bool CPcapLoader::load_pcap_file(std::string cap_file,int pkt_id){ + m_valid=false; + CPacketParser parser; - 0x00,0x04,0x96,0x08,0xe0,0x40, - 0x00,0x0e,0x2e,0x24,0x37,0x5f, - 0x08,0x00, + CCapReaderBase * lp=CCapReaderFactory::CreateReader((char *)cap_file.c_str(),0); - 0x45,0x02,0x00,0x30, - 0x00,0x00,0x40,0x00, - 0x40,0x84,0xbd,0x04, - 0x9b,0xe6,0x18,0x9b, //sIP - 0xcb,0xff,0xfc,0xc2, //DIP + if (lp == 0) { + printf(" ERROR file %s does not exist or not supported \n",(char *)cap_file.c_str()); + return false; + } - 0x80,0x44,//SPORT - 0x00,0x50,//DPORT + int cnt=0; + bool found =false; - 0x00,0x00,0x00,0x00, //checksum - 0x11,0x22,0x33,0x44, // magic - 0x00,0x00,0x00,0x00, //64 bit counter - 0x00,0x00,0x00,0x00, - 0x00,0x01,0xa0,0x00, //seq - 0x00,0x00,0x00,0x00, -}; + while ( true ) { + /* read packet */ + if ( lp->ReadPacket(&m_raw) ==false ){ + break; + } + if (cnt==pkt_id) { + found = true; + break; + } + cnt++; + } + if ( found ){ + if ( parser.ProcessPacket(&m_pkt_indication, &m_raw) ){ + m_valid = true; + } + } + + delete lp; + return (m_valid); +} + +void CPcapLoader::update_ip_src(uint32_t ip_addr){ + + if ( m_pkt_indication.l3.m_ipv4 ) { + m_pkt_indication.l3.m_ipv4->setSourceIp(ip_addr); + m_pkt_indication.l3.m_ipv4->updateCheckSum(); + } +} + +void CPcapLoader::clone_packet_into_stream(TrexStream * stream){ + + uint16_t pkt_size=m_raw.getTotalLen(); + uint8_t *binary = new uint8_t[pkt_size]; + memcpy(binary,m_raw.raw,pkt_size); + stream->m_pkt.binary = binary; + stream->m_pkt.len = pkt_size; +} + + + + +CPcapLoader::CPcapLoader(){ + +} + +void CPcapLoader::dump_packet(){ + if (m_valid ) { + m_pkt_indication.Dump(stdout,1); + }else{ + fprintf(stdout," no packets were found \n"); + } +} + + +TEST_F(basic_stl, load_pcap_file) { + printf (" stateles %d \n",(int)sizeof(CGenNodeStateless)); + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + //pcap.dump_packet(); +} -TEST_F(basic_stl, limit_single_pkt) { +TEST_F(basic_stl, single_pkt_burst1) { CBasicStl t1; CParserOption * po =&CGlobalInfo::m_options; po->preview.setVMode(7); po->preview.setFileWrite(true); - po->out_file ="exp/stl_single_sctp_pkt"; + po->out_file ="exp/stl_single_pkt_burst1"; + + TrexStreamsCompiler compile; + + + std::vector streams; + + TrexStream * stream1 = new TrexStreamBurst(0,0,5, 1.0); + stream1->m_enabled = true; + stream1->m_self_start = true; + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + TrexStreamsCompiledObj comp_obj(0,1.0); + + comp_obj.set_simulation_duration( 10.0); + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); + + + t1.m_msg = lpstart; + + bool res=t1.init(); + + delete stream1 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + + + +TEST_F(basic_stl, single_pkt) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_single_stream"; TrexStreamsCompiler compile; @@ -167,11 +285,11 @@ TEST_F(basic_stl, limit_single_pkt) { stream1->m_enabled = true; stream1->m_self_start = true; - uint8_t *binary = new uint8_t[sizeof(my_test_pkt)]; - memcpy(binary,my_test_pkt,sizeof(my_test_pkt)); - stream1->m_pkt.binary = binary; - stream1->m_pkt.len = sizeof(my_test_pkt); + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); streams.push_back(stream1); @@ -196,6 +314,160 @@ TEST_F(basic_stl, limit_single_pkt) { } +TEST_F(basic_stl, multi_pkt1) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_multi_pkt1"; + + TrexStreamsCompiler compile; + + + std::vector streams; + + TrexStream * stream1 = new TrexStreamContinuous(0,0,1.0); + stream1->m_enabled = true; + stream1->m_self_start = true; + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + + TrexStream * stream2 = new TrexStreamContinuous(0,1,2.0); + stream2->m_enabled = true; + stream2->m_self_start = true; + stream2->m_isg_usec = 1000.0; /* 1 msec */ + pcap.update_ip_src(0x20000001); + pcap.clone_packet_into_stream(stream2); + + streams.push_back(stream2); + + + // stream - clean + TrexStreamsCompiledObj comp_obj(0,1.0); + + comp_obj.set_simulation_duration( 10.0); + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); + + t1.m_msg = lpstart; + + bool res=t1.init(); + + delete stream1 ; + delete stream2 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + + + + +/* check disabled stream with multiplier of 5*/ +TEST_F(basic_stl, multi_pkt2) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_multi_pkt2"; + + TrexStreamsCompiler compile; + + + std::vector streams; + + TrexStream * stream1 = new TrexStreamContinuous(0,0,1.0); + stream1->m_enabled = true; + stream1->m_self_start = true; + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + + TrexStream * stream2 = new TrexStreamContinuous(0,1,2.0); + stream2->m_enabled = false; + stream2->m_self_start = false; + stream2->m_isg_usec = 1000.0; /* 1 msec */ + pcap.update_ip_src(0x20000001); + pcap.clone_packet_into_stream(stream2); + + streams.push_back(stream2); + + + // stream - clean + TrexStreamsCompiledObj comp_obj(0,5.0); + + comp_obj.set_simulation_duration( 10.0); + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); + + t1.m_msg = lpstart; + + bool res=t1.init(); + + delete stream1 ; + delete stream2 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + +TEST_F(basic_stl, multi_burst1) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_multi_burst1"; + + TrexStreamsCompiler compile; + + + std::vector streams; + + + + TrexStream * stream1 = new TrexStreamMultiBurst(0,0,5, 1.0,3,2000000.0); + stream1->m_enabled = true; + stream1->m_self_start = true; + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + TrexStreamsCompiledObj comp_obj(0,1.0); + + comp_obj.set_simulation_duration( 40.0); + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); + + + t1.m_msg = lpstart; + + bool res=t1.init(); + + delete stream1 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index d1a44909..5e6ac19a 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -38,6 +38,15 @@ class TrexRpcCmdAddStream; */ class TrexStream { +public: + enum STREAM_TYPE { + stNONE = 0, + stCONTINUOUS = 4, + stSINGLE_BURST = 5, + stMULTI_BURST = 6 + }; + + public: TrexStream(uint8_t port_id, uint32_t stream_id); virtual ~TrexStream(); @@ -52,8 +61,14 @@ public: /* access the stream json */ const Json::Value & get_stream_json(); + double get_pps() { + return m_pps; + } + + public: /* basic */ + uint8_t m_type; uint8_t m_port_id; uint32_t m_stream_id; @@ -85,6 +100,8 @@ public: } m_rx_check; + double m_pps; + /* original template provided by requester */ Json::Value m_stream_json; @@ -98,15 +115,10 @@ public: */ class TrexStreamContinuous : public TrexStream { public: - TrexStreamContinuous(uint8_t port_id, uint32_t stream_id, double pps) : TrexStream(port_id, stream_id), m_pps(pps) { + TrexStreamContinuous(uint8_t port_id, uint32_t stream_id, double pps) : TrexStream(port_id, stream_id) { + m_type= TrexStream::stCONTINUOUS; + m_pps=pps; } - - double get_pps() { - return m_pps; - } - -protected: - double m_pps; }; /** @@ -117,13 +129,14 @@ class TrexStreamBurst : public TrexStream { public: TrexStreamBurst(uint8_t port_id, uint32_t stream_id, uint32_t total_pkts, double pps) : TrexStream(port_id, stream_id), - m_total_pkts(total_pkts), - m_pps(pps) { + m_total_pkts(total_pkts){ + m_type= TrexStream::stSINGLE_BURST; + m_pps=pps; + } -protected: +public: uint32_t m_total_pkts; - double m_pps; }; /** @@ -138,9 +151,10 @@ public: double pps, uint32_t num_bursts, double ibg_usec) : TrexStreamBurst(port_id, stream_id, pkts_per_burst, pps), m_num_bursts(num_bursts), m_ibg_usec(ibg_usec) { - + m_type= TrexStream::stMULTI_BURST; } -protected: + +public: uint32_t m_num_bursts; double m_ibg_usec; diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index 7891077b..c7b881c5 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -30,24 +30,15 @@ TrexStreamsCompiledObj::TrexStreamsCompiledObj(uint8_t port_id, double mul) : m_ } TrexStreamsCompiledObj::~TrexStreamsCompiledObj() { - for (auto &obj : m_objs) { - delete [] obj.m_pkt; - } m_objs.clear(); m_duration_sim=-1.0; } void -TrexStreamsCompiledObj::add_compiled_stream(double isg_usec, double pps, uint8_t *pkt, uint16_t pkt_len) { +TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream) { obj_st obj; - obj.m_isg_usec = isg_usec; - obj.m_port_id = m_port_id; - obj.m_pps = pps * m_mul; - obj.m_pkt_len = pkt_len; - - obj.m_pkt = new uint8_t[pkt_len]; - memcpy(obj.m_pkt, pkt, pkt_len); + obj.m_stream = stream; m_objs.push_back(obj); } @@ -62,10 +53,7 @@ TrexStreamsCompiledObj::clone() { * clone each element */ for (auto obj : m_objs) { - new_compiled_obj->add_compiled_stream(obj.m_isg_usec, - obj.m_pps, - obj.m_pkt, - obj.m_pkt_len); + new_compiled_obj->add_compiled_stream(obj.m_stream); } new_compiled_obj->m_mul = m_mul; @@ -93,17 +81,8 @@ TrexStreamsCompiler::compile(const std::vector &streams, TrexStrea continue; } - /* for now support only continous ... */ - TrexStreamContinuous *cont_stream = dynamic_cast(stream); - if (!cont_stream) { - continue; - } - /* add it */ - obj.add_compiled_stream(cont_stream->m_isg_usec, - cont_stream->get_pps(), - cont_stream->m_pkt.binary, - cont_stream->m_pkt.len); + obj.add_compiled_stream(stream); } return true; diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index d86d16c6..78ac1ac7 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -40,11 +40,8 @@ public: ~TrexStreamsCompiledObj(); struct obj_st { - double m_isg_usec; - double m_pps; - uint8_t *m_pkt; - uint16_t m_pkt_len; - uint8_t m_port_id; + + TrexStream * m_stream; }; const std::vector & get_objects() { @@ -64,8 +61,12 @@ public: */ TrexStreamsCompiledObj * clone(); + double get_multiplier(){ + return (m_mul); + } + private: - void add_compiled_stream(double isg_usec, double pps, uint8_t *pkt, uint16_t pkt_len); + void add_compiled_stream(TrexStream * stream); std::vector m_objs; uint8_t m_port_id; diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index e1664bd9..899e14be 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -22,6 +22,7 @@ limitations under the License. #include #include #include +#include #include @@ -124,33 +125,64 @@ TrexStatelessDpCore::add_duration(double duration){ void -TrexStatelessDpCore::add_cont_stream(uint8_t port_id, - double isg_usec, - double pps, - const uint8_t *pkt, - uint16_t pkt_len) { +TrexStatelessDpCore::add_cont_stream(TrexStream * stream, + TrexStreamsCompiledObj *comp) { CGenNodeStateless *node = m_core->create_node_sl(); /* add periodic */ node->m_type = CGenNode::STATELESS_PKT; - node->m_time = m_core->m_cur_time_sec + usec_to_sec(isg_usec); + node->m_time = m_core->m_cur_time_sec + usec_to_sec(stream->m_isg_usec); - pkt_dir_t dir = m_core->m_node_gen.m_v_if->port_id_to_dir(port_id); + pkt_dir_t dir = m_core->m_node_gen.m_v_if->port_id_to_dir(stream->m_port_id); node->m_flags = 0; /* set socket id */ node->set_socket_id(m_core->m_node_gen.m_socket_id); /* build a mbuf from a packet */ - uint16_t pkt_size = pkt_len; - const uint8_t *stream_pkt = pkt; + + uint16_t pkt_size = stream->m_pkt.len; + const uint8_t *stream_pkt = stream->m_pkt.binary; + + TrexStreamBurst * lpburst; + TrexStreamMultiBurst * lpmulti; + + node->m_stream_type = stream->m_type; + node->m_next_time_offset = 1.0 / (stream->get_pps() * comp->get_multiplier()) ; + /* stateless specific fields */ - node->m_next_time_offset = 1.0 / pps; + switch ( stream->m_type ) { + + case TrexStream::stCONTINUOUS : + break; + + case TrexStream::stSINGLE_BURST : + node->m_stream_type = TrexStream::stMULTI_BURST; + lpburst = (TrexStreamBurst *)stream; + node->m_single_burst = lpburst->m_total_pkts; + node->m_single_burst_refill = lpburst->m_total_pkts; + node->m_multi_bursts = 1; /* single burst in multi burst of 1 */ + node->m_ibg_sec = 0.0; + break; + + case TrexStream::stMULTI_BURST : + lpmulti =(TrexStreamMultiBurst *)stream; + + node->m_single_burst = lpmulti->m_total_pkts; + node->m_single_burst_refill = lpmulti->m_total_pkts ; + node->m_multi_bursts = lpmulti->m_num_bursts; + node->m_ibg_sec = usec_to_sec( lpmulti->m_ibg_usec ); + break; + default: + + assert(0); + }; + node->m_is_stream_active = 1; - node->m_port_id = port_id; + node->m_port_id = stream->m_port_id; /* allocate const mbuf */ rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), pkt_size); @@ -183,15 +215,10 @@ TrexStatelessDpCore::add_cont_stream(uint8_t port_id, void TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj) { for (auto single_stream : obj->get_objects()) { - add_cont_stream(single_stream.m_port_id, - single_stream.m_isg_usec, - single_stream.m_pps, - single_stream.m_pkt, - single_stream.m_pkt_len); + add_cont_stream(single_stream.m_stream,obj); } double duration=obj->get_simulation_duration(); - printf("duration %f \n",duration); if ( duration >0.0){ add_duration( duration ); diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index 51f882b2..1029213d 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -31,6 +31,7 @@ class TrexStatelessDpStart; class CFlowGenListPerThread; class CGenNodeStateless; class TrexStreamsCompiledObj; +class TrexStream; class TrexStatelessDpCore { @@ -134,11 +135,7 @@ private: /* add global exit */ void add_duration(double duration); - void add_cont_stream(uint8_t dir, - double isg, - double pps, - const uint8_t *pkt, - uint16_t pkt_len); + void add_cont_stream(TrexStream * stream,TrexStreamsCompiledObj *comp); uint8_t m_thread_id; state_e m_state; diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index 2ffe04c3..e4cf964d 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -25,6 +25,7 @@ limitations under the License. #include class TrexStatelessDpCore; +#include /* this is a event for stateless */ struct CGenNodeStateless : public CGenNodeBase { @@ -33,28 +34,51 @@ friend class TrexStatelessDpCore; private: void * m_cache_mbuf; - double m_next_time_offset; + double m_next_time_offset; /* in sec */ + double m_ibg_sec; /* inter burst time in sec */ + + uint8_t m_is_stream_active; uint8_t m_port_id; + uint8_t m_stream_type; /* TrexStream::STREAM_TYPE */ + uint8_t m_pad; + + uint32_t m_single_burst; /* the number of bursts in case of burst */ + uint32_t m_single_burst_refill; + + uint32_t m_multi_bursts; /* in case of multi_burst how many bursts */ + + /* pad to match the size of CGenNode */ - uint8_t m_pad_end[87]; + uint8_t m_pad_end[65]; public: + inline uint8_t get_stream_type(){ + return (m_stream_type); + } + + inline uint32_t get_single_burst_cnt(){ + return (m_single_burst); + } + + inline double get_multi_ibg_sec(){ + return (m_ibg_sec); + } + + inline uint32_t get_multi_burst_cnt(){ + return (m_multi_bursts); + } + inline bool is_active() { return m_is_stream_active; } - - /** - * main function to handle an event of a packet tx - * - */ - inline void handle(CFlowGenListPerThread *thread) { + inline void handle_continues(CFlowGenListPerThread *thread) { thread->m_node_gen.m_v_if->send_node( (CGenNode *)this); /* in case of continues */ @@ -64,6 +88,51 @@ public: thread->m_node_gen.m_p_queue.push( (CGenNode *)this); } + inline void handle_multi_burst(CFlowGenListPerThread *thread) { + thread->m_node_gen.m_v_if->send_node( (CGenNode *)this); + + m_single_burst--; + if (m_single_burst > 0 ) { + /* in case of continues */ + m_time += m_next_time_offset; + + thread->m_node_gen.m_p_queue.push( (CGenNode *)this); + }else{ + m_multi_bursts--; + if ( m_multi_bursts == 0 ) { + /* stop */ + m_is_stream_active =0; + }else{ + m_time += m_ibg_sec; + m_single_burst = m_single_burst_refill; + + } + thread->m_node_gen.m_p_queue.push( (CGenNode *)this); + } + } + + + /** + * main function to handle an event of a packet tx + * + * + * + */ + + inline void handle(CFlowGenListPerThread *thread) { + + if (m_stream_type == TrexStream::stCONTINUOUS ) { + handle_continues(thread) ; + }else{ + if (m_stream_type == TrexStream::stMULTI_BURST) { + handle_multi_burst(thread); + }else{ + assert(0); + } + } + + } + void set_socket_id(socket_id_t socket){ m_socket_id=socket; } @@ -106,6 +175,9 @@ public: } __rte_cache_aligned; -static_assert(sizeof(CGenNodeStateless) == sizeof(CGenNode), "sizeof(CGenNodeStateless) != sizeof(CGenNode)"); +static_assert(sizeof(CGenNodeStateless) == sizeof(CGenNode), "sizeof(CGenNodeStateless) != sizeof(CGenNode)" ); + + + #endif /* __TREX_STREAM_NODE_H__ */ -- cgit 1.2.3-korg From 45b71cff9d0465b77f82e4cd40b64a9f3183c1c7 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Thu, 12 Nov 2015 15:33:30 +0200 Subject: refactor stream object --- .../trex_control_plane/client/trex_async_client.py | 3 +- .../trex_control_plane/console/trex_console.py | 8 +- src/gtest/trex_stateless_gtest.cpp | 34 ++++-- src/platform_cfg.cpp | 2 + src/platform_cfg.h | 2 +- src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 14 ++- src/stateless/cp/trex_stream.cpp | 9 +- src/stateless/cp/trex_stream.h | 132 ++++++++++++--------- src/stateless/cp/trex_streams_compiler.cpp | 7 +- src/stateless/dp/trex_stateless_dp_core.cpp | 18 +-- 10 files changed, 138 insertions(+), 91 deletions(-) (limited to 'src/gtest') diff --git a/scripts/automation/trex_control_plane/client/trex_async_client.py b/scripts/automation/trex_control_plane/client/trex_async_client.py index 72cce5aa..d13513bf 100644 --- a/scripts/automation/trex_control_plane/client/trex_async_client.py +++ b/scripts/automation/trex_control_plane/client/trex_async_client.py @@ -181,7 +181,8 @@ class CTRexAsyncClient(): self.socket.setsockopt(zmq.SUBSCRIBE, '') while self.active: - msg = json.loads(self.socket.recv_string()) + line = self.socket.recv_string(); + msg = json.loads(line) key = msg['name'] self.raw_snapshot[key] = msg['data'] diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 06ae762a..5470e694 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -371,12 +371,12 @@ def setParserOptions(): default = "localhost", type = str) - parser.add_argument("-p", "--port", help = "TRex Server Port [default is 5505]\n", - default = 5505, + parser.add_argument("-p", "--port", help = "TRex Server Port [default is 4501]\n", + default = 4501, type = int) - parser.add_argument("--async_port", help = "TRex ASync Publisher Port [default is 4505]\n", - default = 4505, + parser.add_argument("--async_port", help = "TRex ASync Publisher Port [default is 4500]\n", + default = 4500, dest='pub', type = int) diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 1ea0373c..8b96ef88 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -237,7 +237,9 @@ TEST_F(basic_stl, single_pkt_burst1) { std::vector streams; - TrexStream * stream1 = new TrexStreamBurst(0,0,5, 1.0); + TrexStream * stream1 = new TrexStream(TrexStream::stSINGLE_BURST, 0,0); + stream1->set_pps(1.0); + stream1->set_signle_burtst(5); stream1->m_enabled = true; stream1->m_self_start = true; @@ -281,7 +283,10 @@ TEST_F(basic_stl, single_pkt) { std::vector streams; - TrexStream * stream1 = new TrexStreamContinuous(0,0,1.0); + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream1->set_pps(1.0); + + stream1->m_enabled = true; stream1->m_self_start = true; @@ -327,7 +332,10 @@ TEST_F(basic_stl, multi_pkt1) { std::vector streams; - TrexStream * stream1 = new TrexStreamContinuous(0,0,1.0); + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream1->set_pps(1.0); + + stream1->m_enabled = true; stream1->m_self_start = true; @@ -338,8 +346,9 @@ TEST_F(basic_stl, multi_pkt1) { streams.push_back(stream1); + TrexStream * stream2 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream2->set_pps(2.0); - TrexStream * stream2 = new TrexStreamContinuous(0,1,2.0); stream2->m_enabled = true; stream2->m_self_start = true; stream2->m_isg_usec = 1000.0; /* 1 msec */ @@ -385,7 +394,11 @@ TEST_F(basic_stl, multi_pkt2) { std::vector streams; - TrexStream * stream1 = new TrexStreamContinuous(0,0,1.0); + + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream1->set_pps(1.0); + + stream1->m_enabled = true; stream1->m_self_start = true; @@ -397,7 +410,9 @@ TEST_F(basic_stl, multi_pkt2) { streams.push_back(stream1); - TrexStream * stream2 = new TrexStreamContinuous(0,1,2.0); + TrexStream * stream2 = new TrexStream(TrexStream::stCONTINUOUS,0,1); + stream2->set_pps(2.0); + stream2->m_enabled = false; stream2->m_self_start = false; stream2->m_isg_usec = 1000.0; /* 1 msec */ @@ -439,9 +454,12 @@ TEST_F(basic_stl, multi_burst1) { std::vector streams; + TrexStream * stream1 = new TrexStream(TrexStream::stMULTI_BURST,0,0); + stream1->set_pps(1.0); + stream1->set_multi_burst(5, + 3, + 2000000.0); - - TrexStream * stream1 = new TrexStreamMultiBurst(0,0,5, 1.0,3,2000000.0); stream1->m_enabled = true; stream1->m_self_start = true; diff --git a/src/platform_cfg.cpp b/src/platform_cfg.cpp index df04cd89..547cc3ad 100755 --- a/src/platform_cfg.cpp +++ b/src/platform_cfg.cpp @@ -414,7 +414,9 @@ void CPlatformYamlInfo::Dump(FILE *fd){ } if ( m_telnet_exist ){ fprintf(fd," telnet_port : %d \n",m_telnet_port); + } + fprintf(fd," m_zmq_rpc_port : %d \n",m_zmq_rpc_port); if ( m_mac_info_exist ){ int i; diff --git a/src/platform_cfg.h b/src/platform_cfg.h index b4b03b10..4fc3c3dd 100755 --- a/src/platform_cfg.h +++ b/src/platform_cfg.h @@ -180,11 +180,11 @@ public: m_enable_zmq_pub_exist=false; m_enable_zmq_pub=true; m_zmq_pub_port=4500; + m_zmq_rpc_port = 4501; m_telnet_exist=false; m_telnet_port=4502 ; - m_zmq_rpc_port = 5050; m_mac_info_exist=false; m_port_bandwidth_gb = 10; diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index fffc800a..e32073b0 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -140,14 +140,18 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, uint8_t por if (type == "continuous") { double pps = parse_double(mode, "pps", result); - stream = new TrexStreamContinuous(port_id, stream_id, pps); + stream = new TrexStream( TrexStream::stCONTINUOUS, port_id, stream_id); + stream->set_pps(pps); } else if (type == "single_burst") { uint32_t total_pkts = parse_int(mode, "total_pkts", result); double pps = parse_double(mode, "pps", result); - stream = new TrexStreamBurst(port_id, stream_id, total_pkts, pps); + stream = new TrexStream(TrexStream::stSINGLE_BURST,port_id, stream_id); + stream->set_pps(pps); + stream->set_signle_burtst(total_pkts); + } else if (type == "multi_burst") { @@ -156,8 +160,10 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, uint8_t por uint32_t num_bursts = parse_int(mode, "number_of_bursts", result); uint32_t pkts_per_burst = parse_int(mode, "pkts_per_burst", result); - stream = new TrexStreamMultiBurst(port_id, stream_id, pkts_per_burst, pps, num_bursts, ibg_usec); - + stream = new TrexStream(TrexStream::stMULTI_BURST,port_id, stream_id ); + stream->set_pps(pps); + stream->set_multi_burst(pkts_per_burst,num_bursts,ibg_usec); + } else { generate_parse_err(result, "bad stream type provided: '" + type + "'"); diff --git a/src/stateless/cp/trex_stream.cpp b/src/stateless/cp/trex_stream.cpp index ba306137..1a05257c 100644 --- a/src/stateless/cp/trex_stream.cpp +++ b/src/stateless/cp/trex_stream.cpp @@ -25,9 +25,11 @@ limitations under the License. /************************************** * stream *************************************/ -TrexStream::TrexStream(uint8_t port_id, uint32_t stream_id) : m_port_id(port_id), m_stream_id(stream_id) { +TrexStream::TrexStream(uint8_t type, + uint8_t port_id, uint32_t stream_id) : m_port_id(port_id), m_stream_id(stream_id) { /* default values */ + m_type = type; m_isg_usec = 0; m_next_stream_id = -1; m_enabled = false; @@ -38,6 +40,11 @@ TrexStream::TrexStream(uint8_t port_id, uint32_t stream_id) : m_port_id(port_id) m_rx_check.m_enable = false; + + m_pps=-1.0; + m_burst_total_pkts=0; + m_num_bursts=1; + m_ibg_usec=0.0; } TrexStream::~TrexStream() { diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index 5e6ac19a..151723ad 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -29,9 +29,28 @@ limitations under the License. #include #include +#include +#include class TrexRpcCmdAddStream; + +struct CStreamPktData { + uint8_t *binary; + uint16_t len; + + std::string meta; + +public: + inline void clone(uint8_t * in_binary, + uint32_t in_pkt_size){ + binary = new uint8_t[in_pkt_size]; + len = in_pkt_size; + memcpy(binary,in_binary,in_pkt_size); + } +}; + + /** * Stateless Stream * @@ -48,7 +67,7 @@ public: public: - TrexStream(uint8_t port_id, uint32_t stream_id); + TrexStream(uint8_t type,uint8_t port_id, uint32_t stream_id); virtual ~TrexStream(); /* defines the min max per packet supported */ @@ -65,6 +84,53 @@ public: return m_pps; } + void set_pps(double pps){ + m_pps = pps; + } + + void set_type(uint8_t type){ + m_type = type; + } + + uint8_t get_type(void){ + return ( m_type ); + } + + + + void set_multi_burst(uint32_t burst_total_pkts, + uint32_t num_bursts, + double ibg_usec){ + m_burst_total_pkts = burst_total_pkts; + m_num_bursts = num_bursts; + m_ibg_usec = ibg_usec; + } + + void set_signle_burtst(uint32_t burst_total_pkts){ + set_multi_burst(burst_total_pkts,1,0.0); + } + + /* create new stream */ + TrexStream * clone_as_dp(){ + TrexStream * dp=new TrexStream(m_type,m_port_id,m_stream_id); + + + dp->m_isg_usec = m_isg_usec; + dp->m_next_stream_id = m_next_stream_id; + + dp->m_enabled = m_enabled; + dp->m_self_start = m_self_start; + + /* deep copy */ + dp->m_pkt.clone(m_pkt.binary,m_pkt.len); + + dp->m_rx_check = m_rx_check; + dp->m_pps = m_pps; + dp->m_burst_total_pkts = m_burst_total_pkts; + dp->m_num_bursts = m_num_bursts; + dp->m_ibg_usec = m_ibg_usec ; + return (dp); + } public: /* basic */ @@ -80,13 +146,9 @@ public: /* indicators */ bool m_enabled; bool m_self_start; - + + CStreamPktData m_pkt; /* pkt */ - struct { - uint8_t *binary; - uint16_t len; - std::string meta; - } m_pkt; /* VM */ StreamVm m_vm; @@ -102,63 +164,17 @@ public: double m_pps; + uint32_t m_burst_total_pkts; /* valid in case of burst stSINGLE_BURST,stMULTI_BURST*/ - /* original template provided by requester */ - Json::Value m_stream_json; - - -}; + uint32_t m_num_bursts; /* valid in case of stMULTI_BURST */ -/** - * continuous stream - * - */ -class TrexStreamContinuous : public TrexStream { -public: - TrexStreamContinuous(uint8_t port_id, uint32_t stream_id, double pps) : TrexStream(port_id, stream_id) { - m_type= TrexStream::stCONTINUOUS; - m_pps=pps; - } -}; - -/** - * single burst - * - */ -class TrexStreamBurst : public TrexStream { -public: - TrexStreamBurst(uint8_t port_id, uint32_t stream_id, uint32_t total_pkts, double pps) : - TrexStream(port_id, stream_id), - m_total_pkts(total_pkts){ - m_type= TrexStream::stSINGLE_BURST; - m_pps=pps; + double m_ibg_usec; /* valid in case of stMULTI_BURST */ - } + /* original template provided by requester */ + Json::Value m_stream_json; -public: - uint32_t m_total_pkts; }; -/** - * multi burst - * - */ -class TrexStreamMultiBurst : public TrexStreamBurst { -public: - TrexStreamMultiBurst(uint8_t port_id, - uint32_t stream_id, - uint32_t pkts_per_burst, - double pps, - uint32_t num_bursts, - double ibg_usec) : TrexStreamBurst(port_id, stream_id, pkts_per_burst, pps), m_num_bursts(num_bursts), m_ibg_usec(ibg_usec) { - m_type= TrexStream::stMULTI_BURST; - } - -public: - uint32_t m_num_bursts; - double m_ibg_usec; - -}; /** * holds all the streams diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index c7b881c5..80cdb31c 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -27,18 +27,21 @@ limitations under the License. * stream compiled object *************************************/ TrexStreamsCompiledObj::TrexStreamsCompiledObj(uint8_t port_id, double mul) : m_port_id(port_id), m_mul(mul) { + m_duration_sim=-1.0; } TrexStreamsCompiledObj::~TrexStreamsCompiledObj() { + for (auto obj : m_objs) { + delete obj.m_stream; + } m_objs.clear(); - m_duration_sim=-1.0; } void TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream) { obj_st obj; - obj.m_stream = stream; + obj.m_stream = stream->clone_as_dp(); m_objs.push_back(obj); } diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 899e14be..96c18dbd 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -146,9 +146,6 @@ TrexStatelessDpCore::add_cont_stream(TrexStream * stream, uint16_t pkt_size = stream->m_pkt.len; const uint8_t *stream_pkt = stream->m_pkt.binary; - TrexStreamBurst * lpburst; - TrexStreamMultiBurst * lpmulti; - node->m_stream_type = stream->m_type; node->m_next_time_offset = 1.0 / (stream->get_pps() * comp->get_multiplier()) ; @@ -161,20 +158,17 @@ TrexStatelessDpCore::add_cont_stream(TrexStream * stream, case TrexStream::stSINGLE_BURST : node->m_stream_type = TrexStream::stMULTI_BURST; - lpburst = (TrexStreamBurst *)stream; - node->m_single_burst = lpburst->m_total_pkts; - node->m_single_burst_refill = lpburst->m_total_pkts; + node->m_single_burst = stream->m_burst_total_pkts; + node->m_single_burst_refill = stream->m_burst_total_pkts; node->m_multi_bursts = 1; /* single burst in multi burst of 1 */ node->m_ibg_sec = 0.0; break; case TrexStream::stMULTI_BURST : - lpmulti =(TrexStreamMultiBurst *)stream; - - node->m_single_burst = lpmulti->m_total_pkts; - node->m_single_burst_refill = lpmulti->m_total_pkts ; - node->m_multi_bursts = lpmulti->m_num_bursts; - node->m_ibg_sec = usec_to_sec( lpmulti->m_ibg_usec ); + node->m_single_burst = stream->m_burst_total_pkts; + node->m_single_burst_refill = stream->m_burst_total_pkts; + node->m_multi_bursts = stream->m_num_bursts; + node->m_ibg_sec = usec_to_sec( stream->m_ibg_usec ); break; default: -- cgit 1.2.3-korg From 94b1238942da24e47fb3e689bf695e815a604eb0 Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 15 Nov 2015 18:15:14 +0200 Subject: added duration to the RPC server (and all the way to the DP) *STILL NEEDS FIXING THE DP STOP SCHED MESSAGE" --- .../trex_control_plane/client/trex_stateless_client.py | 15 ++++++++------- .../automation/trex_control_plane/console/parsing_opts.py | 7 +++++-- src/gtest/trex_stateless_gtest.cpp | 15 +++++---------- src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 7 ++++--- src/rpc-server/commands/trex_rpc_cmds.h | 2 +- src/stateless/cp/trex_stateless_port.cpp | 4 ++-- src/stateless/cp/trex_stateless_port.h | 2 +- src/stateless/cp/trex_streams_compiler.cpp | 3 --- src/stateless/cp/trex_streams_compiler.h | 8 -------- src/stateless/dp/trex_stateless_dp_core.cpp | 6 ++---- src/stateless/dp/trex_stateless_dp_core.h | 2 +- src/stateless/messaging/trex_stateless_messaging.cpp | 6 +++--- src/stateless/messaging/trex_stateless_messaging.h | 3 ++- 13 files changed, 34 insertions(+), 46 deletions(-) (limited to 'src/gtest') diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py index 443466b2..4478ed3f 100755 --- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py @@ -280,7 +280,7 @@ class Port: return self.ok() # start traffic - def start (self, mul): + def start (self, mul, duration): if self.state == self.STATE_DOWN: return self.err("Unable to start traffic - port is down") @@ -292,7 +292,8 @@ class Port: params = {"handler": self.handler, "port_id": self.port_id, - "mul": mul} + "mul": mul, + "duration": duration} rc, data = self.transmit("start_traffic", params) if not rc: @@ -580,14 +581,14 @@ class CTRexStatelessClient(object): return self.ports[port_id].get_stream_id_list() - def start_traffic (self, multiplier, port_id_list = None): + def start_traffic (self, multiplier, duration, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: - rc.add(self.ports[port_id].start(multiplier)) + rc.add(self.ports[port_id].start(multiplier, duration)) return rc @@ -685,7 +686,7 @@ class CTRexStatelessClient(object): return RC_OK() # start cmd - def cmd_start (self, port_id_list, stream_list, mult, force): + def cmd_start (self, port_id_list, stream_list, mult, force, duration): active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) @@ -713,7 +714,7 @@ class CTRexStatelessClient(object): # finally, start the traffic - rc = self.start_traffic(mult, port_id_list) + rc = self.start_traffic(mult, duration, port_id_list) rc.annotate("Starting traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc @@ -754,7 +755,7 @@ class CTRexStatelessClient(object): return RC_ERR("Failed to load stream pack") - return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force) + return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force, opts.duration) def cmd_stop_line (self, line): '''Stop active traffic in specified ports on TRex\n''' diff --git a/scripts/automation/trex_control_plane/console/parsing_opts.py b/scripts/automation/trex_control_plane/console/parsing_opts.py index c154ce24..d5c21af0 100755 --- a/scripts/automation/trex_control_plane/console/parsing_opts.py +++ b/scripts/automation/trex_control_plane/console/parsing_opts.py @@ -89,10 +89,13 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], "dest": "all_ports", 'help': "Set this flag to apply the command on all available ports"}), DURATION: ArgumentPack(['-d'], - {"action": "store", + {'action': "store", 'metavar': 'TIME', - "type": match_time_unit, + 'dest': 'duration', + 'type': match_time_unit, + 'default': -1.0, 'help': "Set duration time for TRex."}), + FORCE: ArgumentPack(['--force'], {"action": "store_true", 'default': False, diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 8b96ef88..c845c32e 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -252,10 +252,9 @@ TEST_F(basic_stl, single_pkt_burst1) { TrexStreamsCompiledObj comp_obj(0,1.0); - comp_obj.set_simulation_duration( 10.0); assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 10.0 ); t1.m_msg = lpstart; @@ -303,10 +302,9 @@ TEST_F(basic_stl, single_pkt) { TrexStreamsCompiledObj comp_obj(0,1.0); - comp_obj.set_simulation_duration( 10.0); assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 10 ); t1.m_msg = lpstart; @@ -361,10 +359,9 @@ TEST_F(basic_stl, multi_pkt1) { // stream - clean TrexStreamsCompiledObj comp_obj(0,1.0); - comp_obj.set_simulation_duration( 10.0); assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 10 ); t1.m_msg = lpstart; @@ -425,10 +422,9 @@ TEST_F(basic_stl, multi_pkt2) { // stream - clean TrexStreamsCompiledObj comp_obj(0,5.0); - comp_obj.set_simulation_duration( 10.0); assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 10 ); t1.m_msg = lpstart; @@ -472,10 +468,9 @@ TEST_F(basic_stl, multi_burst1) { TrexStreamsCompiledObj comp_obj(0,1.0); - comp_obj.set_simulation_duration( 40.0); assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone() ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 40 ); t1.m_msg = lpstart; diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index e32073b0..5ec92afc 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -458,8 +458,9 @@ TrexRpcCmdGetStream::_run(const Json::Value ¶ms, Json::Value &result) { trex_rpc_cmd_rc_e TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { - uint8_t port_id = parse_byte(params, "port_id", result); - double mul = parse_double(params, "mul", result); + uint8_t port_id = parse_byte(params, "port_id", result); + double mul = parse_double(params, "mul", result); + double duration = parse_double(params, "duration", result); if (port_id >= get_stateless_obj()->get_port_count()) { std::stringstream ss; @@ -470,7 +471,7 @@ TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); try { - port->start_traffic(mul); + port->start_traffic(mul, duration); } catch (const TrexRpcException &ex) { generate_execute_err(result, ex.what()); } diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h index d7265ff2..b4f37e3b 100644 --- a/src/rpc-server/commands/trex_rpc_cmds.h +++ b/src/rpc-server/commands/trex_rpc_cmds.h @@ -105,7 +105,7 @@ TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStream, "get_stream", 3, true); -TREX_RPC_CMD_DEFINE(TrexRpcCmdStartTraffic, "start_traffic", 2, true); +TREX_RPC_CMD_DEFINE(TrexRpcCmdStartTraffic, "start_traffic", 3, true); TREX_RPC_CMD_DEFINE(TrexRpcCmdStopTraffic, "stop_traffic", 1, true); TREX_RPC_CMD_DEFINE(TrexRpcCmdPauseTraffic, "pause_traffic", 1, true); TREX_RPC_CMD_DEFINE(TrexRpcCmdResumeTraffic, "resume_traffic", 1, true); diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 7f2382d3..cbc5a328 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -86,7 +86,7 @@ TrexStatelessPort::release(void) { * */ void -TrexStatelessPort::start_traffic(double mul) { +TrexStatelessPort::start_traffic(double mul, double duration) { /* command allowed only on state stream */ verify_state(PORT_STATE_STREAMS); @@ -105,7 +105,7 @@ TrexStatelessPort::start_traffic(double mul) { } /* generate a message to all the relevant DP cores to start transmitting */ - TrexStatelessCpToDpMsgBase *start_msg = new TrexStatelessDpStart(compiled_obj); + TrexStatelessCpToDpMsgBase *start_msg = new TrexStatelessDpStart(compiled_obj, duration); send_message_to_dp(start_msg); diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 90bf936e..b533f793 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -72,7 +72,7 @@ public: * start traffic * throws TrexException in case of an error */ - void start_traffic(double mul); + void start_traffic(double mul, double duration = -1); /** * stop traffic diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index 80cdb31c..580db51c 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -27,7 +27,6 @@ limitations under the License. * stream compiled object *************************************/ TrexStreamsCompiledObj::TrexStreamsCompiledObj(uint8_t port_id, double mul) : m_port_id(port_id), m_mul(mul) { - m_duration_sim=-1.0; } TrexStreamsCompiledObj::~TrexStreamsCompiledObj() { @@ -61,8 +60,6 @@ TrexStreamsCompiledObj::clone() { new_compiled_obj->m_mul = m_mul; - new_compiled_obj->m_duration_sim = m_duration_sim; - return new_compiled_obj; } diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 78ac1ac7..44c8a0fc 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -48,13 +48,6 @@ public: return m_objs; } - void set_simulation_duration(double duration){ - m_duration_sim=duration; - } - - double get_simulation_duration(){ - return (m_duration_sim); - } /** * clone the compiled object * @@ -71,7 +64,6 @@ private: uint8_t m_port_id; double m_mul; - double m_duration_sim; /* duration for all simulation */ }; class TrexStreamsCompiler { diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 96c18dbd..eabd6fdb 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -207,14 +207,12 @@ TrexStatelessDpCore::add_cont_stream(TrexStream * stream, } void -TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj) { +TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj, double duration) { for (auto single_stream : obj->get_objects()) { add_cont_stream(single_stream.m_stream,obj); } - double duration=obj->get_simulation_duration(); - - if ( duration >0.0){ + if ( duration > 0.0 ){ add_duration( duration ); } } diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index 1029213d..7448d215 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -75,7 +75,7 @@ public: * @param pkt * @param pkt_len */ - void start_traffic(TrexStreamsCompiledObj *obj); + void start_traffic(TrexStreamsCompiledObj *obj, double duration = -1); /** * stop all traffic for this core diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp index 032559bc..d8ebc52c 100644 --- a/src/stateless/messaging/trex_stateless_messaging.cpp +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -26,7 +26,7 @@ limitations under the License. /************************* start traffic message ************************/ -TrexStatelessDpStart::TrexStatelessDpStart(TrexStreamsCompiledObj *obj) : m_obj(obj) { +TrexStatelessDpStart::TrexStatelessDpStart(TrexStreamsCompiledObj *obj, double duration) : m_obj(obj), m_duration(duration) { } @@ -39,7 +39,7 @@ TrexStatelessDpStart::clone() { TrexStreamsCompiledObj *new_obj = m_obj->clone(); - TrexStatelessCpToDpMsgBase *new_msg = new TrexStatelessDpStart(new_obj); + TrexStatelessCpToDpMsgBase *new_msg = new TrexStatelessDpStart(new_obj, m_duration); return new_msg; } @@ -53,7 +53,7 @@ TrexStatelessDpStart::~TrexStatelessDpStart() { bool TrexStatelessDpStart::handle(TrexStatelessDpCore *dp_core) { - dp_core->start_traffic(m_obj); + dp_core->start_traffic(m_obj, m_duration); return true; } diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index d288fc83..90897665 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -66,7 +66,7 @@ public: class TrexStatelessDpStart : public TrexStatelessCpToDpMsgBase { public: - TrexStatelessDpStart(TrexStreamsCompiledObj *obj); + TrexStatelessDpStart(TrexStreamsCompiledObj *obj, double duration); ~TrexStatelessDpStart(); @@ -77,6 +77,7 @@ public: private: TrexStreamsCompiledObj *m_obj; + double m_duration; }; /** -- cgit 1.2.3-korg From d16ebf0b67ae8e339fd9367c313a786a8172b1b0 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 16 Nov 2015 18:28:01 +0200 Subject: basic compiler checks added checks against: 1. duplicate stream IDs 2. pointing to non existent streams 3. 'dead streams' - unreachable by any other stream --- src/gtest/trex_stateless_gtest.cpp | 200 +++++++++++++++- src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 6 +- src/stateless/cp/trex_stream.h | 8 +- src/stateless/cp/trex_streams_compiler.cpp | 301 +++++++++++++++++++++++- src/stateless/cp/trex_streams_compiler.h | 26 +- 5 files changed, 525 insertions(+), 16 deletions(-) (limited to 'src/gtest') diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index c845c32e..9148d5ae 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -29,7 +29,7 @@ limitations under the License. #include #include #include - +#include #define EXPECT_EQ_UINT32(a,b) EXPECT_EQ((uint32_t)(a),(uint32_t)(b)) @@ -239,7 +239,7 @@ TEST_F(basic_stl, single_pkt_burst1) { TrexStream * stream1 = new TrexStream(TrexStream::stSINGLE_BURST, 0,0); stream1->set_pps(1.0); - stream1->set_signle_burtst(5); + stream1->set_single_burst(5); stream1->m_enabled = true; stream1->m_self_start = true; @@ -344,7 +344,7 @@ TEST_F(basic_stl, multi_pkt1) { streams.push_back(stream1); - TrexStream * stream2 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + TrexStream * stream2 = new TrexStream(TrexStream::stCONTINUOUS,0,1); stream2->set_pps(2.0); stream2->m_enabled = true; @@ -482,6 +482,200 @@ TEST_F(basic_stl, multi_burst1) { EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; } +/********************************************* Itay Tests Start *************************************/ + +/** + * check that continous stream does not point to another stream + * (makes no sense) + */ +TEST_F(basic_stl, compile_bad_1) { + + TrexStreamsCompiler compile; + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,2); + stream1->m_enabled = true; + stream1->set_pps(52.0); + stream1->m_next_stream_id = 3; + + streams.push_back(stream1); + + TrexStreamsCompiledObj comp_obj(0,1.0); + + std::string err_msg; + EXPECT_FALSE(compile.compile(streams, comp_obj, &err_msg)); + + delete stream1; + +} + +/** + * check for streams pointing to non exsistant streams + * + * @author imarom (16-Nov-15) + */ +TEST_F(basic_stl, compile_bad_2) { + + TrexStreamsCompiler compile; + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stSINGLE_BURST,0,1); + stream1->m_enabled = true; + stream1->set_pps(1.0); + stream1->set_single_burst(200); + + /* non existant next stream */ + stream1->m_next_stream_id = 5; + + TrexStream * stream2 = new TrexStream(TrexStream::stCONTINUOUS,0,2); + stream1->set_pps(52.0); + + streams.push_back(stream1); + streams.push_back(stream2); + + TrexStreamsCompiledObj comp_obj(0,1.0); + + std::string err_msg; + EXPECT_FALSE(compile.compile(streams, comp_obj, &err_msg)); + + delete stream1; + delete stream2; + +} + +/** + * check for "dead streams" in the mesh + * a streams that cannot be reached + * + * @author imarom (16-Nov-15) + */ +TEST_F(basic_stl, compile_bad_3) { + + TrexStreamsCompiler compile; + std::vector streams; + TrexStream *stream; + + /* stream 1 */ + stream = new TrexStream(TrexStream::stSINGLE_BURST, 0, 231); + stream->m_enabled = true; + stream->set_pps(1.0); + stream->set_single_burst(200); + + stream->m_next_stream_id = 5481; + stream->m_self_start = true; + + streams.push_back(stream); + /* stream 2 */ + stream = new TrexStream(TrexStream::stCONTINUOUS, 0, 5481); + stream->m_enabled = true; + stream->m_next_stream_id = -1; + stream->m_self_start = false; + stream->set_pps(52.0); + + streams.push_back(stream); + + /* stream 3 */ + + stream = new TrexStream(TrexStream::stSINGLE_BURST, 0, 1928); + stream->m_enabled = true; + stream->set_pps(1.0); + stream->set_single_burst(200); + + stream->m_next_stream_id = -1; + stream->m_self_start = true; + + streams.push_back(stream); + + /* stream 4 */ + + stream = new TrexStream(TrexStream::stSINGLE_BURST, 0, 41231); + stream->m_enabled = true; + stream->set_pps(1.0); + stream->set_single_burst(200); + + stream->m_next_stream_id = 3928; + stream->m_self_start = false; + + streams.push_back(stream); + + /* stream 5 */ + + stream = new TrexStream(TrexStream::stSINGLE_BURST, 0, 3928); + stream->m_enabled = true; + stream->set_pps(1.0); + stream->set_single_burst(200); + + stream->m_next_stream_id = 41231; + stream->m_self_start = false; + + streams.push_back(stream); + + /* compile */ + TrexStreamsCompiledObj comp_obj(0,1.0); + + std::string err_msg; + EXPECT_FALSE(compile.compile(streams, comp_obj, &err_msg)); + + for (auto stream : streams) { + delete stream; + } + +} + +TEST_F(basic_stl, compile_with_warnings) { + + TrexStreamsCompiler compile; + std::vector streams; + TrexStream *stream; + + /* stream 1 */ + stream = new TrexStream(TrexStream::stSINGLE_BURST, 0, 231); + stream->m_enabled = true; + stream->set_pps(1.0); + stream->set_single_burst(200); + + stream->m_next_stream_id = 1928; + stream->m_self_start = true; + + streams.push_back(stream); + + /* stream 2 */ + stream = new TrexStream(TrexStream::stSINGLE_BURST, 0, 5481); + stream->m_enabled = true; + stream->m_next_stream_id = 1928; + stream->m_self_start = true; + stream->set_pps(52.0); + + streams.push_back(stream); + + /* stream 3 */ + + stream = new TrexStream(TrexStream::stSINGLE_BURST, 0, 1928); + stream->m_enabled = true; + stream->set_pps(1.0); + stream->set_single_burst(200); + + stream->m_next_stream_id = -1; + stream->m_self_start = true; + + streams.push_back(stream); + + + + /* compile */ + TrexStreamsCompiledObj comp_obj(0,1.0); + + std::string err_msg; + EXPECT_TRUE(compile.compile(streams, comp_obj, &err_msg)); + + EXPECT_TRUE(compile.get_last_compile_warnings().size() == 1); + + for (auto stream : streams) { + delete stream; + } + +} +/********************************************* Itay Tests End *************************************/ diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index 5ec92afc..cdd13ed6 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -143,6 +143,10 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, uint8_t por stream = new TrexStream( TrexStream::stCONTINUOUS, port_id, stream_id); stream->set_pps(pps); + if (stream->m_next_stream_id != -1) { + generate_parse_err(result, "continious stream cannot provide next stream id - only -1 is valid"); + } + } else if (type == "single_burst") { uint32_t total_pkts = parse_int(mode, "total_pkts", result); @@ -150,7 +154,7 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, uint8_t por stream = new TrexStream(TrexStream::stSINGLE_BURST,port_id, stream_id); stream->set_pps(pps); - stream->set_signle_burtst(total_pkts); + stream->set_single_burst(total_pkts); } else if (type == "multi_burst") { diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index 151723ad..c2628cc3 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -92,21 +92,21 @@ public: m_type = type; } - uint8_t get_type(void){ + uint8_t get_type(void) const { return ( m_type ); } void set_multi_burst(uint32_t burst_total_pkts, - uint32_t num_bursts, - double ibg_usec){ + uint32_t num_bursts, + double ibg_usec) { m_burst_total_pkts = burst_total_pkts; m_num_bursts = num_bursts; m_ibg_usec = ibg_usec; } - void set_signle_burtst(uint32_t burst_total_pkts){ + void set_single_burst(uint32_t burst_total_pkts){ set_multi_burst(burst_total_pkts,1,0.0); } diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index 580db51c..0c3b4ef0 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -19,9 +19,116 @@ See the License for the specific language governing permissions and limitations under the License. */ -#include +#include +#include #include #include +#include +#include +#include + +/** + * describes a graph node in the pre compile check + * + * @author imarom (16-Nov-15) + */ +class GraphNode { +public: + GraphNode(TrexStream *stream, GraphNode *next) : m_stream(stream), m_next(next) { + marked = false; + } + + uint32_t get_stream_id() const { + return m_stream->m_stream_id; + } + + const TrexStream *m_stream; + GraphNode *m_next; + std::vector m_parents; + bool marked; +}; + +/** + * node map + * + */ +class GraphNodeMap { +public: + + GraphNodeMap() : m_dead_end(NULL, NULL) { + + } + + bool add(GraphNode *node) { + if (has(node->get_stream_id())) { + return false; + } + + m_nodes[node->get_stream_id()] = node; + + if (node->m_stream->m_self_start) { + m_roots.push_back(node); + } + + return true; + } + + bool has(uint32_t stream_id) { + + return (get(stream_id) != NULL); + } + + GraphNode * get(uint32_t stream_id) { + + if (stream_id == -1) { + return &m_dead_end; + } + + auto search = m_nodes.find(stream_id); + + if (search != m_nodes.end()) { + return search->second; + } else { + return NULL; + } + } + + void clear_marks() { + for (auto node : m_nodes) { + node.second->marked = false; + } + } + + void get_unmarked(std::vector &unmarked) { + for (auto node : m_nodes) { + if (!node.second->marked) { + unmarked.push_back(node.second); + } + } + } + + + ~GraphNodeMap() { + for (auto node : m_nodes) { + delete node.second; + } + m_nodes.clear(); + } + + std::vector & get_roots() { + return m_roots; + } + + + std::unordered_map get_nodes() { + return m_nodes; + } + +private: + std::unordered_map m_nodes; + std::vector m_roots; + GraphNode m_dead_end; +}; /************************************** * stream compiled object @@ -63,11 +170,196 @@ TrexStreamsCompiledObj::clone() { return new_compiled_obj; } +void +TrexStreamsCompiler::add_warning(const std::string &warning) { + m_warnings.push_back("*** warning: " + warning); +} + +void +TrexStreamsCompiler::err(const std::string &err) { + throw TrexException("*** error: " + err); +} + +void +TrexStreamsCompiler::check_stream(const TrexStream *stream) { + std::stringstream ss; + + /* cont. stream can point only on itself */ + if (stream->get_type() == TrexStream::stCONTINUOUS) { + if (stream->m_next_stream_id != -1) { + ss << "continous stream '" << stream->m_stream_id << "' cannot point on another stream"; + err(ss.str()); + } + } +} + +void +TrexStreamsCompiler::allocate_pass(const std::vector &streams, + GraphNodeMap *nodes) { + std::stringstream ss; + + /* first pass - allocate all nodes and check for duplicates */ + for (auto stream : streams) { + + /* skip non enabled streams */ + if (!stream->m_enabled) { + continue; + } + + /* sanity check on the stream itself */ + check_stream(stream); + + /* duplicate stream id ? */ + if (nodes->has(stream->m_stream_id)) { + ss << "duplicate instance of stream id " << stream->m_stream_id; + err(ss.str()); + } + + GraphNode *node = new GraphNode(stream, NULL); + + /* add to the map */ + assert(nodes->add(node)); + } + +} + +/** + * on this pass we direct the graph to point to the right nodes + * + */ +void +TrexStreamsCompiler::direct_pass(GraphNodeMap *nodes) { + + /* second pass - direct the graph */ + for (auto p : nodes->get_nodes()) { + + GraphNode *node = p.second; + const TrexStream *stream = node->m_stream; + + /* check the stream points on an existing stream */ + GraphNode *next_node = nodes->get(stream->m_next_stream_id); + if (!next_node) { + std::stringstream ss; + ss << "stream " << node->get_stream_id() << " is pointing on non existent stream " << stream->m_next_stream_id; + err(ss.str()); + } + + node->m_next = next_node; + + /* do we have more than one parent ? */ + next_node->m_parents.push_back(node); + } + + + /* check for multiple parents */ + for (auto p : nodes->get_nodes()) { + GraphNode *node = p.second; + + if (node->m_parents.size() > 0 ) { + std::stringstream ss; + + ss << "stream " << node->get_stream_id() << " is triggered by multiple streams: "; + for (auto x : node->m_parents) { + ss << x->get_stream_id() << " "; + } + + add_warning(ss.str()); + } + } +} + +/** + * mark sure all the streams are reachable + * + */ +void +TrexStreamsCompiler::check_for_unreachable_streams(GraphNodeMap *nodes) { + /* start with the roots */ + std::vector next_nodes = nodes->get_roots(); + + + nodes->clear_marks(); + + /* run BFS from all the roots */ + while (!next_nodes.empty()) { + + /* pull one */ + GraphNode *node = next_nodes.back(); + next_nodes.pop_back(); + if (node->marked) { + continue; + } + + node->marked = true; + + if (node->m_next != NULL) { + next_nodes.push_back(node->m_next); + } + + } + + std::vector unmarked; + nodes->get_unmarked(unmarked); + + if (!unmarked.empty()) { + std::stringstream ss; + for (auto node : unmarked) { + ss << "stream " << node->get_stream_id() << " is unreachable from any other stream\n"; + } + err(ss.str()); + } + + +} + +/** + * check validation of streams for compile + * + * @author imarom (16-Nov-15) + * + * @param streams + * @param fail_msg + * + * @return bool + */ +void +TrexStreamsCompiler::pre_compile_check(const std::vector &streams) { + + GraphNodeMap nodes; + + m_warnings.clear(); + + /* allocate nodes */ + allocate_pass(streams, &nodes); + + /* direct the graph */ + direct_pass(&nodes); + + /* check for non reachable streams inside the graph */ + check_for_unreachable_streams(&nodes); + +} + /************************************** * stream compiler *************************************/ bool -TrexStreamsCompiler::compile(const std::vector &streams, TrexStreamsCompiledObj &obj) { +TrexStreamsCompiler::compile(const std::vector &streams, + TrexStreamsCompiledObj &obj, + std::string *fail_msg) { + + /* compile checks */ + try { + pre_compile_check(streams); + } catch (const TrexException &ex) { + if (fail_msg) { + *fail_msg = ex.what(); + } else { + std::cout << ex.what(); + } + return false; + } + /* for now we do something trivial, */ for (auto stream : streams) { @@ -76,11 +368,6 @@ TrexStreamsCompiler::compile(const std::vector &streams, TrexStrea continue; } - /* for now skip also non self started streams */ - if (!stream->m_self_start) { - continue; - } - /* add it */ obj.add_compiled_stream(stream); } diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 44c8a0fc..42cfc5b8 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -23,9 +23,11 @@ limitations under the License. #include #include +#include class TrexStreamsCompiler; class TrexStream; +class GraphNodeMap; /** * compiled object for a table of streams @@ -68,13 +70,35 @@ private: class TrexStreamsCompiler { public: + /** * compiles a vector of streams to an object passable to the DP * * @author imarom (28-Oct-15) * */ - bool compile(const std::vector &streams, TrexStreamsCompiledObj &obj); + bool compile(const std::vector &streams, TrexStreamsCompiledObj &obj, std::string *fail_msg = NULL); + + /** + * + * returns a reference pointer to the last compile warnings + * if no warnings were produced - the vector is empty + */ + const std::vector & get_last_compile_warnings() { + return m_warnings; + } + +private: + + void pre_compile_check(const std::vector &streams); + void allocate_pass(const std::vector &streams, GraphNodeMap *nodes); + void direct_pass(GraphNodeMap *nodes); + void check_for_unreachable_streams(GraphNodeMap *nodes); + void check_stream(const TrexStream *stream); + void add_warning(const std::string &warning); + void err(const std::string &err); + + std::vector m_warnings; }; #endif /* __TREX_STREAMS_COMPILER_H__ */ -- cgit 1.2.3-korg From 0e8c9ae666d61897cb405c469a71be09d54a649b Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Wed, 18 Nov 2015 16:23:55 +0200 Subject: add support for a program of streams. refactor the dp code --- scripts/stl/burst_1pkt.yaml | 36 +++ scripts/stl/burst_1pkt_1burst.yaml | 13 + src/bp_sim.cpp | 44 ++- src/bp_sim.h | 15 +- src/gtest/trex_stateless_gtest.cpp | 59 +++- src/main.cpp | 1 + src/stateless/cp/trex_stream.cpp | 65 ++++ src/stateless/cp/trex_stream.h | 21 +- src/stateless/cp/trex_streams_compiler.cpp | 64 +++- src/stateless/cp/trex_streams_compiler.h | 12 +- src/stateless/dp/trex_stateless_dp_core.cpp | 328 ++++++++++++++++++--- src/stateless/dp/trex_stateless_dp_core.h | 92 +++++- src/stateless/dp/trex_stream_node.h | 101 ++++++- .../messaging/trex_stateless_messaging.cpp | 21 +- src/stateless/messaging/trex_stateless_messaging.h | 30 +- 15 files changed, 823 insertions(+), 79 deletions(-) create mode 100644 scripts/stl/burst_1pkt.yaml create mode 100644 scripts/stl/burst_1pkt_1burst.yaml (limited to 'src/gtest') diff --git a/scripts/stl/burst_1pkt.yaml b/scripts/stl/burst_1pkt.yaml new file mode 100644 index 00000000..9ddc077a --- /dev/null +++ b/scripts/stl/burst_1pkt.yaml @@ -0,0 +1,36 @@ +### Single stream UDP packet, 64B ### +##################################### +- name: stream0 + stream: + self_start: True + next_stream_id: stream1 + packet: + binary: cap2/udp_64B.pcap + mode: + type: single_burst + pps: 100 + total_pkts : 100 + rx_stats: [] + +- name: stream1 + stream: + self_start: False + next_stream_id: stream2 + packet: + binary: cap2/udp_64B.pcap + mode: + type: single_burst + pps: 100 + total_pkts : 200 + rx_stats: [] + +- name: stream2 + stream: + self_start: False + packet: + binary: cap2/udp_64B.pcap + mode: + type: single_burst + pps: 100 + total_pkts : 300 + rx_stats: [] \ No newline at end of file diff --git a/scripts/stl/burst_1pkt_1burst.yaml b/scripts/stl/burst_1pkt_1burst.yaml new file mode 100644 index 00000000..3bf6a064 --- /dev/null +++ b/scripts/stl/burst_1pkt_1burst.yaml @@ -0,0 +1,13 @@ +### Single stream UDP packet, 64B ### +##################################### +- name: stream0 + stream: + self_start: True + packet: + binary: cap2/udp_64B.pcap + mode: + type: single_burst + pps: 100 + total_pkts : 100 + rx_stats: [] + diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index c456e9a3..22335da4 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -26,6 +26,7 @@ limitations under the License. #include #include +#include #undef VALG @@ -3129,6 +3130,13 @@ void CNodeGenerator::remove_all(CFlowGenListPerThread * thread){ while (!m_p_queue.empty()) { node = m_p_queue.top(); m_p_queue.pop(); + /* sanity check */ + if (node->m_type == CGenNode::STATELESS_PKT) { + CGenNodeStateless * p=(CGenNodeStateless *)node; + /* need to be changed in Pause support */ + assert(p->is_mask_for_free()); + } + thread->free_node( node); } } @@ -3144,6 +3152,7 @@ int CNodeGenerator::open_file(std::string file_name, return (0); } + int CNodeGenerator::close_file(CFlowGenListPerThread * thread){ remove_all(thread); BP_ASSERT(m_v_if); @@ -3153,7 +3162,7 @@ int CNodeGenerator::close_file(CFlowGenListPerThread * thread){ int CNodeGenerator::update_stl_stats(CGenNodeStateless *node_sl){ if ( m_preview_mode.getVMode() >2 ){ - fprintf(stdout," %llu ,", (unsigned long long)m_cnt); + fprintf(stdout," %4lu ,", (ulong)m_cnt); node_sl->Dump(stdout); m_cnt++; } @@ -3516,7 +3525,7 @@ int CNodeGenerator::flush_file(dsec_t max_time, #endif /* if the stream has been deactivated - end */ - if (unlikely(!node_sl->is_active())) { + if ( unlikely( node_sl->is_mask_for_free() ) ) { thread->free_node(node); } else { node_sl->handle(thread); @@ -3663,8 +3672,19 @@ CNodeGenerator::handle_slow_messages(uint8_t type, exit_scheduler = true; } else { - printf(" ERROR type is not valid %d \n",type); - assert(0); + if ( type == CGenNode::COMMAND) { + m_p_queue.pop(); + CGenNodeCommand *node_cmd = (CGenNodeCommand *)node; + { + TrexStatelessCpToDpMsgBase * cmd=node_cmd->m_cmd; + cmd->handle(&thread->m_stateless_dp_info); + exit_scheduler = cmd->is_quit(); + thread->free_node((CGenNode *)node_cmd);/* free the node */ + } + }else{ + printf(" ERROR type is not valid %d \n",type); + assert(0); + } } return exit_scheduler; @@ -3956,7 +3976,7 @@ void CFlowGenListPerThread::start_stateless_simulation_file(std::string erf_file } void CFlowGenListPerThread::stop_stateless_simulation_file(){ - m_node_gen.close_file(this); + m_node_gen.m_v_if->close_file(); } void CFlowGenListPerThread::start_stateless_daemon_simulation(){ @@ -3966,6 +3986,15 @@ void CFlowGenListPerThread::start_stateless_daemon_simulation(){ } + +/* return true if we need to shedule next_stream, */ + +bool CFlowGenListPerThread::set_stateless_next_node( CGenNodeStateless * cur_node, + CGenNodeStateless * next_node){ + return ( m_stateless_dp_info.set_stateless_next_node(cur_node,next_node) ); +} + + void CFlowGenListPerThread::start_stateless_daemon(){ m_cur_time_sec = 0; m_stateless_dp_info.start(); @@ -6888,6 +6917,11 @@ void CGenNodeBase::free_base(){ p->free_stl_node(); return; } + if ( m_type == COMMAND ) { + CGenNodeCommand* p=(CGenNodeCommand*)this; + p->free_command(); + } + } diff --git a/src/bp_sim.h b/src/bp_sim.h index d218237c..be462a91 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -62,6 +62,12 @@ limitations under the License. #undef NAT_TRACE_ +static inline double +usec_to_sec(double usec) { + return (usec / (1000 * 1000)); +} + + #define FORCE_NO_INLINE __attribute__ ((noinline)) #define MAX_LATENCY_PORTS 12 @@ -1383,7 +1389,9 @@ public: FLOW_SYNC =4, /* called evey 1 msec */ STATELESS_PKT =5, EXIT_SCHED =6, - EXIT_PORT_SCHED =7 + COMMAND =7, + + EXIT_PORT_SCHED =8 }; @@ -1898,6 +1906,8 @@ public: public: void add_node(CGenNode * mynode); void remove_all(CFlowGenListPerThread * thread); + void remove_all_stateless(CFlowGenListPerThread * thread); + int open_file(std::string file_name, CPreviewMode * preview); int close_file(CFlowGenListPerThread * thread); @@ -3455,6 +3465,9 @@ public: /* close a file for simulation */ void stop_stateless_simulation_file(); + /* return true if we need to shedule next_stream, */ + bool set_stateless_next_node( CGenNodeStateless * cur_node, + CGenNodeStateless * next_node); void Dump(FILE *fd); diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 9148d5ae..46fe22d3 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -1,5 +1,5 @@ /* - Hanoh Haim + Hanoch Haim Cisco Systems, Inc. */ @@ -91,6 +91,7 @@ public: lpt->start_stateless_daemon_simulation(); + //lpt->m_node_gen.DumpHist(stdout); cmp.d_sec = m_time_diff; @@ -279,6 +280,7 @@ TEST_F(basic_stl, single_pkt) { TrexStreamsCompiler compile; + uint8_t port_id=0; std::vector streams; @@ -288,23 +290,23 @@ TEST_F(basic_stl, single_pkt) { stream1->m_enabled = true; stream1->m_self_start = true; + stream1->m_port_id= port_id; CPcapLoader pcap; pcap.load_pcap_file("cap2/udp_64B.pcap",0); pcap.update_ip_src(0x10000001); pcap.clone_packet_into_stream(stream1); - - + streams.push_back(stream1); // stream - clean - TrexStreamsCompiledObj comp_obj(0,1.0); + TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 10 ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 10.0 /*sec */ ); t1.m_msg = lpstart; @@ -678,4 +680,51 @@ TEST_F(basic_stl, compile_with_warnings) { } +TEST_F(basic_stl, compile_good_stream_id_compres) { + + TrexStreamsCompiler compile; + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stSINGLE_BURST,0,700); + stream1->m_self_start = true; + stream1->m_enabled = true; + stream1->set_pps(1.0); + stream1->set_single_burst(200); + + /* non existant next stream */ + stream1->m_next_stream_id = 800; + + + TrexStream * stream2 = new TrexStream(TrexStream::stSINGLE_BURST,0,800); + stream2->set_pps(52.0); + stream2->m_enabled = true; + stream2->m_next_stream_id = 700; + stream2->set_single_burst(300); + + + streams.push_back(stream1); + streams.push_back(stream2); + + TrexStreamsCompiledObj comp_obj(0,1.0); + + std::string err_msg; + EXPECT_TRUE(compile.compile(streams, comp_obj, &err_msg)); + + printf(" %s \n",err_msg.c_str()); + + comp_obj.Dump(stdout); + + EXPECT_EQ_UINT32(comp_obj.get_objects()[0].m_stream->m_stream_id,0); + EXPECT_EQ_UINT32(comp_obj.get_objects()[0].m_stream->m_next_stream_id,1); + + EXPECT_EQ_UINT32(comp_obj.get_objects()[1].m_stream->m_stream_id,1); + EXPECT_EQ_UINT32(comp_obj.get_objects()[1].m_stream->m_next_stream_id,0); + + delete stream1; + delete stream2; + +} + + + /********************************************* Itay Tests End *************************************/ diff --git a/src/main.cpp b/src/main.cpp index 64547d57..b633fce6 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -767,6 +767,7 @@ extern "C" const char * get_build_time(void){ + int main(int argc , char * argv[]){ int res=0; time_init(); diff --git a/src/stateless/cp/trex_stream.cpp b/src/stateless/cp/trex_stream.cpp index 1a05257c..5203b2a2 100644 --- a/src/stateless/cp/trex_stream.cpp +++ b/src/stateless/cp/trex_stream.cpp @@ -25,6 +25,71 @@ limitations under the License. /************************************** * stream *************************************/ + + +std::string TrexStream::get_stream_type_str(stream_type_t stream_type){ + + std::string res; + + + switch (stream_type) { + + case stCONTINUOUS : + res="stCONTINUOUS "; + break; + + case stSINGLE_BURST : + res="stSINGLE_BURST "; + break; + + case stMULTI_BURST : + res="stMULTI_BURST "; + break; + default: + res="Unknow "; + }; + return(res); +} + + +void TrexStream::Dump(FILE *fd){ + + fprintf(fd,"\n"); + fprintf(fd,"==> Stream_id : %lu \n",(ulong)m_stream_id); + fprintf(fd," Enabled : %lu \n",(ulong)(m_enabled?1:0)); + fprintf(fd," Self_start : %lu \n",(ulong)(m_self_start?1:0)); + + if (m_next_stream_id>=0) { + fprintf(fd," Nex_stream_id : %lu \n",(ulong)m_next_stream_id); + }else { + fprintf(fd," Nex_stream_id : %d \n",m_next_stream_id); + } + + fprintf(fd," Port_id : %lu \n",(ulong)m_port_id); + + if (m_isg_usec>0.0) { + fprintf(fd," isg : %6.2f \n",m_isg_usec); + } + fprintf(fd," type : %s \n",get_stream_type_str(m_type).c_str()); + + if ( m_type == TrexStream::stCONTINUOUS ) { + fprintf(fd," pps : %f \n",m_pps); + } + if (m_type == TrexStream::stSINGLE_BURST) { + fprintf(fd," pps : %f \n",m_pps); + fprintf(fd," burst : %lu \n",(ulong)m_burst_total_pkts); + } + if (m_type == TrexStream::stMULTI_BURST) { + fprintf(fd," pps : %f \n",m_pps); + fprintf(fd," burst : %lu \n",(ulong)m_burst_total_pkts); + fprintf(fd," mburst : %lu \n",(ulong)m_num_bursts); + if (m_ibg_usec>0.0) { + fprintf(fd," m_ibg_usec : %f \n",m_ibg_usec); + } + } +} + + TrexStream::TrexStream(uint8_t type, uint8_t port_id, uint32_t stream_id) : m_port_id(port_id), m_stream_id(stream_id) { diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index c2628cc3..0634829e 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -1,5 +1,6 @@ /* Itay Marom + Hanoch Haim Cisco Systems, Inc. */ @@ -65,6 +66,9 @@ public: stMULTI_BURST = 6 }; + typedef uint8_t stream_type_t ; + + static std::string get_stream_type_str(stream_type_t stream_type); public: TrexStream(uint8_t type,uint8_t port_id, uint32_t stream_id); @@ -80,6 +84,12 @@ public: /* access the stream json */ const Json::Value & get_stream_json(); + /* compress the stream id to be zero based */ + void fix_dp_stream_id(uint32_t my_stream_id,int next_stream_id){ + m_stream_id = my_stream_id; + m_next_stream_id = next_stream_id; + } + double get_pps() { return m_pps; } @@ -96,6 +106,14 @@ public: return ( m_type ); } + bool is_dp_next_stream(){ + if (m_next_stream_id<0) { + return (false); + }else{ + return (true); + } + } + void set_multi_burst(uint32_t burst_total_pkts, @@ -132,11 +150,12 @@ public: return (dp); } + void Dump(FILE *fd); public: /* basic */ uint8_t m_type; uint8_t m_port_id; - uint32_t m_stream_id; + uint32_t m_stream_id; /* id from RPC can be anything */ /* config fields */ diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index 0c3b4ef0..bdfc3c01 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -36,6 +36,7 @@ class GraphNode { public: GraphNode(TrexStream *stream, GraphNode *next) : m_stream(stream), m_next(next) { marked = false; + m_compressed_stream_id=-1; } uint32_t get_stream_id() const { @@ -46,6 +47,7 @@ public: GraphNode *m_next; std::vector m_parents; bool marked; + int m_compressed_stream_id; }; /** @@ -143,8 +145,10 @@ TrexStreamsCompiledObj::~TrexStreamsCompiledObj() { m_objs.clear(); } + void -TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream) { +TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream){ + obj_st obj; obj.m_stream = stream->clone_as_dp(); @@ -152,6 +156,26 @@ TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream) { m_objs.push_back(obj); } +void +TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream, + uint32_t my_dp_id, int next_dp_id) { + obj_st obj; + + obj.m_stream = stream->clone_as_dp(); + /* compress the id's*/ + obj.m_stream->fix_dp_stream_id(my_dp_id,next_dp_id); + + m_objs.push_back(obj); +} + +void TrexStreamsCompiledObj::Dump(FILE *fd){ + for (auto obj : m_objs) { + obj.m_stream->Dump(fd); + } +} + + + TrexStreamsCompiledObj * TrexStreamsCompiledObj::clone() { @@ -197,6 +221,8 @@ void TrexStreamsCompiler::allocate_pass(const std::vector &streams, GraphNodeMap *nodes) { std::stringstream ss; + uint32_t compressed_stream_id=0; + /* first pass - allocate all nodes and check for duplicates */ for (auto stream : streams) { @@ -216,6 +242,10 @@ TrexStreamsCompiler::allocate_pass(const std::vector &streams, } GraphNode *node = new GraphNode(stream, NULL); + /* allocate new compressed id */ + node->m_compressed_stream_id = compressed_stream_id; + + compressed_stream_id++; /* add to the map */ assert(nodes->add(node)); @@ -323,9 +353,8 @@ TrexStreamsCompiler::check_for_unreachable_streams(GraphNodeMap *nodes) { * @return bool */ void -TrexStreamsCompiler::pre_compile_check(const std::vector &streams) { - - GraphNodeMap nodes; +TrexStreamsCompiler::pre_compile_check(const std::vector &streams, + GraphNodeMap & nodes) { m_warnings.clear(); @@ -348,9 +377,20 @@ TrexStreamsCompiler::compile(const std::vector &streams, TrexStreamsCompiledObj &obj, std::string *fail_msg) { +#if 0 + fprintf(stdout,"------------pre compile \n"); + for (auto stream : streams) { + stream->Dump(stdout); + } + fprintf(stdout,"------------pre compile \n"); +#endif + + GraphNodeMap nodes; + + /* compile checks */ try { - pre_compile_check(streams); + pre_compile_check(streams,nodes); } catch (const TrexException &ex) { if (fail_msg) { *fail_msg = ex.what(); @@ -360,6 +400,7 @@ TrexStreamsCompiler::compile(const std::vector &streams, return false; } + /* for now we do something trivial, */ for (auto stream : streams) { @@ -368,8 +409,19 @@ TrexStreamsCompiler::compile(const std::vector &streams, continue; } + int new_id= nodes.get(stream->m_stream_id)->m_compressed_stream_id; + assert(new_id>=0); + uint32_t my_stream_id = (uint32_t)new_id; + int my_next_stream_id=-1; + if (stream->m_next_stream_id>=0) { + my_next_stream_id=nodes.get(stream->m_next_stream_id)->m_compressed_stream_id; + } + /* add it */ - obj.add_compiled_stream(stream); + obj.add_compiled_stream(stream, + my_stream_id, + my_next_stream_id + ); } return true; diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 42cfc5b8..200f7ce9 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -50,6 +50,10 @@ public: return m_objs; } + uint8_t get_port_id(){ + return (m_port_id); + } + /** * clone the compiled object * @@ -60,8 +64,13 @@ public: return (m_mul); } + void Dump(FILE *fd); + private: + void add_compiled_stream(TrexStream * stream, + uint32_t my_dp_id, int next_dp_id); void add_compiled_stream(TrexStream * stream); + std::vector m_objs; uint8_t m_port_id; @@ -90,7 +99,8 @@ public: private: - void pre_compile_check(const std::vector &streams); + void pre_compile_check(const std::vector &streams, + GraphNodeMap & nodes); void allocate_pass(const std::vector &streams, GraphNodeMap *nodes); void direct_pass(GraphNodeMap *nodes); void check_for_unreachable_streams(GraphNodeMap *nodes); diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index b25a4cfc..640fdb4d 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -1,5 +1,6 @@ /* Itay Marom + Hanoch Haim Cisco Systems, Inc. */ @@ -26,12 +27,83 @@ limitations under the License. #include -static inline double -usec_to_sec(double usec) { - return (usec / (1000 * 1000)); + +void CDpOneStream::Delete(CFlowGenListPerThread * core){ + assert(m_node->get_state() == CGenNodeStateless::ss_INACTIVE); + core->free_node((CGenNode *)m_node); + delete m_dp_stream; + m_node=0; + m_dp_stream=0; +} + +void CDpOneStream::DeleteOnlyStream(){ + assert(m_dp_stream); + delete m_dp_stream; + m_dp_stream=0; +} + +int CGenNodeStateless::get_stream_id(){ + if (m_state ==CGenNodeStateless::ss_FREE_RESUSE) { + return (-1); // not valid + } + assert(m_ref_stream_info); + return ((int)m_ref_stream_info->m_stream_id); +} + + +void CGenNodeStateless::DumpHeader(FILE *fd){ + fprintf(fd," pkt_id, time, port , action , state, stream_id , stype , m-burst# , burst# \n"); + +} +void CGenNodeStateless::Dump(FILE *fd){ + fprintf(fd," %2.4f, %3lu, %s,%s, %3d, %s, %3lu, %3lu \n", + m_time, + (ulong)m_port_id, + "s-pkt", //action + get_stream_state_str(m_state ).c_str(), + get_stream_id(), //stream_id + TrexStream::get_stream_type_str(m_stream_type).c_str(), //stype + (ulong)m_multi_bursts, + (ulong)m_single_burst + ); +} + + +void CGenNodeStateless::refresh(){ + + /* refill the stream info */ + m_single_burst = m_single_burst_refill; + m_multi_bursts = m_ref_stream_info->m_num_bursts; + m_state = CGenNodeStateless::ss_ACTIVE; +} + + + +void CGenNodeCommand::free_command(){ + assert(m_cmd); + delete m_cmd; } +std::string CGenNodeStateless::get_stream_state_str(stream_state_t stream_state){ + std::string res; + + switch (stream_state) { + case CGenNodeStateless::ss_FREE_RESUSE : + res="FREE "; + break; + case CGenNodeStateless::ss_INACTIVE : + res="INACTIVE "; + break; + case CGenNodeStateless::ss_ACTIVE : + res="ACTIVE "; + break; + default: + res="Unknow "; + }; + return(res); +} + void CGenNodeStateless::free_stl_node(){ /* if we have cache mbuf free it */ @@ -43,11 +115,54 @@ void CGenNodeStateless::free_stl_node(){ } +bool TrexStatelessDpPerPort::update_number_of_active_streams(uint32_t d){ + m_active_streams-=d; /* reduce the number of streams */ + if (m_active_streams == 0) { + return (true); + } + return (false); +} + + +void TrexStatelessDpPerPort::stop_traffic(uint8_t port_id){ + + assert(m_state==TrexStatelessDpPerPort::ppSTATE_TRANSMITTING); + + for (auto dp_stream : m_active_nodes) { + CGenNodeStateless * node =dp_stream.m_node; + assert(node->get_port_id() == port_id); + if ( node->get_state() == CGenNodeStateless::ss_ACTIVE) { + node->mark_for_free(); + m_active_streams--; + dp_stream.DeleteOnlyStream(); + + }else{ + dp_stream.Delete(m_core); + } + } + + /* active stream should be zero */ + assert(m_active_streams==0); + m_active_nodes.clear(); + m_state=TrexStatelessDpPerPort::ppSTATE_IDLE; +} + + +void TrexStatelessDpPerPort::create(CFlowGenListPerThread * core){ + m_core=core; + m_state=TrexStatelessDpPerPort::ppSTATE_IDLE; + m_port_id=0; + m_active_streams=0; + m_active_nodes.clear(); +} + + void TrexStatelessDpCore::create(uint8_t thread_id, CFlowGenListPerThread *core) { m_thread_id = thread_id; m_core = core; + m_local_port_offset = 2*core->getDualPortId(); CMessagingManager * cp_dp = CMsgIns::Ins()->getCpDp(); @@ -55,8 +170,54 @@ TrexStatelessDpCore::create(uint8_t thread_id, CFlowGenListPerThread *core) { m_ring_to_cp = cp_dp->getRingDpToCp(thread_id); m_state = STATE_IDLE; + + int i; + for (i=0; im_port_id); + bool schedule =false; + + bool to_stop_port=false; + + if (next_node == NULL) { + /* there is no next stream , reduce the number of active streams*/ + to_stop_port = lp_port->update_number_of_active_streams(1); + + }else{ + uint8_t state=next_node->get_state(); + + /* can't be FREE_RESUSE */ + assert(state != CGenNodeStateless::ss_FREE_RESUSE); + if (next_node->get_state() == CGenNodeStateless::ss_INACTIVE ) { + + /* refill start info and scedule, no update in active streams */ + next_node->refresh(); + schedule = true; + + }else{ + to_stop_port = lp_port->update_number_of_active_streams(1); + } + } + + if ( to_stop_port ) { + /* call stop port explictly to move the state */ + stop_traffic(cur_node->m_port_id); + } + + return ( schedule ); } + + /** * in idle state loop, the processor most of the time sleeps * and periodically checks for messages @@ -76,7 +237,8 @@ TrexStatelessDpCore::idle_state_loop() { void TrexStatelessDpCore::quit_main_loop(){ m_core->set_terminate_mode(true); /* mark it as terminated */ - add_duration(0.0001); /* add message to terminate */ + m_state = STATE_TERMINATE; + add_global_duration(0.0001); } @@ -97,6 +259,7 @@ TrexStatelessDpCore::start_scheduler() { double old_offset = 0.0; m_core->m_node_gen.flush_file(-1, 0.0, false, m_core, old_offset); + /* TBD do we need that ? */ m_core->m_node_gen.close_file(m_core); } @@ -105,6 +268,11 @@ void TrexStatelessDpCore::run_once(){ idle_state_loop(); + + if ( m_state == STATE_TERMINATE ){ + return; + } + start_scheduler(); } @@ -121,8 +289,25 @@ TrexStatelessDpCore::start() { } } -void -TrexStatelessDpCore::add_duration(double duration){ +/* only if both port are idle we can exit */ +void +TrexStatelessDpCore::schedule_exit(){ + + CGenNodeCommand *node = (CGenNodeCommand *)m_core->create_node() ; + + node->m_type = CGenNode::COMMAND; + + node->m_cmd = new TrexStatelessDpCanQuit(); + + /* make sure it will be scheduled after the current node */ + node->m_time = m_core->m_cur_time_sec ; + + m_core->m_node_gen.add_node((CGenNode *)node); +} + + +void +TrexStatelessDpCore::add_global_duration(double duration){ if (duration > 0.0) { CGenNode *node = m_core->create_node() ; @@ -135,9 +320,28 @@ TrexStatelessDpCore::add_duration(double duration){ } } +/* add per port exit */ +void +TrexStatelessDpCore::add_port_duration(double duration, + uint8_t port_id){ + if (duration > 0.0) { + CGenNodeCommand *node = (CGenNodeCommand *)m_core->create_node() ; + + node->m_type = CGenNode::COMMAND; + + /* make sure it will be scheduled after the current node */ + node->m_time = m_core->m_cur_time_sec + duration ; + + node->m_cmd = new TrexStatelessDpStop(port_id); + + m_core->m_node_gen.add_node((CGenNode *)node); + } +} + void -TrexStatelessDpCore::add_cont_stream(TrexStream * stream, +TrexStatelessDpCore::add_cont_stream(TrexStatelessDpPerPort * lp_port, + TrexStream * stream, TrexStreamsCompiledObj *comp) { CGenNodeStateless *node = m_core->create_node_sl(); @@ -145,6 +349,19 @@ TrexStatelessDpCore::add_cont_stream(TrexStream * stream, /* add periodic */ node->m_type = CGenNode::STATELESS_PKT; + node->m_ref_stream_info = stream->clone_as_dp(); + + node->m_next_stream=0; /* will be fixed later */ + + + if ( stream->m_self_start ){ + /* if self start it is in active mode */ + node->m_state =CGenNodeStateless::ss_ACTIVE; + lp_port->m_active_streams++; + }else{ + node->m_state =CGenNodeStateless::ss_INACTIVE; + } + node->m_time = m_core->m_cur_time_sec + usec_to_sec(stream->m_isg_usec); pkt_dir_t dir = m_core->m_node_gen.m_v_if->port_id_to_dir(stream->m_port_id); @@ -166,6 +383,10 @@ TrexStatelessDpCore::add_cont_stream(TrexStream * stream, switch ( stream->m_type ) { case TrexStream::stCONTINUOUS : + node->m_single_burst=0; + node->m_single_burst_refill=0; + node->m_multi_bursts=0; + node->m_ibg_sec = 0.0; break; case TrexStream::stSINGLE_BURST : @@ -187,7 +408,6 @@ TrexStatelessDpCore::add_cont_stream(TrexStream * stream, assert(0); }; - node->m_is_stream_active = 1; node->m_port_id = stream->m_port_id; /* allocate const mbuf */ @@ -208,59 +428,93 @@ TrexStatelessDpCore::add_cont_stream(TrexStream * stream, /* set the packet as a readonly */ node->set_cache_mbuf(m); - /* keep track */ - m_active_nodes.push_back(node); + CDpOneStream one_stream; + + one_stream.m_dp_stream = node->m_ref_stream_info; + one_stream.m_node =node; + + lp_port->m_active_nodes.push_back(one_stream); /* schedule */ m_core->m_node_gen.add_node((CGenNode *)node); - m_state = TrexStatelessDpCore::STATE_TRANSMITTING; - } void -TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj, double duration) { +TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj, + double duration) { + +#if 0 + /* TBD to remove ! */ + obj->Dump(stdout); +#endif + + TrexStatelessDpPerPort * lp_port=get_port_db(obj->get_port_id()); + lp_port->m_active_streams = 0; + /* no nodes in the list */ + assert(lp_port->m_active_nodes.size()==0); + + for (auto single_stream : obj->get_objects()) { + /* all commands should be for the same port */ + assert(obj->get_port_id() == single_stream.m_stream->m_port_id); + add_cont_stream(lp_port,single_stream.m_stream,obj); + } + + uint32_t nodes = lp_port->m_active_nodes.size(); + /* find next stream */ + assert(nodes == obj->get_objects().size()); + + int cnt=0; + + /* set the next_stream pointer */ for (auto single_stream : obj->get_objects()) { - add_cont_stream(single_stream.m_stream,obj); + + if (single_stream.m_stream->is_dp_next_stream() ) { + int stream_id = single_stream.m_stream->m_next_stream_id; + assert(stream_idm_active_nodes[cnt].m_node->m_next_stream = lp_port->m_active_nodes[stream_id].m_node ; + } + cnt++; } + lp_port->m_state =TrexStatelessDpPerPort::ppSTATE_TRANSMITTING; + m_state = TrexStatelessDpCore::STATE_TRANSMITTING; + + if ( duration > 0.0 ){ - add_duration( duration ); + add_port_duration( duration ,obj->get_port_id() ); + } +} + + +bool TrexStatelessDpCore::are_all_ports_idle(){ + + bool res=true; + int i; + for (i=0; im_port_id == port_id) { - node->m_is_stream_active = 0; - } - } - /* remove all the non active nodes */ - auto pred = std::remove_if(m_active_nodes.begin(), - m_active_nodes.end(), - [](CGenNodeStateless *node) { return (!node->m_is_stream_active); }); + TrexStatelessDpPerPort * lp_port = get_port_db(port_id); - m_active_nodes.erase(pred, m_active_nodes.end()); + lp_port->stop_traffic(port_id); - if (m_active_nodes.size() == 0) { - m_state = STATE_IDLE; - /* stop the scheduler */ + if ( are_all_ports_idle() ) { - CGenNode *node = m_core->create_node() ; - - node->m_type = CGenNode::EXIT_SCHED; - - /* make sure it will be scheduled after the current node */ - node->m_time = m_core->m_cur_time_sec + 0.0001; - - m_core->m_node_gen.add_node(node); + schedule_exit(); } - } /** diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index aaa6eed3..28fff2fb 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -1,5 +1,6 @@ /* Itay Marom + Hanoch Haim Cisco Systems, Inc. */ @@ -33,6 +34,52 @@ class CGenNodeStateless; class TrexStreamsCompiledObj; class TrexStream; + +class CDpOneStream { +public: + void Create(){ + } + + void Delete(CFlowGenListPerThread * core); + void DeleteOnlyStream(); + + CGenNodeStateless * m_node; // schedule node + TrexStream * m_dp_stream; // stream info +}; + +class TrexStatelessDpPerPort { + +public: + /* states */ + enum state_e { + ppSTATE_IDLE, + ppSTATE_TRANSMITTING + }; + +public: + TrexStatelessDpPerPort(){ + } + + void create(CFlowGenListPerThread * core); + + void stop_traffic(uint8_t port_id); + + bool update_number_of_active_streams(uint32_t d); + +public: + + state_e m_state; + uint8_t m_port_id; + + uint32_t m_active_streams; /* how many active streams on this port */ + + std::vector m_active_nodes; /* holds the current active nodes */ + CFlowGenListPerThread * m_core ; +}; + +/* for now */ +#define NUM_PORTS_PER_CORE 2 + class TrexStatelessDpCore { public: @@ -40,7 +87,9 @@ public: /* states */ enum state_e { STATE_IDLE, - STATE_TRANSMITTING + STATE_TRANSMITTING, + STATE_TERMINATE, + }; TrexStatelessDpCore() { @@ -83,6 +132,11 @@ public: */ void stop_traffic(uint8_t port_id); + + /* return if all ports are idel */ + bool are_all_ports_idle(); + + /** * check for and handle messages from CP * @@ -112,7 +166,23 @@ public: /* quit the main loop, work in both stateless in stateful, don't free memory trigger from master */ void quit_main_loop(); + bool set_stateless_next_node(CGenNodeStateless * cur_node, + CGenNodeStateless * next_node); + private: + + + TrexStatelessDpPerPort * get_port_db(uint8_t port_id){ + assert((m_local_port_offset==port_id) ||(m_local_port_offset+1==port_id)); + uint8_t local_port_id = port_id -m_local_port_offset; + assert(local_port_id m_active_nodes; + TrexStatelessDpPerPort m_ports[NUM_PORTS_PER_CORE]; /* pointer to the main object */ - CFlowGenListPerThread *m_core; + CFlowGenListPerThread * m_core; double m_duration; }; diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index e4cf964d..1e53887b 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -1,5 +1,6 @@ /* Itay Marom + Hanoh Haim Cisco Systems, Inc. */ @@ -27,20 +28,51 @@ limitations under the License. class TrexStatelessDpCore; #include +class TrexStatelessCpToDpMsgBase; + +struct CGenNodeCommand : public CGenNodeBase { + +friend class TrexStatelessDpCore; + +public: + TrexStatelessCpToDpMsgBase * m_cmd; + + uint8_t m_pad_end[104]; + +public: + void free_command(); + +} __rte_cache_aligned;; + + +static_assert(sizeof(CGenNodeCommand) == sizeof(CGenNode), "sizeof(CGenNodeCommand) != sizeof(CGenNode)" ); + /* this is a event for stateless */ struct CGenNodeStateless : public CGenNodeBase { friend class TrexStatelessDpCore; +public: + enum { + ss_FREE_RESUSE =1, /* should be free by scheduler */ + ss_INACTIVE =2, /* will be active by other stream or stopped */ + ss_ACTIVE =3 /* the stream is active */ + }; + typedef uint8_t stream_state_t ; + + static std::string get_stream_state_str(stream_state_t stream_state); + private: + /* cache line 0 */ + /* important stuff here */ void * m_cache_mbuf; double m_next_time_offset; /* in sec */ double m_ibg_sec; /* inter burst time in sec */ - uint8_t m_is_stream_active; + stream_state_t m_state; uint8_t m_port_id; - uint8_t m_stream_type; /* TrexStream::STREAM_TYPE */ + uint8_t m_stream_type; /* see TrexStream::STREAM_TYPE ,stream_type_t */ uint8_t m_pad; uint32_t m_single_burst; /* the number of bursts in case of burst */ @@ -48,14 +80,40 @@ private: uint32_t m_multi_bursts; /* in case of multi_burst how many bursts */ - + /* cache line 1 */ + TrexStream * m_ref_stream_info; /* the stream info */ + CGenNodeStateless * m_next_stream; /* pad to match the size of CGenNode */ - uint8_t m_pad_end[65]; + uint8_t m_pad_end[56]; + + public: + uint8_t get_port_id(){ + return (m_port_id); + } + + + /* 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); + } + + inline bool is_mask_for_free(){ + return (get_state() == CGenNodeStateless::ss_FREE_RESUSE ?true:false); + + } + inline void mark_for_free(){ + set_state(CGenNodeStateless::ss_FREE_RESUSE); + /* only to be safe */ + m_ref_stream_info= NULL; + m_next_stream= NULL; + + } + inline uint8_t get_stream_type(){ return (m_stream_type); } @@ -72,11 +130,16 @@ public: return (m_multi_bursts); } + inline void set_state(stream_state_t new_state){ + m_state=new_state; + } - inline bool is_active() { - return m_is_stream_active; + + inline stream_state_t get_state() { + return m_state; } + void refresh(); inline void handle_continues(CFlowGenListPerThread *thread) { thread->m_node_gen.m_v_if->send_node( (CGenNode *)this); @@ -100,14 +163,22 @@ public: }else{ m_multi_bursts--; if ( m_multi_bursts == 0 ) { - /* stop */ - m_is_stream_active =0; + 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); + + thread->m_node_gen.m_p_queue.push( (CGenNode *)m_next_stream); + }else{ + // in case of zero we will schedule a command to stop + // will be called from set_stateless_next_node + } + }else{ m_time += m_ibg_sec; m_single_burst = m_single_burst_refill; - + thread->m_node_gen.m_p_queue.push( (CGenNode *)this); } - thread->m_node_gen.m_p_queue.push( (CGenNode *)this); } } @@ -168,10 +239,14 @@ public: void free_stl_node(); +public: + /* debug functions */ - void Dump(FILE *fd){ - fprintf(fd," %f, %lu, %lu \n",m_time,(ulong)m_port_id,(ulong)get_mbuf_cache_dir()); - } + int get_stream_id(); + + static void DumpHeader(FILE *fd); + + void Dump(FILE *fd); } __rte_cache_aligned; diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp index 2e3acffd..856fd9e3 100644 --- a/src/stateless/messaging/trex_stateless_messaging.cpp +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -1,5 +1,6 @@ /* Itay Marom + Hanoch Haim Cisco Systems, Inc. */ @@ -88,7 +89,6 @@ TrexStatelessDpQuit::clone(){ } - bool TrexStatelessDpQuit::handle(TrexStatelessDpCore *dp_core){ /* quit */ @@ -96,3 +96,22 @@ bool TrexStatelessDpQuit::handle(TrexStatelessDpCore *dp_core){ return (true); } + +bool TrexStatelessDpCanQuit::handle(TrexStatelessDpCore *dp_core){ + + if ( dp_core->are_all_ports_idle() ){ + /* if all ports are idle quit now */ + set_quit(true); + } + return (true); +} + +TrexStatelessCpToDpMsgBase * +TrexStatelessDpCanQuit::clone(){ + + TrexStatelessCpToDpMsgBase *new_msg = new TrexStatelessDpCanQuit(); + + return new_msg; +} + + diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index 6473a6a4..7dc307c7 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -36,6 +36,7 @@ class TrexStatelessCpToDpMsgBase { public: TrexStatelessCpToDpMsgBase() { + m_quit_scheduler=false; } virtual ~TrexStatelessCpToDpMsgBase() { @@ -54,9 +55,19 @@ public: */ virtual TrexStatelessCpToDpMsgBase * clone() = 0; + /* do we want to quit scheduler, can be set by handle function */ + void set_quit(bool enable){ + m_quit_scheduler=enable; + } + + bool is_quit(){ + return ( m_quit_scheduler); + } + /* no copy constructor */ TrexStatelessCpToDpMsgBase(TrexStatelessCpToDpMsgBase &) = delete; - +private: + bool m_quit_scheduler; }; /** @@ -116,5 +127,22 @@ public: virtual TrexStatelessCpToDpMsgBase * clone(); }; +/** + * a message to check if both port are idel and exit + * + * @author hhaim + */ +class TrexStatelessDpCanQuit : public TrexStatelessCpToDpMsgBase { +public: + + TrexStatelessDpCanQuit() { + } + + virtual bool handle(TrexStatelessDpCore *dp_core); + + virtual TrexStatelessCpToDpMsgBase * clone(); +}; + + #endif /* __TREX_STATELESS_MESSAGING_H__ */ -- cgit 1.2.3-korg From a2625fbfa24a812b950c1a95ef067e6fa169a3cf Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Thu, 19 Nov 2015 09:08:28 +0200 Subject: add a test for stream program --- .gitignore | 2 + scripts/exp/stl_simple_prog1-0-ex.erf | Bin 0 -> 880 bytes src/gtest/trex_stateless_gtest.cpp | 63 ++++++++++++++++++++++++++++ src/stateless/dp/trex_stateless_dp_core.cpp | 7 ++-- 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 scripts/exp/stl_simple_prog1-0-ex.erf (limited to 'src/gtest') diff --git a/.gitignore b/.gitignore index e35015d6..2f3d1759 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,8 @@ scripts/exp/stl_multi_pkt2-0.erf scripts/exp/stl_single_pkt_burst1-0.erf scripts/exp/stl_single_sctp_pkt-0.erf scripts/exp/stl_single_stream-0.erf +scripts/exp/stl_simple_prog1-0.erf + *.pyc diff --git a/scripts/exp/stl_simple_prog1-0-ex.erf b/scripts/exp/stl_simple_prog1-0-ex.erf new file mode 100644 index 00000000..374256c2 Binary files /dev/null and b/scripts/exp/stl_simple_prog1-0-ex.erf differ diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 46fe22d3..cf80a50c 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -225,6 +225,69 @@ TEST_F(basic_stl, load_pcap_file) { } + +TEST_F(basic_stl, simple_prog1) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_simple_prog1"; + + TrexStreamsCompiler compile; + + + std::vector streams; + + /* stream1 */ + TrexStream * stream1 = new TrexStream(TrexStream::stSINGLE_BURST, 0,100); + stream1->set_pps(1.0); + stream1->set_single_burst(5); + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_next_stream_id=200; + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + + /* stream1 */ + + TrexStream * stream2 = new TrexStream(TrexStream::stSINGLE_BURST, 0,200); + stream2->set_pps(1.0); + stream2->set_single_burst(5); + stream2->m_enabled = true; + stream2->m_self_start = false; + + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000002); + pcap.clone_packet_into_stream(stream2); + streams.push_back(stream2); + + + TrexStreamsCompiledObj comp_obj(0,1.0); + + EXPECT_TRUE(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 10.0 ); + + + t1.m_msg = lpstart; + + bool res=t1.init(); + + delete stream1 ; + delete stream2 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + + TEST_F(basic_stl, single_pkt_burst1) { CBasicStl t1; diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 640fdb4d..c4fdd44b 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -435,9 +435,10 @@ TrexStatelessDpCore::add_cont_stream(TrexStatelessDpPerPort * lp_port, lp_port->m_active_nodes.push_back(one_stream); - /* schedule */ - m_core->m_node_gen.add_node((CGenNode *)node); - + /* schedule only if active */ + if (node->m_state == CGenNodeStateless::ss_ACTIVE) { + m_core->m_node_gen.add_node((CGenNode *)node); + } } void -- cgit 1.2.3-korg From 7af2e24f4eb76820f9c1c9aad841ab6c91d0435a Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Thu, 19 Nov 2015 09:36:40 +0200 Subject: another stream program tests --- .gitignore | 1 + scripts/exp/stl_simple_prog2-0-ex.erf | Bin 0 -> 792 bytes src/gtest/trex_stateless_gtest.cpp | 63 +++++++++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 scripts/exp/stl_simple_prog2-0-ex.erf (limited to 'src/gtest') diff --git a/.gitignore b/.gitignore index 2f3d1759..34c7060d 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ scripts/exp/stl_single_pkt_burst1-0.erf scripts/exp/stl_single_sctp_pkt-0.erf scripts/exp/stl_single_stream-0.erf scripts/exp/stl_simple_prog1-0.erf +scripts/exp/stl_simple_prog2-0.erf diff --git a/scripts/exp/stl_simple_prog2-0-ex.erf b/scripts/exp/stl_simple_prog2-0-ex.erf new file mode 100644 index 00000000..3ec46e2f Binary files /dev/null and b/scripts/exp/stl_simple_prog2-0-ex.erf differ diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index cf80a50c..2e720255 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -110,7 +110,6 @@ public: return (res); } - public: int m_threads; double m_time_diff; @@ -225,6 +224,68 @@ TEST_F(basic_stl, load_pcap_file) { } +TEST_F(basic_stl, simple_prog2) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_simple_prog2"; + + TrexStreamsCompiler compile; + + + std::vector streams; + + /* stream1 */ + TrexStream * stream1 = new TrexStream(TrexStream::stSINGLE_BURST, 0,100); + stream1->set_pps(1.0); + stream1->set_single_burst(5); + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_next_stream_id=200; + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + + /* stream1 */ + + TrexStream * stream2 = new TrexStream(TrexStream::stSINGLE_BURST, 0,200); + stream2->set_pps(1.0); + stream2->set_single_burst(5); + stream2->m_isg_usec = 2000000; /*time betwean stream 1 to stream 2 */ + stream2->m_enabled = true; + stream2->m_self_start = false; + + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000002); + pcap.clone_packet_into_stream(stream2); + streams.push_back(stream2); + + + TrexStreamsCompiledObj comp_obj(0,1.0); + + EXPECT_TRUE(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 10.0 ); + + + t1.m_msg = lpstart; + + bool res=t1.init(); + + delete stream1 ; + delete stream2 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + TEST_F(basic_stl, simple_prog1) { -- cgit 1.2.3-korg From 91a4e6cc117076d3f5d34437581f7ffe91e6892b Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Thu, 19 Nov 2015 10:44:39 +0200 Subject: another stream program tests --- .gitignore | 1 + scripts/exp/stl_simple_prog3-0-ex.erf | Bin 0 -> 4312 bytes src/gtest/trex_stateless_gtest.cpp | 69 ++++++++++++++++++++++++++++++ src/stateless/dp/trex_stateless_dp_core.h | 2 +- 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 scripts/exp/stl_simple_prog3-0-ex.erf (limited to 'src/gtest') diff --git a/.gitignore b/.gitignore index 34c7060d..183484fb 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ scripts/exp/stl_single_sctp_pkt-0.erf scripts/exp/stl_single_stream-0.erf scripts/exp/stl_simple_prog1-0.erf scripts/exp/stl_simple_prog2-0.erf +scripts/exp/stl_simple_prog3-0.erf diff --git a/scripts/exp/stl_simple_prog3-0-ex.erf b/scripts/exp/stl_simple_prog3-0-ex.erf new file mode 100644 index 00000000..4da3438c Binary files /dev/null and b/scripts/exp/stl_simple_prog3-0-ex.erf differ diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 2e720255..93e8387f 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -224,6 +224,75 @@ TEST_F(basic_stl, load_pcap_file) { } + +TEST_F(basic_stl, simple_prog3) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_simple_prog3"; + + TrexStreamsCompiler compile; + + + std::vector streams; + + /* stream1 */ + TrexStream * stream1 = new TrexStream(TrexStream::stSINGLE_BURST, 0,100); + stream1->set_pps(1.0); + stream1->set_single_burst(5); + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_next_stream_id=200; + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + + /* stream1 */ + + TrexStream * stream2 = new TrexStream(TrexStream::stMULTI_BURST, 0,200); + stream2->set_pps(1.0); + stream2->m_isg_usec = 1000000; /*time betwean stream 1 to stream 2 */ + stream2->m_enabled = true; + stream2->m_self_start = false; + stream2->set_multi_burst(5, + 3, + 2000000.0); + + // next stream is 100 - loop + stream2->m_next_stream_id=100; + + + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000002); + pcap.clone_packet_into_stream(stream2); + streams.push_back(stream2); + + + TrexStreamsCompiledObj comp_obj(0,1.0); + + EXPECT_TRUE(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 50.0 ); + + + t1.m_msg = lpstart; + + bool res=t1.init(); + + delete stream1 ; + delete stream2 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + TEST_F(basic_stl, simple_prog2) { CBasicStl t1; diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index 28fff2fb..85afcf8f 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -88,7 +88,7 @@ public: enum state_e { STATE_IDLE, STATE_TRANSMITTING, - STATE_TERMINATE, + STATE_TERMINATE }; -- cgit 1.2.3-korg From 9c69a86ed94732196c2b62209f61da783cda1386 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Thu, 19 Nov 2015 12:46:48 +0200 Subject: another small test --- .gitignore | 1 + scripts/exp/stl_simple_prog4-0-ex.erf | Bin 0 -> 3344 bytes src/gtest/trex_stateless_gtest.cpp | 83 ++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 scripts/exp/stl_simple_prog4-0-ex.erf (limited to 'src/gtest') diff --git a/.gitignore b/.gitignore index 183484fb..fcc5135f 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ scripts/exp/stl_single_stream-0.erf scripts/exp/stl_simple_prog1-0.erf scripts/exp/stl_simple_prog2-0.erf scripts/exp/stl_simple_prog3-0.erf +scripts/exp/stl_simple_prog4-0.erf diff --git a/scripts/exp/stl_simple_prog4-0-ex.erf b/scripts/exp/stl_simple_prog4-0-ex.erf new file mode 100644 index 00000000..62da4682 Binary files /dev/null and b/scripts/exp/stl_simple_prog4-0-ex.erf differ diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 93e8387f..ac0a5e63 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -225,6 +225,89 @@ TEST_F(basic_stl, load_pcap_file) { +TEST_F(basic_stl, simple_prog4) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_simple_prog4"; + + TrexStreamsCompiler compile; + + + std::vector streams; + + + /* stream0 */ + TrexStream * stream0 = new TrexStream(TrexStream::stCONTINUOUS, 0,300); + stream0->set_pps(1.0); + stream0->m_enabled = true; + stream0->m_self_start = true; + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000000); + pcap.clone_packet_into_stream(stream0); + streams.push_back(stream0); + + + /* stream1 */ + TrexStream * stream1 = new TrexStream(TrexStream::stSINGLE_BURST, 0,100); + stream1->set_pps(1.0); + stream1->set_single_burst(5); + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_next_stream_id=200; + + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + + /* stream1 */ + + TrexStream * stream2 = new TrexStream(TrexStream::stMULTI_BURST, 0,200); + stream2->set_pps(1.0); + stream2->m_isg_usec = 1000000; /*time betwean stream 1 to stream 2 */ + stream2->m_enabled = true; + stream2->m_self_start = false; + stream2->set_multi_burst(5, + 3, + 2000000.0); + + // next stream is 100 - loop + stream2->m_next_stream_id=100; + + + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000002); + pcap.clone_packet_into_stream(stream2); + streams.push_back(stream2); + + + TrexStreamsCompiledObj comp_obj(0,1.0); + + EXPECT_TRUE(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 20.0 ); + + + t1.m_msg = lpstart; + + bool res=t1.init(); + + delete stream0 ; + delete stream1 ; + delete stream2 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + + TEST_F(basic_stl, simple_prog3) { CBasicStl t1; -- cgit 1.2.3-korg From 2ae2e4e860194ee8d2b5ec5c4a1375751f51dd98 Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 19 Nov 2015 17:17:38 +0200 Subject: full async DP stop support --- linux/ws_main.py | 2 +- .../trex_control_plane/client/trex_async_client.py | 48 +++++--- .../client/trex_stateless_client.py | 9 +- scripts/exp/ignore-0-ex.erf | Bin 0 -> 880 bytes scripts/exp/ignore-0.erf | Bin 0 -> 880 bytes src/gtest/trex_stateless_gtest.cpp | 121 ++++++++++++++++++++- src/main_dpdk.cpp | 9 +- src/publisher/trex_publisher.cpp | 2 +- src/publisher/trex_publisher.h | 2 +- src/stateless/cp/trex_stateless.cpp | 2 + src/stateless/cp/trex_stateless.h | 9 ++ src/stateless/cp/trex_stateless_port.cpp | 6 +- src/stateless/messaging/trex_stateless_messaging.h | 16 +++ 13 files changed, 201 insertions(+), 25 deletions(-) create mode 100644 scripts/exp/ignore-0-ex.erf create mode 100644 scripts/exp/ignore-0.erf (limited to 'src/gtest') diff --git a/linux/ws_main.py b/linux/ws_main.py index 0bd61f70..617bcf37 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -117,7 +117,7 @@ main_src = SrcGroup(dir='src', 'utl_json.cpp', 'utl_cpuu.cpp', 'msg_manager.cpp', - + 'publisher/trex_publisher.cpp', 'pal/linux/pal_utl.cpp', 'pal/linux/mbuf.cpp' diff --git a/scripts/automation/trex_control_plane/client/trex_async_client.py b/scripts/automation/trex_control_plane/client/trex_async_client.py index 31bec93f..adb91d97 100644 --- a/scripts/automation/trex_control_plane/client/trex_async_client.py +++ b/scripts/automation/trex_control_plane/client/trex_async_client.py @@ -8,6 +8,8 @@ except ImportError: import client.outer_packages from client_utils.jsonrpc_client import JsonRpcClient, BatchMessage +from common.text_opts import * + import json import threading import time @@ -103,13 +105,9 @@ class TrexAsyncStatsManager(): return self.port_stats[str(port_id)] - def update (self, snapshot): - - if snapshot['name'] == 'trex-global': - self.__handle_snapshot(snapshot['data']) - else: - # for now ignore the rest - return + + def update (self, data): + self.__handle_snapshot(data) def __handle_snapshot (self, snapshot): @@ -151,10 +149,11 @@ class TrexAsyncStatsManager(): class CTRexAsyncClient(): - def __init__ (self, server, port): + def __init__ (self, server, port, stateless_client): self.port = port self.server = server + self.stateless_client = stateless_client self.raw_snapshot = {} @@ -165,14 +164,15 @@ class CTRexAsyncClient(): print "\nConnecting To ZMQ Publisher At {0}".format(self.tr) self.active = True - self.t = threading.Thread(target = self._run) + self.t = threading.Thread(target = self.run) # kill this thread on exit and don't add it to the join list self.t.setDaemon(True) self.t.start() - def _run (self): + + def run (self): # Socket to talk to server self.context = zmq.Context() @@ -185,10 +185,12 @@ class CTRexAsyncClient(): line = self.socket.recv_string(); msg = json.loads(line) - key = msg['name'] - self.raw_snapshot[key] = msg['data'] + name = msg['name'] + data = msg['data'] + type = msg['type'] + self.raw_snapshot[name] = data - self.stats.update(msg) + self.__dispatch(name, type, data) def get_stats (self): @@ -199,6 +201,26 @@ class CTRexAsyncClient(): return self.raw_snapshot + # dispatch the message to the right place + def __dispatch (self, name, type, data): + # stats + if name == "trex-global": + self.stats.update(data) + # events + elif name == "trex-event": + self.__handle_async_event(type, data) + else: + # ignore + pass + + def __handle_async_event (self, type, data): + # DP stopped + if (type == 0): + port_id = int(data['port_id']) + print format_text("\n[Event] - Port {0} Stopped".format(port_id), 'bold') + # call the handler + self.stateless_client.async_event_port_stopped(port_id) + def stop (self): self.active = False self.t.join() diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py index 699f0af2..dd11fb67 100755 --- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py @@ -320,6 +320,9 @@ class Port(object): return self.ok() + ################# events handler ###################### + def async_event_port_stopped (self): + self.state = self.STATE_STREAMS class CTRexStatelessClient(object): @@ -337,12 +340,16 @@ class CTRexStatelessClient(object): self._server_version = None self.__err_log = None - self._async_client = CTRexAsyncClient(server, async_port) + self._async_client = CTRexAsyncClient(server, async_port, self) self.streams_db = CStreamsDB() self.connected = False + ################# events handler ###################### + def async_event_port_stopped (self, port_id): + self.ports[port_id].async_event_port_stopped() + ############# helper functions section ############## def validate_port_list(self, port_id_list): diff --git a/scripts/exp/ignore-0-ex.erf b/scripts/exp/ignore-0-ex.erf new file mode 100644 index 00000000..92883717 Binary files /dev/null and b/scripts/exp/ignore-0-ex.erf differ diff --git a/scripts/exp/ignore-0.erf b/scripts/exp/ignore-0.erf new file mode 100644 index 00000000..92883717 Binary files /dev/null and b/scripts/exp/ignore-0.erf differ diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 432c7382..d7bf2ab6 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -46,16 +46,51 @@ public: }; +/** + * handler for DP to CP messages + * + * @author imarom (19-Nov-15) + */ +class DpToCpHandler { +public: + virtual void handle(TrexStatelessDpToCpMsgBase *msg) = 0; +}; class CBasicStl { public: + + CBasicStl(){ m_time_diff=0.001; m_threads=1; m_dump_json=false; + m_dp_to_cp_handler = NULL; + } + + + void 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; + } + } + bool init(void){ CErfIFStl erf_vif; @@ -106,14 +141,18 @@ public: printf(" %s \n",s.c_str()); } + flush_dp_to_cp_messages(); + fl.Delete(); return (res); } public: - int m_threads; - double m_time_diff; - bool m_dump_json; + int m_threads; + double m_time_diff; + bool m_dump_json; + DpToCpHandler *m_dp_to_cp_handler; + TrexStatelessCpToDpMsgBase * m_msg; CNodeRing *m_ring_from_cp; CFlowGenList fl; @@ -292,7 +331,7 @@ TEST_F(basic_stl, simple_prog4) { EXPECT_TRUE(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart( comp_obj.clone(), 20.0 ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, comp_obj.clone(), 20.0 ); t1.m_msg = lpstart; @@ -1003,4 +1042,78 @@ TEST_F(basic_stl, compile_good_stream_id_compres) { +class DpToCpHandlerStopEvent: public DpToCpHandler { +public: + DpToCpHandlerStopEvent(int event_id) { + m_event_id = event_id; + } + + virtual void handle(TrexStatelessDpToCpMsgBase *msg) { + /* first the message must be an event */ + TrexDpPortEventMsg *event = dynamic_cast(msg); + EXPECT_TRUE(event != NULL); + EXPECT_TRUE(event->get_event_type() == TrexDpPortEvent::EVENT_STOP); + + EXPECT_TRUE(event->get_event_id() == m_event_id); + EXPECT_TRUE(event->get_port_id() == 0); + + } + +private: + int m_event_id; +}; + +TEST_F(basic_stl, dp_stop_event) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/ignore"; + + TrexStreamsCompiler compile; + + uint8_t port_id=0; + + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stSINGLE_BURST,0,0); + stream1->set_pps(1.0); + stream1->set_single_burst(100); + + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_port_id= port_id; + + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + // stream - clean + + TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); + + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(17, comp_obj.clone(), 10.0 /*sec */ ); + + + t1.m_msg = lpstart; + + /* let me handle these */ + DpToCpHandlerStopEvent handler(17); + t1.m_dp_to_cp_handler = &handler; + + bool res=t1.init(); + EXPECT_EQ_UINT32(1, res?1:0); + + delete stream1 ; + +} + + /********************************************* Itay Tests End *************************************/ diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 6c92172c..80739d35 100755 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -3199,19 +3199,21 @@ CGlobalTRex::check_for_dp_message_from_core(int thread_id) { TrexStatelessDpToCpMsgBase * msg = (TrexStatelessDpToCpMsgBase *)node; msg->handle(); + delete msg; } } - +/** + * check for messages that arrived from DP to CP + * + */ void CGlobalTRex::check_for_dp_messages() { /* for all the cores - check for a new message */ for (int i = 0; i < get_cores_tx(); i++) { check_for_dp_message_from_core(i); } - - } bool CGlobalTRex::is_all_links_are_up(bool dump){ @@ -3532,6 +3534,7 @@ bool CGlobalTRex::Create(){ cfg.m_rpc_async_cfg = NULL; cfg.m_rpc_server_verbose = false; cfg.m_platform_api = new TrexDpdkPlatformApi(); + cfg.m_publisher = &m_zmq_publisher; m_trex_stateless = new TrexStateless(cfg); } diff --git a/src/publisher/trex_publisher.cpp b/src/publisher/trex_publisher.cpp index 1afb558a..35653069 100644 --- a/src/publisher/trex_publisher.cpp +++ b/src/publisher/trex_publisher.cpp @@ -86,7 +86,7 @@ TrexPublisher::publish_event(event_type_e type, const Json::Value &data) { Json::Value value; std::string s; - value["name"] = "event"; + value["name"] = "trex-event"; value["type"] = type; value["data"] = data; diff --git a/src/publisher/trex_publisher.h b/src/publisher/trex_publisher.h index 07d06678..82603fda 100644 --- a/src/publisher/trex_publisher.h +++ b/src/publisher/trex_publisher.h @@ -39,7 +39,7 @@ public: void publish_json(const std::string &s); enum event_type_e { - EVENT_PORT_STOPPED = 1 + EVENT_PORT_STOPPED = 0 }; void publish_event(event_type_e type, const Json::Value &data); diff --git a/src/stateless/cp/trex_stateless.cpp b/src/stateless/cp/trex_stateless.cpp index 6ef24a7b..a4522837 100644 --- a/src/stateless/cp/trex_stateless.cpp +++ b/src/stateless/cp/trex_stateless.cpp @@ -51,6 +51,8 @@ TrexStateless::TrexStateless(const TrexStatelessCfg &cfg) { } m_platform_api = cfg.m_platform_api; + m_publisher = cfg.m_publisher; + } /** diff --git a/src/stateless/cp/trex_stateless.h b/src/stateless/cp/trex_stateless.h index 57c6ef1d..5c11be1e 100644 --- a/src/stateless/cp/trex_stateless.h +++ b/src/stateless/cp/trex_stateless.h @@ -30,6 +30,7 @@ limitations under the License. #include #include #include +#include #include @@ -93,6 +94,7 @@ public: m_rpc_async_cfg = NULL; m_rpc_server_verbose = false; m_platform_api = NULL; + m_publisher = NULL; } const TrexRpcServerConfig *m_rpc_req_resp_cfg; @@ -100,6 +102,7 @@ public: const TrexPlatformApi *m_platform_api; bool m_rpc_server_verbose; uint8_t m_port_count; + TrexPublisher *m_publisher; }; /** @@ -150,6 +153,10 @@ public: return (m_platform_api); } + TrexPublisher * get_publisher() { + return m_publisher; + } + const std::vector get_port_list() { return m_ports; } @@ -170,6 +177,8 @@ protected: /* platform API */ const TrexPlatformApi *m_platform_api; + TrexPublisher *m_publisher; + std::mutex m_global_cp_lock; }; diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 13d0fc9f..489e2172 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -315,17 +315,21 @@ TrexStatelessPort::send_message_to_dp(TrexStatelessCpToDpMsgBase *msg) { */ void TrexStatelessPort::on_dp_event_occured(TrexDpPortEvent::event_e event_type) { + Json::Value data; + switch (event_type) { case TrexDpPortEvent::EVENT_STOP: /* set a stop event */ change_state(PORT_STATE_STREAMS); /* send a ZMQ event */ + + data["port_id"] = m_port_id; + get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_STOPPED, data); break; default: assert(0); } - printf("hey"); } diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index 445e9378..ffb36124 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -192,6 +192,22 @@ public: virtual bool handle(); + int get_thread_id() { + return m_thread_id; + } + + uint8_t get_port_id() { + return m_port_id; + } + + TrexDpPortEvent::event_e get_event_type() { + return m_event_type; + } + + int get_event_id() { + return m_event_id; + } + private: int m_thread_id; uint8_t m_port_id; -- cgit 1.2.3-korg From b094110ef86889a0694dc71503c5610abaf47ebe Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 19 Nov 2015 22:13:55 +0200 Subject: BUG: didn't do all the states per port on the DP - now fixed --- src/gtest/trex_stateless_gtest.cpp | 20 ++++++++-------- src/stateless/cp/trex_stateless_port.cpp | 6 ++--- src/stateless/cp/trex_stateless_port.h | 2 -- src/stateless/dp/trex_stateless_dp_core.cpp | 2 +- src/stateless/dp/trex_stateless_dp_core.h | 27 ++++++++++++++-------- .../messaging/trex_stateless_messaging.cpp | 11 ++++++--- src/stateless/messaging/trex_stateless_messaging.h | 8 ++++--- 7 files changed, 45 insertions(+), 31 deletions(-) (limited to 'src/gtest') diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index d7bf2ab6..bdaebcea 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -331,7 +331,7 @@ TEST_F(basic_stl, simple_prog4) { EXPECT_TRUE(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, comp_obj.clone(), 20.0 ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 20.0 ); t1.m_msg = lpstart; @@ -401,7 +401,7 @@ TEST_F(basic_stl, simple_prog3) { EXPECT_TRUE(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, comp_obj.clone(), 50.0 ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 50.0 ); t1.m_msg = lpstart; @@ -463,7 +463,7 @@ TEST_F(basic_stl, simple_prog2) { EXPECT_TRUE(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, comp_obj.clone(), 10.0 ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10.0 ); t1.m_msg = lpstart; @@ -525,7 +525,7 @@ TEST_F(basic_stl, simple_prog1) { EXPECT_TRUE(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, comp_obj.clone(), 10.0 ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10.0 ); t1.m_msg = lpstart; @@ -570,7 +570,7 @@ TEST_F(basic_stl, single_pkt_burst1) { assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, comp_obj.clone(), 10.0 ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10.0 ); t1.m_msg = lpstart; @@ -621,7 +621,7 @@ TEST_F(basic_stl, single_pkt) { assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, comp_obj.clone(), 10.0 /*sec */ ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); t1.m_msg = lpstart; @@ -678,7 +678,7 @@ TEST_F(basic_stl, multi_pkt1) { assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, comp_obj.clone(), 10 ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10 ); t1.m_msg = lpstart; @@ -741,7 +741,7 @@ TEST_F(basic_stl, multi_pkt2) { assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, comp_obj.clone(), 10 ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10 ); t1.m_msg = lpstart; @@ -787,7 +787,7 @@ TEST_F(basic_stl, multi_burst1) { assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, comp_obj.clone(), 40 ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 40 ); t1.m_msg = lpstart; @@ -1099,7 +1099,7 @@ TEST_F(basic_stl, dp_stop_event) { assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(17, comp_obj.clone(), 10.0 /*sec */ ); + TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(port_id, 17, comp_obj.clone(), 10.0 /*sec */ ); t1.m_msg = lpstart; diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 795c0f12..fbc5f7c7 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -121,11 +121,11 @@ TrexStatelessPort::start_traffic(double mul, double duration) { } /* generate a message to all the relevant DP cores to start transmitting */ - m_event_id = m_dp_events.generate_event_id(); + int event_id = m_dp_events.generate_event_id(); /* mark that DP event of stoppped is possible */ - m_dp_events.wait_for_event(TrexDpPortEvent::EVENT_STOP, m_event_id); + m_dp_events.wait_for_event(TrexDpPortEvent::EVENT_STOP, event_id); - TrexStatelessCpToDpMsgBase *start_msg = new TrexStatelessDpStart(m_event_id, compiled_obj, duration); + TrexStatelessCpToDpMsgBase *start_msg = new TrexStatelessDpStart(m_port_id, event_id, compiled_obj, duration); change_state(PORT_STATE_TX); diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index da75284e..73157c15 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -258,11 +258,9 @@ private: std::string m_owner_handler; /* holds the DP cores associated with this port */ - //std::vector> m_cores_id_list; std::vector m_cores_id_list; TrexDpPortEvents m_dp_events; - int m_event_id; }; #endif /* __TREX_STATELESS_PORT_H__ */ diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index cde34a4b..6db66661 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -525,7 +525,7 @@ TrexStatelessDpCore::stop_traffic(uint8_t port_id) { TrexStatelessDpToCpMsgBase *event_msg = new TrexDpPortEventMsg(m_core->m_thread_id, port_id, TrexDpPortEvent::EVENT_STOP, - get_event_id()); + lp_port->get_event_id()); ring->Enqueue((CGenNode *)event_msg); } diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index 7ee5abc4..c0bbe702 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -66,6 +66,18 @@ public: bool update_number_of_active_streams(uint32_t d); + state_e get_state() { + return m_state; + } + + void set_event_id(int event_id) { + m_event_id = event_id; + } + + int get_event_id() { + return m_event_id; + } + public: state_e m_state; @@ -75,6 +87,7 @@ public: std::vector m_active_nodes; /* holds the current active nodes */ CFlowGenListPerThread * m_core ; + int m_event_id; }; /* for now */ @@ -166,19 +179,13 @@ public: /* quit the main loop, work in both stateless in stateful, don't free memory trigger from master */ void quit_main_loop(); - void set_event_id(int event_id) { - m_event_id = event_id; - } - - int get_event_id() { - return m_event_id; + state_e get_state() { + return m_state; } bool set_stateless_next_node(CGenNodeStateless * cur_node, CGenNodeStateless * next_node); -private: - TrexStatelessDpPerPort * get_port_db(uint8_t port_id){ assert((m_local_port_offset==port_id) ||(m_local_port_offset+1==port_id)); @@ -188,6 +195,9 @@ private: } + +private: + void schedule_exit(); @@ -236,7 +246,6 @@ private: CFlowGenListPerThread * m_core; double m_duration; - int m_event_id; }; #endif /* __TREX_STATELESS_DP_CORE_H__ */ diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp index c92ad68a..629fe24c 100644 --- a/src/stateless/messaging/trex_stateless_messaging.cpp +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -29,7 +29,8 @@ limitations under the License. /************************* start traffic message ************************/ -TrexStatelessDpStart::TrexStatelessDpStart(int event_id, TrexStreamsCompiledObj *obj, double duration) { +TrexStatelessDpStart::TrexStatelessDpStart(uint8_t port_id, int event_id, TrexStreamsCompiledObj *obj, double duration) { + m_port_id = port_id; m_event_id = event_id; m_obj = obj; m_duration = duration; @@ -45,7 +46,7 @@ TrexStatelessDpStart::clone() { TrexStreamsCompiledObj *new_obj = m_obj->clone(); - TrexStatelessCpToDpMsgBase *new_msg = new TrexStatelessDpStart(m_event_id, new_obj, m_duration); + TrexStatelessCpToDpMsgBase *new_msg = new TrexStatelessDpStart(m_port_id, m_event_id, new_obj, m_duration); return new_msg; } @@ -60,7 +61,7 @@ bool TrexStatelessDpStart::handle(TrexStatelessDpCore *dp_core) { /* mark the event id for DP response */ - dp_core->set_event_id(m_event_id); + dp_core->get_port_db(m_port_id)->set_event_id(m_event_id); /* staet traffic */ dp_core->start_traffic(m_obj, m_duration); @@ -73,6 +74,10 @@ TrexStatelessDpStart::handle(TrexStatelessDpCore *dp_core) { ************************/ bool TrexStatelessDpStop::handle(TrexStatelessDpCore *dp_core) { + if (dp_core->get_port_db(m_port_id)->get_state() == TrexStatelessDpPerPort::ppSTATE_IDLE) { + return true; + } + dp_core->stop_traffic(m_port_id); return true; } diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index ffb36124..2fb5a024 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -77,7 +77,7 @@ protected: class TrexStatelessDpStart : public TrexStatelessCpToDpMsgBase { public: - TrexStatelessDpStart(int m_event_id, TrexStreamsCompiledObj *obj, double duration); + TrexStatelessDpStart(uint8_t m_port_id, int m_event_id, TrexStreamsCompiledObj *obj, double duration); ~TrexStatelessDpStart(); @@ -87,9 +87,11 @@ public: private: - int m_event_id; + uint8_t m_port_id; + int m_event_id; TrexStreamsCompiledObj *m_obj; - double m_duration; + double m_duration; + }; /** -- cgit 1.2.3-korg From 36dc8ea51adffce882e542123111baad7a1a7ea7 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Sat, 21 Nov 2015 23:00:43 +0200 Subject: add back to back test of DP --- .gitignore | 4 + scripts/exp/stl_bb_start_stop-0-ex.erf | 0 scripts/exp/stl_bb_start_stop2-0-ex.erf | Bin 0 -> 968 bytes scripts/exp/stl_bb_start_stop3-0-ex.erf | 0 src/gtest/trex_stateless_gtest.cpp | 231 ++++++++++++++++++++- src/stateless/dp/trex_stateless_dp_core.cpp | 11 +- src/stateless/dp/trex_stateless_dp_core.h | 2 +- .../messaging/trex_stateless_messaging.cpp | 3 - 8 files changed, 242 insertions(+), 9 deletions(-) create mode 100644 scripts/exp/stl_bb_start_stop-0-ex.erf create mode 100644 scripts/exp/stl_bb_start_stop2-0-ex.erf create mode 100644 scripts/exp/stl_bb_start_stop3-0-ex.erf (limited to 'src/gtest') diff --git a/.gitignore b/.gitignore index fcc5135f..39bea09a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,10 @@ scripts/exp/stl_simple_prog1-0.erf scripts/exp/stl_simple_prog2-0.erf scripts/exp/stl_simple_prog3-0.erf scripts/exp/stl_simple_prog4-0.erf +scripts/exp/stl_bb_start_stop-0.erf +scripts/exp/stl_bb_start_stop2-0.erf +scripts/exp/stl_bb_start_stop3-0.erf + diff --git a/scripts/exp/stl_bb_start_stop-0-ex.erf b/scripts/exp/stl_bb_start_stop-0-ex.erf new file mode 100644 index 00000000..e69de29b diff --git a/scripts/exp/stl_bb_start_stop2-0-ex.erf b/scripts/exp/stl_bb_start_stop2-0-ex.erf new file mode 100644 index 00000000..0eff9601 Binary files /dev/null and b/scripts/exp/stl_bb_start_stop2-0-ex.erf differ diff --git a/scripts/exp/stl_bb_start_stop3-0-ex.erf b/scripts/exp/stl_bb_start_stop3-0-ex.erf new file mode 100644 index 00000000..e69de29b diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index bdaebcea..83721f0d 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -46,6 +46,54 @@ public: }; +/** + * Queue of RPC msgs for test + * + * @author hhaim + */ + +class CBasicStl; + + +struct CBasicStlDelayCommand { + + CBasicStlDelayCommand(){ + m_node=NULL; + } + CGenNodeCommand * m_node; +}; + + + +class CBasicStlMsgQueue { + +friend CBasicStl; + +public: + CBasicStlMsgQueue(){ + } + + /* user will allocate the message, no need to free it by this module */ + void add_msg(TrexStatelessCpToDpMsgBase * msg){ + m_msgs.push_back(msg); + } + void add_command(CBasicStlDelayCommand & command){ + m_commands.push_back(command); + } + + void clear(){ + m_msgs.clear(); + m_commands.clear(); + } + + +protected: + std::vector m_msgs; + + std::vector m_commands; +}; + + /** * handler for DP to CP messages * @@ -66,6 +114,7 @@ public: m_threads=1; m_dump_json=false; m_dp_to_cp_handler = NULL; + m_msg = NULL; } @@ -120,9 +169,22 @@ public: lpt->start_stateless_simulation_file(buf,CGlobalInfo::m_options.preview); /* add stream to the queue */ - assert(m_msg); + if ( m_msg ) { + assert(m_ring_from_cp->Enqueue((CGenNode *)m_msg)==0); + } + if (m_msg_queue.m_msgs.size()>0) { + for (auto msg : m_msg_queue.m_msgs) { + assert(m_ring_from_cp->Enqueue((CGenNode *)msg)==0); + } + } - assert(m_ring_from_cp->Enqueue((CGenNode *)m_msg)==0); + /* add the commands */ + if (m_msg_queue.m_commands.size()>0) { + for (auto cmd : m_msg_queue.m_commands) { + /* add commands nodes */ + lpt->m_node_gen.add_node((CGenNode *)cmd.m_node); + } + } lpt->start_stateless_daemon_simulation(); @@ -142,6 +204,8 @@ public: } flush_dp_to_cp_messages(); + m_msg_queue.clear(); + fl.Delete(); return (res); @@ -155,6 +219,7 @@ public: TrexStatelessCpToDpMsgBase * m_msg; CNodeRing *m_ring_from_cp; + CBasicStlMsgQueue m_msg_queue; CFlowGenList fl; }; @@ -264,6 +329,168 @@ TEST_F(basic_stl, load_pcap_file) { +/* start/stop/stop back to back */ +TEST_F(basic_stl, single_pkt_bb_start_stop3) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_bb_start_stop3"; + + TrexStreamsCompiler compile; + + uint8_t port_id=0; + + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream1->set_pps(1.0); + + + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_port_id= port_id; + + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + // stream - clean + + TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); + + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(port_id); + TrexStatelessDpStop * lpStopCmd1 = new TrexStatelessDpStop(port_id); + + + t1.m_msg_queue.add_msg(lpStartCmd); + t1.m_msg_queue.add_msg(lpStopCmd); + t1.m_msg_queue.add_msg(lpStopCmd1); + + bool res=t1.init(); + + delete stream1 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + +TEST_F(basic_stl, single_pkt_bb_start_stop2) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_bb_start_stop2"; + + TrexStreamsCompiler compile; + + uint8_t port_id=0; + + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream1->set_pps(1.0); + + + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_port_id= port_id; + + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + // stream - clean + + TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); + + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(port_id); + TrexStatelessDpStart * lpStartCmd1 = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + + + t1.m_msg_queue.add_msg(lpStartCmd); + t1.m_msg_queue.add_msg(lpStopCmd); + t1.m_msg_queue.add_msg(lpStartCmd1); + + bool res=t1.init(); + + delete stream1 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + + +/* back to back send start/stop */ +TEST_F(basic_stl, single_pkt_bb_start_stop) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_bb_start_stop"; + + TrexStreamsCompiler compile; + + uint8_t port_id=0; + + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream1->set_pps(1.0); + + + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_port_id= port_id; + + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + // stream - clean + + TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); + + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(port_id); + + + t1.m_msg_queue.add_msg(lpStartCmd); + t1.m_msg_queue.add_msg(lpStopCmd); + + bool res=t1.init(); + + delete stream1 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + + + TEST_F(basic_stl, simple_prog4) { CBasicStl t1; diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index e17c9075..6430e520 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -124,12 +124,12 @@ bool TrexStatelessDpPerPort::update_number_of_active_streams(uint32_t d){ } -void TrexStatelessDpPerPort::stop_traffic(uint8_t port_id){ +bool TrexStatelessDpPerPort::stop_traffic(uint8_t port_id){ /* there could be race of stop after stop */ if (m_state == TrexStatelessDpPerPort::ppSTATE_IDLE) { assert(m_active_streams==0); - return; + return false; } for (auto dp_stream : m_active_nodes) { @@ -149,6 +149,7 @@ void TrexStatelessDpPerPort::stop_traffic(uint8_t port_id){ assert(m_active_streams==0); m_active_nodes.clear(); m_state=TrexStatelessDpPerPort::ppSTATE_IDLE; + return (true); } @@ -517,7 +518,11 @@ TrexStatelessDpCore::stop_traffic(uint8_t port_id) { TrexStatelessDpPerPort * lp_port = get_port_db(port_id); - lp_port->stop_traffic(port_id); + if ( lp_port->stop_traffic(port_id) == false){ + /* nothing to do ! already stopped */ + return; + } + if ( are_all_ports_idle() ) { diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index c0bbe702..326bbe30 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -62,7 +62,7 @@ public: void create(CFlowGenListPerThread * core); - void stop_traffic(uint8_t port_id); + bool stop_traffic(uint8_t port_id); bool update_number_of_active_streams(uint32_t d); diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp index 629fe24c..c861d0fa 100644 --- a/src/stateless/messaging/trex_stateless_messaging.cpp +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -74,9 +74,6 @@ TrexStatelessDpStart::handle(TrexStatelessDpCore *dp_core) { ************************/ bool TrexStatelessDpStop::handle(TrexStatelessDpCore *dp_core) { - if (dp_core->get_port_db(m_port_id)->get_state() == TrexStatelessDpPerPort::ppSTATE_IDLE) { - return true; - } dp_core->stop_traffic(m_port_id); return true; -- cgit 1.2.3-korg From 3408c03067a85789b2128352fdc2343ab707ae32 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Sun, 22 Nov 2015 13:02:08 +0200 Subject: fix stop on duration per port --- .gitignore | 2 + scripts/exp/stl_bb_start_stop_delay1-0-ex.erf | Bin 0 -> 440 bytes scripts/exp/stl_bb_start_stop_delay2-0-ex.erf | Bin 0 -> 1496 bytes src/bp_sim.cpp | 5 +- src/bp_sim.h | 1 + src/gtest/trex_stateless_gtest.cpp | 253 +++++++++++++++++++++ src/stateless/dp/trex_stateless_dp_core.cpp | 56 +++-- src/stateless/dp/trex_stateless_dp_core.h | 13 +- src/stateless/dp/trex_stream_node.h | 1 + .../messaging/trex_stateless_messaging.cpp | 25 +- src/stateless/messaging/trex_stateless_messaging.h | 41 ++++ 11 files changed, 368 insertions(+), 29 deletions(-) create mode 100644 scripts/exp/stl_bb_start_stop_delay1-0-ex.erf create mode 100644 scripts/exp/stl_bb_start_stop_delay2-0-ex.erf (limited to 'src/gtest') diff --git a/.gitignore b/.gitignore index 39bea09a..839008be 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ scripts/exp/stl_simple_prog4-0.erf scripts/exp/stl_bb_start_stop-0.erf scripts/exp/stl_bb_start_stop2-0.erf scripts/exp/stl_bb_start_stop3-0.erf +scripts/exp/stl_bb_start_stop_delay1-0.erf +scripts/exp/stl_bb_start_stop_delay2-0.erf diff --git a/scripts/exp/stl_bb_start_stop_delay1-0-ex.erf b/scripts/exp/stl_bb_start_stop_delay1-0-ex.erf new file mode 100644 index 00000000..08afdf4b Binary files /dev/null and b/scripts/exp/stl_bb_start_stop_delay1-0-ex.erf differ diff --git a/scripts/exp/stl_bb_start_stop_delay2-0-ex.erf b/scripts/exp/stl_bb_start_stop_delay2-0-ex.erf new file mode 100644 index 00000000..01a77466 Binary files /dev/null and b/scripts/exp/stl_bb_start_stop_delay2-0-ex.erf differ diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index f8dd20a1..a61fbb8f 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -3186,6 +3186,7 @@ bool CFlowGenListPerThread::Create(uint32_t thread_id, uint32_t max_threads){ + m_non_active_nodes = 0; m_terminated_by_master=false; m_flow_list =flow_list; m_core_id= core_id; @@ -3655,8 +3656,8 @@ CNodeGenerator::handle_slow_messages(uint8_t type, thread->check_msgs(); /* check messages */ m_v_if->flush_tx_queue(); /* flush pkt each timeout */ - /* on always (clean queue path) and queue empty - exit */ - if ( always && (m_p_queue.empty()) ) { + /* exit in case this is the last node*/ + if ( m_p_queue.size() == m_parent->m_non_active_nodes ) { thread->free_node(node); exit_scheduler = true; } else { diff --git a/src/bp_sim.h b/src/bp_sim.h index fcca2428..0da7fb99 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -3541,6 +3541,7 @@ public: CNodeGenerator m_node_gen; public: uint32_t m_cur_template; + uint32_t m_non_active_nodes; /* the number of non active nodes -> nodes that try to stop somthing */ uint64_t m_cur_flow_id; double m_cur_time_sec; double m_stop_time_sec; diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 83721f0d..5bb7fca1 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -77,10 +77,32 @@ public: void add_msg(TrexStatelessCpToDpMsgBase * msg){ m_msgs.push_back(msg); } + void add_command(CBasicStlDelayCommand & command){ m_commands.push_back(command); } + /* only if both port are idle we can exit */ + void add_command(CFlowGenListPerThread * core, + TrexStatelessCpToDpMsgBase * msg, + double time){ + + CGenNodeCommand *node = (CGenNodeCommand *)core->create_node() ; + + node->m_type = CGenNode::COMMAND; + + node->m_cmd = msg; + + /* make sure it will be scheduled after the current node */ + node->m_time = time ; + + CBasicStlDelayCommand command; + command.m_node =node; + + add_command(command); + } + + void clear(){ m_msgs.clear(); m_commands.clear(); @@ -94,6 +116,20 @@ protected: }; + +class CBasicStlSink { + +public: + CBasicStlSink(){ + m_core=0; + } + virtual void call_after_init(CBasicStl * m_obj)=0; + virtual void call_after_run(CBasicStl * m_obj)=0; + + CFlowGenListPerThread * m_core; +}; + + /** * handler for DP to CP messages * @@ -115,6 +151,7 @@ public: m_dump_json=false; m_dp_to_cp_handler = NULL; m_msg = NULL; + m_sink = NULL; } @@ -161,6 +198,10 @@ public: lpt=fl.m_threads_info[0]; + if ( m_sink ){ + m_sink->m_core =lpt; + } + char buf[100]; char buf_ex[100]; sprintf(buf,"%s-%d.erf",CGlobalInfo::m_options.out_file.c_str(),0); @@ -178,6 +219,10 @@ public: } } + if (m_sink) { + m_sink->call_after_init(this); + } + /* add the commands */ if (m_msg_queue.m_commands.size()>0) { for (auto cmd : m_msg_queue.m_commands) { @@ -203,6 +248,10 @@ public: printf(" %s \n",s.c_str()); } + if (m_sink) { + m_sink->call_after_run(this); + } + flush_dp_to_cp_messages(); m_msg_queue.clear(); @@ -216,6 +265,7 @@ public: double m_time_diff; bool m_dump_json; DpToCpHandler *m_dp_to_cp_handler; + CBasicStlSink * m_sink; TrexStatelessCpToDpMsgBase * m_msg; CNodeRing *m_ring_from_cp; @@ -329,6 +379,209 @@ TEST_F(basic_stl, load_pcap_file) { + + + + + + + +class CBBStartStopDelay2: public CBasicStlSink { +public: + + virtual void call_after_init(CBasicStl * m_obj); + virtual void call_after_run(CBasicStl * m_obj){ + }; + uint8_t m_port_id; +}; + + + +void CBBStartStopDelay2::call_after_init(CBasicStl * m_obj){ + + TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(m_port_id); + TrexStatelessDpStop * lpStopCmd1 = new TrexStatelessDpStop(m_port_id); + + + TrexStreamsCompiler compile; + + uint8_t port_id=0; + + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream1->set_pps(1.0); + + + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_port_id= port_id; + + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000002); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + // stream - clean + + TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); + + assert(compile.compile(streams, comp_obj) ); + + + /* start with different event id */ + TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(m_port_id, 1, comp_obj.clone(), 10.0 /*sec */ ); + + + m_obj->m_msg_queue.add_command(m_core,lpStopCmd, 5.0); /* command in delay of 5 sec */ + m_obj->m_msg_queue.add_command(m_core,lpStopCmd1, 7.0);/* command in delay of 7 sec */ + m_obj->m_msg_queue.add_command(m_core,lpStartCmd, 7.5);/* command in delay of 7 sec */ + + delete stream1 ; + + +} + + + +/* start/stop/stop back to back */ +TEST_F(basic_stl, single_pkt_bb_start_stop_delay2) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_bb_start_stop_delay2"; + + TrexStreamsCompiler compile; + + uint8_t port_id=0; + + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream1->set_pps(1.0); + + + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_port_id= port_id; + + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + // stream - clean + + TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); + + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + + t1.m_msg_queue.add_msg(lpStartCmd); + + + CBBStartStopDelay2 sink; + sink.m_port_id = port_id; + t1.m_sink = &sink; + + bool res=t1.init(); + + delete stream1 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + + + + + + +class CBBStartStopDelay1: public CBasicStlSink { +public: + + virtual void call_after_init(CBasicStl * m_obj); + virtual void call_after_run(CBasicStl * m_obj){ + }; + uint8_t m_port_id; +}; + + + +void CBBStartStopDelay1::call_after_init(CBasicStl * m_obj){ + + TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(m_port_id); + TrexStatelessDpStop * lpStopCmd1 = new TrexStatelessDpStop(m_port_id); + + m_obj->m_msg_queue.add_command(m_core,lpStopCmd, 5.0); /* command in delay of 5 sec */ + m_obj->m_msg_queue.add_command(m_core,lpStopCmd1, 7.0);/* command in delay of 7 sec */ +} + + + +/* start/stop/stop back to back */ +TEST_F(basic_stl, single_pkt_bb_start_stop_delay1) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_bb_start_stop_delay1"; + + TrexStreamsCompiler compile; + + uint8_t port_id=0; + + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream1->set_pps(1.0); + + + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_port_id= port_id; + + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + // stream - clean + + TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); + + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + + t1.m_msg_queue.add_msg(lpStartCmd); + + + CBBStartStopDelay1 sink; + sink.m_port_id = port_id; + t1.m_sink = &sink; + + bool res=t1.init(); + + delete stream1 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} + + /* start/stop/stop back to back */ TEST_F(basic_stl, single_pkt_bb_start_stop3) { diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 6430e520..f8afb3bb 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -78,9 +78,10 @@ void CGenNodeStateless::refresh(){ } - void CGenNodeCommand::free_command(){ + assert(m_cmd); + m_cmd->on_node_remove(); delete m_cmd; } @@ -124,14 +125,23 @@ bool TrexStatelessDpPerPort::update_number_of_active_streams(uint32_t d){ } -bool TrexStatelessDpPerPort::stop_traffic(uint8_t port_id){ +bool TrexStatelessDpPerPort::stop_traffic(uint8_t port_id, + bool stop_on_id, + int event_id){ - /* there could be race of stop after stop */ if (m_state == TrexStatelessDpPerPort::ppSTATE_IDLE) { assert(m_active_streams==0); return false; } + /* there could be race of stop after stop */ + if ( stop_on_id ) { + if (event_id != m_event_id){ + /* we can't stop it is an old message */ + return false; + } + } + for (auto dp_stream : m_active_nodes) { CGenNodeStateless * node =dp_stream.m_node; assert(node->get_port_id() == port_id); @@ -215,7 +225,7 @@ bool TrexStatelessDpCore::set_stateless_next_node(CGenNodeStateless * cur_node, if ( to_stop_port ) { /* call stop port explictly to move the state */ - stop_traffic(cur_node->m_port_id); + stop_traffic(cur_node->m_port_id,false,0); } return ( schedule ); @@ -330,7 +340,8 @@ TrexStatelessDpCore::add_global_duration(double duration){ /* add per port exit */ void TrexStatelessDpCore::add_port_duration(double duration, - uint8_t port_id){ + uint8_t port_id, + int event_id){ if (duration > 0.0) { CGenNodeCommand *node = (CGenNodeCommand *)m_core->create_node() ; @@ -339,7 +350,16 @@ TrexStatelessDpCore::add_port_duration(double duration, /* make sure it will be scheduled after the current node */ node->m_time = m_core->m_cur_time_sec + duration ; - node->m_cmd = new TrexStatelessDpStop(port_id); + TrexStatelessDpStop * cmd=new TrexStatelessDpStop(port_id); + + + /* test this */ + m_core->m_non_active_nodes++; + cmd->set_core_ptr(m_core); + cmd->set_event_id(event_id); + cmd->set_wait_for_event_id(true); + + node->m_cmd = cmd; m_core->m_node_gen.add_node((CGenNode *)node); } @@ -450,15 +470,14 @@ TrexStatelessDpCore::add_cont_stream(TrexStatelessDpPerPort * lp_port, void TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj, - double duration) { + double duration, + int event_id) { -#if 0 - /* TBD to remove ! */ - obj->Dump(stdout); -#endif TrexStatelessDpPerPort * lp_port=get_port_db(obj->get_port_id()); lp_port->m_active_streams = 0; + lp_port->set_event_id(event_id); + /* no nodes in the list */ assert(lp_port->m_active_nodes.size()==0); @@ -491,7 +510,7 @@ TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj, if ( duration > 0.0 ){ - add_port_duration( duration ,obj->get_port_id() ); + add_port_duration( duration ,obj->get_port_id(),event_id ); } } @@ -511,23 +530,26 @@ bool TrexStatelessDpCore::are_all_ports_idle(){ void -TrexStatelessDpCore::stop_traffic(uint8_t port_id) { +TrexStatelessDpCore::stop_traffic(uint8_t port_id, + bool stop_on_id, + int event_id) { /* we cannot remove nodes not from the top of the queue so for every active node - make sure next time the scheduler invokes it, it will be free */ TrexStatelessDpPerPort * lp_port = get_port_db(port_id); - if ( lp_port->stop_traffic(port_id) == false){ + if ( lp_port->stop_traffic(port_id,stop_on_id,event_id) == false){ /* nothing to do ! already stopped */ + //printf(" skip .. %f\n",m_core->m_cur_time_sec); return; } - +#if 0 if ( are_all_ports_idle() ) { - - schedule_exit(); + /* just a place holder if we will need to do somthing in that case */ } +#endif /* inform the control plane we stopped - this might be a async stop (streams ended) diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index 326bbe30..187c40d8 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -62,7 +62,9 @@ public: void create(CFlowGenListPerThread * core); - bool stop_traffic(uint8_t port_id); + bool stop_traffic(uint8_t port_id, + bool stop_on_id, + int event_id); bool update_number_of_active_streams(uint32_t d); @@ -137,13 +139,15 @@ public: * @param pkt * @param pkt_len */ - void start_traffic(TrexStreamsCompiledObj *obj, double duration = -1); + void start_traffic(TrexStreamsCompiledObj *obj, + double duration, + int m_event_id); /** * stop all traffic for this core * */ - void stop_traffic(uint8_t port_id); + void stop_traffic(uint8_t port_id,bool stop_on_id, int event_id); /* return if all ports are idel */ @@ -225,7 +229,8 @@ private: void add_port_duration(double duration, - uint8_t port_id); + uint8_t port_id, + int event_id); void add_global_duration(double duration); diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index 1e53887b..20e32b78 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -29,6 +29,7 @@ class TrexStatelessDpCore; #include class TrexStatelessCpToDpMsgBase; +class CFlowGenListPerThread; struct CGenNodeCommand : public CGenNodeBase { diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp index c861d0fa..bbd4b68c 100644 --- a/src/stateless/messaging/trex_stateless_messaging.cpp +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -23,6 +23,7 @@ limitations under the License. #include #include #include +#include #include @@ -60,11 +61,8 @@ TrexStatelessDpStart::~TrexStatelessDpStart() { bool TrexStatelessDpStart::handle(TrexStatelessDpCore *dp_core) { - /* mark the event id for DP response */ - dp_core->get_port_db(m_port_id)->set_event_id(m_event_id); - /* staet traffic */ - dp_core->start_traffic(m_obj, m_duration); + dp_core->start_traffic(m_obj, m_duration,m_event_id); return true; } @@ -75,17 +73,32 @@ TrexStatelessDpStart::handle(TrexStatelessDpCore *dp_core) { bool TrexStatelessDpStop::handle(TrexStatelessDpCore *dp_core) { - dp_core->stop_traffic(m_port_id); + + dp_core->stop_traffic(m_port_id,m_stop_only_for_event_id,m_event_id); return true; } + +void TrexStatelessDpStop::on_node_remove(){ + if ( m_core ) { + assert(m_core->m_non_active_nodes>0); + m_core->m_non_active_nodes--; + } +} + + /** * clone for DP stop message * */ TrexStatelessCpToDpMsgBase * TrexStatelessDpStop::clone() { - TrexStatelessCpToDpMsgBase *new_msg = new TrexStatelessDpStop(m_port_id); + TrexStatelessDpStop *new_msg = new TrexStatelessDpStop(m_port_id); + + new_msg->set_event_id(m_event_id); + new_msg->set_wait_for_event_id(m_stop_only_for_event_id); + /* set back pointer to master */ + new_msg->set_core_ptr(m_core); return new_msg; } diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index 2fb5a024..afa5953a 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -27,6 +27,7 @@ limitations under the License. class TrexStatelessDpCore; class TrexStreamsCompiledObj; +class CFlowGenListPerThread; /** * defines the base class for CP to DP messages @@ -61,6 +62,10 @@ public: return ( m_quit_scheduler); } + /* this node is called from scheduler in case the node is free */ + virtual void on_node_remove(){ + } + /* no copy constructor */ TrexStatelessCpToDpMsgBase(TrexStatelessCpToDpMsgBase &) = delete; @@ -103,14 +108,50 @@ class TrexStatelessDpStop : public TrexStatelessCpToDpMsgBase { public: TrexStatelessDpStop(uint8_t port_id) : m_port_id(port_id) { + m_stop_only_for_event_id=false; + m_event_id=0; + m_core = NULL; } virtual TrexStatelessCpToDpMsgBase * clone(); + virtual bool handle(TrexStatelessDpCore *dp_core); + void set_core_ptr(CFlowGenListPerThread * core){ + m_core = core; + } + + CFlowGenListPerThread * get_core_ptr(){ + return ( m_core); + } + + + void set_event_id(int event_id){ + m_event_id = event_id; + } + + void set_wait_for_event_id(bool wait){ + m_stop_only_for_event_id = wait; + } + + virtual void on_node_remove(); + + + bool get_is_stop_by_event_id(){ + return (m_stop_only_for_event_id); + } + + int get_event_id(){ + return (m_event_id); + } + private: uint8_t m_port_id; + bool m_stop_only_for_event_id; + int m_event_id; + CFlowGenListPerThread * m_core ; + }; /** -- cgit 1.2.3-korg From bd8b640077591377375f2ab5ec6c542119ead0a2 Mon Sep 17 00:00:00 2001 From: Hanoh Haim Date: Sun, 22 Nov 2015 18:02:22 +0200 Subject: dp support for pause/resume only continues is supported --- .gitignore | 1 + scripts/exp/stl_basic_pause_resume0-0-ex.erf | Bin 0 -> 704 bytes src/gtest/trex_stateless_gtest.cpp | 73 +++++++++++++++++++++ src/stateless/dp/trex_stateless_dp_core.cpp | 52 +++++++++++++++ src/stateless/dp/trex_stateless_dp_core.h | 18 ++++- src/stateless/dp/trex_stream_node.h | 19 +++++- .../messaging/trex_stateless_messaging.cpp | 25 +++++++ src/stateless/messaging/trex_stateless_messaging.h | 36 ++++++++++ 8 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 scripts/exp/stl_basic_pause_resume0-0-ex.erf (limited to 'src/gtest') diff --git a/.gitignore b/.gitignore index 839008be..cfe53466 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ scripts/exp/stl_bb_start_stop2-0.erf scripts/exp/stl_bb_start_stop3-0.erf scripts/exp/stl_bb_start_stop_delay1-0.erf scripts/exp/stl_bb_start_stop_delay2-0.erf +scripts/exp/stl_basic_pause_resume0-0.erf diff --git a/scripts/exp/stl_basic_pause_resume0-0-ex.erf b/scripts/exp/stl_basic_pause_resume0-0-ex.erf new file mode 100644 index 00000000..7f833920 Binary files /dev/null and b/scripts/exp/stl_basic_pause_resume0-0-ex.erf differ diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 5bb7fca1..8640e7db 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -379,11 +379,84 @@ TEST_F(basic_stl, load_pcap_file) { +class CBBStartPause0: public CBasicStlSink { +public: + + virtual void call_after_init(CBasicStl * m_obj); + virtual void call_after_run(CBasicStl * m_obj){ + }; + uint8_t m_port_id; +}; + + + +void CBBStartPause0::call_after_init(CBasicStl * m_obj){ + + TrexStatelessDpPause * lpPauseCmd = new TrexStatelessDpPause(m_port_id); + TrexStatelessDpResume * lpResumeCmd1 = new TrexStatelessDpResume(m_port_id); + + m_obj->m_msg_queue.add_command(m_core,lpPauseCmd, 5.0); /* command in delay of 5 sec */ + m_obj->m_msg_queue.add_command(m_core,lpResumeCmd1, 7.0);/* command in delay of 7 sec */ + +} + + +/* start/stop/stop back to back */ +TEST_F(basic_stl, basic_pause_resume0) { + + CBasicStl t1; + CParserOption * po =&CGlobalInfo::m_options; + po->preview.setVMode(7); + po->preview.setFileWrite(true); + po->out_file ="exp/stl_basic_pause_resume0"; + + TrexStreamsCompiler compile; + uint8_t port_id=0; + + std::vector streams; + + TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0); + stream1->set_pps(1.0); + + stream1->m_enabled = true; + stream1->m_self_start = true; + stream1->m_port_id= port_id; + + + CPcapLoader pcap; + pcap.load_pcap_file("cap2/udp_64B.pcap",0); + pcap.update_ip_src(0x10000001); + pcap.clone_packet_into_stream(stream1); + + streams.push_back(stream1); + + // stream - clean + + TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); + + assert(compile.compile(streams, comp_obj) ); + + TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + + t1.m_msg_queue.add_msg(lpStartCmd); + + + CBBStartPause0 sink; + sink.m_port_id = port_id; + t1.m_sink = &sink; + + bool res=t1.init(); + + delete stream1 ; + + EXPECT_EQ_UINT32(1, res?1:0)<< "pass"; +} +////////////////////////////////////////////////////////////// class CBBStartStopDelay2: public CBasicStlSink { diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index f8afb3bb..03b13d6c 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -124,6 +124,37 @@ bool TrexStatelessDpPerPort::update_number_of_active_streams(uint32_t d){ return (false); } +bool TrexStatelessDpPerPort::resume_traffic(uint8_t port_id){ + + /* we are working with continues streams so we must be in transmit mode */ + assert(m_state == TrexStatelessDpPerPort::ppSTATE_PAUSE); + + for (auto dp_stream : m_active_nodes) { + CGenNodeStateless * node =dp_stream.m_node; + assert(node->get_port_id() == port_id); + assert(node->is_pause() == true); + node->set_pause(false); + } + m_state = TrexStatelessDpPerPort::ppSTATE_TRANSMITTING; + return (true); +} + + +bool TrexStatelessDpPerPort::pause_traffic(uint8_t port_id){ + + /* we are working with continues streams so we must be in transmit mode */ + assert(m_state == TrexStatelessDpPerPort::ppSTATE_TRANSMITTING); + + for (auto dp_stream : m_active_nodes) { + CGenNodeStateless * node =dp_stream.m_node; + assert(node->get_port_id() == port_id); + assert(node->is_pause() == false); + node->set_pause(true); + } + m_state = TrexStatelessDpPerPort::ppSTATE_PAUSE; + return (true); +} + bool TrexStatelessDpPerPort::stop_traffic(uint8_t port_id, bool stop_on_id, @@ -294,6 +325,8 @@ TrexStatelessDpCore::run_once(){ } + + void TrexStatelessDpCore::start() { @@ -402,6 +435,7 @@ TrexStatelessDpCore::add_cont_stream(TrexStatelessDpPerPort * lp_port, uint16_t pkt_size = stream->m_pkt.len; const uint8_t *stream_pkt = stream->m_pkt.binary; + node->m_pause =0; node->m_stream_type = stream->m_type; node->m_next_time_offset = 1.0 / (stream->get_pps() * comp->get_multiplier()) ; @@ -529,6 +563,24 @@ bool TrexStatelessDpCore::are_all_ports_idle(){ } +void +TrexStatelessDpCore::resume_traffic(uint8_t port_id){ + + TrexStatelessDpPerPort * lp_port = get_port_db(port_id); + + lp_port->resume_traffic(port_id); +} + + +void +TrexStatelessDpCore::pause_traffic(uint8_t port_id){ + + TrexStatelessDpPerPort * lp_port = get_port_db(port_id); + + lp_port->pause_traffic(port_id); +} + + void TrexStatelessDpCore::stop_traffic(uint8_t port_id, bool stop_on_id, diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index 187c40d8..eda1ae59 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -53,7 +53,9 @@ public: /* states */ enum state_e { ppSTATE_IDLE, - ppSTATE_TRANSMITTING + ppSTATE_TRANSMITTING, + ppSTATE_PAUSE + }; public: @@ -62,6 +64,10 @@ public: void create(CFlowGenListPerThread * core); + bool pause_traffic(uint8_t port_id); + + bool resume_traffic(uint8_t port_id); + bool stop_traffic(uint8_t port_id, bool stop_on_id, int event_id); @@ -143,7 +149,17 @@ public: double duration, int m_event_id); + + /* pause the streams, work only if all are continues */ + void pause_traffic(uint8_t port_id); + + + + void resume_traffic(uint8_t port_id); + + /** + * * stop all traffic for this core * */ diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index 20e32b78..ccf99eaa 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -48,6 +48,7 @@ public: static_assert(sizeof(CGenNodeCommand) == sizeof(CGenNode), "sizeof(CGenNodeCommand) != sizeof(CGenNode)" ); + /* this is a event for stateless */ struct CGenNodeStateless : public CGenNodeBase { friend class TrexStatelessDpCore; @@ -74,7 +75,7 @@ private: stream_state_t m_state; uint8_t m_port_id; uint8_t m_stream_type; /* see TrexStream::STREAM_TYPE ,stream_type_t */ - uint8_t m_pad; + uint8_t m_pause; uint32_t m_single_burst; /* the number of bursts in case of burst */ uint32_t m_single_burst_refill; @@ -112,7 +113,18 @@ public: /* only to be safe */ m_ref_stream_info= NULL; m_next_stream= NULL; + } + bool is_pause(){ + return (m_pause==1?true:false); + } + + void set_pause(bool enable){ + if ( enable ){ + m_pause=1; + }else{ + m_pause=0; + } } inline uint8_t get_stream_type(){ @@ -143,7 +155,10 @@ public: void refresh(); inline void handle_continues(CFlowGenListPerThread *thread) { - thread->m_node_gen.m_v_if->send_node( (CGenNode *)this); + + if (unlikely (is_pause()==false)) { + thread->m_node_gen.m_v_if->send_node( (CGenNode *)this); + } /* in case of continues */ m_time += m_next_time_offset; diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp index bbd4b68c..ec8b7839 100644 --- a/src/stateless/messaging/trex_stateless_messaging.cpp +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -87,6 +87,31 @@ void TrexStatelessDpStop::on_node_remove(){ } +TrexStatelessCpToDpMsgBase * TrexStatelessDpPause::clone(){ + + TrexStatelessDpPause *new_msg = new TrexStatelessDpPause(m_port_id); + return new_msg; +} + + +bool TrexStatelessDpPause::handle(TrexStatelessDpCore *dp_core){ + dp_core->pause_traffic(m_port_id); + return (true); +} + + + +TrexStatelessCpToDpMsgBase * TrexStatelessDpResume::clone(){ + TrexStatelessDpResume *new_msg = new TrexStatelessDpResume(m_port_id); + return new_msg; +} + +bool TrexStatelessDpResume::handle(TrexStatelessDpCore *dp_core){ + dp_core->resume_traffic(m_port_id); + return (true); +} + + /** * clone for DP stop message * diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index afa5953a..6bd0dbe3 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -99,6 +99,42 @@ private: }; +class TrexStatelessDpPause : public TrexStatelessCpToDpMsgBase { +public: + + TrexStatelessDpPause(uint8_t port_id) : m_port_id(port_id) { + } + + + virtual TrexStatelessCpToDpMsgBase * clone(); + + + virtual bool handle(TrexStatelessDpCore *dp_core); + + +private: + uint8_t m_port_id; +}; + + +class TrexStatelessDpResume : public TrexStatelessCpToDpMsgBase { +public: + + TrexStatelessDpResume(uint8_t port_id) : m_port_id(port_id) { + } + + + virtual TrexStatelessCpToDpMsgBase * clone(); + + + virtual bool handle(TrexStatelessDpCore *dp_core); + + +private: + uint8_t m_port_id; +}; + + /** * a message to stop traffic * -- cgit 1.2.3-korg From 1f6977d1e109acba69f1bf2230d6b9f5e4aae54e Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 23 Nov 2015 18:02:14 +0200 Subject: add stream graph + support for console to use any of the following bps, kbps, mbps, gbps, pps, kpps, mbps percentage is not working yet --- .../trex_control_plane/console/parsing_opts.py | 64 +++++-- src/gtest/trex_stateless_gtest.cpp | 53 ++++++ src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 24 ++- src/stateless/cp/trex_stateless_port.cpp | 33 +++- src/stateless/cp/trex_stateless_port.h | 2 + src/stateless/cp/trex_stream.cpp | 2 + src/stateless/cp/trex_stream.h | 11 +- src/stateless/cp/trex_streams_compiler.cpp | 186 ++++++++++++++++++++- src/stateless/cp/trex_streams_compiler.h | 80 +++++++++ 9 files changed, 431 insertions(+), 24 deletions(-) (limited to 'src/gtest') diff --git a/scripts/automation/trex_control_plane/console/parsing_opts.py b/scripts/automation/trex_control_plane/console/parsing_opts.py index d5c21af0..732ba764 100755 --- a/scripts/automation/trex_control_plane/console/parsing_opts.py +++ b/scripts/automation/trex_control_plane/console/parsing_opts.py @@ -44,22 +44,60 @@ def match_time_unit(val): def match_multiplier(val): '''match some val against multiplier shortcut inputs ''' - match = re.match("^(\d+)(gb|kpps|%?)$", val) + + match = re.match("^(\d+(\.\d+)?)(bps|kbps|mbps|gbps|pps|kpps|mbps|%?)$", val) + + result = {} + if match: - digit = int(match.group(1)) - unit = match.group(2) + + value = float(match.group(1)) + unit = match.group(3) + + # raw type (factor) if not unit: - return digit - elif unit == 'gb': - raise NotImplementedError("gb units are not supported yet") - else: - raise NotImplementedError("kpps units are not supported yet") + result['type'] = 'raw' + result['factor'] = value + + elif unit == 'bps': + result['type'] = 'max_bps' + result['max'] = value + + elif unit == 'kbps': + result['type'] = 'max_bps' + result['max'] = value * 1000 + + elif unit == 'mbps': + result['type'] = 'max_bps' + result['max'] = value * 1000 * 1000 + + elif unit == 'gbps': + result['type'] = 'max_bps' + result['max'] = value * 1000 * 1000 * 1000 + + elif unit == 'pps': + result['type'] = 'max_pps' + result['max'] = value + + elif unit == "kpps": + result['type'] = 'max_pps' + result['max'] = value * 1000 + + elif unit == "mpps": + result['type'] = 'max_pps' + result['max'] = value * 1000 * 1000 + + elif unit == "%": + raise argparse.ArgumentTypeError("percetange is currently unsupported...") + + return result + else: - raise argparse.ArgumentTypeError("Multiplier should be passed in the following format: \n" - "-m 100 : multiply stream file by this factor \n" - "-m 10gb : from graph calculate the maximum rate as this bandwidth (for each port)\n" - "-m 10kpps : from graph calculate the maximum rate as this pps (for each port)\n" - "-m 40% : from graph calculate the maximum rate as this percent from total port (for each port)") + raise argparse.ArgumentTypeError("\n\nMultiplier should be passed in the following format: \n\n" + "-m 100 : multiply by factor \n" + "-m 1bps / 1kbps / 1mbps / 1gbps : normalize to bps \n" + "-m 1pps / 1kpps / 1mbps : normalize to pps \n" + "-m 40% : normalize to % from port line rate\n") diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 83721f0d..3aad2d41 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -1342,5 +1342,58 @@ TEST_F(basic_stl, dp_stop_event) { } +TEST_F(basic_stl, graph_generator) { + std::vector streams; + TrexStreamsGraph graph; + TrexStream *stream; + + /* stream 1 */ + stream = new TrexStream(TrexStream::stSINGLE_BURST, 0, 1); + stream->m_enabled = true; + stream->m_self_start = true; + + stream->m_isg_usec = 42; + stream->set_pps(10); + stream->set_single_burst(43281); + stream->m_pkt.len = 512; + + stream->m_next_stream_id = 2; + + + streams.push_back(stream); + + /* stream 2 */ + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 2); + stream->m_enabled = true; + stream->m_self_start = false; + + stream->set_pps(20); + stream->set_multi_burst(4918, 13, 7); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 64; + + streams.push_back(stream); + + /* stream 3 */ + stream = new TrexStream(TrexStream::stCONTINUOUS, 0, 3); + stream->m_enabled = true; + stream->m_self_start = true; + + stream->m_isg_usec = 50; + stream->set_pps(30); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 1512; + + streams.push_back(stream); + + + const TrexStreamsGraphObj &obj = graph.generate(streams); + EXPECT_TRUE(obj.get_max_bps() == 403840.0); + EXPECT_TRUE(obj.get_max_pps() == 50.0); + + for (auto stream : streams) { + delete stream; + } +} /********************************************* Itay Tests End *************************************/ diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index cdd13ed6..d22fda7d 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -463,7 +463,6 @@ trex_rpc_cmd_rc_e TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { uint8_t port_id = parse_byte(params, "port_id", result); - double mul = parse_double(params, "mul", result); double duration = parse_double(params, "duration", result); if (port_id >= get_stateless_obj()->get_port_count()) { @@ -474,8 +473,29 @@ TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); + + const Json::Value &mul = parse_object(params, "mul", result); + std::string mul_type = parse_string(mul, "type", result); + + /* dispatch according to type of multiplier */ + try { - port->start_traffic(mul, duration); + if (mul_type == "raw") { + + double m = parse_double(mul, "factor", result); + port->start_traffic(m, duration); + + } else if (mul_type == "max_bps") { + + double max_bps = parse_double(mul, "max", result); + port->start_traffic_max_bps(max_bps, duration); + + } else if (mul_type == "max_pps") { + + double max_pps = parse_double(mul, "max", result); + port->start_traffic_max_pps(max_pps, duration); + } + } catch (const TrexRpcException &ex) { generate_execute_err(result, ex.what()); } diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index fbc5f7c7..7dc217a3 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -111,9 +111,12 @@ TrexStatelessPort::start_traffic(double mul, double duration) { vector streams; get_object_list(streams); + /* split it per core */ + double per_core_mul = mul / m_cores_id_list.size(); + /* compiler it */ TrexStreamsCompiler compiler; - TrexStreamsCompiledObj *compiled_obj = new TrexStreamsCompiledObj(m_port_id, mul); + TrexStreamsCompiledObj *compiled_obj = new TrexStreamsCompiledObj(m_port_id, per_core_mul); bool rc = compiler.compile(streams, *compiled_obj); if (!rc) { @@ -133,6 +136,34 @@ TrexStatelessPort::start_traffic(double mul, double duration) { } +void +TrexStatelessPort::start_traffic_max_bps(double max_bps, double duration) { + /* fetch all the streams from the table */ + vector streams; + get_object_list(streams); + + TrexStreamsGraph graph; + const TrexStreamsGraphObj &obj = graph.generate(streams); + double m = (max_bps / obj.get_max_bps()); + + /* call the main function */ + start_traffic(m, duration); +} + +void +TrexStatelessPort::start_traffic_max_pps(double max_pps, double duration) { + /* fetch all the streams from the table */ + vector streams; + get_object_list(streams); + + TrexStreamsGraph graph; + const TrexStreamsGraphObj &obj = graph.generate(streams); + double m = (max_pps / obj.get_max_pps()); + + /* call the main function */ + start_traffic(m, duration); +} + /** * stop traffic on port * diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 73157c15..9b74741c 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -77,6 +77,8 @@ public: * throws TrexException in case of an error */ void start_traffic(double mul, double duration = -1); + void start_traffic_max_bps(double max_bps, double duration = -1); + void start_traffic_max_pps(double max_pps, double duration = -1); /** * stop traffic diff --git a/src/stateless/cp/trex_stream.cpp b/src/stateless/cp/trex_stream.cpp index 5203b2a2..cad603e2 100644 --- a/src/stateless/cp/trex_stream.cpp +++ b/src/stateless/cp/trex_stream.cpp @@ -21,6 +21,7 @@ limitations under the License. #include #include #include +#include /************************************** * stream @@ -129,6 +130,7 @@ TrexStream::get_stream_json() { return m_stream_json; } + /************************************** * stream table *************************************/ diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index 0634829e..5baba840 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -90,7 +90,7 @@ public: m_next_stream_id = next_stream_id; } - double get_pps() { + double get_pps() const { return m_pps; } @@ -150,6 +150,15 @@ public: return (dp); } + + double get_burst_length_usec() const { + return ( (m_burst_total_pkts / m_pps) * 1000 ); + } + + double get_bps() const { + return (m_pps * m_pkt.len * 8); + } + void Dump(FILE *fd); public: /* basic */ diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index bdfc3c01..f36de1b4 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -34,19 +34,25 @@ limitations under the License. */ class GraphNode { public: - GraphNode(TrexStream *stream, GraphNode *next) : m_stream(stream), m_next(next) { - marked = false; + GraphNode(const TrexStream *stream, GraphNode *next) : m_stream(stream), m_next(next) { + m_marked = false; m_compressed_stream_id=-1; + } uint32_t get_stream_id() const { return m_stream->m_stream_id; } + uint32_t get_next_stream_id() const { + return m_stream->m_next_stream_id; + + } + const TrexStream *m_stream; GraphNode *m_next; std::vector m_parents; - bool marked; + bool m_marked; int m_compressed_stream_id; }; @@ -97,13 +103,13 @@ public: void clear_marks() { for (auto node : m_nodes) { - node.second->marked = false; + node.second->m_marked = false; } } void get_unmarked(std::vector &unmarked) { for (auto node : m_nodes) { - if (!node.second->marked) { + if (!node.second->m_marked) { unmarked.push_back(node.second); } } @@ -132,6 +138,7 @@ private: GraphNode m_dead_end; }; + /************************************** * stream compiled object *************************************/ @@ -316,11 +323,11 @@ TrexStreamsCompiler::check_for_unreachable_streams(GraphNodeMap *nodes) { /* pull one */ GraphNode *node = next_nodes.back(); next_nodes.pop_back(); - if (node->marked) { + if (node->m_marked) { continue; } - node->marked = true; + node->m_marked = true; if (node->m_next != NULL) { next_nodes.push_back(node->m_next); @@ -422,9 +429,174 @@ TrexStreamsCompiler::compile(const std::vector &streams, my_stream_id, my_next_stream_id ); + } return true; } +/************************************** + * streams graph + *************************************/ + +void +TrexStreamsGraph::add_rate_events_for_stream(double &offset_usec, const TrexStream *stream) { + TrexStreamsGraphObj::rate_event_st start_event; + TrexStreamsGraphObj::rate_event_st stop_event; + + switch (stream->get_type()) { + case TrexStream::stCONTINUOUS: + + start_event.time = offset_usec + stream->m_isg_usec; + start_event.diff_pps = stream->get_pps(); + start_event.diff_bps = stream->get_bps(); + m_graph_obj.add_rate_event(start_event); + + /* no more events after this stream */ + offset_usec = -1; + + break; + + case TrexStream::stSINGLE_BURST: + + /* start event */ + start_event.time = offset_usec + stream->m_isg_usec; + start_event.diff_pps = stream->get_pps(); + start_event.diff_bps = stream->get_bps(); + m_graph_obj.add_rate_event(start_event); + + /* stop event */ + stop_event.time = start_event.time + stream->get_burst_length_usec(); + stop_event.diff_pps = -(start_event.diff_pps); + stop_event.diff_bps = -(start_event.diff_bps); + m_graph_obj.add_rate_event(stop_event); + + /* next stream starts from here */ + offset_usec = stop_event.time; + + break; + + case TrexStream::stMULTI_BURST: + + double delay = stream->m_isg_usec; + + start_event.diff_pps = stream->get_pps(); + start_event.diff_bps = stream->get_bps(); + + stop_event.diff_pps = -(start_event.diff_pps); + stop_event.diff_bps = -(start_event.diff_bps); + + for (int i = 0; i < stream->m_num_bursts; i++) { + + start_event.time = offset_usec + delay; + m_graph_obj.add_rate_event(start_event); + + stop_event.time = start_event.time + stream->get_burst_length_usec(); + m_graph_obj.add_rate_event(stop_event); + + delay = stream->m_ibg_usec; + + offset_usec = stop_event.time; + } + + break; + } +} + +void +TrexStreamsGraph::generate_graph_for_one_root(uint32_t root_stream_id) { + + + std::unordered_map loop_hash; + + + uint32_t stream_id = root_stream_id; + double offset = 0; + + while (true) { + + const TrexStream *stream = m_streams_hash.at(stream_id); + /* add the node to the hash for loop detection */ + loop_hash[stream_id] = true; + + add_rate_events_for_stream(offset, stream); + + /* do we have a next stream ? */ + if (stream->m_next_stream_id == -1) { + break; + } + + /* loop detection */ + + auto search = loop_hash.find(stream->m_next_stream_id); + if (search != loop_hash.end()) { + break; + } + + /* handle the next one */ + stream_id = stream->m_next_stream_id; + } +} + +const TrexStreamsGraphObj & +TrexStreamsGraph::generate(const std::vector &streams) { + std::vector root_streams; + + + for (TrexStream *stream : streams) { + + /* for fast search we populate all the streams in a hash */ + m_streams_hash[stream->m_stream_id] = stream; + + /* hold all the self start nodes in a vector */ + if (stream->m_self_start) { + root_streams.push_back(stream->m_stream_id); + } + } + + /* for each node - scan until done or loop */ + for (uint32_t root_id : root_streams) { + generate_graph_for_one_root(root_id); + } + + + m_graph_obj.generate(); + + return m_graph_obj; +} + +/************************************** + * streams graph object + *************************************/ +void +TrexStreamsGraphObj::find_max_rate() { + double max_rate_pps = 0; + double current_rate_pps = 0; + + double max_rate_bps = 0; + double current_rate_bps = 0; + + /* now we simply walk the list and hold the max */ + for (auto &ev : m_rate_events) { + current_rate_pps += ev.diff_pps; + current_rate_bps += ev.diff_bps; + + max_rate_pps = std::max(max_rate_pps, current_rate_pps); + max_rate_bps = std::max(max_rate_bps, current_rate_bps); + } + + m_max_pps = max_rate_pps; + m_max_bps = max_rate_bps; +} + +static +bool event_compare (const TrexStreamsGraphObj::rate_event_st &first, const TrexStreamsGraphObj::rate_event_st &second) { + return (first.time < second.time); +} + +void +TrexStreamsGraphObj::generate() { + m_rate_events.sort(event_compare); + find_max_rate(); +} diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 200f7ce9..28a9bd10 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -23,7 +23,9 @@ limitations under the License. #include #include +#include #include +#include class TrexStreamsCompiler; class TrexStream; @@ -109,6 +111,84 @@ private: void err(const std::string &err); std::vector m_warnings; + +}; + +class TrexStreamsGraph; + +/************************************** + * streams graph object + * + * holds the step graph for bandwidth + *************************************/ +class TrexStreamsGraphObj { + friend class TrexStreamsGraph; + +public: + + /** + * rate event is defined by those: + * time - the time of the event on the timeline + * diff - what is the nature of the change ? + * + * @author imarom (23-Nov-15) + */ + struct rate_event_st { + double time; + double diff_pps; + double diff_bps; + }; + + double get_max_pps() const { + return m_max_pps; + } + + double get_max_bps() const { + return m_max_bps; + } + + +private: + + void add_rate_event(const rate_event_st &ev) { + m_rate_events.push_back(ev); + } + + void generate(); + void find_max_rate(); + + double m_max_pps; + double m_max_bps; + + /* list of rate events */ + std::list m_rate_events; +}; + +/** + * graph creator + * + * @author imarom (23-Nov-15) + */ +class TrexStreamsGraph { +public: + + /** + * generate a sequence graph for streams + * + */ + const TrexStreamsGraphObj & generate(const std::vector &streams); + +private: + + void generate_graph_for_one_root(uint32_t root_stream_id); + + void add_rate_events_for_stream(double &offset, const TrexStream *stream); + + /* for fast processing of streams */ + std::unordered_map m_streams_hash; + + /* main object to hold the graph - returned to the user */ + TrexStreamsGraphObj m_graph_obj; }; #endif /* __TREX_STREAMS_COMPILER_H__ */ -- cgit 1.2.3-korg From 161a85c57c3d2a165e4fa94140d67db05714a7d3 Mon Sep 17 00:00:00 2001 From: imarom Date: Tue, 24 Nov 2015 11:52:33 +0200 Subject: bug fixes for the graph --- src/gtest/trex_stateless_gtest.cpp | 128 +++++++++++++++++++++- src/stateless/cp/trex_stream.h | 5 +- src/stateless/cp/trex_streams_compiler.cpp | 170 +++++++++++++++++++++-------- src/stateless/cp/trex_streams_compiler.h | 7 ++ 4 files changed, 260 insertions(+), 50 deletions(-) (limited to 'src/gtest') diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 3aad2d41..72a99e93 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -1342,7 +1342,7 @@ TEST_F(basic_stl, dp_stop_event) { } -TEST_F(basic_stl, graph_generator) { +TEST_F(basic_stl, graph_generator1) { std::vector streams; TrexStreamsGraph graph; TrexStream *stream; @@ -1388,12 +1388,134 @@ TEST_F(basic_stl, graph_generator) { const TrexStreamsGraphObj &obj = graph.generate(streams); - EXPECT_TRUE(obj.get_max_bps() == 403840.0); - EXPECT_TRUE(obj.get_max_pps() == 50.0); + EXPECT_EQ(obj.get_max_bps(), 405120); + EXPECT_EQ(obj.get_max_pps(), 50); for (auto stream : streams) { delete stream; } } + +TEST_F(basic_stl, graph_generator2) { + std::vector streams; + TrexStreamsGraph graph; + TrexStream *stream; + + /* add some multi burst streams */ + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 1); + stream->m_enabled = true; + stream->m_self_start = true; + + + stream->set_pps(1000); + + /* a burst of 2000 packets with a delay of 1 second */ + stream->m_isg_usec = 0; + stream->set_multi_burst(1000, 500, 1000 * 1000); + stream->m_pkt.len = 64; + + stream->m_next_stream_id = -1; + + streams.push_back(stream); + + /* another multi burst stream but with a shorter burst ( less 2 ms ) and + higher ibg (2 ms) , one milli for each side + */ + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 2); + stream->m_enabled = true; + stream->m_self_start = true; + + stream->set_pps(1000); + stream->m_isg_usec = 1000 * 1000 + 1000; + stream->set_multi_burst(1000 - 2, 1000, 1000 * 1000 + 2000); + stream->m_pkt.len = 128; + + stream->m_next_stream_id = -1; + + streams.push_back(stream); + + const TrexStreamsGraphObj &obj = graph.generate(streams); + EXPECT_EQ(obj.get_max_pps(), 1000.0); + + EXPECT_EQ(obj.get_max_bps(), (1000 * (128 + 4) * 8)); + + + for (auto stream : streams) { + delete stream; + } +} + +/* stress test */ +#if 0 +TEST_F(basic_stl, graph_generator2) { + std::vector streams; + TrexStreamsGraph graph; + TrexStream *stream; + + /* add some multi burst streams */ + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 1); + stream->m_enabled = true; + stream->m_self_start = true; + stream->m_isg_usec = 100; + + stream->set_pps(20); + stream->set_multi_burst(4918, 321312, 15); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 64; + + streams.push_back(stream); + + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 2); + stream->m_enabled = true; + stream->m_self_start = true; + stream->m_isg_usec = 59281; + + stream->set_pps(30); + stream->set_multi_burst(4918, 51040, 27); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 64; + + streams.push_back(stream); + + stream = new TrexStream(TrexStream::stMULTI_BURST, 0, 3); + stream->m_enabled = true; + stream->m_self_start = true; + stream->m_isg_usec = 59281492; + + stream->set_pps(40); + stream->set_multi_burst(4918, 412312, 2917); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 64; + + streams.push_back(stream); + + + /* stream 3 */ + stream = new TrexStream(TrexStream::stCONTINUOUS, 0, 4); + stream->m_enabled = true; + stream->m_self_start = true; + + stream->m_isg_usec = 50; + stream->set_pps(30); + stream->m_next_stream_id = -1; + stream->m_pkt.len = 1512; + + streams.push_back(stream); + + + const TrexStreamsGraphObj &obj = graph.generate(streams); + printf("event_count is: %lu, max BPS: %f, max PPS: %f\n", obj.get_events().size(), obj.get_max_bps(), obj.get_max_pps()); + +// for (const TrexStreamsGraphObj::rate_event_st &ev : obj.get_events()) { +// printf("time: %f, diff bps: %f, diff pps: %f\n", ev.time, ev.diff_bps, ev.diff_pps); +// } + + for (auto stream : streams) { + delete stream; + } +} + +#endif + /********************************************* Itay Tests End *************************************/ diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index 5baba840..3e48d7e4 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -152,11 +152,12 @@ public: double get_burst_length_usec() const { - return ( (m_burst_total_pkts / m_pps) * 1000 ); + return ( (m_burst_total_pkts / m_pps) * 1000 * 1000); } double get_bps() const { - return (m_pps * m_pkt.len * 8); + /* packet length + 4 CRC bytes to bits and multiplied by PPS */ + return (m_pps * (m_pkt.len + 4) * 8); } void Dump(FILE *fd); diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index f36de1b4..f97b15b9 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -439,86 +439,154 @@ TrexStreamsCompiler::compile(const std::vector &streams, * streams graph *************************************/ +/** + * for each stream we create the right rate events (up/down) + * + * @author imarom (24-Nov-15) + * + * @param offset_usec + * @param stream + */ void TrexStreamsGraph::add_rate_events_for_stream(double &offset_usec, const TrexStream *stream) { - TrexStreamsGraphObj::rate_event_st start_event; - TrexStreamsGraphObj::rate_event_st stop_event; switch (stream->get_type()) { + case TrexStream::stCONTINUOUS: + add_rate_events_for_stream_cont(offset_usec, stream); + return; + + case TrexStream::stSINGLE_BURST: + add_rate_events_for_stream_single_burst(offset_usec, stream); + return; - start_event.time = offset_usec + stream->m_isg_usec; - start_event.diff_pps = stream->get_pps(); - start_event.diff_bps = stream->get_bps(); - m_graph_obj.add_rate_event(start_event); + case TrexStream::stMULTI_BURST: + add_rate_events_for_stream_multi_burst(offset_usec, stream); + return; + } +} - /* no more events after this stream */ - offset_usec = -1; +/** + * continous stream + * + */ +void +TrexStreamsGraph::add_rate_events_for_stream_cont(double &offset_usec, const TrexStream *stream) { - break; - - case TrexStream::stSINGLE_BURST: + TrexStreamsGraphObj::rate_event_st start_event; - /* start event */ - start_event.time = offset_usec + stream->m_isg_usec; - start_event.diff_pps = stream->get_pps(); - start_event.diff_bps = stream->get_bps(); - m_graph_obj.add_rate_event(start_event); + /* for debug purposes */ + start_event.stream_id = stream->m_stream_id; - /* stop event */ - stop_event.time = start_event.time + stream->get_burst_length_usec(); - stop_event.diff_pps = -(start_event.diff_pps); - stop_event.diff_bps = -(start_event.diff_bps); - m_graph_obj.add_rate_event(stop_event); + start_event.time = offset_usec + stream->m_isg_usec; + start_event.diff_pps = stream->get_pps(); + start_event.diff_bps = stream->get_bps(); + m_graph_obj.add_rate_event(start_event); - /* next stream starts from here */ - offset_usec = stop_event.time; + /* no more events after this stream */ + offset_usec = -1; +} + +/** + * single burst stream + * + */ +void +TrexStreamsGraph::add_rate_events_for_stream_single_burst(double &offset_usec, const TrexStream *stream) { + TrexStreamsGraphObj::rate_event_st start_event; + TrexStreamsGraphObj::rate_event_st stop_event; - break; - case TrexStream::stMULTI_BURST: + /* for debug purposes */ + start_event.stream_id = stream->m_stream_id; + stop_event.stream_id = stream->m_stream_id; + + /* start event */ + start_event.time = offset_usec + stream->m_isg_usec; + start_event.diff_pps = stream->get_pps(); + start_event.diff_bps = stream->get_bps(); + m_graph_obj.add_rate_event(start_event); + + /* stop event */ + stop_event.time = start_event.time + stream->get_burst_length_usec(); + stop_event.diff_pps = -(start_event.diff_pps); + stop_event.diff_bps = -(start_event.diff_bps); + m_graph_obj.add_rate_event(stop_event); + + /* next stream starts from here */ + offset_usec = stop_event.time; - double delay = stream->m_isg_usec; +} - start_event.diff_pps = stream->get_pps(); - start_event.diff_bps = stream->get_bps(); +/** + * multi burst stream + * + */ +void +TrexStreamsGraph::add_rate_events_for_stream_multi_burst(double &offset_usec, const TrexStream *stream) { + TrexStreamsGraphObj::rate_event_st start_event; + TrexStreamsGraphObj::rate_event_st stop_event; - stop_event.diff_pps = -(start_event.diff_pps); - stop_event.diff_bps = -(start_event.diff_bps); + /* first the delay is the inter stream gap */ + double delay = stream->m_isg_usec; + + /* for debug purposes */ + + start_event.diff_pps = stream->get_pps(); + start_event.diff_bps = stream->get_bps(); + start_event.stream_id = stream->m_stream_id; - for (int i = 0; i < stream->m_num_bursts; i++) { + stop_event.diff_pps = -(start_event.diff_pps); + stop_event.diff_bps = -(start_event.diff_bps); + stop_event.stream_id = stream->m_stream_id; - start_event.time = offset_usec + delay; - m_graph_obj.add_rate_event(start_event); + /* for each burst create up/down events */ + for (int i = 0; i < stream->m_num_bursts; i++) { - stop_event.time = start_event.time + stream->get_burst_length_usec(); - m_graph_obj.add_rate_event(stop_event); + start_event.time = offset_usec + delay; + m_graph_obj.add_rate_event(start_event); - delay = stream->m_ibg_usec; + stop_event.time = start_event.time + stream->get_burst_length_usec(); + m_graph_obj.add_rate_event(stop_event); - offset_usec = stop_event.time; - } + /* after the first burst, the delay is inter burst gap */ + delay = stream->m_ibg_usec; - break; + offset_usec = stop_event.time; } } +/** + * for a single root we can until done or a loop detected + * + * @author imarom (24-Nov-15) + * + * @param root_stream_id + */ void TrexStreamsGraph::generate_graph_for_one_root(uint32_t root_stream_id) { - std::unordered_map loop_hash; - + std::stringstream ss; uint32_t stream_id = root_stream_id; double offset = 0; while (true) { + const TrexStream *stream; + + /* fetch the stream from the hash - if it is not present, report an error */ + try { + stream = m_streams_hash.at(stream_id); + } catch (const std::out_of_range &e) { + ss << "stream id " << stream_id << " does not exists"; + throw TrexException(ss.str()); + } - const TrexStream *stream = m_streams_hash.at(stream_id); /* add the node to the hash for loop detection */ loop_hash[stream_id] = true; + /* create the right rate events for the stream */ add_rate_events_for_stream(offset, stream); /* do we have a next stream ? */ @@ -527,7 +595,6 @@ TrexStreamsGraph::generate_graph_for_one_root(uint32_t root_stream_id) { } /* loop detection */ - auto search = loop_hash.find(stream->m_next_stream_id); if (search != loop_hash.end()) { break; @@ -538,13 +605,25 @@ TrexStreamsGraph::generate_graph_for_one_root(uint32_t root_stream_id) { } } +/** + * for a vector of streams generate a graph of BW + * see graph object for more details + * + */ const TrexStreamsGraphObj & TrexStreamsGraph::generate(const std::vector &streams) { std::vector root_streams; - + /* before anything we create a hash streams ID + and grab the root nodes + */ for (TrexStream *stream : streams) { - + + /* skip non enabled streams */ + if (!stream->m_enabled) { + continue; + } + /* for fast search we populate all the streams in a hash */ m_streams_hash[stream->m_stream_id] = stream; @@ -578,6 +657,7 @@ TrexStreamsGraphObj::find_max_rate() { /* now we simply walk the list and hold the max */ for (auto &ev : m_rate_events) { + current_rate_pps += ev.diff_pps; current_rate_bps += ev.diff_bps; diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 28a9bd10..9f0c1f8e 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -137,6 +137,7 @@ public: double time; double diff_pps; double diff_bps; + uint32_t stream_id; }; double get_max_pps() const { @@ -147,6 +148,9 @@ public: return m_max_bps; } + const std::list & get_events() const { + return m_rate_events; + } private: @@ -183,6 +187,9 @@ private: void generate_graph_for_one_root(uint32_t root_stream_id); void add_rate_events_for_stream(double &offset, const TrexStream *stream); + void add_rate_events_for_stream_cont(double &offset_usec, const TrexStream *stream); + void add_rate_events_for_stream_single_burst(double &offset_usec, const TrexStream *stream); + void add_rate_events_for_stream_multi_burst(double &offset_usec, const TrexStream *stream); /* for fast processing of streams */ std::unordered_map m_streams_hash; -- cgit 1.2.3-korg From 59548ae8f65f8aa387900a321b437b8501046fde Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 26 Nov 2015 06:26:27 -0500 Subject: Hanoch's review - changed update model to differential also, graph is calculated on demand and once for each update --- src/gtest/trex_stateless_gtest.cpp | 16 ++-- src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 44 ++++----- src/stateless/cp/trex_stateless_port.cpp | 103 +++++++++++++++------ src/stateless/cp/trex_stateless_port.h | 59 +++++++++--- src/stateless/cp/trex_streams_compiler.cpp | 18 ++-- src/stateless/cp/trex_streams_compiler.h | 9 +- src/stateless/dp/trex_stateless_dp_core.cpp | 11 +-- src/stateless/dp/trex_stateless_dp_core.h | 2 +- src/stateless/dp/trex_stream_node.h | 8 +- .../messaging/trex_stateless_messaging.cpp | 4 +- src/stateless/messaging/trex_stateless_messaging.h | 6 +- 11 files changed, 184 insertions(+), 96 deletions(-) (limited to 'src/gtest') diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 5b298023..ea54a935 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -1713,13 +1713,15 @@ TEST_F(basic_stl, graph_generator1) { streams.push_back(stream); - const TrexStreamsGraphObj &obj = graph.generate(streams); - EXPECT_EQ(obj.get_max_bps(), 405120); - EXPECT_EQ(obj.get_max_pps(), 50); + const TrexStreamsGraphObj *obj = graph.generate(streams); + EXPECT_EQ(obj->get_max_bps(), 405120); + EXPECT_EQ(obj->get_max_pps(), 50); for (auto stream : streams) { delete stream; } + + delete obj; } @@ -1761,15 +1763,17 @@ TEST_F(basic_stl, graph_generator2) { streams.push_back(stream); - const TrexStreamsGraphObj &obj = graph.generate(streams); - EXPECT_EQ(obj.get_max_pps(), 1000.0); + const TrexStreamsGraphObj *obj = graph.generate(streams); + EXPECT_EQ(obj->get_max_pps(), 1000.0); - EXPECT_EQ(obj.get_max_bps(), (1000 * (128 + 4) * 8)); + EXPECT_EQ(obj->get_max_bps(), (1000 * (128 + 4) * 8)); for (auto stream : streams) { delete stream; } + + delete obj; } /* stress test */ diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index 96224d4e..a5bf0d16 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -473,32 +473,32 @@ TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); + /* multiplier */ + const Json::Value &mul_obj = parse_object(params, "mul", result); + std::string mul_type = parse_string(mul_obj, "type", result); + double mul_value = parse_double(mul_obj, "max", result); - const Json::Value &mul = parse_object(params, "mul", result); - - std::string mul_type = parse_string(mul, "type", result); - double max_rate = parse_double(mul, "max", result); - - - double m = 0; + /* now create an object for multiplier */ + TrexStatelessPort::mul_st mul; + + mul.value = mul_value; /* dispatch according to type of multiplier */ if (mul_type == "raw") { - m = max_rate; + mul.type = TrexStatelessPort::MUL_FACTOR; } else if (mul_type == "max_bps") { - m = port->calculate_m_from_bps(max_rate); + mul.type = TrexStatelessPort::MUL_MAX_BPS; } else if (mul_type == "max_pps") { - m = port->calculate_m_from_pps(max_rate); + mul.type = TrexStatelessPort::MUL_MAX_PPS; } else { generate_parse_err(result, "multiplier type can be either 'raw', 'max_bps' or 'max_pps'"); } - try { - port->start_traffic(m, duration); + port->start_traffic(mul, duration); } catch (const TrexRpcException &ex) { generate_execute_err(result, ex.what()); @@ -651,29 +651,31 @@ TrexRpcCmdUpdateTraffic::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); /* multiplier */ - const Json::Value &mul = parse_object(params, "mul", result); + const Json::Value &mul_obj = parse_object(params, "mul", result); + std::string mul_type = parse_string(mul_obj, "type", result); + double mul_value = parse_double(mul_obj, "max", result); - std::string mul_type = parse_string(mul, "type", result); - double max_rate = parse_double(mul, "max", result); - - double m = 0; + /* now create an object for multiplier */ + TrexStatelessPort::mul_st mul; + + mul.value = mul_value; /* dispatch according to type of multiplier */ if (mul_type == "raw") { - m = max_rate; + mul.type = TrexStatelessPort::MUL_FACTOR; } else if (mul_type == "max_bps") { - m = port->calculate_m_from_bps(max_rate); + mul.type = TrexStatelessPort::MUL_MAX_BPS; } else if (mul_type == "max_pps") { - m = port->calculate_m_from_pps(max_rate); + mul.type = TrexStatelessPort::MUL_MAX_PPS; } else { generate_parse_err(result, "multiplier type can be either 'raw', 'max_bps' or 'max_pps'"); } try { - port->update_traffic(m); + port->update_traffic(mul); } catch (const TrexRpcException &ex) { generate_execute_err(result, ex.what()); } diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 8e18a5bf..8346b61d 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -104,17 +104,21 @@ TrexStatelessPort::release(void) { * */ void -TrexStatelessPort::start_traffic(double mul, double duration) { +TrexStatelessPort::start_traffic(const TrexStatelessPort::mul_st &mul, double duration) { /* command allowed only on state stream */ verify_state(PORT_STATE_STREAMS); + /* just making sure no leftovers... */ + delete_streams_graph(); + + /* calculate the effective M */ + double per_core_mul = calculate_effective_mul(mul); + /* fetch all the streams from the table */ vector streams; get_object_list(streams); - /* split it per core */ - double per_core_mul = mul / m_cores_id_list.size(); /* compiler it */ TrexStreamsCompiler compiler; @@ -127,6 +131,7 @@ TrexStatelessPort::start_traffic(double mul, double duration) { /* generate a message to all the relevant DP cores to start transmitting */ int event_id = m_dp_events.generate_event_id(); + /* mark that DP event of stoppped is possible */ m_dp_events.wait_for_event(TrexDpPortEvent::EVENT_STOP, event_id); @@ -142,32 +147,11 @@ TrexStatelessPort::start_traffic(double mul, double duration) { Json::Value data; data["port_id"] = m_port_id; get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_STARTED, data); -} - -double -TrexStatelessPort::calculate_m_from_bps(double max_bps) { - /* fetch all the streams from the table */ - vector streams; - get_object_list(streams); - - TrexStreamsGraph graph; - const TrexStreamsGraphObj &obj = graph.generate(streams); - - return (max_bps / obj.get_max_bps()); + /* save the per core multiplier for update messages */ + m_current_per_core_m = per_core_mul; } -double -TrexStatelessPort::calculate_m_from_pps(double max_pps) { - /* fetch all the streams from the table */ - vector streams; - get_object_list(streams); - - TrexStreamsGraph graph; - const TrexStreamsGraphObj &obj = graph.generate(streams); - - return (max_pps / obj.get_max_pps()); -} /** * stop traffic on port @@ -180,10 +164,13 @@ void TrexStatelessPort::stop_traffic(void) { if (!( (m_port_state == PORT_STATE_TX) - || (m_port_state ==PORT_STATE_PAUSE) )) { + || (m_port_state == PORT_STATE_PAUSE) )) { return; } + /* delete any previous graphs */ + delete_streams_graph(); + /* mask out the DP stop event */ m_dp_events.disable(TrexDpPortEvent::EVENT_STOP); @@ -234,16 +221,20 @@ TrexStatelessPort::resume_traffic(void) { } void -TrexStatelessPort::update_traffic(double mul) { +TrexStatelessPort::update_traffic(const TrexStatelessPort::mul_st &mul) { verify_state(PORT_STATE_TX | PORT_STATE_PAUSE); /* generate a message to all the relevant DP cores to start transmitting */ - double per_core_mul = mul / m_cores_id_list.size(); - TrexStatelessCpToDpMsgBase *update_msg = new TrexStatelessDpUpdate(m_port_id, per_core_mul); + double new_per_core_m = calculate_effective_mul(mul); + double factor = new_per_core_m / m_current_per_core_m; + + TrexStatelessCpToDpMsgBase *update_msg = new TrexStatelessDpUpdate(m_port_id, factor); send_message_to_dp(update_msg); + m_current_per_core_m = new_per_core_m; + } std::string @@ -376,3 +367,55 @@ TrexStatelessPort::on_dp_event_occured(TrexDpPortEvent::event_e event_type) { } } + +/** + * calculate an effective M based on requirments + * + */ +double +TrexStatelessPort::calculate_effective_mul(const mul_st &mul) { + + /* for a simple factor request - calculate the multiplier per core */ + if (mul.type == MUL_FACTOR) { + return (mul.value / m_cores_id_list.size()); + } + + /* we now need the graph - generate it if we don't have it (happens once) */ + if (!m_graph_obj) { + generate_streams_graph(); + } + + /* now we can calculate the effective M */ + if (mul.type == MUL_MAX_BPS) { + return ( (mul.value / m_graph_obj->get_max_bps()) / m_cores_id_list.size()); + } else if (mul.type == MUL_MAX_PPS) { + return ( (mul.value / m_graph_obj->get_max_pps()) / m_cores_id_list.size()); + } else { + assert(0); + } +} + +void +TrexStatelessPort::generate_streams_graph() { + + /* dispose of the old one */ + if (m_graph_obj) { + delete_streams_graph(); + } + + /* fetch all the streams from the table */ + vector streams; + get_object_list(streams); + + TrexStreamsGraph graph; + m_graph_obj = graph.generate(streams); +} + +void +TrexStatelessPort::delete_streams_graph() { + if (m_graph_obj) { + delete m_graph_obj; + m_graph_obj = NULL; + } +} + diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index b061a414..7d20f338 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -26,6 +26,7 @@ limitations under the License. #include class TrexStatelessCpToDpMsgBase; +class TrexStreamsGraphObj; /** * describes a stateless port @@ -58,6 +59,24 @@ public: RC_ERR_FAILED_TO_COMPILE_STREAMS }; + /** + * defines the type of multipler passed to start + */ + enum mul_type_e { + MUL_FACTOR, + MUL_MAX_BPS, + MUL_MAX_PPS + }; + + /** + * multiplier object + */ + typedef struct { + mul_type_e type; + double value; + } mul_st; + + TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api); /** @@ -76,19 +95,7 @@ public: * start traffic * throws TrexException in case of an error */ - void start_traffic(double mul, double duration = -1); - - /** - * given a BPS rate calculate ther correct M for this port - * - */ - double calculate_m_from_bps(double max_bps); - - /** - * given a PPS rate calculate the correct M for this port - * - */ - double calculate_m_from_pps(double max_pps); + void start_traffic(const mul_st &mul, double duration = -1); /** * stop traffic @@ -112,7 +119,7 @@ public: * update current traffic on port * */ - void update_traffic(double mul); + void update_traffic(const mul_st &mul); /** * get the port state @@ -265,6 +272,26 @@ private: void on_dp_event_occured(TrexDpPortEvent::event_e event_type); + /** + * calculate effective M per core + * + */ + double calculate_effective_mul(const mul_st &mul); + + /** + * generates a graph of streams graph + * + */ + void generate_streams_graph(); + + /** + * dispose of it + * + * @author imarom (26-Nov-15) + */ + void delete_streams_graph(); + + TrexStreamTable m_stream_table; uint8_t m_port_id; port_state_e m_port_state; @@ -279,8 +306,12 @@ private: bool m_last_all_streams_continues; double m_last_duration; + double m_current_per_core_m; TrexDpPortEvents m_dp_events; + + /* holds a graph of streams rate*/ + const TrexStreamsGraphObj *m_graph_obj; }; #endif /* __TREX_STATELESS_PORT_H__ */ diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index b28989be..c8aa1e40 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -486,7 +486,7 @@ TrexStreamsGraph::add_rate_events_for_stream_cont(double &offset_usec, const Tre start_event.time = offset_usec + stream->m_isg_usec; start_event.diff_pps = stream->get_pps(); start_event.diff_bps = stream->get_bps(); - m_graph_obj.add_rate_event(start_event); + m_graph_obj->add_rate_event(start_event); /* no more events after this stream */ offset_usec = -1; @@ -510,13 +510,13 @@ TrexStreamsGraph::add_rate_events_for_stream_single_burst(double &offset_usec, c start_event.time = offset_usec + stream->m_isg_usec; start_event.diff_pps = stream->get_pps(); start_event.diff_bps = stream->get_bps(); - m_graph_obj.add_rate_event(start_event); + m_graph_obj->add_rate_event(start_event); /* stop event */ stop_event.time = start_event.time + stream->get_burst_length_usec(); stop_event.diff_pps = -(start_event.diff_pps); stop_event.diff_bps = -(start_event.diff_bps); - m_graph_obj.add_rate_event(stop_event); + m_graph_obj->add_rate_event(stop_event); /* next stream starts from here */ offset_usec = stop_event.time; @@ -549,10 +549,10 @@ TrexStreamsGraph::add_rate_events_for_stream_multi_burst(double &offset_usec, co for (int i = 0; i < stream->m_num_bursts; i++) { start_event.time = offset_usec + delay; - m_graph_obj.add_rate_event(start_event); + m_graph_obj->add_rate_event(start_event); stop_event.time = start_event.time + stream->get_burst_length_usec(); - m_graph_obj.add_rate_event(stop_event); + m_graph_obj->add_rate_event(stop_event); /* after the first burst, the delay is inter burst gap */ delay = stream->m_ibg_usec; @@ -615,8 +615,12 @@ TrexStreamsGraph::generate_graph_for_one_root(uint32_t root_stream_id) { * see graph object for more details * */ -const TrexStreamsGraphObj & +const TrexStreamsGraphObj * TrexStreamsGraph::generate(const std::vector &streams) { + + /* main object to hold the graph - returned to the user */ + m_graph_obj = new TrexStreamsGraphObj(); + std::vector root_streams; /* before anything we create a hash streams ID @@ -644,7 +648,7 @@ TrexStreamsGraph::generate(const std::vector &streams) { } - m_graph_obj.generate(); + m_graph_obj->generate(); return m_graph_obj; } diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 70a31c5e..a4c12f8d 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -171,6 +171,7 @@ private: /* list of rate events */ std::list m_rate_events; + }; /** @@ -181,11 +182,15 @@ private: class TrexStreamsGraph { public: + TrexStreamsGraph() { + m_graph_obj = NULL; + } + /** * generate a sequence graph for streams * */ - const TrexStreamsGraphObj & generate(const std::vector &streams); + const TrexStreamsGraphObj * generate(const std::vector &streams); private: @@ -200,7 +205,7 @@ private: std::unordered_map m_streams_hash; /* main object to hold the graph - returned to the user */ - TrexStreamsGraphObj m_graph_obj; + TrexStreamsGraphObj *m_graph_obj; }; #endif /* __TREX_STREAMS_COMPILER_H__ */ diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index dd4937cd..9b62fabd 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -139,7 +139,7 @@ bool TrexStatelessDpPerPort::resume_traffic(uint8_t port_id){ return (true); } -bool TrexStatelessDpPerPort::update_traffic(uint8_t port_id, double mul) { +bool TrexStatelessDpPerPort::update_traffic(uint8_t port_id, double factor) { assert( (m_state == TrexStatelessDpPerPort::ppSTATE_TRANSMITTING || (m_state == TrexStatelessDpPerPort::ppSTATE_PAUSE)) ); @@ -148,7 +148,7 @@ bool TrexStatelessDpPerPort::update_traffic(uint8_t port_id, double mul) { CGenNodeStateless * node = dp_stream.m_node; assert(node->get_port_id() == port_id); - node->set_multiplier(mul); + node->update_rate(factor); } return (true); @@ -453,8 +453,7 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port, node->m_pause =0; node->m_stream_type = stream->m_type; - node->m_base_pps = stream->get_pps(); - node->set_multiplier(comp->get_multiplier()); + node->m_next_time_offset = 1.0 / (stream->get_pps() * comp->get_multiplier()); /* stateless specific fields */ switch ( stream->m_type ) { @@ -597,11 +596,11 @@ TrexStatelessDpCore::pause_traffic(uint8_t port_id){ } void -TrexStatelessDpCore::update_traffic(uint8_t port_id, double mul) { +TrexStatelessDpCore::update_traffic(uint8_t port_id, double factor) { TrexStatelessDpPerPort * lp_port = get_port_db(port_id); - lp_port->update_traffic(port_id, mul); + lp_port->update_traffic(port_id, factor); } diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index 563159b2..7dc4a2b2 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -68,7 +68,7 @@ public: bool resume_traffic(uint8_t port_id); - bool update_traffic(uint8_t port_id, double mul); + bool update_traffic(uint8_t port_id, double factor); bool stop_traffic(uint8_t port_id, bool stop_on_id, diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index 5997376f..111af845 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -86,9 +86,8 @@ private: TrexStream * m_ref_stream_info; /* the stream info */ CGenNodeStateless * m_next_stream; - double m_base_pps; /* pad to match the size of CGenNode */ - uint8_t m_pad_end[48]; + uint8_t m_pad_end[56]; @@ -105,8 +104,9 @@ public: * on the PPS and multiplier * */ - void set_multiplier(double mul) { - m_next_time_offset = 1.0 / (m_base_pps * mul) ; + void update_rate(double factor) { + /* update the inter packet gap */ + m_next_time_offset = m_next_time_offset / factor; } /* we restart the stream, schedule it using stream isg */ diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp index 3210f29a..257de168 100644 --- a/src/stateless/messaging/trex_stateless_messaging.cpp +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -168,14 +168,14 @@ TrexStatelessDpCanQuit::clone(){ ************************/ bool TrexStatelessDpUpdate::handle(TrexStatelessDpCore *dp_core) { - dp_core->update_traffic(m_port_id, m_mul); + dp_core->update_traffic(m_port_id, m_factor); return true; } TrexStatelessCpToDpMsgBase * TrexStatelessDpUpdate::clone() { - TrexStatelessCpToDpMsgBase *new_msg = new TrexStatelessDpUpdate(m_port_id, m_mul); + TrexStatelessCpToDpMsgBase *new_msg = new TrexStatelessDpUpdate(m_port_id, m_factor); return new_msg; } diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index 7390be60..d56596bf 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -231,9 +231,9 @@ public: class TrexStatelessDpUpdate : public TrexStatelessCpToDpMsgBase { public: - TrexStatelessDpUpdate(uint8_t port_id, double mul) { + TrexStatelessDpUpdate(uint8_t port_id, double factor) { m_port_id = port_id; - m_mul = mul; + m_factor = factor; } virtual bool handle(TrexStatelessDpCore *dp_core); @@ -242,7 +242,7 @@ public: private: uint8_t m_port_id; - double m_mul; + double m_factor; }; -- cgit 1.2.3-korg From 23e1f07edcd8289f09a1477c416ce260d1a0a804 Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 6 Dec 2015 03:53:35 -0500 Subject: moved gtest to new compile API --- src/gtest/trex_stateless_gtest.cpp | 204 ++++++++++++----------------- src/stateless/cp/trex_stateless_port.cpp | 8 +- src/stateless/cp/trex_streams_compiler.cpp | 4 +- src/stateless/cp/trex_streams_compiler.h | 4 +- 4 files changed, 95 insertions(+), 125 deletions(-) (limited to 'src/gtest') diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index ea54a935..566e7ed4 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -30,6 +30,7 @@ limitations under the License. #include #include #include +#include #define EXPECT_EQ_UINT32(a,b) EXPECT_EQ((uint32_t)(a),(uint32_t)(b)) @@ -435,11 +436,9 @@ TEST_F(basic_stl, basic_pause_resume0) { // stream - clean - TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + std::vector objs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); t1.m_msg_queue.add_msg(lpStartCmd); @@ -499,14 +498,9 @@ void CBBStartStopDelay2::call_after_init(CBasicStl * m_obj){ streams.push_back(stream1); // stream - clean - - TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); - - assert(compile.compile(streams, comp_obj) ); - - - /* start with different event id */ - TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(m_port_id, 1, comp_obj.clone(), 10.0 /*sec */ ); + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 1, objs[0], 10.0 /*sec */ ); m_obj->m_msg_queue.add_command(m_core,lpStopCmd, 5.0); /* command in delay of 5 sec */ @@ -552,12 +546,9 @@ TEST_F(basic_stl, single_pkt_bb_start_stop_delay2) { streams.push_back(stream1); // stream - clean - - TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); t1.m_msg_queue.add_msg(lpStartCmd); @@ -633,12 +624,9 @@ TEST_F(basic_stl, single_pkt_bb_start_stop_delay1) { streams.push_back(stream1); // stream - clean - - TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); t1.m_msg_queue.add_msg(lpStartCmd); @@ -687,12 +675,10 @@ TEST_F(basic_stl, single_pkt_bb_start_stop3) { streams.push_back(stream1); // stream - clean + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); - TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(port_id); TrexStatelessDpStop * lpStopCmd1 = new TrexStatelessDpStop(port_id); @@ -740,14 +726,12 @@ TEST_F(basic_stl, single_pkt_bb_start_stop2) { streams.push_back(stream1); // stream - clean + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); - TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(port_id); - TrexStatelessDpStart * lpStartCmd1 = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + TrexStatelessDpStart * lpStartCmd1 = new TrexStatelessDpStart(port_id, 0, objs[0]->clone(), 10.0 /*sec */ ); t1.m_msg_queue.add_msg(lpStartCmd); @@ -795,12 +779,10 @@ TEST_F(basic_stl, single_pkt_bb_start_stop) { streams.push_back(stream1); // stream - clean + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); - TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(port_id); @@ -880,14 +862,13 @@ TEST_F(basic_stl, simple_prog4) { streams.push_back(stream2); - TrexStreamsCompiledObj comp_obj(0,1.0); + uint8_t port_id = 0; + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 20.0 /*sec */ ); - EXPECT_TRUE(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 20.0 ); - - - t1.m_msg = lpstart; + t1.m_msg = lpStartCmd; bool res=t1.init(); @@ -950,11 +931,10 @@ TEST_F(basic_stl, simple_prog3) { streams.push_back(stream2); - TrexStreamsCompiledObj comp_obj(0,1.0); - - EXPECT_TRUE(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 50.0 ); + uint8_t port_id = 0; + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 50.0 /*sec */ ); t1.m_msg = lpstart; @@ -1011,13 +991,10 @@ TEST_F(basic_stl, simple_prog2) { pcap.clone_packet_into_stream(stream2); streams.push_back(stream2); - - TrexStreamsCompiledObj comp_obj(0,1.0); - - EXPECT_TRUE(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10.0 ); - + uint8_t port_id = 0; + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); t1.m_msg = lpstart; @@ -1074,11 +1051,10 @@ TEST_F(basic_stl, simple_prog1) { streams.push_back(stream2); - TrexStreamsCompiledObj comp_obj(0,1.0); - - EXPECT_TRUE(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10.0 ); + uint8_t port_id = 0; + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); t1.m_msg = lpstart; @@ -1119,12 +1095,10 @@ TEST_F(basic_stl, single_pkt_burst1) { streams.push_back(stream1); - TrexStreamsCompiledObj comp_obj(0,1.0); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10.0 ); - + uint8_t port_id = 0; + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); t1.m_msg = lpstart; @@ -1170,11 +1144,9 @@ TEST_F(basic_stl, single_pkt) { // stream - clean - TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ ); + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); t1.m_msg = lpstart; @@ -1226,12 +1198,11 @@ TEST_F(basic_stl, multi_pkt1) { streams.push_back(stream2); - // stream - clean - TrexStreamsCompiledObj comp_obj(0,1.0); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10 ); + // stream - clean + uint8_t port_id = 0; + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); t1.m_msg = lpstart; @@ -1290,11 +1261,10 @@ TEST_F(basic_stl, multi_pkt2) { // stream - clean - TrexStreamsCompiledObj comp_obj(0,5.0); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10 ); + uint8_t port_id = 0; + std::vectorobjs; + assert(compile.compile(port_id, streams, objs, 1, 5.0)); + TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ ); t1.m_msg = lpstart; @@ -1336,11 +1306,10 @@ TEST_F(basic_stl, multi_burst1) { streams.push_back(stream1); - TrexStreamsCompiledObj comp_obj(0,1.0); - - assert(compile.compile(streams, comp_obj) ); - - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 40 ); + uint8_t port_id = 0; + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 40.0 /*sec */ ); t1.m_msg = lpstart; @@ -1370,10 +1339,9 @@ TEST_F(basic_stl, compile_bad_1) { streams.push_back(stream1); - TrexStreamsCompiledObj comp_obj(0,1.0); - std::string err_msg; - EXPECT_FALSE(compile.compile(streams, comp_obj, &err_msg)); + std::vectorobjs; + EXPECT_FALSE(compile.compile(0, streams, objs, 1, 1, &err_msg)); delete stream1; @@ -1403,10 +1371,12 @@ TEST_F(basic_stl, compile_bad_2) { streams.push_back(stream1); streams.push_back(stream2); - TrexStreamsCompiledObj comp_obj(0,1.0); + uint8_t port_id = 0; std::string err_msg; - EXPECT_FALSE(compile.compile(streams, comp_obj, &err_msg)); + std::vectorobjs; + EXPECT_FALSE(compile.compile(port_id, streams, objs, 1, 1, &err_msg)); + delete stream1; delete stream2; @@ -1482,10 +1452,10 @@ TEST_F(basic_stl, compile_bad_3) { streams.push_back(stream); /* compile */ - TrexStreamsCompiledObj comp_obj(0,1.0); - std::string err_msg; - EXPECT_FALSE(compile.compile(streams, comp_obj, &err_msg)); + std::vectorobjs; + EXPECT_FALSE(compile.compile(0, streams, objs, 1, 1, &err_msg)); + for (auto stream : streams) { delete stream; @@ -1534,11 +1504,11 @@ TEST_F(basic_stl, compile_with_warnings) { /* compile */ - TrexStreamsCompiledObj comp_obj(0,1.0); - std::string err_msg; - EXPECT_TRUE(compile.compile(streams, comp_obj, &err_msg)); - + std::vectorobjs; + EXPECT_TRUE(compile.compile(0, streams, objs, 1, 1, &err_msg)); + delete objs[0]; + EXPECT_TRUE(compile.get_last_compile_warnings().size() == 1); for (auto stream : streams) { @@ -1573,20 +1543,22 @@ TEST_F(basic_stl, compile_good_stream_id_compres) { streams.push_back(stream1); streams.push_back(stream2); - TrexStreamsCompiledObj comp_obj(0,1.0); - + uint8_t port_id = 0; std::string err_msg; - EXPECT_TRUE(compile.compile(streams, comp_obj, &err_msg)); + std::vectorobjs; + EXPECT_TRUE(compile.compile(port_id, streams, objs, 1, 1, &err_msg)); printf(" %s \n",err_msg.c_str()); - comp_obj.Dump(stdout); + objs[0]->Dump(stdout); + + EXPECT_EQ_UINT32(objs[0]->get_objects()[0].m_stream->m_stream_id,0); + EXPECT_EQ_UINT32(objs[0]->get_objects()[0].m_stream->m_next_stream_id,1); - EXPECT_EQ_UINT32(comp_obj.get_objects()[0].m_stream->m_stream_id,0); - EXPECT_EQ_UINT32(comp_obj.get_objects()[0].m_stream->m_next_stream_id,1); + EXPECT_EQ_UINT32(objs[0]->get_objects()[1].m_stream->m_stream_id,1); + EXPECT_EQ_UINT32(objs[0]->get_objects()[1].m_stream->m_next_stream_id,0); - EXPECT_EQ_UINT32(comp_obj.get_objects()[1].m_stream->m_stream_id,1); - EXPECT_EQ_UINT32(comp_obj.get_objects()[1].m_stream->m_next_stream_id,0); + delete objs[0]; delete stream1; delete stream2; @@ -1648,14 +1620,12 @@ TEST_F(basic_stl, dp_stop_event) { // stream - clean - TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/); + std::vectorobjs; + assert(compile.compile(port_id, streams, objs)); + TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 17, objs[0], 10.0 /*sec */ ); - assert(compile.compile(streams, comp_obj) ); - TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(port_id, 17, comp_obj.clone(), 10.0 /*sec */ ); - - - t1.m_msg = lpstart; + t1.m_msg = lpStartCmd; /* let me handle these */ DpToCpHandlerStopEvent handler(17); diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 10e863c5..0e45bf0b 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -128,10 +128,10 @@ TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration) TrexStreamsCompiler compiler; bool rc = compiler.compile(m_port_id, - get_dp_core_count(), - factor, streams, compiled_objs, + get_dp_core_count(), + factor, &fail_msg); if (!rc) { throw TrexRpcException(fail_msg); @@ -556,10 +556,10 @@ TrexStatelessPort::validate(void) { std::string fail_msg; bool rc = compiler.compile(m_port_id, - get_dp_core_count(), - 1.0, streams, compiled_objs, + get_dp_core_count(), + 1.0, &fail_msg); if (!rc) { throw TrexException(fail_msg); diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp index 36b165d1..d83e4ab6 100644 --- a/src/stateless/cp/trex_streams_compiler.cpp +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -370,10 +370,10 @@ TrexStreamsCompiler::pre_compile_check(const std::vector &streams, *************************************/ bool TrexStreamsCompiler::compile(uint8_t port_id, - uint8_t dp_core_count, - double factor, const std::vector &streams, std::vector &objs, + uint8_t dp_core_count, + double factor, std::string *fail_msg) { #if 0 diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index 93a63061..e193a749 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -85,10 +85,10 @@ public: * */ bool compile(uint8_t port_id, - uint8_t dp_core_count, - double factor, const std::vector &streams, std::vector &objs, + uint8_t dp_core_count = 1, + double factor = 1.0, std::string *fail_msg = NULL); -- cgit 1.2.3-korg