summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/bp_gtest.cpp2
-rwxr-xr-xsrc/bp_sim.cpp19
-rwxr-xr-xsrc/bp_sim.h6
-rw-r--r--src/gtest/trex_stateless_gtest.cpp1072
-rwxr-xr-xsrc/main_dpdk.cpp22
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp44
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_test.cpp5
-rw-r--r--src/rpc-server/trex_rpc_cmd.cpp20
-rw-r--r--src/rpc-server/trex_rpc_cmd_api.h3
-rw-r--r--src/stateless/cp/trex_stream.cpp35
-rw-r--r--src/stateless/cp/trex_stream.h86
-rw-r--r--src/stateless/cp/trex_stream_vm.cpp804
-rw-r--r--src/stateless/cp/trex_stream_vm.h854
-rw-r--r--src/stateless/cp/trex_streams_compiler.cpp37
-rw-r--r--src/stateless/cp/trex_streams_compiler.h9
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.cpp129
-rw-r--r--src/stateless/dp/trex_stream_node.h63
17 files changed, 3022 insertions, 188 deletions
diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp
index 3ef25c9d..005801c4 100755
--- a/src/bp_gtest.cpp
+++ b/src/bp_gtest.cpp
@@ -2041,7 +2041,7 @@ public:
virtual int send_node(CGenNode * node);
- virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, rte_mbuf_t *m){
+ virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, uint8_t * p){
return (0);
}
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index 49cdbd23..081553b5 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -4655,13 +4655,24 @@ int CErfIFStl::send_node(CGenNode * _no_to_use){
if ( m_preview_mode->getFileWrite() ){
CGenNodeStateless * node_sl=(CGenNodeStateless *) _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();
- assert( m );
- pkt_dir_t dir=(pkt_dir_t)node_sl->get_mbuf_cache_dir();
+ 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);
+
+ }
- fill_raw_packet(m,_no_to_use,dir);
BP_ASSERT(m_writer);
bool res=m_writer->write_packet(m_raw);
diff --git a/src/bp_sim.h b/src/bp_sim.h
index 3d81c759..da8e8780 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -381,7 +381,7 @@ public:
*
* @return
*/
- virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, rte_mbuf_t *m)=0;
+ virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, uint8_t * p)=0;
/**
* translate a port_id to the correct dir on the core
@@ -1805,7 +1805,7 @@ public:
virtual int write_pkt(CCapPktRaw *pkt_raw);
virtual int close_file(void);
- virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, rte_mbuf_t *m){
+ virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, uint8_t * p){
return (0);
}
@@ -1884,7 +1884,7 @@ public:
return (0);
}
- virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, rte_mbuf_t *m){
+ virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, uint8_t * p){
return (0);
}
diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp
index 566e7ed4..1626ac25 100644
--- a/src/gtest/trex_stateless_gtest.cpp
+++ b/src/gtest/trex_stateless_gtest.cpp
@@ -32,6 +32,894 @@ limitations under the License.
#include <iostream>
#include <vector>
+
+
+
+class CPcapLoader {
+public:
+ CPcapLoader();
+ ~CPcapLoader();
+
+
+public:
+ bool load_pcap_file(std::string file,int pkt_id=0);
+ void update_ip_src(uint32_t ip_addr);
+ void clone_packet_into_stream(TrexStream * stream);
+ void dump_packet();
+
+public:
+ bool m_valid;
+ CCapPktRaw m_raw;
+ CPacketIndication m_pkt_indication;
+};
+
+CPcapLoader::~CPcapLoader(){
+}
+
+bool CPcapLoader::load_pcap_file(std::string cap_file,int pkt_id){
+ m_valid=false;
+ CPacketParser parser;
+
+ CCapReaderBase * lp=CCapReaderFactory::CreateReader((char *)cap_file.c_str(),0);
+
+ if (lp == 0) {
+ printf(" ERROR file %s does not exist or not supported \n",(char *)cap_file.c_str());
+ return false;
+ }
+
+ int cnt=0;
+ bool found =false;
+
+
+ while ( true ) {
+ /* read packet */
+ if ( lp->ReadPacket(&m_raw) ==false ){
+ break;
+ }
+ if (cnt==pkt_id) {
+ found = true;
+ break;
+ }
+ cnt++;
+ }
+ if ( found ){
+ if ( parser.ProcessPacket(&m_pkt_indication, &m_raw) ){
+ m_valid = true;
+ }
+ }
+
+ delete lp;
+ return (m_valid);
+}
+
+void CPcapLoader::update_ip_src(uint32_t ip_addr){
+
+ if ( m_pkt_indication.l3.m_ipv4 ) {
+ m_pkt_indication.l3.m_ipv4->setSourceIp(ip_addr);
+ m_pkt_indication.l3.m_ipv4->updateCheckSum();
+ }
+}
+
+void CPcapLoader::clone_packet_into_stream(TrexStream * stream){
+
+ uint16_t pkt_size=m_raw.getTotalLen();
+
+ uint8_t *binary = new uint8_t[pkt_size];
+ memcpy(binary,m_raw.raw,pkt_size);
+ stream->m_pkt.binary = binary;
+ stream->m_pkt.len = pkt_size;
+}
+
+
+
+
+CPcapLoader::CPcapLoader(){
+
+}
+
+void CPcapLoader::dump_packet(){
+ if (m_valid ) {
+ m_pkt_indication.Dump(stdout,1);
+ }else{
+ fprintf(stdout," no packets were found \n");
+ }
+}
+
+
+
+
+class basic_vm : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+ virtual void TearDown() {
+ }
+ public:
+};
+
+
+
+
+TEST_F(basic_vm, pkt_size) {
+
+ EXPECT_EQ(calc_writable_mbuf_size(36,62),62);
+ EXPECT_EQ(calc_writable_mbuf_size(63,62),62);
+ EXPECT_EQ(calc_writable_mbuf_size(45,65),65);
+ EXPECT_EQ(calc_writable_mbuf_size(66,65),65);
+ EXPECT_EQ(calc_writable_mbuf_size(62,128),128);
+ EXPECT_EQ(calc_writable_mbuf_size(62,252),61);
+ EXPECT_EQ(calc_writable_mbuf_size(121,252),120);
+ EXPECT_EQ(calc_writable_mbuf_size(253,252),252);
+ EXPECT_EQ(calc_writable_mbuf_size(250,252),252);
+ EXPECT_EQ(calc_writable_mbuf_size(184,252),183);
+}
+
+
+/* start/stop/stop back to back */
+TEST_F(basic_vm, vm0) {
+
+ StreamVm vm;
+
+ vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(20) );
+ vm.add_instruction( new StreamVmInstructionFlowMan( "var1",1,
+ StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,0,1,7 )
+ );
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "var1",14, 0,true)
+ );
+
+ vm.Dump(stdout);
+}
+
+TEST_F(basic_vm, vm1) {
+
+ StreamVm vm;
+
+ vm.add_instruction( new StreamVmInstructionFlowMan( "var1",1,
+ StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,0,1,7 )
+ );
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "var1",26, 0,true)
+ );
+ vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) );
+
+ vm.set_packet_size(128);
+
+ vm.compile();
+
+
+ uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+
+ printf (" program size : %lu \n",(ulong)program_size);
+
+
+ vm.Dump(stdout);
+
+}
+
+TEST_F(basic_vm, vm2) {
+
+ StreamVm vm;
+
+ vm.add_instruction( new StreamVmInstructionFlowMan( "var1",1,
+ StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,4,1,7 )
+ );
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "var1",26, 0,true)
+ );
+ //vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) );
+
+ vm.set_packet_size(128);
+
+ vm.compile();
+
+
+ uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+
+ printf (" program size : %lu \n",(ulong)program_size);
+
+
+ vm.Dump(stdout);
+
+ uint8_t test_udp_pkt[14+20+4+4]={
+ 0x00,0x00,0x00,0x01,0x00,0x00,
+ 0x00,0x00,0x00,0x01,0x00,0x00,
+ 0x08,0x00,
+
+ 0x45,0x00,0x00,0x81, /*14 */
+ 0xaf,0x7e,0x00,0x00, /*18 */
+ 0x12,0x11,0xd9,0x23, /*22 */
+ 0x01,0x01,0x01,0x01, /*26 */
+ 0x3d,0xad,0x72,0x1b, /*30 */
+
+ 0x11,0x11,
+ 0x11,0x11,
+
+ 0x00,0x6d,
+ 0x00,0x00,
+ };
+
+
+
+ StreamDPVmInstructionsRunner runner;
+
+ uint8_t ex[]={5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3};
+
+ int i;
+ for (i=0; i<20; i++) {
+ runner.run(program_size,
+ vm.get_dp_instruction_buffer()->get_program(),
+ vm.get_bss_ptr(),
+ test_udp_pkt);
+ EXPECT_EQ(test_udp_pkt[26],ex[i]);
+ }
+
+}
+
+
+TEST_F(basic_vm, vm3) {
+
+ StreamVm vm;
+
+ vm.add_instruction( new StreamVmInstructionFlowMan( "var1",4 /* size */,
+ StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,4,1,7 )
+ );
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "var1",26, 0,true)
+ );
+ //vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) );
+
+ vm.set_packet_size(128);
+
+ vm.compile();
+
+
+ uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+
+ printf (" program size : %lu \n",(ulong)program_size);
+
+
+ vm.Dump(stdout);
+
+ #define PKT_TEST_SIZE (14+20+4+4)
+ uint8_t test_udp_pkt[PKT_TEST_SIZE]={
+ 0x00,0x00,0x00,0x01,0x00,0x00,
+ 0x00,0x00,0x00,0x01,0x00,0x00,
+ 0x08,0x00,
+
+ 0x45,0x00,0x00,0x81, /*14 */
+ 0xaf,0x7e,0x00,0x00, /*18 */
+ 0x12,0x11,0xd9,0x23, /*22 */
+ 0x01,0x01,0x01,0x01, /*26 */
+ 0x3d,0xad,0x72,0x1b, /*30 */
+
+ 0x11,0x11,
+ 0x11,0x11,
+
+ 0x00,0x6d,
+ 0x00,0x00,
+ };
+
+
+
+ StreamDPVmInstructionsRunner runner;
+
+ uint8_t ex[]={5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3};
+
+ int i;
+ for (i=0; i<20; i++) {
+ runner.run(program_size,
+ vm.get_dp_instruction_buffer()->get_program(),
+ vm.get_bss_ptr(),
+ test_udp_pkt);
+
+ fprintf(stdout," %d \n",i);
+ //utl_DumpBuffer(stdout,test_udp_pkt,PKT_TEST_SIZE,0);
+ /* big */
+ EXPECT_EQ(test_udp_pkt[29],ex[i]);
+ EXPECT_EQ(test_udp_pkt[28],0);
+ EXPECT_EQ(test_udp_pkt[27],0);
+ EXPECT_EQ(test_udp_pkt[26],0);
+ }
+
+}
+
+TEST_F(basic_vm, vm4) {
+
+ StreamVm vm;
+
+ vm.add_instruction( new StreamVmInstructionFlowMan( "var1",4 /* size */,
+ StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,4,1,7 )
+ );
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "var1",26, 0,false)
+ );
+ //vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) );
+
+ vm.set_packet_size(128);
+
+ vm.compile();
+
+
+ uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+
+ printf (" program size : %lu \n",(ulong)program_size);
+
+
+ vm.Dump(stdout);
+
+ #define PKT_TEST_SIZE (14+20+4+4)
+ uint8_t test_udp_pkt[PKT_TEST_SIZE]={
+ 0x00,0x00,0x00,0x01,0x00,0x00,
+ 0x00,0x00,0x00,0x01,0x00,0x00,
+ 0x08,0x00,
+
+ 0x45,0x00,0x00,0x81, /*14 */
+ 0xaf,0x7e,0x00,0x00, /*18 */
+ 0x12,0x11,0xd9,0x23, /*22 */
+ 0x01,0x01,0x01,0x01, /*26 */
+ 0x3d,0xad,0x72,0x1b, /*30 */
+
+ 0x11,0x11,
+ 0x11,0x11,
+
+ 0x00,0x6d,
+ 0x00,0x00,
+ };
+
+
+
+ StreamDPVmInstructionsRunner runner;
+
+ uint8_t ex[]={5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3};
+
+ int i;
+ for (i=0; i<20; i++) {
+ runner.run(program_size,
+ vm.get_dp_instruction_buffer()->get_program(),
+ vm.get_bss_ptr(),
+ test_udp_pkt);
+
+ fprintf(stdout," %d \n",i);
+ //utl_DumpBuffer(stdout,test_udp_pkt,PKT_TEST_SIZE,0);
+ /* not big */
+ EXPECT_EQ(test_udp_pkt[29],0);
+ EXPECT_EQ(test_udp_pkt[28],0);
+ EXPECT_EQ(test_udp_pkt[27],0);
+ EXPECT_EQ(test_udp_pkt[26],ex[i]);
+ }
+
+}
+
+
+/* two fields */
+TEST_F(basic_vm, vm5) {
+
+ StreamVm vm;
+
+ vm.add_instruction( new StreamVmInstructionFlowMan( "var1",4 /* size */,
+ StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,4,1,7 )
+ );
+
+ vm.add_instruction( new StreamVmInstructionFlowMan( "var2",1 /* size */,
+ StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC,25,23,27 ) );
+
+ /* src ip */
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "var1",26, 0,true)
+ );
+
+ /* change TOS */
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "var2",15, 0,true)
+ );
+
+ vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) );
+
+ vm.set_packet_size(128);
+
+ vm.compile();
+
+
+ uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+
+ printf (" program size : %lu \n",(ulong)program_size);
+
+
+ vm.Dump(stdout);
+
+ #define PKT_TEST_SIZE (14+20+4+4)
+ uint8_t test_udp_pkt[PKT_TEST_SIZE]={
+ 0x00,0x00,0x00,0x01,0x00,0x00,
+ 0x00,0x00,0x00,0x01,0x00,0x00,
+ 0x08,0x00,
+
+ 0x45,0x00,0x00,0x81, /*14 */
+ 0xaf,0x7e,0x00,0x00, /*18 */
+ 0x12,0x11,0xd9,0x23, /*22 */
+ 0x01,0x01,0x01,0x01, /*26 */
+ 0x3d,0xad,0x72,0x1b, /*30 */
+
+ 0x11,0x11, /*34 */
+ 0x11,0x11,
+
+ 0x00,0x6d,
+ 0x00,0x00,
+ };
+
+
+
+ StreamDPVmInstructionsRunner runner;
+
+ uint8_t ex[]={5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 1,
+ 2,
+ 3};
+
+ uint8_t ex_tos[]={0x18,
+ 0x17,
+ 0x1b,
+ 0x1a,
+ 0x19,
+ 0x18,
+ 0x17,
+ 0x1b,
+ 0x1a,
+ 0x19,
+ 0x18,
+ 0x17,
+ 0x1b,
+ 0x1a,
+ 0x19,
+ 0x18,
+ 0x17,
+ 0x1b,
+ 0x1a,
+ 0x19,
+ 0x18,
+ 0x17,
+
+ 0x1b,
+ 0x1a,
+ 0x19,
+ 0x18,
+ 0x17,
+
+ 0x1b,
+ 0x1a,
+ 0x19,
+ 0x18,
+ 0x17,
+
+ 0x1b,
+ 0x1a,
+ 0x19,
+ 0x18,
+ 0x17,
+ };
+
+ int i;
+ for (i=0; i<20; i++) {
+ runner.run(program_size,
+ vm.get_dp_instruction_buffer()->get_program(),
+ vm.get_bss_ptr(),
+ test_udp_pkt);
+
+ fprintf(stdout," %d \n",i);
+ //utl_DumpBuffer(stdout,test_udp_pkt,PKT_TEST_SIZE,0);
+ /* not big */
+ EXPECT_EQ(test_udp_pkt[29],ex[i]);
+ EXPECT_EQ(test_udp_pkt[28],0);
+ EXPECT_EQ(test_udp_pkt[27],0);
+ EXPECT_EQ(test_udp_pkt[26],0);
+
+ /* check tos */
+ EXPECT_EQ(test_udp_pkt[15],ex_tos[i]);
+ }
+}
+
+/* -load file, write to file */
+TEST_F(basic_vm, vm6) {
+
+
+
+ StreamVm vm;
+
+ vm.add_instruction( new StreamVmInstructionFlowMan( "var1",4 /* size */,
+ StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,0x10000001,0x10000001,0x100000fe)
+ );
+
+ vm.add_instruction( new StreamVmInstructionFlowMan( "var2",1 /* size */,
+ StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC,25,23,27 ) );
+
+ /* src ip */
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "var1",26, 0,true)
+ );
+
+ /* change TOS */
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "var2",15, 0,true)
+ );
+
+ vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) );
+
+ vm.set_packet_size(128);
+
+ vm.compile();
+
+
+ uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+
+ printf (" program size : %lu \n",(ulong)program_size);
+
+
+ vm.Dump(stdout);
+
+ CPcapLoader pcap;
+ pcap.load_pcap_file("cap2/udp_64B.pcap",0);
+
+
+
+ CFileWriterBase * lpWriter=CCapWriterFactory::CreateWriter(LIBPCAP,(char *)"exp/udp_64B_vm6.pcap");
+ assert(lpWriter);
+
+
+ StreamDPVmInstructionsRunner runner;
+
+ int i;
+ for (i=0; i<20; i++) {
+ runner.run(program_size,
+ vm.get_dp_instruction_buffer()->get_program(),
+ vm.get_bss_ptr(),
+ (uint8_t*)pcap.m_raw.raw);
+
+ //utl_DumpBuffer(stdout,pcap.m_raw.raw,pcap.m_raw.pkt_len,0);
+ assert(lpWriter->write_packet(&pcap.m_raw));
+ }
+
+ delete lpWriter;
+
+ CErfCmp cmp;
+
+ bool res1=cmp.compare("exp/udp_64B_vm6.pcap","exp/udp_64B_vm6-ex.pcap");
+ EXPECT_EQ(1, res1?1:0);
+}
+
+/* test client command */
+TEST_F(basic_vm, vm7) {
+
+
+
+ StreamVm vm;
+
+ vm.add_instruction( new StreamVmInstructionFlowClient( "cl1",
+ 0x10000001,
+ 0x10000004,
+ 1025,
+ 1027,
+ 100,
+ 0) );
+
+ /* src ip */
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "cl1.ip",26, 0,true)
+ );
+
+ vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) );
+
+ /* src port */
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "cl1.port",34, 0,true)
+ );
+
+
+ vm.set_packet_size(128);
+
+ vm.compile();
+
+
+ uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+
+ printf (" program size : %lu \n",(ulong)program_size);
+
+
+ vm.Dump(stdout);
+
+ CPcapLoader pcap;
+ pcap.load_pcap_file("cap2/udp_64B.pcap",0);
+
+
+
+ CFileWriterBase * lpWriter=CCapWriterFactory::CreateWriter(LIBPCAP,(char *)"exp/udp_64B_vm7.pcap");
+ assert(lpWriter);
+
+
+ StreamDPVmInstructionsRunner runner;
+
+ int i;
+ for (i=0; i<20; i++) {
+ runner.run(program_size,
+ vm.get_dp_instruction_buffer()->get_program(),
+ vm.get_bss_ptr(),
+ (uint8_t*)pcap.m_raw.raw);
+
+ assert(lpWriter->write_packet(&pcap.m_raw));
+ }
+
+ delete lpWriter;
+
+ CErfCmp cmp;
+
+ bool res1=cmp.compare("exp/udp_64B_vm7.pcap","exp/udp_64B_vm7-ex.pcap");
+ EXPECT_EQ(1, res1?1:0);
+}
+
+TEST_F(basic_vm, vm8) {
+
+
+
+ StreamVm vm;
+
+ vm.add_instruction( new StreamVmInstructionFlowClient( "cl1",
+ 0x10000001,
+ 0x10000006,
+ 1025,
+ 1027,
+ 4,
+ 0) );
+
+ /* src ip */
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "cl1.ip",26, 0,true)
+ );
+
+ vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) );
+
+ /* src port */
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "cl1.port",34, 0,true)
+ );
+
+
+ vm.set_packet_size(128);
+
+ vm.compile();
+
+
+ uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+
+ printf (" program size : %lu \n",(ulong)program_size);
+
+
+ vm.Dump(stdout);
+
+ CPcapLoader pcap;
+ pcap.load_pcap_file("cap2/udp_64B.pcap",0);
+
+
+
+ CFileWriterBase * lpWriter=CCapWriterFactory::CreateWriter(LIBPCAP,(char *)"exp/udp_64B_vm8.pcap");
+ assert(lpWriter);
+
+
+ StreamDPVmInstructionsRunner runner;
+
+ int i;
+ for (i=0; i<20; i++) {
+ runner.run(program_size,
+ vm.get_dp_instruction_buffer()->get_program(),
+ vm.get_bss_ptr(),
+ (uint8_t*)pcap.m_raw.raw);
+
+ assert(lpWriter->write_packet(&pcap.m_raw));
+ }
+
+ delete lpWriter;
+
+ CErfCmp cmp;
+
+ bool res1=cmp.compare("exp/udp_64B_vm8.pcap","exp/udp_64B_vm8-ex.pcap");
+ EXPECT_EQ(1, res1?1:0);
+}
+
+static void vm_build_program_seq(StreamVm & vm,
+ uint16_t packet_size,
+ bool should_compile){
+
+ vm.add_instruction( new StreamVmInstructionFlowClient( "tuple_gen",
+ 0x10000001,
+ 0x10000006,
+ 1025,
+ 1027,
+ 20,
+ 0) );
+
+ /* src ip */
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "tuple_gen.ip",26, 0,true)
+ );
+
+ vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) );
+
+ /* src port */
+ vm.add_instruction( new StreamVmInstructionWriteToPkt( "tuple_gen.port",34, 0,true)
+ );
+
+
+ vm.set_packet_size(packet_size);
+
+ if (should_compile) {
+ vm.compile();
+ }
+}
+
+
+TEST_F(basic_vm, vm9) {
+
+
+ StreamVm vm;
+
+ vm_build_program_seq(vm,128, true);
+
+ printf(" max packet update %lu \n",(ulong)vm.get_max_packet_update_offset());
+
+ EXPECT_EQ(36,vm.get_max_packet_update_offset());
+
+ uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+
+ printf (" program size : %lu \n",(ulong)program_size);
+
+
+ vm.Dump(stdout);
+
+ CPcapLoader pcap;
+ pcap.load_pcap_file("cap2/udp_64B.pcap",0);
+
+
+
+ CFileWriterBase * lpWriter=CCapWriterFactory::CreateWriter(LIBPCAP,(char *)"exp/udp_64B_vm9.pcap");
+ assert(lpWriter);
+
+
+ StreamDPVmInstructionsRunner runner;
+
+ int i;
+ for (i=0; i<30; i++) {
+ runner.run(program_size,
+ vm.get_dp_instruction_buffer()->get_program(),
+ vm.get_bss_ptr(),
+ (uint8_t*)pcap.m_raw.raw);
+
+ assert(lpWriter->write_packet(&pcap.m_raw));
+ }
+
+ delete lpWriter;
+
+ CErfCmp cmp;
+
+ bool res1=cmp.compare("exp/udp_64B_vm9.pcap","exp/udp_64B_vm9-ex.pcap");
+ EXPECT_EQ(1, res1?1:0);
+}
+
+
+/* test vmDP object */
+TEST_F(basic_vm, vm10) {
+
+ StreamVm vm;
+
+ vm_build_program_seq(vm,128, true);
+
+ printf(" max packet update %lu \n",(ulong)vm.get_max_packet_update_offset());
+
+ EXPECT_EQ(36,vm.get_max_packet_update_offset());
+
+ StreamVmDp * lpDpVm =vm.cloneAsVmDp();
+
+ EXPECT_EQ(lpDpVm->get_bss_size(),vm.get_bss_size());
+
+ uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+
+ printf (" program size : %lu \n",(ulong)program_size);
+
+
+ vm.Dump(stdout);
+
+ CPcapLoader pcap;
+ pcap.load_pcap_file("cap2/udp_64B.pcap",0);
+
+
+
+ CFileWriterBase * lpWriter=CCapWriterFactory::CreateWriter(LIBPCAP,(char *)"exp/udp_64B_vm9.pcap");
+ assert(lpWriter);
+
+
+ StreamDPVmInstructionsRunner runner;
+
+ int i;
+ for (i=0; i<30; i++) {
+
+ runner.run(lpDpVm->get_program_size(),
+ lpDpVm->get_program(),
+ lpDpVm->get_bss(),
+ (uint8_t*)pcap.m_raw.raw);
+
+ assert(lpWriter->write_packet(&pcap.m_raw));
+ }
+
+ delete lpWriter;
+
+ CErfCmp cmp;
+ delete lpDpVm;
+
+ bool res1=cmp.compare("exp/udp_64B_vm9.pcap","exp/udp_64B_vm9-ex.pcap");
+ EXPECT_EQ(1, res1?1:0);
+}
+
+
+
+//////////////////////////////////////////////////////
+
+
#define EXPECT_EQ_UINT32(a,b) EXPECT_EQ((uint32_t)(a),(uint32_t)(b))
@@ -275,96 +1163,6 @@ public:
};
-class CPcapLoader {
-public:
- CPcapLoader();
- ~CPcapLoader();
-
-
-public:
- bool load_pcap_file(std::string file,int pkt_id=0);
- void update_ip_src(uint32_t ip_addr);
- void clone_packet_into_stream(TrexStream * stream);
- void dump_packet();
-
-public:
- bool m_valid;
- CCapPktRaw m_raw;
- CPacketIndication m_pkt_indication;
-};
-
-CPcapLoader::~CPcapLoader(){
-}
-
-bool CPcapLoader::load_pcap_file(std::string cap_file,int pkt_id){
- m_valid=false;
- CPacketParser parser;
-
- CCapReaderBase * lp=CCapReaderFactory::CreateReader((char *)cap_file.c_str(),0);
-
- if (lp == 0) {
- printf(" ERROR file %s does not exist or not supported \n",(char *)cap_file.c_str());
- return false;
- }
-
- int cnt=0;
- bool found =false;
-
-
- while ( true ) {
- /* read packet */
- if ( lp->ReadPacket(&m_raw) ==false ){
- break;
- }
- if (cnt==pkt_id) {
- found = true;
- break;
- }
- cnt++;
- }
- if ( found ){
- if ( parser.ProcessPacket(&m_pkt_indication, &m_raw) ){
- m_valid = true;
- }
- }
-
- delete lp;
- return (m_valid);
-}
-
-void CPcapLoader::update_ip_src(uint32_t ip_addr){
-
- if ( m_pkt_indication.l3.m_ipv4 ) {
- m_pkt_indication.l3.m_ipv4->setSourceIp(ip_addr);
- m_pkt_indication.l3.m_ipv4->updateCheckSum();
- }
-}
-
-void CPcapLoader::clone_packet_into_stream(TrexStream * stream){
-
- uint16_t pkt_size=m_raw.getTotalLen();
-
- uint8_t *binary = new uint8_t[pkt_size];
- memcpy(binary,m_raw.raw,pkt_size);
- stream->m_pkt.binary = binary;
- stream->m_pkt.len = pkt_size;
-}
-
-
-
-
-CPcapLoader::CPcapLoader(){
-
-}
-
-void CPcapLoader::dump_packet(){
- if (m_valid ) {
- m_pkt_indication.Dump(stdout,1);
- }else{
- fprintf(stdout," no packets were found \n");
- }
-}
-
TEST_F(basic_stl, load_pcap_file) {
printf (" stateles %d \n",(int)sizeof(CGenNodeStateless));
@@ -1215,6 +2013,100 @@ TEST_F(basic_stl, multi_pkt1) {
}
+class CEnableVm {
+public:
+ void run(bool full_packet,double duration );
+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){
+
+ CBasicStl t1;
+ CParserOption * po =&CGlobalInfo::m_options;
+ po->preview.setVMode(7);
+ po->preview.setFileWrite(true);
+ po->out_file =m_out_file;
+
+ TrexStreamsCompiler compile;
+
+ uint8_t port_id=0;
+
+ std::vector<TrexStream *> streams;
+
+ TrexStream * stream1 = new TrexStream(TrexStream::stCONTINUOUS,0,0);
+
+ stream1->set_pps(1.0);
+
+ stream1->m_enabled = true;
+ stream1->m_self_start = true;
+ stream1->m_port_id= port_id;
+
+ CPcapLoader pcap;
+ pcap.load_pcap_file(m_input_packet,0);
+ pcap.update_ip_src(0x10000001);
+ pcap.clone_packet_into_stream(stream1);
+
+ uint16_t pkt_size=pcap.m_raw.pkt_len;
+
+ vm_build_program_seq(stream1->m_vm,pkt_size, false);
+ #if 0
+ if ( full_packet ){
+ EXPECT_EQ(stream1->m_vm_prefix_size,pkt_size);
+ }else{
+ EXPECT_EQ(stream1->m_vm_prefix_size,35);
+ }
+ #endif
+
+
+ streams.push_back(stream1);
+
+ // stream - clean
+ std::vector<TrexStreamsCompiledObj *> objs;
+
+ assert(compile.compile(port_id,streams, objs) );
+
+ TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], duration /*sec */ );
+
+
+ t1.m_msg = lpstart;
+
+ bool res=t1.init();
+
+ delete stream1 ;
+
+ EXPECT_EQ_UINT32(1, res?1:0)<< "pass";
+}
+
+
+TEST_F(basic_stl, vm_enable0) {
+
+ CEnableVm vm_test;
+ vm_test.m_out_file = "exp/stl_vm_enable0";
+ vm_test.m_input_packet = "cap2/udp_64B.pcap";
+ vm_test.run(true);
+}
+
+
+TEST_F(basic_stl, vm_enable1) {
+
+ CEnableVm vm_test;
+ vm_test.m_out_file = "exp/stl_vm_enable1";
+ vm_test.m_input_packet = "stl/udp_594B_no_crc.pcap";
+ vm_test.run(false);
+}
+
+
+
+TEST_F(basic_stl, vm_enable2) {
+
+ CEnableVm vm_test;
+ vm_test.m_out_file = "exp/stl_vm_enable2";
+ vm_test.m_input_packet = "cap2/udp_64B.pcap";
+ vm_test.run(true,50.0);
+}
+
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 441df5ce..8c9eb914 100755
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -1874,7 +1874,7 @@ public:
bool process_rx_pkt(pkt_dir_t dir,rte_mbuf_t * m);
- virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, rte_mbuf_t *m);
+ virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, uint8_t * p);
virtual pkt_dir_t port_id_to_dir(uint8_t port_id);
@@ -2077,6 +2077,8 @@ int CCoreEthIF::send_pkt(CCorePerPort * lp_port,
CVirtualIFPerSideStats * lp_stats
){
+ //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);
@@ -2133,12 +2135,18 @@ int CCoreEthIFStateless::send_node(CGenNode * no){
/* check that we have mbuf */
rte_mbuf_t * m=node_sl->get_cache_mbuf();
- assert( m );
pkt_dir_t dir=(pkt_dir_t)node_sl->get_mbuf_cache_dir();
CCorePerPort * lp_port=&m_ports[dir];
CVirtualIFPerSideStats * lp_stats = &m_stats[dir];
- rte_pktmbuf_refcnt_update(m,1);
+ if (m) {
+ /* cache case */
+ rte_pktmbuf_refcnt_update(m,1);
+ }else{
+ m=node_sl->alloc_node_with_vm();
+ assert(m);
+ }
send_pkt(lp_port,m,lp_stats);
+
return (0);
};
@@ -2237,14 +2245,12 @@ int CCoreEthIF::send_node(CGenNode * node){
}
-int CCoreEthIF::update_mac_addr_from_global_cfg(pkt_dir_t dir,
- rte_mbuf_t *m){
- assert(m);
+int CCoreEthIF::update_mac_addr_from_global_cfg(pkt_dir_t dir, uint8_t * p){
+ assert(p);
assert(dir<2);
+
CCorePerPort * lp_port=&m_ports[dir];
- uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*);
uint8_t p_id=lp_port->m_port->get_port_id();
-
memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12);
return (0);
}
diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
index 305ccc17..a1c3bb99 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -29,22 +29,6 @@ limitations under the License.
using namespace std;
-/**
- * simple parser of string to number
- * only difference is that it enforces whole number
- * and not partial
- *
- */
-static uint64_t str2num(const string &str) {
- size_t index;
-
- uint64_t num = std::stoull(str, &index, 0);
- if (index != str.size()) {
- throw invalid_argument("could not parse string to number");
- }
-
- return (num);
-}
/***************************
* add new stream
@@ -213,31 +197,9 @@ TrexRpcCmdAddStream::parse_vm_instr_flow_var(const Json::Value &inst, TrexStream
throw TrexRpcException("internal error");
}
- std::string init_value_str = parse_string(inst, "init_value", result);
- std::string min_value_str = parse_string(inst, "min_value", result);
- std::string max_value_str = parse_string(inst, "max_value", result);
-
- uint64_t init_value = 0;
- uint64_t min_value = 0;
- uint64_t max_value = 0;
-
- try {
- init_value = str2num(init_value_str);
- } catch (invalid_argument) {
- generate_parse_err(result, "failed to parse 'init_value' as a number");
- }
-
- try {
- min_value = str2num(min_value_str);
- } catch (invalid_argument) {
- generate_parse_err(result, "failed to parse 'min_value' as a number");
- }
-
- try {
- max_value = str2num(max_value_str);
- } catch (invalid_argument) {
- generate_parse_err(result, "failed to parse 'max_value' as a number");
- }
+ uint64_t init_value = parse_uint64(inst, "init_value", result);
+ uint64_t min_value = parse_uint64(inst, "min_value", result);
+ uint64_t max_value = parse_uint64(inst, "max_value", result);
stream->m_vm.add_instruction(new StreamVmInstructionFlowMan(flow_var_name,
flow_var_size,
diff --git a/src/rpc-server/commands/trex_rpc_cmd_test.cpp b/src/rpc-server/commands/trex_rpc_cmd_test.cpp
index 3cdddd31..ad4d3bb1 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_test.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_test.cpp
@@ -21,6 +21,7 @@ limitations under the License.
#include "trex_rpc_cmds.h"
#include <iostream>
#include <sstream>
+#include <json/json.h>
using namespace std;
@@ -31,7 +32,7 @@ using namespace std;
trex_rpc_cmd_rc_e
TrexRpcCmdTestAdd::_run(const Json::Value &params, Json::Value &result) {
- result["result"] = parse_int(params, "x", result) + parse_int(params, "y", result);
+ result["result"] = Json::Value::UInt64(parse_uint64(params, "x", result) + parse_uint64(params, "y", result));
return (TREX_RPC_CMD_OK);
}
@@ -44,7 +45,7 @@ TrexRpcCmdTestAdd::_run(const Json::Value &params, Json::Value &result) {
trex_rpc_cmd_rc_e
TrexRpcCmdTestSub::_run(const Json::Value &params, Json::Value &result) {
- result["result"] = parse_int(params, "x", result) - parse_int(params, "y", result);
+ result["result"] = Json::Value::UInt64(parse_uint64(params, "x", result) - parse_uint64(params, "y", result));
return (TREX_RPC_CMD_OK);
}
diff --git a/src/rpc-server/trex_rpc_cmd.cpp b/src/rpc-server/trex_rpc_cmd.cpp
index 8f0ffbad..b5dd121c 100644
--- a/src/rpc-server/trex_rpc_cmd.cpp
+++ b/src/rpc-server/trex_rpc_cmd.cpp
@@ -98,6 +98,8 @@ TrexRpcCommand::type_to_str(field_type_e type) {
return "uint16";
case FIELD_TYPE_UINT32:
return "uint32";
+ case FIELD_TYPE_UINT64:
+ return "uint64";
case FIELD_TYPE_BOOL:
return "bool";
case FIELD_TYPE_INT:
@@ -179,6 +181,18 @@ TrexRpcCommand::parse_uint32(const Json::Value &parent, int index, Json::Value &
return parent[index].asUInt();
}
+uint64_t
+TrexRpcCommand::parse_uint64(const Json::Value &parent, const std::string &name, Json::Value &result) {
+ check_field_type(parent, name, FIELD_TYPE_UINT64, result);
+ return parent[name].asUInt64();
+}
+
+uint64_t
+TrexRpcCommand::parse_uint64(const Json::Value &parent, int index, Json::Value &result) {
+ check_field_type(parent, index, FIELD_TYPE_UINT64, result);
+ return parent[index].asUInt64();
+}
+
int
TrexRpcCommand::parse_int(const Json::Value &parent, const std::string &name, Json::Value &result) {
check_field_type(parent, name, FIELD_TYPE_INT, result);
@@ -286,6 +300,12 @@ TrexRpcCommand::check_field_type_common(const Json::Value &field, const std::str
}
break;
+ case FIELD_TYPE_UINT64:
+ if (!field.isInt64()) {
+ rc = false;
+ }
+ break;
+
case FIELD_TYPE_BOOL:
if (!field.isBool()) {
rc = false;
diff --git a/src/rpc-server/trex_rpc_cmd_api.h b/src/rpc-server/trex_rpc_cmd_api.h
index f81981d4..7cbdf4ff 100644
--- a/src/rpc-server/trex_rpc_cmd_api.h
+++ b/src/rpc-server/trex_rpc_cmd_api.h
@@ -100,6 +100,7 @@ protected:
FIELD_TYPE_BYTE,
FIELD_TYPE_UINT16,
FIELD_TYPE_UINT32,
+ FIELD_TYPE_UINT64,
FIELD_TYPE_INT,
FIELD_TYPE_DOUBLE,
FIELD_TYPE_BOOL,
@@ -138,6 +139,7 @@ protected:
uint8_t parse_byte(const Json::Value &parent, const std::string &name, Json::Value &result);
uint16_t parse_uint16(const Json::Value &parent, const std::string &name, Json::Value &result);
uint32_t parse_uint32(const Json::Value &parent, const std::string &name, Json::Value &result);
+ uint64_t parse_uint64(const Json::Value &parent, const std::string &name, Json::Value &result);
int parse_int(const Json::Value &parent, const std::string &name, Json::Value &result);
double parse_double(const Json::Value &parent, const std::string &name, Json::Value &result);
bool parse_bool(const Json::Value &parent, const std::string &name, Json::Value &result);
@@ -148,6 +150,7 @@ protected:
uint8_t parse_byte(const Json::Value &parent, int index, Json::Value &result);
uint16_t parse_uint16(const Json::Value &parent, int index, Json::Value &result);
uint32_t parse_uint32(const Json::Value &parent, int index, Json::Value &result);
+ uint64_t parse_uint64(const Json::Value &parent, int index, Json::Value &result);
int parse_int(const Json::Value &parent, int index, Json::Value &result);
double parse_double(const Json::Value &parent, int index, Json::Value &result);
bool parse_bool(const Json::Value &parent, int index, Json::Value &result);
diff --git a/src/stateless/cp/trex_stream.cpp b/src/stateless/cp/trex_stream.cpp
index cad603e2..72e72c7c 100644
--- a/src/stateless/cp/trex_stream.cpp
+++ b/src/stateless/cp/trex_stream.cpp
@@ -53,6 +53,33 @@ std::string TrexStream::get_stream_type_str(stream_type_t stream_type){
}
+void
+TrexStream::compile() {
+
+ /* in case there are no instructions - nothing to do */
+ if (m_vm.is_vm_empty()) {
+ m_has_vm = false;
+ return;
+ }
+
+ m_has_vm = true;
+
+ m_vm.set_packet_size(m_pkt.len);
+
+ m_vm.compile();
+
+ m_vm_dp = m_vm.cloneAsVmDp();
+
+
+ /* calc m_vm_prefix_size which is the size of the writable packet */
+ uint16_t max_pkt_offset = m_vm_dp->get_max_packet_update_offset();
+ uint16_t pkt_size = m_pkt.len;
+
+ /* calculate the mbuf size that we should allocate */
+ m_vm_prefix_size = calc_writable_mbuf_size(max_pkt_offset, pkt_size);
+}
+
+
void TrexStream::Dump(FILE *fd){
fprintf(fd,"\n");
@@ -103,6 +130,8 @@ TrexStream::TrexStream(uint8_t type,
m_pkt.binary = NULL;
m_pkt.len = 0;
+ m_has_vm = false;
+ m_vm_prefix_size = 0;
m_rx_check.m_enable = false;
@@ -111,12 +140,17 @@ TrexStream::TrexStream(uint8_t type,
m_burst_total_pkts=0;
m_num_bursts=1;
m_ibg_usec=0.0;
+ m_vm_dp = NULL;
}
TrexStream::~TrexStream() {
if (m_pkt.binary) {
delete [] m_pkt.binary;
}
+ if ( m_vm_dp ){
+ delete m_vm_dp;
+ m_vm_dp=NULL;
+ }
}
void
@@ -199,3 +233,4 @@ int TrexStreamTable::size() {
return m_stream_table.size();
}
+
diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h
index b991b05f..720246f6 100644
--- a/src/stateless/cp/trex_stream.h
+++ b/src/stateless/cp/trex_stream.h
@@ -36,6 +36,54 @@ limitations under the License.
class TrexRpcCmdAddStream;
+static inline uint16_t get_log2_size(uint16_t size){
+
+ uint16_t _sizes[]={64,128,256,512,1024,2048};
+ int i;
+ for (i=0; i<sizeof(_sizes)/sizeof(_sizes[0]); i++) {
+ if (size<=_sizes[i]) {
+ return (_sizes[i]);
+ }
+ }
+ assert(0);
+ return (0);
+}
+
+/**
+ * calculate the size of writable mbuf in bytes. maximum size if packet size
+ *
+ * @param max_offset_writable
+ * the last byte that we don't write too. for example when 63 it means that bytes [62] in the array is written (zero base)
+ * @param pkt_size packet size in bytes
+ *
+ * @return the writable size of the first mbuf . the idea is to give at least 64 bytes const mbuf else all packet will be writeable
+ *
+ * examples:
+ * max_offset_writable =63
+ * pkt_size =62
+ * ==>62
+ *
+ */
+static inline uint16_t calc_writable_mbuf_size(uint16_t max_offset_writable,
+ uint16_t pkt_size){
+
+ if ( pkt_size<=64 ){
+ return (pkt_size);
+ }
+ if (pkt_size<=128) {
+ return (pkt_size);
+ }
+
+ //pkt_size> 128
+ uint16_t non_writable = pkt_size - (max_offset_writable -1) ;
+ if ( non_writable<64 ) {
+ return (pkt_size);
+ }
+ return(max_offset_writable-1);
+}
+
+
+
struct CStreamPktData {
uint8_t *binary;
uint16_t len;
@@ -132,10 +180,18 @@ public:
TrexStream * clone_as_dp() const {
TrexStream *dp = new TrexStream(m_type,m_port_id,m_stream_id);
-
-
- dp->m_isg_usec = m_isg_usec;
- dp->m_next_stream_id = m_next_stream_id;
+ dp->m_has_vm = m_has_vm;
+ if (m_vm_dp) {
+ /* should have vm */
+ assert(m_has_vm);
+ dp->m_vm_dp = m_vm_dp->clone();
+ }else{
+ dp->m_vm_dp = NULL;
+ }
+ dp->m_vm_prefix_size = m_vm_prefix_size;
+
+ dp->m_isg_usec = m_isg_usec;
+ dp->m_next_stream_id = m_next_stream_id;
dp->m_enabled = m_enabled;
dp->m_self_start = m_self_start;
@@ -162,10 +218,28 @@ public:
}
void Dump(FILE *fd);
+
+ bool is_vm(){
+ return ( m_has_vm );
+ }
+
+ StreamVmDp * getDpVm(){
+ return ( m_vm_dp);
+ }
+
+ void post_vm_compile();
+
+ /**
+ * internal compilation of stream (for DP)
+ *
+ */
+ void compile();
+
public:
/* basic */
uint8_t m_type;
uint8_t m_port_id;
+ uint16_t m_vm_prefix_size; /* writeable mbuf size */
uint32_t m_stream_id; /* id from RPC can be anything */
@@ -176,6 +250,10 @@ public:
/* indicators */
bool m_enabled;
bool m_self_start;
+ bool m_has_vm; /* do we have instructions to run */
+
+
+ StreamVmDp * m_vm_dp; /* compile VM */
CStreamPktData m_pkt;
/* pkt */
diff --git a/src/stateless/cp/trex_stream_vm.cpp b/src/stateless/cp/trex_stream_vm.cpp
index 2e760ae9..e10e1a81 100644
--- a/src/stateless/cp/trex_stream_vm.cpp
+++ b/src/stateless/cp/trex_stream_vm.cpp
@@ -1,5 +1,6 @@
/*
Itay Marom
+ Hanoch Haim
Cisco Systems, Inc.
*/
@@ -19,6 +20,108 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <trex_stream_vm.h>
+#include <sstream>
+#include <assert.h>
+#include <iostream>
+#include <trex_stateless.h>
+#include <common/Network/Packet/IPHeader.h>
+#include <common/basic_utils.h>
+
+
+
+
+void StreamVmInstructionFixChecksumIpv4::Dump(FILE *fd){
+ fprintf(fd," fix_check_sum , %lu \n",(ulong)m_pkt_offset);
+}
+
+
+void StreamVmInstructionFlowMan::sanity_check_valid_size(uint32_t ins_id,StreamVm *lp){
+ uint8_t valid[]={1,2,4,8};
+ int i;
+ for (i=0; i<sizeof(valid)/sizeof(valid[0]); i++) {
+ if (valid[i]==m_size_bytes) {
+ return;
+ }
+ }
+
+ std::stringstream ss;
+
+ ss << "instruction id '" << ins_id << "' has non valid length " << m_size_bytes ;
+
+ lp->err(ss.str());
+}
+
+void StreamVmInstructionFlowMan::sanity_check_valid_opt(uint32_t ins_id,StreamVm *lp){
+ uint8_t valid[]={FLOW_VAR_OP_INC,
+ FLOW_VAR_OP_DEC,
+ FLOW_VAR_OP_RANDOM};
+ int i;
+ for (i=0; i<sizeof(valid)/sizeof(valid[0]); i++) {
+ if (valid[i]==m_op) {
+ return;
+ }
+ }
+
+ std::stringstream ss;
+
+ ss << "instruction id '" << ins_id << "' has non valid op " << (int)m_op ;
+
+ lp->err(ss.str());
+}
+
+void StreamVmInstructionFlowMan::sanity_check_valid_range(uint32_t ins_id,StreamVm *lp){
+ //TBD check that init,min,max in valid range
+}
+
+
+
+void StreamVmInstructionFlowMan::sanity_check(uint32_t ins_id,StreamVm *lp){
+
+ sanity_check_valid_size(ins_id,lp);
+ sanity_check_valid_opt(ins_id,lp);
+ sanity_check_valid_range(ins_id,lp);
+}
+
+
+void StreamVmInstructionFlowMan::Dump(FILE *fd){
+ fprintf(fd," flow_var , %s ,%lu, ",m_var_name.c_str(),(ulong)m_size_bytes);
+
+ switch (m_op) {
+
+ case FLOW_VAR_OP_INC :
+ fprintf(fd," INC ,");
+ break;
+ case FLOW_VAR_OP_DEC :
+ fprintf(fd," DEC ,");
+ break;
+ case FLOW_VAR_OP_RANDOM :
+ fprintf(fd," RANDOM ,");
+ break;
+ default:
+ fprintf(fd," UNKNOWN,");
+ break;
+ };
+
+ fprintf(fd," (%lu:%lu:%lu) \n",m_init_value,m_min_value,m_max_value);
+}
+
+
+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 StreamVmInstructionFlowClient::Dump(FILE *fd){
+
+ fprintf(fd," client_var ,%s , ",m_var_name.c_str());
+
+ fprintf(fd," ip:(%x-%x) port:(%x-%x) flow_limit:%lu flags: %x\n",m_client_min,m_client_max, m_port_min,m_port_max,(ulong)m_limit_num_flows,m_flags);
+}
+
+
+
/***************************
* StreamVmInstruction
@@ -36,19 +139,714 @@ void StreamVm::add_instruction(StreamVmInstruction *inst) {
m_inst_list.push_back(inst);
}
+StreamDPVmInstructions *
+StreamVm::get_dp_instruction_buffer(){
+ return &m_instructions;
+}
+
+
const std::vector<StreamVmInstruction *> &
StreamVm::get_instruction_list() {
return m_inst_list;
}
-bool StreamVm::compile() {
- /* implement me */
- return (false);
+void StreamVm::var_clear_table(){
+ m_flow_var_offset.clear();
+}
+
+bool StreamVm::var_add(const std::string &var_name,VmFlowVarRec & var){
+ m_flow_var_offset[var_name] = var;
+ return (true);
+}
+
+
+uint16_t StreamVm::get_var_offset(const std::string &var_name){
+ VmFlowVarRec var;
+ bool res=var_lookup(var_name,var);
+ assert(res);
+ return (var.m_offset);
+}
+
+
+bool StreamVm::var_lookup(const std::string &var_name,VmFlowVarRec & var){
+ auto search = m_flow_var_offset.find(var_name);
+
+ if (search != m_flow_var_offset.end()) {
+ var = search->second;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+
+void StreamVm::err(const std::string &err){
+ throw TrexException("*** error: " + err);
+}
+
+
+void StreamVm::build_flow_var_table() {
+
+ var_clear_table();
+ m_cur_var_offset=0;
+ uint32_t ins_id=0;
+ /* scan all flow var instruction and build */
+ for (auto inst : m_inst_list) {
+ if ( inst->get_instruction_type() == StreamVmInstruction::itFLOW_MAN ){
+
+ StreamVmInstructionFlowMan * ins_man=(StreamVmInstructionFlowMan *)inst;
+
+ /* check that instruction is valid */
+ ins_man->sanity_check(ins_id,this);
+
+ VmFlowVarRec var;
+ /* if this is the first time */
+ if ( var_lookup( ins_man->m_var_name,var) == true){
+ std::stringstream ss;
+ ss << "instruction id '" << ins_id << "' flow variable name " << ins_man->m_var_name << " already exists";
+ err(ss.str());
+ }else{
+ var.m_offset=m_cur_var_offset;
+ var.m_ins.m_ins_flowv = ins_man;
+ var.m_size_bytes = ins_man->m_size_bytes;
+ var_add(ins_man->m_var_name,var);
+ m_cur_var_offset += ins_man->m_size_bytes;
+
+ }
+ }
+
+ if ( inst->get_instruction_type() == StreamVmInstruction::itFLOW_CLIENT ){
+ StreamVmInstructionFlowClient * ins_man=(StreamVmInstructionFlowClient *)inst;
+
+ VmFlowVarRec var;
+ /* if this is the first time */
+ if ( var_lookup( ins_man->m_var_name+".ip",var) == true){
+ std::stringstream ss;
+ ss << "instruction id '" << ins_id << "' client variable name " << ins_man->m_var_name << " already exists";
+ err(ss.str());
+ }
+ if ( var_lookup( ins_man->m_var_name+".port",var) == true){
+ std::stringstream ss;
+ ss << "instruction id '" << ins_id << "' client variable name " << ins_man->m_var_name << " already exists";
+ err(ss.str());
+ }
+
+ if ( var_lookup( ins_man->m_var_name+".flow_limit",var) == true){
+ std::stringstream ss;
+ ss << "instruction id '" << ins_id << "' client variable name " << ins_man->m_var_name << " already exists";
+ err(ss.str());
+ }
+
+ var.m_offset = m_cur_var_offset;
+ var.m_ins.m_ins_flow_client = ins_man;
+ var.m_size_bytes =4;
+
+ VmFlowVarRec var_port;
+
+ var_port.m_offset = m_cur_var_offset+4;
+ var_port.m_ins.m_ins_flow_client = ins_man;
+ var_port.m_size_bytes =2;
+
+ VmFlowVarRec var_flow_limit;
+
+ var_flow_limit.m_offset = m_cur_var_offset+6;
+ var_flow_limit.m_ins.m_ins_flow_client = ins_man;
+ var_flow_limit.m_size_bytes =4;
+
+
+ var_add(ins_man->m_var_name+".ip",var);
+ var_add(ins_man->m_var_name+".port",var_port);
+ var_add(ins_man->m_var_name+".flow_limit",var_flow_limit);
+
+ m_cur_var_offset += StreamVmInstructionFlowClient::get_flow_var_size();
+
+ assert(sizeof(StreamDPFlowClient)==StreamVmInstructionFlowClient::get_flow_var_size());
+ }
+
+ /* limit the flow var size */
+ if (m_cur_var_offset > StreamVm::svMAX_FLOW_VAR ) {
+ std::stringstream ss;
+ ss << "too many flow varibles current size is :" << m_cur_var_offset << " maximum support is " << StreamVm::svMAX_FLOW_VAR;
+ err(ss.str());
+ }
+ ins_id++;
+ }
+
+}
+
+void StreamVm::alloc_bss(){
+ free_bss();
+ m_bss=(uint8_t *)malloc(m_cur_var_offset);
+}
+
+void StreamVm::clean_max_field_cnt(){
+ m_max_field_update=0;
+}
+
+void StreamVm::add_field_cnt(uint16_t new_cnt){
+
+ if ( new_cnt > m_max_field_update) {
+ m_max_field_update = new_cnt;
+ }
+}
+
+
+void StreamVm::free_bss(){
+ if (m_bss) {
+ free(m_bss);
+ m_bss=0;
+ }
+}
+
+
+void StreamVm::build_program(){
+
+ /* build the commands into a buffer */
+ m_instructions.clear();
+ clean_max_field_cnt();
+ uint32_t ins_id=0;
+
+ for (auto inst : m_inst_list) {
+ StreamVmInstruction::instruction_type_t ins_type=inst->get_instruction_type();
+
+ /* itFIX_IPV4_CS */
+ if (ins_type == StreamVmInstruction::itFIX_IPV4_CS) {
+ StreamVmInstructionFixChecksumIpv4 *lpFix =(StreamVmInstructionFixChecksumIpv4 *)inst;
+
+ add_field_cnt(lpFix->m_pkt_offset +12);
+
+ if ( (lpFix->m_pkt_offset + IPV4_HDR_LEN) > m_pkt_size ) {
+
+ std::stringstream ss;
+ ss << "instruction id '" << ins_id << "' fix ipv4 command offset " << lpFix->m_pkt_offset << " is too high relative to packet size "<< m_pkt_size;
+ err(ss.str());
+ }
+
+ StreamDPOpIpv4Fix ipv_fix;
+ ipv_fix.m_offset = lpFix->m_pkt_offset;
+ ipv_fix.m_op = StreamDPVmInstructions::ditFIX_IPV4_CS;
+ m_instructions.add_command(&ipv_fix,sizeof(ipv_fix));
+ }
+
+
+ /* flow man */
+ if (ins_type == StreamVmInstruction::itFLOW_MAN) {
+ StreamVmInstructionFlowMan *lpMan =(StreamVmInstructionFlowMan *)inst;
+
+
+ if (lpMan->m_size_bytes == 1 ){
+
+ uint8_t op=StreamDPVmInstructions::ditINC8;
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_INC ){
+ op = StreamDPVmInstructions::ditINC8 ;
+ }
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC ){
+ op = StreamDPVmInstructions::ditDEC8 ;
+ }
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM ){
+ op = StreamDPVmInstructions::ditRANDOM8 ;
+ }
+
+ StreamDPOpFlowVar8 fv8;
+ fv8.m_op = op;
+ fv8.m_flow_offset = get_var_offset(lpMan->m_var_name);
+ fv8.m_min_val = (uint8_t)lpMan->m_min_value;
+ fv8.m_max_val = (uint8_t)lpMan->m_max_value;
+ m_instructions.add_command(&fv8,sizeof(fv8));
+ }
+
+ if (lpMan->m_size_bytes == 2 ){
+ uint8_t op;
+
+ op = StreamDPVmInstructions::ditINC16;
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_INC ){
+ op = StreamDPVmInstructions::ditINC16 ;
+ }
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC ){
+ op = StreamDPVmInstructions::ditDEC16 ;
+ }
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM ){
+ op = StreamDPVmInstructions::ditRANDOM16 ;
+ }
+
+ StreamDPOpFlowVar16 fv16;
+ fv16.m_op = op;
+ fv16.m_flow_offset = get_var_offset(lpMan->m_var_name);
+ fv16.m_min_val = (uint16_t)lpMan->m_min_value;
+ fv16.m_max_val = (uint16_t)lpMan->m_max_value;
+ m_instructions.add_command(&fv16,sizeof(fv16));
+ }
+
+ if (lpMan->m_size_bytes == 4 ){
+ uint8_t op;
+
+ op = StreamDPVmInstructions::ditINC32;
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_INC ){
+ op = StreamDPVmInstructions::ditINC32 ;
+ }
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC ){
+ op = StreamDPVmInstructions::ditDEC32 ;
+ }
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM ){
+ op = StreamDPVmInstructions::ditRANDOM32 ;
+ }
+
+ StreamDPOpFlowVar32 fv32;
+ fv32.m_op = op;
+ fv32.m_flow_offset = get_var_offset(lpMan->m_var_name);
+ fv32.m_min_val = (uint32_t)lpMan->m_min_value;
+ fv32.m_max_val = (uint32_t)lpMan->m_max_value;
+ m_instructions.add_command(&fv32,sizeof(fv32));
+ }
+
+ if (lpMan->m_size_bytes == 8 ){
+ uint8_t op;
+
+ op = StreamDPVmInstructions::ditINC64;
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_INC ){
+ op = StreamDPVmInstructions::ditINC64 ;
+ }
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC ){
+ op = StreamDPVmInstructions::ditDEC64 ;
+ }
+
+ if ( lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM ){
+ op = StreamDPVmInstructions::ditRANDOM64 ;
+ }
+
+ StreamDPOpFlowVar32 fv64;
+ fv64.m_op = op;
+ fv64.m_flow_offset = get_var_offset(lpMan->m_var_name);
+ fv64.m_min_val = (uint64_t)lpMan->m_min_value;
+ fv64.m_max_val = (uint64_t)lpMan->m_max_value;
+ m_instructions.add_command(&fv64,sizeof(fv64));
+ }
+ }
+
+ if (ins_type == StreamVmInstruction::itPKT_WR) {
+ StreamVmInstructionWriteToPkt *lpPkt =(StreamVmInstructionWriteToPkt *)inst;
+
+ VmFlowVarRec var;
+ if ( var_lookup(lpPkt->m_flow_var_name ,var) == false){
+
+ std::stringstream ss;
+ ss << "instruction id '" << ins_id << "' packet write with no valid flow varible name '" << lpPkt->m_flow_var_name << "'" ;
+ err(ss.str());
+ }
+
+ if (lpPkt->m_pkt_offset + var.m_size_bytes > m_pkt_size ) {
+ std::stringstream ss;
+ 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);
+
+
+ uint8_t op_size=var.m_size_bytes;
+ bool is_big = lpPkt->m_is_big_endian;
+ uint8_t flags = (is_big?StreamDPOpPktWrBase::PKT_WR_IS_BIG:0);
+ uint8_t flow_offset = get_var_offset(lpPkt->m_flow_var_name);
+
+ if (op_size == 1) {
+ StreamDPOpPktWr8 pw8;
+ pw8.m_op = StreamDPVmInstructions::itPKT_WR8;
+ pw8.m_flags =flags;
+ pw8.m_offset =flow_offset;
+ pw8.m_pkt_offset = lpPkt->m_pkt_offset;
+ pw8.m_val_offset = (int8_t)lpPkt->m_add_value;
+ m_instructions.add_command(&pw8,sizeof(pw8));
+ }
+
+ if (op_size == 2) {
+ StreamDPOpPktWr16 pw16;
+ pw16.m_op = StreamDPVmInstructions::itPKT_WR16;
+ pw16.m_flags =flags;
+ pw16.m_offset =flow_offset;
+ pw16.m_pkt_offset = lpPkt->m_pkt_offset;
+ pw16.m_val_offset = (int16_t)lpPkt->m_add_value;
+ m_instructions.add_command(&pw16,sizeof(pw16));
+ }
+
+ if (op_size == 4) {
+ StreamDPOpPktWr32 pw32;
+ pw32.m_op = StreamDPVmInstructions::itPKT_WR32;
+ pw32.m_flags =flags;
+ pw32.m_offset =flow_offset;
+ pw32.m_pkt_offset = lpPkt->m_pkt_offset;
+ pw32.m_val_offset = (int32_t)lpPkt->m_add_value;
+ m_instructions.add_command(&pw32,sizeof(pw32));
+ }
+
+ if (op_size == 8) {
+ StreamDPOpPktWr64 pw64;
+ pw64.m_op = StreamDPVmInstructions::itPKT_WR64;
+ pw64.m_flags =flags;
+ pw64.m_offset =flow_offset;
+ pw64.m_pkt_offset = lpPkt->m_pkt_offset;
+ pw64.m_val_offset = (int64_t)lpPkt->m_add_value;
+ m_instructions.add_command(&pw64,sizeof(pw64));
+ }
+
+ }
+
+
+ if (ins_type == StreamVmInstruction::itFLOW_CLIENT) {
+ StreamVmInstructionFlowClient *lpMan =(StreamVmInstructionFlowClient *)inst;
+
+ if ( lpMan->is_unlimited_flows() ){
+ StreamDPOpClientsUnLimit client_cmd;
+ client_cmd.m_op = StreamDPVmInstructions::itCLIENT_VAR_UNLIMIT;
+
+ client_cmd.m_flow_offset = get_var_offset(lpMan->m_var_name+".ip"); /* start offset */
+ client_cmd.m_flags = 0; /* not used */
+ client_cmd.m_pad = 0;
+ client_cmd.m_min_ip = lpMan->m_client_min;
+ client_cmd.m_max_ip = lpMan->m_client_max;
+ m_instructions.add_command(&client_cmd,sizeof(client_cmd));
+
+ }else{
+ StreamDPOpClientsLimit client_cmd;
+ client_cmd.m_op = StreamDPVmInstructions::itCLIENT_VAR;
+
+ client_cmd.m_flow_offset = get_var_offset(lpMan->m_var_name+".ip"); /* start offset */
+ client_cmd.m_flags = 0; /* not used */
+ client_cmd.m_pad = 0;
+ client_cmd.m_min_port = lpMan->m_port_min;
+ client_cmd.m_max_port = lpMan->m_port_max;
+ client_cmd.m_min_ip = lpMan->m_client_min;
+ client_cmd.m_max_ip = lpMan->m_client_max;
+ client_cmd.m_limit_flows = lpMan->m_limit_num_flows;
+ m_instructions.add_command(&client_cmd,sizeof(client_cmd));
+ }
+ }
+
+ ins_id++;
+ }
+}
+
+
+void StreamVm::build_bss() {
+ alloc_bss();
+ uint8_t * p=(uint8_t *)m_bss;
+
+ for (auto inst : m_inst_list) {
+
+ if ( inst->get_instruction_type() == StreamVmInstruction::itFLOW_MAN ){
+
+ StreamVmInstructionFlowMan * ins_man=(StreamVmInstructionFlowMan *)inst;
+
+ switch (ins_man->m_size_bytes) {
+ case 1:
+ *p=(uint8_t)ins_man->m_init_value;
+ p+=1;
+ break;
+ case 2:
+ *((uint16_t*)p)=(uint16_t)ins_man->m_init_value;
+ p+=2;
+ break;
+ case 4:
+ *((uint32_t*)p)=(uint32_t)ins_man->m_init_value;
+ p+=4;
+ break;
+ case 8:
+ *((uint64_t*)p)=(uint64_t)ins_man->m_init_value;
+ p+=8;
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ if ( inst->get_instruction_type() == StreamVmInstruction::itFLOW_CLIENT ){
+
+ StreamVmInstructionFlowClient * ins_man=(StreamVmInstructionFlowClient *)inst;
+ if (ins_man->m_client_min>0) {
+ *((uint32_t*)p)=(uint32_t)(ins_man->m_client_min-1);
+ }else{
+ *((uint32_t*)p)=(uint32_t)ins_man->m_client_min;
+ }
+ p+=4;
+
+ if (ins_man->is_unlimited_flows() ) {
+ *((uint16_t*)p)=StreamDPOpClientsUnLimit::CLIENT_UNLIMITED_MIN_PORT;
+ }else{
+ *((uint16_t*)p)=(uint16_t)ins_man->m_port_min;
+ }
+ p+=2;
+
+ *((uint32_t*)p)=0;
+ p+=4;
+ }
+
+ }
+}
+
+
+
+void StreamVm::compile() {
+
+ /* build flow var offset table */
+ build_flow_var_table() ;
+
+ /* build init flow var memory */
+ build_bss();
+
+ build_program();
+
+ if ( get_max_packet_update_offset() >svMAX_PACKET_OFFSET_CHANGE ){
+ std::stringstream ss;
+ ss << "maximum offset is" << get_max_packet_update_offset() << " bigger than maximum " <<svMAX_PACKET_OFFSET_CHANGE;
+ err(ss.str());
+ }
}
+
StreamVm::~StreamVm() {
for (auto inst : m_inst_list) {
delete inst;
+ }
+ free_bss();
+}
+
+
+void StreamVm::Dump(FILE *fd){
+ fprintf(fd," instructions \n");
+ uint32_t cnt=0;
+ for (auto inst : m_inst_list) {
+ fprintf(fd," [%04lu] : ",(ulong)cnt);
+ inst->Dump(fd);
+ cnt++;
}
+
+ if ( get_bss_size() ) {
+ fprintf(fd," BSS size %lu\n",(ulong)get_bss_size());
+ utl_DumpBuffer(fd,get_bss_ptr(),get_bss_size(),0);
+ }
+
+ if ( m_instructions.get_program_size() > 0 ){
+ fprintf(fd," RAW instructions \n");
+ m_instructions.Dump(fd);
+ }
+}
+
+
+void StreamDPVmInstructions::clear(){
+ m_inst_list.clear();
+}
+
+
+void StreamDPVmInstructions::add_command(void *buffer,uint16_t size){
+ int i;
+ uint8_t *p= (uint8_t *)buffer;
+ /* push byte by byte */
+ for (i=0; i<size; i++) {
+ m_inst_list.push_back(*p);
+ p++;
+ }
+}
+
+uint8_t * StreamDPVmInstructions::get_program(){
+ return (&m_inst_list[0]);
+}
+
+uint32_t StreamDPVmInstructions::get_program_size(){
+ return (m_inst_list.size());
+}
+
+void StreamDPVmInstructions::Dump(FILE *fd){
+
+ uint8_t * p=get_program();
+
+
+ uint32_t program_size = get_program_size();
+ uint8_t * p_end=p+program_size;
+
+ StreamDPOpFlowVar8 *lpv8;
+ StreamDPOpFlowVar16 *lpv16;
+ StreamDPOpFlowVar32 *lpv32;
+ StreamDPOpFlowVar64 *lpv64;
+ StreamDPOpIpv4Fix *lpIpv4Fix;
+ StreamDPOpPktWr8 *lpw8;
+ StreamDPOpPktWr16 *lpw16;
+ StreamDPOpPktWr32 *lpw32;
+ StreamDPOpPktWr64 *lpw64;
+ StreamDPOpClientsLimit *lp_client;
+ StreamDPOpClientsUnLimit *lp_client_unlimited;
+
+
+ while ( p < p_end) {
+ uint8_t op_code=*p;
+ switch (op_code) {
+
+ case ditINC8 :
+ lpv8 =(StreamDPOpFlowVar8 *)p;
+ lpv8->dump(fd,"INC8");
+ p+=sizeof(StreamDPOpFlowVar8);
+ break;
+ case ditINC16 :
+ lpv16 =(StreamDPOpFlowVar16 *)p;
+ lpv16->dump(fd,"INC16");
+ p+=sizeof(StreamDPOpFlowVar16);
+ break;
+ case ditINC32 :
+ lpv32 =(StreamDPOpFlowVar32 *)p;
+ lpv32->dump(fd,"INC32");
+ p+=sizeof(StreamDPOpFlowVar32);
+ break;
+ case ditINC64 :
+ lpv64 =(StreamDPOpFlowVar64 *)p;
+ lpv64->dump(fd,"INC64");
+ p+=sizeof(StreamDPOpFlowVar64);
+ break;
+
+ case ditDEC8 :
+ lpv8 =(StreamDPOpFlowVar8 *)p;
+ lpv8->dump(fd,"DEC8");
+ p+=sizeof(StreamDPOpFlowVar8);
+ break;
+ case ditDEC16 :
+ lpv16 =(StreamDPOpFlowVar16 *)p;
+ lpv16->dump(fd,"DEC16");
+ p+=sizeof(StreamDPOpFlowVar16);
+ break;
+ case ditDEC32 :
+ lpv32 =(StreamDPOpFlowVar32 *)p;
+ lpv32->dump(fd,"DEC32");
+ p+=sizeof(StreamDPOpFlowVar32);
+ break;
+ case ditDEC64 :
+ lpv64 =(StreamDPOpFlowVar64 *)p;
+ lpv64->dump(fd,"DEC64");
+ p+=sizeof(StreamDPOpFlowVar64);
+ break;
+
+ case ditRANDOM8 :
+ lpv8 =(StreamDPOpFlowVar8 *)p;
+ lpv8->dump(fd,"RAND8");
+ p+=sizeof(StreamDPOpFlowVar8);
+ break;
+ case ditRANDOM16 :
+ lpv16 =(StreamDPOpFlowVar16 *)p;
+ lpv16->dump(fd,"RAND16");
+ p+=sizeof(StreamDPOpFlowVar16);
+ break;
+ case ditRANDOM32 :
+ lpv32 =(StreamDPOpFlowVar32 *)p;
+ lpv32->dump(fd,"RAND32");
+ p+=sizeof(StreamDPOpFlowVar32);
+ break;
+ case ditRANDOM64 :
+ lpv64 =(StreamDPOpFlowVar64 *)p;
+ lpv64->dump(fd,"RAND64");
+ p+=sizeof(StreamDPOpFlowVar64);
+ break;
+
+ case ditFIX_IPV4_CS :
+ lpIpv4Fix =(StreamDPOpIpv4Fix *)p;
+ lpIpv4Fix->dump(fd,"Ipv4Fix");
+ p+=sizeof(StreamDPOpIpv4Fix);
+ break;
+
+ case itPKT_WR8 :
+ lpw8 =(StreamDPOpPktWr8 *)p;
+ lpw8->dump(fd,"Wr8");
+ p+=sizeof(StreamDPOpPktWr8);
+ break;
+
+ case itPKT_WR16 :
+ lpw16 =(StreamDPOpPktWr16 *)p;
+ lpw16->dump(fd,"Wr16");
+ p+=sizeof(StreamDPOpPktWr16);
+ break;
+
+ case itPKT_WR32 :
+ lpw32 =(StreamDPOpPktWr32 *)p;
+ lpw32->dump(fd,"Wr32");
+ p+=sizeof(StreamDPOpPktWr32);
+ break;
+
+ case itPKT_WR64 :
+ lpw64 =(StreamDPOpPktWr64 *)p;
+ lpw64->dump(fd,"Wr64");
+ p+=sizeof(StreamDPOpPktWr64);
+ break;
+
+ case itCLIENT_VAR :
+ lp_client =(StreamDPOpClientsLimit *)p;
+ lp_client->dump(fd,"Client");
+ p+=sizeof(StreamDPOpClientsLimit);
+ break;
+
+ case itCLIENT_VAR_UNLIMIT :
+ lp_client_unlimited =(StreamDPOpClientsUnLimit *)p;
+ lp_client_unlimited->dump(fd,"ClientUnlimted");
+ p+=sizeof(StreamDPOpClientsUnLimit);
+ break;
+
+
+ default:
+ assert(0);
+ }
+ };
+}
+
+
+void StreamDPOpFlowVar8::dump(FILE *fd,std::string opt){
+ fprintf(fd," %10s op:%lu, of:%lu, (%lu- %lu) \n", opt.c_str(),(ulong)m_op,(ulong)m_flow_offset,(ulong)m_min_val,(ulong)m_max_val);
+}
+
+void StreamDPOpFlowVar16::dump(FILE *fd,std::string opt){
+ fprintf(fd," %10s op:%lu, of:%lu, (%lu-%lu) \n", opt.c_str(),(ulong)m_op,(ulong)m_flow_offset,(ulong)m_min_val,(ulong)m_max_val);
+}
+
+void StreamDPOpFlowVar32::dump(FILE *fd,std::string opt){
+ fprintf(fd," %10s op:%lu, of:%lu, (%lu-%lu) \n", opt.c_str(),(ulong)m_op,(ulong)m_flow_offset,(ulong)m_min_val,(ulong)m_max_val);
+}
+
+void StreamDPOpFlowVar64::dump(FILE *fd,std::string opt){
+ fprintf(fd," %10s op:%lu, of:%lu, (%lu-%lu) \n", opt.c_str(),(ulong)m_op,(ulong)m_flow_offset,(ulong)m_min_val,(ulong)m_max_val);
+}
+
+void StreamDPOpPktWr8::dump(FILE *fd,std::string opt){
+ fprintf(fd," %10s op:%lu, flags:%lu, pkt_of:%lu, f_of:%lu \n", opt.c_str(),(ulong)m_op,(ulong)m_flags,(ulong)m_pkt_offset,(ulong)m_offset);
}
+void StreamDPOpPktWr16::dump(FILE *fd,std::string opt){
+ fprintf(fd," %10s op:%lu, flags:%lu, pkt_of:%lu , f_of:%lu \n", opt.c_str(),(ulong)m_op,(ulong)m_flags,(ulong)m_pkt_offset,(ulong)m_offset);
+}
+
+void StreamDPOpPktWr32::dump(FILE *fd,std::string opt){
+ fprintf(fd," %10s op:%lu, flags:%lu, pkt_of:%lu , f_of:%lu \n", opt.c_str(),(ulong)m_op,(ulong)m_flags,(ulong)m_pkt_offset,(ulong)m_offset);
+}
+
+void StreamDPOpPktWr64::dump(FILE *fd,std::string opt){
+ fprintf(fd," %10s op:%lu, flags:%lu, pkt_of:%lu , f_of:%lu \n", opt.c_str(),(ulong)m_op,(ulong)m_flags,(ulong)m_pkt_offset,(ulong)m_offset);
+}
+
+
+void StreamDPOpIpv4Fix::dump(FILE *fd,std::string opt){
+ fprintf(fd," %10s op:%lu, offset: %lu \n", opt.c_str(),(ulong)m_op,(ulong)m_offset);
+}
+
+
+void StreamDPOpClientsLimit::dump(FILE *fd,std::string opt){
+ fprintf(fd," %10s op:%lu, flow_offset: %lu (%x-%x) (%x-%x) flow_limit :%lu flags:%x \n", opt.c_str(),(ulong)m_op,(ulong)m_flow_offset,m_min_ip,m_max_ip,m_min_port,m_max_port,(ulong)m_limit_flows,m_flags);
+}
+
+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);
+}
+
+
diff --git a/src/stateless/cp/trex_stream_vm.h b/src/stateless/cp/trex_stream_vm.h
index 56edbcaf..e65a87e3 100644
--- a/src/stateless/cp/trex_stream_vm.h
+++ b/src/stateless/cp/trex_stream_vm.h
@@ -24,6 +24,526 @@ limitations under the License.
#include <string>
#include <stdint.h>
#include <vector>
+#include <unordered_map>
+#include <assert.h>
+#include <common/Network/Packet/IPHeader.h>
+#include "pal_utl.h"
+#include "mbuf.h"
+
+
+
+
+class StreamVm;
+
+
+/* in memory program */
+
+struct StreamDPOpFlowVar8 {
+ uint8_t m_op;
+ uint8_t m_flow_offset;
+ uint8_t m_min_val;
+ uint8_t m_max_val;
+public:
+ void dump(FILE *fd,std::string opt);
+
+ inline void run_inc(uint8_t * flow_var) {
+ uint8_t * p=(flow_var+m_flow_offset);
+ *p=*p+1;
+ if (*p>m_max_val) {
+ *p=m_min_val;
+ }
+ }
+
+ inline void run_dec(uint8_t * flow_var) {
+ uint8_t * p=(flow_var+m_flow_offset);
+ *p=*p-1;
+ if (*p<m_min_val) {
+ *p=m_max_val;
+ }
+ }
+
+ inline void run_rand(uint8_t * flow_var) {
+ uint8_t * p=(flow_var+m_flow_offset);
+ *p= m_min_val + (rand() % (int)(m_max_val - m_min_val + 1));
+ }
+
+
+} __attribute__((packed)) ;
+
+struct StreamDPOpFlowVar16 {
+ uint8_t m_op;
+ uint8_t m_flow_offset;
+ uint16_t m_min_val;
+ uint16_t m_max_val;
+public:
+ void dump(FILE *fd,std::string opt);
+
+ inline void run_inc(uint8_t * flow_var) {
+ uint16_t * p=(uint16_t *)(flow_var+m_flow_offset);
+ *p=*p+1;
+ if (*p>m_max_val) {
+ *p=m_min_val;
+ }
+ }
+
+ inline void run_dec(uint8_t * flow_var) {
+ uint16_t * p=(uint16_t *)(flow_var+m_flow_offset);
+ *p=*p-1;
+ if (*p<m_min_val) {
+ *p=m_max_val;
+ }
+ }
+
+ inline void run_rand(uint8_t * flow_var) {
+ uint16_t * p=(uint16_t *)(flow_var+m_flow_offset);
+ *p= m_min_val + (rand() % (int)(m_max_val - m_min_val + 1));
+ }
+
+
+
+} __attribute__((packed)) ;
+
+struct StreamDPOpFlowVar32 {
+ uint8_t m_op;
+ uint8_t m_flow_offset;
+ uint32_t m_min_val;
+ uint32_t m_max_val;
+public:
+ void dump(FILE *fd,std::string opt);
+
+ inline void run_inc(uint8_t * flow_var) {
+ uint32_t * p=(uint32_t *)(flow_var+m_flow_offset);
+ *p=*p+1;
+ if (*p>m_max_val) {
+ *p=m_min_val;
+ }
+ }
+
+ inline void run_dec(uint8_t * flow_var) {
+ uint32_t * p=(uint32_t *)(flow_var+m_flow_offset);
+ *p=*p-1;
+ if (*p<m_min_val) {
+ *p=m_max_val;
+ }
+ }
+
+ inline void run_rand(uint8_t * flow_var) {
+ uint32_t * p=(uint32_t *)(flow_var+m_flow_offset);
+ *p= m_min_val + (rand() % (int)(m_max_val - m_min_val + 1));
+ }
+
+} __attribute__((packed)) ;
+
+struct StreamDPOpFlowVar64 {
+ uint8_t m_op;
+ uint8_t m_flow_offset;
+ uint64_t m_min_val;
+ uint64_t m_max_val;
+public:
+ void dump(FILE *fd,std::string opt);
+
+ inline void run_inc(uint8_t * flow_var) {
+ uint64_t * p=(uint64_t *)(flow_var+m_flow_offset);
+ *p=*p+1;
+ if (*p>m_max_val) {
+ *p=m_min_val;
+ }
+ }
+
+ inline void run_dec(uint8_t * flow_var) {
+ uint64_t * p=(uint64_t *)(flow_var+m_flow_offset);
+ *p=*p-1;
+ if (*p<m_min_val) {
+ *p=m_max_val;
+ }
+ }
+
+ inline void run_rand(uint8_t * flow_var) {
+ uint64_t * p=(uint64_t *)(flow_var+m_flow_offset);
+ *p= m_min_val + (rand() % (int)(m_max_val - m_min_val + 1));
+ }
+
+
+} __attribute__((packed)) ;
+
+
+struct StreamDPOpPktWrBase {
+ enum {
+ PKT_WR_IS_BIG = 1
+ }; /* for flags */
+
+ uint8_t m_op;
+ uint8_t m_flags;
+ uint8_t m_offset;
+
+public:
+ bool is_big(){
+ return ( (m_flags &StreamDPOpPktWrBase::PKT_WR_IS_BIG) == StreamDPOpPktWrBase::PKT_WR_IS_BIG ?true:false);
+ }
+
+} __attribute__((packed)) ;
+
+
+struct StreamDPOpPktWr8 : public StreamDPOpPktWrBase {
+ int8_t m_val_offset;
+ uint16_t m_pkt_offset;
+
+public:
+ void dump(FILE *fd,std::string opt);
+
+ inline void wr(uint8_t * flow_var_base,uint8_t * pkt_base) {
+ uint8_t * p_pkt = (pkt_base+m_pkt_offset);
+ uint8_t * p_flow_var = (flow_var_base+m_offset);
+ *p_pkt=(*p_flow_var+m_val_offset);
+
+ }
+
+
+} __attribute__((packed)) ;
+
+
+struct StreamDPOpPktWr16 : public StreamDPOpPktWrBase {
+ uint16_t m_pkt_offset;
+ int16_t m_val_offset;
+public:
+ void dump(FILE *fd,std::string opt);
+
+ inline void wr(uint8_t * flow_var_base,uint8_t * pkt_base) {
+ uint16_t * p_pkt = (uint16_t*)(pkt_base+m_pkt_offset);
+ uint16_t * p_flow_var = (uint16_t*)(flow_var_base+m_offset);
+
+ if ( likely(is_big())){
+ *p_pkt=PKT_HTONS((*p_flow_var+m_val_offset));
+ }else{
+ *p_pkt=(*p_flow_var+m_val_offset);
+ }
+
+ }
+} __attribute__((packed));
+
+struct StreamDPOpPktWr32 : public StreamDPOpPktWrBase {
+ uint16_t m_pkt_offset;
+ int32_t m_val_offset;
+public:
+ void dump(FILE *fd,std::string opt);
+
+ inline void wr(uint8_t * flow_var_base,uint8_t * pkt_base) {
+ uint32_t * p_pkt = (uint32_t*)(pkt_base+m_pkt_offset);
+ uint32_t * p_flow_var = (uint32_t*)(flow_var_base+m_offset);
+ if ( likely(is_big())){
+ *p_pkt=PKT_HTONL((*p_flow_var+m_val_offset));
+ }else{
+ *p_pkt=(*p_flow_var+m_val_offset);
+ }
+ }
+
+} __attribute__((packed));
+
+struct StreamDPOpPktWr64 : public StreamDPOpPktWrBase {
+ uint16_t m_pkt_offset;
+ int64_t m_val_offset;
+
+public:
+ void dump(FILE *fd,std::string opt);
+
+ inline void wr(uint8_t * flow_var_base,uint8_t * pkt_base) {
+ uint64_t * p_pkt = (uint64_t*)(pkt_base+m_pkt_offset);
+ uint64_t * p_flow_var = (uint64_t*)(flow_var_base+m_offset);
+ if ( likely(is_big())){
+ *p_pkt=pal_ntohl64((*p_flow_var+m_val_offset));
+ }else{
+ *p_pkt=(*p_flow_var+m_val_offset);
+ }
+ }
+
+
+} __attribute__((packed));
+
+struct StreamDPOpIpv4Fix {
+ uint8_t m_op;
+ uint16_t m_offset;
+public:
+ void dump(FILE *fd,std::string opt);
+ void run(uint8_t * pkt_base){
+ IPHeader * ipv4= (IPHeader *)(pkt_base+m_offset);
+ ipv4->updateCheckSum();
+ }
+
+} __attribute__((packed));
+
+
+/* flow varible of Client command */
+struct StreamDPFlowClient {
+ uint32_t cur_ip;
+ uint16_t cur_port;
+ uint32_t cur_flow_id;
+} __attribute__((packed));
+
+
+struct StreamDPOpClientsLimit {
+ uint8_t m_op;
+ uint8_t m_flow_offset; /* offset into the flow var bytes */
+ uint8_t m_flags;
+ uint8_t m_pad;
+ uint16_t m_min_port;
+ uint16_t m_max_port;
+
+ uint32_t m_min_ip;
+ uint32_t m_max_ip;
+ uint32_t m_limit_flows; /* limit the number of flows */
+
+public:
+ void dump(FILE *fd,std::string opt);
+ inline void run(uint8_t * flow_var_base) {
+ StreamDPFlowClient * lp= (StreamDPFlowClient *)(flow_var_base+m_flow_offset);
+ lp->cur_ip++;
+ if (lp->cur_ip > m_max_ip ) {
+ lp->cur_ip= m_min_ip;
+ lp->cur_port++;
+ if (lp->cur_port > m_max_port) {
+ lp->cur_port = m_min_port;
+ }
+ }
+
+ if (m_limit_flows) {
+ lp->cur_flow_id++;
+ if ( lp->cur_flow_id > m_limit_flows ){
+ /* reset to the first flow */
+ lp->cur_flow_id = 1;
+ lp->cur_ip = m_min_ip;
+ lp->cur_port = m_min_port;
+ }
+ }
+ }
+
+
+} __attribute__((packed));
+
+struct StreamDPOpClientsUnLimit {
+ enum __MIN_PORT {
+ CLIENT_UNLIMITED_MIN_PORT = 1025
+ };
+
+ uint8_t m_op;
+ uint8_t m_flow_offset; /* offset into the flow var bytes */
+ uint8_t m_flags;
+ uint8_t m_pad;
+ uint32_t m_min_ip;
+ uint32_t m_max_ip;
+
+public:
+ void dump(FILE *fd,std::string opt);
+ inline void run(uint8_t * flow_var_base) {
+ StreamDPFlowClient * lp= (StreamDPFlowClient *)(flow_var_base+m_flow_offset);
+ lp->cur_ip++;
+ if (lp->cur_ip > m_max_ip ) {
+ lp->cur_ip= m_min_ip;
+ lp->cur_port++;
+ if (lp->cur_port == 0) {
+ lp->cur_port = StreamDPOpClientsUnLimit::CLIENT_UNLIMITED_MIN_PORT;
+ }
+ }
+ }
+
+} __attribute__((packed));
+
+
+/* datapath instructions */
+class StreamDPVmInstructions {
+public:
+ enum INS_TYPE {
+ ditINC8 ,
+ ditINC16 ,
+ ditINC32 ,
+ ditINC64 ,
+
+ ditDEC8 ,
+ ditDEC16 ,
+ ditDEC32 ,
+ ditDEC64 ,
+
+ ditRANDOM8 ,
+ ditRANDOM16 ,
+ ditRANDOM32 ,
+ ditRANDOM64 ,
+
+ ditFIX_IPV4_CS ,
+
+ itPKT_WR8 ,
+ itPKT_WR16 ,
+ itPKT_WR32 ,
+ itPKT_WR64 ,
+ itCLIENT_VAR ,
+ itCLIENT_VAR_UNLIMIT
+ };
+
+
+public:
+ void clear();
+ void add_command(void *buffer,uint16_t size);
+ uint8_t * get_program();
+ uint32_t get_program_size();
+
+
+ void Dump(FILE *fd);
+
+
+private:
+ std::vector<uint8_t> m_inst_list;
+};
+
+
+class StreamDPVmInstructionsRunner {
+public:
+ inline void run(uint32_t program_size,
+ uint8_t * program, /* program */
+ uint8_t * flow_var, /* flow var */
+ uint8_t * pkt); /* pkt */
+
+};
+
+
+inline void StreamDPVmInstructionsRunner::run(uint32_t program_size,
+ uint8_t * program, /* program */
+ uint8_t * flow_var, /* flow var */
+ uint8_t * pkt){
+
+
+ uint8_t * p=program;
+ uint8_t * p_end=p+program_size;
+
+
+ union ua_ {
+ StreamDPOpFlowVar8 *lpv8;
+ StreamDPOpFlowVar16 *lpv16;
+ StreamDPOpFlowVar32 *lpv32;
+ StreamDPOpFlowVar64 *lpv64;
+ StreamDPOpIpv4Fix *lpIpv4Fix;
+ StreamDPOpPktWr8 *lpw8;
+ StreamDPOpPktWr16 *lpw16;
+ StreamDPOpPktWr32 *lpw32;
+ StreamDPOpPktWr64 *lpw64;
+ StreamDPOpClientsLimit *lpcl;
+ StreamDPOpClientsUnLimit *lpclu;
+ } ua ;
+
+ while ( p < p_end) {
+ uint8_t op_code=*p;
+ switch (op_code) {
+
+ case StreamDPVmInstructions::itCLIENT_VAR :
+ ua.lpcl =(StreamDPOpClientsLimit *)p;
+ ua.lpcl->run(flow_var);
+ p+=sizeof(StreamDPOpClientsLimit);
+ break;
+
+ case StreamDPVmInstructions::itCLIENT_VAR_UNLIMIT :
+ ua.lpclu =(StreamDPOpClientsUnLimit *)p;
+ ua.lpclu->run(flow_var);
+ p+=sizeof(StreamDPOpClientsUnLimit);
+ break;
+
+ case StreamDPVmInstructions::ditINC8 :
+ ua.lpv8 =(StreamDPOpFlowVar8 *)p;
+ ua.lpv8->run_inc(flow_var);
+ p+=sizeof(StreamDPOpFlowVar8);
+ break;
+
+ case StreamDPVmInstructions::ditINC16 :
+ ua.lpv16 =(StreamDPOpFlowVar16 *)p;
+ ua.lpv16->run_inc(flow_var);
+ p+=sizeof(StreamDPOpFlowVar16);
+ break;
+ case StreamDPVmInstructions::ditINC32 :
+ ua.lpv32 =(StreamDPOpFlowVar32 *)p;
+ ua.lpv32->run_inc(flow_var);
+ p+=sizeof(StreamDPOpFlowVar32);
+ break;
+ case StreamDPVmInstructions::ditINC64 :
+ ua.lpv64 =(StreamDPOpFlowVar64 *)p;
+ ua.lpv64->run_inc(flow_var);
+ p+=sizeof(StreamDPOpFlowVar64);
+ break;
+
+ case StreamDPVmInstructions::ditDEC8 :
+ ua.lpv8 =(StreamDPOpFlowVar8 *)p;
+ ua.lpv8->run_dec(flow_var);
+ p+=sizeof(StreamDPOpFlowVar8);
+ break;
+ case StreamDPVmInstructions::ditDEC16 :
+ ua.lpv16 =(StreamDPOpFlowVar16 *)p;
+ ua.lpv16->run_dec(flow_var);
+ p+=sizeof(StreamDPOpFlowVar16);
+ break;
+ case StreamDPVmInstructions::ditDEC32 :
+ ua.lpv32 =(StreamDPOpFlowVar32 *)p;
+ ua.lpv32->run_dec(flow_var);
+ p+=sizeof(StreamDPOpFlowVar32);
+ break;
+ case StreamDPVmInstructions::ditDEC64 :
+ ua.lpv64 =(StreamDPOpFlowVar64 *)p;
+ ua.lpv64->run_dec(flow_var);
+ p+=sizeof(StreamDPOpFlowVar64);
+ break;
+
+ case StreamDPVmInstructions::ditRANDOM8 :
+ ua.lpv8 =(StreamDPOpFlowVar8 *)p;
+ ua.lpv8->run_rand(flow_var);
+ p+=sizeof(StreamDPOpFlowVar8);
+ break;
+ case StreamDPVmInstructions::ditRANDOM16 :
+ ua.lpv16 =(StreamDPOpFlowVar16 *)p;
+ ua.lpv16->run_rand(flow_var);
+ p+=sizeof(StreamDPOpFlowVar16);
+ break;
+ case StreamDPVmInstructions::ditRANDOM32 :
+ ua.lpv32 =(StreamDPOpFlowVar32 *)p;
+ ua.lpv32->run_rand(flow_var);
+ p+=sizeof(StreamDPOpFlowVar32);
+ break;
+ case StreamDPVmInstructions::ditRANDOM64 :
+ ua.lpv64 =(StreamDPOpFlowVar64 *)p;
+ ua.lpv64->run_rand(flow_var);
+ p+=sizeof(StreamDPOpFlowVar64);
+ break;
+
+ case StreamDPVmInstructions::ditFIX_IPV4_CS :
+ ua.lpIpv4Fix =(StreamDPOpIpv4Fix *)p;
+ ua.lpIpv4Fix->run(pkt);
+ p+=sizeof(StreamDPOpIpv4Fix);
+ break;
+
+ case StreamDPVmInstructions::itPKT_WR8 :
+ ua.lpw8 =(StreamDPOpPktWr8 *)p;
+ ua.lpw8->wr(flow_var,pkt);
+ p+=sizeof(StreamDPOpPktWr8);
+ break;
+
+ case StreamDPVmInstructions::itPKT_WR16 :
+ ua.lpw16 =(StreamDPOpPktWr16 *)p;
+ ua.lpw16->wr(flow_var,pkt);
+ p+=sizeof(StreamDPOpPktWr16);
+ break;
+
+ case StreamDPVmInstructions::itPKT_WR32 :
+ ua.lpw32 =(StreamDPOpPktWr32 *)p;
+ ua.lpw32->wr(flow_var,pkt);
+ p+=sizeof(StreamDPOpPktWr32);
+ break;
+
+ case StreamDPVmInstructions::itPKT_WR64 :
+ ua.lpw64 =(StreamDPOpPktWr64 *)p;
+ ua.lpw64->wr(flow_var,pkt);
+ p+=sizeof(StreamDPOpPktWr64);
+ break;
+ default:
+ assert(0);
+ }
+ };
+};
+
+
+
/**
* interface for stream VM instruction
@@ -32,8 +552,24 @@ limitations under the License.
class StreamVmInstruction {
public:
+ enum INS_TYPE {
+ itNONE = 0,
+ itFIX_IPV4_CS = 4,
+ itFLOW_MAN = 5,
+ itPKT_WR = 6,
+ itFLOW_CLIENT = 7
+
+ };
+
+ typedef uint8_t instruction_type_t ;
+
+ virtual instruction_type_t get_instruction_type()=0;
+
virtual ~StreamVmInstruction();
+ virtual void Dump(FILE *fd)=0;
+
+
private:
static const std::string m_name;
};
@@ -48,8 +584,14 @@ public:
}
-private:
- uint16_t m_pkt_offset;
+ virtual instruction_type_t get_instruction_type(){
+ return ( StreamVmInstruction::itFIX_IPV4_CS);
+ }
+
+ virtual void Dump(FILE *fd);
+
+public:
+ uint16_t m_pkt_offset; /* the offset of IPv4 header from the start of the packet */
};
/**
@@ -61,6 +603,10 @@ class StreamVmInstructionFlowMan : public StreamVmInstruction {
public:
+ virtual instruction_type_t get_instruction_type(){
+ return ( StreamVmInstruction::itFLOW_MAN);
+ }
+
/**
* different types of operations on the object
*/
@@ -85,7 +631,16 @@ public:
}
+ virtual void Dump(FILE *fd);
+
+ void sanity_check(uint32_t ins_id,StreamVm *lp);
+
private:
+ void sanity_check_valid_range(uint32_t ins_id,StreamVm *lp);
+ void sanity_check_valid_size(uint32_t ins_id,StreamVm *lp);
+ void sanity_check_valid_opt(uint32_t ins_id,StreamVm *lp);
+
+public:
/* flow var name */
@@ -105,6 +660,83 @@ private:
};
+
+/**
+ * flow client instruction - save state for client range and port range
+ *
+ * @author hhaim
+ */
+class StreamVmInstructionFlowClient : public StreamVmInstruction {
+
+public:
+ enum client_flags_e {
+ CLIENT_F_UNLIMITED_FLOWS=1, /* unlimited number of flow, don't care about ports */
+ };
+
+
+ virtual instruction_type_t get_instruction_type(){
+ return ( StreamVmInstruction::itFLOW_CLIENT);
+ }
+
+
+ StreamVmInstructionFlowClient(const std::string &var_name,
+ uint32_t client_min_value,
+ uint32_t client_max_value,
+ uint16_t port_min,
+ uint16_t port_max,
+ uint32_t limit_num_flows, /* zero means don't limit */
+ uint16_t flags
+ ) {
+ m_var_name = var_name;
+ m_client_min = client_min_value;
+ m_client_max = client_max_value;
+
+ m_port_min = port_min;
+ m_port_max = port_max;
+
+ m_limit_num_flows = limit_num_flows;
+ m_flags = flags;
+ }
+
+ virtual void Dump(FILE *fd);
+
+ static uint8_t get_flow_var_size(){
+ return (4+2+4);
+ }
+
+ bool is_unlimited_flows(){
+ return ( (m_flags & StreamVmInstructionFlowClient::CLIENT_F_UNLIMITED_FLOWS ) ==
+ StreamVmInstructionFlowClient::CLIENT_F_UNLIMITED_FLOWS );
+ }
+public:
+
+
+ /* flow var name */
+ std::string m_var_name;
+
+ uint32_t m_client_min; // min ip
+ uint32_t m_client_max; // max ip
+ uint16_t m_port_min; // start port
+ uint16_t m_port_max; // start port
+ uint32_t m_limit_num_flows; // number of flows
+ uint16_t m_flags;
+};
+
+
+
+class VmFlowVarRec {
+public:
+ uint32_t m_offset;
+ union {
+ StreamVmInstructionFlowMan * m_ins_flowv;
+ StreamVmInstructionFlowClient * m_ins_flow_client;
+ } m_ins;
+ uint8_t m_size_bytes;
+};
+
+
+
+
/**
* write flow var to packet
*
@@ -121,7 +753,14 @@ public:
m_pkt_offset(pkt_offset),
m_add_value(add_value),
m_is_big_endian(is_big_endian) {}
-private:
+
+ virtual instruction_type_t get_instruction_type(){
+ return ( StreamVmInstruction::itPKT_WR);
+ }
+
+ virtual void Dump(FILE *fd);
+
+public:
/* flow var name to write */
std::string m_flow_var_name;
@@ -136,12 +775,161 @@ private:
bool m_is_big_endian;
};
+
+/**
+ * describes a VM program for DP
+ *
+ */
+
+class StreamVmDp {
+public:
+ StreamVmDp(){
+ m_bss_ptr=NULL;
+ m_program_ptr =NULL ;
+ m_bss_size=0;
+ m_program_size=0;
+ m_max_pkt_offset_change=0;
+ }
+
+ StreamVmDp( uint8_t * bss,
+ uint16_t bss_size,
+ uint8_t * prog,
+ uint16_t prog_size,
+ uint16_t max_pkt_offset
+ ){
+
+ if (bss) {
+ assert(bss_size);
+ m_bss_ptr=(uint8_t*)malloc(bss_size);
+ assert(m_bss_ptr);
+ memcpy(m_bss_ptr,bss,bss_size);
+ m_bss_size=bss_size;
+ }else{
+ m_bss_ptr=NULL;
+ m_bss_size=0;
+ }
+
+ if (prog) {
+ assert(prog_size);
+ m_program_ptr=(uint8_t*)malloc(prog_size);
+ memcpy(m_program_ptr,prog,prog_size);
+ m_program_size = prog_size;
+ }else{
+ m_program_ptr = NULL;
+ m_program_size=0;
+ }
+ m_max_pkt_offset_change =max_pkt_offset;
+ }
+
+ ~StreamVmDp(){
+ if (m_bss_ptr) {
+ free(m_bss_ptr);
+ m_bss_ptr=0;
+ m_bss_size=0;
+ }
+ if (m_program_ptr) {
+ free(m_program_ptr);
+ m_program_size=0;
+ m_program_ptr=0;
+ }
+ }
+
+ StreamVmDp * clone() const {
+ StreamVmDp * lp= new StreamVmDp(m_bss_ptr,
+ m_bss_size,
+ m_program_ptr,
+ m_program_size,
+ m_max_pkt_offset_change
+ );
+ assert(lp);
+ return (lp);
+ }
+
+ uint8_t* clone_bss(){
+ assert(m_bss_size>0);
+ uint8_t *p=(uint8_t *)malloc(m_bss_size);
+ assert(p);
+ memcpy(p,m_bss_ptr,m_bss_size);
+ return (p);
+ }
+
+ uint16_t get_bss_size(){
+ return(m_bss_size);
+ }
+
+ uint8_t* get_bss(){
+ return (m_bss_ptr);
+ }
+
+ uint8_t* get_program(){
+ return (m_program_ptr);
+ }
+
+ uint16_t get_program_size(){
+ return (m_program_size);
+ }
+
+ uint16_t get_max_packet_update_offset(){
+ return (m_max_pkt_offset_change);
+ }
+
+private:
+ uint8_t * m_bss_ptr; /* pointer to the data section */
+ uint8_t * m_program_ptr; /* pointer to the program */
+ uint16_t m_bss_size;
+ uint16_t m_program_size; /* program size*/
+ uint16_t m_max_pkt_offset_change;
+
+};
+
+
/**
* describes a VM program
*
*/
class StreamVm {
+
public:
+ enum STREAM_VM {
+ svMAX_FLOW_VAR = 64, /* maximum flow varible */
+ svMAX_PACKET_OFFSET_CHANGE = 512
+ };
+
+
+
+ StreamVm(){
+ m_bss=0;
+ m_pkt_size=0;
+ m_cur_var_offset=0;
+ }
+
+
+ /* set packet size */
+ void set_packet_size(uint16_t pkt_size){
+ m_pkt_size = pkt_size;
+ }
+
+ uint16_t get_packet_size(){
+ return ( m_pkt_size);
+ }
+
+
+ StreamVmDp * cloneAsVmDp(){
+
+ StreamVmDp * lp= new StreamVmDp(get_bss_ptr(),
+ get_bss_size(),
+ get_dp_instruction_buffer()->get_program(),
+ get_dp_instruction_buffer()->get_program_size(),
+ get_max_packet_update_offset()
+ );
+ assert(lp);
+ return (lp);
+
+ }
+
+ bool is_vm_empty() {
+ return (m_inst_list.size() == 0);
+ }
/**
* add new instruction to the VM
@@ -155,17 +943,75 @@ public:
*/
const std::vector<StreamVmInstruction *> & get_instruction_list();
+ StreamDPVmInstructions * get_dp_instruction_buffer();
+
+ uint16_t get_bss_size(){
+ return (m_cur_var_offset );
+ }
+
+ uint8_t * get_bss_ptr(){
+ return (m_bss );
+ }
+
+
+ uint16_t get_max_packet_update_offset(){
+ return ( m_max_field_update );
+ }
+
+
+
/**
* compile the VM
* return true of success, o.w false
*
*/
- bool compile();
+ void compile();
~StreamVm();
+ void Dump(FILE *fd);
+
+ /* raise exception */
+ void err(const std::string &err);
+
private:
+
+ /* lookup for varible offset, */
+ bool var_lookup(const std::string &var_name,VmFlowVarRec & var);
+
+ void var_clear_table();
+
+ bool var_add(const std::string &var_name,VmFlowVarRec & var);
+
+ uint16_t get_var_offset(const std::string &var_name);
+
+ void build_flow_var_table() ;
+
+ void build_bss();
+
+ void build_program();
+
+ void alloc_bss();
+
+ void free_bss();
+
+private:
+
+ void clean_max_field_cnt();
+
+ void add_field_cnt(uint16_t new_cnt);
+
+private:
+ uint16_t m_pkt_size;
+ uint16_t m_cur_var_offset;
+ uint16_t m_max_field_update; /* the location of the last byte that is going to be changed in the packet */
+
std::vector<StreamVmInstruction *> m_inst_list;
+ std::unordered_map<std::string, VmFlowVarRec> m_flow_var_offset;
+ uint8_t * m_bss;
+
+ StreamDPVmInstructions m_instructions;
+
};
#endif /* __TREX_STREAM_VM_API_H__ */
diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp
index 478e09f8..c4900e66 100644
--- a/src/stateless/cp/trex_streams_compiler.cpp
+++ b/src/stateless/cp/trex_streams_compiler.cpp
@@ -376,6 +376,26 @@ TrexStreamsCompiler::compile(uint8_t port_id,
double factor,
std::string *fail_msg) {
+ try {
+ return compile_internal(port_id,streams,objs,dp_core_count,factor,fail_msg);
+ } catch (const TrexException &ex) {
+ if (fail_msg) {
+ *fail_msg = ex.what();
+ } else {
+ std::cout << ex.what();
+ }
+ return false;
+ }
+
+}
+bool
+TrexStreamsCompiler::compile_internal(uint8_t port_id,
+ const std::vector<TrexStream *> &streams,
+ std::vector<TrexStreamsCompiledObj *> &objs,
+ uint8_t dp_core_count,
+ double factor,
+ std::string *fail_msg) {
+
#if 0
for (auto stream : streams) {
stream->Dump(stdout);
@@ -387,16 +407,7 @@ TrexStreamsCompiler::compile(uint8_t port_id,
/* compile checks */
- try {
- pre_compile_check(streams, nodes);
- } catch (const TrexException &ex) {
- if (fail_msg) {
- *fail_msg = ex.what();
- } else {
- std::cout << ex.what();
- }
- return false;
- }
+ pre_compile_check(streams, nodes);
/* check if all are cont. streams */
bool all_continues = true;
@@ -424,7 +435,6 @@ TrexStreamsCompiler::compile(uint8_t port_id,
/* compile a single stream to all cores */
compile_stream(stream, factor, dp_core_count, objs, nodes);
-
}
return true;
@@ -457,6 +467,10 @@ TrexStreamsCompiler::compile_stream(const TrexStream *stream,
double per_core_rate = (stream->m_pps * (factor / dp_core_count));
int per_core_burst_total_pkts = (stream->m_burst_total_pkts / dp_core_count);
+ /* compile VM */
+ /* fix this const away problem */
+ ((TrexStream *)stream)->compile();
+
std::vector<TrexStream *> per_core_streams(dp_core_count);
/* for each core - creates its own version of the stream */
@@ -486,6 +500,7 @@ TrexStreamsCompiler::compile_stream(const TrexStream *stream,
}
+
/**************************************
* streams graph
*************************************/
diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h
index 7fe2dbf2..d2b0cd1d 100644
--- a/src/stateless/cp/trex_streams_compiler.h
+++ b/src/stateless/cp/trex_streams_compiler.h
@@ -103,6 +103,13 @@ public:
private:
+ bool compile_internal(uint8_t port_id,
+ const std::vector<TrexStream *> &streams,
+ std::vector<TrexStreamsCompiledObj *> &objs,
+ uint8_t dp_core_count,
+ double factor,
+ std::string *fail_msg);
+
void pre_compile_check(const std::vector<TrexStream *> &streams,
GraphNodeMap & nodes);
void allocate_pass(const std::vector<TrexStream *> &streams, GraphNodeMap *nodes);
@@ -118,6 +125,8 @@ private:
std::vector<TrexStreamsCompiledObj *> &objs,
GraphNodeMap &nodes);
+ void compile_stream_vm(TrexStream *stream);
+
std::vector<std::string> m_warnings;
};
diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp
index 22ca922d..585ff2c7 100644
--- a/src/stateless/dp/trex_stateless_dp_core.cpp
+++ b/src/stateless/dp/trex_stateless_dp_core.cpp
@@ -106,12 +106,56 @@ std::string CGenNodeStateless::get_stream_state_str(stream_state_t stream_state)
}
+rte_mbuf_t * CGenNodeStateless::alloc_node_with_vm(){
+
+ rte_mbuf_t * m;
+ /* alloc small packet buffer*/
+ uint16_t prefix_size = prefix_header_size();
+ m = CGlobalInfo::pktmbuf_alloc( get_socket_id(), prefix_size );
+ if (m==0) {
+ return (m);
+ }
+ /* TBD remove this, should handle cases of error */
+ assert(m);
+ char *p=rte_pktmbuf_append(m, prefix_size);
+ memcpy( p ,m_original_packet_data_prefix, prefix_size);
+
+
+ /* run the VM program */
+ StreamDPVmInstructionsRunner runner;
+
+ runner.run( m_vm_program_size,
+ m_vm_program,
+ m_vm_flow_var,
+ (uint8_t*)p);
+
+
+ rte_mbuf_t * m_const = get_const_mbuf();
+ if ( m_const != NULL) {
+ utl_rte_pktmbuf_add_after(m,m_const);
+ }
+ return (m);
+}
+
+
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;
+ }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;
}
}
@@ -423,6 +467,7 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port,
CGenNodeStateless *node = m_core->create_node_sl();
/* add periodic */
+ node->m_cache_mbuf=0;
node->m_type = CGenNode::STATELESS_PKT;
node->m_ref_stream_info = stream->clone_as_dp();
@@ -442,6 +487,10 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port,
pkt_dir_t dir = m_core->m_node_gen.m_v_if->port_id_to_dir(stream->m_port_id);
node->m_flags = 0;
+ node->m_src_port =0;
+ node->m_original_packet_data_prefix = 0;
+
+
/* set socket id */
node->set_socket_id(m_core->m_node_gen.m_socket_id);
@@ -486,23 +535,77 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port,
node->m_port_id = stream->m_port_id;
- /* allocate const mbuf */
- rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), pkt_size);
- assert(m);
-
- char *p = rte_pktmbuf_append(m, pkt_size);
- assert(p);
- /* copy the packet */
- memcpy(p,stream_pkt,pkt_size);
-
/* set dir 0 or 1 client or server */
node->set_mbuf_cache_dir(dir);
- /* TBD repace the mac if req we should add flag */
- m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir, m);
- /* set the packet as a readonly */
- node->set_cache_mbuf(m);
+ if (stream->is_vm() == false ) {
+ /* no VM */
+
+ node->m_vm_flow_var = NULL;
+ node->m_vm_program = NULL;
+ node->m_vm_program_size =0;
+
+ /* allocate const mbuf */
+ rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), pkt_size);
+ assert(m);
+
+ char *p = rte_pktmbuf_append(m, pkt_size);
+ assert(p);
+ /* copy the packet */
+ memcpy(p,stream_pkt,pkt_size);
+
+ /* TBD repace the mac if req we should add flag */
+ m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir,(uint8_t*) p);
+
+ /* set the packet as a readonly */
+ node->set_cache_mbuf(m);
+
+ node->m_original_packet_data_prefix =0;
+ }else{
+
+ /* set the program */
+ TrexStream * local_mem_stream = node->m_ref_stream_info;
+
+ StreamVmDp * lpDpVm = local_mem_stream->getDpVm();
+
+ node->m_vm_flow_var = lpDpVm->clone_bss(); /* clone the flow var */
+ node->m_vm_program = lpDpVm->get_program(); /* same ref to the program */
+ node->m_vm_program_size =lpDpVm->get_program_size();
+
+
+ /* we need to copy the object */
+ if ( pkt_size > stream->m_vm_prefix_size ) {
+ /* we need const packet */
+ uint16_t const_pkt_size = pkt_size - stream->m_vm_prefix_size ;
+ rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), const_pkt_size );
+ assert(m);
+
+ char *p = rte_pktmbuf_append(m, const_pkt_size);
+ assert(p);
+
+ /* copy packet data */
+ memcpy(p,(stream_pkt+ stream->m_vm_prefix_size),const_pkt_size);
+
+ node->set_const_mbuf(m);
+ }
+
+
+ if (stream->m_vm_prefix_size > pkt_size ) {
+ stream->m_vm_prefix_size = pkt_size;
+ }
+ /* copy the headr */
+ uint16_t header_size = stream->m_vm_prefix_size;
+ assert(header_size);
+ node->alloc_prefix_header(header_size);
+ uint8_t *p=node->m_original_packet_data_prefix;
+ assert(p);
+
+ memcpy(p,stream_pkt , header_size);
+ /* TBD repace the mac if req we should add flag */
+ m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir, p);
+ }
+
CDpOneStream one_stream;
diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h
index 111af845..d33785fe 100644
--- a/src/stateless/dp/trex_stream_node.h
+++ b/src/stateless/dp/trex_stream_node.h
@@ -54,6 +54,16 @@ struct CGenNodeStateless : public CGenNodeBase {
friend class TrexStatelessDpCore;
public:
+
+ /* flags MASKS*/
+ enum {
+ SL_NODE_FLAGS_DIR =1, //USED by master
+ SL_NODE_FLAGS_MBUF_CACHE =2, //USED by master
+
+ SL_NODE_CONST_MBUF =4
+
+ };
+
enum {
ss_FREE_RESUSE =1, /* should be free by scheduler */
ss_INACTIVE =2, /* will be active by other stream or stopped */
@@ -83,13 +93,20 @@ private:
uint32_t m_multi_bursts; /* in case of multi_burst how many bursts */
/* cache line 1 */
- TrexStream * m_ref_stream_info; /* the stream info */
+ TrexStream * m_ref_stream_info; /* the stream info */
CGenNodeStateless * m_next_stream;
- /* pad to match the size of CGenNode */
- uint8_t m_pad_end[56];
+ uint8_t * m_original_packet_data_prefix; /* pointer to the original first pointer 64/128/512 */
+
+ /* Fast Field VM section */
+ 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 */
+ /* End Fast Field VM Section */
+ /* pad to match the size of CGenNode */
+ uint8_t m_pad_end[30];
public:
@@ -256,13 +273,51 @@ public:
}
inline rte_mbuf_t * get_cache_mbuf(){
- if ( m_flags &NODE_FLAGS_MBUF_CACHE ) {
+ if ( m_flags & NODE_FLAGS_MBUF_CACHE ) {
+ return ((rte_mbuf_t *)m_cache_mbuf);
+ }else{
+ return ((rte_mbuf_t *)0);
+ }
+ }
+
+ inline void set_const_mbuf(rte_mbuf_t * m){
+ m_cache_mbuf=(void *)m;
+ m_flags |= SL_NODE_CONST_MBUF;
+ }
+
+ inline rte_mbuf_t * get_const_mbuf(){
+ if ( m_flags &SL_NODE_CONST_MBUF ) {
return ((rte_mbuf_t *)m_cache_mbuf);
}else{
return ((rte_mbuf_t *)0);
}
}
+ /* 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);
+ m_original_packet_data_prefix = (uint8_t *)malloc(size);
+ assert(m_original_packet_data_prefix);
+ }
+
+ inline void free_prefix_header(){
+ if (m_original_packet_data_prefix) {
+ free(m_original_packet_data_prefix);
+ }
+ }
+
+ /* prefix headr could be 64/128/512 */
+ inline void set_prefix_header_size(uint16_t size){
+ m_src_port=size;
+ }
+
+ inline uint16_t prefix_header_size(){
+ return (m_src_port);
+ }
+
+
+ rte_mbuf_t * alloc_node_with_vm();
+
void free_stl_node();
public: