summaryrefslogtreecommitdiffstats
path: root/src/stateless
diff options
context:
space:
mode:
authorHanoh Haim <hhaim@cisco.com>2016-09-29 13:59:46 +0300
committerHanoh Haim <hhaim@cisco.com>2016-09-29 16:50:29 +0300
commit4f91be3fe9e751b8f264efe989f367976f3349ad (patch)
treef295eab6694730061fafd75e101ce4c2a41ae89c /src/stateless
parent2c57dd9251934cc41852152fd5f3e809ec785a28 (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.cpp111
-rw-r--r--src/stateless/cp/trex_stream_vm.h111
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.cpp1
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,