diff options
author | Hanoh Haim <hhaim@cisco.com> | 2016-09-29 13:59:46 +0300 |
---|---|---|
committer | Hanoh Haim <hhaim@cisco.com> | 2016-09-29 16:50:29 +0300 |
commit | 4f91be3fe9e751b8f264efe989f367976f3349ad (patch) | |
tree | f295eab6694730061fafd75e101ce4c2a41ae89c /src/stateless | |
parent | 2c57dd9251934cc41852152fd5f3e809ec785a28 (diff) |
Add FE Instruction to fix TCP/UDP Payload checksum using hardware offload engine
Diffstat (limited to 'src/stateless')
-rw-r--r-- | src/stateless/cp/trex_stream_vm.cpp | 111 | ||||
-rw-r--r-- | src/stateless/cp/trex_stream_vm.h | 111 | ||||
-rw-r--r-- | src/stateless/dp/trex_stateless_dp_core.cpp | 1 |
3 files changed, 220 insertions, 3 deletions
diff --git a/src/stateless/cp/trex_stream_vm.cpp b/src/stateless/cp/trex_stream_vm.cpp index c157ab06..a9935759 100644 --- a/src/stateless/cp/trex_stream_vm.cpp +++ b/src/stateless/cp/trex_stream_vm.cpp @@ -92,6 +92,9 @@ void StreamVmInstructionFixChecksumIpv4::Dump(FILE *fd){ fprintf(fd," fix_check_sum , %lu \n",(ulong)m_pkt_offset); } +void StreamVmInstructionFixHwChecksum::Dump(FILE *fd){ + fprintf(fd," fix_hw_cs %lu:%lu \n",(ulong)m_l2_len,(ulong)m_l3_len); +} void StreamVmInstructionFlowMan::sanity_check_valid_size(uint32_t ins_id,StreamVm *lp){ uint8_t valid[]={1,2,4,8}; @@ -633,6 +636,101 @@ void StreamVm::build_program(){ for (auto inst : m_inst_list) { StreamVmInstruction::instruction_type_t ins_type=inst->get_instruction_type(); + if (ins_type == StreamVmInstruction::itFIX_HW_CS) { + StreamVmInstructionFixHwChecksum *lpFix =(StreamVmInstructionFixHwChecksum *)inst; + if (lpFix->m_l2_len < 14 ) { + std::stringstream ss; + ss << "instruction id '" << ins_id << "' fix hw offset l2 " << lpFix->m_l2_len << " is lower than 14 "; + err(ss.str()); + } + + if (lpFix->m_l3_len < 8 ) { + std::stringstream ss; + ss << "instruction id '" << ins_id << "' fix hw offset l3 " << lpFix->m_l3_len << " is lower than 8 "; + err(ss.str()); + } + + uint16_t total_l4_offset = lpFix->m_l2_len + lpFix->m_l3_len; + uint16_t l4_header_size =0; + + + assert( m_pkt ); + + bool packet_is_ipv4=true; + IPHeader * ipv4= (IPHeader *)(m_pkt+lpFix->m_l2_len); + if (ipv4->getVersion() ==4 ) { + packet_is_ipv4=true; + if (ipv4->getSize() != lpFix->m_l3_len ) { + std::stringstream ss; + ss << "instruction id '" << ins_id << "' fix hw command IPv4 header size is not valid " << ipv4->getSize() ; + err(ss.str()); + } + if ( !((ipv4->getNextProtocol() == IPHeader::Protocol::TCP) || + (ipv4->getNextProtocol() == IPHeader::Protocol::UDP) ) ) { + std::stringstream ss; + ss << "instruction id '" << ins_id << "' fix hw command L4 should be TCP or UDP " << ipv4->getSize() ; + err(ss.str()); + } + }else{ + if (ipv4->getVersion() ==6) { + /* pass */ + }else{ + std::stringstream ss; + ss << "instruction id '" << ins_id << "' fix hw command should work on IPv4 or IPv6 " ; + err(ss.str()); + } + } + + StreamDPOpHwCsFix ipv_fix; + ipv_fix.m_l2_len = lpFix->m_l2_len; + ipv_fix.m_l3_len = lpFix->m_l3_len; + ipv_fix.m_op = StreamDPVmInstructions::ditFIX_HW_CS; + + if (packet_is_ipv4) { + if ( ipv4->getNextProtocol() == IPHeader::Protocol::TCP ){ + /* Ipv4 TCP */ + ipv_fix.m_ol_flags = (PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM); + l4_header_size = TCP_HEADER_LEN; + }else{ + assert( ipv4->getNextProtocol() == IPHeader::Protocol::UDP ); + /* Ipv4 UDP */ + ipv_fix.m_ol_flags = (PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_UDP_CKSUM); + l4_header_size = UDP_HEADER_LEN; + } + }else{ + /* Ipv6*/ + /* in this case we need to scan the Ipv6 headers */ + /* TBD replace with parser of IPv6 function */ + if ( lpFix->m_l4_type==StreamVmInstructionFixHwChecksum::L4_TYPE_TCP ){ + ipv_fix.m_ol_flags = (PKT_TX_IPV6 | PKT_TX_TCP_CKSUM); + l4_header_size = TCP_HEADER_LEN; + }else{ + if ( lpFix->m_l4_type==StreamVmInstructionFixHwChecksum::L4_TYPE_UDP ){ + ipv_fix.m_ol_flags = (PKT_TX_IPV6 | PKT_TX_UDP_CKSUM); + l4_header_size = UDP_HEADER_LEN; + }else{ + std::stringstream ss; + ss << "instruction id '" << ins_id << "' fix hw command offsets should be TCP or UDP "; + err(ss.str()); + } + } + } + + if ( (total_l4_offset + l4_header_size) > m_pkt_size ) { + + std::stringstream ss; + ss << "instruction id '" << ins_id << "' fix hw command offsets " << (total_l4_offset + l4_header_size) << " is too high relative to packet size "<< m_pkt_size; + err(ss.str()); + } + + /* add the instruction*/ + m_instructions.add_command(&ipv_fix,sizeof(ipv_fix)); + + /* mark R/W of the packet */ + add_field_cnt(total_l4_offset + l4_header_size); + + } + /* itFIX_IPV4_CS */ if (ins_type == StreamVmInstruction::itFIX_IPV4_CS) { StreamVmInstructionFixChecksumIpv4 *lpFix =(StreamVmInstructionFixChecksumIpv4 *)inst; @@ -1233,6 +1331,8 @@ void StreamDPVmInstructions::Dump(FILE *fd){ StreamDPOpFlowVar32Step *lpv32s; StreamDPOpFlowVar64Step *lpv64s; + StreamDPOpHwCsFix *lpHwFix; + StreamDPOpIpv4Fix *lpIpv4Fix; StreamDPOpPktWr8 *lpw8; StreamDPOpPktWr16 *lpw16; @@ -1273,6 +1373,12 @@ void StreamDPVmInstructions::Dump(FILE *fd){ p+=sizeof(StreamDPOpFlowVar64Step); break; + case ditFIX_HW_CS : + lpHwFix =(StreamDPOpHwCsFix *)p; + lpHwFix->dump(fd,"HwFixCs"); + p+=sizeof(StreamDPOpHwCsFix); + break; + case ditFIX_IPV4_CS : lpIpv4Fix =(StreamDPOpIpv4Fix *)p; lpIpv4Fix->dump(fd,"Ipv4Fix"); @@ -1438,6 +1544,11 @@ void StreamDPOpPktWrMask::dump(FILE *fd,std::string opt){ } +void StreamDPOpHwCsFix::dump(FILE *fd,std::string opt){ + fprintf(fd," %10s op:%lu, lens: %lu,%lu \n", opt.c_str(),(ulong)m_op,(ulong)m_l2_len,(ulong)m_l3_len); + +} + 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); } diff --git a/src/stateless/cp/trex_stream_vm.h b/src/stateless/cp/trex_stream_vm.h index 4f500a44..c9f459d3 100644 --- a/src/stateless/cp/trex_stream_vm.h +++ b/src/stateless/cp/trex_stream_vm.h @@ -27,9 +27,16 @@ limitations under the License. #include <unordered_map> #include <assert.h> #include <common/Network/Packet/IPHeader.h> +#include <common/Network/Packet/UdpHeader.h> +#include <common/Network/Packet/TcpHeader.h> #include "pal_utl.h" #include "mbuf.h" +#ifdef RTE_DPDK +# include <rte_ip.h> +#endif /* RTE_DPDK */ + + class StreamVmInstructionFlowClient; /** @@ -535,6 +542,46 @@ public: } __attribute__((packed)); +/* fix checksum using hardware */ +struct StreamDPOpHwCsFix { + uint8_t m_op; + uint16_t m_l2_len; + uint16_t m_l3_len; + uint64_t m_ol_flags; + +public: + void dump(FILE *fd,std::string opt); + void run(uint8_t * pkt_base,rte_mbuf_t * m){ + IPHeader * ipv4 = (IPHeader *)(pkt_base+m_l2_len); + union { + TCPHeader * tcp; + UDPHeader * udp; + } u; + + u.tcp = (TCPHeader*)(pkt_base+m_l3_len); + /* set the mbuf info */ + m->l2_len = m_l2_len; + m->l3_len = m_l3_len; + m->ol_flags |= m_ol_flags; + if (m_ol_flags & PKT_TX_IPV4 ){ /* splitting to 4 instructions didn't improve performance .. */ + ipv4->ClearCheckSum(); + if (m_ol_flags & PKT_TX_TCP_CKSUM ){ + u.tcp->setChecksumRaw(rte_ipv4_phdr_cksum((struct ipv4_hdr *)ipv4,m_ol_flags)); + }else{ + u.udp->setChecksumRaw(rte_ipv4_phdr_cksum((struct ipv4_hdr *)ipv4,m_ol_flags)); + } + }else{ + if (m_ol_flags & PKT_TX_TCP_CKSUM ){ + u.tcp->setChecksumRaw(rte_ipv6_phdr_cksum((struct ipv6_hdr *)ipv4,m_ol_flags)); + }else{ + u.udp->setChecksumRaw(rte_ipv6_phdr_cksum((struct ipv6_hdr *)ipv4,m_ol_flags)); + } + } + } +} __attribute__((packed)); + + + /* flow varible of Client command */ struct StreamDPFlowClient { uint32_t cur_ip; @@ -654,6 +701,7 @@ public: ditRANDOM64 , ditFIX_IPV4_CS , + ditFIX_HW_CS , itPKT_WR8 , itPKT_WR16 , @@ -701,8 +749,8 @@ private: class StreamDPVmInstructionsRunner { public: StreamDPVmInstructionsRunner(){ - m_new_pkt_size=0;; - + m_new_pkt_size=0; + m_m=0; } void slow_commands(uint8_t op_code, @@ -719,12 +767,23 @@ public: inline uint16_t get_new_pkt_size(){ return (m_new_pkt_size); } + + inline void set_mbuf(rte_mbuf_t * mbuf){ + m_m=mbuf; + } + inline rte_mbuf_t * get_mbuf(){ + return (m_m); + } + + private: uint16_t m_new_pkt_size; + rte_mbuf_t * m_m; }; typedef union ua_ { + StreamDPOpHwCsFix * lpHwFix; StreamDPOpIpv4Fix *lpIpv4Fix; StreamDPOpPktWr8 *lpw8; StreamDPOpPktWr16 *lpw16; @@ -856,6 +915,12 @@ inline void StreamDPVmInstructionsRunner::run(uint32_t * per_thread_random, p+=sizeof(StreamDPOpIpv4Fix); break; + case StreamDPVmInstructions::ditFIX_HW_CS : + ua.lpHwFix =(StreamDPOpHwCsFix *)p; + ua.lpHwFix->run(pkt,m_m); + p+=sizeof(StreamDPOpHwCsFix); + break; + case StreamDPVmInstructions::itPKT_WR8 : ua.lpw8 =(StreamDPOpPktWr8 *)p; ua.lpw8->wr(flow_var,pkt); @@ -911,7 +976,8 @@ public: itFLOW_CLIENT = 7 , itPKT_SIZE_CHANGE = 8, itPKT_WR_MASK = 9, - itFLOW_RAND_LIMIT = 10 /* random with limit & seed */ + itFLOW_RAND_LIMIT = 10, /* random with limit & seed */ + itFIX_HW_CS =11 }; @@ -1002,6 +1068,44 @@ public: }; /** + * fix Ipv6/Ipv6 TCP/UDP L4 headers using HW ofload to fix only IPv6 header use software it would be faster + * + */ +class StreamVmInstructionFixHwChecksum : public StreamVmInstruction { +public: + + enum { + L4_TYPE_UDP = 11, + L4_TYPE_TCP = 13, + + }; /* for flags */ + + StreamVmInstructionFixHwChecksum(uint16_t l2_len, + uint16_t l3_len, + uint8_t l4_type) { + m_l2_len = l2_len; + m_l3_len = l3_len; + m_l4_type = l4_type; + } + + virtual instruction_type_t get_instruction_type() const { + return ( StreamVmInstruction::itFIX_HW_CS); + } + + virtual void Dump(FILE *fd); + + virtual StreamVmInstruction * clone() { + return new StreamVmInstructionFixHwChecksum(m_l2_len,m_l3_len,m_l4_type); + } + +public: + uint16_t m_l2_len; + uint16_t m_l3_len; + uint8_t m_l4_type; /* should be either TCP or UDP - TBD could be fixed and calculated by a scan function */ +}; + + +/** * flow manipulation instruction * * @author imarom (07-Sep-15) @@ -1214,6 +1318,7 @@ public: }; + /** * write flow-write-mask to packet, hhaim * diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index bea52d42..857ac8f9 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -345,6 +345,7 @@ rte_mbuf_t * CGenNodeStateless::alloc_node_with_vm(){ /* run the VM program */ StreamDPVmInstructionsRunner runner; + runner.set_mbuf(m); runner.run( (uint32_t*)m_vm_flow_var, m_vm_program_size, |