From efb8873783d59ae2e5a870a99f05e40ebf661c16 Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Tue, 27 Sep 2016 14:24:32 +0300 Subject: pre test: Code review fixes --- linux/ws_main.py | 4 +- linux_dpdk/ws_main.py | 4 +- src/bp_gtest.cpp | 2 +- src/bp_sim.cpp | 2 +- src/debug.cpp | 8 +- src/flow_stat_parser.cpp | 2 +- src/latency.cpp | 1086 -------------------------- src/latency.h | 352 --------- src/main_dpdk.cpp | 264 ++++--- src/main_dpdk.h | 30 +- src/pkt_gen.cpp | 284 +++++++ src/pkt_gen.h | 51 ++ src/pre_test.cpp | 80 +- src/pre_test.h | 15 + src/stateful_rx_core.cpp | 1110 +++++++++++++++++++++++++++ src/stateful_rx_core.h | 381 +++++++++ src/stateless/rx/trex_stateless_rx_core.cpp | 2 +- src/stateless/rx/trex_stateless_rx_core.h | 2 +- src/test_pkt_gen.cpp | 284 ------- src/test_pkt_gen.h | 50 -- 20 files changed, 2068 insertions(+), 1945 deletions(-) delete mode 100644 src/latency.cpp delete mode 100644 src/latency.h create mode 100644 src/pkt_gen.cpp create mode 100644 src/pkt_gen.h create mode 100644 src/stateful_rx_core.cpp create mode 100644 src/stateful_rx_core.h delete mode 100644 src/test_pkt_gen.cpp delete mode 100644 src/test_pkt_gen.h diff --git a/linux/ws_main.py b/linux/ws_main.py index f20afcce..2a0d7286 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -112,14 +112,14 @@ main_src = SrcGroup(dir='src', 'rx_check_header.cpp', 'nat_check.cpp', 'nat_check_flow_table.cpp', - 'test_pkt_gen.cpp', + 'pkt_gen.cpp', 'timer_wheel_pq.cpp', 'time_histogram.cpp', 'utl_json.cpp', 'utl_cpuu.cpp', 'msg_manager.cpp', 'publisher/trex_publisher.cpp', - 'latency.cpp', + 'stateful_rx_core.cpp', 'flow_stat.cpp', 'flow_stat_parser.cpp', 'trex_watchdog.cpp', diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py index 47c479c4..0a2c9dfa 100755 --- a/linux_dpdk/ws_main.py +++ b/linux_dpdk/ws_main.py @@ -115,13 +115,13 @@ main_src = SrcGroup(dir='src', 'flow_stat.cpp', 'flow_stat_parser.cpp', 'bp_sim.cpp', - 'latency.cpp', + 'pkt_gen.cpp', 'platform_cfg.cpp', 'pre_test.cpp', 'tuple_gen.cpp', 'rx_check.cpp', 'rx_check_header.cpp', - 'test_pkt_gen.cpp', + 'stateful_rx_core.cpp', 'timer_wheel_pq.cpp', 'time_histogram.cpp', 'os_time.cpp', diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp index a1f80407..ca514c88 100755 --- a/src/bp_gtest.cpp +++ b/src/bp_gtest.cpp @@ -31,7 +31,7 @@ limitations under the License. #include "msg_manager.h" #include #include "platform_cfg.h" -#include "latency.h" +#include "stateful_rx_core.h" #include "nat_check_flow_table.h" int test_policer(){ diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index 773e82fc..b276d4ff 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -20,7 +20,7 @@ limitations under the License. */ #include "bp_sim.h" -#include "latency.h" +#include "stateful_rx_core.h" #include "utl_json.h" #include "utl_yaml.h" #include "msg_manager.h" diff --git a/src/debug.cpp b/src/debug.cpp index 5abdbdc6..542d2fa1 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -27,7 +27,7 @@ #include #include #include -#include "test_pkt_gen.h" +#include "pkt_gen.h" #include "main_dpdk.h" #include "debug.h" @@ -446,7 +446,7 @@ int CTrexDebug::test_send(uint pkt_type) { } else { ip_ver = 4; } - if (pkt_type > 3) { + if (pkt_type > D_PKT_TYPE_ARP) { printf("Packet type not supported\n"); exit(1); } @@ -462,6 +462,10 @@ int CTrexDebug::test_send(uint pkt_type) { case D_PKT_TYPE_TCP: l4_proto = IPPROTO_TCP; break; + case D_PKT_TYPE_ARP: + ip_ver = 1; + l4_proto = IPPROTO_TCP; //just to prevenet compilation warning. Not used in this case. + break; } d = create_test_pkt(ip_ver, l4_proto, 254, FLOW_STAT_PAYLOAD_IP_ID, 0); } diff --git a/src/flow_stat_parser.cpp b/src/flow_stat_parser.cpp index b809b0f9..7335a6a2 100644 --- a/src/flow_stat_parser.cpp +++ b/src/flow_stat_parser.cpp @@ -25,7 +25,7 @@ #include "common/Network/Packet/IPHeader.h" #include "common/Network/Packet/IPv6Header.h" #include "common/Network/Packet/TcpHeader.h" -#include "test_pkt_gen.h" +#include "pkt_gen.h" #include "flow_stat_parser.h" void CFlowStatParser::reset() { diff --git a/src/latency.cpp b/src/latency.cpp deleted file mode 100644 index 76f12b46..00000000 --- a/src/latency.cpp +++ /dev/null @@ -1,1086 +0,0 @@ -/* - Hanoh Haim - Ido Barnea - Cisco Systems, Inc. -*/ - -/* -Copyright (c) 2015-2015 Cisco Systems, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -#include "bp_sim.h" -#include "flow_stat_parser.h" -#include "utl_json.h" -#include "trex_watchdog.h" -#include "test_pkt_gen.h" -#include "common/basic_utils.h" -#include "latency.h" - -const uint8_t sctp_pkt[]={ - - 0x00,0x04,0x96,0x08,0xe0,0x40, - 0x00,0x0e,0x2e,0x24,0x37,0x5f, - 0x08,0x00, - - 0x45,0x02,0x00,0x30, - 0x00,0x00,0x40,0x00, - 0xff,0x84,0xbd,0x04, - 0x9b,0xe6,0x18,0x9b, //sIP - 0xcb,0xff,0xfc,0xc2, //DIP - - 0x80,0x44,//SPORT - 0x00,0x50,//DPORT - - 0x00,0x00,0x00,0x00, //checksum - - 0x11,0x22,0x33,0x44, // magic - 0x00,0x00,0x00,0x00, //64 bit counter - 0x00,0x00,0x00,0x00, - 0x00,0x01,0xa0,0x00, //seq - 0x00,0x00,0x00,0x00, - -}; - -const uint8_t icmp_pkt[]={ - 0x00,0x04,0x96,0x08,0xe0,0x40, - 0x00,0x0e,0x2e,0x24,0x37,0x5f, - 0x08,0x00, - - 0x45,0x02,0x00,0x30, - 0x00,0x00,0x40,0x00, - 0xff,0x01,0xbd,0x04, - 0x9b,0xe6,0x18,0x9b, //SIP - 0xcb,0xff,0xfc,0xc2, //DIP - - 0x08, 0x00, - 0x01, 0x02, //checksum - 0xaa, 0xbb, // id - 0x00, 0x00, // Sequence number - - 0x11,0x22,0x33,0x44, // magic - 0x00,0x00,0x00,0x00, //64 bit counter - 0x00,0x00,0x00,0x00, - 0x00,0x01,0xa0,0x00, //seq - 0x00,0x00,0x00,0x00, - -}; - - -void CLatencyPktInfo::Create(class CLatencyPktMode *m_l_pkt_info){ - uint8_t pkt_size = m_l_pkt_info->getPacketLen(); - - m_packet = new CCapPktRaw( pkt_size); - m_packet->pkt_cnt=0; - m_packet->time_sec=0; - m_packet->time_nsec=0; - memcpy(m_packet->raw, m_l_pkt_info->getPacketData(), pkt_size); - m_packet->pkt_len=pkt_size; - - m_pkt_indication.m_packet =m_packet; - - m_pkt_indication.m_ether = (EthernetHeader *)m_packet->raw; - m_pkt_indication.l3.m_ipv4=(IPHeader *)(m_packet->raw+14); - m_pkt_indication.m_is_ipv6 = false; - m_pkt_indication.l4.m_icmp=(ICMPHeader *)m_packet->raw+14+20; - m_pkt_indication.m_payload=(uint8_t *)m_packet->raw+14+20+16; - m_pkt_indication.m_payload_len=0; - m_pkt_indication.m_packet_padding=4; - - - m_pkt_indication.m_ether_offset =0; - m_pkt_indication.m_ip_offset =14; - m_pkt_indication.m_udp_tcp_offset = 34; - m_pkt_indication.m_payload_offset = 34+8; - - CPacketDescriptor * lpd=&m_pkt_indication.m_desc; - lpd->Clear(); - lpd->SetInitSide(true); - lpd->SetSwapTuple(false); - lpd->SetIsValidPkt(true); - lpd->SetIsIcmp(true); - lpd->SetIsLastPkt(true); - m_pkt_info.Create(&m_pkt_indication); - - memset(&m_dummy_node,0,sizeof(m_dummy_node)); - - m_dummy_node.set_socket_id( CGlobalInfo::m_socket.port_to_socket(0) ); - - m_dummy_node.m_time =0.1; - m_dummy_node.m_pkt_info = &m_pkt_info; - m_dummy_node.m_dest_ip = 0; - m_dummy_node.m_src_ip = 0; - m_dummy_node.m_src_port = 0x11; - m_dummy_node.m_flow_id =0; - m_dummy_node.m_flags =CGenNode::NODE_FLAGS_LATENCY; - -} - -rte_mbuf_t * CLatencyPktInfo::generate_pkt(int port_id,uint32_t extern_ip){ - bool is_client_to_server=(port_id%2==0)?true:false; - - int dual_port_index=(port_id>>1); - uint32_t c=m_client_ip.v4; - uint32_t s=m_server_ip.v4; - if ( extern_ip ){ - c=extern_ip; - } - - if (!is_client_to_server) { - /*swap */ - uint32_t t=c; - c=s; - s=t; - } - uint32_t mask=dual_port_index*m_dual_port_mask; - if ( extern_ip==0 ){ - c+=mask; - } - s+=mask; - m_dummy_node.m_src_ip = c; - m_dummy_node.m_dest_ip = s; - - rte_mbuf_t * m=m_pkt_info.generate_new_mbuf(&m_dummy_node); - return (m); -} - -void CLatencyPktInfo::set_ip(uint32_t src, - uint32_t dst, - uint32_t dual_port_mask){ - m_client_ip.v4=src; - m_server_ip.v4=dst; - m_dual_port_mask=dual_port_mask; -} - -void CLatencyPktInfo::Delete(){ - m_pkt_info.Delete(); - delete m_packet; -} - -void CCPortLatency::reset(){ - m_rx_seq =m_tx_seq; - m_pad = 0; - m_tx_pkt_err=0; - m_tx_pkt_ok =0; - m_tx_grat_arp_ok =0; - m_pkt_ok=0; - m_rx_check=0; - m_no_magic=0; - m_unsup_prot=0; - m_no_id=0; - m_seq_error=0; - m_length_error=0; - m_no_ipv4_option=0; - m_hist.Reset(); -} - -static uint8_t nat_is_port_can_send(uint8_t port_id){ - uint8_t client_index = (port_id %2); - return (client_index ==0 ?1:0); -} - -bool CCPortLatency::Create(CLatencyManager * parent, - uint8_t id, - uint16_t payload_offset, - uint16_t l4_offset, - uint16_t pkt_size, - CCPortLatency * rx_port){ - m_parent = parent; - m_id = id; - m_tx_seq =0x12345678; - m_icmp_tx_seq = 1; - m_icmp_rx_seq = 0; - m_l4_offset = l4_offset; - m_payload_offset = payload_offset; - m_pkt_size = pkt_size; - m_rx_port = rx_port; - m_nat_can_send = nat_is_port_can_send(m_id); - m_nat_learn = m_nat_can_send; - m_nat_external_ip=0; - - m_hist.Create(); - reset(); - return (true); -} - -void CCPortLatency::Delete(){ - m_hist.Delete(); -} - -void CCPortLatency::update_packet(rte_mbuf_t * m, int port_id){ - uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); - bool is_client_to_server=(port_id%2==0)?true:false; - - /* update mac addr dest/src 12 bytes */ - memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(m_id),12); - - latency_header * h=(latency_header *)(p+m_payload_offset); - h->magic = LATENCY_MAGIC | m_id ; - h->time_stamp = os_get_hr_tick_64(); - h->seq = m_tx_seq; - m_tx_seq++; - - CLatencyPktMode *c_l_pkt_mode = m_parent->c_l_pkt_mode; - c_l_pkt_mode->update_pkt(p + m_l4_offset, is_client_to_server, m_pkt_size - m_l4_offset, &m_icmp_tx_seq); -} - - -void CCPortLatency::DumpShortHeader(FILE *fd){ - fprintf(fd," if| tx_ok , rx_ok , rx check ,error, latency (usec) , Jitter max window \n"); - fprintf(fd," | , , , , average , max , (usec) \n"); - fprintf(fd," ---------------------------------------------------------------------------------------------------------------- \n"); -} - - - -std::string CCPortLatency::get_field(std::string name,float f){ - char buff[200]; - sprintf(buff,"\"%s-%d\":%.1f,",name.c_str(),m_id,f); - return (std::string(buff)); -} - - -void CCPortLatency::dump_json_v2(std::string & json ){ - char buff[200]; - sprintf(buff,"\"port-%d\": {",m_id); - json+=std::string(buff); - m_hist.dump_json("hist",json); - dump_counters_json(json); - json+="},"; -} - -void CCPortLatency::dump_json(std::string & json ){ - json += get_field("avg",m_hist.get_average_latency() ); - json += get_field("max",m_hist.get_max_latency() ); - json += get_field("c-max",m_hist.get_max_latency_last_update() ); - json += get_field("error",(float)(m_unsup_prot+m_no_magic+m_no_id+m_seq_error+m_length_error) ); - json += get_field("jitter",(float)get_jitter_usec() ); -} - - -void CCPortLatency::DumpShort(FILE *fd){ - -// m_hist.update(); <- moved to CLatencyManager::update() - fprintf(fd,"%8lu,%8lu,%10lu,%5lu,", - m_tx_pkt_ok, - m_pkt_ok, - m_rx_check, - m_unsup_prot+m_no_magic+m_no_id+m_seq_error+m_length_error+m_no_ipv4_option+m_tx_pkt_err - ); - - fprintf(fd," %8.0f ,%8.0f,%8d ", - m_hist.get_average_latency(), - m_hist.get_max_latency(), - get_jitter_usec() - ); - fprintf(fd," | "); - m_hist.DumpWinMax(fd); - -} - -#define DPL_J(f) json+=add_json(#f,f); -#define DPL_J_LAST(f) json+=add_json(#f,f,true); - -void CCPortLatency::dump_counters_json(std::string & json ){ - - json+="\"stats\" : {"; - DPL_J(m_tx_pkt_ok); - DPL_J(m_tx_grat_arp_ok); - DPL_J(m_tx_pkt_err); - DPL_J(m_pkt_ok); - DPL_J(m_unsup_prot); - DPL_J(m_no_magic); - DPL_J(m_no_id); - DPL_J(m_seq_error); - DPL_J(m_length_error); - DPL_J(m_no_ipv4_option); - json+=add_json("m_jitter",get_jitter_usec()); - /* must be last */ - DPL_J_LAST(m_rx_check); - json+="}"; - - -} - -void CCPortLatency::DumpCounters(FILE *fd){ - #define DP_A1(f) if (f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)f) - - fprintf(fd," counter \n"); - fprintf(fd," -----------\n"); - - DP_A1(m_tx_pkt_err); - DP_A1(m_tx_pkt_ok); - DP_A1(m_tx_grat_arp_ok); - DP_A1(m_pkt_ok); - DP_A1(m_unsup_prot); - DP_A1(m_no_magic); - DP_A1(m_no_id); - DP_A1(m_seq_error); - DP_A1(m_length_error); - DP_A1(m_rx_check); - DP_A1(m_no_ipv4_option); - - - fprintf(fd," -----------\n"); - m_hist.Dump(fd); - fprintf(fd," %-40s : %lu \n","jitter", (ulong)get_jitter_usec()); -} - -bool CCPortLatency::dump_packet(rte_mbuf_t * m){ - fprintf(stdout," %f.03 dump packet ..\n",now_sec()); - uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); - uint16_t pkt_size=rte_pktmbuf_pkt_len(m); - utl_DumpBuffer(stdout,p,pkt_size,0); - return (0); -#if 0 - if (pkt_size < ( sizeof(CRx_check_header)+14+20) ) { - assert(0); - } - CRx_check_header * lp=(CRx_check_header *)(p+pkt_size-sizeof(CRx_check_header)); - - lp->dump(stdout); - - return (0); -#endif - -} - -bool CCPortLatency::check_rx_check(rte_mbuf_t * m) { - m_rx_check++; - return (true); -} - -bool CCPortLatency::do_learn(uint32_t external_ip) { - m_nat_learn=true; - m_nat_can_send=true; - m_nat_external_ip=external_ip; - return (true); -} - -bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) { - CSimplePacketParser parser(m); - if ( !parser.Parse() ) { - m_unsup_prot++; // Unsupported protocol - return (false); - } - CLatencyPktMode *c_l_pkt_mode = m_parent->c_l_pkt_mode; - uint16_t pkt_size=rte_pktmbuf_pkt_len(m); - uint16_t vlan_offset=parser.m_vlan_offset; - uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); - - rx_p = (CRx_check_header *)0; - - bool is_lateancy_pkt = c_l_pkt_mode->IsLatencyPkt(parser.m_ipv4) & IsLatencyPkt(parser.m_l4 + c_l_pkt_mode->l4_header_len()); - - if ( ! is_lateancy_pkt) { - -#ifdef NAT_TRACE_ - printf(" %.3f RX : got packet !!! \n",now_sec() ); -#endif - - /* ipv6+rx-check */ - if ( parser.m_ipv6 ) { - /* if we have ipv6 packet */ - if (parser.m_protocol == RX_CHECK_V6_OPT_TYPE) { - if ( get_is_rx_check_mode() ){ - m_rx_check++; - rx_p=(CRx_check_header *)((uint8_t*)parser.m_ipv6 +IPv6Header::DefaultSize); - return (true); - } - - } - m_seq_error++; - return (false); - } - - uint8_t opt_len = parser.m_ipv4->getOptionLen(); - uint8_t *opt_ptr = parser.m_ipv4->getOption(); - /* Process IP option header(s) */ - while ( opt_len != 0 ) { - switch (*opt_ptr) { - case RX_CHECK_V4_OPT_TYPE: - /* rx-check option header */ - if ( ( !get_is_rx_check_mode() ) || - (opt_len < RX_CHECK_LEN) ) { - m_seq_error++; - return (false); - } - m_rx_check++; - rx_p=(CRx_check_header *)opt_ptr; - opt_len -= RX_CHECK_LEN; - opt_ptr += RX_CHECK_LEN; - break; - case CNatOption::noIPV4_OPTION: - /* NAT learn option header */ - CNatOption *lp; - if ( ( !CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION) ) || - (opt_len < CNatOption::noOPTION_LEN) ) { - m_seq_error++; - return (false); - } - lp = (CNatOption *)opt_ptr; - if ( !lp->is_valid_ipv4_magic() ) { - m_no_ipv4_option++; - return (false); - } - m_parent->get_nat_manager()->handle_packet_ipv4(lp, parser.m_ipv4, true); - opt_len -= CNatOption::noOPTION_LEN; - opt_ptr += CNatOption::noOPTION_LEN; - break; - default: - m_seq_error++; - return (false); - } // End of switch - } // End of while - - bool first; - if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP) && parser.IsNatInfoPkt(first)) { - m_parent->get_nat_manager()->handle_packet_ipv4(NULL, parser.m_ipv4, first); - } - - return (true); - } // End of check for non-latency packet - // learn for latency packets. We only have one flow for latency, so translation is for it. - if ( CGlobalInfo::is_learn_mode() && (m_nat_learn ==false) ) { - do_learn(parser.m_ipv4->getSourceIp()); - } - - if ( (pkt_size-vlan_offset) != m_pkt_size ) { - m_length_error++; - return (false); - } - c_l_pkt_mode->update_recv(p + m_l4_offset + vlan_offset, &m_icmp_rx_seq, &m_icmp_tx_seq); -#ifdef LATENCY_DEBUG - c_l_pkt_mode->rcv_debug_print(p + m_l4_offset + vlan_offset); -#endif - latency_header * h=(latency_header *)(p+m_payload_offset + vlan_offset); - if ( h->seq != m_rx_seq ){ - m_seq_error++; - m_rx_seq =h->seq +1; - return (false); - }else{ - m_rx_seq++; - } - m_pkt_ok++; - uint64_t d = (os_get_hr_tick_64() - h->time_stamp ); - dsec_t ctime=ptime_convert_hr_dsec(d); - m_hist.Add(ctime); - m_jitter.calc(ctime); - return (true); -} - -void CLatencyManager::Delete(){ - m_pkt_gen.Delete(); - - if ( get_is_rx_check_mode() ) { - m_rx_check_manager.Delete(); - } - if ( CGlobalInfo::is_learn_mode() ){ - m_nat_check_manager.Delete(); - } - m_cpu_cp_u.Delete(); -} - -/* 0->1 - 1->0 - 2->3 - 3->2 -*/ -static uint8_t swap_port(uint8_t port_id){ - uint8_t offset= ((port_id>>1)<<1); - uint8_t client_index = (port_id %2); - return (offset + (client_index ^ 1)); -} - - - -bool CLatencyManager::Create(CLatencyManagerCfg * cfg){ - switch (CGlobalInfo::m_options.get_l_pkt_mode()) { - default: - case 0: - c_l_pkt_mode = (CLatencyPktModeSCTP *) new CLatencyPktModeSCTP(CGlobalInfo::m_options.get_l_pkt_mode()); - break; - case 1: - case 2: - case 3: - c_l_pkt_mode = (CLatencyPktModeICMP *) new CLatencyPktModeICMP(CGlobalInfo::m_options.get_l_pkt_mode()); - break; - } - - m_max_ports=cfg->m_max_ports; - assert (m_max_ports <= TREX_MAX_PORTS); - assert ((m_max_ports%2)==0); - m_port_mask =0xffffffff; - m_do_stop =false; - m_is_active =false; - m_pkt_gen.Create(c_l_pkt_mode); - int i; - for (i=0; im_io=cfg->m_ports[i]; - lp->m_port.Create(this, - i, - m_pkt_gen.get_payload_offset(), - m_pkt_gen.get_l4_offset(), - m_pkt_gen.get_pkt_size(),lpo ); - } - m_cps= cfg->m_cps; - m_d_time =ptime_convert_dsec_hr((1.0/m_cps)); - m_delta_sec =(1.0/m_cps); - - - if ( get_is_rx_check_mode() ) { - assert(m_rx_check_manager.Create()); - m_rx_check_manager.m_cur_time= now_sec(); - } - - - m_pkt_gen.set_ip(cfg->m_client_ip.v4,cfg->m_server_ip.v4,cfg->m_dual_port_mask); - m_cpu_cp_u.Create(&m_cpu_dp_u); - if ( CGlobalInfo::is_learn_mode() ){ - m_nat_check_manager.Create(); - } - - return (true); -} - -void CLatencyManager::send_pkt_all_ports(){ - m_start_time = os_get_hr_tick_64(); - int i; - for (i=0; im_port.can_send_packet(i%2) ){ - rte_mbuf_t * m=m_pkt_gen.generate_pkt(i,lp->m_port.external_nat_ip()); - lp->m_port.update_packet(m, i); - -#ifdef LATENCY_DEBUG - uint8_t *p = rte_pktmbuf_mtod(m, uint8_t*); - c_l_pkt_mode->send_debug_print(p + 34); -#endif - if ( lp->m_io->tx(m) == 0 ){ - lp->m_port.m_tx_pkt_ok++; - }else{ - lp->m_port.m_tx_pkt_err++; - } - - } - } - } -} - -void CLatencyManager::send_grat_arp_all_ports() { - for (int port_id = 0; port_id < m_max_ports; port_id++) { - if (! CGlobalInfo::m_options.m_ip_cfg[port_id].grat_arp_needed()) - continue; - - CLatencyManagerPerPort * lp = &m_ports[port_id]; - rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(port_id)); - assert(m); - uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, 60); // ARP packet is shorter than 60 - uint32_t sip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip(); - uint8_t *src_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src; - uint16_t vlan = CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan(); - // gratuitous ARP. Requested IP is our source. - CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, port_id); - - if (CGlobalInfo::m_options.preview.getVMode() >= 3) { - printf("Sending gratuitous ARP on port %d vlan:%d, sip:0x%08x\n", port_id, vlan, sip); - utl_DumpBuffer(stdout, p, 60, 0); - } - - if ( lp->m_io->tx(m) == 0 ) { - lp->m_port.m_tx_grat_arp_ok++; - } else { - lp->m_port.m_tx_pkt_err++; - } - } -} - -void CLatencyManager::wait_for_rx_dump(){ - rte_mbuf_t * rx_pkts[64]; - int i; - while ( true ) { - rte_pause(); - rte_pause(); - rte_pause(); - for (i=0; im_io->rx_burst(rx_pkts, 64); - if (cnt_p) { - int j; - for (j=0; jm_port.dump_packet( m); - rte_pktmbuf_free(m); - } - } /*cnt_p*/ - }/* for*/ - } -} - - -void CLatencyManager::handle_rx_pkt(CLatencyManagerPerPort * lp, - rte_mbuf_t * m){ - CRx_check_header *rxc = NULL; - - lp->m_port.check_packet(m,rxc); - if ( unlikely(rxc!=NULL) ){ - m_rx_check_manager.handle_packet(rxc); - } - - rte_pktmbuf_free(m); -} - -// In VM, we receive the RX packets in DP core, and send message to RX core with the packet -void CLatencyManager::handle_latency_pkt_msg(uint8_t thread_id, CGenNodeLatencyPktInfo * msg) { - - assert(msg->m_latency_offset==0xdead); - - uint8_t rx_port_index=(thread_id<<1)+(msg->m_dir&1); - assert( rx_port_index m_pkt); -} - - -void CLatencyManager::run_rx_queue_msgs(uint8_t thread_id, - CNodeRing * r){ - - while ( true ) { - CGenNode * node; - if ( r->Dequeue(node)!=0 ){ - break; - } - assert(node); - - CGenNodeMsgBase * msg=(CGenNodeMsgBase *)node; - - uint8_t msg_type = msg->m_msg_type; - switch (msg_type ) { - case CGenNodeMsgBase::LATENCY_PKT: - handle_latency_pkt_msg(thread_id,(CGenNodeLatencyPktInfo *) msg); - break; - default: - printf("ERROR latency-thread message type is not valid %d \n",msg_type); - assert(0); - } - - CGlobalInfo::free_node(node); - } -} - -// VM mode function. Handle messages from DP -void CLatencyManager::try_rx_queues(){ - - CMessagingManager * rx_dp = CMsgIns::Ins()->getRxDp(); - uint8_t threads=CMsgIns::Ins()->get_num_threads(); - int ti; - for (ti=0; ti<(int)threads; ti++) { - CNodeRing * r = rx_dp->getRingDpToCp(ti); - if ( !r->isEmpty() ){ - run_rx_queue_msgs((uint8_t)ti,r); - } - } -} - -void CLatencyManager::try_rx(){ - rte_mbuf_t * rx_pkts[64]; - int i; - for (i=0; im_io->rx_burst(rx_pkts, 64); - if (cnt_p) { - m_cpu_dp_u.start_work1(); - int j; - for (j=0; jm_port.reset(); - } - -} - -void CLatencyManager::tickle() { - m_monitor.tickle(); -} - -void CLatencyManager::start(int iter, bool activate_watchdog) { - m_do_stop =false; - m_is_active =false; - int cnt=0; - - double n_time; - CGenNode * node = new CGenNode(); - node->m_type = CGenNode::FLOW_SYNC; /* general stuff */ - node->m_time = now_sec()+0.007; - m_p_queue.push(node); - - node = new CGenNode(); - node->m_type = CGenNode::FLOW_PKT; /* latency */ - node->m_time = now_sec(); /* 1/cps rate */ - m_p_queue.push(node); - - if (CGlobalInfo::m_options.m_arp_ref_per > 0) { - node = new CGenNode(); - node->m_type = CGenNode::GRAT_ARP; /* gratuitous ARP */ - node->m_time = now_sec() + CGlobalInfo::m_options.m_arp_ref_per; - m_p_queue.push(node); - } - - bool do_try_rx_queue = CGlobalInfo::m_options.preview.get_vm_one_queue_enable() ? true : false; - - if (activate_watchdog) { - m_monitor.create("STF RX CORE", 1); - TrexWatchDog::getInstance().register_monitor(&m_monitor); - } - - while ( !m_p_queue.empty() ) { - node = m_p_queue.top(); - n_time = node->m_time; - - /* wait for event */ - while ( true ) { - double dt = now_sec() - n_time ; - if (dt> (0.0)) { - break; - } - if (do_try_rx_queue){ - try_rx_queues(); - } - try_rx(); - rte_pause(); - } - - switch (node->m_type) { - case CGenNode::FLOW_SYNC: - - tickle(); - - if ( CGlobalInfo::is_learn_mode() ) { - m_nat_check_manager.handle_aging(); - } - - m_p_queue.pop(); - node->m_time += SYNC_TIME_OUT; - m_p_queue.push(node); - - break; - case CGenNode::FLOW_PKT: - m_cpu_dp_u.start_work1(); - send_pkt_all_ports(); - m_p_queue.pop(); - node->m_time += m_delta_sec; - m_p_queue.push(node); - m_cpu_dp_u.commit1(); - break; - - case CGenNode::GRAT_ARP: - m_cpu_dp_u.start_work1(); - send_grat_arp_all_ports(); - m_p_queue.pop(); - node->m_time += CGlobalInfo::m_options.m_arp_ref_per; - m_p_queue.push(node); - m_cpu_dp_u.commit1(); - break; - } - - /* this will be called every sync which is 1msec */ - if ( m_do_stop ) { - break; - } - if ( iter>0 ){ - if ( ( cnt>iter) ){ - printf("stop due iter %d\n",iter); - break; - } - } - cnt++; - } - - /* free all nodes in the queue */ - while (!m_p_queue.empty()) { - node = m_p_queue.top(); - m_p_queue.pop(); - delete node; - } - - printf(" latency daemon has stopped\n"); - if ( get_is_rx_check_mode() ) { - m_rx_check_manager.tw_drain(); - } - - /* disable the monitor */ - if (activate_watchdog) { - m_monitor.disable(); - } - -} - -void CLatencyManager::stop(){ - m_do_stop =true; -} - -bool CLatencyManager::is_active(){ - return (m_is_active); -} - - -double CLatencyManager::get_max_latency(){ - double l=0.0; - int i; - for (i=0; im_port.m_hist.get_max_latency() ){ - l=lp->m_port.m_hist.get_max_latency(); - } - } - return (l); -} - -double CLatencyManager::get_avr_latency(){ - double l=0.0; - int i; - for (i=0; im_port.m_hist.get_average_latency() ){ - l=lp->m_port.m_hist.get_average_latency(); - } - } - return (l); -} - -uint64_t CLatencyManager::get_total_pkt(){ - int i; - uint64_t t=0; - for (i=0; im_port.m_tx_pkt_ok ; - } - return t; -} - -uint64_t CLatencyManager::get_total_bytes(){ - int i; - uint64_t t=0; - for (i=0; im_port.m_tx_pkt_ok* (m_pkt_gen.get_pkt_size()+4); - } - return t; - -} - - -bool CLatencyManager::is_any_error(){ - int i; - for (i=0; im_port.is_any_err() ){ - return (true); - } - } - return (false); -} - - -void CLatencyManager::dump_json(std::string & json ){ - json="{\"name\":\"trex-latecny\",\"type\":0,\"data\":{"; - int i; - for (i=0; im_port.dump_json(json); - } - - json+="\"unknown\":0}}" ; - -} - -void CLatencyManager::dump_json_v2(std::string & json ){ - json="{\"name\":\"trex-latecny-v2\",\"type\":0,\"data\":{"; - json+=add_json("cpu_util",m_cpu_cp_u.GetVal()); - - int i; - for (i=0; im_port.dump_json_v2(json); - } - - json+="\"unknown\":0}}" ; - -} - -void CLatencyManager::DumpRxCheck(FILE *fd){ - if ( get_is_rx_check_mode() ) { - fprintf(fd," rx checker : \n"); - m_rx_check_manager.DumpShort(fd); - m_rx_check_manager.Dump(fd); - } -} - -void CLatencyManager::DumpShortRxCheck(FILE *fd){ - if ( get_is_rx_check_mode() ) { - m_rx_check_manager.DumpShort(fd); - } -} - -void CLatencyManager::dump_nat_flow_table(FILE *fd) { - m_nat_check_manager.Dump(fd); -} - -void CLatencyManager::rx_check_dump_json(std::string & json){ - if ( get_is_rx_check_mode() ) { - m_rx_check_manager.dump_json(json ); - } -} - - -void CLatencyManager::update_fast(){ - m_cpu_cp_u.Update() ; -} - -void CLatencyManager::update(){ - for (int i=0; im_port.m_hist.update(); - } -} - -void CLatencyManager::DumpShort(FILE *fd){ - int i; - fprintf(fd," Cpu Utilization : %2.1f %% \n",m_cpu_cp_u.GetVal()); - CCPortLatency::DumpShortHeader(fd); - for (i=0; im_port.DumpShort(fd); - fprintf(fd,"\n"); - } - - -} - -void CLatencyManager::Dump(FILE *fd){ - int i; - fprintf(fd," cpu : %2.1f %% \n",m_cpu_cp_u.GetVal()); - for (i=0; im_port.DumpCounters(fd); - } -} - -void CLatencyManager::DumpRxCheckVerification(FILE *fd, - uint64_t total_tx_rx_check){ - if ( !get_is_rx_check_mode() ) { - fprintf(fd," rx_checker is disabled \n"); - return; - } - fprintf(fd," rx_check Tx : %llu \n", (unsigned long long)total_tx_rx_check); - fprintf(fd," rx_check Rx : %llu \n", (unsigned long long)m_rx_check_manager.getTotalRx() ); - fprintf(fd," rx_check verification :" ); - if (m_rx_check_manager.getTotalRx() == total_tx_rx_check) { - fprintf(fd," OK \n" ); - }else{ - fprintf(fd," FAIL \n" ); - } -} - -uint8_t CLatencyPktModeICMP::getPacketLen() {return sizeof(icmp_pkt);} -const uint8_t *CLatencyPktModeICMP::getPacketData() {return icmp_pkt;} -void CLatencyPktModeICMP::rcv_debug_print(uint8_t *pkt) { - ICMPHeader *m_icmp = (ICMPHeader *)pkt; - printf ("received latency ICMP packet code:%d seq:%x\n" - , m_icmp->getType(), m_icmp->getSeqNum()); -}; - -void CLatencyPktModeICMP::send_debug_print(uint8_t *pkt) { - ICMPHeader *m_icmp = (ICMPHeader *)pkt; - printf ("Sending latency ICMP packet code:%d seq:%x\n", m_icmp->getType(), m_icmp->getSeqNum()); -} - -void CLatencyPktModeICMP::update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq) { - ICMPHeader * m_icmp =(ICMPHeader *)(pkt); - - if (m_submode == L_PKT_SUBMODE_0_SEQ) { - m_icmp->setSeqNum(0); - } else { - m_icmp->setSeqNum(*tx_seq); - (*tx_seq)++; - } - - if ((!is_client_to_server) && (m_submode == L_PKT_SUBMODE_REPLY)) { - m_icmp->setType(0); // echo reply - } else { - m_icmp->setType(8); // echo request - } - // ICMP checksum is calculated on payload + ICMP header - m_icmp->updateCheckSum(l4_len); - -} - -bool CLatencyPktModeICMP::IsLatencyPkt(IPHeader *ip) { - if (!ip) - return false; - if (ip->getProtocol() != 0x1) - return false; - return true; -}; - -void CLatencyPktModeICMP::update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq) { - ICMPHeader *m_icmp = (ICMPHeader *)(pkt); - *r_seq = m_icmp->getSeqNum(); - // Previously, we assumed we can send for sequences smaller than r_seq. - // Actually, if the DUT (firewall) dropped an ICMP request, we should not send response for the dropped packet. - // We are only sure that we can send reqponse for the request we just got. - // This should be OK, since we send requests and responses in the same rate. - *t_seq = *r_seq; -} - - -uint8_t CLatencyPktModeSCTP::getPacketLen() {return sizeof(sctp_pkt);} -const uint8_t *CLatencyPktModeSCTP::getPacketData() {return sctp_pkt;} -void CLatencyPktModeSCTP::rcv_debug_print(uint8_t *pkt) {printf("Received latency SCTP packet\n");} -void CLatencyPktModeSCTP::send_debug_print(uint8_t *pkt) {printf("Sending latency SCTP packet\n"); - // utl_DumpBuffer(stdout,pkt-20,28,0); -} -void CLatencyPktModeSCTP::update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq) {} -bool CLatencyPktModeSCTP::IsLatencyPkt(IPHeader *ip) { - if (!ip) { - return false; - } - if (ip->getProtocol() != 0x84) { - return false; - } - return true; -}; -void CLatencyPktModeSCTP::update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq) {} diff --git a/src/latency.h b/src/latency.h deleted file mode 100644 index 2f8a1134..00000000 --- a/src/latency.h +++ /dev/null @@ -1,352 +0,0 @@ -#ifndef LATENCY_H -#define LATENCY_H -/* - Hanoh Haim - Ido Barnea - Cisco Systems, Inc. -*/ - -/* -Copyright (c) 2015-2015 Cisco Systems, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -#include "bp_sim.h" -#include "flow_stat.h" - -#define L_PKT_SUBMODE_NO_REPLY 1 -#define L_PKT_SUBMODE_REPLY 2 -#define L_PKT_SUBMODE_0_SEQ 3 - -class TrexWatchDog; - -class CLatencyPktInfo { -public: - void Create(class CLatencyPktMode *m_l_pkt_info); - void Delete(); - void set_ip(uint32_t src, - uint32_t dst, - uint32_t dual_port_mask); - rte_mbuf_t * generate_pkt(int port_id,uint32_t extern_ip=0); - - CGenNode * getNode(){ - return (&m_dummy_node); - } - - uint16_t get_payload_offset(void){ - return ( m_pkt_indication.getFastPayloadOffset()); - } - - uint16_t get_l4_offset(void){ - return ( m_pkt_indication.getFastTcpOffset()); - } - - uint16_t get_pkt_size(void){ - return ( m_packet->pkt_len ); - } - -private: - ipaddr_t m_client_ip; - ipaddr_t m_server_ip; - uint32_t m_dual_port_mask; - CGenNode m_dummy_node; - CFlowPktInfo m_pkt_info; - CPacketIndication m_pkt_indication; - CCapPktRaw * m_packet; -}; - -#define LATENCY_MAGIC 0x12345600 - -struct latency_header { - uint64_t time_stamp; - uint32_t magic; - uint32_t seq; - - uint8_t get_id(){ - return( magic & 0xff); - } -}; - -class CLatencyManager ; - -// per port -class CCPortLatency { -public: - bool Create(CLatencyManager * parent, - uint8_t id, - uint16_t offset, - uint16_t l4_offset, - uint16_t pkt_size, - CCPortLatency * rx_port - ); - void Delete(); - void reset(); - bool can_send_packet(int direction){ - // in icmp_reply mode, can send response from server, only after we got the relevant request - // if we got request, we are sure to have NAT translation in place already. - if ((CGlobalInfo::m_options.m_l_pkt_mode == L_PKT_SUBMODE_REPLY) && (direction == 1)) { - if (m_icmp_tx_seq <= m_icmp_rx_seq) - return(true); - else - return(false); - } - - if ( !CGlobalInfo::is_learn_mode() ) { - return(true); - } - return ( m_nat_can_send ); - } - uint32_t external_nat_ip(){ - return (m_nat_external_ip); - } - void update_packet(rte_mbuf_t * m, int port_id); - bool do_learn(uint32_t external_ip); - bool check_packet(rte_mbuf_t * m, CRx_check_header * & rx_p); - bool check_rx_check(rte_mbuf_t * m); - bool dump_packet(rte_mbuf_t * m); - void DumpCounters(FILE *fd); - void dump_counters_json(std::string & json ); - void DumpShort(FILE *fd); - void dump_json(std::string & json ); - void dump_json_v2(std::string & json ); - uint32_t get_jitter_usec(void){ - return ((uint32_t)(m_jitter.get_jitter()*1000000.0)); - } - static void DumpShortHeader(FILE *fd); - - bool is_any_err(){ - if ( (m_tx_pkt_ok == m_rx_port->m_pkt_ok ) && - - ((m_unsup_prot+ - m_no_magic+ - m_no_id+ - m_seq_error+ - m_length_error+m_no_ipv4_option+m_tx_pkt_err)==0) ) { - return (false); - } - return (true); - } - - uint16_t get_icmp_tx_seq() {return m_icmp_tx_seq;} - uint16_t get_icmp_rx_seq() {return m_icmp_rx_seq;} - - // Check if packet contains latency data - static inline bool IsLatencyPkt(uint8_t *p) { - if (! p) - return false; - - latency_header * h=(latency_header *)(p); - if ( (h->magic & 0xffffff00) != LATENCY_MAGIC ){ - return false; - } - - return true; - } - -private: - std::string get_field(std::string name,float f); - - -private: - CLatencyManager * m_parent; - CCPortLatency * m_rx_port; /* corespond rx port */ - bool m_nat_learn; - bool m_nat_can_send; - uint32_t m_nat_external_ip; - uint32_t m_tx_seq; - uint32_t m_rx_seq; - uint8_t m_pad; - uint8_t m_id; - uint16_t m_payload_offset; - uint16_t m_l4_offset; - uint16_t m_pkt_size; - // following two variables are for the latency ICMP reply mode. - // if we want to pass through firewall, we want to send reply only after we got request with same seq num - // ICMP seq num of next packet we will transmit - uint16_t m_icmp_tx_seq; - // ICMP seq num of last request we got - uint16_t m_icmp_rx_seq; - uint16_t pad1[1]; - -public: - uint64_t m_tx_pkt_ok; - uint64_t m_tx_grat_arp_ok; - uint64_t m_tx_pkt_err; - uint64_t m_pkt_ok; - uint64_t m_unsup_prot; - uint64_t m_no_magic; - uint64_t m_no_id; - uint64_t m_seq_error; - uint64_t m_rx_check; - uint64_t m_no_ipv4_option; - uint64_t m_length_error; - CTimeHistogram m_hist; /* all window */ - CJitter m_jitter; -}; - - -class CPortLatencyHWBase { - public: - virtual int tx(rte_mbuf_t * m)=0; - virtual rte_mbuf_t * rx()=0; - virtual uint16_t rx_burst(struct rte_mbuf **rx_pkts, - uint16_t nb_pkts){ - return(0); - } -}; - - -class CLatencyManagerCfg { - public: - CLatencyManagerCfg (){ - m_max_ports=0; - m_cps=0.0; - memset(m_ports, 0, sizeof(m_ports)); - m_client_ip.v4=0x10000000; - m_server_ip.v4=0x20000000; - m_dual_port_mask=0x01000000; - } - - public: - uint32_t m_max_ports; - double m_cps;// CPS - CPortLatencyHWBase * m_ports[TREX_MAX_PORTS]; - ipaddr_t m_client_ip; - ipaddr_t m_server_ip; - uint32_t m_dual_port_mask; -}; - -class CLatencyManagerPerPort { -public: - CCPortLatency m_port; - CPortLatencyHWBase * m_io; - uint32_t m_flag; -}; - -class CLatencyPktMode { - public: - uint8_t m_submode; - CLatencyPktMode(uint8_t submode) {m_submode = submode;} - virtual uint8_t getPacketLen() = 0; - virtual const uint8_t *getPacketData() = 0; - virtual void rcv_debug_print(uint8_t *pkt) = 0; - virtual void send_debug_print(uint8_t *pkt) = 0; - virtual void update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq) = 0; - virtual bool IsLatencyPkt(IPHeader *ip) = 0; - uint8_t l4_header_len() {return 8;} - virtual void update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq) = 0; - virtual uint8_t getProtocol() = 0; - virtual ~CLatencyPktMode() {} -}; - -class CLatencyPktModeICMP: public CLatencyPktMode { - public: - CLatencyPktModeICMP(uint8_t submode) : CLatencyPktMode(submode) {} - uint8_t getPacketLen(); - const uint8_t *getPacketData(); - void rcv_debug_print(uint8_t *); - void send_debug_print(uint8_t *); - void update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq); - bool IsLatencyPkt(IPHeader *ip); - void update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq); - uint8_t getProtocol() {return 0x1;} -}; - -class CLatencyPktModeSCTP: public CLatencyPktMode { - public: - CLatencyPktModeSCTP(uint8_t submode) : CLatencyPktMode(submode) {} - uint8_t getPacketLen(); - const uint8_t *getPacketData(); - void rcv_debug_print(uint8_t *); - void send_debug_print(uint8_t *); - void update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq); - bool IsLatencyPkt(IPHeader *ip); - void update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq); - uint8_t getProtocol() {return 0x84;} -}; - -class CLatencyManager { -public: - bool Create(CLatencyManagerCfg * cfg); - void Delete(); - void reset(); - void start(int iter, bool activate_watchdog); - void stop(); - bool is_active(); - void set_ip(uint32_t client_ip, - uint32_t server_ip, - uint32_t mask_dual_port){ - m_pkt_gen.set_ip(client_ip,server_ip,mask_dual_port); - } - void Dump(FILE *fd); // dump all - void DumpShort(FILE *fd); // dump short histogram of latency - - void DumpRxCheck(FILE *fd); // dump all - void DumpShortRxCheck(FILE *fd); // dump short histogram of latency - void dump_nat_flow_table(FILE *fd); - void rx_check_dump_json(std::string & json); - uint16_t get_latency_header_offset(){ - return ( m_pkt_gen.get_payload_offset() ); - } - void update(); - void update_fast(); - - void dump_json(std::string & json ); // dump to json - void dump_json_v2(std::string & json ); - void DumpRxCheckVerification(FILE *fd,uint64_t total_tx_rx_check); - void set_mask(uint32_t mask){ - m_port_mask=mask; - } - double get_max_latency(void); - double get_avr_latency(void); - bool is_any_error(); - uint64_t get_total_pkt(); - uint64_t get_total_bytes(); - CNatRxManager * get_nat_manager(){ - return ( &m_nat_check_manager ); - } - CLatencyPktMode *c_l_pkt_mode; - -private: - void tickle(); - void send_pkt_all_ports(); - void send_grat_arp_all_ports(); - void try_rx(); - void try_rx_queues(); - void run_rx_queue_msgs(uint8_t thread_id, CNodeRing * r); - void wait_for_rx_dump(); - void handle_rx_pkt(CLatencyManagerPerPort * lp, rte_mbuf_t * m); - /* messages handlers */ - void handle_latency_pkt_msg(uint8_t thread_id, CGenNodeLatencyPktInfo * msg); - - private: - pqueue_t m_p_queue; /* priorty queue */ - bool m_is_active; - CLatencyPktInfo m_pkt_gen; - CLatencyManagerPerPort m_ports[TREX_MAX_PORTS]; - uint64_t m_d_time; // calc tick betwen sending - double m_cps; - double m_delta_sec; - uint64_t m_start_time; // calc tick betwen sending - uint32_t m_port_mask; - uint32_t m_max_ports; - RxCheckManager m_rx_check_manager; - CNatRxManager m_nat_check_manager; - CCpuUtlDp m_cpu_dp_u; - CCpuUtlCp m_cpu_cp_u; - TrexMonitor m_monitor; - - volatile bool m_do_stop __rte_cache_aligned ; -}; - -#endif diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index a6ea3876..edeeb3ee 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -74,9 +74,9 @@ extern "C" { #include "msg_manager.h" #include "platform_cfg.h" #include "pre_test.h" -#include "latency.h" +#include "stateful_rx_core.h" #include "debug.h" -#include "test_pkt_gen.h" +#include "pkt_gen.h" #include "internal_api/trex_platform_api.h" #include "main_dpdk.h" #include "trex_watchdog.h" @@ -653,7 +653,7 @@ static int usage(){ printf(" -m : factor of bandwidth \n"); printf(" \n"); printf(" --send-debug-pkt [proto] : Do not run traffic generator. Just send debug packet and dump receive queue."); - printf(" Supported protocols are 1 for icmp, 2 for UDP, 3 for TCP, 4 for 9K UDP\n"); + printf(" Supported protocols are 1 for icmp, 2 for UDP, 3 for TCP, 4 for ARP, 5 for 9K UDP\n"); printf(" \n"); printf(" -k [sec] : run latency test before starting the test. it will wait for x sec sending packet and x sec after that \n"); printf(" \n"); @@ -1014,7 +1014,8 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t "if you think it is important,open a defect \n"); } - if (po->preview.get_is_rx_check_enable() || po->is_latency_enabled() || CGlobalInfo::is_learn_mode()) { + if (po->preview.get_is_rx_check_enable() || po->is_latency_enabled() || CGlobalInfo::is_learn_mode() + || (CGlobalInfo::m_options.m_arp_ref_per != 0)) { po->set_rx_enabled(); } @@ -1212,7 +1213,7 @@ typedef struct cnt_name_ { #define MY_REG(a) {a,(char *)#a} -void CPhyEthIFStats::Clear(){ +void CPhyEthIFStats::Clear() { ipackets = 0; ibytes = 0; f_ipackets = 0; @@ -1223,13 +1224,13 @@ void CPhyEthIFStats::Clear(){ oerrors = 0; imcasts = 0; rx_nombuf = 0; + memset(&m_prev_stats, 0, sizeof(m_prev_stats)); memset(m_rx_per_flow_pkts, 0, sizeof(m_rx_per_flow_pkts)); memset(m_rx_per_flow_bytes, 0, sizeof(m_rx_per_flow_bytes)); } - -void CPhyEthIFStats::DumpAll(FILE *fd){ - +// dump all counters (even ones that equal 0) +void CPhyEthIFStats::DumpAll(FILE *fd) { #define DP_A4(f) printf(" %-40s : %llu \n",#f, (unsigned long long)f) #define DP_A(f) if (f) printf(" %-40s : %llu \n",#f, (unsigned long long)f) DP_A4(opackets); @@ -1238,18 +1239,14 @@ void CPhyEthIFStats::DumpAll(FILE *fd){ DP_A4(ibytes); DP_A(ierrors); DP_A(oerrors); - } - -void CPhyEthIFStats::Dump(FILE *fd){ - +// dump all non zero counters +void CPhyEthIFStats::Dump(FILE *fd) { DP_A(opackets); DP_A(obytes); - DP_A(f_ipackets); DP_A(f_ibytes); - DP_A(ipackets); DP_A(ibytes); DP_A(ierrors); @@ -1258,6 +1255,15 @@ void CPhyEthIFStats::Dump(FILE *fd){ DP_A(rx_nombuf); } +void CPhyEthIgnoreStats::dump(FILE *fd) { + DP_A4(opackets); + DP_A4(obytes); + DP_A4(ipackets); + DP_A4(ibytes); + DP_A4(m_tx_arp); + DP_A4(m_rx_arp); +} + // Clear the RX queue of an interface, dropping all packets void CPhyEthIF::flush_rx_queue(void){ @@ -1565,51 +1571,6 @@ void CPhyEthIF::macaddr_get(struct ether_addr *mac_addr){ rte_eth_macaddr_get(m_port_id , mac_addr); } - -void CPhyEthIF::get_stats_1g(CPhyEthIFStats *stats){ - - stats->ipackets += pci_reg_read(E1000_GPRC) ; - - stats->ibytes += (pci_reg_read(E1000_GORCL) ); - stats->ibytes += (((uint64_t)pci_reg_read(E1000_GORCH))<<32); - - - stats->opackets += pci_reg_read(E1000_GPTC); - stats->obytes += pci_reg_read(E1000_GOTCL) ; - stats->obytes += ( (((uint64_t)pci_reg_read(IXGBE_GOTCH))<<32) ); - - stats->f_ipackets += 0; - stats->f_ibytes += 0; - - - stats->ierrors += ( pci_reg_read(E1000_RNBC) + - pci_reg_read(E1000_CRCERRS) + - pci_reg_read(E1000_ALGNERRC ) + - pci_reg_read(E1000_SYMERRS ) + - pci_reg_read(E1000_RXERRC ) + - - pci_reg_read(E1000_ROC)+ - pci_reg_read(E1000_RUC)+ - pci_reg_read(E1000_RJC) + - - pci_reg_read(E1000_XONRXC)+ - pci_reg_read(E1000_XONTXC)+ - pci_reg_read(E1000_XOFFRXC)+ - pci_reg_read(E1000_XOFFTXC)+ - pci_reg_read(E1000_FCRUC) - ); - - stats->oerrors += 0; - stats->imcasts = 0; - stats->rx_nombuf = 0; - - m_last_tx_rate = m_bw_tx.add(stats->obytes); - m_last_rx_rate = m_bw_rx.add(stats->ibytes); - m_last_tx_pps = m_pps_tx.add(stats->opackets); - m_last_rx_pps = m_pps_rx.add(stats->ipackets); - -} - int CPhyEthIF::dump_fdir_global_stats(FILE *fd) { return get_ex_drv()->dump_fdir_global_stats(this, fd); } @@ -1672,8 +1633,8 @@ void dump_hw_state(FILE *fd,struct ixgbe_hw_stats *hs ){ DP_A1(mptc); DP_A1(bptc); DP_A1(xec); - DP_A2(qprc,16) - DP_A2(qptc,16); + DP_A2(qprc,16); + DP_A2(qptc,16); DP_A2(qbrc,16); DP_A2(qbtc,16); DP_A2(qprdc,16); @@ -1701,14 +1662,27 @@ void dump_hw_state(FILE *fd,struct ixgbe_hw_stats *hs ){ DP_A1(o2bspc); } - -void CPhyEthIF::update_counters(){ +void CPhyEthIF::set_ignore_stats_base(CPreTestStats &pre_stats) { + // reading m_stats, so drivers saving prev in m_stats will be updated. + // Actually, we want m_stats to be cleared get_ex_drv()->get_extended_stats(this, &m_stats); - m_last_tx_rate = m_bw_tx.add(m_stats.obytes); - m_last_rx_rate = m_bw_rx.add(m_stats.ibytes); - m_last_tx_pps = m_pps_tx.add(m_stats.opackets); - m_last_rx_pps = m_pps_rx.add(m_stats.ipackets); + m_ignore_stats.ipackets = m_stats.ipackets; + m_ignore_stats.ibytes = m_stats.ibytes; + m_ignore_stats.opackets = m_stats.opackets; + m_ignore_stats.obytes = m_stats.obytes; + m_stats.ipackets = 0; + m_stats.opackets = 0; + m_stats.ibytes = 0; + m_stats.obytes = 0; + + m_ignore_stats.m_tx_arp = pre_stats.m_tx_arp; + m_ignore_stats.m_rx_arp = pre_stats.m_rx_arp; + + if (CGlobalInfo::m_options.preview.getVMode() >= 3) { + fprintf(stdout, "Pre test statistics for port %d\n", get_port_id()); + m_ignore_stats.dump(stdout); + } } void CPhyEthIF::dump_stats(FILE *fd){ @@ -2842,7 +2816,6 @@ public: void rx_sl_configure(); bool is_all_links_are_up(bool dump=false); void pre_test(); - int reset_counters(); /** * mark for shutdown @@ -3011,7 +2984,13 @@ void CGlobalTRex::pre_test() { } pretest.send_grat_arp_all(); - pretest.resolve_all(); + bool ret; + int count = 0; + do { + ret = pretest.resolve_all(); + count++; + } while ((ret != true) && (count < 3)); + if ( CGlobalInfo::m_options.preview.getVMode() > 0) { pretest.dump(stdout); } @@ -3031,22 +3010,16 @@ void CGlobalTRex::pre_test() { CGlobalInfo::m_options.m_ip_cfg[port_id].set_grat_arp_needed(false); } + // update statistics baseline, so we can ignore what happened in pre test phase CPhyEthIF *pif = &m_ports[port_id]; + CPreTestStats pre_stats = pretest.get_stats(port_id); + pif->set_ignore_stats_base(pre_stats); + // Configure port back to normal mode. Only relevant packets handled by software. CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, false); } } -int CGlobalTRex::reset_counters(){ - int i; - for (i=0; istats_clear(); - } - - return (0); -} - /** * check for a single core * @@ -3175,8 +3148,14 @@ void CGlobalTRex::ixgbe_configure_mg(void) { if ( latency_rate ) { mg_cfg.m_cps = (double)latency_rate ; - }else{ - mg_cfg.m_cps = 1.0; + } else { + // If RX core needed, we need something to make the scheduler running. + // If nothing configured, send 1 CPS latency measurement packets. + if (CGlobalInfo::m_options.m_arp_ref_per == 0) { + mg_cfg.m_cps = 1.0; + } else { + mg_cfg.m_cps = 0; + } } if ( get_vm_one_queue_enable() ) { @@ -3657,6 +3636,8 @@ void CGlobalTRex::dump_post_test_stats(FILE *fd){ uint64_t sw_pkt_out=0; uint64_t sw_pkt_out_err=0; uint64_t sw_pkt_out_bytes=0; + uint64_t tx_arp = 0; + uint64_t rx_arp = 0; int i; for (i=0; iget_stats().ibytes; pkt_out +=_if->get_stats().opackets; pkt_out_bytes +=_if->get_stats().obytes; + tx_arp += _if->get_ignore_stats().get_tx_arp(); + rx_arp += _if->get_ignore_stats().get_rx_arp(); } if ( CGlobalInfo::m_options.is_latency_enabled() ){ sw_pkt_out += m_mg.get_total_pkt(); @@ -3703,6 +3686,8 @@ void CGlobalTRex::dump_post_test_stats(FILE *fd){ fprintf (fd," Total-rx-pkt : %llu pkts \n", (unsigned long long)pkt_in); fprintf (fd," Total-sw-tx-pkt : %llu pkts \n", (unsigned long long)sw_pkt_out); fprintf (fd," Total-sw-err : %llu pkts \n", (unsigned long long)sw_pkt_out_err); + fprintf (fd," Total ARP sent : %llu pkts \n", (unsigned long long)tx_arp); + fprintf (fd," Total ARP received : %llu pkts \n", (unsigned long long)rx_arp); if ( CGlobalInfo::m_options.is_latency_enabled() ){ @@ -4550,6 +4535,22 @@ int CGlobalTRex::start_master_statefull() { //////////////////////////////////////////// static CGlobalTRex g_trex; +void CPhyEthIF::update_counters() { + get_ex_drv()->get_extended_stats(this, &m_stats); + CRXCoreIgnoreStat ign_stats; + g_trex.m_mg.get_ignore_stats(m_port_id, ign_stats, true); + m_stats.obytes -= ign_stats.get_tx_bytes(); + m_stats.opackets -= ign_stats.get_tx_pkts(); + m_ignore_stats.opackets += ign_stats.get_tx_pkts(); + m_ignore_stats.obytes += ign_stats.get_tx_bytes(); + m_ignore_stats.m_tx_arp += ign_stats.get_tx_arp(); + + m_last_tx_rate = m_bw_tx.add(m_stats.obytes); + m_last_rx_rate = m_bw_rx.add(m_stats.ibytes); + m_last_tx_pps = m_pps_tx.add(m_stats.opackets); + m_last_rx_pps = m_pps_rx.add(m_stats.ipackets); +} + bool CPhyEthIF::Create(uint8_t portid) { m_port_id = portid; m_last_rx_rate = 0.0; @@ -5140,18 +5141,6 @@ int main_test(int argc , char * argv[]){ /* set dump mode */ g_trex.m_io_modes.set_mode((CTrexGlobalIoMode::CliDumpMode)CGlobalInfo::m_options.m_io_mode); - if ( CGlobalInfo::m_options.is_latency_enabled() - && (CGlobalInfo::m_options.m_latency_prev > 0)) { - uint32_t pkts = CGlobalInfo::m_options.m_latency_prev * - CGlobalInfo::m_options.m_latency_rate; - printf("Starting pre latency check for %d sec\n",CGlobalInfo::m_options.m_latency_prev); - g_trex.m_mg.start(pkts, NULL); - delay(CGlobalInfo::m_options.m_latency_prev* 1000); - printf("Finished \n"); - g_trex.m_mg.reset(); - g_trex.reset_counters(); - } - /* disable WD if needed */ bool wd_enable = (CGlobalInfo::m_options.preview.getWDDisable() ? false : true); TrexWatchDog::getInstance().init(wd_enable); @@ -5211,6 +5200,7 @@ int main_test(int argc , char * argv[]){ } g_trex.pre_test(); + // after doing all needed ARP resolution, we need to flush queues, and stop our drop queue g_trex.ixgbe_rx_queue_flush(); for (int i = 0; i < g_trex.m_max_ports; i++) { @@ -5218,6 +5208,17 @@ int main_test(int argc , char * argv[]){ _if->stop_rx_drop_queue(); } + if ( CGlobalInfo::m_options.is_latency_enabled() + && (CGlobalInfo::m_options.m_latency_prev > 0)) { + uint32_t pkts = CGlobalInfo::m_options.m_latency_prev * + CGlobalInfo::m_options.m_latency_rate; + printf("Starting warm up phase for %d sec\n",CGlobalInfo::m_options.m_latency_prev); + g_trex.m_mg.start(pkts, NULL); + delay(CGlobalInfo::m_options.m_latency_prev* 1000); + printf("Finished \n"); + g_trex.m_mg.reset(); + } + if ( CGlobalInfo::m_options.preview.getOnlyLatency() ){ rte_eal_mp_remote_launch(latency_one_lcore, NULL, CALL_MASTER); RTE_LCORE_FOREACH_SLAVE(lcore_id) { @@ -6054,20 +6055,32 @@ int CTRexExtendedDriverBase40G::dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd } } -void CTRexExtendedDriverBase40G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){ +void CTRexExtendedDriverBase40G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats) { struct rte_eth_stats stats1; + struct rte_eth_stats *prev_stats = &stats->m_prev_stats; rte_eth_stats_get(_if->get_port_id(), &stats1); - stats->ipackets = stats1.ipackets; - stats->ibytes = stats1.ibytes ; - stats->opackets = stats1.opackets; - stats->obytes = stats1.obytes + (stats1.opackets<<2); - stats->f_ipackets = 0; - stats->f_ibytes = 0; - stats->ierrors = stats1.imissed + stats1.ierrors + stats1.rx_nombuf; - stats->oerrors = stats1.oerrors;; - stats->imcasts = 0; - stats->rx_nombuf = stats1.rx_nombuf; + stats->ipackets += stats1.ipackets - prev_stats->ipackets; + stats->ibytes += stats1.ibytes - prev_stats->ibytes; + stats->opackets += stats1.opackets - prev_stats->opackets; + stats->obytes += stats1.obytes - prev_stats->obytes + + (stats1.opackets << 2) - (prev_stats->opackets << 2); + stats->f_ipackets += 0; + stats->f_ibytes += 0; + stats->ierrors += stats1.imissed + stats1.ierrors + stats1.rx_nombuf + - prev_stats->imissed - prev_stats->ierrors - prev_stats->rx_nombuf; + stats->oerrors += stats1.oerrors - prev_stats->oerrors; + stats->imcasts += 0; + stats->rx_nombuf += stats1.rx_nombuf - prev_stats->rx_nombuf; + + prev_stats->ipackets = stats1.ipackets; + prev_stats->ibytes = stats1.ibytes; + prev_stats->opackets = stats1.opackets; + prev_stats->obytes = stats1.obytes; + prev_stats->imissed = stats1.imissed; + prev_stats->oerrors = stats1.oerrors; + prev_stats->ierrors = stats1.ierrors; + prev_stats->rx_nombuf = stats1.rx_nombuf; } int CTRexExtendedDriverBase40G::wait_for_stable_link(){ @@ -6154,31 +6167,30 @@ int CTRexExtendedDriverBase1GVm::stop_queue(CPhyEthIF * _if, uint16_t q_num) { } void CTRexExtendedDriverBase1GVm::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){ - struct rte_eth_stats stats1; + struct rte_eth_stats *prev_stats = &stats->m_prev_stats; rte_eth_stats_get(_if->get_port_id(), &stats1); - - stats->ipackets = stats1.ipackets; - stats->ibytes = stats1.ibytes; - - stats->opackets = stats1.opackets; - stats->obytes = stats1.obytes; - - stats->f_ipackets = 0; - stats->f_ibytes = 0; - - - stats->ierrors = stats1.imissed + - stats1.ierrors + - stats1.oerrors + - stats1.rx_nombuf; - - - stats->oerrors = stats1.oerrors;; - stats->imcasts = 0; - stats->rx_nombuf = stats1.rx_nombuf; - + stats->ipackets += stats1.ipackets - prev_stats->ipackets; + stats->ibytes += stats1.ibytes - prev_stats->ibytes; + stats->opackets += stats1.opackets - prev_stats->opackets; + stats->obytes += stats1.obytes - prev_stats->obytes; + stats->f_ipackets += 0; + stats->f_ibytes += 0; + stats->ierrors += stats1.imissed + stats1.ierrors + stats1.rx_nombuf + - prev_stats->imissed - prev_stats->ierrors - prev_stats->rx_nombuf; + stats->oerrors += stats1.oerrors - prev_stats->oerrors; + stats->imcasts += 0; + stats->rx_nombuf += stats1.rx_nombuf - prev_stats->rx_nombuf; + + prev_stats->ipackets = stats1.ipackets; + prev_stats->ibytes = stats1.ibytes; + prev_stats->opackets = stats1.opackets; + prev_stats->obytes = stats1.obytes; + prev_stats->imissed = stats1.imissed; + prev_stats->oerrors = stats1.oerrors; + prev_stats->ierrors = stats1.ierrors; + prev_stats->rx_nombuf = stats1.rx_nombuf; } int CTRexExtendedDriverBase1GVm::wait_for_stable_link(){ diff --git a/src/main_dpdk.h b/src/main_dpdk.h index bde10659..97994c47 100644 --- a/src/main_dpdk.h +++ b/src/main_dpdk.h @@ -18,6 +18,7 @@ #define MAIN_DPDK_H #include +#include "pre_test.h" #include "bp_sim.h" enum { @@ -25,8 +26,28 @@ enum { MAIN_DPDK_RX_Q = 1, }; -class CPhyEthIFStats { +// These are statistics for packets we send, and do not expect to get back (Like ARP) +// We reduce them from general statistics we report (and report them separately, so we can keep the assumption +// that tx_pkts == rx_pkts and tx_bytes==rx_bytes +class CPhyEthIgnoreStats { + friend class CPhyEthIF; + public: + uint64_t get_rx_arp() {return m_rx_arp;} + uint64_t get_tx_arp() {return m_tx_arp;} + private: + uint64_t ipackets; /**< Total number of successfully received packets. */ + uint64_t ibytes; /**< Total number of successfully received bytes. */ + uint64_t opackets; /**< Total number of successfully transmitted packets.*/ + uint64_t obytes; /**< Total number of successfully transmitted bytes. */ + uint64_t m_tx_arp; /**< Total number of successfully transmitted ARP packets */ + uint64_t m_rx_arp; /**< Total number of successfully received ARP packets */ + + private: + void dump(FILE *fd); +}; + +class CPhyEthIFStats { public: uint64_t ipackets; /**< Total number of successfully received packets. */ uint64_t ibytes; /**< Total number of successfully received bytes. */ @@ -38,6 +59,7 @@ class CPhyEthIFStats { uint64_t oerrors; /**< Total number of failed transmitted packets. */ uint64_t imcasts; /**< Total number of multicast received packets. */ uint64_t rx_nombuf; /**< Total number of RX mbuf allocation failures. */ + struct rte_eth_stats m_prev_stats; uint64_t m_rx_per_flow_pkts [MAX_FLOW_STATS]; // Per flow RX pkts uint64_t m_rx_per_flow_bytes[MAX_FLOW_STATS]; // Per flow RX bytes // Previous fdir stats values read from driver. Since on xl710 this is 32 bit, we save old value, to handle wrap around. @@ -71,7 +93,6 @@ class CPhyEthIF { int reset_hw_flow_stats(); int get_flow_stats(rx_per_flow_t *rx_stats, tx_per_flow_t *tx_stats, int min, int max, bool reset); int get_flow_stats_payload(rx_per_flow_t *rx_stats, tx_per_flow_t *tx_stats, int min, int max, bool reset); - void get_stats_1g(CPhyEthIFStats *stats); void rx_queue_setup(uint16_t rx_queue_id, uint16_t nb_rx_desc, unsigned int socket_id, @@ -99,6 +120,7 @@ class CPhyEthIF { void add_mac(char * mac); bool get_promiscuous(); void dump_stats(FILE *fd); + void set_ignore_stats_base(CPreTestStats &pre_stats); void update_counters(); void stats_clear(); uint8_t get_port_id(){ @@ -120,6 +142,9 @@ class CPhyEthIF { CPhyEthIFStats & get_stats(){ return ( m_stats ); } + CPhyEthIgnoreStats & get_ignore_stats() { + return m_ignore_stats; + } void flush_dp_rx_queue(void); void flush_rx_queue(void); int add_rx_flow_stat_rule(uint8_t port_id, uint16_t l3_type, uint8_t l4_proto @@ -167,6 +192,7 @@ class CPhyEthIF { CPPSMeasure m_pps_tx; CPPSMeasure m_pps_rx; CPhyEthIFStats m_stats; + CPhyEthIgnoreStats m_ignore_stats; float m_last_tx_rate; float m_last_rx_rate; float m_last_tx_pps; diff --git a/src/pkt_gen.cpp b/src/pkt_gen.cpp new file mode 100644 index 00000000..eb9a26f9 --- /dev/null +++ b/src/pkt_gen.cpp @@ -0,0 +1,284 @@ +/* + Ido Barnea + Cisco Systems, Inc. +*/ + +/* + Copyright (c) 2016-2016 Cisco Systems, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rx_check_header.h" +#include "pkt_gen.h" + +// For use in tests +char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t ttl, uint32_t ip_id, uint16_t flags + , uint16_t max_payload, int &pkt_size) { + // ASA 2 + uint8_t dst_mac[6] = {0x74, 0xa2, 0xe6, 0xd5, 0x39, 0x25}; + uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02}; + uint8_t vlan_header[4] = {0x0a, 0xbc, 0x00, 0x00}; // we set the type below according to if pkt is ipv4 or 6 + uint8_t vlan_header2[4] = {0x0a, 0xbc, 0x88, 0xa8}; + uint16_t l2_proto; + uint16_t payload_len; + + // ASA 1 + // uint8_t dst_mac[6] = {0xd4, 0x8c, 0xb5, 0xc9, 0x54, 0x2b}; + // uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x0}; + if (flags & DPF_VLAN) { + l2_proto = 0x0081; + } else { + l2_proto = htons(l3_type); + } + + uint8_t ip_header[] = { + 0x45,0x02,0x00,0x30, + 0x00,0x00,0x40,0x00, + 0xff,0x01,0xbd,0x04, + 0x10,0x0,0x0,0x1, //SIP + 0x30,0x0,0x0,0x1, //DIP + // 0x82, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // IP option. change 45 to 48 (header len) if using it. + }; + uint8_t ipv6_header[] = { + 0x60,0x00,0xff,0x30, // traffic class + flow label + 0x00,0x00,0x40,0x00, // payload len + next header + hop limit + 0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //SIP + 0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //DIP + }; + uint8_t udp_header[] = {0x11, 0x11, 0x11,0x11, 0x00, 0x6d, 0x00, 0x00}; + uint8_t udp_data[] = {0x64,0x31,0x3a,0x61, + 0x64,0x32,0x3a,0x69,0x64, + 0x32,0x30,0x3a,0xd0,0x0e, + 0xa1,0x4b,0x7b,0xbd,0xbd, + 0x16,0xc6,0xdb,0xc4,0xbb,0x43, + 0xf9,0x4b,0x51,0x68,0x33,0x72, + 0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f, + 0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3, + 0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f, + 0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39, + 0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31, + 0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d, + 0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d, + 0xe7 + }; + + uint8_t tcp_header[] = {0xab, 0xcd, 0x00, 0x80, // src, dst ports + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // seq num, ack num + 0x50, 0x00, 0xff, 0xff, // Header size, flags, window size + 0x00, 0x00, 0x00, 0x00, // checksum ,urgent pointer + }; + + uint8_t tcp_data[] = {0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5, + 0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5}; + + uint8_t icmp_header[] = { + 0x08, 0x00, + 0xb8, 0x21, //checksum + 0xaa, 0xbb, // id + 0x00, 0x01, // Sequence number + }; + uint8_t icmp_data[] = { + 0xd6, 0x6e, 0x64, 0x34, // magic + 0x6a, 0xad, 0x0f, 0x00, //64 bit counter + 0x00, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, 0x00, 0x00 // seq + }; + + pkt_size = 14; + + if (flags & DPF_VLAN) { + pkt_size += 4; + if (flags & DPF_QINQ) { + pkt_size += 4; + } + } + + switch(l3_type) { + case EthernetHeader::Protocol::IP: + pkt_size += sizeof(ip_header); + break; + case EthernetHeader::Protocol::IPv6: + pkt_size += sizeof(ipv6_header); + if (flags & DPF_RXCHECK) { + pkt_size += sizeof(struct CRx_check_header); + } + break; + } + + switch (l4_proto) { + case IPPROTO_ICMP: + pkt_size += sizeof(icmp_header); + payload_len = (max_payload < sizeof(icmp_data)) ? max_payload:sizeof(icmp_data); + pkt_size += payload_len; + break; + case IPPROTO_UDP: + pkt_size += sizeof(udp_header); + payload_len = (max_payload < sizeof(udp_data)) ? max_payload:sizeof(udp_data); + pkt_size += payload_len; + break; + case IPPROTO_TCP: + pkt_size += sizeof(tcp_header); + payload_len = (max_payload < sizeof(tcp_data)) ? max_payload:sizeof(tcp_data); + pkt_size += payload_len; + break; + default: + payload_len = (max_payload < sizeof(udp_data)) ? max_payload:sizeof(udp_data); + pkt_size += payload_len; + break; + } + + char *p_start = (char *)malloc(pkt_size); + assert(p_start); + char *p = p_start; + + /* set pkt data */ + memcpy(p, dst_mac, sizeof(dst_mac)); p += sizeof(dst_mac); + memcpy(p, src_mac, sizeof(src_mac)); p += sizeof(src_mac); + memcpy(p, &l2_proto, sizeof(l2_proto)); p += sizeof(l2_proto); + + if (flags & DPF_VLAN) { + if (flags & DPF_QINQ) { + memcpy(p, &vlan_header2, sizeof(vlan_header2)); p += sizeof(vlan_header2); + } + + uint16_t l3_type_htons = htons(l3_type); + memcpy(&vlan_header[2], &l3_type_htons, sizeof(l3_type)); + memcpy(p, &vlan_header, sizeof(vlan_header)); p += sizeof(vlan_header); + } + + struct IPHeader *ip = (IPHeader *)p; + struct IPv6Header *ipv6 = (IPv6Header *)p; + switch(l3_type) { + case EthernetHeader::Protocol::IP: + memcpy(p, ip_header, sizeof(ip_header)); p += sizeof(ip_header); + ip->setProtocol(l4_proto); + ip->setTotalLength(pkt_size - 14); + ip->setId(ip_id); + break; + case EthernetHeader::Protocol::IPv6: + memcpy(p, ipv6_header, sizeof(ipv6_header)); p += sizeof(ipv6_header); + if (flags & DPF_RXCHECK) { + // rx check header + ipv6->setNextHdr(RX_CHECK_V6_OPT_TYPE); + if (flags & DPF_RXCHECK) { + struct CRx_check_header *rxch = (struct CRx_check_header *)p; + p += sizeof(CRx_check_header); + rxch->m_option_type = l4_proto; + rxch->m_option_len = RX_CHECK_V6_OPT_LEN; + } + } else { + ipv6->setNextHdr(l4_proto); + } + ipv6->setPayloadLen(pkt_size - 14 - sizeof(ipv6_header)); + ipv6->setFlowLabel(ip_id); + break; + } + + + struct TCPHeader *tcp = (TCPHeader *)p; + struct ICMPHeader *icmp= (ICMPHeader *)p; + switch (l4_proto) { + case IPPROTO_ICMP: + memcpy(p, icmp_header, sizeof(icmp_header)); p += sizeof(icmp_header); + memcpy(p, icmp_data, payload_len); p += payload_len; + icmp->updateCheckSum(sizeof(icmp_header) + sizeof(icmp_data)); + break; + case IPPROTO_UDP: + memcpy(p, udp_header, sizeof(udp_header)); p += sizeof(udp_header); + memcpy(p, udp_data, payload_len); p += payload_len; + break; + case IPPROTO_TCP: + memcpy(p, tcp_header, sizeof(tcp_header)); p += sizeof(tcp_header); + memcpy(p, tcp_data, payload_len); p += payload_len; + tcp->setSynFlag(false); + // printf("Sending TCP header:"); + //tcp->dump(stdout); + break; + default: + memcpy(p, udp_data, payload_len); p += payload_len; + break; + } + + switch(l3_type) { + case EthernetHeader::Protocol::IP: + ip->setTimeToLive(ttl); + ip->updateCheckSum(); + break; + case EthernetHeader::Protocol::IPv6: + ipv6->setHopLimit(ttl); + break; + } + + return p_start; +} + +/* + * Create ARP request packet + * Parameters: + * pkt - Buffer to fill the packet in. Size should be big enough to contain the packet (60 is a good value). + * sip - Our source IP + * tip - Target IP for which we need resolution (In case of gratuitous ARP, should be equal sip). + * src_mac - Our source MAC + * vlan - VLAN tag to send the packet on. If set to 0, no vlan will be sent. + * port - Port we intended to send packet on. This is needed since we put some "magic" number with the port, so + * we can identify if we are connected in loopback, which ports are connected. + */ +void CTestPktGen::create_arp_req(uint8_t *pkt, uint32_t sip, uint32_t tip, uint8_t *src_mac, uint16_t vlan + , uint16_t port) { + uint16_t l2_proto = htons(EthernetHeader::Protocol::ARP); + + // dst MAC + memset(pkt, 0xff, ETHER_ADDR_LEN); + pkt += ETHER_ADDR_LEN; + // src MAC + memcpy(pkt, src_mac, ETHER_ADDR_LEN); + pkt += ETHER_ADDR_LEN; + + if (vlan != 0) { + uint16_t htons_vlan = htons(vlan); + uint16_t vlan_proto = htons(0x8100); + memcpy(pkt, &vlan_proto, sizeof(vlan_proto)); + pkt += 2; + memcpy(pkt, &htons_vlan, sizeof(uint16_t)); + pkt += 2; + } + + // l3 type + memcpy(pkt, &l2_proto, sizeof(l2_proto)); + pkt += 2; + + ArpHdr *arp = (ArpHdr *)pkt; + arp->m_arp_hrd = htons(ArpHdr::ARP_HDR_HRD_ETHER); // Format of hardware address + arp->m_arp_pro = htons(EthernetHeader::Protocol::IP); // Format of protocol address + arp->m_arp_hln = ETHER_ADDR_LEN; // Length of hardware address + arp->m_arp_pln = 4; // Length of protocol address + arp->m_arp_op = htons(ArpHdr::ARP_HDR_OP_REQUEST); // ARP opcode (command) + + memcpy(&arp->m_arp_sha.data, src_mac, ETHER_ADDR_LEN); // Sender MAC address + arp->m_arp_sip = htonl(sip); // Sender IP address + + uint8_t magic[5] = {0x1, 0x3, 0x5, 0x7, 0x9}; + memcpy(&arp->m_arp_tha.data, magic, 5); // Target MAC address + arp->m_arp_tha.data[5] = port; + arp->m_arp_tip = htonl(tip); +} diff --git a/src/pkt_gen.h b/src/pkt_gen.h new file mode 100644 index 00000000..309e02b9 --- /dev/null +++ b/src/pkt_gen.h @@ -0,0 +1,51 @@ +/* + Ido Barnea + Cisco Systems, Inc. +*/ + +/* + Copyright (c) 2016-2016 Cisco Systems, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef __PKT_GEN_H__ +#define __PKT_GEN_H__ + +enum { + D_PKT_TYPE_ICMP = 1, + D_PKT_TYPE_UDP = 2, + D_PKT_TYPE_TCP = 3, + D_PKT_TYPE_ARP = 4, + D_PKT_TYPE_9k_UDP = 5, + D_PKT_TYPE_IPV6 = 60, + D_PKT_TYPE_HW_VERIFY = 100, + D_PKT_TYPE_HW_VERIFY_RCV_ALL = 101, + D_PKT_TYPE_HW_TOGGLE_TEST = 102, +}; + +enum { + DPF_VLAN = 0x1, + DPF_QINQ = 0X2, + DPF_RXCHECK = 0x4 +}; + +class CTestPktGen { + public: + static char *create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t ttl, uint32_t ip_id, uint16_t flags + , uint16_t max_payload, int &pkt_size); + static void create_arp_req(uint8_t *pkt, uint32_t sip, uint32_t tip, uint8_t *src_mac, uint16_t vlan + , uint16_t port); +}; + +#endif diff --git a/src/pre_test.cpp b/src/pre_test.cpp index 0639d9c8..278db98b 100644 --- a/src/pre_test.cpp +++ b/src/pre_test.cpp @@ -26,10 +26,9 @@ #include "common/basic_utils.h" #include "bp_sim.h" #include "main_dpdk.h" -#include "test_pkt_gen.h" +#include "pkt_gen.h" #include "pre_test.h" - void CPretestPortInfo::set_params(CPerPortIPCfg port_cfg, const uint8_t *src_mac, bool resolve_needed) { m_ip = port_cfg.get_ip(); m_def_gw = port_cfg.get_def_gw(); @@ -73,18 +72,24 @@ void CPretestPortInfo::dump(FILE *fd) { put in mac relevant dest MAC for port/ip pair. return false if no relevant info exists, true otherwise. */ -bool CPretest::get_mac(uint16_t port, uint32_t ip, uint8_t *mac) { - assert(port < TREX_MAX_PORTS); +bool CPretest::get_mac(uint16_t port_id, uint32_t ip, uint8_t *mac) { + assert(port_id < TREX_MAX_PORTS); - if (m_port_info[port].m_state != CPretestPortInfo::RESOLVE_DONE) { + if (m_port_info[port_id].m_state != CPretestPortInfo::RESOLVE_DONE) { return false; } - memcpy(mac, &m_port_info[port].m_dst_mac, sizeof(m_port_info[port].m_dst_mac)); + memcpy(mac, &m_port_info[port_id].m_dst_mac, sizeof(m_port_info[port_id].m_dst_mac)); return true; } +CPreTestStats CPretest::get_stats(uint16_t port_id) { + assert(port_id < TREX_MAX_PORTS); + + return m_port_info[port_id].m_stats; +} + bool CPretest::is_loopback(uint16_t port) { assert(port < TREX_MAX_PORTS); @@ -104,22 +109,26 @@ int CPretest::handle_rx(int port_id, int queue_id) { uint16_t cnt; int i; int verbose = CGlobalInfo::m_options.preview.getVMode(); - - cnt = rte_eth_rx_burst(port_id, queue_id, rx_pkts, sizeof(rx_pkts)/sizeof(rx_pkts[0])); - - for (i = 0; i < cnt; i++) { - rte_mbuf_t * m = rx_pkts[i]; - int pkt_size = rte_pktmbuf_pkt_len(m); - uint8_t *p = rte_pktmbuf_mtod(m, uint8_t *); - ArpHdr *arp; - CPretestPortInfo *port = &m_port_info[port_id]; - if (is_arp(p, pkt_size, arp)) { - if (arp->m_arp_op == htons(ArpHdr::ARP_HDR_OP_REQUEST)) { - if (verbose >= 3) { - fprintf(stdout, "RX ARP request on port %d queue %d sip:0x%08x tip:0x%08x\n", port_id, queue_id - , ntohl(arp->m_arp_sip) - , ntohl(arp->m_arp_tip)); - } + int tries = 0; + + do { + cnt = rte_eth_rx_burst(port_id, queue_id, rx_pkts, sizeof(rx_pkts)/sizeof(rx_pkts[0])); + tries++; + + for (i = 0; i < cnt; i++) { + rte_mbuf_t * m = rx_pkts[i]; + int pkt_size = rte_pktmbuf_pkt_len(m); + uint8_t *p = rte_pktmbuf_mtod(m, uint8_t *); + ArpHdr *arp; + CPretestPortInfo *port = &m_port_info[port_id]; + if (is_arp(p, pkt_size, arp)) { + m_port_info[port_id].m_stats.m_rx_arp++; + if (arp->m_arp_op == htons(ArpHdr::ARP_HDR_OP_REQUEST)) { + if (verbose >= 3) { + fprintf(stdout, "RX ARP request on port %d queue %d sip:0x%08x tip:0x%08x\n", port_id, queue_id + , ntohl(arp->m_arp_sip) + , ntohl(arp->m_arp_tip)); + } // is this request for our IP? if (ntohl(arp->m_arp_tip) == port->m_ip) { // If our request(i.e. we are connected in loopback) @@ -137,23 +146,24 @@ int CPretest::handle_rx(int port_id, int queue_id) { } else { // ARP request not to our IP. At the moment, we ignore this. } - } else { - if (arp->m_arp_op == htons(ArpHdr::ARP_HDR_OP_REPLY)) { - if (verbose >= 3) { - fprintf(stdout, "RX ARP response on port %d queue %d sip:0x%08x tip:0x%08x\n", port_id, queue_id - , ntohl(arp->m_arp_sip) - , ntohl(arp->m_arp_tip)); - } - // If this is response to our request, update our tables - if (port->m_def_gw == ntohl(arp->m_arp_sip)) { - port->set_dst_mac((uint8_t *)&arp->m_arp_sha); + } else { + if (arp->m_arp_op == htons(ArpHdr::ARP_HDR_OP_REPLY)) { + if (verbose >= 3) { + fprintf(stdout, "RX ARP response on port %d queue %d sip:0x%08x tip:0x%08x\n", port_id, queue_id + , ntohl(arp->m_arp_sip) + , ntohl(arp->m_arp_tip)); + } + // If this is response to our request, update our tables + if (port->m_def_gw == ntohl(arp->m_arp_sip)) { + port->set_dst_mac((uint8_t *)&arp->m_arp_sha); + } } } } + rte_pktmbuf_free(m); } + } while ((cnt != 0) && (tries < 1000)); - rte_pktmbuf_free(m); - } return 0; } @@ -242,6 +252,8 @@ void CPretest::send_arp_req(uint16_t port_id, bool is_grat) { if (num_sent < 1) { fprintf(stderr, "Failed sending ARP to port:%d\n", port_id); exit(1); + } else { + m_port_info[port_id].m_stats.m_tx_arp++; } } diff --git a/src/pre_test.h b/src/pre_test.h index 7bbeb40d..ad7608a6 100644 --- a/src/pre_test.h +++ b/src/pre_test.h @@ -27,6 +27,18 @@ #include "bp_sim.h" #include "trex_defs.h" +class CPreTestStats { + public: + uint32_t m_rx_arp; // how many ARP packets we received + uint32_t m_tx_arp; // how many ARP packets we sent + + public: + void clear() { + m_rx_arp = 0; + m_tx_arp = 0; + } +}; + class CPretestPortInfo { friend class CPretest; @@ -41,6 +53,7 @@ class CPretestPortInfo { CPretestPortInfo() { m_state = INIT_NEEDED; m_is_loopback = false; + m_stats.clear(); } void dump(FILE *fd); uint8_t *create_arp_req(uint16_t &pkt_size, uint8_t port, bool is_grat); @@ -55,6 +68,7 @@ class CPretestPortInfo { uint8_t m_dst_mac[6]; enum CPretestPortInfoStates m_state; bool m_is_loopback; + CPreTestStats m_stats; }; @@ -64,6 +78,7 @@ class CPretest { m_max_ports = max_ports; } bool get_mac(uint16_t port, uint32_t ip, uint8_t *mac); + CPreTestStats get_stats(uint16_t port_id); bool is_loopback(uint16_t port); void set_port_params(uint16_t port_id, const CPerPortIPCfg &port_cfg, const uint8_t *src_mac, bool resolve_needed); bool resolve_all(); diff --git a/src/stateful_rx_core.cpp b/src/stateful_rx_core.cpp new file mode 100644 index 00000000..ebc51fcb --- /dev/null +++ b/src/stateful_rx_core.cpp @@ -0,0 +1,1110 @@ +/* + Hanoh Haim + Ido Barnea + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2016 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include "bp_sim.h" +#include "flow_stat_parser.h" +#include "utl_json.h" +#include "trex_watchdog.h" +#include "pkt_gen.h" +#include "common/basic_utils.h" +#include "stateful_rx_core.h" + +const uint8_t sctp_pkt[]={ + + 0x00,0x04,0x96,0x08,0xe0,0x40, + 0x00,0x0e,0x2e,0x24,0x37,0x5f, + 0x08,0x00, + + 0x45,0x02,0x00,0x30, + 0x00,0x00,0x40,0x00, + 0xff,0x84,0xbd,0x04, + 0x9b,0xe6,0x18,0x9b, //sIP + 0xcb,0xff,0xfc,0xc2, //DIP + + 0x80,0x44,//SPORT + 0x00,0x50,//DPORT + + 0x00,0x00,0x00,0x00, //checksum + + 0x11,0x22,0x33,0x44, // magic + 0x00,0x00,0x00,0x00, //64 bit counter + 0x00,0x00,0x00,0x00, + 0x00,0x01,0xa0,0x00, //seq + 0x00,0x00,0x00,0x00, + +}; + +const uint8_t icmp_pkt[]={ + 0x00,0x04,0x96,0x08,0xe0,0x40, + 0x00,0x0e,0x2e,0x24,0x37,0x5f, + 0x08,0x00, + + 0x45,0x02,0x00,0x30, + 0x00,0x00,0x40,0x00, + 0xff,0x01,0xbd,0x04, + 0x9b,0xe6,0x18,0x9b, //SIP + 0xcb,0xff,0xfc,0xc2, //DIP + + 0x08, 0x00, + 0x01, 0x02, //checksum + 0xaa, 0xbb, // id + 0x00, 0x00, // Sequence number + + 0x11,0x22,0x33,0x44, // magic + 0x00,0x00,0x00,0x00, //64 bit counter + 0x00,0x00,0x00,0x00, + 0x00,0x01,0xa0,0x00, //seq + 0x00,0x00,0x00,0x00, + +}; + + +void CLatencyPktInfo::Create(class CLatencyPktMode *m_l_pkt_info){ + uint8_t pkt_size = m_l_pkt_info->getPacketLen(); + + m_packet = new CCapPktRaw( pkt_size); + m_packet->pkt_cnt=0; + m_packet->time_sec=0; + m_packet->time_nsec=0; + memcpy(m_packet->raw, m_l_pkt_info->getPacketData(), pkt_size); + m_packet->pkt_len=pkt_size; + + m_pkt_indication.m_packet =m_packet; + + m_pkt_indication.m_ether = (EthernetHeader *)m_packet->raw; + m_pkt_indication.l3.m_ipv4=(IPHeader *)(m_packet->raw+14); + m_pkt_indication.m_is_ipv6 = false; + m_pkt_indication.l4.m_icmp=(ICMPHeader *)m_packet->raw+14+20; + m_pkt_indication.m_payload=(uint8_t *)m_packet->raw+14+20+16; + m_pkt_indication.m_payload_len=0; + m_pkt_indication.m_packet_padding=4; + + + m_pkt_indication.m_ether_offset =0; + m_pkt_indication.m_ip_offset =14; + m_pkt_indication.m_udp_tcp_offset = 34; + m_pkt_indication.m_payload_offset = 34+8; + + CPacketDescriptor * lpd=&m_pkt_indication.m_desc; + lpd->Clear(); + lpd->SetInitSide(true); + lpd->SetSwapTuple(false); + lpd->SetIsValidPkt(true); + lpd->SetIsIcmp(true); + lpd->SetIsLastPkt(true); + m_pkt_info.Create(&m_pkt_indication); + + memset(&m_dummy_node,0,sizeof(m_dummy_node)); + + m_dummy_node.set_socket_id( CGlobalInfo::m_socket.port_to_socket(0) ); + + m_dummy_node.m_time =0.1; + m_dummy_node.m_pkt_info = &m_pkt_info; + m_dummy_node.m_dest_ip = 0; + m_dummy_node.m_src_ip = 0; + m_dummy_node.m_src_port = 0x11; + m_dummy_node.m_flow_id =0; + m_dummy_node.m_flags =CGenNode::NODE_FLAGS_LATENCY; + +} + +rte_mbuf_t * CLatencyPktInfo::generate_pkt(int port_id,uint32_t extern_ip){ + bool is_client_to_server=(port_id%2==0)?true:false; + + int dual_port_index=(port_id>>1); + uint32_t c=m_client_ip.v4; + uint32_t s=m_server_ip.v4; + if ( extern_ip ){ + c=extern_ip; + } + + if (!is_client_to_server) { + /*swap */ + uint32_t t=c; + c=s; + s=t; + } + uint32_t mask=dual_port_index*m_dual_port_mask; + if ( extern_ip==0 ){ + c+=mask; + } + s+=mask; + m_dummy_node.m_src_ip = c; + m_dummy_node.m_dest_ip = s; + + rte_mbuf_t * m=m_pkt_info.generate_new_mbuf(&m_dummy_node); + return (m); +} + +void CLatencyPktInfo::set_ip(uint32_t src, + uint32_t dst, + uint32_t dual_port_mask){ + m_client_ip.v4=src; + m_server_ip.v4=dst; + m_dual_port_mask=dual_port_mask; +} + +void CLatencyPktInfo::Delete(){ + m_pkt_info.Delete(); + delete m_packet; +} + +void CCPortLatency::reset(){ + m_rx_seq =m_tx_seq; + m_pad = 0; + m_tx_pkt_err=0; + m_tx_pkt_ok =0; + m_ign_stats.clear(); + m_ign_stats_prev.clear(); + m_pkt_ok=0; + m_rx_check=0; + m_no_magic=0; + m_unsup_prot=0; + m_no_id=0; + m_seq_error=0; + m_length_error=0; + m_no_ipv4_option=0; + m_hist.Reset(); +} + +static uint8_t nat_is_port_can_send(uint8_t port_id){ + uint8_t client_index = (port_id %2); + return (client_index ==0 ?1:0); +} + +bool CCPortLatency::Create(CLatencyManager * parent, + uint8_t id, + uint16_t payload_offset, + uint16_t l4_offset, + uint16_t pkt_size, + CCPortLatency * rx_port){ + m_parent = parent; + m_id = id; + m_tx_seq =0x12345678; + m_icmp_tx_seq = 1; + m_icmp_rx_seq = 0; + m_l4_offset = l4_offset; + m_payload_offset = payload_offset; + m_pkt_size = pkt_size; + m_rx_port = rx_port; + m_nat_can_send = nat_is_port_can_send(m_id); + m_nat_learn = m_nat_can_send; + m_nat_external_ip=0; + + m_hist.Create(); + reset(); + return (true); +} + +void CCPortLatency::Delete(){ + m_hist.Delete(); +} + +void CCPortLatency::update_packet(rte_mbuf_t * m, int port_id){ + uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); + bool is_client_to_server=(port_id%2==0)?true:false; + + /* update mac addr dest/src 12 bytes */ + memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(m_id),12); + + latency_header * h=(latency_header *)(p+m_payload_offset); + h->magic = LATENCY_MAGIC | m_id ; + h->time_stamp = os_get_hr_tick_64(); + h->seq = m_tx_seq; + m_tx_seq++; + + CLatencyPktMode *c_l_pkt_mode = m_parent->c_l_pkt_mode; + c_l_pkt_mode->update_pkt(p + m_l4_offset, is_client_to_server, m_pkt_size - m_l4_offset, &m_icmp_tx_seq); +} + + +void CCPortLatency::DumpShortHeader(FILE *fd){ + fprintf(fd," if| tx_ok , rx_ok , rx check ,error, latency (usec) , Jitter max window \n"); + fprintf(fd," | , , , , average , max , (usec) \n"); + fprintf(fd," ---------------------------------------------------------------------------------------------------------------- \n"); +} + + + +std::string CCPortLatency::get_field(std::string name,float f){ + char buff[200]; + sprintf(buff,"\"%s-%d\":%.1f,",name.c_str(),m_id,f); + return (std::string(buff)); +} + + +void CCPortLatency::dump_json_v2(std::string & json ){ + char buff[200]; + sprintf(buff,"\"port-%d\": {",m_id); + json+=std::string(buff); + m_hist.dump_json("hist",json); + dump_counters_json(json); + json+="},"; +} + +void CCPortLatency::dump_json(std::string & json ){ + json += get_field("avg",m_hist.get_average_latency() ); + json += get_field("max",m_hist.get_max_latency() ); + json += get_field("c-max",m_hist.get_max_latency_last_update() ); + json += get_field("error",(float)(m_unsup_prot+m_no_magic+m_no_id+m_seq_error+m_length_error) ); + json += get_field("jitter",(float)get_jitter_usec() ); +} + + +void CCPortLatency::DumpShort(FILE *fd){ + +// m_hist.update(); <- moved to CLatencyManager::update() + fprintf(fd,"%8lu,%8lu,%10lu,%5lu,", + m_tx_pkt_ok, + m_pkt_ok, + m_rx_check, + m_unsup_prot+m_no_magic+m_no_id+m_seq_error+m_length_error+m_no_ipv4_option+m_tx_pkt_err + ); + + fprintf(fd," %8.0f ,%8.0f,%8d ", + m_hist.get_average_latency(), + m_hist.get_max_latency(), + get_jitter_usec() + ); + fprintf(fd," | "); + m_hist.DumpWinMax(fd); + +} + +#define DPL_J(f) json+=add_json(#f,f); +#define DPL_J_LAST(f) json+=add_json(#f,f,true); + +void CCPortLatency::dump_counters_json(std::string & json ){ + + json+="\"stats\" : {"; + DPL_J(m_tx_pkt_ok); + json+=add_json("tx_arp", m_ign_stats.get_tx_arp()); + json+=add_json("ipv6_n_solic", m_ign_stats.get_tx_n_solic()); + json+=add_json("ignore_bytes", m_ign_stats.get_tx_bytes()); + DPL_J(m_tx_pkt_err); + DPL_J(m_pkt_ok); + DPL_J(m_unsup_prot); + DPL_J(m_no_magic); + DPL_J(m_no_id); + DPL_J(m_seq_error); + DPL_J(m_length_error); + DPL_J(m_no_ipv4_option); + json+=add_json("m_jitter",get_jitter_usec()); + /* must be last */ + DPL_J_LAST(m_rx_check); + json+="}"; + + +} + +void CCPortLatency::DumpCounters(FILE *fd){ +#define DP_A1(f) if (f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)f) +#define DP_A2(str, f) if (f) fprintf(fd," %-40s : %llu \n", str, (unsigned long long)f) + + fprintf(fd," counter \n"); + fprintf(fd," -----------\n"); + + DP_A1(m_tx_pkt_err); + DP_A1(m_tx_pkt_ok); + DP_A1(m_pkt_ok); + DP_A1(m_unsup_prot); + DP_A1(m_no_magic); + DP_A1(m_no_id); + DP_A1(m_seq_error); + DP_A1(m_length_error); + DP_A1(m_rx_check); + DP_A1(m_no_ipv4_option); + DP_A2("tx_arp", m_ign_stats.get_tx_arp()); + DP_A2("ipv6_n_solic", m_ign_stats.get_tx_n_solic()); + DP_A2("ignore_bytes", m_ign_stats.get_tx_bytes()); + + fprintf(fd," -----------\n"); + m_hist.Dump(fd); + fprintf(fd," %-40s : %lu \n","jitter", (ulong)get_jitter_usec()); +} + +bool CCPortLatency::dump_packet(rte_mbuf_t * m){ + fprintf(stdout," %f.03 dump packet ..\n",now_sec()); + uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); + uint16_t pkt_size=rte_pktmbuf_pkt_len(m); + utl_DumpBuffer(stdout,p,pkt_size,0); + return (0); +#if 0 + if (pkt_size < ( sizeof(CRx_check_header)+14+20) ) { + assert(0); + } + CRx_check_header * lp=(CRx_check_header *)(p+pkt_size-sizeof(CRx_check_header)); + + lp->dump(stdout); + + return (0); +#endif + +} + +bool CCPortLatency::check_rx_check(rte_mbuf_t * m) { + m_rx_check++; + return (true); +} + +bool CCPortLatency::do_learn(uint32_t external_ip) { + m_nat_learn=true; + m_nat_can_send=true; + m_nat_external_ip=external_ip; + return (true); +} + +bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) { + CSimplePacketParser parser(m); + if ( !parser.Parse() ) { + m_unsup_prot++; // Unsupported protocol + return (false); + } + CLatencyPktMode *c_l_pkt_mode = m_parent->c_l_pkt_mode; + uint16_t pkt_size=rte_pktmbuf_pkt_len(m); + uint16_t vlan_offset=parser.m_vlan_offset; + uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); + + rx_p = (CRx_check_header *)0; + + bool is_lateancy_pkt = c_l_pkt_mode->IsLatencyPkt(parser.m_ipv4) & IsLatencyPkt(parser.m_l4 + c_l_pkt_mode->l4_header_len()); + + if ( ! is_lateancy_pkt) { + +#ifdef NAT_TRACE_ + printf(" %.3f RX : got packet !!! \n",now_sec() ); +#endif + + /* ipv6+rx-check */ + if ( parser.m_ipv6 ) { + /* if we have ipv6 packet */ + if (parser.m_protocol == RX_CHECK_V6_OPT_TYPE) { + if ( get_is_rx_check_mode() ){ + m_rx_check++; + rx_p=(CRx_check_header *)((uint8_t*)parser.m_ipv6 +IPv6Header::DefaultSize); + return (true); + } + + } + m_seq_error++; + return (false); + } + + uint8_t opt_len = parser.m_ipv4->getOptionLen(); + uint8_t *opt_ptr = parser.m_ipv4->getOption(); + /* Process IP option header(s) */ + while ( opt_len != 0 ) { + switch (*opt_ptr) { + case RX_CHECK_V4_OPT_TYPE: + /* rx-check option header */ + if ( ( !get_is_rx_check_mode() ) || + (opt_len < RX_CHECK_LEN) ) { + m_seq_error++; + return (false); + } + m_rx_check++; + rx_p=(CRx_check_header *)opt_ptr; + opt_len -= RX_CHECK_LEN; + opt_ptr += RX_CHECK_LEN; + break; + case CNatOption::noIPV4_OPTION: + /* NAT learn option header */ + CNatOption *lp; + if ( ( !CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION) ) || + (opt_len < CNatOption::noOPTION_LEN) ) { + m_seq_error++; + return (false); + } + lp = (CNatOption *)opt_ptr; + if ( !lp->is_valid_ipv4_magic() ) { + m_no_ipv4_option++; + return (false); + } + m_parent->get_nat_manager()->handle_packet_ipv4(lp, parser.m_ipv4, true); + opt_len -= CNatOption::noOPTION_LEN; + opt_ptr += CNatOption::noOPTION_LEN; + break; + default: + m_seq_error++; + return (false); + } // End of switch + } // End of while + + bool first; + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP) && parser.IsNatInfoPkt(first)) { + m_parent->get_nat_manager()->handle_packet_ipv4(NULL, parser.m_ipv4, first); + } + + return (true); + } // End of check for non-latency packet + // learn for latency packets. We only have one flow for latency, so translation is for it. + if ( CGlobalInfo::is_learn_mode() && (m_nat_learn ==false) ) { + do_learn(parser.m_ipv4->getSourceIp()); + } + + if ( (pkt_size-vlan_offset) != m_pkt_size ) { + m_length_error++; + return (false); + } + c_l_pkt_mode->update_recv(p + m_l4_offset + vlan_offset, &m_icmp_rx_seq, &m_icmp_tx_seq); +#ifdef LATENCY_DEBUG + c_l_pkt_mode->rcv_debug_print(p + m_l4_offset + vlan_offset); +#endif + latency_header * h=(latency_header *)(p+m_payload_offset + vlan_offset); + if ( h->seq != m_rx_seq ){ + m_seq_error++; + m_rx_seq =h->seq +1; + return (false); + }else{ + m_rx_seq++; + } + m_pkt_ok++; + uint64_t d = (os_get_hr_tick_64() - h->time_stamp ); + dsec_t ctime=ptime_convert_hr_dsec(d); + m_hist.Add(ctime); + m_jitter.calc(ctime); + return (true); +} + +void CLatencyManager::Delete(){ + m_pkt_gen.Delete(); + + if ( get_is_rx_check_mode() ) { + m_rx_check_manager.Delete(); + } + if ( CGlobalInfo::is_learn_mode() ){ + m_nat_check_manager.Delete(); + } + m_cpu_cp_u.Delete(); +} + +/* 0->1 + 1->0 + 2->3 + 3->2 +*/ +static uint8_t swap_port(uint8_t port_id){ + uint8_t offset= ((port_id>>1)<<1); + uint8_t client_index = (port_id %2); + return (offset + (client_index ^ 1)); +} + + + +bool CLatencyManager::Create(CLatencyManagerCfg * cfg){ + switch (CGlobalInfo::m_options.get_l_pkt_mode()) { + default: + case 0: + c_l_pkt_mode = (CLatencyPktModeSCTP *) new CLatencyPktModeSCTP(CGlobalInfo::m_options.get_l_pkt_mode()); + break; + case 1: + case 2: + case 3: + c_l_pkt_mode = (CLatencyPktModeICMP *) new CLatencyPktModeICMP(CGlobalInfo::m_options.get_l_pkt_mode()); + break; + } + + m_max_ports=cfg->m_max_ports; + assert (m_max_ports <= TREX_MAX_PORTS); + assert ((m_max_ports%2)==0); + m_port_mask =0xffffffff; + m_do_stop =false; + m_is_active =false; + m_pkt_gen.Create(c_l_pkt_mode); + int i; + for (i=0; im_io=cfg->m_ports[i]; + lp->m_port.Create(this, + i, + m_pkt_gen.get_payload_offset(), + m_pkt_gen.get_l4_offset(), + m_pkt_gen.get_pkt_size(),lpo ); + } + m_cps= cfg->m_cps; + if (m_cps != 0) { + m_delta_sec =(1.0/m_cps); + } else { + m_delta_sec = 0.0; + } + + if ( get_is_rx_check_mode() ) { + assert(m_rx_check_manager.Create()); + m_rx_check_manager.m_cur_time= now_sec(); + } + + + m_pkt_gen.set_ip(cfg->m_client_ip.v4,cfg->m_server_ip.v4,cfg->m_dual_port_mask); + m_cpu_cp_u.Create(&m_cpu_dp_u); + if ( CGlobalInfo::is_learn_mode() ){ + m_nat_check_manager.Create(); + } + + return (true); +} + +void CLatencyManager::send_pkt_all_ports(){ + m_start_time = os_get_hr_tick_64(); + int i; + for (i=0; im_port.can_send_packet(i%2) ){ + rte_mbuf_t * m=m_pkt_gen.generate_pkt(i,lp->m_port.external_nat_ip()); + lp->m_port.update_packet(m, i); + +#ifdef LATENCY_DEBUG + uint8_t *p = rte_pktmbuf_mtod(m, uint8_t*); + c_l_pkt_mode->send_debug_print(p + 34); +#endif + if ( lp->m_io->tx(m) == 0 ){ + lp->m_port.m_tx_pkt_ok++; + }else{ + lp->m_port.m_tx_pkt_err++; + } + + } + } + } +} + +void CLatencyManager::send_grat_arp_all_ports() { + for (int port_id = 0; port_id < m_max_ports; port_id++) { + if (! CGlobalInfo::m_options.m_ip_cfg[port_id].grat_arp_needed()) + continue; + + CLatencyManagerPerPort * lp = &m_ports[port_id]; + rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(port_id)); + assert(m); + uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, 60); // ARP packet is shorter than 60 + uint32_t sip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip(); + uint8_t *src_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src; + uint16_t vlan = CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan(); + // gratuitous ARP. Requested IP is our source. + CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, port_id); + + if (CGlobalInfo::m_options.preview.getVMode() >= 3) { + printf("Sending gratuitous ARP on port %d vlan:%d, sip:0x%08x\n", port_id, vlan, sip); + utl_DumpBuffer(stdout, p, 60, 0); + } + + if ( lp->m_io->tx(m) == 0 ) { + lp->m_port.m_ign_stats.m_tx_arp++; + lp->m_port.m_ign_stats.m_tot_bytes += 64; // mbuf size is smaller, but 64 bytes will be sent + } else { + lp->m_port.m_tx_pkt_err++; + } + } +} + +void CLatencyManager::wait_for_rx_dump(){ + rte_mbuf_t * rx_pkts[64]; + int i; + while ( true ) { + rte_pause(); + rte_pause(); + rte_pause(); + for (i=0; im_io->rx_burst(rx_pkts, 64); + if (cnt_p) { + int j; + for (j=0; jm_port.dump_packet( m); + rte_pktmbuf_free(m); + } + } /*cnt_p*/ + }/* for*/ + } +} + + +void CLatencyManager::handle_rx_pkt(CLatencyManagerPerPort * lp, + rte_mbuf_t * m){ + CRx_check_header *rxc = NULL; + + lp->m_port.check_packet(m,rxc); + if ( unlikely(rxc!=NULL) ){ + m_rx_check_manager.handle_packet(rxc); + } + + rte_pktmbuf_free(m); +} + +// In VM, we receive the RX packets in DP core, and send message to RX core with the packet +void CLatencyManager::handle_latency_pkt_msg(uint8_t thread_id, CGenNodeLatencyPktInfo * msg) { + + assert(msg->m_latency_offset==0xdead); + + uint8_t rx_port_index=(thread_id<<1)+(msg->m_dir&1); + assert( rx_port_index m_pkt); +} + + +void CLatencyManager::run_rx_queue_msgs(uint8_t thread_id, + CNodeRing * r){ + + while ( true ) { + CGenNode * node; + if ( r->Dequeue(node)!=0 ){ + break; + } + assert(node); + + CGenNodeMsgBase * msg=(CGenNodeMsgBase *)node; + + uint8_t msg_type = msg->m_msg_type; + switch (msg_type ) { + case CGenNodeMsgBase::LATENCY_PKT: + handle_latency_pkt_msg(thread_id,(CGenNodeLatencyPktInfo *) msg); + break; + default: + printf("ERROR latency-thread message type is not valid %d \n",msg_type); + assert(0); + } + + CGlobalInfo::free_node(node); + } +} + +// VM mode function. Handle messages from DP +void CLatencyManager::try_rx_queues(){ + + CMessagingManager * rx_dp = CMsgIns::Ins()->getRxDp(); + uint8_t threads=CMsgIns::Ins()->get_num_threads(); + int ti; + for (ti=0; ti<(int)threads; ti++) { + CNodeRing * r = rx_dp->getRingDpToCp(ti); + if ( !r->isEmpty() ){ + run_rx_queue_msgs((uint8_t)ti,r); + } + } +} + +void CLatencyManager::try_rx(){ + rte_mbuf_t * rx_pkts[64]; + int i; + for (i=0; im_io->rx_burst(rx_pkts, 64); + if (cnt_p) { + m_cpu_dp_u.start_work1(); + int j; + for (j=0; jm_port.reset(); + } + +} + +void CLatencyManager::tickle() { + m_monitor.tickle(); +} + +void CLatencyManager::start(int iter, bool activate_watchdog) { + m_do_stop =false; + m_is_active =false; + int cnt=0; + + double n_time; + CGenNode * node = new CGenNode(); + node->m_type = CGenNode::FLOW_SYNC; /* general stuff */ + node->m_time = now_sec()+0.007; + m_p_queue.push(node); + + if (m_delta_sec > 0) { + node = new CGenNode(); + node->m_type = CGenNode::FLOW_PKT; /* latency */ + node->m_time = now_sec(); /* 1/cps rate */ + m_p_queue.push(node); + } + + if (CGlobalInfo::m_options.m_arp_ref_per > 0) { + node = new CGenNode(); + node->m_type = CGenNode::GRAT_ARP; /* gratuitous ARP */ + node->m_time = now_sec() + (double) CGlobalInfo::m_options.m_arp_ref_per; + m_p_queue.push(node); + } + + bool do_try_rx_queue = CGlobalInfo::m_options.preview.get_vm_one_queue_enable() ? true : false; + + if (activate_watchdog) { + m_monitor.create("STF RX CORE", 1); + TrexWatchDog::getInstance().register_monitor(&m_monitor); + } + + while ( !m_p_queue.empty() ) { + node = m_p_queue.top(); + n_time = node->m_time; + + /* wait for event */ + while ( true ) { + double dt = now_sec() - n_time ; + if (dt> (0.0)) { + break; + } + if (do_try_rx_queue){ + try_rx_queues(); + } + try_rx(); + rte_pause(); + } + + switch (node->m_type) { + case CGenNode::FLOW_SYNC: + + tickle(); + + if ( CGlobalInfo::is_learn_mode() ) { + m_nat_check_manager.handle_aging(); + } + + m_p_queue.pop(); + node->m_time += SYNC_TIME_OUT; + m_p_queue.push(node); + + break; + case CGenNode::FLOW_PKT: + m_cpu_dp_u.start_work1(); + send_pkt_all_ports(); + m_p_queue.pop(); + node->m_time += m_delta_sec; + m_p_queue.push(node); + m_cpu_dp_u.commit1(); + break; + + case CGenNode::GRAT_ARP: + m_cpu_dp_u.start_work1(); + send_grat_arp_all_ports(); + m_p_queue.pop(); + node->m_time += (double)CGlobalInfo::m_options.m_arp_ref_per; + m_p_queue.push(node); + m_cpu_dp_u.commit1(); + break; + } + + /* this will be called every sync which is 1msec */ + if ( m_do_stop ) { + break; + } + if ( iter>0 ){ + if ( ( cnt>iter) ){ + printf("stop due iter %d\n",iter); + break; + } + } + cnt++; + } + + /* free all nodes in the queue */ + while (!m_p_queue.empty()) { + node = m_p_queue.top(); + m_p_queue.pop(); + delete node; + } + + printf(" latency daemon has stopped\n"); + if ( get_is_rx_check_mode() ) { + m_rx_check_manager.tw_drain(); + } + + /* disable the monitor */ + if (activate_watchdog) { + m_monitor.disable(); + } + +} + +void CLatencyManager::stop(){ + m_do_stop =true; +} + +bool CLatencyManager::is_active(){ + return (m_is_active); +} + +// return the statistics we want to ignore for port port_id +// stat - hold values we return. +// if get_diff is true, return diff from last read. Else return total. +void CLatencyManager::get_ignore_stats(int port_id, CRXCoreIgnoreStat &stat, bool get_diff) { + CLatencyManagerPerPort * lp = &m_ports[port_id]; + CRXCoreIgnoreStat temp; + temp = lp->m_port.m_ign_stats; + if (get_diff) { + stat = temp - lp->m_port.m_ign_stats_prev; + lp->m_port.m_ign_stats_prev = temp; + } else { + stat = lp->m_port.m_ign_stats; + } +} + +double CLatencyManager::get_max_latency(){ + double l=0.0; + int i; + for (i=0; im_port.m_hist.get_max_latency() ){ + l=lp->m_port.m_hist.get_max_latency(); + } + } + return (l); +} + +double CLatencyManager::get_avr_latency(){ + double l=0.0; + int i; + for (i=0; im_port.m_hist.get_average_latency() ){ + l=lp->m_port.m_hist.get_average_latency(); + } + } + return (l); +} + +uint64_t CLatencyManager::get_total_pkt(){ + int i; + uint64_t t=0; + for (i=0; im_port.m_tx_pkt_ok ; + } + return t; +} + +uint64_t CLatencyManager::get_total_bytes(){ + int i; + uint64_t t=0; + for (i=0; im_port.m_tx_pkt_ok* (m_pkt_gen.get_pkt_size()+4); + } + return t; + +} + + +bool CLatencyManager::is_any_error(){ + int i; + for (i=0; im_port.is_any_err() ){ + return (true); + } + } + return (false); +} + + +void CLatencyManager::dump_json(std::string & json ){ + json="{\"name\":\"trex-latecny\",\"type\":0,\"data\":{"; + int i; + for (i=0; im_port.dump_json(json); + } + + json+="\"unknown\":0}}" ; + +} + +void CLatencyManager::dump_json_v2(std::string & json ){ + json="{\"name\":\"trex-latecny-v2\",\"type\":0,\"data\":{"; + json+=add_json("cpu_util",m_cpu_cp_u.GetVal()); + + int i; + for (i=0; im_port.dump_json_v2(json); + } + + json+="\"unknown\":0}}" ; + +} + +void CLatencyManager::DumpRxCheck(FILE *fd){ + if ( get_is_rx_check_mode() ) { + fprintf(fd," rx checker : \n"); + m_rx_check_manager.DumpShort(fd); + m_rx_check_manager.Dump(fd); + } +} + +void CLatencyManager::DumpShortRxCheck(FILE *fd){ + if ( get_is_rx_check_mode() ) { + m_rx_check_manager.DumpShort(fd); + } +} + +void CLatencyManager::dump_nat_flow_table(FILE *fd) { + m_nat_check_manager.Dump(fd); +} + +void CLatencyManager::rx_check_dump_json(std::string & json){ + if ( get_is_rx_check_mode() ) { + m_rx_check_manager.dump_json(json ); + } +} + + +void CLatencyManager::update_fast(){ + m_cpu_cp_u.Update() ; +} + +void CLatencyManager::update(){ + for (int i=0; im_port.m_hist.update(); + } +} + +void CLatencyManager::DumpShort(FILE *fd){ + int i; + fprintf(fd," Cpu Utilization : %2.1f %% \n",m_cpu_cp_u.GetVal()); + CCPortLatency::DumpShortHeader(fd); + for (i=0; im_port.DumpShort(fd); + fprintf(fd,"\n"); + } + + +} + +void CLatencyManager::Dump(FILE *fd){ + int i; + fprintf(fd," cpu : %2.1f %% \n",m_cpu_cp_u.GetVal()); + for (i=0; im_port.DumpCounters(fd); + } +} + +void CLatencyManager::DumpRxCheckVerification(FILE *fd, + uint64_t total_tx_rx_check){ + if ( !get_is_rx_check_mode() ) { + fprintf(fd," rx_checker is disabled \n"); + return; + } + fprintf(fd," rx_check Tx : %llu \n", (unsigned long long)total_tx_rx_check); + fprintf(fd," rx_check Rx : %llu \n", (unsigned long long)m_rx_check_manager.getTotalRx() ); + fprintf(fd," rx_check verification :" ); + if (m_rx_check_manager.getTotalRx() == total_tx_rx_check) { + fprintf(fd," OK \n" ); + }else{ + fprintf(fd," FAIL \n" ); + } +} + +uint8_t CLatencyPktModeICMP::getPacketLen() {return sizeof(icmp_pkt);} +const uint8_t *CLatencyPktModeICMP::getPacketData() {return icmp_pkt;} +void CLatencyPktModeICMP::rcv_debug_print(uint8_t *pkt) { + ICMPHeader *m_icmp = (ICMPHeader *)pkt; + printf ("received latency ICMP packet code:%d seq:%x\n" + , m_icmp->getType(), m_icmp->getSeqNum()); +}; + +void CLatencyPktModeICMP::send_debug_print(uint8_t *pkt) { + ICMPHeader *m_icmp = (ICMPHeader *)pkt; + printf ("Sending latency ICMP packet code:%d seq:%x\n", m_icmp->getType(), m_icmp->getSeqNum()); +} + +void CLatencyPktModeICMP::update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq) { + ICMPHeader * m_icmp =(ICMPHeader *)(pkt); + + if (m_submode == L_PKT_SUBMODE_0_SEQ) { + m_icmp->setSeqNum(0); + } else { + m_icmp->setSeqNum(*tx_seq); + (*tx_seq)++; + } + + if ((!is_client_to_server) && (m_submode == L_PKT_SUBMODE_REPLY)) { + m_icmp->setType(0); // echo reply + } else { + m_icmp->setType(8); // echo request + } + // ICMP checksum is calculated on payload + ICMP header + m_icmp->updateCheckSum(l4_len); + +} + +bool CLatencyPktModeICMP::IsLatencyPkt(IPHeader *ip) { + if (!ip) + return false; + if (ip->getProtocol() != 0x1) + return false; + return true; +}; + +void CLatencyPktModeICMP::update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq) { + ICMPHeader *m_icmp = (ICMPHeader *)(pkt); + *r_seq = m_icmp->getSeqNum(); + // Previously, we assumed we can send for sequences smaller than r_seq. + // Actually, if the DUT (firewall) dropped an ICMP request, we should not send response for the dropped packet. + // We are only sure that we can send reqponse for the request we just got. + // This should be OK, since we send requests and responses in the same rate. + *t_seq = *r_seq; +} + + +uint8_t CLatencyPktModeSCTP::getPacketLen() {return sizeof(sctp_pkt);} +const uint8_t *CLatencyPktModeSCTP::getPacketData() {return sctp_pkt;} +void CLatencyPktModeSCTP::rcv_debug_print(uint8_t *pkt) {printf("Received latency SCTP packet\n");} +void CLatencyPktModeSCTP::send_debug_print(uint8_t *pkt) {printf("Sending latency SCTP packet\n"); + // utl_DumpBuffer(stdout,pkt-20,28,0); +} +void CLatencyPktModeSCTP::update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq) {} +bool CLatencyPktModeSCTP::IsLatencyPkt(IPHeader *ip) { + if (!ip) { + return false; + } + if (ip->getProtocol() != 0x84) { + return false; + } + return true; +}; +void CLatencyPktModeSCTP::update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq) {} diff --git a/src/stateful_rx_core.h b/src/stateful_rx_core.h new file mode 100644 index 00000000..3fa5892f --- /dev/null +++ b/src/stateful_rx_core.h @@ -0,0 +1,381 @@ +/* + Hanoh Haim + Ido Barnea + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2016 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#ifndef __STATEFUL_RX_CORE_H__ +#define __STATEFUL_RX_CORE_H__ + +#include "bp_sim.h" +#include "flow_stat.h" + +#define L_PKT_SUBMODE_NO_REPLY 1 +#define L_PKT_SUBMODE_REPLY 2 +#define L_PKT_SUBMODE_0_SEQ 3 + +class TrexWatchDog; + +class CRXCoreIgnoreStat { + friend class CCPortLatency; + friend class CLatencyManager; + public: + inline CRXCoreIgnoreStat operator- (const CRXCoreIgnoreStat &t_in) { + CRXCoreIgnoreStat t_out; + t_out.m_tx_arp = this->m_tx_arp - t_in.m_tx_arp; + t_out.m_tx_ipv6_n_solic = this->m_tx_ipv6_n_solic - t_in.m_tx_ipv6_n_solic; + t_out.m_tot_bytes = this->m_tot_bytes - t_in.m_tot_bytes; + return t_out; + } + uint64_t get_tx_bytes() {return m_tot_bytes;} + uint64_t get_tx_pkts() {return m_tx_arp + m_tx_ipv6_n_solic;} + uint64_t get_tx_arp() {return m_tx_arp;} + uint64_t get_tx_n_solic() {return m_tx_ipv6_n_solic;} + void clear() { + m_tx_arp = 0; + m_tx_ipv6_n_solic = 0; + m_tot_bytes = 0; + } + + private: + uint64_t m_tx_arp; + uint64_t m_tx_ipv6_n_solic; + uint64_t m_tot_bytes; +}; + +class CLatencyPktInfo { +public: + void Create(class CLatencyPktMode *m_l_pkt_info); + void Delete(); + void set_ip(uint32_t src, + uint32_t dst, + uint32_t dual_port_mask); + rte_mbuf_t * generate_pkt(int port_id,uint32_t extern_ip=0); + + CGenNode * getNode(){ + return (&m_dummy_node); + } + + uint16_t get_payload_offset(void){ + return ( m_pkt_indication.getFastPayloadOffset()); + } + + uint16_t get_l4_offset(void){ + return ( m_pkt_indication.getFastTcpOffset()); + } + + uint16_t get_pkt_size(void){ + return ( m_packet->pkt_len ); + } + +private: + ipaddr_t m_client_ip; + ipaddr_t m_server_ip; + uint32_t m_dual_port_mask; + CGenNode m_dummy_node; + CFlowPktInfo m_pkt_info; + CPacketIndication m_pkt_indication; + CCapPktRaw * m_packet; +}; + +#define LATENCY_MAGIC 0x12345600 + +struct latency_header { + uint64_t time_stamp; + uint32_t magic; + uint32_t seq; + + uint8_t get_id(){ + return( magic & 0xff); + } +}; + +class CLatencyManager ; + +// per port +class CCPortLatency { +public: + bool Create(CLatencyManager * parent, + uint8_t id, + uint16_t offset, + uint16_t l4_offset, + uint16_t pkt_size, + CCPortLatency * rx_port + ); + void Delete(); + void reset(); + bool can_send_packet(int direction){ + // in icmp_reply mode, can send response from server, only after we got the relevant request + // if we got request, we are sure to have NAT translation in place already. + if ((CGlobalInfo::m_options.m_l_pkt_mode == L_PKT_SUBMODE_REPLY) && (direction == 1)) { + if (m_icmp_tx_seq <= m_icmp_rx_seq) + return(true); + else + return(false); + } + + if ( !CGlobalInfo::is_learn_mode() ) { + return(true); + } + return ( m_nat_can_send ); + } + uint32_t external_nat_ip(){ + return (m_nat_external_ip); + } + void update_packet(rte_mbuf_t * m, int port_id); + bool do_learn(uint32_t external_ip); + bool check_packet(rte_mbuf_t * m, CRx_check_header * & rx_p); + bool check_rx_check(rte_mbuf_t * m); + bool dump_packet(rte_mbuf_t * m); + void DumpCounters(FILE *fd); + void dump_counters_json(std::string & json ); + void DumpShort(FILE *fd); + void dump_json(std::string & json ); + void dump_json_v2(std::string & json ); + uint32_t get_jitter_usec(void){ + return ((uint32_t)(m_jitter.get_jitter()*1000000.0)); + } + static void DumpShortHeader(FILE *fd); + + bool is_any_err(){ + if ( (m_tx_pkt_ok == m_rx_port->m_pkt_ok ) && + + ((m_unsup_prot+ + m_no_magic+ + m_no_id+ + m_seq_error+ + m_length_error+m_no_ipv4_option+m_tx_pkt_err)==0) ) { + return (false); + } + return (true); + } + + uint16_t get_icmp_tx_seq() {return m_icmp_tx_seq;} + uint16_t get_icmp_rx_seq() {return m_icmp_rx_seq;} + + // Check if packet contains latency data + static inline bool IsLatencyPkt(uint8_t *p) { + if (! p) + return false; + + latency_header * h=(latency_header *)(p); + if ( (h->magic & 0xffffff00) != LATENCY_MAGIC ){ + return false; + } + + return true; + } + +private: + std::string get_field(std::string name,float f); + + +private: + CLatencyManager * m_parent; + CCPortLatency * m_rx_port; /* corespond rx port */ + bool m_nat_learn; + bool m_nat_can_send; + uint32_t m_nat_external_ip; + uint32_t m_tx_seq; + uint32_t m_rx_seq; + uint8_t m_pad; + uint8_t m_id; + uint16_t m_payload_offset; + uint16_t m_l4_offset; + uint16_t m_pkt_size; + // following two variables are for the latency ICMP reply mode. + // if we want to pass through firewall, we want to send reply only after we got request with same seq num + // ICMP seq num of next packet we will transmit + uint16_t m_icmp_tx_seq; + // ICMP seq num of last request we got + uint16_t m_icmp_rx_seq; + uint16_t pad1[1]; + +public: + uint64_t m_tx_pkt_ok; + uint64_t m_tx_pkt_err; + uint64_t m_pkt_ok; + uint64_t m_unsup_prot; + uint64_t m_no_magic; + uint64_t m_no_id; + uint64_t m_seq_error; + uint64_t m_rx_check; + uint64_t m_no_ipv4_option; + uint64_t m_length_error; + CRXCoreIgnoreStat m_ign_stats; + CRXCoreIgnoreStat m_ign_stats_prev; + CTimeHistogram m_hist; /* all window */ + CJitter m_jitter; +}; + + +class CPortLatencyHWBase { + public: + virtual int tx(rte_mbuf_t * m)=0; + virtual rte_mbuf_t * rx()=0; + virtual uint16_t rx_burst(struct rte_mbuf **rx_pkts, + uint16_t nb_pkts){ + return(0); + } +}; + + +class CLatencyManagerCfg { + public: + CLatencyManagerCfg (){ + m_max_ports=0; + m_cps=0.0; + memset(m_ports, 0, sizeof(m_ports)); + m_client_ip.v4=0x10000000; + m_server_ip.v4=0x20000000; + m_dual_port_mask=0x01000000; + } + + public: + uint32_t m_max_ports; + double m_cps;// CPS + CPortLatencyHWBase * m_ports[TREX_MAX_PORTS]; + ipaddr_t m_client_ip; + ipaddr_t m_server_ip; + uint32_t m_dual_port_mask; +}; + +class CLatencyManagerPerPort { +public: + CCPortLatency m_port; + CPortLatencyHWBase * m_io; + uint32_t m_flag; +}; + +class CLatencyPktMode { + public: + uint8_t m_submode; + CLatencyPktMode(uint8_t submode) {m_submode = submode;} + virtual uint8_t getPacketLen() = 0; + virtual const uint8_t *getPacketData() = 0; + virtual void rcv_debug_print(uint8_t *pkt) = 0; + virtual void send_debug_print(uint8_t *pkt) = 0; + virtual void update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq) = 0; + virtual bool IsLatencyPkt(IPHeader *ip) = 0; + uint8_t l4_header_len() {return 8;} + virtual void update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq) = 0; + virtual uint8_t getProtocol() = 0; + virtual ~CLatencyPktMode() {} +}; + +class CLatencyPktModeICMP: public CLatencyPktMode { + public: + CLatencyPktModeICMP(uint8_t submode) : CLatencyPktMode(submode) {} + uint8_t getPacketLen(); + const uint8_t *getPacketData(); + void rcv_debug_print(uint8_t *); + void send_debug_print(uint8_t *); + void update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq); + bool IsLatencyPkt(IPHeader *ip); + void update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq); + uint8_t getProtocol() {return 0x1;} +}; + +class CLatencyPktModeSCTP: public CLatencyPktMode { + public: + CLatencyPktModeSCTP(uint8_t submode) : CLatencyPktMode(submode) {} + uint8_t getPacketLen(); + const uint8_t *getPacketData(); + void rcv_debug_print(uint8_t *); + void send_debug_print(uint8_t *); + void update_pkt(uint8_t *pkt, bool is_client_to_server, uint16_t l4_len, uint16_t *tx_seq); + bool IsLatencyPkt(IPHeader *ip); + void update_recv(uint8_t *pkt, uint16_t *r_seq, uint16_t *t_seq); + uint8_t getProtocol() {return 0x84;} +}; + +class CLatencyManager { +public: + bool Create(CLatencyManagerCfg * cfg); + void Delete(); + void reset(); + void start(int iter, bool activate_watchdog); + void stop(); + bool is_active(); + void set_ip(uint32_t client_ip, + uint32_t server_ip, + uint32_t mask_dual_port){ + m_pkt_gen.set_ip(client_ip,server_ip,mask_dual_port); + } + void Dump(FILE *fd); // dump all + void DumpShort(FILE *fd); // dump short histogram of latency + + void DumpRxCheck(FILE *fd); // dump all + void DumpShortRxCheck(FILE *fd); // dump short histogram of latency + void dump_nat_flow_table(FILE *fd); + void rx_check_dump_json(std::string & json); + uint16_t get_latency_header_offset(){ + return ( m_pkt_gen.get_payload_offset() ); + } + void update(); + void update_fast(); + + void dump_json(std::string & json ); // dump to json + void dump_json_v2(std::string & json ); + void DumpRxCheckVerification(FILE *fd,uint64_t total_tx_rx_check); + void set_mask(uint32_t mask){ + m_port_mask=mask; + } + void get_ignore_stats(int port_id, CRXCoreIgnoreStat &stat, bool get_diff); + double get_max_latency(void); + double get_avr_latency(void); + bool is_any_error(); + uint64_t get_total_pkt(); + uint64_t get_total_bytes(); + CNatRxManager * get_nat_manager(){ + return ( &m_nat_check_manager ); + } + CLatencyPktMode *c_l_pkt_mode; + +private: + void tickle(); + void send_pkt_all_ports(); + void send_grat_arp_all_ports(); + void try_rx(); + void try_rx_queues(); + void run_rx_queue_msgs(uint8_t thread_id, CNodeRing * r); + void wait_for_rx_dump(); + void handle_rx_pkt(CLatencyManagerPerPort * lp, rte_mbuf_t * m); + /* messages handlers */ + void handle_latency_pkt_msg(uint8_t thread_id, CGenNodeLatencyPktInfo * msg); + + private: + pqueue_t m_p_queue; /* priorty queue */ + bool m_is_active; + CLatencyPktInfo m_pkt_gen; + CLatencyManagerPerPort m_ports[TREX_MAX_PORTS]; + double m_cps; + double m_delta_sec; + uint64_t m_start_time; // calc tick betwen sending + uint32_t m_port_mask; + uint32_t m_max_ports; + RxCheckManager m_rx_check_manager; + CNatRxManager m_nat_check_manager; + CCpuUtlDp m_cpu_dp_u; + CCpuUtlCp m_cpu_cp_u; + TrexMonitor m_monitor; + + volatile bool m_do_stop __rte_cache_aligned ; +}; + +#endif diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp index e61fb448..d162c5b3 100644 --- a/src/stateless/rx/trex_stateless_rx_core.cpp +++ b/src/stateless/rx/trex_stateless_rx_core.cpp @@ -22,7 +22,7 @@ #include #include "bp_sim.h" #include "flow_stat_parser.h" -#include "latency.h" +#include "stateful_rx_core.h" #include "pal/linux/sanb_atomic.h" #include "trex_stateless_messaging.h" #include "trex_stateless_rx_core.h" diff --git a/src/stateless/rx/trex_stateless_rx_core.h b/src/stateless/rx/trex_stateless_rx_core.h index 39af8199..3f9fb6cc 100644 --- a/src/stateless/rx/trex_stateless_rx_core.h +++ b/src/stateless/rx/trex_stateless_rx_core.h @@ -21,7 +21,7 @@ #ifndef __TREX_STATELESS_RX_CORE_H__ #define __TREX_STATELESS_RX_CORE_H__ #include -#include "latency.h" +#include "stateful_rx_core.h" #include "os_time.h" #include "pal/linux/sanb_atomic.h" #include "utl_cpuu.h" diff --git a/src/test_pkt_gen.cpp b/src/test_pkt_gen.cpp deleted file mode 100644 index 502e84dc..00000000 --- a/src/test_pkt_gen.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - Ido Barnea - Cisco Systems, Inc. -*/ - -/* - Copyright (c) 2016-2016 Cisco Systems, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rx_check_header.h" -#include "test_pkt_gen.h" - -// For use in tests -char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t ttl, uint32_t ip_id, uint16_t flags - , uint16_t max_payload, int &pkt_size) { - // ASA 2 - uint8_t dst_mac[6] = {0x74, 0xa2, 0xe6, 0xd5, 0x39, 0x25}; - uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02}; - uint8_t vlan_header[4] = {0x0a, 0xbc, 0x00, 0x00}; // we set the type below according to if pkt is ipv4 or 6 - uint8_t vlan_header2[4] = {0x0a, 0xbc, 0x88, 0xa8}; - uint16_t l2_proto; - uint16_t payload_len; - - // ASA 1 - // uint8_t dst_mac[6] = {0xd4, 0x8c, 0xb5, 0xc9, 0x54, 0x2b}; - // uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x0}; - if (flags & DPF_VLAN) { - l2_proto = 0x0081; - } else { - l2_proto = htons(l3_type); - } - - uint8_t ip_header[] = { - 0x45,0x02,0x00,0x30, - 0x00,0x00,0x40,0x00, - 0xff,0x01,0xbd,0x04, - 0x10,0x0,0x0,0x1, //SIP - 0x30,0x0,0x0,0x1, //DIP - // 0x82, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // IP option. change 45 to 48 (header len) if using it. - }; - uint8_t ipv6_header[] = { - 0x60,0x00,0xff,0x30, // traffic class + flow label - 0x00,0x00,0x40,0x00, // payload len + next header + hop limit - 0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //SIP - 0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //DIP - }; - uint8_t udp_header[] = {0x11, 0x11, 0x11,0x11, 0x00, 0x6d, 0x00, 0x00}; - uint8_t udp_data[] = {0x64,0x31,0x3a,0x61, - 0x64,0x32,0x3a,0x69,0x64, - 0x32,0x30,0x3a,0xd0,0x0e, - 0xa1,0x4b,0x7b,0xbd,0xbd, - 0x16,0xc6,0xdb,0xc4,0xbb,0x43, - 0xf9,0x4b,0x51,0x68,0x33,0x72, - 0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f, - 0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3, - 0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f, - 0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39, - 0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31, - 0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d, - 0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d, - 0xe7 - }; - - uint8_t tcp_header[] = {0xab, 0xcd, 0x00, 0x80, // src, dst ports - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // seq num, ack num - 0x50, 0x00, 0xff, 0xff, // Header size, flags, window size - 0x00, 0x00, 0x00, 0x00, // checksum ,urgent pointer - }; - - uint8_t tcp_data[] = {0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5, - 0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5}; - - uint8_t icmp_header[] = { - 0x08, 0x00, - 0xb8, 0x21, //checksum - 0xaa, 0xbb, // id - 0x00, 0x01, // Sequence number - }; - uint8_t icmp_data[] = { - 0xd6, 0x6e, 0x64, 0x34, // magic - 0x6a, 0xad, 0x0f, 0x00, //64 bit counter - 0x00, 0x56, 0x34, 0x12, - 0x78, 0x56, 0x34, 0x12, 0x00, 0x00 // seq - }; - - pkt_size = 14; - - if (flags & DPF_VLAN) { - pkt_size += 4; - if (flags & DPF_QINQ) { - pkt_size += 4; - } - } - - switch(l3_type) { - case EthernetHeader::Protocol::IP: - pkt_size += sizeof(ip_header); - break; - case EthernetHeader::Protocol::IPv6: - pkt_size += sizeof(ipv6_header); - if (flags & DPF_RXCHECK) { - pkt_size += sizeof(struct CRx_check_header); - } - break; - } - - switch (l4_proto) { - case IPPROTO_ICMP: - pkt_size += sizeof(icmp_header); - payload_len = (max_payload < sizeof(icmp_data)) ? max_payload:sizeof(icmp_data); - pkt_size += payload_len; - break; - case IPPROTO_UDP: - pkt_size += sizeof(udp_header); - payload_len = (max_payload < sizeof(udp_data)) ? max_payload:sizeof(udp_data); - pkt_size += payload_len; - break; - case IPPROTO_TCP: - pkt_size += sizeof(tcp_header); - payload_len = (max_payload < sizeof(tcp_data)) ? max_payload:sizeof(tcp_data); - pkt_size += payload_len; - break; - default: - payload_len = (max_payload < sizeof(udp_data)) ? max_payload:sizeof(udp_data); - pkt_size += payload_len; - break; - } - - char *p_start = (char *)malloc(pkt_size); - assert(p_start); - char *p = p_start; - - /* set pkt data */ - memcpy(p, dst_mac, sizeof(dst_mac)); p += sizeof(dst_mac); - memcpy(p, src_mac, sizeof(src_mac)); p += sizeof(src_mac); - memcpy(p, &l2_proto, sizeof(l2_proto)); p += sizeof(l2_proto); - - if (flags & DPF_VLAN) { - if (flags & DPF_QINQ) { - memcpy(p, &vlan_header2, sizeof(vlan_header2)); p += sizeof(vlan_header2); - } - - uint16_t l3_type_htons = htons(l3_type); - memcpy(&vlan_header[2], &l3_type_htons, sizeof(l3_type)); - memcpy(p, &vlan_header, sizeof(vlan_header)); p += sizeof(vlan_header); - } - - struct IPHeader *ip = (IPHeader *)p; - struct IPv6Header *ipv6 = (IPv6Header *)p; - switch(l3_type) { - case EthernetHeader::Protocol::IP: - memcpy(p, ip_header, sizeof(ip_header)); p += sizeof(ip_header); - ip->setProtocol(l4_proto); - ip->setTotalLength(pkt_size - 14); - ip->setId(ip_id); - break; - case EthernetHeader::Protocol::IPv6: - memcpy(p, ipv6_header, sizeof(ipv6_header)); p += sizeof(ipv6_header); - if (flags & DPF_RXCHECK) { - // rx check header - ipv6->setNextHdr(RX_CHECK_V6_OPT_TYPE); - if (flags & DPF_RXCHECK) { - struct CRx_check_header *rxch = (struct CRx_check_header *)p; - p += sizeof(CRx_check_header); - rxch->m_option_type = l4_proto; - rxch->m_option_len = RX_CHECK_V6_OPT_LEN; - } - } else { - ipv6->setNextHdr(l4_proto); - } - ipv6->setPayloadLen(pkt_size - 14 - sizeof(ipv6_header)); - ipv6->setFlowLabel(ip_id); - break; - } - - - struct TCPHeader *tcp = (TCPHeader *)p; - struct ICMPHeader *icmp= (ICMPHeader *)p; - switch (l4_proto) { - case IPPROTO_ICMP: - memcpy(p, icmp_header, sizeof(icmp_header)); p += sizeof(icmp_header); - memcpy(p, icmp_data, payload_len); p += payload_len; - icmp->updateCheckSum(sizeof(icmp_header) + sizeof(icmp_data)); - break; - case IPPROTO_UDP: - memcpy(p, udp_header, sizeof(udp_header)); p += sizeof(udp_header); - memcpy(p, udp_data, payload_len); p += payload_len; - break; - case IPPROTO_TCP: - memcpy(p, tcp_header, sizeof(tcp_header)); p += sizeof(tcp_header); - memcpy(p, tcp_data, payload_len); p += payload_len; - tcp->setSynFlag(false); - // printf("Sending TCP header:"); - //tcp->dump(stdout); - break; - default: - memcpy(p, udp_data, payload_len); p += payload_len; - break; - } - - switch(l3_type) { - case EthernetHeader::Protocol::IP: - ip->setTimeToLive(ttl); - ip->updateCheckSum(); - break; - case EthernetHeader::Protocol::IPv6: - ipv6->setHopLimit(ttl); - break; - } - - return p_start; -} - -/* - * Create ARP request packet - * Parameters: - * pkt - Buffer to fill the packet in. Size should be big enough to contain the packet (60 is a good value). - * sip - Our source IP - * tip - Target IP for which we need resolution (In case of gratuitous ARP, should be equal sip). - * src_mac - Our source MAC - * vlan - VLAN tag to send the packet on. If set to 0, no vlan will be sent. - * port - Port we intended to send packet on. This is needed since we put some "magic" number with the port, so - * we can identify if we are connected in loopback, which ports are connected. - */ -void CTestPktGen::create_arp_req(uint8_t *pkt, uint32_t sip, uint32_t tip, uint8_t *src_mac, uint16_t vlan - , uint16_t port) { - uint16_t l2_proto = htons(EthernetHeader::Protocol::ARP); - - // dst MAC - memset(pkt, 0xff, ETHER_ADDR_LEN); - pkt += ETHER_ADDR_LEN; - // src MAC - memcpy(pkt, src_mac, ETHER_ADDR_LEN); - pkt += ETHER_ADDR_LEN; - - if (vlan != 0) { - uint16_t htons_vlan = htons(vlan); - uint16_t vlan_proto = htons(0x8100); - memcpy(pkt, &vlan_proto, sizeof(vlan_proto)); - pkt += 2; - memcpy(pkt, &htons_vlan, sizeof(uint16_t)); - pkt += 2; - } - - // l3 type - memcpy(pkt, &l2_proto, sizeof(l2_proto)); - pkt += 2; - - ArpHdr *arp = (ArpHdr *)pkt; - arp->m_arp_hrd = htons(ArpHdr::ARP_HDR_HRD_ETHER); // Format of hardware address - arp->m_arp_pro = htons(EthernetHeader::Protocol::IP); // Format of protocol address - arp->m_arp_hln = ETHER_ADDR_LEN; // Length of hardware address - arp->m_arp_pln = 4; // Length of protocol address - arp->m_arp_op = htons(ArpHdr::ARP_HDR_OP_REQUEST); // ARP opcode (command) - - memcpy(&arp->m_arp_sha.data, src_mac, ETHER_ADDR_LEN); // Sender MAC address - arp->m_arp_sip = htonl(sip); // Sender IP address - - uint8_t magic[5] = {0x1, 0x3, 0x5, 0x7, 0x9}; - memcpy(&arp->m_arp_tha.data, magic, 5); // Target MAC address - arp->m_arp_tha.data[5] = port; - arp->m_arp_tip = htonl(tip); -} diff --git a/src/test_pkt_gen.h b/src/test_pkt_gen.h deleted file mode 100644 index 4257c9ae..00000000 --- a/src/test_pkt_gen.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Ido Barnea - Cisco Systems, Inc. -*/ - -/* - Copyright (c) 2016-2016 Cisco Systems, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#ifndef __TEST_PKT_GEN_H__ -#define __TEST_PKT_GEN_H__ - -enum { - D_PKT_TYPE_ICMP = 1, - D_PKT_TYPE_UDP = 2, - D_PKT_TYPE_TCP = 3, - D_PKT_TYPE_9k_UDP = 4, - D_PKT_TYPE_IPV6 = 60, - D_PKT_TYPE_HW_VERIFY = 100, - D_PKT_TYPE_HW_VERIFY_RCV_ALL = 101, - D_PKT_TYPE_HW_TOGGLE_TEST = 102, -}; - -enum { - DPF_VLAN = 0x1, - DPF_QINQ = 0X2, - DPF_RXCHECK = 0x4 -}; - -class CTestPktGen { - public: - static char *create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t ttl, uint32_t ip_id, uint16_t flags - , uint16_t max_payload, int &pkt_size); - static void create_arp_req(uint8_t *pkt, uint32_t sip, uint32_t tip, uint8_t *src_mac, uint16_t vlan - , uint16_t port); -}; - -#endif -- cgit 1.2.3-korg