summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py25
-rw-r--r--scripts/exp/stl_vm_enable0_cache_10-0-ex.erfbin0 -> 880 bytes
-rw-r--r--scripts/exp/stl_vm_enable1_cache_500-0-ex.erfbin0 -> 12936 bytes
-rw-r--r--scripts/stl/udp_1pkt_src_ip_split.py5
-rwxr-xr-xsrc/bp_sim.cpp24
-rw-r--r--src/gtest/trex_stateless_gtest.cpp25
-rw-r--r--src/main_dpdk.cpp26
-rwxr-xr-xsrc/pal/linux/mbuf.h7
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp2
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.cpp90
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.h5
-rw-r--r--src/stateless/dp/trex_stream_node.h11
12 files changed, 175 insertions, 45 deletions
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py
index f8517a47..f06d5d70 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py
@@ -185,7 +185,7 @@ class STLScVmRaw(CTRexScriptsBase):
"""
Raw instructions
"""
- def __init__(self,list_of_commands=None,split_by_field=None):
+ def __init__(self,list_of_commands=None,split_by_field=None,cache_size=None):
"""
Include a list of a basic instructions objects.
@@ -196,6 +196,8 @@ class STLScVmRaw(CTRexScriptsBase):
split_by_field : string
by which field to split to threads
+ cache_size : uint16_t
+ In case it is bigger than zero, FE results will be cached - this will speedup of the program at the cost of limiting the number of possible packets to the number of cache. The cache size is limited to the pool size
The following example splits the generated traffic by "ip_src" variable.
@@ -218,13 +220,16 @@ class STLScVmRaw(CTRexScriptsBase):
STLVmFixIpv4(offset = "IP"), # fix checksum
]
- ,split_by_field = "ip_src"
+ ,split_by_field = "ip_src",
+ cache_size = 1000
)
"""
super(STLScVmRaw, self).__init__()
self.split_by_field = split_by_field
+ self.cache_size = cache_size
+
if list_of_commands==None:
self.commands =[]
else:
@@ -339,6 +344,8 @@ class CTRexVmEngine(object):
super(CTRexVmEngine, self).__init__()
self.ins=[]
self.split_by_var = ''
+ self.cache_size = 0
+
# return as json
def get_json (self):
@@ -347,7 +354,10 @@ class CTRexVmEngine(object):
for obj in self.ins:
inst_array.append(obj.__dict__);
- return {'instructions': inst_array, 'split_by_var': self.split_by_var}
+ d={'instructions': inst_array, 'split_by_var': self.split_by_var};
+ if self.cache_size >0 :
+ d['cache']=self.cache_size
+ return d
def add_ins (self,ins):
#assert issubclass(ins, CTRexVmInsBase)
@@ -1422,11 +1432,14 @@ class STLPktBuilder(CTrexPktBuilderInterface):
# set split_by_var
if obj.split_by_field :
validate_type('obj.split_by_field', obj.split_by_field, str)
- #if not vars.has_key(obj.split_by_field):
- # raise CTRexPacketBuildException(-11,("variable %s does not exists. change split_by_var args ") % (var_name) );
-
self.vm_low_level.split_by_var = obj.split_by_field
+ #set cache size
+ if obj.cache_size :
+ validate_type('obj.cache_size', obj.cache_size, int)
+ self.vm_low_level.cache_size = obj.cache_size
+
+
# lazy packet build only on demand
def __lazy_build_packet (self):
diff --git a/scripts/exp/stl_vm_enable0_cache_10-0-ex.erf b/scripts/exp/stl_vm_enable0_cache_10-0-ex.erf
new file mode 100644
index 00000000..1a0ba1f6
--- /dev/null
+++ b/scripts/exp/stl_vm_enable0_cache_10-0-ex.erf
Binary files differ
diff --git a/scripts/exp/stl_vm_enable1_cache_500-0-ex.erf b/scripts/exp/stl_vm_enable1_cache_500-0-ex.erf
new file mode 100644
index 00000000..73a1a963
--- /dev/null
+++ b/scripts/exp/stl_vm_enable1_cache_500-0-ex.erf
Binary files differ
diff --git a/scripts/stl/udp_1pkt_src_ip_split.py b/scripts/stl/udp_1pkt_src_ip_split.py
index d83da06e..778ccf54 100644
--- a/scripts/stl/udp_1pkt_src_ip_split.py
+++ b/scripts/stl/udp_1pkt_src_ip_split.py
@@ -18,10 +18,11 @@ class STLS1(object):
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
+ 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
+ ,cache_size =255 # the cache size
);
pkt = STLPktBuilder(pkt = base_pkt/pad,
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index 9725084c..687f51fd 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -4840,20 +4840,26 @@ int CErfIFStl::send_node(CGenNode * _no_to_use){
pkt_dir_t dir=(pkt_dir_t)node_sl->get_mbuf_cache_dir();
- /* check that we have mbuf */
- rte_mbuf_t * m=node_sl->get_cache_mbuf();
- if (m) {
- /* cache packet */
+ rte_mbuf_t * m;
+ if ( likely(node_sl->is_cache_mbuf_array()) ) {
+ m=node_sl->cache_mbuf_array_get_cur();
fill_raw_packet(m,_no_to_use,dir);
- /* can't free the m, it is cached*/
}else{
+ m=node_sl->get_cache_mbuf();
+ if (m) {
+ /* cache packet */
+ fill_raw_packet(m,_no_to_use,dir);
+ /* can't free the m, it is cached*/
+ }else{
- m=node_sl->alloc_node_with_vm();
- assert(m);
- fill_raw_packet(m,_no_to_use,dir);
- rte_pktmbuf_free(m);
+ m=node_sl->alloc_node_with_vm();
+ assert(m);
+ fill_raw_packet(m,_no_to_use,dir);
+ rte_pktmbuf_free(m);
+ }
}
+ /* check that we have mbuf */
int rc = write_pkt(m_raw);
BP_ASSERT(rc == 0);
diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp
index a33d2d74..11070f5c 100644
--- a/src/gtest/trex_stateless_gtest.cpp
+++ b/src/gtest/trex_stateless_gtest.cpp
@@ -156,7 +156,6 @@ TEST_F(basic_vm, cache_basic) {
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();
@@ -2775,13 +2774,13 @@ TEST_F(basic_stl, multi_pkt1) {
class CEnableVm {
public:
- void run(bool full_packet,double duration );
+ void run(bool full_packet,double duration,uint16_t cache );
public:
std::string m_input_packet; //"cap2/udp_64B.pcap"
std::string m_out_file; //"exp/stl_vm_enable0";
};
-void CEnableVm::run(bool full_packet,double duration=10.0){
+void CEnableVm::run(bool full_packet,double duration=10.0,uint16_t cache=0){
CBasicStl t1;
CParserOption * po =&CGlobalInfo::m_options;
@@ -2797,6 +2796,10 @@ void CEnableVm::run(bool full_packet,double duration=10.0){
TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0);
+ if ( cache ){
+ stream1->m_cache_size=cache;
+ }
+
stream1->set_rate(TrexStreamRate::RATE_PPS, 1.0);
stream1->m_enabled = true;
@@ -2839,6 +2842,22 @@ void CEnableVm::run(bool full_packet,double duration=10.0){
EXPECT_EQ_UINT32(1, res?1:0)<< "pass";
}
+TEST_F(basic_stl, vm_enable_cache_10) {
+
+ CEnableVm vm_test;
+ vm_test.m_out_file = "exp/stl_vm_enable0_cache_10";
+ vm_test.m_input_packet = "cap2/udp_64B.pcap";
+ vm_test.run(true,10.0,100);
+}
+
+TEST_F(basic_stl, vm_enable_cache_500) {
+ /* multi mbuf cache */
+ CEnableVm vm_test;
+ vm_test.m_out_file = "exp/stl_vm_enable1_cache_500";
+ vm_test.m_input_packet = "stl/yaml/udp_594B_no_crc.pcap";
+ vm_test.run(false,20.0,19);
+}
+
TEST_F(basic_stl, vm_enable0) {
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 6dec3dec..3fa3ca68 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -1943,13 +1943,6 @@ 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));
-
- /* 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;
len++;
@@ -2001,16 +1994,23 @@ void CCoreEthIF::update_mac_addr(CGenNode * node,uint8_t *p){
int CCoreEthIFStateless::send_node(CGenNode * no){
CGenNodeStateless * node_sl=(CGenNodeStateless *) no;
/* check that we have mbuf */
- rte_mbuf_t * m=node_sl->get_cache_mbuf();
+ rte_mbuf_t * m;
+
pkt_dir_t dir=(pkt_dir_t)node_sl->get_mbuf_cache_dir();
CCorePerPort * lp_port=&m_ports[dir];
CVirtualIFPerSideStats * lp_stats = &m_stats[dir];
- if (m) {
- /* cache case */
- rte_pktmbuf_refcnt_update(m,1);
+ if ( likely(node_sl->is_cache_mbuf_array()) ) {
+ m=node_sl->cache_mbuf_array_get_cur();
}else{
- m=node_sl->alloc_node_with_vm();
- assert(m);
+ m=node_sl->get_cache_mbuf();
+
+ if (m) {
+ /* cache case */
+ rte_pktmbuf_refcnt_update(m,1);
+ }else{
+ m=node_sl->alloc_node_with_vm();
+ assert(m);
+ }
}
if (unlikely(node_sl->is_stat_needed())) {
diff --git a/src/pal/linux/mbuf.h b/src/pal/linux/mbuf.h
index 4132f842..50f00b94 100755
--- a/src/pal/linux/mbuf.h
+++ b/src/pal/linux/mbuf.h
@@ -182,6 +182,13 @@ static inline void utl_rte_pktmbuf_add_last(rte_mbuf_t *m,rte_mbuf_t *m_last){
}
}
+static inline void rte_pktmbuf_refcnt_update(struct rte_mbuf *m, int16_t v)
+{
+ do {
+ rte_mbuf_refcnt_update(m, v);
+ } while ((m = m->next) != NULL);
+}
+
diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
index 54e35d4e..2013c9e8 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -396,6 +396,8 @@ TrexRpcCmdAddStream::parse_vm(const Json::Value &vm, std::unique_ptr<TrexStream>
}
stream->m_vm.set_split_instruction(instr);
}
+ stream->m_cache_size = parse_uint16(vm, "cache", result,0); /* default is zero */
+
}
void
diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp
index 23f1f4c2..4bfeef4b 100644
--- a/src/stateless/dp/trex_stateless_dp_core.cpp
+++ b/src/stateless/dp/trex_stateless_dp_core.cpp
@@ -25,6 +25,7 @@ limitations under the License.
#include "trex_stream.h"
#include "trex_stream_node.h"
#include "trex_streams_compiler.h"
+#include "mbuf.h"
@@ -35,6 +36,18 @@ void CGenNodeStateless::cache_mbuf_array_init(){
}
+
+void CGenNodeStateless::cache_mbuf_array_copy(CGenNodeCacheMbuf *obj,
+ uint16_t size){
+
+ int i;
+ cache_mbuf_array_alloc(size);
+ for (i=0; i<size; i++) {
+ cache_mbuf_array_set(i,obj->m_array[i]);
+ }
+ cache_mbuf_array_set_const_mbuf(obj->m_mbuf_const);
+}
+
rte_mbuf_t ** CGenNodeStateless::cache_mbuf_array_alloc(uint16_t size){
@@ -255,6 +268,25 @@ rte_mbuf_t * CGenNodeStateless::alloc_node_with_vm(){
return (m);
}
+void CGenNodeStateless::free_stl_vm_buf(){
+ rte_mbuf_t * m ;
+ m=get_const_mbuf();
+ if (m) {
+ rte_pktmbuf_free(m); /* reduce the ref counter */
+ /* clear the const marker */
+ clear_const_mbuf();
+ }
+
+ free_prefix_header();
+
+ if (m_vm_flow_var) {
+ /* free flow var */
+ free(m_vm_flow_var);
+ m_vm_flow_var=0;
+ }
+}
+
+
void CGenNodeStateless::free_stl_node(){
@@ -267,20 +299,9 @@ void CGenNodeStateless::free_stl_node(){
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 */
- free(m_vm_flow_var);
- m_vm_flow_var=0;
- }
+ free_stl_vm_buf();
}
@@ -650,12 +671,52 @@ void TrexStatelessDpCore::update_mac_addr(TrexStream * stream,
}
+void TrexStatelessDpCore::replay_vm_into_cache(TrexStream * stream,
+ CGenNodeStateless *node){
+
+ uint16_t cache_size = stream->m_cache_size;
+ assert(cache_size>0);
+ rte_mbuf_t * m=0;
+
+ /* TBD do we have enough from this type of object , need to ask ! */
+
+ uint32_t buf_size = CGenNodeCacheMbuf::get_object_size(cache_size);
+ /* TBD replace with align, zero API */
+ CGenNodeCacheMbuf * p = (CGenNodeCacheMbuf *)malloc(buf_size);
+ assert(p);
+ memset(p,0,buf_size);
+
+ int i;
+ for (i=0; i<cache_size; i++) {
+ p->m_array[i] = node->alloc_node_with_vm();
+ }
+ /* save const */
+ m=node->get_const_mbuf();
+ if (m) {
+ p->m_mbuf_const=m;
+ rte_pktmbuf_refcnt_update(m,1);
+ }
+
+ /* free all VM and const mbuf */
+ node->free_stl_vm_buf();
+
+ /* copy to local node meory */
+ node->cache_mbuf_array_copy(p,cache_size);
+
+ /* free the memory */
+ free(p);
+}
+
+
void
TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port,
TrexStream * stream,
TrexStreamsCompiledObj *comp) {
CGenNodeStateless *node = m_core->create_node_sl();
+ node->cache_mbuf_array_init();
+ node->m_batch_size=0;
+
/* add periodic */
node->m_cache_mbuf=0;
node->m_type = CGenNode::STATELESS_PKT;
@@ -815,6 +876,11 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port,
memcpy(p,stream_pkt , header_size);
update_mac_addr(stream,node,dir,(char *)p);
+
+ if (stream->m_cache_size > 0 ) {
+ /* we need to create cache of objects */
+ replay_vm_into_cache(stream, node);
+ }
}
diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h
index cb102b8d..cd61b486 100644
--- a/src/stateless/dp/trex_stateless_dp_core.h
+++ b/src/stateless/dp/trex_stateless_dp_core.h
@@ -281,6 +281,11 @@ private:
TrexStream * stream,
TrexStreamsCompiledObj *comp);
+
+ void replay_vm_into_cache(TrexStream * stream,
+ CGenNodeStateless *node);
+
+
uint8_t m_thread_id;
uint8_t m_local_port_offset;
diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h
index 4d3c2ae1..e9e5cf5b 100644
--- a/src/stateless/dp/trex_stream_node.h
+++ b/src/stateless/dp/trex_stream_node.h
@@ -361,6 +361,10 @@ public:
}
}
+ void clear_const_mbuf(){
+ m_flags= ( m_flags & ~SL_NODE_CONST_MBUF );
+ }
+
/* prefix header exits only in non cache mode size is 64/128/512 other are not possible right now */
inline void alloc_prefix_header(uint16_t size){
set_prefix_header_size(size);
@@ -371,6 +375,7 @@ public:
inline void free_prefix_header(){
if (m_original_packet_data_prefix) {
free(m_original_packet_data_prefix);
+ m_original_packet_data_prefix=0;
}
}
@@ -388,6 +393,10 @@ public:
void free_stl_node();
+protected:
+
+ void free_stl_vm_buf();
+
public:
void cache_mbuf_array_init();
@@ -395,6 +404,8 @@ public:
return ( m_flags & SL_NODE_CONST_MBUF_CACHE_ARRAY ? true:false );
}
+ void cache_mbuf_array_copy(CGenNodeCacheMbuf *obj,uint16_t size);
+
rte_mbuf_t ** cache_mbuf_array_alloc(uint16_t size);
void cache_mbuf_array_free();