add write_mask vm instruction
authorHanoh Haim <[email protected]>
Thu, 18 Feb 2016 13:35:43 +0000 (15:35 +0200)
committerHanoh Haim <[email protected]>
Thu, 18 Feb 2016 13:35:43 +0000 (15:35 +0200)
13 files changed:
.gitignore
scripts/exp/udp_64B_mask1-ex.pcap [new file with mode: 0644]
scripts/exp/udp_64B_vm_mask1-ex.pcap [new file with mode: 0644]
scripts/exp/udp_64B_vm_mask2-ex.pcap [new file with mode: 0644]
scripts/exp/udp_64B_vm_mask3-ex.pcap [new file with mode: 0644]
scripts/exp/udp_64B_vm_mask4-ex.pcap [new file with mode: 0644]
scripts/exp/udp_64B_vm_mask5-ex.pcap [new file with mode: 0644]
scripts/exp/udp_64B_vm_mask6-ex.pcap [new file with mode: 0644]
scripts/stl/udp_1pkt_1mac_step.py [new file with mode: 0644]
scripts/stl/yaml/imix_1pkt_vm_minus.yaml [new file with mode: 0644]
src/gtest/trex_stateless_gtest.cpp
src/stateless/cp/trex_stream_vm.cpp
src/stateless/cp/trex_stream_vm.h

index 856d3da..1faab6b 100644 (file)
@@ -62,6 +62,13 @@ scripts/exp/stl_single_stream_mac0-0.erf
 scripts/exp/stl_single_stream_mac01-0.erf
 scripts/exp/stl_single_stream_mac10-0.erf
 scripts/exp/stl_single_stream_mac11-0.erf
+scripts/exp/udp_64B_vm_mask1.pcap
+scripts/exp/udp_64B_vm_mask2.pcap
+scripts/exp/udp_64B_vm_mask3.pcap
+scripts/exp/udp_64B_vm_mask4.pcap
+scripts/exp/udp_64B_vm_mask5.pcap
+scripts/exp/udp_64B_vm_mask6.pcap
+
 
 
 #files generated by global
