summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gtest/trex_stateless_gtest.cpp32
-rwxr-xr-xsrc/main_dpdk.cpp1
-rw-r--r--src/stateless/cp/trex_stream_vm.cpp309
-rw-r--r--src/stateless/cp/trex_stream_vm.h253
4 files changed, 592 insertions, 3 deletions
diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp
index ce97fbcb..9e15cb46 100644
--- a/src/gtest/trex_stateless_gtest.cpp
+++ b/src/gtest/trex_stateless_gtest.cpp
@@ -31,6 +31,38 @@ limitations under the License.
#include <trex_rpc_server_api.h>
#include <iostream>
+
+class basic_vm : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+ virtual void TearDown() {
+ }
+ public:
+};
+
+
+/* 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);
+
+
+}
+
+
+//////////////////////////////////////////////////////
+
+
#define EXPECT_EQ_UINT32(a,b) EXPECT_EQ((uint32_t)(a),(uint32_t)(b))
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index c17f32f3..f4acb344 100755
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -2299,6 +2299,7 @@ int CCoreEthIF::send_node(CGenNode * node){
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_id=lp_port->m_port->get_port_id();
memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12);
diff --git a/src/stateless/cp/trex_stream_vm.cpp b/src/stateless/cp/trex_stream_vm.cpp
index 2e760ae9..d8d0dd2e 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,98 @@ 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>
+
+
+
+
+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",m_flow_var_name.c_str(),(ulong)m_pkt_offset,(long)m_add_value,(ulong)(m_is_big_endian?1:0));
+}
+
+
+
+
/***************************
* StreamVmInstruction
@@ -41,8 +134,145 @@ StreamVm::get_instruction_list() {
return m_inst_list;
}
+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);
+}
+
+
+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_instruction = ins_man;
+ var_add(ins_man->m_var_name,var);
+ m_cur_var_offset += ins_man->m_size_bytes;
+
+ /* 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::free_bss(){
+ if (m_bss) {
+ free(m_bss);
+ m_bss=0;
+ }
+}
+
+
+void StreamVm::build_program(){
+
+}
+
+
+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);
+ }
+ }
+ }
+}
+
+
+
+void StreamVm::compile_next() {
+
+ /* build flow var offset table */
+ build_flow_var_table() ;
+
+ /* build init flow var memory */
+ build_bss();
+
+ build_program();
+
+
+}
+
+
bool StreamVm::compile() {
- /* implement me */
+
+ //m_flow_var_offset
+
return (false);
}
@@ -52,3 +282,80 @@ StreamVm::~StreamVm() {
}
}
+
+void StreamVm::Dump(FILE *fd){
+ uint32_t cnt=0;
+ for (auto inst : m_inst_list) {
+ fprintf(fd," [%04lu] : ",(ulong)cnt);
+ inst->Dump(fd);
+ cnt++;
+ }
+}
+
+
+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();
+
+
+}
+
+
+void StreamDPOpFlowVar8::dump(FILE *fd){
+ fprintf(fd," %lu, %lu, %lu , %lu \n", (ulong)m_op,(ulong)m_flow_offset,(ulong)m_min_val,(ulong)m_max_val);
+}
+
+void StreamDPOpFlowVar16::dump(FILE *fd){
+ fprintf(fd," %lu, %lu, %lu , %lu \n", (ulong)m_op,(ulong)m_flow_offset,(ulong)m_min_val,(ulong)m_max_val);
+}
+
+void StreamDPOpFlowVar32::dump(FILE *fd){
+ fprintf(fd," %lu, %lu, %lu , %lu \n", (ulong)m_op,(ulong)m_flow_offset,(ulong)m_min_val,(ulong)m_max_val);
+}
+
+void StreamDPOpFlowVar64::dump(FILE *fd){
+ fprintf(fd," %lu, %lu, %lu , %lu \n", (ulong)m_op,(ulong)m_flow_offset,(ulong)m_min_val,(ulong)m_max_val);
+}
+
+void StreamDPOpPktWr8::dump(FILE *fd){
+ fprintf(fd," %lu, %lu, %lu , %lu \n", (ulong)m_op,(ulong)m_flags,(ulong)m_pkt_offset,(ulong)m_offset);
+}
+
+void StreamDPOpPktWr16::dump(FILE *fd){
+ fprintf(fd," %lu, %lu, %lu , %lu \n", (ulong)m_op,(ulong)m_flags,(ulong)m_pkt_offset,(ulong)m_offset);
+}
+
+void StreamDPOpPktWr32::dump(FILE *fd){
+ fprintf(fd," %lu, %lu, %lu , %lu \n", (ulong)m_op,(ulong)m_flags,(ulong)m_pkt_offset,(ulong)m_offset);
+}
+
+void StreamDPOpPktWr64::dump(FILE *fd){
+ fprintf(fd," %lu, %lu, %lu , %lu \n", (ulong)m_op,(ulong)m_flags,(ulong)m_pkt_offset,(ulong)m_offset);
+}
+
+
+void StreamDPOpIpv4Fix::dump(FILE *fd){
+ fprintf(fd," %lu, %lu \n", (ulong)m_op,(ulong)m_offset);
+}
+
+
+
+
diff --git a/src/stateless/cp/trex_stream_vm.h b/src/stateless/cp/trex_stream_vm.h
index 56edbcaf..ed0e2087 100644
--- a/src/stateless/cp/trex_stream_vm.h
+++ b/src/stateless/cp/trex_stream_vm.h
@@ -24,6 +24,148 @@ limitations under the License.
#include <string>
#include <stdint.h>
#include <vector>
+#include <unordered_map>
+
+
+
+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);
+
+} __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);
+
+} __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);
+
+} __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);
+
+} __attribute__((packed)) ;
+
+
+struct StreamDPOpPktWr8 {
+ uint8_t m_op;
+ uint8_t m_flags;
+ uint8_t m_offset;
+ uint16_t m_pkt_offset;
+public:
+ void dump(FILE *fd);
+
+} __attribute__((packed)) ;
+
+
+struct StreamDPOpPktWr16 {
+ uint8_t m_op;
+ uint8_t m_flags;
+ uint16_t m_pkt_offset;
+ uint16_t m_offset;
+public:
+ void dump(FILE *fd);
+
+} __attribute__((packed));
+
+struct StreamDPOpPktWr32 {
+ uint8_t m_op;
+ uint8_t m_flags;
+ uint16_t m_pkt_offset;
+ uint32_t m_offset;
+public:
+ void dump(FILE *fd);
+
+} __attribute__((packed));
+
+struct StreamDPOpPktWr64 {
+ uint8_t m_op;
+ uint8_t m_flags;
+ uint16_t m_pkt_offset;
+ uint32_t m_offset;
+public:
+ void dump(FILE *fd);
+
+} __attribute__((packed));
+
+struct StreamDPOpIpv4Fix {
+ uint8_t m_op;
+ uint32_t m_offset;
+public:
+ void dump(FILE *fd);
+
+} __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
+ };
+
+
+public:
+ 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;
+};
+
+
/**
* interface for stream VM instruction
@@ -32,8 +174,22 @@ limitations under the License.
class StreamVmInstruction {
public:
+ enum INS_TYPE {
+ itNONE = 0,
+ itFIX_IPV4_CS = 4,
+ itFLOW_MAN = 5,
+ itPKT_WR = 6
+ };
+
+ 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,7 +204,13 @@ public:
}
-private:
+ virtual instruction_type_t get_instruction_type(){
+ return ( StreamVmInstruction::itFIX_IPV4_CS);
+ }
+
+ virtual void Dump(FILE *fd);
+
+public:
uint16_t m_pkt_offset;
};
@@ -61,6 +223,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 +251,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 +280,16 @@ private:
};
+
+class VmFlowVarRec {
+public:
+ uint32_t m_offset;
+ StreamVmInstructionFlowMan * m_instruction;
+};
+
+
+
+
/**
* write flow var to packet
*
@@ -121,7 +306,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;
@@ -142,6 +334,29 @@ private:
*/
class StreamVm {
public:
+ enum STREAM_VM {
+ svMAX_FLOW_VAR = 64 /* maximum flow varible */
+ };
+
+
+
+ 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);
+ }
+
+
/**
* add new instruction to the VM
@@ -162,10 +377,44 @@ public:
*/
bool compile();
+
+ void compile_next();
+
+
~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);
+
+ void build_flow_var_table() ;
+
+ void build_bss();
+
+ void build_program();
+
+ void alloc_bss();
+
+ void free_bss();
+
+
private:
+ uint16_t m_pkt_size;
+ uint16_t m_cur_var_offset;
std::vector<StreamVmInstruction *> m_inst_list;
+ std::unordered_map<std::string, VmFlowVarRec> m_flow_var_offset;
+ uint8_t * m_bss;
+
};
#endif /* __TREX_STREAM_VM_API_H__ */