diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/bp_sim.cpp | 94 | ||||
-rwxr-xr-x | src/bp_sim.h | 98 | ||||
-rwxr-xr-x | src/common/captureFile.h | 2 | ||||
-rw-r--r-- | src/debug.cpp | 330 | ||||
-rw-r--r-- | src/debug.h | 42 | ||||
-rw-r--r-- | src/gtest/trex_stateless_gtest.cpp | 198 | ||||
-rwxr-xr-x | src/main.cpp | 80 | ||||
-rwxr-xr-x | src/main_dpdk.cpp | 624 | ||||
-rw-r--r-- | src/main_dpdk.h | 158 | ||||
-rwxr-xr-x | src/pal/linux/mbuf.cpp | 10 | ||||
-rwxr-xr-x | src/platform_cfg.cpp | 35 | ||||
-rwxr-xr-x | src/platform_cfg.h | 38 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 17 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmds.h | 2 | ||||
-rw-r--r-- | src/sim/trex_sim.h | 25 | ||||
-rw-r--r-- | src/sim/trex_sim_stateless.cpp | 190 | ||||
-rw-r--r-- | src/stateless/cp/trex_stateless_port.cpp | 21 | ||||
-rw-r--r-- | src/stateless/cp/trex_stateless_port.h | 17 | ||||
-rw-r--r-- | src/stateless/cp/trex_stream.h | 6 | ||||
-rw-r--r-- | src/stateless/cp/trex_stream_vm.cpp | 94 | ||||
-rw-r--r-- | src/stateless/cp/trex_stream_vm.h | 100 | ||||
-rw-r--r-- | src/stateless/dp/trex_stateless_dp_core.cpp | 34 | ||||
-rw-r--r-- | src/stateless/dp/trex_stream_node.h | 12 |
23 files changed, 1536 insertions, 691 deletions
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index 6342b7f3..31ce0440 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -66,7 +66,7 @@ void CGlobalMemory::Dump(FILE *fd){ int i=0; for (i=0; i<MBUF_SIZE; i++) { - if ( (i>MBUF_2048) && (i<MBUF_DP_FLOWS)){ + if ( (i>MBUF_9k) && (i<MBUF_DP_FLOWS)){ continue; } if ( i<TRAFFIC_MBUF_64 ){ @@ -95,6 +95,8 @@ void CGlobalMemory::set(const CPlatformMemoryYamlInfo &info,float mul){ m_mbuf[MBUF_512] += info.m_mbuf[TRAFFIC_MBUF_512]; m_mbuf[MBUF_1024] += info.m_mbuf[TRAFFIC_MBUF_1024]; m_mbuf[MBUF_2048] += info.m_mbuf[TRAFFIC_MBUF_2048]; + m_mbuf[MBUF_4096] += info.m_mbuf[TRAFFIC_MBUF_4096]; + m_mbuf[MBUF_9k] += info.m_mbuf[MBUF_9k]; } @@ -494,7 +496,10 @@ void CRteMemPool::dump(FILE *fd){ DUMP_MBUF("mbuf_256",m_mbuf_pool_256); DUMP_MBUF("mbuf_512",m_mbuf_pool_512); DUMP_MBUF("mbuf_1024",m_mbuf_pool_1024); - DUMP_MBUF("mbuf_2048",m_big_mbuf_pool); + DUMP_MBUF("mbuf_2048",m_mbuf_pool_2048); + DUMP_MBUF("mbuf_4096",m_mbuf_pool_4096); + DUMP_MBUF("mbuf_9k",m_mbuf_pool_9k); + } //////////////////////////////////////// @@ -506,12 +511,14 @@ void CGlobalInfo::free_pools(){ 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(lpmem->m_mbuf_pool_2048); + utl_rte_mempool_delete(lpmem->m_mbuf_pool_4096); + utl_rte_mempool_delete(lpmem->m_mbuf_pool_9k); } utl_rte_mempool_delete(m_mem_pool[0].m_mbuf_global_nodes); } @@ -531,12 +538,6 @@ void CGlobalInfo::init_pools(uint32_t rx_buffers){ lpmem= &m_mem_pool[i]; lpmem->m_pool_id=i; - lpmem->m_big_mbuf_pool = utl_rte_mempool_create("big-pkt-const", - (lp->get_2k_num_blocks()+rx_buffers), - CONST_MBUF_SIZE, - 32, - (i<<5)+ 1,i); - assert(lpmem->m_big_mbuf_pool); /* this include the packet from 0-64 this is for small packets */ lpmem->m_small_mbuf_pool =utl_rte_mempool_create("small-pkt-const", @@ -577,6 +578,26 @@ void CGlobalInfo::init_pools(uint32_t rx_buffers){ assert(lpmem->m_mbuf_pool_1024); + lpmem->m_mbuf_pool_2048=utl_rte_mempool_create("_2048-pkt-const", + lp->m_mbuf[MBUF_2048], + CONST_2048_MBUF_SIZE, + 32,(i<<5)+ 5,i); + + assert(lpmem->m_mbuf_pool_2048); + + lpmem->m_mbuf_pool_4096=utl_rte_mempool_create("_4096-pkt-const", + lp->m_mbuf[MBUF_4096], + CONST_4096_MBUF_SIZE, + 32,(i<<5)+ 5,i); + + assert(lpmem->m_mbuf_pool_4096); + + lpmem->m_mbuf_pool_9k=utl_rte_mempool_create("_9k-pkt-const", + lp->m_mbuf[MBUF_9k]+rx_buffers, + CONST_9k_MBUF_SIZE, + 32,(i<<5)+ 5,i); + + assert(lpmem->m_mbuf_pool_9k); } } @@ -1190,9 +1211,9 @@ void CPacketIndication::ProcessIpPacket(CPacketParser *parser, return; } - if ( m_packet->pkt_len > MAX_BUF_SIZE -FIRST_PKT_SIZE ){ + if ( m_packet->pkt_len > MAX_PKT_SIZE ){ m_cnt->m_tcp_udp_pkt_length_error++; - printf("ERROR packet is too big, not supported jumbo packets that larger than %d \n",MAX_BUF_SIZE); + printf("ERROR packet is too big, not supported jumbo packets that larger than %d \n",MAX_PKT_SIZE); return; } @@ -1200,9 +1221,6 @@ void CPacketIndication::ProcessIpPacket(CPacketParser *parser, m_packet->pkt_len = l3.m_ipv4->getTotalLength() + getIpOffset(); if (m_packet->pkt_len < 60) { m_packet->pkt_len = 60; } - - - m_cnt->m_valid_udp_tcp++; m_payload_len = l3.m_ipv4->getTotalLength() - (payload_offset_from_ip); m_payload = (uint8_t *)(packetBase +offset); @@ -3146,7 +3164,8 @@ int CNodeGenerator::open_file(std::string file_name, /* ser preview mode */ m_v_if->set_review_mode(preview_mode); m_v_if->open_file(file_name); - m_cnt = 0; + m_cnt = 0; + m_limit = 0; return (0); } @@ -3161,10 +3180,12 @@ int CNodeGenerator::close_file(CFlowGenListPerThread * thread){ int CNodeGenerator::update_stl_stats(CGenNodeStateless *node_sl){ m_cnt++; + #ifdef _DEBUG if ( m_preview_mode.getVMode() >2 ){ fprintf(stdout," %4lu ,", (ulong)m_cnt); node_sl->Dump(stdout); } + #endif return (0); } @@ -3179,6 +3200,10 @@ int CNodeGenerator::update_stats(CGenNode * node){ return (0); } +bool CNodeGenerator::has_limit_reached() { + /* do we have a limit and has it passed ? */ + return ( (m_limit > 0) && (m_cnt >= m_limit) ); +} bool CFlowGenListPerThread::Create(uint32_t thread_id, uint32_t core_id, @@ -3514,9 +3539,6 @@ int CNodeGenerator::flush_file(dsec_t max_time, } } - //#ifndef RTE_DPDK - //thread->check_msgs(); - //#endif uint8_t type=node->m_type; @@ -3524,16 +3546,21 @@ 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_mask_for_free() ) ) { thread->free_node(node); } else { node_sl->handle(thread); + + #ifdef TREX_SIM + update_stl_stats(node_sl); + if (has_limit_reached()) { + thread->m_stateless_dp_info.stop_traffic(node_sl->get_port_id(), false, 0); + } + #endif + } + }else{ if ( likely( type == CGenNode::FLOW_PKT ) ) { @@ -3974,9 +4001,11 @@ void CFlowGenListPerThread::check_msgs(void) { void CFlowGenListPerThread::start_stateless_simulation_file(std::string erf_file_name, - CPreviewMode &preview){ + CPreviewMode &preview, + uint64_t limit){ m_preview_mode = preview; m_node_gen.open_file(erf_file_name,&m_preview_mode); + m_node_gen.set_packet_limit(limit); } void CFlowGenListPerThread::stop_stateless_simulation_file(){ @@ -3987,7 +4016,6 @@ void CFlowGenListPerThread::start_stateless_daemon_simulation(){ m_cur_time_sec = 0; m_stateless_dp_info.run_once(); - } @@ -4677,13 +4705,11 @@ int CErfIFStl::send_node(CGenNode * _no_to_use){ rte_pktmbuf_free(m); } - - BP_ASSERT(m_writer); - bool res=m_writer->write_packet(m_raw); - - - BP_ASSERT(res); + + int rc = write_pkt(m_raw); + BP_ASSERT(rc == 0); } + return (0); } @@ -4721,13 +4747,9 @@ int CErfIF::send_node(CGenNode * node){ //utl_DumpBuffer(stdout,p, 12,0); - BP_ASSERT(m_writer); - - bool res=m_writer->write_packet(m_raw); - - //utl_DumpBuffer(stdout,m_raw->raw,m_raw->pkt_len,0); + int rc = write_pkt(m_raw); + BP_ASSERT(rc == 0); - BP_ASSERT(res); rte_pktmbuf_free(m); } return (0); diff --git a/src/bp_sim.h b/src/bp_sim.h index da8e8780..b9a42027 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -411,10 +411,6 @@ public: #define CONST_NB_MBUF 16380 - -#define MAX_BUF_SIZE (2048) -#define CONST_MBUF_SIZE (MAX_BUF_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) - /* this is the first small part of the packet that we manipulate */ #define FIRST_PKT_SIZE 64 #define CONST_SMALL_MBUF_SIZE (FIRST_PKT_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) @@ -424,13 +420,19 @@ public: #define _256_MBUF_SIZE 256 #define _512_MBUF_SIZE 512 #define _1024_MBUF_SIZE 1024 +#define _2048_MBUF_SIZE 2048 +#define _4096_MBUF_SIZE 4096 +#define MAX_PKT_ALIGN_BUF_9K (9*1024+64) +#define MBUF_PKT_PREFIX ( sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM ) - -#define CONST_128_MBUF_SIZE (128 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) -#define CONST_256_MBUF_SIZE (256 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) -#define CONST_512_MBUF_SIZE (512 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) -#define CONST_1024_MBUF_SIZE (1024 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) +#define CONST_128_MBUF_SIZE (128 + MBUF_PKT_PREFIX ) +#define CONST_256_MBUF_SIZE (256 + MBUF_PKT_PREFIX ) +#define CONST_512_MBUF_SIZE (512 + MBUF_PKT_PREFIX) +#define CONST_1024_MBUF_SIZE (1024 + MBUF_PKT_PREFIX) +#define CONST_2048_MBUF_SIZE (2048 + MBUF_PKT_PREFIX) +#define CONST_4096_MBUF_SIZE (4096 + MBUF_PKT_PREFIX) +#define CONST_9k_MBUF_SIZE (MAX_PKT_ALIGN_BUF_9K + MBUF_PKT_PREFIX) class CPreviewMode { @@ -774,6 +776,7 @@ public: uint16_t m_run_flags; uint8_t m_mac_splitter; uint8_t m_l_pkt_mode; + uint16_t m_debug_pkt_proto; trex_run_mode_e m_run_mode; @@ -1118,9 +1121,13 @@ public: m = _rte_pktmbuf_alloc(m_mbuf_pool_512); }else if (size < _1024_MBUF_SIZE) { m = _rte_pktmbuf_alloc(m_mbuf_pool_1024); + }else if (size < _2048_MBUF_SIZE) { + m = _rte_pktmbuf_alloc(m_mbuf_pool_2048); + }else if (size < _4096_MBUF_SIZE) { + m = _rte_pktmbuf_alloc(m_mbuf_pool_4096); }else{ - assert(size<MAX_BUF_SIZE); - m = _rte_pktmbuf_alloc(m_big_mbuf_pool); + assert(size<MAX_PKT_ALIGN_BUF_9K); + m = _rte_pktmbuf_alloc(m_mbuf_pool_9k); } return (m); } @@ -1129,21 +1136,22 @@ public: return ( _rte_pktmbuf_alloc(m_small_mbuf_pool) ); } - inline rte_mbuf_t * pktmbuf_alloc_big(){ - return ( _rte_pktmbuf_alloc(m_big_mbuf_pool) ); - } void dump(FILE *fd); void dump_in_case_of_error(FILE *fd); public: - rte_mempool_t * m_big_mbuf_pool; /* pool for const packets */ rte_mempool_t * m_small_mbuf_pool; /* pool for start packets */ + rte_mempool_t * m_mbuf_pool_128; rte_mempool_t * m_mbuf_pool_256; rte_mempool_t * m_mbuf_pool_512; rte_mempool_t * m_mbuf_pool_1024; + rte_mempool_t * m_mbuf_pool_2048; + rte_mempool_t * m_mbuf_pool_4096; + rte_mempool_t * m_mbuf_pool_9k; + rte_mempool_t * m_mbuf_global_nodes; uint32_t m_pool_id; }; @@ -1162,11 +1170,7 @@ public: return ( m_mem_pool[socket].pktmbuf_alloc_small() ); } - static inline rte_mbuf_t * pktmbuf_alloc_big(socket_id_t socket){ - return ( m_mem_pool[socket].pktmbuf_alloc_big() ); - } - - + /** * try to allocate small buffers too @@ -1832,7 +1836,7 @@ public: protected: - void fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir); + virtual void fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir); CFileWriterBase * m_writer; CCapPktRaw * m_raw; @@ -1846,6 +1850,41 @@ public: virtual int send_node(CGenNode * node); }; +/** + * same as regular STL but no I/O (dry run) + * + * @author imarom (07-Jan-16) + */ +class CErfIFStlNull : public CErfIFStl { +public: + + virtual int open_file(std::string file_name) { + return (0); + } + + virtual int write_pkt(CCapPktRaw *pkt_raw) { + return (0); + } + + virtual int close_file(void) { + return (0); + } + + virtual void fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir) { + + } + + virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, uint8_t * p){ + return (0); + } + + + virtual int flush_tx_queue(void){ + return (0); + + } + +}; static inline int fill_pkt(CCapPktRaw * raw,rte_mbuf_t * m){ @@ -1929,6 +1968,12 @@ public: add_node(node); } + /** + * set packet limit for the generator + */ + void set_packet_limit(uint64_t limit) { + m_limit = limit; + } void DumpHist(FILE *fd){ fprintf(fd,"\n"); @@ -1947,7 +1992,7 @@ private: } int update_stats(CGenNode * node); int update_stl_stats(CGenNodeStateless *node_sl); - + bool has_limit_reached(); FORCE_NO_INLINE bool handle_slow_messages(uint8_t type, CGenNode * node, @@ -1963,6 +2008,7 @@ public: CFlowGenListPerThread * m_parent; CPreviewMode m_preview_mode; uint64_t m_cnt; + uint64_t m_limit; CTimeHistogram m_realtime_his; }; @@ -3095,7 +3141,11 @@ public: SIZE_512 = 512, SIZE_1024 = 1024, SIZE_2048 = 2048, - MASK_SIZE =6 + SIZE_4096 = 4096, + SIZE_8192 = 8192, + SIZE_16384 = 16384, + + MASK_SIZE =9 }; void clear(){ @@ -3477,7 +3527,7 @@ public: void start_stateless_daemon_simulation(); /* open a file for simulation */ - void start_stateless_simulation_file(std::string erf_file_name,CPreviewMode &preview); + void start_stateless_simulation_file(std::string erf_file_name,CPreviewMode &preview, uint64_t limit = 0); /* close a file for simulation */ void stop_stateless_simulation_file(); diff --git a/src/common/captureFile.h b/src/common/captureFile.h index 027f1fcf..16a6120b 100755 --- a/src/common/captureFile.h +++ b/src/common/captureFile.h @@ -35,7 +35,7 @@ typedef enum capture_type { LAST_TYPE } capture_type_e; -#define MAX_PKT_SIZE (2048) +#define MAX_PKT_SIZE (9*1024+22) /* 9k IP +14+4 FCS +some spare */ #define READER_MAX_PACKET_SIZE MAX_PKT_SIZE diff --git a/src/debug.cpp b/src/debug.cpp new file mode 100644 index 00000000..e5e207e1 --- /dev/null +++ b/src/debug.cpp @@ -0,0 +1,330 @@ +/* + Copyright (c) 2016-2016 Cisco Systems, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// DPDK c++ issue +#define UINT8_MAX 255 +#define UINT16_MAX 0xFFFF +// DPDK c++ issue + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <rte_mbuf.h> +#include <rte_pci.h> +#include <rte_ethdev.h> +#include <common/basic_utils.h> +#include "main_dpdk.h" +#include "debug.h" + +const uint8_t udp_pkt[] = { + 0x00,0x00,0x00,0x01,0x00,0x00, + 0x00,0x00,0x00,0x01,0x00,0x00, + 0x08,0x00, + + 0x45,0x00,0x00,0x81, + 0xaf,0x7e,0x00,0x00, + 0xfe,0x06,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 +}; + +CTrexDebug::CTrexDebug(CPhyEthIF m_ports_arg[12], int max_ports) { + m_test = NULL; + m_ports = m_ports_arg; + m_max_ports = max_ports; +} + +int CTrexDebug::rcv_send(int port, int queue_id) { + CPhyEthIF * lp = &m_ports[port]; + rte_mbuf_t * rx_pkts[32]; + printf(" test rx port:%d queue:%d \n",port,queue_id); + printf(" --------------\n"); + uint16_t cnt = lp->rx_burst(queue_id,rx_pkts,32); + int i; + + for (i=0; i < (int)cnt; i++) { + rte_mbuf_t * m = rx_pkts[i]; + int pkt_size = rte_pktmbuf_pkt_len(m); + char *p = rte_pktmbuf_mtod(m, char*); + utl_DumpBuffer(stdout, p, pkt_size, 0); + rte_pktmbuf_free(m); + } + return 0; +} + +int CTrexDebug::rcv_send_all(int queue_id) { + int i; + for (i=0; i<m_max_ports; i++) { + rcv_send(i,queue_id); + } + return 0; +} + +// For playing around, and testing packet sending in debug mode +rte_mbuf_t *CTrexDebug::create_test_pkt(int pkt_type) { + uint8_t proto; + int pkt_size = 0; + // uint8_t dst_mac[6] = {0xd4, 0x8c, 0xb5, 0xc9, 0x54, 0x2b}; + uint8_t dst_mac[6] = {0x79, 0xa2, 0xe6, 0xd5, 0x39, 0x25}; + uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02}; + uint16_t l2_proto = 0x0008; + uint8_t ip_header[] = { + 0x45,0x02,0x00,0x30, + 0x00,0x00,0x40,0x00, + 0xff,0x01,0xbd,0x04, + 0x10,0x0,0x0,0x1, //SIP + 0x30,0x0,0x0,0x1, //DIP + // 0x82, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // IP option. change 45 to 48 (header len) if using it. + }; + uint8_t udp_header[] = {0x11, 0x11, 0x11,0x11, 0x00, 0x6d, 0x00, 0x00}; + uint8_t udp_data[] = {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 + }; + uint8_t tcp_header[] = {0xab, 0xcd, 0x00, 0x80, // src, dst ports + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // seq num, ack num + 0x50, 0x00, 0xff, 0xff, // Header size, flags, window size + 0x00, 0x00, 0x00, 0x00, // checksum ,urgent pointer + }; + + uint8_t tcp_data[] = {0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5}; + + uint8_t icmp_header[] = { + 0x08, 0x00, + 0xb8, 0x21, //checksum + 0xaa, 0xbb, // id + 0x00, 0x01, // Sequence number + }; + uint8_t icmp_data[] = { + 0xd6, 0x6e, 0x64, 0x34, // magic + 0x6a, 0xad, 0x0f, 0x00, //64 bit counter + 0x00, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, 0x00, 0x00 // seq + }; + + switch (pkt_type) { + case 1: + proto = IPPROTO_ICMP; + pkt_size = 14 + sizeof(ip_header) + sizeof(icmp_header) + sizeof (icmp_data); + break; + case 2: + proto = IPPROTO_UDP; + pkt_size = 14 + sizeof(ip_header) + sizeof(udp_header) + sizeof (udp_data); + break; + case 3: + proto = IPPROTO_TCP; + pkt_size = 14 + sizeof(ip_header) + sizeof(tcp_header) + sizeof (tcp_data); + break; + default: + return NULL; + } + + rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(0, pkt_size); + if ( unlikely(m == 0) ) { + printf("ERROR no packets \n"); + return (NULL); + } + char *p = rte_pktmbuf_append(m, pkt_size); + assert(p); + + /* set pkt data */ + memcpy(p, dst_mac, sizeof(dst_mac)); p += sizeof(dst_mac); + memcpy(p, src_mac, sizeof(src_mac)); p += sizeof(src_mac); + memcpy(p, &l2_proto, sizeof(l2_proto)); p += sizeof(l2_proto); + struct IPHeader *ip = (IPHeader *)p; + memcpy(p, ip_header, sizeof(ip_header)); p += sizeof(ip_header); + ip->setProtocol(proto); + ip->setTotalLength(pkt_size - 14); + + struct TCPHeader *tcp = (TCPHeader *)p; + struct ICMPHeader *icmp= (ICMPHeader *)p; + switch (pkt_type) { + case 1: + memcpy(p, icmp_header, sizeof(icmp_header)); p += sizeof(icmp_header); + memcpy(p, icmp_data, sizeof(icmp_data)); p += sizeof(icmp_data); + icmp->updateCheckSum(sizeof(icmp_header) + sizeof(icmp_data)); + break; + case 2: + memcpy(p, udp_header, sizeof(udp_header)); p += sizeof(udp_header); + memcpy(p, udp_data, sizeof(udp_data)); p += sizeof(udp_data); + break; + case 3: + memcpy(p, tcp_header, sizeof(tcp_header)); p += sizeof(tcp_header); + memcpy(p, tcp_data, sizeof(tcp_data)); p += sizeof(tcp_data); + tcp->setSynFlag(true); + printf("Sending TCP header:"); + tcp->dump(stdout); + break; + default: + return NULL; + } + + ip->updateCheckSum(); + return m; +} + +rte_mbuf_t *CTrexDebug::create_pkt(uint8_t *pkt, int pkt_size) { + rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(0, pkt_size); + if ( unlikely(m == 0) ) { + printf("ERROR no packets \n"); + return 0; + } + + char *p = rte_pktmbuf_append(m, pkt_size); + assert(p); + /* set pkt data */ + memcpy(p, pkt, pkt_size); + return m; +} + +rte_mbuf_t *CTrexDebug::create_pkt_indirect(rte_mbuf_t *m, uint32_t new_pkt_size){ + rte_mbuf_t *d = CGlobalInfo::pktmbuf_alloc(0, 60); + assert(d); + + rte_pktmbuf_attach(d, m); + d->data_len = new_pkt_size; + d->pkt_len = new_pkt_size; + return d; +} + +rte_mbuf_t *CTrexDebug::create_udp_9k_pkt() { + rte_mbuf_t *m; + uint16_t pkt_size = 9*1024+21; + uint8_t *p = (uint8_t *)malloc(9*1024+22); + assert(p); + memset(p, 0x55, pkt_size); + memcpy(p, (uint8_t*)udp_pkt, sizeof(udp_pkt)); + m = create_pkt(p, pkt_size); + free(p); + return m; +} + +int CTrexDebug::test_send_pkts(rte_mbuf_t *m, uint16_t queue_id, int num_pkts, int port) { + CPhyEthIF * lp = &m_ports[port]; + rte_mbuf_t * tx_pkts[32]; + if (num_pkts > 32) { + num_pkts = 32; + } + + int i; + for (i=0; i < num_pkts; i++) { + rte_mbuf_refcnt_update(m, 1); + tx_pkts[i] = m; + } + uint16_t res = lp->tx_burst(queue_id, tx_pkts, num_pkts); + if ((num_pkts - res) > 0) { + m_test_drop += (num_pkts - res); + } + return (0); +} + +int CTrexDebug::set_promisc_all(bool enable) { + int i; + for (i=0; i < m_max_ports; i++) { + CPhyEthIF *_if = &m_ports[i]; + _if->set_promiscuous(enable); + } + + return 0; +} + +int CTrexDebug::test_send(uint pkt_type) { + set_promisc_all(true); + rte_mbuf_t *m, *d; + if (pkt_type < 1 || pkt_type > 4) { + printf("Unsupported packet type %d\n", pkt_type); + printf("Supported packet types are: %d(ICMP), %d(UDP), %d(TCP) %d(9k UDP)\n", 1, 2, 3, 4); + exit(-1); + } + + if (pkt_type == 4) { + m = create_udp_9k_pkt(); + assert (m); + d = create_pkt_indirect(m, 9*1024+18); + } else { + d = create_test_pkt(pkt_type); + } + if (d == NULL) { + printf("Packet creation failed\n"); + exit(-1); + } + + printf("Sending packet:\n"); + utl_DumpBuffer(stdout, rte_pktmbuf_mtod(d, char *), 64, 0); + + test_send_pkts(d, 0, 2, 0); + test_send_pkts(d, 0, 1, 1); + + delay(1000); + + printf(" ---------\n"); + printf(" rx queue 0 \n"); + printf(" ---------\n"); + rcv_send_all(0); + printf("\n\n"); + + printf(" ---------\n"); + printf(" rx queue 1 \n"); + printf(" ---------\n"); + rcv_send_all(1); + printf(" ---------\n"); + + delay(1000); + + int j=0; + for (j=0; j<m_max_ports; j++) { + CPhyEthIF * lp=&m_ports[j]; + printf(" port : %d \n",j); + printf(" ----------\n"); + lp->update_counters(); + lp->get_stats().Dump(stdout); + lp->dump_stats_extended(stdout); + } + + return (0); +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 00000000..fe37c186 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,42 @@ +/* +Copyright (c) 2016-2016 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef _TREX_DEBUG_H +#define _TREX_DEBUG_H +#include "mbuf.h" + +class CTrexDebug { + rte_mbuf_t *m_test; + uint64_t m_test_drop; + CPhyEthIF *m_ports; + uint32_t m_max_ports; + + int rcv_send(int port,int queue_id); + int rcv_send_all(int queue_id); + rte_mbuf_t *create_pkt(uint8_t *pkt,int pkt_size); + rte_mbuf_t *create_pkt_indirect(rte_mbuf_t *m, uint32_t new_pkt_size); + rte_mbuf_t *create_udp_pkt(); + rte_mbuf_t *create_udp_9k_pkt(); + int set_promisc_all(bool enable); + int test_send_pkts(rte_mbuf_t *, uint16_t queue_id, int pkt, int port); + rte_mbuf_t *create_test_pkt(int proto); + + public: + CTrexDebug(CPhyEthIF *m_ports_arg, int max_ports); + int test_send(uint pkt_type); +}; + +#endif diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 73b7536a..70f397b1 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -22,6 +22,7 @@ limitations under the License. #include "bp_sim.h" #include <common/gtest.h> #include <common/basic_utils.h> +#include <trex_stateless.h> #include <trex_stateless_dp_core.h> #include <trex_stateless_messaging.h> #include <trex_streams_compiler.h> @@ -1027,6 +1028,203 @@ TEST_F(basic_vm, vm_syn_attack) { } +void run_vm_program( StreamVm & vm, + std::string input_pcap_file, + std::string out_file_name, + int num_pkts + ){ + + CPcapLoader pcap; + pcap.load_pcap_file(input_pcap_file,0); + + printf(" packet size : %lu \n",(ulong)pcap.m_raw.pkt_len); + vm.compile(pcap.m_raw.pkt_len); + + StreamVmDp * lpDpVm =vm.generate_dp_object(); + + uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size(); + + printf (" program size : %lu \n",(ulong)program_size); + + vm.Dump(stdout); + + std::string out_file_full ="exp/"+out_file_name +".pcap"; + std::string out_file_ex_full ="exp/"+out_file_name +"-ex.pcap"; + + CFileWriterBase * lpWriter=CCapWriterFactory::CreateWriter(LIBPCAP,(char *)out_file_full.c_str()); + assert(lpWriter); + + + StreamDPVmInstructionsRunner runner; + + uint32_t random_per_thread=0; + + int i; + for (i=0; i<num_pkts; i++) { + + runner.run(&random_per_thread, + lpDpVm->get_program_size(), + lpDpVm->get_program(), + lpDpVm->get_bss(), + (uint8_t*)pcap.m_raw.raw); + uint16_t new_pkt_size=runner.get_new_pkt_size(); + assert(new_pkt_size>0); + if (new_pkt_size ==0) { + assert(lpWriter->write_packet(&pcap.m_raw)); + }else{ + /* we can only reduce */ + if (new_pkt_size>pcap.m_raw.pkt_len) { + new_pkt_size=pcap.m_raw.pkt_len; + } + CCapPktRaw np(new_pkt_size); + np.time_sec = pcap.m_raw.time_sec; + np.time_nsec = pcap.m_raw.time_nsec; + np.pkt_cnt = pcap.m_raw.pkt_cnt; + memcpy(np.raw,pcap.m_raw.raw,new_pkt_size); + assert(lpWriter->write_packet(&np)); + } + } + + delete lpWriter; + + CErfCmp cmp; + delete lpDpVm; + + bool res1=cmp.compare(out_file_full.c_str() ,out_file_ex_full.c_str()); + EXPECT_EQ(1, res1?1:0); +} + + +TEST_F(basic_vm, vm_inc_size_64_128) { + + StreamVm vm; + + vm.add_instruction( new StreamVmInstructionFlowMan( "rand_pkt_size_var", + 2, // size var must be 16bit size + StreamVmInstructionFlowMan::FLOW_VAR_OP_INC, + 127, + 128, + 256)); + + vm.add_instruction( new StreamVmInstructionChangePktSize( "rand_pkt_size_var")); + + /* src ip */ + /*14+ 2 , remove the */ + + vm.add_instruction( new StreamVmInstructionWriteToPkt( "rand_pkt_size_var",16, -14,true) + ); + + vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) ); + + /* update UDP length */ + vm.add_instruction( new StreamVmInstructionWriteToPkt( "rand_pkt_size_var",32+6, -(14+20),true) + ); + + run_vm_program(vm,"stl/udp_1518B_no_crc.pcap","stl_vm_inc_size_64_128",20); +} + +TEST_F(basic_vm, vm_random_size_64_128) { + + StreamVm vm; + srand(0x1234); + + vm.add_instruction( new StreamVmInstructionFlowMan( "rand_pkt_size_var", + 2, // size var must be 16bit size + StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM, + 0, + 128, + 256)); + + vm.add_instruction( new StreamVmInstructionChangePktSize( "rand_pkt_size_var")); + + /* src ip */ + /*14+ 2 , remove the */ + + vm.add_instruction( new StreamVmInstructionWriteToPkt( "rand_pkt_size_var",16, -14,true) + ); + + vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) ); + + /* update UDP length */ + vm.add_instruction( new StreamVmInstructionWriteToPkt( "rand_pkt_size_var",32+6, -(14+20),true) + ); + + + run_vm_program(vm,"stl/udp_1518B_no_crc.pcap","stl_vm_rand_size_64_128",20); + +} + + + +/* should have exception packet size is smaller than range */ +TEST_F(basic_vm, vm_random_size_64_127_128) { + + StreamVm vm; + srand(0x1234); + + vm.add_instruction( new StreamVmInstructionFlowMan( "rand_pkt_size_var", + 2, // size var must be 16bit size + StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM, + 127, + 128, + 256)); + + vm.add_instruction( new StreamVmInstructionChangePktSize( "rand_pkt_size_var")); + + /* src ip */ + /*14+ 2 , remove the */ + + vm.add_instruction( new StreamVmInstructionWriteToPkt( "rand_pkt_size_var",16, -14,true) + ); + + vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) ); + + /* update UDP length */ + vm.add_instruction( new StreamVmInstructionWriteToPkt( "rand_pkt_size_var",32+6, -(14+20),true) + ); + + bool fail=false; + + try { + run_vm_program(vm,"stl/udp_64B_no_crc.pcap","stl_vm_rand_size_64B_127_128",20); + } catch (const TrexException &ex) { + fail=true; + } + + EXPECT_EQ(true, fail); + +} + + +TEST_F(basic_vm, vm_random_size_500b_0_9k) { + + StreamVm vm; + srand(0x1234); + + vm.add_instruction( new StreamVmInstructionFlowMan( "rand_pkt_size_var", + 2, // size var must be 16bit size + StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM, + 0, + 0, + 9*1024)); + + vm.add_instruction( new StreamVmInstructionChangePktSize( "rand_pkt_size_var")); + + /* src ip */ + /*14+ 2 , remove the */ + + vm.add_instruction( new StreamVmInstructionWriteToPkt( "rand_pkt_size_var",16, -14,true) + ); + + vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) ); + + /* update UDP length */ + vm.add_instruction( new StreamVmInstructionWriteToPkt( "rand_pkt_size_var",32+6, -(14+20),true) + ); + + run_vm_program(vm,"stl/udp_594B_no_crc.pcap","stl_vm_rand_size_512B_64_128",10); + +} diff --git a/src/main.cpp b/src/main.cpp index ba6e258a..a2d06067 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ limitations under the License. #include "bp_sim.h" #include "os_time.h" +#include <unordered_map> #include <string> #include <common/arg/SimpleGlob.h> @@ -35,7 +36,8 @@ using namespace std; // An enum for all the option types enum { OPT_HELP, OPT_CFG, OPT_NODE_DUMP, OP_STATS, OPT_FILE_OUT, OPT_UT, OPT_PCAP, OPT_IPV6, OPT_MAC_FILE, - OPT_SL, OPT_DP_CORE_COUNT, OPT_DP_CORE_INDEX}; + OPT_SL, OPT_DP_CORE_COUNT, OPT_DP_CORE_INDEX, OPT_LIMIT, + OPT_DRY_RUN}; @@ -73,14 +75,13 @@ static CSimpleOpt::SOption parser_options[] = { OPT_SL, "--sl", SO_NONE }, { OPT_DP_CORE_COUNT, "--cores", SO_REQ_SEP }, { OPT_DP_CORE_INDEX, "--core_index", SO_REQ_SEP }, + { OPT_LIMIT, "--limit", SO_REQ_SEP }, + { OPT_DRY_RUN, "--dry", SO_NONE }, SO_END_OF_OPTIONS }; - - - static int usage(){ printf(" Usage: bp_sim [OPTION] -f cfg.yaml -o outfile.erf \n"); @@ -119,9 +120,7 @@ static int usage(){ static int parse_options(int argc, char *argv[], CParserOption* po, - opt_type_e &type, - int &dp_core_count, - int &dp_core_index) { + std::unordered_map<std::string, int> ¶ms) { CSimpleOpt args(argc, argv, parser_options); @@ -131,16 +130,13 @@ static int parse_options(int argc, po->preview.setFileWrite(true); /* by default - type is stateful */ - type = OPT_TYPE_SF; - - dp_core_count = 1; - dp_core_index = 0; + params["type"] = OPT_TYPE_SF; while ( args.Next() ){ if (args.LastError() == SO_SUCCESS) { switch (args.OptionId()) { case OPT_UT : - type = OPT_TYPE_GTEST; + params["type"] = OPT_TYPE_GTEST; return (0); break; @@ -149,7 +145,7 @@ static int parse_options(int argc, return -1; case OPT_SL: - type = OPT_TYPE_SL; + params["type"] = OPT_TYPE_SL; break; case OPT_CFG: @@ -179,11 +175,19 @@ static int parse_options(int argc, break; case OPT_DP_CORE_COUNT: - dp_core_count = atoi(args.OptionArg()); + params["dp_core_count"] = atoi(args.OptionArg()); break; case OPT_DP_CORE_INDEX: - dp_core_index = atoi(args.OptionArg()); + params["dp_core_index"] = atoi(args.OptionArg()); + break; + + case OPT_LIMIT: + params["limit"] = atoi(args.OptionArg()); + break; + + case OPT_DRY_RUN: + params["dry"] = 1; break; default: @@ -215,16 +219,18 @@ static int parse_options(int argc, } } - if (dp_core_count != -1) { - if ( (dp_core_count < 1) || (dp_core_count > 8) ) { + /* did the user configure dp core count or dp core index ? */ + + if (params.count("dp_core_count") > 0) { + if (!in_range(params["dp_core_count"], 1, 8)) { printf("dp core count must be a value between 1 and 8\n"); return (-1); } } - if (dp_core_index != -1) { - if ( (dp_core_index < 0) || (dp_core_index >= dp_core_count) ) { - printf("dp core count must be a value between 0 and cores - 1\n"); + if (params.count("dp_core_index") > 0) { + if (!in_range(params["dp_core_index"], 0, params["dp_core_count"] - 1)) { + printf("dp core index must be a value between 0 and cores - 1\n"); return (-1); } } @@ -235,14 +241,14 @@ static int parse_options(int argc, int main(int argc , char * argv[]){ - opt_type_e type; - int dp_core_count; - int dp_core_index; + std::unordered_map<std::string, int> params; - if ( parse_options(argc, argv, &CGlobalInfo::m_options , type, dp_core_count, dp_core_index) != 0) { + if ( parse_options(argc, argv, &CGlobalInfo::m_options , params) != 0) { exit(-1); } + opt_type_e type = (opt_type_e) params["type"]; + switch (type) { case OPT_TYPE_GTEST: { @@ -259,7 +265,31 @@ int main(int argc , char * argv[]){ case OPT_TYPE_SL: { SimStateless &st = SimStateless::get_instance(); - return st.run(CGlobalInfo::m_options.cfg_file, CGlobalInfo::m_options.out_file, 2, dp_core_count, dp_core_index); + + if (params.count("dp_core_count") == 0) { + params["dp_core_count"] = 1; + } + + if (params.count("dp_core_index") == 0) { + params["dp_core_index"] = -1; + } + + if (params.count("limit") == 0) { + params["limit"] = 5000; + } + + if (params.count("dry") == 0) { + params["dry"] = 0; + } + + return st.run(CGlobalInfo::m_options.cfg_file, + CGlobalInfo::m_options.out_file, + 2, + params["dp_core_count"], + params["dp_core_index"], + params["limit"], + (params["dry"] == 1) + ); } } } diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 0d534b2e..d3dcb0c5 100755 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -4,7 +4,7 @@ */ /* -Copyright (c) 2015-2015 Cisco Systems, Inc. +Copyright (c) 2015-2016 Cisco Systems, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -79,6 +79,8 @@ extern "C" { #include "msg_manager.h" #include "platform_cfg.h" #include "latency.h" +#include "main_dpdk.h" +#include "debug.h" #include <internal_api/trex_platform_api.h> @@ -119,8 +121,8 @@ static inline int get_is_latency_thread_enable(){ } struct port_cfg_t; -class CPhyEthIF; -class CPhyEthIFStats ; +//class CPhyEthIF; +//class CPhyEthIFStats ; class CTRexExtendedDriverBase { public: @@ -307,6 +309,27 @@ private: uint8_t ttl); }; +class CTRexExtendedDriverBaseVIC : public CTRexExtendedDriverBase40G { +public: + CTRexExtendedDriverBaseVIC(){ + } + + static CTRexExtendedDriverBase * create(){ + return ( new CTRexExtendedDriverBaseVIC() ); + } + + virtual bool is_hardware_filter_is_supported(){ + return (false); + } + + bool flow_control_disable_supported(){return false;} + + virtual void update_configuration(port_cfg_t * cfg); + +}; + + + typedef CTRexExtendedDriverBase * (*create_object_t) (void); @@ -361,7 +384,7 @@ private: register_driver(std::string("rte_em_pmd"),CTRexExtendedDriverBase1GVm::create); register_driver(std::string("rte_vmxnet3_pmd"),CTRexExtendedDriverBase1GVm::create); register_driver(std::string("rte_virtio_pmd"),CTRexExtendedDriverBase1GVm::create); - register_driver(std::string("rte_enic_pmd"),CTRexExtendedDriverBase1GVm::create); + register_driver(std::string("rte_enic_pmd"),CTRexExtendedDriverBaseVIC::create); @@ -481,8 +504,8 @@ enum { OPT_HELP, OPT_VLAN, OPT_VIRT_ONE_TX_RX_QUEUE, OPT_PREFIX, - OPT_MAC_SPLIT - + OPT_MAC_SPLIT, + OPT_SEND_DEBUG_PKT }; @@ -541,6 +564,7 @@ static CSimpleOpt::SOption parser_options[] = { OPT_VIRT_ONE_TX_RX_QUEUE, "--vm-sim", SO_NONE }, { OPT_PREFIX, "--prefix", SO_REQ_SEP }, { OPT_MAC_SPLIT, "--mac-spread", SO_REQ_SEP }, + { OPT_SEND_DEBUG_PKT, "--send-debug-pkt", SO_REQ_SEP }, SO_END_OF_OPTIONS }; @@ -594,6 +618,9 @@ static int usage(){ printf(" -m : factor of bandwidth \n"); printf(" \n"); + printf(" --send-debug-pkt [proto] : Do not run traffic generator. Just send debug packet and dump receive queue."); + printf(" Supported protocols are 1 for icmp, 2 for UDP, 3 for TCP, 4 for 9K UDP\n"); + printf(" \n"); printf(" -k [sec] : run latency test before starting the test. it will wait for x sec sending packet and x sec after that \n"); printf(" \n"); @@ -876,6 +903,12 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t po->preview.setDestMacSplit(true); break; + case OPT_SEND_DEBUG_PKT: + sscanf(args.OptionArg(),"%d", &tmp_data); + po->m_debug_pkt_proto = (uint8_t)tmp_data; + break; + + default: usage(); return -1; @@ -1017,7 +1050,7 @@ struct port_cfg_t { m_tx_conf.tx_thresh.wthresh = TX_WTHRESH; m_port_conf.rxmode.jumbo_frame=1; - m_port_conf.rxmode.max_rx_pkt_len =2000; + m_port_conf.rxmode.max_rx_pkt_len =9*1024+22; m_port_conf.rxmode.hw_strip_crc=1; } @@ -1111,31 +1144,6 @@ typedef struct cnt_name_ { #define MY_REG(a) {a,(char *)#a} - -class CPhyEthIFStats { - -public: - uint64_t ipackets; /**< Total number of successfully received packets. */ - uint64_t ibytes; /**< Total number of successfully received bytes. */ - - uint64_t f_ipackets; /**< Total number of successfully received packets - filter SCTP*/ - uint64_t f_ibytes; /**< Total number of successfully received bytes. - filter SCTP */ - - uint64_t opackets; /**< Total number of successfully transmitted packets.*/ - uint64_t obytes; /**< Total number of successfully transmitted bytes. */ - - uint64_t ierrors; /**< Total number of erroneous received packets. */ - uint64_t oerrors; /**< Total number of failed transmitted packets. */ - uint64_t imcasts; /**< Total number of multicast received packets. */ - uint64_t rx_nombuf; /**< Total number of RX mbuf allocation failures. */ - - -public: - void Clear(); - void Dump(FILE *fd); - void DumpAll(FILE *fd); -}; - void CPhyEthIFStats::Clear(){ ipackets =0; @@ -1184,165 +1192,6 @@ void CPhyEthIFStats::Dump(FILE *fd){ DP_A(rx_nombuf); } - - -class CPhyEthIF { -public: - CPhyEthIF (){ - m_port_id=0; - m_rx_queue=0; - } - bool Create(uint8_t portid){ - m_port_id = portid; - m_last_rx_rate = 0.0; - m_last_tx_rate = 0.0; - m_last_tx_pps = 0.0; - return (true); - } - void Delete(); - - void set_rx_queue(uint8_t rx_queue){ - m_rx_queue=rx_queue; - } - - - void configure(uint16_t nb_rx_queue, - uint16_t nb_tx_queue, - const struct rte_eth_conf *eth_conf); - - void macaddr_get(struct ether_addr *mac_addr); - - void get_stats(CPhyEthIFStats *stats); - - void get_stats_1g(CPhyEthIFStats *stats); - - - void rx_queue_setup(uint16_t rx_queue_id, - uint16_t nb_rx_desc, - unsigned int socket_id, - const struct rte_eth_rxconf *rx_conf, - struct rte_mempool *mb_pool); - - void tx_queue_setup(uint16_t tx_queue_id, - uint16_t nb_tx_desc, - unsigned int socket_id, - const struct rte_eth_txconf *tx_conf); - - void configure_rx_drop_queue(); - - void configure_rx_duplicate_rules(); - - void start(); - - void stop(); - - void update_link_status(); - - bool is_link_up(){ - return (m_link.link_status?true:false); - } - - void dump_link(FILE *fd); - - void disable_flow_control(); - - void set_promiscuous(bool enable); - - void add_mac(char * mac); - - - bool get_promiscuous(); - - void dump_stats(FILE *fd); - - void update_counters(); - - - void stats_clear(); - - uint8_t get_port_id(){ - return (m_port_id); - } - - float get_last_tx_rate(){ - return (m_last_tx_rate); - } - - float get_last_rx_rate(){ - return (m_last_rx_rate); - } - - float get_last_tx_pps_rate(){ - return (m_last_tx_pps); - } - - float get_last_rx_pps_rate(){ - return (m_last_rx_pps); - } - - CPhyEthIFStats & get_stats(){ - return ( m_stats ); - } - - void flush_rx_queue(void); - -public: - - inline uint16_t tx_burst(uint16_t queue_id, - struct rte_mbuf **tx_pkts, - uint16_t nb_pkts); - - inline uint16_t rx_burst(uint16_t queue_id, - struct rte_mbuf **rx_pkts, - uint16_t nb_pkts); - - - inline uint32_t pci_reg_read(uint32_t reg_off){ - void *reg_addr; - uint32_t reg_v; - reg_addr = (void *)((char *)m_dev_info.pci_dev->mem_resource[0].addr + - reg_off); - reg_v = *((volatile uint32_t *)reg_addr); - return rte_le_to_cpu_32(reg_v); - } - - - inline void pci_reg_write(uint32_t reg_off, - uint32_t reg_v){ - void *reg_addr; - - reg_addr = (void *)((char *)m_dev_info.pci_dev->mem_resource[0].addr + - reg_off); - *((volatile uint32_t *)reg_addr) = rte_cpu_to_le_32(reg_v); - } - - void dump_stats_extended(FILE *fd); - - uint8_t get_rte_port_id(void){ - return ( m_port_id ); - } -private: - uint8_t m_port_id; - uint8_t m_rx_queue; - struct rte_eth_link m_link; - uint64_t m_sw_try_tx_pkt; - uint64_t m_sw_tx_drop_pkt; - CBwMeasure m_bw_tx; - CBwMeasure m_bw_rx; - CPPSMeasure m_pps_tx; - CPPSMeasure m_pps_rx; - - CPhyEthIFStats m_stats; - - float m_last_tx_rate; - float m_last_rx_rate; - float m_last_tx_pps; - float m_last_rx_pps; -public: - struct rte_eth_dev_info m_dev_info; -}; - - void CPhyEthIF::flush_rx_queue(void){ rte_mbuf_t * rx_pkts[32]; @@ -1467,8 +1316,8 @@ void CPhyEthIF::configure_rx_duplicate_rules(){ void CPhyEthIF::configure_rx_drop_queue(){ - - if ( get_vm_one_queue_enable() ) { + // In debug mode, we want to see all packets. Don't want to disable any queue. + if ( get_vm_one_queue_enable() || (CGlobalInfo::m_options.m_debug_pkt_proto != 0)) { return; } if ( CGlobalInfo::m_options.is_latency_disabled()==false ) { @@ -1790,25 +1639,6 @@ void CPhyEthIF::stats_clear(){ m_stats.Clear(); } -inline uint16_t CPhyEthIF::tx_burst(uint16_t queue_id, - struct rte_mbuf **tx_pkts, - uint16_t nb_pkts){ - uint16_t ret = rte_eth_tx_burst(m_port_id, queue_id, tx_pkts, nb_pkts); - return (ret); -} - - -inline uint16_t CPhyEthIF::rx_burst(uint16_t queue_id, - struct rte_mbuf **rx_pkts, - uint16_t nb_pkts){ - return (rte_eth_rx_burst(m_port_id, queue_id, - rx_pkts, nb_pkts)); - -} - - - - class CCorePerPort { public: CCorePerPort (){ @@ -2069,10 +1899,12 @@ int CCoreEthIF::send_pkt(CCorePerPort * lp_port, CVirtualIFPerSideStats * lp_stats ){ + //printf(" %lu \n",(ulong)rte_pktmbuf_pkt_len(m)); //rte_pktmbuf_dump(stdout,m, rte_pktmbuf_pkt_len(m)); - lp_stats->m_tx_pkt +=1; - lp_stats->m_tx_bytes += (rte_pktmbuf_pkt_len(m)+4); + /* too expensive remove this for now */ + //lp_stats->m_tx_pkt +=1; + //lp_stats->m_tx_bytes += (rte_pktmbuf_pkt_len(m)+4); uint16_t len = lp_port->m_len; lp_port->m_table[len]=m; @@ -2137,6 +1969,7 @@ int CCoreEthIFStateless::send_node(CGenNode * no){ m=node_sl->alloc_node_with_vm(); assert(m); } + send_pkt(lp_port,m,lp_stats); return (0); @@ -2685,13 +2518,7 @@ void CGlobalStats::Dump(FILE *fd,DumpFormat mode){ } - - - - - - -struct CGlobalTRex { +class CGlobalTRex { public: CGlobalTRex (){ @@ -2699,50 +2526,37 @@ public: m_max_cores=1; m_cores_to_dual_ports=0; m_max_queues_per_port=0; - m_test =NULL; m_fl_was_init=false; m_expected_pps=0.0; m_expected_cps=0.0; m_expected_bps=0.0; m_trex_stateless = NULL; } -public: bool Create(); void Delete(); - int ixgbe_prob_init(); int cores_prob_init(); int queues_prob_init(); int ixgbe_start(); int ixgbe_rx_queue_flush(); int ixgbe_configure_mg(); - - bool is_all_links_are_up(bool dump=false); - int set_promisc_all(bool enable); - int reset_counters(); -public: - private: /* try to stop all datapath cores */ void try_stop_all_dp(); /* send message to all dp cores */ int send_message_all_dp(TrexStatelessCpToDpMsgBase *msg); - void check_for_dp_message_from_core(int thread_id); void check_for_dp_messages(); public: - int start_send_master(); int start_master_stateless(); - int run_in_core(virtual_thread_id_t virt_core_id); int stop_core(virtual_thread_id_t virt_core_id); - int core_for_latency(){ if ( (!get_is_latency_thread_enable()) ){ return (-1); @@ -2751,14 +2565,10 @@ public: } } - int run_in_laterncy_core(); - int run_in_master(); int stop_master(); - - - /* return the minimum number of dp cores need to support the active ports + /* return the minimum number of dp cores needed to support the active ports this is for c==1 or m_cores_mul==1 */ int get_base_num_cores(){ @@ -2768,8 +2578,6 @@ public: int get_cores_tx(){ /* 0 - master num_of_cores - - - last for latency */ if ( (!get_is_latency_thread_enable()) ){ return (m_max_cores - 1 ); @@ -2778,69 +2586,27 @@ public: } } - - - -public: - int test_send(); - - - - int rcv_send(int port,int queue_id); - int rcv_send_all(int queue_id); - private: bool is_all_cores_finished(); - int test_send_pkts(uint16_t queue_id, - int pkt, - int port); - - - int create_pkt(uint8_t *pkt,int pkt_size); - int create_udp_pkt(); - int create_icmp_pkt(); - - - public: void dump_stats(FILE *fd, std::string & json,CGlobalStats::DumpFormat format); - void dump_template_info(std::string & json); - bool sanity_check(); - void update_stats(void); void get_stats(CGlobalStats & stats); - - void dump_post_test_stats(FILE *fd); - void dump_config(FILE *fd); public: port_cfg_t m_port_cfg; - - /* - exaple1 : - req=4 ,m_max_ports =4 ,c=1 , l=1 - - ==> - m_max_cores = 4/2+1+1 =4; - m_cores_mul = 1 - - - */ - uint32_t m_max_ports; /* active number of ports supported options are 2,4,8,10,12 */ uint32_t m_max_cores; /* current number of cores , include master and latency ==> ( master)1+c*(m_max_ports>>1)+1( latency ) */ uint32_t m_cores_mul; /* how cores multipler given c=4 ==> m_cores_mul */ - uint32_t m_max_queues_per_port; uint32_t m_cores_to_dual_ports; /* number of ports that will handle dual ports */ uint16_t m_latency_tx_queue_id; - // statistic CPPSMeasure m_cps; float m_expected_pps; @@ -2848,32 +2614,20 @@ public: float m_expected_bps;//bps float m_last_total_cps; - - CPhyEthIF m_ports[BP_MAX_PORTS]; - CCoreEthIF m_cores_vif_sf[BP_MAX_CORES]; /* counted from 1 , 2,3 core zero is reserve - stateful */ - CCoreEthIFStateless m_cores_vif_sl[BP_MAX_CORES]; /* counted from 1 , 2,3 core zero is reserve - stateless*/ + CCoreEthIF m_cores_vif_sf[BP_MAX_CORES]; /* counted from 1 , 2,3 core zero is reserved - stateful */ + CCoreEthIFStateless m_cores_vif_sl[BP_MAX_CORES]; /* counted from 1 , 2,3 core zero is reserved - stateless*/ CCoreEthIF * m_cores_vif[BP_MAX_CORES]; - - CParserOption m_po ; CFlowGenList m_fl; bool m_fl_was_init; - volatile uint8_t m_signal[BP_MAX_CORES] __rte_cache_aligned ; - CLatencyManager m_mg; CTrexGlobalIoMode m_io_modes; private: - -private: - rte_mbuf_t * m_test; - uint64_t m_test_drop; - CLatencyHWPort m_latency_vports[BP_MAX_PORTS]; /* read hardware driver */ CLatencyVmPort m_latency_vm_vports[BP_MAX_PORTS]; /* vm driver */ - CLatencyPktInfo m_latency_pkt; TrexPublisher m_zmq_publisher; @@ -2881,244 +2635,6 @@ public: TrexStateless *m_trex_stateless; }; - - -int CGlobalTRex::rcv_send(int port,int queue_id){ - - CPhyEthIF * lp=&m_ports[port]; - rte_mbuf_t * rx_pkts[32]; - printf(" test rx port:%d queue:%d \n",port,queue_id); - printf(" --------------\n"); - uint16_t cnt=lp->rx_burst(queue_id,rx_pkts,32); - - int i; - for (i=0; i<(int)cnt;i++) { - rte_mbuf_t * m=rx_pkts[i]; - int pkt_size=rte_pktmbuf_pkt_len(m); - char *p=rte_pktmbuf_mtod(m, char*); - utl_DumpBuffer(stdout,p,pkt_size,0); - rte_pktmbuf_free(m); - } - return (0); -} - -int CGlobalTRex::rcv_send_all(int queue_id){ - int i; - for (i=0; i<m_max_ports; i++) { - rcv_send(i,queue_id); - } - return (0); -} - - - - -int CGlobalTRex::test_send(){ - int i; - - set_promisc_all(true); - create_udp_pkt(); - - CRx_check_header rx_check_header; - (void)rx_check_header; - - rx_check_header.m_time_stamp=0x1234567; - rx_check_header.m_option_type=RX_CHECK_V4_OPT_TYPE; - rx_check_header.m_option_len=RX_CHECK_V4_OPT_LEN; - rx_check_header.m_magic=2; - rx_check_header.m_pkt_id=7; - rx_check_header.m_flow_id=9; - rx_check_header.m_flags=11; - - - assert(m_test); - for (i=0; i<1; i++) { - //test_send_pkts(0,1,0); - //test_send_pkts(m_latency_tx_queue_id,12,0); - //test_send_pkts(m_latency_tx_queue_id,1,1); - //test_send_pkts(m_latency_tx_queue_id,1,2); - //test_send_pkts(m_latency_tx_queue_id,1,3); - test_send_pkts(0,1,0); - test_send_pkts(0,2,1); - - /*delay(1000); - fprintf(stdout," --------------------------------\n"); - fprintf(stdout," after sending to port %d \n",i); - fprintf(stdout," --------------------------------\n"); - dump_stats(stdout); - fprintf(stdout," --------------------------------\n");*/ - } - //test_send_pkts(m_latency_tx_queue_id,1,1); - //test_send_pkts(m_latency_tx_queue_id,1,2); - //test_send_pkts(m_latency_tx_queue_id,1,3); - - - printf(" ---------\n"); - printf(" rx queue 0 \n"); - printf(" ---------\n"); - rcv_send_all(0); - printf("\n\n"); - - printf(" ---------\n"); - printf(" rx queue 1 \n"); - printf(" ---------\n"); - rcv_send_all(1); - printf(" ---------\n"); - - delay(1000); - - #if 1 - int j=0; - for (j=0; j<m_max_ports; j++) { - CPhyEthIF * lp=&m_ports[j]; - printf(" port : %d \n",j); - printf(" ----------\n"); - - lp->update_counters(); - lp->get_stats().Dump(stdout); - lp->dump_stats_extended(stdout); - } - /*for (j=0; j<4; j++) { - CPhyEthIF * lp=&m_ports[j]; - lp->dump_stats_extended(stdout); - }*/ - #endif - - fprintf(stdout," drop : %llu \n", (unsigned long long)m_test_drop); - return (0); -} - - - -const uint8_t udp_pkt[]={ - 0x00,0x00,0x00,0x01,0x00,0x00, - 0x00,0x00,0x00,0x01,0x00,0x00, - 0x08,0x00, - - 0x45,0x00,0x00,0x81, - 0xaf,0x7e,0x00,0x00, - 0xfe,0x06,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 -}; - - -const uint8_t icmp_pkt1[]={ - 0x00,0x00,0x00,0x01,0x00,0x00, - 0x00,0x00,0x00,0x01,0x00,0x00, - 0x08,0x00, - - 0x45,0x02,0x00,0x30, - 0x00,0x00,0x40,0x00, - 0xff,0x01,0xbd,0x04, - 0x9b,0xe6,0x18,0x9b, //SIP - 0xcb,0xff,0xfc,0xc2, //DIP - - 0x08, 0x00, - 0x01, 0x02, //checksum - 0xaa, 0xbb, // id - 0x00, 0x00, // Sequence number - - 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, - -}; - - - - -int CGlobalTRex::create_pkt(uint8_t *pkt,int pkt_size){ - rte_mempool_t * mp= CGlobalInfo::m_mem_pool[0].m_big_mbuf_pool ; - - rte_mbuf_t * m=rte_pktmbuf_alloc(mp); - if ( unlikely(m==0) ) { - printf("ERROR no packets \n"); - return (0); - } - char *p=rte_pktmbuf_append(m, pkt_size); - assert(p); - /* set pkt data */ - memcpy(p,pkt,pkt_size); - //m->ol_flags = PKT_TX_VLAN_PKT; - //m->pkt.vlan_tci =200; - - m_test = m; - - return (0); -} - -int CGlobalTRex::create_udp_pkt(){ - return (create_pkt((uint8_t*)udp_pkt,sizeof(udp_pkt))); -} - -int CGlobalTRex::create_icmp_pkt(){ - return (create_pkt((uint8_t*)icmp_pkt1,sizeof(icmp_pkt1))); -} - - -/* test by sending 10 packets ...*/ -int CGlobalTRex::test_send_pkts(uint16_t queue_id, - int pkt, - int port){ - - CPhyEthIF * lp=&m_ports[port]; - rte_mbuf_t * tx_pkts[32]; - if (pkt >32 ) { - pkt =32; - } - - int i; - for (i=0; i<pkt; i++) { - rte_mbuf_refcnt_update(m_test,1); - tx_pkts[i]=m_test; - } - uint16_t res=lp->tx_burst(queue_id,tx_pkts,pkt); - if ((pkt-res)>0) { - m_test_drop+=(pkt-res); - } - return (0); -} - - - - - -int CGlobalTRex::set_promisc_all(bool enable){ - int i; - for (i=0; i<m_max_ports; i++) { - CPhyEthIF * _if=&m_ports[i]; - _if->set_promiscuous(enable); - } - - return (0); -} - - - int CGlobalTRex::reset_counters(){ int i; for (i=0; i<m_max_ports; i++) { @@ -3290,6 +2806,11 @@ int CGlobalTRex::ixgbe_start(void){ /* last TX queue if for latency check */ if ( get_vm_one_queue_enable() ) { /* one tx one rx */ + + /* VMXNET3 does claim to support 16K but somehow does not work */ + /* reduce to 2000 */ + m_port_cfg.m_port_conf.rxmode.max_rx_pkt_len = 2000; + _if->configure(1, 1, &m_port_cfg.m_port_conf); @@ -3298,7 +2819,7 @@ int CGlobalTRex::ixgbe_start(void){ m_latency_tx_queue_id= m_cores_to_dual_ports; socket_id_t socket_id = CGlobalInfo::m_socket.port_to_socket((port_id_t)i); - assert(CGlobalInfo::m_mem_pool[socket_id].m_big_mbuf_pool); + assert(CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); @@ -3307,7 +2828,7 @@ int CGlobalTRex::ixgbe_start(void){ RTE_TEST_RX_DESC_VM_DEFAULT, socket_id, &m_port_cfg.m_rx_conf, - CGlobalInfo::m_mem_pool[socket_id].m_big_mbuf_pool); + CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); int qid; for ( qid=0; qid<(m_max_queues_per_port); qid++) { @@ -3327,7 +2848,7 @@ int CGlobalTRex::ixgbe_start(void){ m_latency_tx_queue_id= m_cores_to_dual_ports; socket_id_t socket_id = CGlobalInfo::m_socket.port_to_socket((port_id_t)i); - assert(CGlobalInfo::m_mem_pool[socket_id].m_big_mbuf_pool); + assert(CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); /* drop queue */ @@ -3335,7 +2856,7 @@ int CGlobalTRex::ixgbe_start(void){ RTE_TEST_RX_DESC_DEFAULT, socket_id, &m_port_cfg.m_rx_conf, - CGlobalInfo::m_mem_pool[socket_id].m_big_mbuf_pool); + CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048); /* set the filter queue */ @@ -3345,7 +2866,7 @@ int CGlobalTRex::ixgbe_start(void){ RTE_TEST_RX_LATENCY_DESC_DEFAULT, socket_id, &m_port_cfg.m_rx_conf, - CGlobalInfo::m_mem_pool[socket_id].m_big_mbuf_pool); + CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_9k); int qid; for ( qid=0; qid<(m_max_queues_per_port+1); qid++) { @@ -4713,16 +4234,11 @@ int main_test(int argc , char * argv[]){ g_trex.start_send_master(); } - - /* TBD_FDIR */ -#if 0 - printf(" test_send \n"); - g_trex.test_send(); - // while (1) { - delay(10000); - exit(0); - // } -#endif + if (CGlobalInfo::m_options.m_debug_pkt_proto != 0) { + CTrexDebug debug = CTrexDebug(g_trex.m_ports, g_trex.m_max_ports); + debug.test_send(CGlobalInfo::m_options.m_debug_pkt_proto); + exit(1); + } if ( CGlobalInfo::m_options.preview.getOnlyLatency() ){ rte_eal_mp_remote_launch(latency_one_lcore, NULL, CALL_MASTER); @@ -5072,6 +4588,14 @@ void CTRexExtendedDriverBase40G::clear_extended_stats(CPhyEthIF * _if){ } + +void CTRexExtendedDriverBaseVIC::update_configuration(port_cfg_t * cfg){ + cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH; + cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; + cfg->m_tx_conf.tx_thresh.wthresh = TX_WTHRESH; + cfg->m_port_conf.rxmode.max_rx_pkt_len =9*1000-10; +} + void CTRexExtendedDriverBase40G::update_configuration(port_cfg_t * cfg){ cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH; cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH; diff --git a/src/main_dpdk.h b/src/main_dpdk.h new file mode 100644 index 00000000..e2c0cdb2 --- /dev/null +++ b/src/main_dpdk.h @@ -0,0 +1,158 @@ +/* +Copyright (c) 2015-2016 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef MAIN_DPDK_H +#define MAIN_DPDK_H + +#include "bp_sim.h" + +class CPhyEthIFStats { + +public: + uint64_t ipackets; /**< Total number of successfully received packets. */ + uint64_t ibytes; /**< Total number of successfully received bytes. */ + uint64_t f_ipackets; /**< Total number of successfully received packets - filter SCTP*/ + uint64_t f_ibytes; /**< Total number of successfully received bytes. - filter SCTP */ + uint64_t opackets; /**< Total number of successfully transmitted packets.*/ + uint64_t obytes; /**< Total number of successfully transmitted bytes. */ + uint64_t ierrors; /**< Total number of erroneous received packets. */ + uint64_t oerrors; /**< Total number of failed transmitted packets. */ + uint64_t imcasts; /**< Total number of multicast received packets. */ + uint64_t rx_nombuf; /**< Total number of RX mbuf allocation failures. */ + +public: + void Clear(); + void Dump(FILE *fd); + void DumpAll(FILE *fd); +}; + +class CPhyEthIF { +public: + CPhyEthIF (){ + m_port_id=0; + m_rx_queue=0; + } + bool Create(uint8_t portid){ + m_port_id = portid; + m_last_rx_rate = 0.0; + m_last_tx_rate = 0.0; + m_last_tx_pps = 0.0; + return (true); + } + void Delete(); + + void set_rx_queue(uint8_t rx_queue){ + m_rx_queue=rx_queue; + } + + void configure(uint16_t nb_rx_queue, + uint16_t nb_tx_queue, + const struct rte_eth_conf *eth_conf); + void macaddr_get(struct ether_addr *mac_addr); + void get_stats(CPhyEthIFStats *stats); + void get_stats_1g(CPhyEthIFStats *stats); + void rx_queue_setup(uint16_t rx_queue_id, + uint16_t nb_rx_desc, + unsigned int socket_id, + const struct rte_eth_rxconf *rx_conf, + struct rte_mempool *mb_pool); + void tx_queue_setup(uint16_t tx_queue_id, + uint16_t nb_tx_desc, + unsigned int socket_id, + const struct rte_eth_txconf *tx_conf); + void configure_rx_drop_queue(); + void configure_rx_duplicate_rules(); + void start(); + void stop(); + void update_link_status(); + bool is_link_up(){ + return (m_link.link_status?true:false); + } + void dump_link(FILE *fd); + void disable_flow_control(); + void set_promiscuous(bool enable); + void add_mac(char * mac); + bool get_promiscuous(); + void dump_stats(FILE *fd); + void update_counters(); + void stats_clear(); + uint8_t get_port_id(){ + return (m_port_id); + } + float get_last_tx_rate(){ + return (m_last_tx_rate); + } + float get_last_rx_rate(){ + return (m_last_rx_rate); + } + float get_last_tx_pps_rate(){ + return (m_last_tx_pps); + } + float get_last_rx_pps_rate(){ + return (m_last_rx_pps); + } + CPhyEthIFStats & get_stats(){ + return ( m_stats ); + } + void flush_rx_queue(void); + +public: + inline uint16_t tx_burst(uint16_t queue_id, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) { + return rte_eth_tx_burst(m_port_id, queue_id, tx_pkts, nb_pkts); + } + inline uint16_t rx_burst(uint16_t queue_id, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) { + return rte_eth_rx_burst(m_port_id, queue_id, rx_pkts, nb_pkts); + } + inline uint32_t pci_reg_read(uint32_t reg_off) { + void *reg_addr; + uint32_t reg_v; + reg_addr = (void *)((char *)m_dev_info.pci_dev->mem_resource[0].addr + + reg_off); + reg_v = *((volatile uint32_t *)reg_addr); + return rte_le_to_cpu_32(reg_v); + } + inline void pci_reg_write(uint32_t reg_off, + uint32_t reg_v) { + void *reg_addr; + + reg_addr = (void *)((char *)m_dev_info.pci_dev->mem_resource[0].addr + + reg_off); + *((volatile uint32_t *)reg_addr) = rte_cpu_to_le_32(reg_v); + } + void dump_stats_extended(FILE *fd); + uint8_t get_rte_port_id(void) { + return m_port_id; + } +private: + uint8_t m_port_id; + uint8_t m_rx_queue; + struct rte_eth_link m_link; + uint64_t m_sw_try_tx_pkt; + uint64_t m_sw_tx_drop_pkt; + CBwMeasure m_bw_tx; + CBwMeasure m_bw_rx; + CPPSMeasure m_pps_tx; + CPPSMeasure m_pps_rx; + CPhyEthIFStats m_stats; + float m_last_tx_rate; + float m_last_rx_rate; + float m_last_tx_pps; + float m_last_rx_pps; +public: + struct rte_eth_dev_info m_dev_info; +}; + +#endif diff --git a/src/pal/linux/mbuf.cpp b/src/pal/linux/mbuf.cpp index 26a54fe9..7e9f4775 100755 --- a/src/pal/linux/mbuf.cpp +++ b/src/pal/linux/mbuf.cpp @@ -89,7 +89,7 @@ void utl_rte_mempool_delete(rte_mempool_t * & pool){ uint16_t rte_mbuf_refcnt_update(rte_mbuf_t *m, int16_t value) { utl_rte_pktmbuf_check(m); - uint32_t a=sanb_atomic_add_return_32_old(&m->refcnt_reserved,1); + uint32_t a=sanb_atomic_add_return_32_old(&m->refcnt_reserved, value); return (a); } @@ -136,11 +136,11 @@ rte_mbuf_t *rte_pktmbuf_alloc(rte_mempool_t *mp){ m->buf_addr =(char *)((char *)m+sizeof(rte_mbuf_t)+RTE_PKTMBUF_HEADROOM) ; rte_pktmbuf_reset(m); + return (m); } - void rte_pktmbuf_free_seg(rte_mbuf_t *m){ utl_rte_pktmbuf_check(m); @@ -150,8 +150,10 @@ void rte_pktmbuf_free_seg(rte_mbuf_t *m){ if ( md != m ) { rte_pktmbuf_detach(m); - if (rte_mbuf_refcnt_update(md, -1) == 0) - free(md); + if (rte_mbuf_refcnt_update(md, -1) == 0) { + free(md); + } + } free(m); diff --git a/src/platform_cfg.cpp b/src/platform_cfg.cpp index ca42aa31..15834544 100755 --- a/src/platform_cfg.cpp +++ b/src/platform_cfg.cpp @@ -35,9 +35,17 @@ void CPlatformMemoryYamlInfo::reset(){ m_mbuf[MBUF_64] = m_mbuf[MBUF_64]*2; m_mbuf[MBUF_2048] = CONST_NB_MBUF_2_10G/2; + m_mbuf[MBUF_4096] = 128; + m_mbuf[MBUF_9k] = 512; + + m_mbuf[TRAFFIC_MBUF_64] = m_mbuf[MBUF_64] * 4; m_mbuf[TRAFFIC_MBUF_2048] = CONST_NB_MBUF_2_10G * 8; + m_mbuf[TRAFFIC_MBUF_4096] = 128; + m_mbuf[TRAFFIC_MBUF_9k] = 512; + + m_mbuf[MBUF_DP_FLOWS] = (1024*1024/2); m_mbuf[MBUF_GLOBAL_FLOWS] =(10*1024/2); } @@ -47,7 +55,11 @@ const std::string names []={ "MBUF_256", "MBUF_512", "MBUF_1024", - "MBUF_2048", + "MBUF_2048", + "MBUF_4096", + "MBUF_9K", + + "TRAFFIC_MBUF_64", "TRAFFIC_MBUF_128", @@ -55,6 +67,9 @@ const std::string names []={ "TRAFFIC_MBUF_512", "TRAFFIC_MBUF_1024", "TRAFFIC_MBUF_2048", + "TRAFFIC_MBUF_4096", + "TRAFFIC_MBUF_9K", + "MBUF_DP_FLOWS", "MBUF_GLOBAL_FLOWS" @@ -214,6 +229,15 @@ void operator >> (const YAML::Node& node, CPlatformMemoryYamlInfo & plat_info) { node["mbuf_2048"] >> plat_info.m_mbuf[MBUF_2048]; } + if ( node.FindValue("mbuf_4096") ){ + node["mbuf_4096"] >> plat_info.m_mbuf[MBUF_4096]; + } + + if ( node.FindValue("mbuf_9k") ){ + node["mbuf_9k"] >> plat_info.m_mbuf[MBUF_9k]; + } + + if ( node.FindValue("traffic_mbuf_64") ){ node["traffic_mbuf_64"] >> plat_info.m_mbuf[TRAFFIC_MBUF_64]; } @@ -238,6 +262,15 @@ void operator >> (const YAML::Node& node, CPlatformMemoryYamlInfo & plat_info) { node["traffic_mbuf_2048"] >> plat_info.m_mbuf[TRAFFIC_MBUF_2048]; } + if ( node.FindValue("traffic_mbuf_4096") ){ + node["traffic_mbuf_4096"] >> plat_info.m_mbuf[TRAFFIC_MBUF_4096]; + } + + if ( node.FindValue("traffic_mbuf_9k") ){ + node["traffic_mbuf_9k"] >> plat_info.m_mbuf[TRAFFIC_MBUF_9k]; + } + + if ( node.FindValue("dp_flows") ){ node["dp_flows"] >> plat_info.m_mbuf[MBUF_DP_FLOWS]; } diff --git a/src/platform_cfg.h b/src/platform_cfg.h index 4fc3c3dd..e8f93d0b 100755 --- a/src/platform_cfg.h +++ b/src/platform_cfg.h @@ -31,25 +31,31 @@ limitations under the License. #define CONST_NB_MBUF_2_10G (16380/4) -typedef enum { MBUF_64 =0, // per dual port, per NUMA +typedef enum { MBUF_64 , // per dual port, per NUMA + + MBUF_128 , + MBUF_256 , + MBUF_512 , + MBUF_1024 , + MBUF_2048 , + MBUF_4096 , + MBUF_9k , - MBUF_128 =1, - MBUF_256 =2, - MBUF_512 =3, - MBUF_1024 =4, - MBUF_2048 =5, // per NUMA - TRAFFIC_MBUF_64 =6, - TRAFFIC_MBUF_128 =7, - TRAFFIC_MBUF_256 =8, - TRAFFIC_MBUF_512 =9, - TRAFFIC_MBUF_1024 =10, - TRAFFIC_MBUF_2048 =11, - - MBUF_DP_FLOWS =12, - MBUF_GLOBAL_FLOWS =13, - MBUF_SIZE =14 + TRAFFIC_MBUF_64 , + TRAFFIC_MBUF_128 , + TRAFFIC_MBUF_256 , + TRAFFIC_MBUF_512 , + TRAFFIC_MBUF_1024 , + TRAFFIC_MBUF_2048 , + TRAFFIC_MBUF_4096 , + TRAFFIC_MBUF_9k , + + + MBUF_DP_FLOWS , + MBUF_GLOBAL_FLOWS , + MBUF_SIZE } mbuf_sizes_t; const std::string * get_mbuf_names(void); diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index 51db0b20..95cd895b 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -175,6 +175,16 @@ TrexRpcCmdAddStream::parse_vm_instr_checksum(const Json::Value &inst, TrexStream stream->m_vm.add_instruction(new StreamVmInstructionFixChecksumIpv4(pkt_offset)); } + +void +TrexRpcCmdAddStream::parse_vm_instr_trim_pkt_size(const Json::Value &inst, TrexStream *stream, Json::Value &result){ + + std::string flow_var_name = parse_string(inst, "name", result); + + stream->m_vm.add_instruction(new StreamVmInstructionChangePktSize(flow_var_name)); +} + + void TrexRpcCmdAddStream::parse_vm_instr_tuple_flow_var(const Json::Value &inst, TrexStream *stream, Json::Value &result){ @@ -255,7 +265,7 @@ TrexRpcCmdAddStream::parse_vm(const Json::Value &vm, TrexStream *stream, Json::V for (int i = 0; i < instructions.size(); i++) { const Json::Value & inst = parse_object(instructions, i, result); - auto vm_types = {"fix_checksum_ipv4", "flow_var", "write_flow_var","tuple_flow_var"}; + auto vm_types = {"fix_checksum_ipv4", "flow_var", "write_flow_var","tuple_flow_var","trim_pkt_size"}; std::string vm_type = parse_choice(inst, "type", vm_types, result); // checksum instruction @@ -269,7 +279,10 @@ TrexRpcCmdAddStream::parse_vm(const Json::Value &vm, TrexStream *stream, Json::V parse_vm_instr_write_flow_var(inst, stream, result); } else if (vm_type == "tuple_flow_var") { - parse_vm_instr_tuple_flow_var(inst, stream, result); + parse_vm_instr_tuple_flow_var(inst, stream, result); + + } else if (vm_type == "trim_pkt_size") { + parse_vm_instr_trim_pkt_size(inst, stream, result); } else { /* internal error */ throw TrexRpcException("internal error"); diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h index f4651d7b..b1750053 100644 --- a/src/rpc-server/commands/trex_rpc_cmds.h +++ b/src/rpc-server/commands/trex_rpc_cmds.h @@ -96,6 +96,8 @@ void parse_vm(const Json::Value &vm, TrexStream *stream, Json::Value &result); void parse_vm_instr_checksum(const Json::Value &inst, TrexStream *stream, Json::Value &result); void parse_vm_instr_flow_var(const Json::Value &inst, TrexStream *stream, Json::Value &result); void parse_vm_instr_tuple_flow_var(const Json::Value &inst, TrexStream *stream, Json::Value &result); +void parse_vm_instr_trim_pkt_size(const Json::Value &inst, TrexStream *stream, Json::Value &result); + void parse_vm_instr_write_flow_var(const Json::Value &inst, TrexStream *stream, Json::Value &result); ); diff --git a/src/sim/trex_sim.h b/src/sim/trex_sim.h index cc02fd75..8feb7bc0 100644 --- a/src/sim/trex_sim.h +++ b/src/sim/trex_sim.h @@ -32,6 +32,12 @@ class TrexStateless; class TrexPublisher; class DpToCpHandler; + +static inline bool +in_range(int x, int low, int high) { + return ( (x >= low) && (x <= high) ); +} + /** * interface for a sim target * @@ -102,7 +108,9 @@ public: const std::string &out_filename, int port_count, int dp_core_count, - int dp_core_index); + int dp_core_index, + int limit, + bool is_dry_run); TrexStateless * get_stateless_obj() { return m_trex_stateless; @@ -121,12 +129,22 @@ private: void execute_json(const std::string &json_filename); void run_dp(const std::string &out_filename); - void run_dp_core(int core_index, const std::string &out_filename); + + void run_dp_core(int core_index, + const std::string &out_filename, + uint64_t &simulated_pkts, + uint64_t &written_pkts); void flush_dp_to_cp_messages_core(int core_index); void validate_response(const Json::Value &resp); + bool should_capture_core(int i); + bool is_multiple_capture(); + uint64_t get_limit_per_core(int core_index); + + void show_intro(const std::string &out_filename); + bool is_verbose() { return m_verbose; } @@ -136,11 +154,14 @@ private: TrexPublisher *m_publisher; CFlowGenList m_fl; CErfIFStl m_erf_vif; + CErfIFStlNull m_null_erf_vif; bool m_verbose; int m_port_count; int m_dp_core_count; int m_dp_core_index; + uint64_t m_limit; + bool m_is_dry_run; }; #endif /* __TREX_SIM_H__ */ diff --git a/src/sim/trex_sim_stateless.cpp b/src/sim/trex_sim_stateless.cpp index 2821644f..215315e0 100644 --- a/src/sim/trex_sim_stateless.cpp +++ b/src/sim/trex_sim_stateless.cpp @@ -26,9 +26,34 @@ limitations under the License. #include <json/json.h> #include <stdexcept> #include <sstream> +#include <trex_streams_compiler.h> using namespace std; +/****** utils ******/ +static string format_num(double num, const string &suffix = "") { + const char x[] = {' ','K','M','G','T','P'}; + + double my_num = num; + + for (int i = 0; i < sizeof(x); i++) { + if (std::abs(my_num) < 1000.0) { + stringstream ss; + + char buf[100]; + snprintf(buf, sizeof(buf), "%.2f", my_num); + + ss << buf << " " << x[i] << suffix; + return ss.str(); + + } else { + my_num /= 1000.0; + } + } + + return "NaN"; +} + TrexStateless * get_stateless_obj() { return SimStateless::get_instance().get_stateless_obj(); } @@ -57,8 +82,12 @@ public: virtual void get_global_stats(TrexPlatformGlobalStats &stats) const { } + virtual void get_interface_info(uint8_t interface_id, std::string &driver_name, driver_speed_e &speed) const { + driver_name = "TEST"; + speed = TrexPlatformApi::SPEED_10G; } + virtual void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const { } @@ -120,6 +149,8 @@ SimStateless::SimStateless() { m_dp_core_count = -1; m_dp_core_index = -1; m_port_count = -1; + m_limit = 0; + m_is_dry_run = false; /* override ownership checks */ TrexRpcCommand::test_set_override_ownership(true); @@ -131,15 +162,20 @@ SimStateless::run(const string &json_filename, const string &out_filename, int port_count, int dp_core_count, - int dp_core_index) { + int dp_core_index, + int limit, + bool is_dry_run) { assert(dp_core_count > 0); - assert(dp_core_index >= 0); - assert(dp_core_index < dp_core_count); + + /* -1 means its not set or positive value between 0 and the dp core count - 1*/ + assert( (dp_core_index == -1) || ( in_range(dp_core_index, 0, dp_core_count - 1)) ); m_dp_core_count = dp_core_count; m_dp_core_index = dp_core_index; m_port_count = port_count; + m_limit = limit; + m_is_dry_run = is_dry_run; prepare_dataplane(); prepare_control_plane(); @@ -216,7 +252,11 @@ SimStateless::prepare_dataplane() { m_fl.generate_p_thread_info(m_dp_core_count); for (int i = 0; i < m_dp_core_count; i++) { - m_fl.m_threads_info[i]->set_vif(&m_erf_vif); + if (should_capture_core(i)) { + m_fl.m_threads_info[i]->set_vif(&m_erf_vif); + } else { + m_fl.m_threads_info[i]->set_vif(&m_null_erf_vif); + } } } @@ -263,36 +303,125 @@ SimStateless::validate_response(const Json::Value &resp) { } +static inline bool is_debug() { + #ifdef DEBUG + return true; + #else + return false; + #endif +} + +void +SimStateless::show_intro(const std::string &out_filename) { + uint64_t bps = 0; + uint64_t pps = 0; + + std::cout << "\nGeneral info:\n"; + std::cout << "------------\n\n"; + + std::cout << "image type: " << (is_debug() ? "debug" : "release") << "\n"; + std::cout << "I/O output: " << (m_is_dry_run ? "*DRY*" : out_filename) << "\n"; + + if (m_limit > 0) { + std::cout << "packet limit: " << m_limit << "\n"; + } else { + std::cout << "packet limit: " << "*NO LIMIT*" << "\n"; + } + + if (m_dp_core_index != -1) { + std::cout << "core recording: " << m_dp_core_index << "\n"; + } else { + std::cout << "core recording: merge all\n"; + } + + std::cout << "\nConfiguration info:\n"; + std::cout << "-------------------\n\n"; + + std::cout << "ports: " << m_port_count << "\n"; + std::cout << "cores: " << m_dp_core_count << "\n"; + + + std::cout << "\nPort Config:\n"; + std::cout << "------------\n\n"; + + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(0); + + std::cout << "stream count: " << port->get_stream_count() << "\n"; + + port->get_port_effective_rate(bps, pps); + + std::cout << "max BPS: " << format_num(bps, "bps") << "\n"; + std::cout << "max PPS: " << format_num(pps, "pps") << "\n"; + + std::cout << "\n\nStarting simulation...\n"; +} void SimStateless::run_dp(const std::string &out_filename) { + uint64_t simulated_pkts_cnt = 0; + uint64_t written_pkts_cnt = 0; - for (int i = 0; i < m_dp_core_count; i++) { - if (i == m_dp_core_index) { - run_dp_core(i, out_filename); - } else { - run_dp_core(i, "/dev/null"); + show_intro(out_filename); + + if (is_multiple_capture()) { + for (int i = 0; i < m_dp_core_count; i++) { + std::stringstream ss; + ss << out_filename << "-" << i; + run_dp_core(i, ss.str(), simulated_pkts_cnt, written_pkts_cnt); + } + + } else { + for (int i = 0; i < m_dp_core_count; i++) { + run_dp_core(i, out_filename, simulated_pkts_cnt, written_pkts_cnt); } } - CFlowGenListPerThread *lpt = m_fl.m_threads_info[m_dp_core_index]; - + std::cout << "\n\nSimulation summary:\n"; + std::cout << "-------------------\n\n"; + std::cout << "simulated " << simulated_pkts_cnt << " packets\n"; + + if (m_is_dry_run) { + std::cout << "*DRY RUN* - no packets were written\n"; + } else { + std::cout << "written " << written_pkts_cnt << " packets " << "to '" << out_filename << "'\n\n"; + } + std::cout << "\n"; - std::cout << "ports: " << m_port_count << "\n"; - std::cout << "cores: " << m_dp_core_count << "\n"; - std::cout << "core index: " << m_dp_core_index << "\n"; - std::cout << "\nwritten " << lpt->m_node_gen.m_cnt << " packets " << "to '" << out_filename << "'\n\n"; +} + + +uint64_t +SimStateless::get_limit_per_core(int core_index) { + /* global no limit ? */ + if (m_limit == 0) { + return (0); + } else { + uint64_t l = std::max((uint64_t)1, m_limit / m_dp_core_count); + if (core_index == 0) { + l += (m_limit % m_dp_core_count); + } + return l; + } } void -SimStateless::run_dp_core(int core_index, const std::string &out_filename) { +SimStateless::run_dp_core(int core_index, + const std::string &out_filename, + uint64_t &simulated_pkts, + uint64_t &written_pkts) { CFlowGenListPerThread *lpt = m_fl.m_threads_info[core_index]; - lpt->start_stateless_simulation_file((std::string)out_filename, CGlobalInfo::m_options.preview); + lpt->start_stateless_simulation_file((std::string)out_filename, CGlobalInfo::m_options.preview, get_limit_per_core(core_index)); lpt->start_stateless_daemon_simulation(); flush_dp_to_cp_messages_core(core_index); + + simulated_pkts += lpt->m_node_gen.m_cnt; + + if (should_capture_core(core_index)) { + written_pkts += lpt->m_node_gen.m_cnt; + } } @@ -316,3 +445,30 @@ SimStateless::flush_dp_to_cp_messages_core(int core_index) { delete msg; } } + +bool +SimStateless::should_capture_core(int i) { + + /* dry run - no core should be recordered */ + if (m_is_dry_run) { + return false; + } + + /* no specific core index ? record all */ + if (m_dp_core_index == -1) { + return true; + } else { + return (i == m_dp_core_index); + } +} + +bool +SimStateless::is_multiple_capture() { + /* dry run - no core should be recordered */ + if (m_is_dry_run) { + return false; + } + + return ( (m_dp_core_count > 1) && (m_dp_core_index == -1) ); +} + diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index aa34e87b..05283d5f 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -76,6 +76,11 @@ TrexStatelessPort::TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api m_graph_obj = NULL; } +TrexStatelessPort::~TrexStatelessPort() { + if (m_graph_obj) { + delete m_graph_obj; + } +} /** * acquire the port @@ -589,6 +594,22 @@ TrexStatelessPort::validate(void) { } + +void +TrexStatelessPort::get_port_effective_rate(uint64_t &bps, uint64_t &pps) { + + if (get_stream_count() == 0) { + return; + } + + if (!m_graph_obj) { + generate_streams_graph(); + } + + bps = m_graph_obj->get_max_bps() * m_factor; + pps = m_graph_obj->get_max_pps() * m_factor; +} + /************* Trex Port Owner **************/ TrexPortOwner::TrexPortOwner() { diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index a529d38f..c3785b0c 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -134,6 +134,8 @@ public: TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api); + ~TrexStatelessPort(); + /** * acquire port * throws TrexException in case of an error @@ -259,6 +261,10 @@ public: return m_stream_table.get_stream_by_id(stream_id); } + int get_stream_count() { + return m_stream_table.size(); + } + void get_id_list(std::vector<uint32_t> &id_list) { m_stream_table.get_id_list(id_list); } @@ -298,6 +304,17 @@ public: return m_owner; } + + /** + * get the port effective rate (on a started / paused port) + * + * @author imarom (07-Jan-16) + * + * @param bps + * @param pps + */ + void get_port_effective_rate(uint64_t &bps, uint64_t &pps); + private: diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index b4f19111..a164f266 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -32,6 +32,8 @@ limitations under the License. #include <trex_stream_vm.h> #include <stdio.h> #include <string.h> +#include <common/captureFile.h> + class TrexRpcCmdAddStream; @@ -123,8 +125,8 @@ public: virtual ~TrexStream(); /* defines the min max per packet supported */ - static const uint32_t MIN_PKT_SIZE_BYTES = 1; - static const uint32_t MAX_PKT_SIZE_BYTES = 9000; + static const uint32_t MIN_PKT_SIZE_BYTES = 60; + static const uint32_t MAX_PKT_SIZE_BYTES = MAX_PKT_SIZE; /* provides storage for the stream json*/ void store_stream_json(const Json::Value &stream_json); diff --git a/src/stateless/cp/trex_stream_vm.cpp b/src/stateless/cp/trex_stream_vm.cpp index a3f585ad..b992d1ab 100644 --- a/src/stateless/cp/trex_stream_vm.cpp +++ b/src/stateless/cp/trex_stream_vm.cpp @@ -107,11 +107,14 @@ void StreamVmInstructionFlowMan::Dump(FILE *fd){ void StreamVmInstructionWriteToPkt::Dump(FILE *fd){ - fprintf(fd," write_pkt , %s ,%lu, add, %ld, big, %lu \n",m_flow_var_name.c_str(),(ulong)m_pkt_offset,(long)m_add_value,(ulong)(m_is_big_endian?1:0)); } +void StreamVmInstructionChangePktSize::Dump(FILE *fd){ + fprintf(fd," pkt_size_change , %s \n",m_flow_var_name.c_str() ); +} + void StreamVmInstructionFlowClient::Dump(FILE *fd){ @@ -192,6 +195,7 @@ void StreamVm::build_flow_var_table() { m_cur_var_offset=0; uint32_t ins_id=0; m_is_random_var=false; + m_is_change_pkt_size=false; /* scan all flow var instruction and build */ for (auto inst : m_inst_list) { @@ -201,6 +205,10 @@ void StreamVm::build_flow_var_table() { m_is_random_var =true; } } + + if ( inst->get_instruction_type() == StreamVmInstruction::itPKT_SIZE_CHANGE ){ + m_is_change_pkt_size=true; + } } /* if we found allocate BSS +4 bytes */ @@ -296,6 +304,51 @@ void StreamVm::build_flow_var_table() { ins_id++; } + + ins_id=0; + + /* second interation for sanity check and fixups*/ + for (auto inst : m_inst_list) { + + + if (inst->get_instruction_type() == StreamVmInstruction::itPKT_SIZE_CHANGE ) { + StreamVmInstructionChangePktSize *lpPkt =(StreamVmInstructionChangePktSize *)inst; + + VmFlowVarRec var; + if ( var_lookup(lpPkt->m_flow_var_name ,var) == false){ + + std::stringstream ss; + ss << "instruction id '" << ins_id << "' packet size with no valid flow varible name '" << lpPkt->m_flow_var_name << "'" ; + err(ss.str()); + } + + if ( var.m_size_bytes != 2 ) { + std::stringstream ss; + ss << "instruction id '" << ins_id << "' packet size change should point to a flow varible with size 2 "; + err(ss.str()); + } + + if ( var.m_ins.m_ins_flowv->m_max_value > m_pkt_size) { + var.m_ins.m_ins_flowv->m_max_value =m_pkt_size; + } + + if (var.m_ins.m_ins_flowv->m_min_value > m_pkt_size) { + var.m_ins.m_ins_flowv->m_min_value = m_pkt_size; + } + + + if ( var.m_ins.m_ins_flowv->m_min_value >= var.m_ins.m_ins_flowv->m_max_value ) { + std::stringstream ss; + ss << "instruction id '" << ins_id << "' min packet size " << var.m_ins.m_ins_flowv->m_min_value << " is bigger or eq to max packet size " << var.m_ins.m_ins_flowv->m_max_value; + err(ss.str()); + } + + if ( var.m_ins.m_ins_flowv->m_min_value < 60) { + var.m_ins.m_ins_flowv->m_min_value =60; + } + } + }/* for */ + } void StreamVm::alloc_bss(){ @@ -474,6 +527,8 @@ void StreamVm::build_program(){ ss << "instruction id '" << ins_id << "' packet write with packet_offset " << lpPkt->m_pkt_offset + var.m_size_bytes << " bigger than packet size "<< m_pkt_size; err(ss.str()); } + + add_field_cnt(lpPkt->m_pkt_offset + var.m_size_bytes); @@ -555,6 +610,32 @@ void StreamVm::build_program(){ } } + + if (ins_type == StreamVmInstruction::itPKT_SIZE_CHANGE ) { + StreamVmInstructionChangePktSize *lpPkt =(StreamVmInstructionChangePktSize *)inst; + + VmFlowVarRec var; + if ( var_lookup(lpPkt->m_flow_var_name ,var) == false){ + + std::stringstream ss; + ss << "instruction id '" << ins_id << "' packet size with no valid flow varible name '" << lpPkt->m_flow_var_name << "'" ; + err(ss.str()); + } + + if ( var.m_size_bytes != 2 ) { + std::stringstream ss; + ss << "instruction id '" << ins_id << "' packet size change should point to a flow varible with size 2 "; + err(ss.str()); + } + + uint8_t flow_offset = get_var_offset(lpPkt->m_flow_var_name); + + StreamDPOpPktSizeChange pkt_size_ch; + pkt_size_ch.m_op =StreamDPVmInstructions::itPKT_SIZE_CHANGE; + pkt_size_ch.m_flow_offset = flow_offset; + m_instructions.add_command(&pkt_size_ch,sizeof(pkt_size_ch)); + } + ins_id++; } } @@ -790,6 +871,8 @@ void StreamDPVmInstructions::Dump(FILE *fd){ StreamDPOpPktWr64 *lpw64; StreamDPOpClientsLimit *lp_client; StreamDPOpClientsUnLimit *lp_client_unlimited; + StreamDPOpPktSizeChange *lp_pkt_size_change; + while ( p < p_end) { @@ -901,6 +984,12 @@ void StreamDPVmInstructions::Dump(FILE *fd){ p+=sizeof(StreamDPOpClientsUnLimit); break; + case itPKT_SIZE_CHANGE : + lp_pkt_size_change =(StreamDPOpPktSizeChange *)p; + lp_pkt_size_change->dump(fd,"pkt_size_c"); + p+=sizeof(StreamDPOpPktSizeChange); + break; + default: assert(0); @@ -955,4 +1044,7 @@ void StreamDPOpClientsUnLimit::dump(FILE *fd,std::string opt){ fprintf(fd," %10s op:%lu, flow_offset: %lu (%x-%x) flags:%x \n", opt.c_str(),(ulong)m_op,(ulong)m_flow_offset,m_min_ip,m_max_ip,m_flags); } +void StreamDPOpPktSizeChange::dump(FILE *fd,std::string opt){ + fprintf(fd," %10s op:%lu, flow_offset: %lu \n", opt.c_str(),(ulong)m_op,(ulong)m_flow_offset); +} diff --git a/src/stateless/cp/trex_stream_vm.h b/src/stateless/cp/trex_stream_vm.h index 891e5b51..edc4f730 100644 --- a/src/stateless/cp/trex_stream_vm.h +++ b/src/stateless/cp/trex_stream_vm.h @@ -396,6 +396,21 @@ public: } __attribute__((packed)); +struct StreamDPOpPktSizeChange { + uint8_t m_op; + uint8_t m_flow_offset; /* offset to the flow var */ + + inline void run(uint8_t * flow_var_base,uint16_t & new_size) { + uint16_t * p_flow_var = (uint16_t*)(flow_var_base+m_flow_offset); + new_size = (*p_flow_var); + } + + void dump(FILE *fd,std::string opt); + + +} __attribute__((packed)); ; + + /* datapath instructions */ class StreamDPVmInstructions { public: @@ -422,7 +437,9 @@ public: itPKT_WR32 , itPKT_WR64 , itCLIENT_VAR , - itCLIENT_VAR_UNLIMIT + itCLIENT_VAR_UNLIMIT , + itPKT_SIZE_CHANGE , + }; @@ -443,12 +460,20 @@ private: class StreamDPVmInstructionsRunner { public: + StreamDPVmInstructionsRunner(){ + m_new_pkt_size=0;; + } inline void run(uint32_t * per_thread_random, uint32_t program_size, uint8_t * program, /* program */ uint8_t * flow_var, /* flow var */ uint8_t * pkt); /* pkt */ + inline uint16_t get_new_pkt_size(){ + return (m_new_pkt_size); + } +private: + uint16_t m_new_pkt_size; }; @@ -456,7 +481,8 @@ inline void StreamDPVmInstructionsRunner::run(uint32_t * per_thread_random, uint32_t program_size, uint8_t * program, /* program */ uint8_t * flow_var, /* flow var */ - uint8_t * pkt){ + uint8_t * pkt + ){ uint8_t * p=program; @@ -473,6 +499,8 @@ inline void StreamDPVmInstructionsRunner::run(uint32_t * per_thread_random, StreamDPOpPktWr16 *lpw16; StreamDPOpPktWr32 *lpw32; StreamDPOpPktWr64 *lpw64; + StreamDPOpPktSizeChange *lpw_pkt_size; + StreamDPOpClientsLimit *lpcl; StreamDPOpClientsUnLimit *lpclu; } ua ; @@ -586,6 +614,13 @@ inline void StreamDPVmInstructionsRunner::run(uint32_t * per_thread_random, ua.lpw64->wr(flow_var,pkt); p+=sizeof(StreamDPOpPktWr64); break; + + case StreamDPVmInstructions::itPKT_SIZE_CHANGE : + ua.lpw_pkt_size =(StreamDPOpPktSizeChange *)p; + ua.lpw_pkt_size->run(flow_var,m_new_pkt_size); + p+=sizeof(StreamDPOpPktSizeChange); + break; + default: assert(0); } @@ -607,7 +642,8 @@ public: itFIX_IPV4_CS = 4, itFLOW_MAN = 5, itPKT_WR = 6, - itFLOW_CLIENT = 7 + itFLOW_CLIENT = 7 , + itPKT_SIZE_CHANGE = 8 }; @@ -880,7 +916,7 @@ public: /** - * write flow var to packet + * write flow var to packet, hhaim * */ class StreamVmInstructionWriteToPkt : public StreamVmInstruction { @@ -925,6 +961,36 @@ public: }; + +/** + * change packet size, + * + */ +class StreamVmInstructionChangePktSize : public StreamVmInstruction { +public: + + StreamVmInstructionChangePktSize(const std::string &flow_var_name) : + + m_flow_var_name(flow_var_name) + {} + + virtual instruction_type_t get_instruction_type() const { + return ( StreamVmInstruction::itPKT_SIZE_CHANGE ); + } + + virtual void Dump(FILE *fd); + + virtual StreamVmInstruction * clone() { + return new StreamVmInstructionChangePktSize(m_flow_var_name); + } + +public: + + /* flow var name to write */ + std::string m_flow_var_name; +}; + + /** * describes a VM program for DP * @@ -939,6 +1005,7 @@ public: m_program_size=0; m_max_pkt_offset_change=0; m_prefix_size = 0; + m_is_pkt_size_var=false; } StreamVmDp( uint8_t * bss, @@ -946,7 +1013,8 @@ public: uint8_t * prog, uint16_t prog_size, uint16_t max_pkt_offset, - uint16_t prefix_size + uint16_t prefix_size, + bool a_is_pkt_size_var ){ if (bss) { @@ -972,6 +1040,7 @@ public: m_max_pkt_offset_change = max_pkt_offset; m_prefix_size = prefix_size; + m_is_pkt_size_var=a_is_pkt_size_var; } ~StreamVmDp(){ @@ -993,7 +1062,8 @@ public: m_program_ptr, m_program_size, m_max_pkt_offset_change, - m_prefix_size + m_prefix_size, + m_is_pkt_size_var ); assert(lp); return (lp); @@ -1035,6 +1105,14 @@ public: m_prefix_size = prefix_size; } + void set_pkt_size_is_var(bool pkt_size_var){ + m_is_pkt_size_var=pkt_size_var; + } + bool is_pkt_size_var(){ + return (m_is_pkt_size_var); + } + + private: uint8_t * m_bss_ptr; /* pointer to the data section */ uint8_t * m_program_ptr; /* pointer to the program */ @@ -1042,6 +1120,7 @@ private: uint16_t m_program_size; /* program size*/ uint16_t m_max_pkt_offset_change; uint16_t m_prefix_size; + bool m_is_pkt_size_var; }; @@ -1093,7 +1172,8 @@ public: get_dp_instruction_buffer()->get_program(), get_dp_instruction_buffer()->get_program_size(), get_max_packet_update_offset(), - get_prefix_size() + get_prefix_size(), + is_var_pkt_size() ); assert(lp); return (lp); @@ -1142,6 +1222,11 @@ public: return m_prefix_size; } + bool is_var_pkt_size(){ + return (m_is_change_pkt_size); + } + + bool is_compiled() { return m_is_compiled; } @@ -1197,6 +1282,7 @@ private: private: bool m_is_random_var; + bool m_is_change_pkt_size; bool m_is_compiled; uint16_t m_prefix_size; uint16_t m_pkt_size; diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 0a9a88ab..a80efc08 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -149,10 +149,34 @@ rte_mbuf_t * CGenNodeStateless::alloc_node_with_vm(){ m_vm_flow_var, (uint8_t*)p); + uint16_t pkt_new_size=runner.get_new_pkt_size(); + if ( likely( pkt_new_size == 0) ) { + /* no packet size change */ + rte_mbuf_t * m_const = get_const_mbuf(); + if ( m_const != NULL) { + utl_rte_pktmbuf_add_after(m,m_const); + } + return (m); + } + /* packet size change there are a few changes */ rte_mbuf_t * m_const = get_const_mbuf(); - if ( m_const != NULL) { - utl_rte_pktmbuf_add_after(m,m_const); + if ( (m_const == 0 ) || (pkt_new_size<=prefix_size) ) { + /* one mbuf , just trim it */ + m->data_len = pkt_new_size; + m->pkt_len = pkt_new_size; + return (m); + } + + rte_mbuf_t * mi= CGlobalInfo::pktmbuf_alloc_small(get_socket_id()); + assert(mi); + rte_pktmbuf_attach(mi,m_const); + utl_rte_pktmbuf_add_after2(m,mi); + + if ( pkt_new_size < m->pkt_len) { + /* need to trim it */ + mi->data_len = (pkt_new_size - prefix_size); + m->pkt_len = pkt_new_size; } return (m); } @@ -617,6 +641,12 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port, } + if ( lpDpVm->is_pkt_size_var() ) { + // mark the node as varible size + node->set_var_pkt_size(); + } + + if (lpDpVm->get_prefix_size() > pkt_size ) { lpDpVm->set_prefix_size(pkt_size); } diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index 70a66e6a..dfa4cc13 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -60,7 +60,9 @@ public: SL_NODE_FLAGS_DIR =1, //USED by master SL_NODE_FLAGS_MBUF_CACHE =2, //USED by master - SL_NODE_CONST_MBUF =4 + SL_NODE_CONST_MBUF =4, + + SL_NODE_VAR_PKT_SIZE =8 }; @@ -282,6 +284,14 @@ public: } } + inline void set_var_pkt_size(){ + m_flags |= SL_NODE_VAR_PKT_SIZE; + } + + inline bool is_var_pkt_size(){ + return ( ( m_flags &SL_NODE_VAR_PKT_SIZE )?true:false); + } + inline void set_const_mbuf(rte_mbuf_t * m){ m_cache_mbuf=(void *)m; m_flags |= SL_NODE_CONST_MBUF; |