diff --git a/scripts/exp/udp_64B_mask1-ex.pcap b/scripts/exp/udp_64B_mask1-ex.pcap
new file mode 100644 (file)
index 0000000..41005ee
Binary files /dev/null and b/scripts/exp/udp_64B_mask1-ex.pcap differ
diff --git a/scripts/exp/udp_64B_vm_mask1-ex.pcap b/scripts/exp/udp_64B_vm_mask1-ex.pcap
new file mode 100644 (file)
index 0000000..80d4e37
Binary files /dev/null and b/scripts/exp/udp_64B_vm_mask1-ex.pcap differ
diff --git a/scripts/exp/udp_64B_vm_mask2-ex.pcap b/scripts/exp/udp_64B_vm_mask2-ex.pcap
new file mode 100644 (file)
index 0000000..89e43eb
Binary files /dev/null and b/scripts/exp/udp_64B_vm_mask2-ex.pcap differ
diff --git a/scripts/exp/udp_64B_vm_mask3-ex.pcap b/scripts/exp/udp_64B_vm_mask3-ex.pcap
new file mode 100644 (file)
index 0000000..e8f7afe
Binary files /dev/null and b/scripts/exp/udp_64B_vm_mask3-ex.pcap differ
diff --git a/scripts/exp/udp_64B_vm_mask4-ex.pcap b/scripts/exp/udp_64B_vm_mask4-ex.pcap
new file mode 100644 (file)
index 0000000..4275b19
Binary files /dev/null and b/scripts/exp/udp_64B_vm_mask4-ex.pcap differ
diff --git a/scripts/exp/udp_64B_vm_mask5-ex.pcap b/scripts/exp/udp_64B_vm_mask5-ex.pcap
new file mode 100644 (file)
index 0000000..a738c78
Binary files /dev/null and b/scripts/exp/udp_64B_vm_mask5-ex.pcap differ
diff --git a/scripts/exp/udp_64B_vm_mask6-ex.pcap b/scripts/exp/udp_64B_vm_mask6-ex.pcap
new file mode 100644 (file)
index 0000000..d791abc
Binary files /dev/null and b/scripts/exp/udp_64B_vm_mask6-ex.pcap differ
diff --git a/scripts/stl/udp_1pkt_1mac_step.py b/scripts/stl/udp_1pkt_1mac_step.py
new file mode 100644 (file)
index 0000000..bab46fb
--- /dev/null
@@ -0,0 +1,35 @@
+from trex_stl_lib.api import *
+
+
+# step is not 1. 
+class STLS1(object):
+
+    def __init__ (self):
+        self.fsize  =64; # the size of the packet 
+
+    def create_stream (self):
+
+        # create a base packet and pad it to size
+        size = self.fsize - 4; # no FCS
+        base_pkt =  Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
+        pad = max(0, size - len(base_pkt)) * 'x'
+
+        vm = CTRexScRaw( [ STLVmFlowVar(name="mac_src", min_value=1, max_value=30, size=1, op="dec",step=7), 
+                           STLVmWrFlowVar(fv_name="mac_src", pkt_offset= 11)                           # write it to LSB of SRC offset it 11
+                          ]
+                       )
+
+        return STLStream(packet = STLPktBuilder(pkt = base_pkt/pad,vm = vm),
+                         mode = STLTXCont( pps=10 ))
+
+    def get_streams (self, direction = 0):
+        # create 1 stream 
+        return [ self.create_stream() ]
+
+
+# dynamic load - used for trex console or simulator
+def register():
+    return STLS1()
+
+
+
diff --git a/scripts/stl/yaml/imix_1pkt_vm_minus.yaml b/scripts/stl/yaml/imix_1pkt_vm_minus.yaml
new file mode 100644 (file)
index 0000000..bf67c83
--- /dev/null
@@ -0,0 +1,33 @@
+### Single stream UDP packet, 64B ###
+#####################################
+- name: udp_64B
+  stream:
+    self_start: True
+    packet:
+      pcap: udp_64B_no_crc.pcap  # pcap should not include CRC
+    mode:
+      type: continuous
+      pps: 100
+    rx_stats: []
+
+    vm:
+      instructions: [
+               {
+                  "init_value" : 500,
+                  "max_value" : 75000,
+                  "min_value" : 1000,
+                  "name" : "l3_src",
+                  "op" : "inc",
+                  "size" : 2,
+                  "type" : "flow_var"
+               },
+               {
+                  "add_value" : 1,
+                  "is_big_endian" : false,
+                  "name" : "l3_src",
+                  "pkt_offset" : 34,
+                  "type" : "write_flow_var"
+               }
+                    ]
+      split_by_var: "l3_src"
+        
index 68f9a4b..3faaede 100644 (file)
@@ -724,6 +724,351 @@ TEST_F(basic_vm, vm7) {
     EXPECT_EQ(1, res1?1:0);
 }
 
