summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--scripts/stl/udp_1pkt_src_ip_split.py45
-rwxr-xr-xsrc/bp_gtest.cpp2
-rwxr-xr-xsrc/bp_sim.cpp20
-rwxr-xr-xsrc/bp_sim.h2
-rw-r--r--src/gtest/trex_stateless_gtest.cpp27
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp1
-rw-r--r--src/stateless/cp/trex_stream.cpp3
-rw-r--r--src/stateless/cp/trex_stream.h3
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.cpp97
-rw-r--r--src/stateless/dp/trex_stream_node.h72
-rwxr-xr-xsrc/utl_cpuu.h10
11 files changed, 254 insertions, 28 deletions
diff --git a/scripts/stl/udp_1pkt_src_ip_split.py b/scripts/stl/udp_1pkt_src_ip_split.py
new file mode 100644
index 00000000..d83da06e
--- /dev/null
+++ b/scripts/stl/udp_1pkt_src_ip_split.py
@@ -0,0 +1,45 @@
+from trex_stl_lib.api import *
+
+
+# split the range of IP to cores
+#
+class STLS1(object):
+
+ def __init__ (self):
+ self.fsize =64;
+
+ def create_stream (self):
+ # create a base packet and pad it to size
+ size = self.fsize - 4; # no FCS
+
+ base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+
+ pad = max(0, size - len(base_pkt)) * 'x'
+
+ vm = STLScVmRaw( [ STLVmFlowVar ( "ip_src", min_value="10.0.0.1",
+ max_value="10.0.0.255", size=4, step=1,op="inc"),
+ STLVmWrFlowVar (fv_name="ip_src", pkt_offset= "IP.src" ) # write ip to packet IP.src
+ #STLVmFixIpv4(offset = "IP"), # fix checksum
+ ]
+ ,split_by_field = "ip_src" # split to cores base on the tuple generator
+ );
+
+ pkt = STLPktBuilder(pkt = base_pkt/pad,
+ vm = vm)
+ stream = STLStream(packet = pkt,
+ mode = STLTXCont())
+ #print(stream.to_code())
+ return stream
+
+
+ def get_streams (self, direction = 0, **kwargs):
+ # create 1 stream
+ return [ self.create_stream() ]
+
+
+# dynamic load - used for trex console or simulator
+def register():
+ return STLS1()
+
+
+
diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp
index 3189e886..6085de76 100755
--- a/src/bp_gtest.cpp
+++ b/src/bp_gtest.cpp
@@ -1134,6 +1134,7 @@ TEST_F(basic, http1_ipv6) {
void delay(int msec);
+#if 0
TEST_F(cpu, cpu1) {
CCpuUtlDp cpu_dp;
@@ -1176,6 +1177,7 @@ TEST_F(cpu, cpu2) {
cpu_cp.Delete();
}
+#endif
#if 0
TEST_F(cpu, cpu3) {
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index 94f8a2ba..9725084c 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -3576,16 +3576,22 @@ int CNodeGenerator::flush_file(dsec_t max_time,
CFlowGenListPerThread * thread,
double &old_offset){
CGenNode * node;
+ #ifdef TREX_SIM
dsec_t flush_time=now_sec();
+ #endif
dsec_t offset=0.0;
+ #ifdef TREX_SIM
dsec_t n_time;
+ #endif
if (always) {
offset=old_offset;
}
+ #ifdef TREX_SIM
uint32_t events=0;
+ #endif
bool done=false;
- thread->m_cpu_dp_u.start_work();
+ thread->m_cpu_dp_u.start_work1();
/**
* if a positive value was given to max time
@@ -3602,18 +3608,25 @@ int CNodeGenerator::flush_file(dsec_t max_time,
while (true) {
node = m_p_queue.top();
+ #ifdef TREX_SIM
n_time = node->m_time + offset;
events++;
+ #endif
/*#ifdef VALG
if (events > 1 ) {
CALLGRIND_START_INSTRUMENTATION;
}
#endif*/
+ thread->m_cpu_dp_u.commit1();
+ thread->m_cpu_dp_u.start_work1();
+
+ #ifdef TREX_SIM
+
if ( likely ( m_is_realtime ) ){
dsec_t dt ;
- thread->m_cpu_dp_u.commit();
+ thread->m_cpu_dp_u.commit1();
while ( true ) {
dt = now_sec() - n_time ;
@@ -3624,7 +3637,7 @@ int CNodeGenerator::flush_file(dsec_t max_time,
rte_pause();
}
- thread->m_cpu_dp_u.start_work();
+ thread->m_cpu_dp_u.start_work1();
/* add offset in case of faliures more than 100usec */
if ( unlikely( dt > 0.000100 ) ) {
@@ -3640,6 +3653,7 @@ int CNodeGenerator::flush_file(dsec_t max_time,
flush_time=now_sec();
}
}
+ #endif
uint8_t type=node->m_type;
diff --git a/src/bp_sim.h b/src/bp_sim.h
index 1ec036c0..c077b0b9 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -1436,7 +1436,7 @@ public:
NODE_FLAGS_LATENCY =0x20, /* got NAT msg */
NODE_FLAGS_INIT_START_FROM_SERVER_SIDE = 0x40,
NODE_FLAGS_ALL_FLOW_SAME_PORT_SIDE = 0x80,
- NODE_FLAGS_INIT_START_FROM_SERVER_SIDE_SERVER_ADDR = 0x100 /* init packet start from server side with server addr */
+ NODE_FLAGS_INIT_START_FROM_SERVER_SIDE_SERVER_ADDR = 0x100, /* init packet start from server side with server addr */
};
diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp
index a5cf3307..a33d2d74 100644
--- a/src/gtest/trex_stateless_gtest.cpp
+++ b/src/gtest/trex_stateless_gtest.cpp
@@ -140,6 +140,29 @@ class basic_vm : public testing::Test {
};
+TEST_F(basic_vm, cache_basic) {
+
+ CGenNodeStateless *node = new CGenNodeStateless();
+
+ node->cache_mbuf_array_init();
+ int i;
+ node->cache_mbuf_array_alloc(10);
+ for (i=0; i<10; i++) {
+ rte_mbuf_t * m =CGlobalInfo::pktmbuf_alloc_small(0);
+ m->data_off=i;
+ node->cache_mbuf_array_set(i,(rte_mbuf_t *) m);
+ }
+
+ for (i=0; i<10; i++) {
+ rte_mbuf_t * m =node->cache_mbuf_array_get_cur();
+ printf(" %d \n",m->data_off);
+ //rte_pktmbuf_refcnt_update(m,1); /* both */
+ }
+
+ node->cache_mbuf_array_free();
+
+ delete node;
+}
TEST_F(basic_vm, pkt_size) {
@@ -3585,3 +3608,7 @@ TEST_F(rx_stat_pkt_parse, x710_parser) {
parser.test();
}
+
+
+
+
diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
index 40719325..54e35d4e 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -60,6 +60,7 @@ TrexRpcCmdAddStream::_run(const Json::Value &params, Json::Value &result) {
stream->m_flags = parse_int(section, "flags", result);
stream->m_action_count = parse_uint16(section, "action_count", result);
stream->m_random_seed = parse_uint32(section, "random_seed", result,0); /* default is zero */
+ stream->m_cache_size = parse_uint16(section, "cache", result,0); /* default is zero */
/* inter stream gap */
stream->m_isg_usec = parse_double(section, "isg", result);
diff --git a/src/stateless/cp/trex_stream.cpp b/src/stateless/cp/trex_stream.cpp
index 4325858c..5a24e2b3 100644
--- a/src/stateless/cp/trex_stream.cpp
+++ b/src/stateless/cp/trex_stream.cpp
@@ -121,7 +121,7 @@ void TrexStream::Dump(FILE *fd){
fprintf(fd," bps L1 : %f\n", m_rate.get_bps_L1());
fprintf(fd," bps L2 : %f\n", m_rate.get_bps_L2());
fprintf(fd," percentage : %f\n", m_rate.get_percentage());
-
+ fprintf(fd," cache_size : %lu\n", (ulong)m_cache_size);
}
@@ -134,6 +134,7 @@ TrexStream::TrexStream(uint8_t type,
m_next_stream_id = -1;
m_enabled = false;
m_self_start = false;
+ m_cache_size = 0;
m_mc_phase_pre_sec = 0;
m_mc_phase_post_sec = 0;
diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h
index c5bfdb98..ba5fa214 100644
--- a/src/stateless/cp/trex_stream.h
+++ b/src/stateless/cp/trex_stream.h
@@ -440,6 +440,7 @@ public:
dp->m_num_bursts = m_num_bursts;
dp->m_ibg_usec = m_ibg_usec;
dp->m_flags = m_flags;
+ dp->m_cache_size = m_cache_size;
dp->m_action_count = m_action_count;
dp->m_random_seed = m_random_seed;
@@ -514,8 +515,10 @@ public:
uint8_t m_type;
uint8_t m_port_id;
uint16_t m_flags;
+
uint32_t m_stream_id; /* id from RPC can be anything */
uint16_t m_action_count;
+ uint16_t m_cache_size;
uint32_t m_random_seed;
diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp
index d3d49a34..23f1f4c2 100644
--- a/src/stateless/dp/trex_stateless_dp_core.cpp
+++ b/src/stateless/dp/trex_stateless_dp_core.cpp
@@ -26,6 +26,75 @@ limitations under the License.
#include "trex_stream_node.h"
#include "trex_streams_compiler.h"
+
+
+
+void CGenNodeStateless::cache_mbuf_array_init(){
+ m_cache_size=0;
+ m_cache_array_cnt=0;
+}
+
+
+
+rte_mbuf_t ** CGenNodeStateless::cache_mbuf_array_alloc(uint16_t size){
+
+ uint32_t buf_size = CGenNodeCacheMbuf::get_object_size(size);
+ /* TBD replace with align, zero API */
+ m_cache_mbuf = (void *)malloc(buf_size);
+ assert(m_cache_mbuf);
+ memset(m_cache_mbuf,0,buf_size);
+
+ m_flags |= SL_NODE_CONST_MBUF_CACHE_ARRAY;
+ m_cache_size=size;
+ m_cache_array_cnt=0;
+ return ((rte_mbuf_t **)m_cache_mbuf);
+}
+
+void CGenNodeStateless::cache_mbuf_array_free(){
+
+ assert(m_cache_mbuf);
+ int i;
+ for (i=0; i<(int)m_cache_size; i++) {
+ rte_mbuf_t * m=cache_mbuf_array_get((uint16_t)i);
+ assert(m);
+ rte_pktmbuf_free(m);
+ }
+
+ /* free the const */
+ rte_mbuf_t * m=cache_mbuf_array_get_const_mbuf() ;
+ if (m) {
+ rte_pktmbuf_free(m);
+ }
+
+ free(m_cache_mbuf);
+ m_cache_mbuf=0;
+}
+
+
+rte_mbuf_t * CGenNodeStateless::cache_mbuf_array_get(uint16_t index){
+
+ CGenNodeCacheMbuf *p =(CGenNodeCacheMbuf *) m_cache_mbuf;
+ return (p->m_array[index]);
+}
+
+void CGenNodeStateless::cache_mbuf_array_set_const_mbuf(rte_mbuf_t * m){
+ CGenNodeCacheMbuf *p =(CGenNodeCacheMbuf *) m_cache_mbuf;
+ p->m_mbuf_const=m;
+}
+
+rte_mbuf_t * CGenNodeStateless::cache_mbuf_array_get_const_mbuf(){
+ CGenNodeCacheMbuf *p =(CGenNodeCacheMbuf *) m_cache_mbuf;
+ return (p->m_mbuf_const);
+}
+
+
+void CGenNodeStateless::cache_mbuf_array_set(uint16_t index,
+ rte_mbuf_t * m){
+ CGenNodeCacheMbuf *p =(CGenNodeCacheMbuf *) m_cache_mbuf;
+ p->m_array[index]=m;
+}
+
+
void CDpOneStream::Delete(CFlowGenListPerThread * core){
assert(m_node->get_state() == CGenNodeStateless::ss_INACTIVE);
core->free_node((CGenNode *)m_node);
@@ -188,18 +257,24 @@ rte_mbuf_t * CGenNodeStateless::alloc_node_with_vm(){
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;
+
+ if ( is_cache_mbuf_array() ){
+ /* do we have cache of mbuf pre allocated */
+ cache_mbuf_array_free();
}else{
- /* non cache - must have an header */
- m=get_const_mbuf();
- if (m) {
- rte_pktmbuf_free(m); /* reduce the ref counter */
- }
- free_prefix_header();
+ /* if we have cache mbuf free it */
+ rte_mbuf_t * m=get_cache_mbuf();
+ if (m) {
+ rte_pktmbuf_free(m);
+ m_cache_mbuf=0;
+ }else{
+ /* non cache - must have an header */
+ m=get_const_mbuf();
+ if (m) {
+ rte_pktmbuf_free(m); /* reduce the ref counter */
+ }
+ free_prefix_header();
+ }
}
if (m_vm_flow_var) {
/* free flow var */
diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h
index c85bf8b5..4d3c2ae1 100644
--- a/src/stateless/dp/trex_stream_node.h
+++ b/src/stateless/dp/trex_stream_node.h
@@ -49,6 +49,15 @@ public:
static_assert(sizeof(CGenNodeCommand) == sizeof(CGenNode), "sizeof(CGenNodeCommand) != sizeof(CGenNode)" );
+struct CGenNodeCacheMbuf {
+ rte_mbuf_t * m_mbuf_const;
+ rte_mbuf_t * m_array[0];
+public:
+ static uint32_t get_object_size(uint32_t size){
+ return ( sizeof(CGenNodeCacheMbuf) + sizeof(rte_mbuf_t *) * size );
+ }
+};
+
/* this is a event for stateless */
struct CGenNodeStateless : public CGenNodeBase {
friend class TrexStatelessDpCore;
@@ -61,10 +70,10 @@ public:
SL_NODE_FLAGS_MBUF_CACHE =2, //USED by master
SL_NODE_CONST_MBUF =4,
-
- SL_NODE_VAR_PKT_SIZE =8,
- SL_NODE_STATS_NEEDED = 0x10
-
+
+ SL_NODE_VAR_PKT_SIZE = 8,
+ SL_NODE_STATS_NEEDED = 0x10,
+ SL_NODE_CONST_MBUF_CACHE_ARRAY = 0x20 /* array of mbuf - cache */
};
enum {
@@ -77,15 +86,18 @@ public:
static std::string get_stream_state_str(stream_state_t stream_state);
private:
- /* cache line 0 */
- /* important stuff here */
- void * m_cache_mbuf;
+ /******************************/
+ /* cache line 0 */
+ /* important stuff here R/W */
+ /******************************/
+ void * m_cache_mbuf; /* could be an array or a one mbuf */
double m_next_time_offset; /* in sec */
uint16_t m_action_counter;
uint8_t m_stat_hw_id; // hw id used to count rx and tx stats
uint8_t m_null_stream;
- uint32_t m_pad12;
+ uint16_t m_cache_array_cnt;
+ uint16_t m_pad12;
stream_state_t m_state;
uint8_t m_port_id;
@@ -97,7 +109,10 @@ private:
uint32_t m_multi_bursts; /* in case of multi_burst how many bursts */
- /* cache line 1 */
+ /******************************/
+ /* cache line 1
+ this cache line should be READONLY ! you can write only at init time */
+ /******************************/
TrexStream * m_ref_stream_info; /* the stream info */
CGenNodeStateless * m_next_stream;
@@ -107,8 +122,11 @@ private:
uint8_t * m_vm_flow_var; /* pointer to the vm flow var */
uint8_t * m_vm_program; /* pointer to the program */
uint16_t m_vm_program_size; /* up to 64K op codes */
- uint16_t m_pad2;
- uint32_t m_pad3;
+ uint16_t m_cache_size; /*RO*/ /* the size of the mbuf array */
+ uint8_t m_batch_size; /*RO*/ /* the batch size */
+
+ uint8_t m_pad4;
+ uint16_t m_pad5;
/* End Fast Field VM Section */
@@ -118,6 +136,8 @@ private:
public:
+
+
void set_random_seed(uint32_t seed){
uint32_t *p=get_random_bss_seed_memory();
*p=seed;
@@ -369,6 +389,36 @@ public:
void free_stl_node();
public:
+ void cache_mbuf_array_init();
+
+ inline bool is_cache_mbuf_array(){
+ return ( m_flags & SL_NODE_CONST_MBUF_CACHE_ARRAY ? true:false );
+ }
+
+ rte_mbuf_t ** cache_mbuf_array_alloc(uint16_t size);
+
+ void cache_mbuf_array_free();
+
+ void cache_mbuf_array_set(uint16_t index,rte_mbuf_t * m);
+
+ void cache_mbuf_array_set_const_mbuf(rte_mbuf_t * m);
+
+ rte_mbuf_t * cache_mbuf_array_get_const_mbuf();
+
+ rte_mbuf_t * cache_mbuf_array_get(uint16_t index);
+
+ rte_mbuf_t * cache_mbuf_array_get_cur(void){
+ CGenNodeCacheMbuf *p =(CGenNodeCacheMbuf *) m_cache_mbuf;
+ rte_mbuf_t * m=p->m_array[m_cache_array_cnt];
+ assert(m);
+ m_cache_array_cnt++;
+ if (m_cache_array_cnt == m_cache_size) {
+ m_cache_array_cnt=0;
+ }
+ return m;
+ }
+
+public:
/* debug functions */
int get_stream_id();
diff --git a/src/utl_cpuu.h b/src/utl_cpuu.h
index e7bb50bb..bb3fe67c 100755
--- a/src/utl_cpuu.h
+++ b/src/utl_cpuu.h
@@ -32,6 +32,14 @@ public:
m_total_cycles=0;
m_data=0;
}
+ inline void start_work1(){
+ m_data=1;
+
+ }
+ inline void commit1(){
+ m_data=0;
+ }
+
inline void start_work(){
m_data=os_get_hr_tick_64();
}
@@ -50,7 +58,7 @@ public:
private:
uint64_t m_total_cycles;
- uint64_t m_data;
+ uint8_t m_data;
} __rte_cache_aligned;