+
+////////////////////////////////////////////////////////
+
+TEST_F(basic_vm, vm_mask_err) {
+
+    bool fail=false;
+    /* should fail */
+
+    try {
+        StreamVm vm;
+        vm.add_instruction( new StreamVmInstructionFixChecksumIpv4(14) );
+        vm.compile(128);
+        uint32_t program_size=vm.get_dp_instruction_buffer()->get_program_size();
+        printf(" program_size : %lu \n",(ulong)program_size);
+     } catch (const TrexException &ex) {
+        fail=true;
+    }
+
+     EXPECT_EQ(true, fail);
+}
+
+
+TEST_F(basic_vm, vm_mask1) {
+
+
+
+    StreamVm vm;
+
+    vm.add_instruction( new StreamVmInstructionFlowMan( "var1",4 /* size */,
+                                                        StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,0x10000007,0x10000007,0x100000fe)  );
+
+
+    vm.add_instruction( new StreamVmInstructionWriteMaskToPkt("var1", 36,2,0x00ff,0,1) );
+
+    vm.compile(128);
+
+
+    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_vm_mask1.pcap");
+    assert(lpWriter);
+
+
+    StreamDPVmInstructionsRunner runner;
+
+    uint32_t random_per_thread=0;
+
+    int i;
+    for (i=0; i<20; i++) {
+        runner.run(&random_per_thread,
+                   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_vm_mask1.pcap","exp/udp_64B_vm_mask1-ex.pcap");
+    EXPECT_EQ(1, res1?1:0);
+}
+
+
+TEST_F(basic_vm, vm_mask2) {
+
+
+
+    StreamVm vm;
+
+    vm.add_instruction( new StreamVmInstructionFlowMan( "var1",4 /* size */,
+                                                        StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,0x10000007,0x10000007,0x100000fe)  );
+
+
+    vm.add_instruction( new StreamVmInstructionWriteMaskToPkt("var1", 36,2,0xff00,8,1) );
+
+    vm.compile(128);
+
+
+    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_vm_mask2.pcap");
+    assert(lpWriter);
+
+
+    StreamDPVmInstructionsRunner runner;
+
+    uint32_t random_per_thread=0;
+
+    int i;
+    for (i=0; i<20; i++) {
+        runner.run(&random_per_thread,
+                   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_vm_mask2.pcap","exp/udp_64B_vm_mask2-ex.pcap");
+    EXPECT_EQ(1, res1?1:0);
+}
+
+TEST_F(basic_vm, vm_mask3) {
+
+
+
+    StreamVm vm;
+
+    vm.add_instruction( new StreamVmInstructionFlowMan( "var1",4 /* size */,
+                                                        StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,0x10000007,0x10000007,0x100000fe)  );
+
+
+    vm.add_instruction( new StreamVmInstructionWriteMaskToPkt("var1", 36,1,0x2,1,1) );
+
+    vm.compile(128);
+
+
+    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_vm_mask3.pcap");
+    assert(lpWriter);
+
+
+    StreamDPVmInstructionsRunner runner;
+
+    uint32_t random_per_thread=0;
+
+    int i;
+    for (i=0; i<20; i++) {
+        runner.run(&random_per_thread,
+                   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_vm_mask3.pcap","exp/udp_64B_vm_mask3-ex.pcap");
+    EXPECT_EQ(1, res1?1:0);
+}
+
+TEST_F(basic_vm, vm_mask4) {
+
+
+
+    StreamVm vm;
+
+    vm.add_instruction( new StreamVmInstructionFlowMan( "var1",1 /* size */,
+                                                        StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,1,1,10)  );
+
+
+    vm.add_instruction( new StreamVmInstructionWriteMaskToPkt("var1", 36,2,0xFF00,8,1) );
+
+    vm.compile(128);
+
+
+    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_vm_mask4.pcap");
+    assert(lpWriter);
+
+
+    StreamDPVmInstructionsRunner runner;
+
+    uint32_t random_per_thread=0;
+
+    int i;
+    for (i=0; i<20; i++) {
+        runner.run(&random_per_thread,
+                   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_vm_mask4.pcap","exp/udp_64B_vm_mask4-ex.pcap");
+    EXPECT_EQ(1, res1?1:0);
+}
+
+TEST_F(basic_vm, vm_mask5) {
+
+
+
+    StreamVm vm;
+
+    vm.add_instruction( new StreamVmInstructionFlowMan( "var1",1 /* size */,
+                                                        StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,1,1,10)  );
+
+
+    vm.add_instruction( new StreamVmInstructionWriteMaskToPkt("var1", 36,4,0x00FF0000,16,1) );
+
+    vm.compile(128);
+
+
+    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_vm_mask5.pcap");
+    assert(lpWriter);
+
+
+    StreamDPVmInstructionsRunner runner;
+
+    uint32_t random_per_thread=0;
+
+    int i;
+    for (i=0; i<20; i++) {
+        runner.run(&random_per_thread,
+                   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_vm_mask5.pcap","exp/udp_64B_vm_mask5-ex.pcap");
+    EXPECT_EQ(1, res1?1:0);
+}
+
+
+TEST_F(basic_vm, vm_mask6) {
+
+
+
+    StreamVm vm;
+
+    vm.add_instruction( new StreamVmInstructionFlowMan( "var1",4 /* size */,
+                                                        StreamVmInstructionFlowMan::FLOW_VAR_OP_INC,1,1,20)  );
+
+
+    vm.add_instruction( new StreamVmInstructionWriteMaskToPkt("var1", 36,2,0x00FF,-1,1) );
+
+    vm.compile(128);
+
+
+    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_vm_mask6.pcap");
+    assert(lpWriter);
+
+
+    StreamDPVmInstructionsRunner runner;
+
+    uint32_t random_per_thread=0;
+
+    int i;
+    for (i=0; i<20; i++) {
+        runner.run(&random_per_thread,
+                   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_vm_mask6.pcap","exp/udp_64B_vm_mask6-ex.pcap");
+    EXPECT_EQ(1, res1?1:0);
+}
+
+////////////////////////////////////////////////////////
+
+
 TEST_F(basic_vm, vm8) {
 
 
index f99c3c9..f83025d 100644 (file)
@@ -83,6 +83,11 @@ void StreamVmInstructionFlowMan::sanity_check(uint32_t ins_id,StreamVm *lp){
 }
 
 
+void StreamVmInstructionWriteMaskToPkt::Dump(FILE *fd){
+    fprintf(fd," flow_var:%s, offset:%lu, cast_size:%lu, mask:0x%lx, shift:%ld, is_big:%lu \n",m_flow_var_name.c_str(),(ulong)m_pkt_offset,(ulong)m_pkt_cast_size,(ulong)m_mask,(long)m_shift,(ulong)(m_is_big_endian?1:0));
+}
+
+
 void StreamVmInstructionFlowMan::Dump(FILE *fd){
     fprintf(fd," flow_var  , %s ,%lu,  ",m_var_name.c_str(),(ulong)m_size_bytes);
 
@@ -380,6 +385,7 @@ void StreamVm::build_program(){
 
     /* build the commands into a buffer */
     m_instructions.clear();
+    int var_cnt=0;
     clean_max_field_cnt();
     uint32_t ins_id=0;
 
@@ -410,6 +416,7 @@ void StreamVm::build_program(){
         if (ins_type == StreamVmInstruction::itFLOW_MAN) {
             StreamVmInstructionFlowMan *lpMan =(StreamVmInstructionFlowMan *)inst;
 
+            var_cnt++;
 
             if (lpMan->m_size_bytes == 1 ){
                 if ( (lpMan->m_step == 1) || (lpMan->m_op == StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM ) ){
@@ -663,8 +670,64 @@ void StreamVm::build_program(){
 
         }
 
+        if (ins_type == StreamVmInstruction::itPKT_WR_MASK) {
+            StreamVmInstructionWriteMaskToPkt *lpPkt =(StreamVmInstructionWriteMaskToPkt *)inst;
+
+            VmFlowVarRec var;
+
+            uint8_t cast_size = lpPkt->m_pkt_cast_size;
+            if (!((cast_size==4)||(cast_size==2)||(cast_size==1))){
+                std::stringstream ss;
+                ss << "instruction id '" << ins_id << " cast size should be 1,2,4 it is "<<lpPkt->m_pkt_cast_size;
+                err(ss.str());
+            }
+
+            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 + lpPkt->m_pkt_cast_size > m_pkt_size ) {
+                std::stringstream ss;
+                ss << "instruction id '" << ins_id << "' packet write with packet_offset   " << (lpPkt->m_pkt_offset + lpPkt->m_pkt_cast_size)  << "   bigger than packet size   "<< m_pkt_size;
+                err(ss.str());
+            }
+
+
+            add_field_cnt(lpPkt->m_pkt_offset + lpPkt->m_pkt_cast_size);
+
+
+            uint8_t       op_size = var.m_size_bytes;
+            bool is_big           = lpPkt->m_is_big_endian;
+            uint8_t       flags   = (is_big?StreamDPOpPktWrMask::MASK_PKT_WR_IS_BIG:0);
+            uint8_t       flow_offset = get_var_offset(lpPkt->m_flow_var_name);
+
+            /* read LSB in case of 64bit varible */
+            if (op_size == 8) {
+                op_size = 4;
+                if ( is_big ) {
+                    flow_offset +=4;
+                }
+            }
+
+            StreamDPOpPktWrMask pmask;
+            pmask.m_op = StreamDPVmInstructions::itPKT_WR_MASK;
+            pmask.m_flags      =   flags;
+            pmask.m_var_offset =   flow_offset;
+            pmask.m_shift      =   lpPkt->m_shift;
+            pmask.m_pkt_cast_size =   cast_size;
+            pmask.m_flowv_cast_size = op_size;
+            pmask.m_pkt_offset      = lpPkt->m_pkt_offset;
+            pmask.m_mask            = lpPkt->m_mask;
+
+            m_instructions.add_command(&pmask,sizeof(pmask));
+        }
+
 
         if (ins_type == StreamVmInstruction::itFLOW_CLIENT) {
+            var_cnt++;
             StreamVmInstructionFlowClient *lpMan =(StreamVmInstructionFlowClient *)inst;
 
             if ( lpMan->is_unlimited_flows() ){
@@ -722,6 +785,13 @@ void StreamVm::build_program(){
 
         ins_id++;
     }
+
+
+    if ( var_cnt ==0 ){
+        std::stringstream ss;
+        ss << "It is not valid to have a VM program without a variable  or tuple generator ";
+        err(ss.str());
+    }
 }
 
 
@@ -985,6 +1055,7 @@ void StreamDPVmInstructions::Dump(FILE *fd){
     StreamDPOpPktWr16    *lpw16;
     StreamDPOpPktWr32    *lpw32;
     StreamDPOpPktWr64    *lpw64;
+    StreamDPOpPktWrMask  *lpwrmask;
     StreamDPOpClientsLimit   *lp_client;
     StreamDPOpClientsUnLimit  *lp_client_unlimited;
     StreamDPOpPktSizeChange  *lp_pkt_size_change;
@@ -1148,6 +1219,12 @@ void StreamDPVmInstructions::Dump(FILE *fd){
             p+=sizeof(StreamDPOpFlowVar64Step);
             break;
 
+        case  itPKT_WR_MASK :  
+            lpwrmask =(StreamDPOpPktWrMask *)p;
+            lpwrmask->dump(fd,"WR_MASK");
+            p+=sizeof(StreamDPOpPktWrMask);
+            break;
+
         default:
             assert(0);
         }
@@ -1204,6 +1281,10 @@ 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 StreamDPOpPktWrMask::dump(FILE *fd,std::string opt){
+    fprintf(fd," %10s  op:%lu, flags:%lu, var_of:%lu , (%ld-%lu-%lu-%lu-%lu) \n",  opt.c_str(),(ulong)m_op,(ulong)m_flags,(ulong)m_var_offset,(long)m_shift,(ulong)m_pkt_offset,(ulong)m_mask,(ulong)m_pkt_cast_size,(ulong)m_flowv_cast_size);
+}
+
 
 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);
@@ -1224,6 +1305,86 @@ void StreamDPOpPktSizeChange::dump(FILE *fd,std::string opt){
 
 
 
+
+void StreamDPOpPktWrMask::wr(uint8_t * flow_var_base,
+                             uint8_t * pkt_base) {
+        uint32_t val=0;
+        uint8_t * pv=(flow_var_base+m_var_offset);
+        /* read flow var with the right size */
+        switch (m_flowv_cast_size) {
+        case 1:
+            val= (uint32_t)(*((uint8_t*)pv));
+            break;
+        case 2:
+            val=(uint32_t)(*((uint16_t*)pv));
+            break;
+        case 4:
+            val=(*((uint32_t*)pv));
+            break;
+        default:
+          assert(0);    
+        }
+
+        /* shift the flow var val */
+        if (m_shift>0) {
+            val=val<<m_shift;
+        }else{
+            if (m_shift<0) {
+                val=val>>(-m_shift);
+            }
+        }
+
+        uint8_t * p_pkt = pkt_base+m_pkt_offset;
+        uint32_t pkt_val=0;
+
+        /* RMW */
+        if ( likely( is_big() ) ) {
+
+            switch (m_pkt_cast_size) {
+            case 1:
+                pkt_val= (uint32_t)(*((uint8_t*)p_pkt));
+                pkt_val = ((pkt_val & ~m_mask) | (val & m_mask)) & 0xff;   
+                *p_pkt=pkt_val;
+                break;
+            case 2:
+                pkt_val= (uint32_t)PKT_NTOHS((*((uint16_t*)p_pkt)));
+                pkt_val = ((pkt_val & ~m_mask) | (val & m_mask)) & 0xffff;   
+                *((uint16_t*)p_pkt)=PKT_NTOHS(pkt_val);
+                break;
+            case 4:
+                pkt_val= (uint32_t)PKT_NTOHL((*((uint32_t*)p_pkt)));
+                pkt_val = ((pkt_val & ~m_mask) | (val & m_mask)) ;   
+                *((uint32_t*)p_pkt)=PKT_NTOHL(pkt_val);
+                break;
+            default:
+              assert(0);    
+            }
+        }else{
+            switch (m_flowv_cast_size) {
+            case 1:
+                pkt_val= (uint32_t)(*((uint8_t*)p_pkt));
+                pkt_val = ((pkt_val & ~m_mask) | (val & m_mask)) & 0xff;   
+                *p_pkt=pkt_val;
+                break;
+            case 2:
+                pkt_val= (uint32_t)(*((uint16_t*)p_pkt));
+                pkt_val = ((pkt_val & ~m_mask) | (val & m_mask)) & 0xffff;   
+                *((uint16_t*)p_pkt)=pkt_val;
+                break;
+            case 4:
+                pkt_val= (uint32_t)(*((uint32_t*)p_pkt));
+                pkt_val = ((pkt_val & ~m_mask) | (val & m_mask)) ;   
+                *((uint32_t*)p_pkt)=pkt_val;
+                break;
+            default:
+              assert(0);    
+            }
+        }
+}
+
+
+
+
 void   StreamDPVmInstructionsRunner::slow_commands(uint8_t op_code,
                        uint8_t * flow_var, /* flow var */
                        uint8_t * pkt,
@@ -1274,8 +1435,16 @@ void   StreamDPVmInstructionsRunner::slow_commands(uint8_t op_code,
         ua.lpv64s->run_dec(flow_var);
         p+=sizeof(StreamDPOpFlowVar64Step);
         break;
+    case  StreamDPVmInstructions::itPKT_WR_MASK:
+        ua.lpwr_mask =(StreamDPOpPktWrMask *)p;
+        ua.lpwr_mask->wr(flow_var,pkt);
+        p+=sizeof(StreamDPOpPktWrMask);
+        break;
+
     default:
         assert(0);
     }
 }
 
+
+
index fd685b2..1350470 100644 (file)
@@ -429,6 +429,37 @@ public:
 
 } __attribute__((packed));
 
+
+struct StreamDPOpPktWrMask  {
+
+    enum {
+        MASK_PKT_WR_IS_BIG = 1
+    }; /* for flags */
+
+    uint8_t  m_op;
+    uint8_t  m_flags;
+    uint8_t  m_var_offset; 
+    int8_t   m_shift;    
+    uint8_t  m_pkt_cast_size; 
+    uint8_t  m_flowv_cast_size; /* 1,2,4 */
+    uint16_t m_pkt_offset;
+    uint32_t m_mask;
+    bool is_big(){
+        return ( (m_flags &StreamDPOpPktWrMask::MASK_PKT_WR_IS_BIG) == StreamDPOpPktWrMask::MASK_PKT_WR_IS_BIG ?true:false);
+    }
+
+
+public:
+    void dump(FILE *fd,std::string opt);
+
+    void wr(uint8_t * flow_var_base,
+                   uint8_t * pkt_base) ;
+
+} __attribute__((packed));
+
+
+
+
 struct StreamDPOpIpv4Fix {
     uint8_t m_op;
     uint16_t  m_offset;
@@ -572,6 +603,7 @@ public:
         ditDEC16_STEP        ,
         ditDEC32_STEP        ,
         ditDEC64_STEP        ,
+        itPKT_WR_MASK
 
 
     };
@@ -637,6 +669,8 @@ typedef union  ua_ {
         StreamDPOpFlowVar16Step *lpv16s;
         StreamDPOpFlowVar32Step *lpv32s;
         StreamDPOpFlowVar64Step *lpv64s;
+        StreamDPOpPktWrMask     *lpwr_mask;
+
 } ua_t ;
 
 
@@ -792,7 +826,8 @@ public:
         itFLOW_MAN     = 5,
         itPKT_WR       = 6,
         itFLOW_CLIENT  = 7 ,
-        itPKT_SIZE_CHANGE = 8 
+        itPKT_SIZE_CHANGE = 8,
+        itPKT_WR_MASK     = 9
 
     };
 
@@ -979,6 +1014,69 @@ public:
 };
 
 
+/**
+ * write flow-write-mask  to packet, hhaim
+ * 
+ *  uint32_t var_tmp=(uint32_t )(flow_var_t size )flow_var;
+ *  if (shift){
+ *     var_tmp=var_tmp<<shift
+ *  }else{
+ *      var_tmp=var_tmp>>shift
+ *  }
+ *  
+ *  pkt_data=read_pkt_size()
+ *  pkt_data =  (pkt_data & ~mask) |(var_tmp & mask)   
+ *  write_pkt(pkt_data)
+ * 
+ */
+class StreamVmInstructionWriteMaskToPkt : public StreamVmInstruction {
+public:
+
+    StreamVmInstructionWriteMaskToPkt(const std::string &flow_var_name,
+                                  uint16_t           pkt_offset,
+                                  uint8_t            pkt_cast_size, /* valid 1,2,4 */
+                                  uint32_t           mask,
+                                  int                shift,       /* positive is shift left, negetive shift right */
+                                  bool               is_big_endian = true) :
+                                                        m_flow_var_name(flow_var_name),
+                                                        m_pkt_offset(pkt_offset),
+                                                        m_pkt_cast_size(pkt_cast_size), 
+                                                        m_mask(mask),
+                                                        m_shift(shift),       
+                                                        m_is_big_endian(is_big_endian) {}
+
+    virtual instruction_type_t get_instruction_type() const {
+        return ( StreamVmInstruction::itPKT_WR_MASK);
+    }
+
+    virtual void Dump(FILE *fd);
+
+    virtual StreamVmInstruction * clone() {
+        return new StreamVmInstructionWriteMaskToPkt(m_flow_var_name,
+                                                     m_pkt_offset,
+                                                     m_pkt_cast_size,
+                                                     m_mask,
+                                                     m_shift,
+                                                     m_is_big_endian);
+    }
+
+public:
+
+    /* flow var name to write */
+    std::string   m_flow_var_name;
+
+    /* where to write */
+    uint16_t      m_pkt_offset;
+    uint8_t       m_pkt_cast_size; /* valid 1,2,4 */
+
+    uint32_t      m_mask;
+    int           m_shift;       
+    bool          m_is_big_endian;
+};
+
+
+
+
 /**
  * flow client instruction - save state for client range and port range 
  * 
@@ -1081,10 +1179,10 @@ public:
 class StreamVmInstructionWriteToPkt : public StreamVmInstruction {
 public:
 
-    StreamVmInstructionWriteToPkt(const std::string &flow_var_name,
-                                  uint16_t           pkt_offset,
-                                  int32_t            add_value = 0,
-                                  bool               is_big_endian = true) :
+      StreamVmInstructionWriteToPkt(const std::string &flow_var_name,
+                                    uint16_t           pkt_offset,
+                                    int32_t            add_value = 0,
+                                    bool               is_big_endian = true) :
 
                                                         m_flow_var_name(flow_var_name),
                                                         m_pkt_offset(pkt_offset),