summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHanoh Haim <hhaim@cisco.com>2015-12-14 16:03:27 +0200
committerHanoh Haim <hhaim@cisco.com>2015-12-14 16:03:27 +0200
commita3611f0f06cb8fca0692eab5e4aafd5827fb88cc (patch)
tree3094b889a322dd4655a6b48a4630b92c81809db5 /src
parent4e0f17da4400a9db25a4919242000ec44fa03763 (diff)
parent3f94a09f66657970636a532aac9411ad6a5290ad (diff)
merge from master
Diffstat (limited to 'src')
-rwxr-xr-xsrc/bp_gtest.cpp305
-rwxr-xr-xsrc/bp_sim.cpp900
-rwxr-xr-xsrc/bp_sim.h346
-rw-r--r--src/common/Network/Packet/IcmpHeader.h89
-rw-r--r--src/common/Network/Packet/IcmpHeader.inl87
-rwxr-xr-xsrc/common/bitMan.h4
-rwxr-xr-xsrc/dpdk_lib18/librte_ether/rte_eth_ctrl.h1
-rwxr-xr-xsrc/dpdk_lib18/librte_pmd_i40e/i40e_ethdev.c20
-rwxr-xr-xsrc/dpdk_lib18/librte_pmd_i40e/i40e_fdir.c5
-rw-r--r--src/gtest/trex_stateless_gtest.cpp204
-rw-r--r--src/latency.cpp1019
-rw-r--r--src/latency.h386
-rwxr-xr-xsrc/main_dpdk.cpp238
-rwxr-xr-xsrc/platform_cfg.cpp4
-rw-r--r--src/publisher/trex_publisher.h14
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp58
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp200
-rw-r--r--src/rpc-server/commands/trex_rpc_cmds.h12
-rw-r--r--src/rpc-server/trex_rpc_cmd.cpp28
-rw-r--r--src/rpc-server/trex_rpc_cmd_api.h3
-rw-r--r--src/rpc-server/trex_rpc_cmds_table.cpp7
-rw-r--r--src/rpc-server/trex_rpc_req_resp_server.cpp54
-rw-r--r--src/rpc-server/trex_rpc_req_resp_server.h4
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp225
-rw-r--r--src/stateless/cp/trex_stateless_port.h177
-rw-r--r--src/stateless/cp/trex_stream.h5
-rw-r--r--src/stateless/cp/trex_streams_compiler.cpp163
-rw-r--r--src/stateless/cp/trex_streams_compiler.h56
-rw-r--r--src/stateless/dp/trex_stateless_dp_core.cpp2
29 files changed, 2638 insertions, 1978 deletions
diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp
index f24464e3..005801c4 100755
--- a/src/bp_gtest.cpp
+++ b/src/bp_gtest.cpp
@@ -31,6 +31,7 @@ limitations under the License.
#include "msg_manager.h"
#include <common/cgen_map.h>
#include "platform_cfg.h"
+#include "latency.h"
int test_policer(){
CPolicer policer;
@@ -623,7 +624,6 @@ TEST_F(basic, test_pcap_mode1) {
EXPECT_EQ_UINT32(1, res?1:0)<< "pass";
}
-
/* check override the low IPG */
TEST_F(basic, test_pcap_mode2) {
@@ -638,154 +638,191 @@ TEST_F(basic, test_pcap_mode2) {
EXPECT_EQ_UINT32(1, res?1:0)<< "pass";
}
+#define l_pkt_test_s_ip 0x01020304
+#define l_pkt_test_d_ip 0x05060708
-
-
-
-TEST_F(basic, latency1) {
- CLatencyPktInfo l;
- l.Create();
-
- CParserOption * po =&CGlobalInfo::m_options;
- po->preview.setVMode(3);
- po->preview.setFileWrite(true);
-
- uint8_t mac[]={0,0,0,1,0,0};
- (void)mac;
-
- CErfIF erf_vif;
- erf_vif.set_review_mode(&CGlobalInfo::m_options.preview);
-
- erf_vif.open_file("exp/sctp.erf");
-
-
- mac[0]=0;
- mac[1]=0;
- mac[2]=0;
- mac[3]=1;
- mac[4]=0;
- mac[5]=0;
-
-
- l.set_ip(0x10000000,0x20000000,0x01000000);
-
- int i;
- /* simulate 8 ports */
- for (i=0;i<8; i++) {
- rte_mbuf_t * m=l.generate_pkt(i);
- erf_vif.send_node(l.getNode());
- rte_pktmbuf_free(m);
- }
-
- erf_vif.close_file();
-
-
- l.Delete();
-
- CErfCmp cmp;
- cmp.dump=1;
-
- bool res=true;
-
- if ( cmp.compare("exp/sctp.erf","exp/sctp-ex.erf") != true ) {
- res=false;
+CLatencyPktMode *
+latency_pkt_mod_create(uint8_t l_pkt_mode) {
+ switch (l_pkt_mode) {
+ default:
+ return new CLatencyPktModeSCTP(l_pkt_mode);
+ break;
+ case L_PKT_SUBMODE_NO_REPLY:
+ case L_PKT_SUBMODE_REPLY:
+ case L_PKT_SUBMODE_0_SEQ:
+ return new CLatencyPktModeICMP(l_pkt_mode);
+ break;
}
- EXPECT_EQ_UINT32((uint32_t)res?1:0, (uint32_t)1)<< "pass";
}
-
-
-TEST_F(basic, latency2) {
- CLatencyPktInfo l;
+rte_mbuf_t *
+create_latency_test_pkt(uint8_t l_pkt_mode, uint16_t &pkt_size, uint8_t port_id, uint8_t pkt_num) {
+ rte_mbuf_t * m;
+ CLatencyPktMode *c_l_pkt_mode;
CCPortLatency port0;
- l.Create();
- port0.Create(0,0,l.get_payload_offset(),l.get_pkt_size(),0);
-
-
- uint8_t mac[]={0,0,0,1,0,0};
- (void)mac;
-
- mac[0]=0;
- mac[1]=0;
- mac[2]=0;
- mac[3]=1;
- mac[4]=0;
- mac[5]=0;
-
-
- l.set_ip(0x01000000,0x02000000,0x01000000);
-
-
- int i;
- for (i=0; i<100; i++) {
- rte_mbuf_t * m=l.generate_pkt(0);
- rte_pktmbuf_mtod(m, uint8_t*);
- //utl_DumpBuffer(stdout,p,l.get_pkt_size(),0);
-
- port0.update_packet(m);
+ CLatencyPktInfo info;
+ CLatencyManager mgr;
- rte_pktmbuf_mtod(m, uint8_t*);
- //utl_DumpBuffer(stdout,p,l.get_pkt_size(),0);
- //printf("offset is : %d \n",l.get_payload_offset());
+ c_l_pkt_mode = latency_pkt_mod_create(l_pkt_mode);
- CRx_check_header * rx_p;
- bool res=port0.check_packet(m,rx_p);
- EXPECT_EQ_UINT32((uint32_t)res?1:0, (uint32_t)1)<< "pass";
- if (!res ) {
- printf(" ERROR \n");
+ mgr.c_l_pkt_mode = c_l_pkt_mode;
+ info.Create(c_l_pkt_mode);
+ port0.Create(&mgr, 0, info.get_payload_offset(), info.get_l4_offset(), info.get_pkt_size(), 0);
+ info.set_ip(l_pkt_test_s_ip ,l_pkt_test_d_ip, 0x01000000);
+ m=info.generate_pkt(0);
+ while (pkt_num > 0) {
+ pkt_num--;
+ port0.update_packet(m, port_id);
+ }
+ pkt_size = info.get_pkt_size();
+ port0.Delete();
+ info.Delete();
+ delete c_l_pkt_mode;
+
+ return m;
+}
+
+bool
+verify_latency_pkt(uint8_t *p, uint8_t proto, uint16_t icmp_seq, uint8_t icmp_type) {
+ EthernetHeader *eth = (EthernetHeader *)p;
+ IPHeader *ip = (IPHeader *)(p + 14);
+ uint8_t srcmac[]={0,0,0,1,0,0};
+ uint8_t dstmac[]={0,0,0,1,0,0};
+ latency_header * h;
+
+ // eth
+ EXPECT_EQ_UINT32(eth->getNextProtocol(), 0x0800)<< "Failed ethernet next protocol check";
+ EXPECT_EQ_UINT32(memcmp(p, srcmac, 6), 0)<< "Failed ethernet source MAC check";
+ EXPECT_EQ_UINT32(memcmp(p, dstmac, 6), 0)<< "Failed ethernet dest MAC check";
+ // IP
+ EXPECT_EQ_UINT32(ip->getSourceIp(), l_pkt_test_s_ip)<< "Failed IP src check";
+ EXPECT_EQ_UINT32(ip->getDestIp(), l_pkt_test_d_ip)<< "Failed IP dst check";
+ EXPECT_EQ_UINT32(ip->getProtocol(), proto)<< "Failed IP protocol check";
+ EXPECT_EQ_UINT32(ip->isChecksumOK()?0:1, 0)<< "Failed IP checksum check";
+ EXPECT_EQ_UINT32(ip->getTimeToLive(), 0xff)<< "Failed IP ttl check";
+ EXPECT_EQ_UINT32(ip->getTotalLength(), 48)<< "Failed IP total length check";
+
+ // payload
+ h=(latency_header *)(p+42);
+ EXPECT_EQ_UINT32(h->magic, LATENCY_MAGIC)<< "Failed latency magic check";
+
+ if (proto == 0x84)
+ return true;
+ // ICMP
+ ICMPHeader *icmp = (ICMPHeader *)(p + 34);
+ EXPECT_EQ_UINT32(icmp->isCheckSumOk(28)?0:1, 0)<< "Failed ICMP checksum verification";
+ EXPECT_EQ_UINT32(icmp->getSeqNum(), icmp_seq)<< "Failed ICMP sequence number check";
+ EXPECT_EQ_UINT32(icmp->getType(), icmp_type)<< "Failed ICMP type check";
+ EXPECT_EQ_UINT32(icmp->getCode(), 0)<< "Failed ICMP code check";
+ EXPECT_EQ_UINT32(icmp->getId(), 0xaabb)<< "Failed ICMP ID check";
+
+ return true;
+}
+
+bool
+test_latency_pkt_rcv(rte_mbuf_t *m, uint8_t l_pkt_mode, uint8_t port_num, uint16_t num_pkt, bool exp_pkt_ok
+ , uint16_t exp_tx_seq, uint16_t exp_rx_seq) {
+ CLatencyPktMode *c_l_pkt_mode;
+ CCPortLatency port;
+ CLatencyPktInfo info;
+ CLatencyManager mgr;
+ CRx_check_header *rxc;
+ CGlobalInfo::m_options.m_l_pkt_mode = l_pkt_mode;
+
+ c_l_pkt_mode = latency_pkt_mod_create(l_pkt_mode);
+ mgr.c_l_pkt_mode = c_l_pkt_mode;
+ info.Create(c_l_pkt_mode);
+ port.Create(&mgr, 0, info.get_payload_offset(), info.get_l4_offset(), info.get_pkt_size(), 0);
+ bool pkt_ok = port.check_packet(m, rxc);
+
+ while (num_pkt > 0) {
+ num_pkt--;
+ if (port.can_send_packet(port_num)) {
+ port.update_packet(m, 0);
}
- rte_pktmbuf_free(m);
}
- port0.DumpCounters(stdout);
- EXPECT_EQ_UINT32(port0.m_pkt_ok, (uint32_t)100)<< "pass";
- port0.Delete();
- l.Delete();
+ EXPECT_EQ_UINT32(pkt_ok ?0:1, exp_pkt_ok?0:1)<< "Failed packet OK check";
+ EXPECT_EQ_UINT32(port.get_icmp_tx_seq(), exp_tx_seq)<< "Failed tx check";
+ EXPECT_EQ_UINT32(port.get_icmp_rx_seq(), exp_rx_seq)<< "Failed rx check";
+ // if packet is bad, check_packet raise the error counter
+ EXPECT_EQ_UINT32(port.m_unsup_prot, exp_pkt_ok?0:1)<< "Failed unsupported packets count";
+
+ return true;
}
-TEST_F(basic, latency3) {
- CLatencyPktInfo l;
- CCPortLatency port0;
- l.Create();
- port0.Create(0,0,l.get_payload_offset(),l.get_pkt_size(),0);
+// Testing latency packet generation
+TEST_F(basic, latency1) {
+ uint8_t *p;
+ rte_mbuf_t * m;
+ uint16_t pkt_size;
+ // SCTP packet
+ m = create_latency_test_pkt(0, pkt_size, 0, 1);
+ p=rte_pktmbuf_mtod(m, uint8_t*);
+ verify_latency_pkt(p, 0x84, 0, 0);
+ rte_pktmbuf_free(m);
- uint8_t mac[]={0,0,0,1,0,0};
- (void)mac;
+ m = create_latency_test_pkt(L_PKT_SUBMODE_NO_REPLY, pkt_size, 1, 2);
+ p=rte_pktmbuf_mtod(m, uint8_t*);
+ verify_latency_pkt(p, 0x01, 2, 8);
+ rte_pktmbuf_free(m);
+ // ICMP reply mode client side
+ m = create_latency_test_pkt(L_PKT_SUBMODE_REPLY, pkt_size, 0, 3);
+ p = rte_pktmbuf_mtod(m, uint8_t*);
+ verify_latency_pkt(p, 0x01, 3, 8);
+ rte_pktmbuf_free(m);
- mac[0]=0;
- mac[1]=0;
- mac[2]=0;
- mac[3]=1;
- mac[4]=0;
- mac[5]=0;
+ // ICMP reply mode server side
+ m = create_latency_test_pkt(L_PKT_SUBMODE_REPLY, pkt_size, 1, 4);
+ p=rte_pktmbuf_mtod(m, uint8_t*);
+ verify_latency_pkt(p, 0x01, 4, 0);
+ rte_pktmbuf_free(m);
+ m = create_latency_test_pkt(L_PKT_SUBMODE_0_SEQ, pkt_size, 1, 5);
+ p=rte_pktmbuf_mtod(m, uint8_t*);
+ verify_latency_pkt(p, 0x01, 0, 8);
+ rte_pktmbuf_free(m);
+}
- l.set_ip(0x01000000,0x02000000,0x01000000);
+// Testing latency packet receive path
+TEST_F(basic, latency2) {
+ rte_mbuf_t *m;
+ uint16_t pkt_size;
+ uint8_t port_id = 0;
+ uint8_t pkt_num = 1;
+ uint8_t l_pkt_mode;
- uint8_t *p;
- rte_mbuf_t * m=l.generate_pkt(0);
- port0.update_packet(m);
- p=rte_pktmbuf_mtod(m, uint8_t*);
- memset(p,0,l.get_pkt_size());
+ l_pkt_mode = 0;
+ m = create_latency_test_pkt(l_pkt_mode, pkt_size, port_id, pkt_num);
+ test_latency_pkt_rcv(m, l_pkt_mode, 0, 2, true, 1, 0);
- CRx_check_header * rx_p;
- bool res=port0.check_packet(m,rx_p);
- EXPECT_EQ_UINT32((uint32_t)res?0:1, (uint32_t)1)<< "pass";
- if (!res ) {
- printf(" OK \n");
- }
- rte_pktmbuf_free(m);
- EXPECT_EQ_UINT32(port0.m_unsup_prot, (uint32_t)1)<< "pass";
+ l_pkt_mode = L_PKT_SUBMODE_NO_REPLY;
+ m = create_latency_test_pkt(l_pkt_mode, pkt_size, port_id, pkt_num);
+ test_latency_pkt_rcv(m, l_pkt_mode, 1, 2, true, 3, 1);
- port0.Delete();
- l.Delete();
-}
+ // reply mode server
+ l_pkt_mode = L_PKT_SUBMODE_REPLY;
+ m = create_latency_test_pkt(l_pkt_mode, pkt_size, port_id, pkt_num);
+ test_latency_pkt_rcv(m, l_pkt_mode, 1, 2, true, 2, 1);
+ // reply mode client
+ l_pkt_mode = L_PKT_SUBMODE_REPLY;
+ m = create_latency_test_pkt(l_pkt_mode, pkt_size, port_id, pkt_num);
+ test_latency_pkt_rcv(m, l_pkt_mode, 0, 2, true, 3, 1);
+ l_pkt_mode = L_PKT_SUBMODE_0_SEQ;
+ m = create_latency_test_pkt(l_pkt_mode, pkt_size, port_id, pkt_num);
+ test_latency_pkt_rcv(m, l_pkt_mode, 0, 2, true, 0, 0);
+ // bad packet
+ m = create_latency_test_pkt(l_pkt_mode, pkt_size, port_id, pkt_num);
+ EthernetHeader *eth = (EthernetHeader *)rte_pktmbuf_mtod(m, uint8_t*);
+ eth->setNextProtocol(0x5);
+ test_latency_pkt_rcv(m, l_pkt_mode, 0, 2, false, 1, 0);
+}
class CDummyLatencyHWBase : public CPortLatencyHWBase {
public:
@@ -835,21 +872,8 @@ public:
uint8_t m_port_id;
};
-
-
-TEST_F(basic, latency4) {
-
- uint8_t mac[]={0,0,0,1,0,0};
- (void)mac;
-
- mac[0]=0;
- mac[1]=0;
- mac[2]=0;
- mac[3]=1;
- mac[4]=0;
- mac[5]=0;
-
-
+// Testing latency statistics functions
+TEST_F(basic, latency3) {
CLatencyManager mg;
CLatencyManagerCfg cfg;
CDummyLatencyHWBase dports[MAX_LATENCY_PORTS];
@@ -882,7 +906,6 @@ TEST_F(basic, latency4) {
mg.Delete();
}
-
TEST_F(basic, hist1) {
CTimeHistogram hist1;
@@ -902,8 +925,6 @@ TEST_F(basic, hist1) {
hist1.Delete();
}
-
-
TEST_F(basic, rtsp1) {
CTestBasic t1;
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index ed729c75..84dd9c56 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -20,6 +20,7 @@ limitations under the License.
*/
#include "bp_sim.h"
+#include "latency.h"
#include "utl_json.h"
#include "utl_yaml.h"
#include "msg_manager.h"
@@ -1311,7 +1312,6 @@ bool CPacketIndication::ConvertPacketToIpv6InPlace(CCapPktRaw * pkt,
return (true);
}
-
void CPacketIndication::ProcessPacket(CPacketParser *parser,
CCapPktRaw * pkt){
_ProcessPacket(parser,pkt);
@@ -1320,8 +1320,6 @@ void CPacketIndication::ProcessPacket(CPacketParser *parser,
}
}
-
-
/* process packet */
void CPacketIndication::_ProcessPacket(CPacketParser *parser,
CCapPktRaw * pkt){
@@ -4730,900 +4728,10 @@ int CErfIF::send_node(CGenNode * node){
return (0);
}
-
int CErfIF::flush_tx_queue(void){
return (0);
}
-
-
-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,
- 0x40,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,
-
-};
-
-// 20+8+20`
-
-void CLatencyPktInfo::Create(){
- m_packet = new CCapPktRaw( sizeof(sctp_pkt) );
- m_packet->pkt_cnt=0;
- m_packet->time_sec=0;
- m_packet->time_nsec=0;
- memcpy(m_packet->raw,sctp_pkt,sizeof(sctp_pkt));
- m_packet->pkt_len=sizeof(sctp_pkt);
-
- 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_udp=(UDPHeader *)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->SetIsUdp(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_serever=(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_serever) {
- /*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_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 offset,
- uint16_t pkt_size,
- CCPortLatency * rx_port){
- m_parent = parent;
- m_id = id;
- m_tx_seq =0x12345678;
- m_offset = 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){
- uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*);
- /* 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_offset);
- h->magic = LATENCY_MAGIC | m_id ;
- h->time_stamp = os_get_hr_tick_64();
- h->seq = m_tx_seq;
- m_tx_seq++;
-}
-
-
-void CCPortLatency::DumpShortHeader(FILE *fd){
-
-
- fprintf(fd," if| tx_ok , rx_ok , rx ,error, average , max , Jitter , max window \n");
- fprintf(fd," | , , check, , latency(usec),latency (usec) ,(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();
- fprintf(fd,"%8lu,%8lu,%10lu,%4lu,",
- 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_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_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 (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);
-
-
- uint16_t vlan_offset=0;
- if ( unlikely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){
- vlan_offset=4;
- }
-
- (void)vlan_offset;
-
-// utl_DumpBuffer(stdout,p,pkt_size,0);
- return (0);
-
-}
-
-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);
- }
-
- uint16_t pkt_size=rte_pktmbuf_pkt_len(m);
- /* check if CRC was extracted */
- if ( parser.getPktSize() == pkt_size-4) {
- // CRC was not extracted by driver (VM E1000 driver issue) extract it
- pkt_size=pkt_size-4;
- }
-
- uint16_t vlan_offset=parser.m_vlan_offset;
- uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*);
-
- rx_p = (CRx_check_header *)0;
-
- if ( !parser.IsLatencyPkt() ){
-
- #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() ) ||
- (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);
- opt_len -= CNatOption::noOPTION_LEN;
- opt_ptr += CNatOption::noOPTION_LEN;
- break;
- default:
- m_seq_error++;
- return (false);
- } // End of switch
- } // End of while
-
- return (true);
- } // End of check for non-latency packet
-
- 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);
- }
-
- latency_header * h=(latency_header *)(p+m_offset+vlan_offset);
-
- if ( (h->magic & 0xffffff00) != LATENCY_MAGIC ){
- m_no_magic++;
- return (false);
- }
-
- 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){
- m_max_ports=cfg->m_max_ports;
- assert (m_max_ports<=MAX_LATENCY_PORTS);
- assert ((m_max_ports%2)==0);
- m_port_mask =0xffffffff;
- m_do_stop =false;
- m_is_active =false;
- m_pkt_gen.Create();
- int i;
- for (i=0; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- CCPortLatency * lpo=&m_ports[swap_port(i)].m_port;
-
- lp->m_io=cfg->m_ports[i];
- lp->m_port.Create(this,
- i,
- m_pkt_gen.get_payload_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; i<m_max_ports; i++) {
- if ( m_port_mask & (1<<i) ){
- CLatencyManagerPerPort * lp=&m_ports[i];
- if (lp->m_port.can_send_packet() ){
- rte_mbuf_t * m=m_pkt_gen.generate_pkt(i,lp->m_port.external_nat_ip());
- lp->m_port.update_packet(m);
- if ( lp->m_io->tx(m) == 0 ){
- lp->m_port.m_tx_pkt_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; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- rte_mbuf_t * m;
- uint16_t cnt_p = lp->m_io->rx_burst(rx_pkts, 64);
- if (cnt_p) {
- int j;
- for (j=0; j<cnt_p; j++) {
- m=rx_pkts[j] ;
- lp->m_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;
- lp->m_port.check_packet(m,rxc);
- if ( unlikely(rxc!=NULL) ){
- m_rx_check_manager.handle_packet(rxc);
- }
- rte_pktmbuf_free(m);
-}
-
-void CLatencyManager::handle_latecy_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_max_ports ) ;
- CLatencyManagerPerPort * lp=&m_ports[rx_port_index];
- handle_rx_pkt(lp,(rte_mbuf_t *)msg->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_latecy_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);
- }
-}
-
-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; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- rte_mbuf_t * m;
- m_cpu_dp_u.start_work();
- /* try to read 64 packets clean up the queue */
- uint16_t cnt_p = lp->m_io->rx_burst(rx_pkts, 64);
- if (cnt_p) {
- int j;
- for (j=0; j<cnt_p; j++) {
- m=rx_pkts[j] ;
- handle_rx_pkt(lp,m);
- }
- /* commit only if there was work to do ! */
- m_cpu_dp_u.commit();
- }/* if work */
- }// all ports
-}
-
-
-void CLatencyManager::reset(){
-
- int i;
- for (i=0; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- lp->m_port.reset();
- }
-
-}
-
-void CLatencyManager::start(int iter){
- 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);
- bool do_try_rx_queue =CGlobalInfo::m_options.preview.get_vm_one_queue_enable()?true:false;
-
-
- 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:
- 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_work();
- send_pkt_all_ports();
- m_p_queue.pop();
- node->m_time += m_delta_sec;
- m_p_queue.push(node);
- m_cpu_dp_u.commit();
- 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();
- }
-
-}
-
-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; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- if ( l <lp->m_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; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- if ( l <lp->m_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; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- t+=lp->m_port.m_tx_pkt_ok ;
- }
- return t;
-}
-
-uint64_t CLatencyManager::get_total_bytes(){
- int i;
- uint64_t t=0;
- for (i=0; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- t+=lp->m_port.m_tx_pkt_ok* (m_pkt_gen.get_pkt_size()+4);
- }
- return t;
-
-}
-
-
-bool CLatencyManager::is_any_error(){
- int i;
- for (i=0; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- if ( lp->m_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; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- lp->m_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; i<m_max_ports; i++) {
- CLatencyManagerPerPort * lp=&m_ports[i];
- lp->m_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::rx_check_dump_json(std::string & json){
- if ( get_is_rx_check_mode() ) {
- m_rx_check_manager.dump_json(json );
- }
-}
-
-void CLatencyManager::update(){
- m_cpu_cp_u.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; i<m_max_ports; i++) {
- fprintf(fd," %d | ",i);
- CLatencyManagerPerPort * lp=&m_ports[i];
- lp->m_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; i<m_max_ports; i++) {
- fprintf(fd," port %d \n",i);
- fprintf(fd," -----------------\n");
- CLatencyManagerPerPort * lp=&m_ports[i];
- lp->m_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" );
- }
-}
-
-
-
void CTcpSeq::update(uint8_t *p, CFlowPktInfo *pkt_info, int16_t s_size){
TCPHeader *tcp= (TCPHeader *)(p+pkt_info->m_pkt_indication.getFastTcpOffset());
uint32_t seqnum, acknum;
@@ -6876,6 +5984,7 @@ bool CSimplePacketParser::Parse(){
case EthernetHeader::Protocol::IP :
// IPv4 packet
ipv4=(IPHeader *)(p+14);
+ m_l4 = (uint8_t *)ipv4 + ipv4->getHeaderLength();
protocol = ipv4->getProtocol();
m_option_offset = 14 + IPV4_HDR_LEN;
break;
@@ -6891,6 +6000,7 @@ bool CSimplePacketParser::Parse(){
case EthernetHeader::Protocol::IP:
// IPv4 packet
ipv4=(IPHeader *)(p+18);
+ m_l4 = (uint8_t *)ipv4 + ipv4->getHeaderLength();
protocol = ipv4->getProtocol();
m_option_offset = 18+ IPV4_HDR_LEN;
break;
@@ -6940,7 +6050,3 @@ void CGenNodeBase::free_base(){
}
-
-
-
-
diff --git a/src/bp_sim.h b/src/bp_sim.h
index b71cb3ff..da8e8780 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -37,6 +37,7 @@ limitations under the License.
#include <string>
#include <common/Network/Packet/TcpHeader.h>
#include <common/Network/Packet/UdpHeader.h>
+#include <common/Network/Packet/IcmpHeader.h>
#include <common/Network/Packet/IPHeader.h>
#include <common/Network/Packet/IPv6Header.h>
#include <common/Network/Packet/EthernetHeader.h>
@@ -749,6 +750,7 @@ public:
prefix="";
m_mac_splitter=0;
m_run_mode = RUN_MODE_INVALID;
+ m_l_pkt_mode = 0;
}
@@ -771,7 +773,7 @@ public:
uint16_t m_io_mode; //0,1,2 0 disable, 1- normal , 2 - short
uint16_t m_run_flags;
uint8_t m_mac_splitter;
- uint8_t m_pad;
+ uint8_t m_l_pkt_mode;
trex_run_mode_e m_run_mode;
@@ -828,6 +830,9 @@ public:
return ( (m_run_flags &RUN_FLAGS_RXCHECK_CONST_TS)?true:false );
}
+ inline uint8_t get_l_pkt_mode(){
+ return (m_l_pkt_mode);
+ }
void dump(FILE *fd);
};
@@ -1237,7 +1242,8 @@ static inline int get_is_rx_check_mode(){
}
static inline bool get_is_rx_filter_enable(){
- return ( ( get_is_rx_check_mode() || CGlobalInfo::is_learn_mode()) ?true:false );
+ uint32_t latency_rate=CGlobalInfo::m_options.m_latency_rate;
+ return ( ( get_is_rx_check_mode() || CGlobalInfo::is_learn_mode() || latency_rate != 0) ?true:false );
}
static inline uint16_t get_rx_check_hops() {
return (CGlobalInfo::m_options.m_rx_check_hops);
@@ -2061,11 +2067,8 @@ inline bool CFlowKey::operator ==(const CFlowKey& rhs) const{
#define IS_VALID_S 1
#define IS_VALID_E 1
-#define IS_TCP_S 2
-#define IS_TCP_E 2
-
-#define IS_UDP_S 3
-#define IS_UDP_E 3
+#define PROTO_S 3
+#define PROTO_E 2
#define IS_INIT_SIDE 4
@@ -2235,19 +2238,27 @@ public:
}
inline void SetIsTcp(bool is_valid){
- btSetMaskBit32(m_flags,IS_TCP_S,IS_TCP_E,is_valid?1:0);
+ btSetMaskBit32(m_flags,PROTO_S,PROTO_E,is_valid?1:0);
}
inline bool IsTcp(){
- return (btGetMaskBit32(m_flags,IS_TCP_S,IS_TCP_E) ? true:false);
+ return ((btGetMaskBit32(m_flags,PROTO_S,PROTO_E) == 1) ? true:false);
}
inline void SetIsUdp(bool is_valid){
- btSetMaskBit32(m_flags,IS_UDP_S,IS_UDP_E,is_valid?1:0);
+ btSetMaskBit32(m_flags,PROTO_S,PROTO_E,is_valid?2:0);
}
inline bool IsUdp(){
- return (btGetMaskBit32(m_flags,IS_UDP_S,IS_UDP_E) ? true:false);
+ return ((btGetMaskBit32(m_flags,PROTO_S,PROTO_E) == 2) ? true:false);
+ }
+
+ inline void SetIsIcmp(bool is_valid){
+ btSetMaskBit32(m_flags,PROTO_S,PROTO_E,is_valid?3:0);
+ }
+
+ inline bool IsIcmp(){
+ return ((btGetMaskBit32(m_flags,PROTO_S,PROTO_E) == 3) ? true:false);
}
inline void SetId(uint16_t _id){
@@ -2379,6 +2390,7 @@ public:
union {
TCPHeader * m_tcp;
UDPHeader * m_udp;
+ ICMPHeader * m_icmp;
} l4;
uint8_t * m_payload;
uint16_t m_payload_len;
@@ -2902,7 +2914,11 @@ inline void CFlowPktInfo::update_pkt_info(char *p,
m_udp->setDestPort(src_port);
}
}else{
- BP_ASSERT(0);
+#ifdef _DEBUG
+ if (!m_pkt_indication.m_desc.IsIcmp()) {
+ BP_ASSERT(0);
+ }
+#endif
}
}
}
@@ -3733,312 +3749,6 @@ inline void CFlowGeneratorRecPerThread::generate_flow(CNodeGenerator * gen,
node);
}
-
-
-class CLatencyPktInfo {
-public:
- void Create();
- 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_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 CSimplePacketParser {
-public:
-
- CSimplePacketParser(rte_mbuf_t * m){
- m_m=m;
- }
-
- bool Parse();
- uint8_t getTTl();
- uint16_t getPktSize();
-
-
-
- inline bool IsLatencyPkt(){
- return ( (m_protocol ==0x84 )?true:false );
- }
-
-
-public:
- IPHeader * m_ipv4;
- IPv6Header * m_ipv6;
- uint8_t m_protocol;
- uint16_t m_vlan_offset;
- uint16_t m_option_offset;
-private:
- rte_mbuf_t * m_m ;
-};
-
-
-
-class CLatencyManager ;
-// per port
-class CCPortLatency {
-public:
- bool Create(CLatencyManager * parent,
- uint8_t id,
- uint16_t offset,
- uint16_t pkt_size,
- CCPortLatency * rx_port
- );
- void Delete();
- void reset();
- bool can_send_packet(){
- 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);
-
- 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);
- }
-
-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_offset;
-
- uint16_t m_pkt_size;
- uint16_t pad1[3];
-
-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;
- 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;
- m_client_ip.v4=0x10000000;
- m_server_ip.v4=0x20000000;
- m_dual_port_mask=0x01000000;
- }
- uint32_t m_max_ports;
- double m_cps;// CPS
- CPortLatencyHWBase * m_ports[MAX_LATENCY_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 CLatencyManager {
-public:
- bool Create(CLatencyManagerCfg * cfg);
- void Delete();
-
-public:
- void reset();
- void start(int iter);
- 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);
- }
-
-public:
- 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 rx_check_dump_json(std::string & json);
- uint16_t get_latency_header_offset(){
- return ( m_pkt_gen.get_payload_offset() );
- }
- void update();
- 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 );
- }
-
-private:
- void send_pkt_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);
-
-
-private:
- /* messages handlers */
- void handle_latecy_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[MAX_LATENCY_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;
-
- volatile bool m_do_stop __rte_cache_aligned ;
-
-};
-
-
inline bool CGenNode::is_responder_pkt(){
return ( m_pkt_info->m_pkt_indication.m_desc.IsInitSide() ?false:true );
}
diff --git a/src/common/Network/Packet/IcmpHeader.h b/src/common/Network/Packet/IcmpHeader.h
new file mode 100644
index 00000000..99d89329
--- /dev/null
+++ b/src/common/Network/Packet/IcmpHeader.h
@@ -0,0 +1,89 @@
+/*
+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.
+*/
+
+#ifndef _ICMP_HEADER_H_
+#define _ICMP_HEADER_H_
+
+#include "PacketHeaderBase.h"
+#include "IPHeader.h"
+
+class ICMPHeader
+{
+
+public:
+ ICMPHeader()
+ {
+ setCode(0);
+ setType(0);
+ setSeqNum(0xDEAD);
+ setId(0xBEEF);
+ setChecksum(0);
+ }
+
+ ICMPHeader(uint8_t argType,
+ uint8_t argCode,
+ uint16_t argId,
+ uint16_t argSeqNum)
+ {
+ setType(argType);
+ setCode(argCode);
+ setId(argId);
+ setSeqNum(argSeqNum);
+ }
+
+
+ inline void setCode(uint8_t data);
+ inline uint8_t getCode();
+
+ inline void setType(uint8_t data);
+ inline uint8_t getType();
+
+ inline void setSeqNum(uint16_t data);
+ inline uint16_t getSeqNum();
+
+ inline void setId(uint16_t data);
+ inline uint16_t getId();
+
+ inline void setChecksum(uint16_t data);
+ inline uint16_t getChecksum();
+
+ inline void updateCheckSum(uint16_t len);
+ inline bool isCheckSumOk(uint16_t len);
+ inline uint16_t calcCheckSum(uint16_t len);
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Common Header Interface
+////////////////////////////////////////////////////////////////////////////////////////
+
+public:
+ inline uint8_t* getPointer (){return (uint8_t*)this;}
+ inline uint32_t getSize (){return 8;}
+
+ void dump (FILE* fd);
+
+private:
+ uint8_t myType;
+ uint8_t myCode;
+ uint16_t myChecksum;
+ uint16_t myId;
+ uint16_t mySeqNum;
+};
+
+
+#include "IcmpHeader.inl"
+
+#endif
diff --git a/src/common/Network/Packet/IcmpHeader.inl b/src/common/Network/Packet/IcmpHeader.inl
new file mode 100644
index 00000000..0e6806f8
--- /dev/null
+++ b/src/common/Network/Packet/IcmpHeader.inl
@@ -0,0 +1,87 @@
+/*
+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.
+*/
+
+inline void ICMPHeader::setCode(uint8_t argCode)
+{
+ myCode = argCode;
+}
+
+inline uint8_t ICMPHeader::getCode()
+{
+ return myCode;
+}
+
+inline void ICMPHeader::setType(uint8_t argType)
+{
+ myType = argType;
+}
+
+inline uint8_t ICMPHeader::getType()
+{
+ return myType;
+}
+
+inline void ICMPHeader::setSeqNum(uint16_t argSeqNum)
+{
+ mySeqNum = PKT_NTOHS(argSeqNum);
+}
+
+inline uint16_t ICMPHeader::getSeqNum()
+{
+ return PKT_NTOHS(mySeqNum);
+}
+
+inline void ICMPHeader::setId(uint16_t argId)
+{
+ myId = PKT_NTOHS(argId);
+}
+
+inline uint16_t ICMPHeader::getId()
+{
+ return PKT_NTOHS(myId);
+}
+
+inline void ICMPHeader::setChecksum(uint16_t argNewChecksum)
+{
+ myChecksum = PKT_NTOHS(argNewChecksum);
+}
+
+inline uint16_t ICMPHeader::getChecksum()
+{
+ return PKT_NTOHS(myChecksum);
+}
+
+inline void ICMPHeader::updateCheckSum(uint16_t len)
+{
+ setChecksum(0);// must be here
+
+ myChecksum =calcCheckSum(len);
+}
+
+inline bool ICMPHeader::isCheckSumOk(uint16_t len)
+{
+ uint16_t theChecksum= PKT_NTOHS(calcCheckSum(len));
+
+ return(theChecksum == 0);
+}
+
+// len is in bytes. Including ICMP header + data.
+inline uint16_t ICMPHeader::calcCheckSum(uint16_t len)
+{
+ uint16_t theChecksum = pkt_InetChecksum((uint8_t*)this, len);
+
+ return(theChecksum);
+}
diff --git a/src/common/bitMan.h b/src/common/bitMan.h
index ffa05598..8019b3f7 100755
--- a/src/common/bitMan.h
+++ b/src/common/bitMan.h
@@ -160,8 +160,8 @@ inline void btSetMaskBit32(unsigned int & a,
btSetMaskBit<unsigned int>(a,startbit,stopbit,newVal);
}
-/* start > stop startbit = 10 ,
- stop = 8
+/* Notice:
+ startbit should be bigger (or equal) than stopbit
count like big E
diff --git a/src/dpdk_lib18/librte_ether/rte_eth_ctrl.h b/src/dpdk_lib18/librte_ether/rte_eth_ctrl.h
index 642adb76..d9cdb379 100755
--- a/src/dpdk_lib18/librte_ether/rte_eth_ctrl.h
+++ b/src/dpdk_lib18/librte_ether/rte_eth_ctrl.h
@@ -202,6 +202,7 @@ enum rte_eth_flow_type {
struct rte_eth_ipv4_flow {
uint32_t src_ip; /**< IPv4 source address to match. */
uint32_t dst_ip; /**< IPv4 destination address to match. */
+ uint8_t l4_proto; /* IPv4 protocol to match */
};
/**
diff --git a/src/dpdk_lib18/librte_pmd_i40e/i40e_ethdev.c b/src/dpdk_lib18/librte_pmd_i40e/i40e_ethdev.c
index 9c0db84c..b0e00464 100755
--- a/src/dpdk_lib18/librte_pmd_i40e/i40e_ethdev.c
+++ b/src/dpdk_lib18/librte_pmd_i40e/i40e_ethdev.c
@@ -355,6 +355,20 @@ static inline void i40e_flex_payload_reg_init(struct i40e_hw *hw)
#define I40E_PRTQF_FD_INSET(_i, _j) (0x00250000 + ((_i) * 64 + (_j) * 32))
#define I40E_GLQF_FD_MSK(_i, _j) (0x00267200 + ((_i) * 4 + (_j) * 8))
+void dump_regs(struct i40e_hw *hw)
+{
+ int reg_nums[] = {31, 33, 34, 35, 41, 43};
+ int i;
+ uint32_t reg;
+
+ for (i =0; i < sizeof (reg_nums)/sizeof(int); i++) {
+ reg = I40E_READ_REG(hw,I40E_PRTQF_FD_INSET(reg_nums[i], 0));
+ printf("I40E_PRTQF_FD_INSET(%d, 0): 0x%08x\n", reg_nums[i], reg);
+ reg = I40E_READ_REG(hw,I40E_PRTQF_FD_INSET(reg_nums[i], 1));
+ printf("I40E_PRTQF_FD_INSET(%d, 1): 0x%08x\n", reg_nums[i], reg);
+ }
+}
+
static inline void i40e_fillter_fields_reg_init(struct i40e_hw *hw)
{
uint32_t reg;
@@ -403,6 +417,10 @@ static inline void i40e_fillter_fields_reg_init(struct i40e_hw *hw)
//printf("I40E_PRTQF_FD_INSET(34, 1) = 0x%08x\n", reg);
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(34, 1), 0x00040000);
+ // filter IP according to ttl and L4 protocol
+ I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(35, 0), 0);
+ I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(35, 1), 0x00040000);
+
reg = I40E_READ_REG(hw,I40E_PRTQF_FD_INSET(44, 0));
//printf("I40E_PRTQF_FD_INSET(44, 0) = 0x%08x\n", reg);
I40E_WRITE_REG(hw, I40E_PRTQF_FD_INSET(44, 0), 0);
@@ -420,8 +438,6 @@ static inline void i40e_fillter_fields_reg_init(struct i40e_hw *hw)
I40E_WRITE_FLUSH(hw);
}
-
-
static int
eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
struct rte_eth_dev *dev)
diff --git a/src/dpdk_lib18/librte_pmd_i40e/i40e_fdir.c b/src/dpdk_lib18/librte_pmd_i40e/i40e_fdir.c
index 98df9357..4b209e18 100755
--- a/src/dpdk_lib18/librte_pmd_i40e/i40e_fdir.c
+++ b/src/dpdk_lib18/librte_pmd_i40e/i40e_fdir.c
@@ -727,7 +727,10 @@ i40e_fdir_fill_eth_ip_head(const struct rte_eth_fdir_input *fdir_input,
*/
ip->src_addr = fdir_input->flow.ip4_flow.dst_ip;
ip->dst_addr = fdir_input->flow.ip4_flow.src_ip;
- ip->next_proto_id = next_proto[fdir_input->flow_type];
+ if (fdir_input->flow_type == RTE_ETH_FLOW_TYPE_IPV4_OTHER) {
+ ip->next_proto_id = fdir_input->flow.ip4_flow.l4_proto;
+ } else
+ ip->next_proto_id = next_proto[fdir_input->flow_type];
break;
case RTE_ETH_FLOW_TYPE_UDPV6:
case RTE_ETH_FLOW_TYPE_TCPV6:
diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp
index bc89ec54..da652599 100644
--- a/src/gtest/trex_stateless_gtest.cpp
+++ b/src/gtest/trex_stateless_gtest.cpp
@@ -30,6 +30,7 @@ limitations under the License.
#include <trex_stateless_port.h>
#include <trex_rpc_server_api.h>
#include <iostream>
+#include <vector>
class CPcapLoader {
@@ -1148,11 +1149,9 @@ TEST_F(basic_stl, basic_pause_resume0) {
// stream - clean
- TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ );
+ std::vector<TrexStreamsCompiledObj *> objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
t1.m_msg_queue.add_msg(lpStartCmd);
@@ -1212,14 +1211,9 @@ void CBBStartStopDelay2::call_after_init(CBasicStl * m_obj){
streams.push_back(stream1);
// stream - clean
-
- TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/);
-
- assert(compile.compile(streams, comp_obj) );
-
-
- /* start with different event id */
- TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(m_port_id, 1, comp_obj.clone(), 10.0 /*sec */ );
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 1, objs[0], 10.0 /*sec */ );
m_obj->m_msg_queue.add_command(m_core,lpStopCmd, 5.0); /* command in delay of 5 sec */
@@ -1265,12 +1259,9 @@ TEST_F(basic_stl, single_pkt_bb_start_stop_delay2) {
streams.push_back(stream1);
// stream - clean
-
- TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ );
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
t1.m_msg_queue.add_msg(lpStartCmd);
@@ -1346,12 +1337,9 @@ TEST_F(basic_stl, single_pkt_bb_start_stop_delay1) {
streams.push_back(stream1);
// stream - clean
-
- TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ );
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
t1.m_msg_queue.add_msg(lpStartCmd);
@@ -1400,12 +1388,10 @@ TEST_F(basic_stl, single_pkt_bb_start_stop3) {
streams.push_back(stream1);
// stream - clean
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
- TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ );
TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(port_id);
TrexStatelessDpStop * lpStopCmd1 = new TrexStatelessDpStop(port_id);
@@ -1453,14 +1439,12 @@ TEST_F(basic_stl, single_pkt_bb_start_stop2) {
streams.push_back(stream1);
// stream - clean
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
- TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ );
TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(port_id);
- TrexStatelessDpStart * lpStartCmd1 = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ );
+ TrexStatelessDpStart * lpStartCmd1 = new TrexStatelessDpStart(port_id, 0, objs[0]->clone(), 10.0 /*sec */ );
t1.m_msg_queue.add_msg(lpStartCmd);
@@ -1508,12 +1492,10 @@ TEST_F(basic_stl, single_pkt_bb_start_stop) {
streams.push_back(stream1);
// stream - clean
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
- TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpStartCmd = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ );
TrexStatelessDpStop * lpStopCmd = new TrexStatelessDpStop(port_id);
@@ -1593,14 +1575,13 @@ TEST_F(basic_stl, simple_prog4) {
streams.push_back(stream2);
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
- EXPECT_TRUE(compile.compile(streams, comp_obj) );
+ uint8_t port_id = 0;
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 0, objs[0], 20.0 /*sec */ );
- TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 20.0 );
-
- t1.m_msg = lpstart;
+ t1.m_msg = lpStartCmd;
bool res=t1.init();
@@ -1663,11 +1644,10 @@ TEST_F(basic_stl, simple_prog3) {
streams.push_back(stream2);
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
- EXPECT_TRUE(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 50.0 );
+ uint8_t port_id = 0;
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 50.0 /*sec */ );
t1.m_msg = lpstart;
@@ -1724,13 +1704,10 @@ TEST_F(basic_stl, simple_prog2) {
pcap.clone_packet_into_stream(stream2);
streams.push_back(stream2);
-
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
- EXPECT_TRUE(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10.0 );
-
+ uint8_t port_id = 0;
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
t1.m_msg = lpstart;
@@ -1787,11 +1764,10 @@ TEST_F(basic_stl, simple_prog1) {
streams.push_back(stream2);
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
- EXPECT_TRUE(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10.0 );
+ uint8_t port_id = 0;
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
t1.m_msg = lpstart;
@@ -1832,12 +1808,10 @@ TEST_F(basic_stl, single_pkt_burst1) {
streams.push_back(stream1);
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10.0 );
-
+ uint8_t port_id = 0;
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
t1.m_msg = lpstart;
@@ -1883,11 +1857,9 @@ TEST_F(basic_stl, single_pkt) {
// stream - clean
- TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(port_id, 0, comp_obj.clone(), 10.0 /*sec */ );
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
t1.m_msg = lpstart;
@@ -1939,12 +1911,11 @@ TEST_F(basic_stl, multi_pkt1) {
streams.push_back(stream2);
- // stream - clean
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10 );
+ // stream - clean
+ uint8_t port_id = 0;
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
t1.m_msg = lpstart;
@@ -2157,11 +2128,10 @@ TEST_F(basic_stl, multi_pkt2) {
// stream - clean
- TrexStreamsCompiledObj comp_obj(0,5.0);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 10 );
+ uint8_t port_id = 0;
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs, 1, 5.0));
+ TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 10.0 /*sec */ );
t1.m_msg = lpstart;
@@ -2203,11 +2173,10 @@ TEST_F(basic_stl, multi_burst1) {
streams.push_back(stream1);
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(0, 0, comp_obj.clone(), 40 );
+ uint8_t port_id = 0;
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpstart = new TrexStatelessDpStart(port_id, 0, objs[0], 40.0 /*sec */ );
t1.m_msg = lpstart;
@@ -2237,10 +2206,9 @@ TEST_F(basic_stl, compile_bad_1) {
streams.push_back(stream1);
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
std::string err_msg;
- EXPECT_FALSE(compile.compile(streams, comp_obj, &err_msg));
+ std::vector<TrexStreamsCompiledObj *>objs;
+ EXPECT_FALSE(compile.compile(0, streams, objs, 1, 1, &err_msg));
delete stream1;
@@ -2270,10 +2238,12 @@ TEST_F(basic_stl, compile_bad_2) {
streams.push_back(stream1);
streams.push_back(stream2);
- TrexStreamsCompiledObj comp_obj(0,1.0);
+ uint8_t port_id = 0;
std::string err_msg;
- EXPECT_FALSE(compile.compile(streams, comp_obj, &err_msg));
+ std::vector<TrexStreamsCompiledObj *>objs;
+ EXPECT_FALSE(compile.compile(port_id, streams, objs, 1, 1, &err_msg));
+
delete stream1;
delete stream2;
@@ -2349,10 +2319,10 @@ TEST_F(basic_stl, compile_bad_3) {
streams.push_back(stream);
/* compile */
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
std::string err_msg;
- EXPECT_FALSE(compile.compile(streams, comp_obj, &err_msg));
+ std::vector<TrexStreamsCompiledObj *>objs;
+ EXPECT_FALSE(compile.compile(0, streams, objs, 1, 1, &err_msg));
+
for (auto stream : streams) {
delete stream;
@@ -2401,11 +2371,11 @@ TEST_F(basic_stl, compile_with_warnings) {
/* compile */
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
std::string err_msg;
- EXPECT_TRUE(compile.compile(streams, comp_obj, &err_msg));
-
+ std::vector<TrexStreamsCompiledObj *>objs;
+ EXPECT_TRUE(compile.compile(0, streams, objs, 1, 1, &err_msg));
+ delete objs[0];
+
EXPECT_TRUE(compile.get_last_compile_warnings().size() == 1);
for (auto stream : streams) {
@@ -2440,20 +2410,22 @@ TEST_F(basic_stl, compile_good_stream_id_compres) {
streams.push_back(stream1);
streams.push_back(stream2);
- TrexStreamsCompiledObj comp_obj(0,1.0);
-
+ uint8_t port_id = 0;
std::string err_msg;
- EXPECT_TRUE(compile.compile(streams, comp_obj, &err_msg));
+ std::vector<TrexStreamsCompiledObj *>objs;
+ EXPECT_TRUE(compile.compile(port_id, streams, objs, 1, 1, &err_msg));
printf(" %s \n",err_msg.c_str());
- comp_obj.Dump(stdout);
+ objs[0]->Dump(stdout);
- EXPECT_EQ_UINT32(comp_obj.get_objects()[0].m_stream->m_stream_id,0);
- EXPECT_EQ_UINT32(comp_obj.get_objects()[0].m_stream->m_next_stream_id,1);
+ EXPECT_EQ_UINT32(objs[0]->get_objects()[0].m_stream->m_stream_id,0);
+ EXPECT_EQ_UINT32(objs[0]->get_objects()[0].m_stream->m_next_stream_id,1);
- EXPECT_EQ_UINT32(comp_obj.get_objects()[1].m_stream->m_stream_id,1);
- EXPECT_EQ_UINT32(comp_obj.get_objects()[1].m_stream->m_next_stream_id,0);
+ EXPECT_EQ_UINT32(objs[0]->get_objects()[1].m_stream->m_stream_id,1);
+ EXPECT_EQ_UINT32(objs[0]->get_objects()[1].m_stream->m_next_stream_id,0);
+
+ delete objs[0];
delete stream1;
delete stream2;
@@ -2515,14 +2487,12 @@ TEST_F(basic_stl, dp_stop_event) {
// stream - clean
- TrexStreamsCompiledObj comp_obj(port_id, 1.0 /*mul*/);
+ std::vector<TrexStreamsCompiledObj *>objs;
+ assert(compile.compile(port_id, streams, objs));
+ TrexStatelessDpStart *lpStartCmd = new TrexStatelessDpStart(port_id, 17, objs[0], 10.0 /*sec */ );
- assert(compile.compile(streams, comp_obj) );
-
- TrexStatelessDpStart * lpstart = new TrexStatelessDpStart(port_id, 17, comp_obj.clone(), 10.0 /*sec */ );
-
- t1.m_msg = lpstart;
+ t1.m_msg = lpStartCmd;
/* let me handle these */
DpToCpHandlerStopEvent handler(17);
diff --git a/src/latency.cpp b/src/latency.cpp
new file mode 100644
index 00000000..02b54f75
--- /dev/null
+++ b/src/latency.cpp
@@ -0,0 +1,1019 @@
+/*
+ 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 "latency.h"
+#include "bp_sim.h"
+#include "utl_json.h"
+#include <common/basic_utils.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_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 ,error, average , max , Jitter , max window \n");
+ fprintf(fd," | , , check, , latency(usec),latency (usec) ,(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();
+ fprintf(fd,"%8lu,%8lu,%10lu,%4lu,",
+ 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_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_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 (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);
+
+
+ uint16_t vlan_offset=0;
+ if ( unlikely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){
+ vlan_offset=4;
+ }
+
+ (void)vlan_offset;
+
+// utl_DumpBuffer(stdout,p,pkt_size,0);
+ return (0);
+
+}
+
+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);
+
+ /* check if CRC was extracted */
+ if ( parser.getPktSize() == pkt_size-4) {
+ // CRC was not extracted by driver (VM E1000 driver issue) extract it
+ pkt_size=pkt_size-4;
+ }
+
+ 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) & parser.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() ) ||
+ (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);
+ opt_len -= CNatOption::noOPTION_LEN;
+ opt_ptr += CNatOption::noOPTION_LEN;
+ break;
+ default:
+ m_seq_error++;
+ return (false);
+ } // End of switch
+ } // End of while
+
+ return (true);
+ } // End of check for non-latency packet
+ 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<=MAX_LATENCY_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; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ CCPortLatency * lpo=&m_ports[swap_port(i)].m_port;
+
+ lp->m_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; i<m_max_ports; i++) {
+ if ( m_port_mask & (1<<i) ){
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ if (lp->m_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::wait_for_rx_dump(){
+ rte_mbuf_t * rx_pkts[64];
+ int i;
+ while ( true ) {
+ rte_pause();
+ rte_pause();
+ rte_pause();
+ for (i=0; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ rte_mbuf_t * m;
+ uint16_t cnt_p = lp->m_io->rx_burst(rx_pkts, 64);
+ if (cnt_p) {
+ int j;
+ for (j=0; j<cnt_p; j++) {
+ m=rx_pkts[j] ;
+ lp->m_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);
+}
+
+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_max_ports ) ;
+ CLatencyManagerPerPort * lp=&m_ports[rx_port_index];
+ handle_rx_pkt(lp,(rte_mbuf_t *)msg->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);
+ }
+}
+
+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; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ rte_mbuf_t * m;
+ m_cpu_dp_u.start_work();
+ /* try to read 64 packets clean up the queue */
+ uint16_t cnt_p = lp->m_io->rx_burst(rx_pkts, 64);
+ if (cnt_p) {
+ int j;
+ for (j=0; j<cnt_p; j++) {
+ m=rx_pkts[j] ;
+ handle_rx_pkt(lp,m);
+ }
+ /* commit only if there was work to do ! */
+ m_cpu_dp_u.commit();
+ }/* if work */
+ }// all ports
+}
+
+
+void CLatencyManager::reset(){
+
+ int i;
+ for (i=0; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ lp->m_port.reset();
+ }
+
+}
+
+void CLatencyManager::start(int iter){
+ 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);
+ bool do_try_rx_queue =CGlobalInfo::m_options.preview.get_vm_one_queue_enable()?true:false;
+
+
+ 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:
+ 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_work();
+ send_pkt_all_ports();
+ m_p_queue.pop();
+ node->m_time += m_delta_sec;
+ m_p_queue.push(node);
+ m_cpu_dp_u.commit();
+ 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();
+ }
+
+}
+
+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; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ if ( l <lp->m_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; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ if ( l <lp->m_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; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ t+=lp->m_port.m_tx_pkt_ok ;
+ }
+ return t;
+}
+
+uint64_t CLatencyManager::get_total_bytes(){
+ int i;
+ uint64_t t=0;
+ for (i=0; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ t+=lp->m_port.m_tx_pkt_ok* (m_pkt_gen.get_pkt_size()+4);
+ }
+ return t;
+
+}
+
+
+bool CLatencyManager::is_any_error(){
+ int i;
+ for (i=0; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ if ( lp->m_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; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ lp->m_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; i<m_max_ports; i++) {
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ lp->m_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::rx_check_dump_json(std::string & json){
+ if ( get_is_rx_check_mode() ) {
+ m_rx_check_manager.dump_json(json );
+ }
+}
+
+void CLatencyManager::update(){
+ m_cpu_cp_u.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; i<m_max_ports; i++) {
+ fprintf(fd," %d | ",i);
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ lp->m_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; i<m_max_ports; i++) {
+ fprintf(fd," port %d \n",i);
+ fprintf(fd," -----------------\n");
+ CLatencyManagerPerPort * lp=&m_ports[i];
+ lp->m_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:%d\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();
+ // handle wrap around, so can_send_packet will allow us to send
+ if (*r_seq == 0)
+ *t_seq = 0;
+}
+
+
+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
new file mode 100644
index 00000000..59481a59
--- /dev/null
+++ b/src/latency.h
@@ -0,0 +1,386 @@
+#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>
+
+#define L_PKT_SUBMODE_NO_REPLY 1
+#define L_PKT_SUBMODE_REPLY 2
+#define L_PKT_SUBMODE_0_SEQ 3
+
+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 CSimplePacketParser {
+public:
+
+ CSimplePacketParser(rte_mbuf_t * m){
+ m_m=m;
+ }
+
+ bool Parse();
+ uint8_t getTTl();
+ uint16_t getPktSize();
+
+ inline bool IsLatencyPkt(uint8_t *p) {
+ latency_header * h=(latency_header *)(p);
+ if ( (h->magic & 0xffffff00) != LATENCY_MAGIC ){
+ return (false);
+ }
+
+ return true;
+ }
+
+
+public:
+ IPHeader * m_ipv4;
+ IPv6Header * m_ipv6;
+ uint8_t m_protocol;
+ uint16_t m_vlan_offset;
+ uint16_t m_option_offset;
+ uint8_t * m_l4;
+private:
+ rte_mbuf_t * m_m ;
+};
+
+
+
+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;}
+
+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;
+ 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;
+ m_client_ip.v4=0x10000000;
+ m_server_ip.v4=0x20000000;
+ m_dual_port_mask=0x01000000;
+ }
+ uint32_t m_max_ports;
+ double m_cps;// CPS
+ CPortLatencyHWBase * m_ports[MAX_LATENCY_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);
+ 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 rx_check_dump_json(std::string & json);
+ uint16_t get_latency_header_offset(){
+ return ( m_pkt_gen.get_payload_offset() );
+ }
+ void update();
+ 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 send_pkt_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);
+
+ pqueue_t m_p_queue; /* priorty queue */
+ bool m_is_active;
+ CLatencyPktInfo m_pkt_gen;
+ CLatencyManagerPerPort m_ports[MAX_LATENCY_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;
+ volatile bool m_do_stop __rte_cache_aligned ;
+};
+
+#endif
+
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index f4acb344..fc9dd00e 100755
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -51,6 +51,7 @@ limitations under the License.
#include <rte_mbuf.h>
#include <rte_random.h>
#include "bp_sim.h"
+#include "latency.h"
#include "os_time.h"
#include <common/arg/SimpleGlob.h>
#include <common/arg/SimpleOpt.h>
@@ -77,6 +78,7 @@ extern "C" {
#include "utl_term_io.h"
#include "msg_manager.h"
#include "platform_cfg.h"
+#include "latency.h"
#include <internal_api/trex_platform_api.h>
@@ -118,13 +120,10 @@ static inline int get_is_latency_thread_enable(){
return (CGlobalInfo::m_options.is_latency_enabled() ?1:0);
}
-
-
struct port_cfg_t;
class CPhyEthIF;
class CPhyEthIFStats ;
-
class CTRexExtendedDriverBase {
public:
@@ -436,12 +435,6 @@ static inline int get_min_sample_rate(void){
return ( get_ex_drv()->get_min_sample_rate());
}
-
-
-
-
-
-
#define MAX_DPDK_ARGS 40
static CPlatformYamlInfo global_platform_cfg_info;
static int global_dpdk_args_num ;
@@ -450,9 +443,6 @@ static char global_cores_str[100];
static char global_prefix_str[100];
static char global_loglevel_str[20];
-
-
-
// cores =0==1,1*2,2,3,4,5,6
// An enum for all the option types
enum { OPT_HELP,
@@ -487,6 +477,7 @@ enum { OPT_HELP,
OPT_IPV6,
OPT_LEARN,
OPT_LEARN_VERIFY,
+ OPT_L_PKT_MODE,
OPT_NO_FLOW_CONTROL,
OPT_RX_CHECK_HOPS,
OPT_MAC_FILE,
@@ -499,9 +490,6 @@ enum { OPT_HELP,
};
-
-
-
/* these are the argument types:
SO_NONE -- no argument needed
SO_REQ_SEP -- single required argument
@@ -549,6 +537,7 @@ static CSimpleOpt::SOption parser_options[] =
{ OPT_IPV6, "--ipv6", SO_NONE },
{ OPT_LEARN, "--learn", SO_NONE },
{ OPT_LEARN_VERIFY, "--learn-verify", SO_NONE },
+ { OPT_L_PKT_MODE, "--l-pkt-mode", SO_REQ_SEP },
{ OPT_NO_FLOW_CONTROL, "--no-flow-control", SO_NONE },
{ OPT_VLAN, "--vlan", SO_NONE },
{ OPT_MAC_FILE, "--mac", SO_REQ_SEP },
@@ -622,7 +611,11 @@ static int usage(){
printf(" --learn : Work in NAT environments, learn the dynamic NAT translation and ALG \n");
printf(" --learn-verify : Learn the translation, but intended for verification of the mechanism in cases that NAT does not exist \n");
printf(" \n");
-
+ printf(" --l-pkt-mode [0-3] : Set mode for sending latency packets.\n");
+ printf(" 0 (default) send SCTP packets \n");
+ printf(" 1 Send ICMP request packets \n");
+ printf(" 2 Send ICMP requests from client side, and response from server side (for working with firewall) \n");
+ printf(" 3 Send ICMP requests with sequence ID 0 from both sides \n");
printf(" -v [1-3] : verbose mode ( works only on the debug image ! ) \n");
printf(" 1 show only stats \n");
printf(" 2 run preview do not write to file \n");
@@ -685,7 +678,7 @@ static int usage(){
printf(" limitations under the License. \n");
printf(" \n");
printf(" Open Source Components / Libraries \n");
- printf(" DPDK (BSD) \n");
+ printf(" DPDK (BSD) \n");
printf(" YAML-CPP (BSD) \n");
printf(" JSONCPP (MIT) \n");
printf(" \n");
@@ -696,6 +689,7 @@ static int usage(){
printf(" User : %s \n",VERSION_USER);
printf(" Date : %s , %s \n",get_build_date(),get_build_time());
printf(" Uuid : %s \n",VERSION_UIID);
+ printf(" Git SHA : %s \n",VERSION_GIT_SHA);
return (0);
}
@@ -782,6 +776,11 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
po->preview.set_lean_and_verify_mode_enable(true);
break;
+ case OPT_L_PKT_MODE :
+ sscanf(args.OptionArg(),"%d", &tmp_data);
+ po->m_l_pkt_mode=(uint8_t)tmp_data;
+ break;
+
case OPT_REAL_TIME :
printf(" warning -r is deprecated, real time is not needed any more , it is the default \n");
po->preview.setRealTime(true);
@@ -1448,11 +1447,11 @@ void CPhyEthIF::configure(uint16_t nb_rx_queue,
/*
-rx-queue 0 - default- all traffic no SCTP
+rx-queue 0 - default- all traffic not goint to queue 1
will be drop as queue is disable
-rx-queue 1 - SCTP traffic will go to here
+rx-queue 1 - Latency measurement packets will go here
pci_reg_write(IXGBE_L34T_IMIR(0),(1<<21));
@@ -1918,8 +1917,6 @@ public:
virtual int send_node(CGenNode * node);
};
-
-
bool CCoreEthIF::Create(uint8_t core_id,
uint16_t tx_client_queue_id,
CPhyEthIF * tx_client_port,
@@ -1939,54 +1936,6 @@ bool CCoreEthIF::Create(uint8_t core_id,
return (true);
}
-bool CCoreEthIF::process_rx_pkt(pkt_dir_t dir,
- rte_mbuf_t * m){
-
- CSimplePacketParser parser(m);
- if ( !parser.Parse() ){
- return false;
- }
- bool send=false;
- if ( parser.IsLatencyPkt() ){
- send=true;
-
- }else{
- if ( get_is_rx_filter_enable() ){
- uint8_t max_ttl = 0xff - get_rx_check_hops();
- uint8_t pkt_ttl = parser.getTTl();
- if ( (pkt_ttl==max_ttl) || (pkt_ttl==(max_ttl-1) ) ) {
- send=true;
- }
- }
- }
-
-
- if (send) {
- CGenNodeLatencyPktInfo * node=(CGenNodeLatencyPktInfo * )CGlobalInfo::create_node();
- if ( node ) {
- node->m_msg_type = CGenNodeMsgBase::LATENCY_PKT;
- node->m_dir = dir;
- node->m_latency_offset = 0xdead;
- node->m_pkt = m;
- if ( m_ring_to_rx->Enqueue((CGenNode*)node)==0 ){
- }else{
- CGlobalInfo::free_node((CGenNode *)node);
- send=false;
- }
-
- #ifdef LATENCY_QUEUE_TRACE_
- printf("rx to cp --\n");
- rte_pktmbuf_dump(stdout,m, rte_pktmbuf_pkt_len(m));
- #endif
- }else{
- send=false;
- }
- }
- return (send);
-}
-
-
-
void CCoreEthIF::flush_rx_queue(void){
pkt_dir_t dir ;
bool is_latency=get_is_latency_thread_enable();
@@ -2020,7 +1969,6 @@ void CCoreEthIF::flush_rx_queue(void){
}
}
-
int CCoreEthIF::flush_tx_queue(void){
/* flush both sides */
pkt_dir_t dir ;
@@ -2040,7 +1988,6 @@ int CCoreEthIF::flush_tx_queue(void){
return (0);
}
-
void CCoreEthIF::GetCoreCounters(CVirtualIFPerSideStats *stats){
stats->Clear();
pkt_dir_t dir ;
@@ -2858,7 +2805,7 @@ private:
int create_pkt(uint8_t *pkt,int pkt_size);
int create_udp_pkt();
- int create_sctp_pkt();
+ int create_icmp_pkt();
@@ -2976,7 +2923,6 @@ int CGlobalTRex::test_send(){
int i;
//set_promisc_all(true);
- //create_sctp_pkt();
create_udp_pkt();
CRx_check_header rx_check_header;
@@ -2999,18 +2945,7 @@ int CGlobalTRex::test_send(){
//test_send_pkts(m_latency_tx_queue_id,1,2);
//test_send_pkts(m_latency_tx_queue_id,1,3);
test_send_pkts(0,1,0);
- test_send_pkts(0,1,1);
- //test_send_pkts(2,1,0);
-
-
- //test_send_pkts(0,1,1);
- //test_send_pkts(0,1,2);
- //test_send_pkts(0,1,3);
-
- /*test_send_pkts(2,1,0);
- test_send_pkts(2,1,1);
- test_send_pkts(2,1,2);
- test_send_pkts(2,1,3);*/
+ test_send_pkts(0,2,1);
/*delay(1000);
fprintf(stdout," --------------------------------\n");
@@ -3095,22 +3030,21 @@ const uint8_t udp_pkt[]={
};
-const uint8_t sctp_pkt1[]={
-
+const uint8_t icmp_pkt1[]={
0x00,0x00,0x00,0x01,0x00,0x00,
0x00,0x00,0x00,0x01,0x00,0x00,
0x08,0x00,
0x45,0x02,0x00,0x30,
0x00,0x00,0x40,0x00,
- 0x40,0x84,0xbd,0x04,
- 0x01,0x01,0x01,0x01, //sIP
- 0x02,0x02,0x02,0x02, //DIP
-
- 0x80,0x44,//SPORT
- 0x00,0x50,//DPORT
+ 0xaa,0x01,0xbd,0x04,
+ 0x9b,0xe6,0x18,0x9b, //SIP
+ 0xcb,0xff,0xfc,0xc2, //DIP
- 0x00,0x00,0x00,0x00, //checksum
+ 0x08, 0x00,
+ 0x01, 0x02, //checksum
+ 0xaa, 0xbb, // id
+ 0x00, 0x00, // Sequence number
0x11,0x22,0x33,0x44, // magic
0x00,0x00,0x00,0x00, //64 bit counter
@@ -3118,8 +3052,7 @@ const uint8_t sctp_pkt1[]={
0x00,0x01,0xa0,0x00, //seq
0x00,0x00,0x00,0x00,
-};
-
+};
@@ -3148,8 +3081,8 @@ int CGlobalTRex::create_udp_pkt(){
return (create_pkt((uint8_t*)udp_pkt,sizeof(udp_pkt)));
}
-int CGlobalTRex::create_sctp_pkt(){
- return (create_pkt((uint8_t*)sctp_pkt1,sizeof(sctp_pkt1)));
+int CGlobalTRex::create_icmp_pkt(){
+ return (create_pkt((uint8_t*)icmp_pkt1,sizeof(icmp_pkt1)));
}
@@ -3396,7 +3329,7 @@ int CGlobalTRex::ixgbe_start(void){
m_cores_to_dual_ports+1,
&m_port_cfg.m_port_conf);
- /* the latency queue for SCTP */
+ /* the latency queue for latency measurement packets */
m_latency_tx_queue_id= m_cores_to_dual_ports;
socket_id_t socket_id = CGlobalInfo::m_socket.port_to_socket((port_id_t)i);
@@ -3413,7 +3346,7 @@ int CGlobalTRex::ixgbe_start(void){
/* set the filter queue */
_if->set_rx_queue(1);
- /* sctp ring is 1 */
+ /* latency measurement ring is 1 */
_if->rx_queue_setup(1,
RTE_TEST_RX_LATENCY_DESC_DEFAULT,
socket_id,
@@ -4114,13 +4047,15 @@ int CGlobalTRex::run_in_master(){
break;
}
- m_mg.rx_check_dump_json(json );
- m_zmq_publisher.publish_json(json);
-
}/* ex checked */
}
+ if ( get_is_rx_check_mode() ) {
+ m_mg.rx_check_dump_json(json );
+ m_zmq_publisher.publish_json(json);
+ }
+
/* backward compatible */
m_mg.dump_json(json );
m_zmq_publisher.publish_json(json);
@@ -4355,6 +4290,54 @@ int CGlobalTRex::start_send_master(){
static CGlobalTRex g_trex;
+bool CCoreEthIF::process_rx_pkt(pkt_dir_t dir,
+ rte_mbuf_t * m){
+
+ CSimplePacketParser parser(m);
+ if ( !parser.Parse() ){
+ return false;
+ }
+ bool send=false;
+ CLatencyPktMode *c_l_pkt_mode = g_trex.m_mg.c_l_pkt_mode;
+ bool is_lateancy_pkt = c_l_pkt_mode->IsLatencyPkt(parser.m_ipv4) & parser.IsLatencyPkt(parser.m_l4 + c_l_pkt_mode->l4_header_len());
+
+ if (is_lateancy_pkt){
+ send=true;
+ }else{
+ if ( get_is_rx_filter_enable() ){
+ uint8_t max_ttl = 0xff - get_rx_check_hops();
+ uint8_t pkt_ttl = parser.getTTl();
+ if ( (pkt_ttl==max_ttl) || (pkt_ttl==(max_ttl-1) ) ) {
+ send=true;
+ }
+ }
+ }
+
+
+ if (send) {
+ CGenNodeLatencyPktInfo * node=(CGenNodeLatencyPktInfo * )CGlobalInfo::create_node();
+ if ( node ) {
+ node->m_msg_type = CGenNodeMsgBase::LATENCY_PKT;
+ node->m_dir = dir;
+ node->m_latency_offset = 0xdead;
+ node->m_pkt = m;
+ if ( m_ring_to_rx->Enqueue((CGenNode*)node)==0 ){
+ }else{
+ CGlobalInfo::free_node((CGenNode *)node);
+ send=false;
+ }
+
+ #ifdef LATENCY_QUEUE_TRACE_
+ printf("rx to cp --\n");
+ rte_pktmbuf_dump(stdout,m, rte_pktmbuf_pkt_len(m));
+ #endif
+ }else{
+ send=false;
+ }
+ }
+ return (send);
+}
+
TrexStateless * get_stateless_obj() {
return g_trex.m_trex_stateless;
@@ -4480,8 +4463,7 @@ int update_global_info_from_platform_file(){
CGlobalInfo::m_memory_cfg.set(cg->m_memory,mul);
CGlobalInfo::m_memory_cfg.set_number_of_dp_cors(
- CGlobalInfo::m_options.get_number_of_dp_cores_needed() );
-
+ CGlobalInfo::m_options.get_number_of_dp_cores_needed() );
return (0);
}
@@ -4740,15 +4722,19 @@ int CTRexExtendedDriverBase1G::wait_for_stable_link(){
}
int CTRexExtendedDriverBase1G::configure_drop_queue(CPhyEthIF * _if){
+ uint8_t protocol;
+ if (CGlobalInfo::m_options.m_l_pkt_mode == 0) {
+ protocol = IPPROTO_SCTP;
+ } else {
+ protocol = IPPROTO_ICMP;
+ }
+
_if->pci_reg_write( E1000_RXDCTL(0) , 0);
/* enable filter to pass packet to rx queue 1 */
-
_if->pci_reg_write( E1000_IMIR(0), 0x00020000);
-
_if->pci_reg_write( E1000_IMIREXT(0), 0x00081000);
-
- _if->pci_reg_write( E1000_TTQF(0), 0x00000084 /* protocol */
+ _if->pci_reg_write( E1000_TTQF(0), protocol
| 0x00008100 /* enable */
| 0xE0010000 /* RX queue is 1 */
);
@@ -4776,11 +4762,13 @@ int CTRexExtendedDriverBase1G::configure_rx_filter_rules(CPhyEthIF * _if){
*/
int i;
// IPv4: bytes being compared are {TTL, Protocol}
- uint16_t ff_rules_v4[4]={
+ uint16_t ff_rules_v4[6]={
(uint16_t)(0xFF06 - v4_hops),
(uint16_t)(0xFE11 - v4_hops),
(uint16_t)(0xFF11 - v4_hops),
(uint16_t)(0xFE06 - v4_hops),
+ (uint16_t)(0xFF01 - v4_hops),
+ (uint16_t)(0xFE01 - v4_hops),
} ;
// IPv6: bytes being compared are {NextHdr, HopLimit}
uint16_t ff_rules_v6[2]={
@@ -4921,24 +4909,30 @@ int CTRexExtendedDriverBase10G::configure_rx_filter_rules(CPhyEthIF * _if){
// IPv4: bytes being compared are {TTL, Protocol}
- uint16_t ff_rules_v4[4]={
+ uint16_t ff_rules_v4[6]={
(uint16_t)(0xFF11 - v4_hops),
(uint16_t)(0xFE11 - v4_hops),
(uint16_t)(0xFF06 - v4_hops),
(uint16_t)(0xFE06 - v4_hops),
+ (uint16_t)(0xFF01 - v4_hops),
+ (uint16_t)(0xFE01 - v4_hops),
} ;
// IPv6: bytes being compared are {NextHdr, HopLimit}
- uint16_t ff_rules_v6[4]={
+ uint16_t ff_rules_v6[6]={
+ (uint16_t)(0x3CFF - hops),
+ (uint16_t)(0x3CFE - hops),
(uint16_t)(0x3CFF - hops),
(uint16_t)(0x3CFE - hops),
(uint16_t)(0x3CFF - hops),
(uint16_t)(0x3CFE - hops),
} ;
- const rte_l4type ff_rules_type[4]={
+ const rte_l4type ff_rules_type[6]={
RTE_FDIR_L4TYPE_UDP,
RTE_FDIR_L4TYPE_UDP,
RTE_FDIR_L4TYPE_TCP,
- RTE_FDIR_L4TYPE_TCP
+ RTE_FDIR_L4TYPE_TCP,
+ RTE_FDIR_L4TYPE_NONE,
+ RTE_FDIR_L4TYPE_NONE
} ;
uint16_t *ff_rules;
@@ -4978,8 +4972,7 @@ int CTRexExtendedDriverBase10G::configure_rx_filter_rules(CPhyEthIF * _if){
}
int CTRexExtendedDriverBase10G::configure_drop_queue(CPhyEthIF * _if){
-
- /* enable rule 0 SCTP -> queue 1 for latency */
+ /* enable rule 0 SCTP -> queue 1 for latency */
/* 1<<21 means that queue 1 is for SCTP */
_if->pci_reg_write(IXGBE_L34T_IMIR(0),(1<<21));
@@ -4989,7 +4982,6 @@ int CTRexExtendedDriverBase10G::configure_drop_queue(CPhyEthIF * _if){
((0x0f)<<IXGBE_FTQF_5TUPLE_MASK_SHIFT)|IXGBE_FTQF_QUEUE_ENABLE);
/* disable queue zero - default all traffic will go to here and will be dropped */
-
_if->pci_reg_write( IXGBE_RXDCTL(0) , 0);
return (0);
}
@@ -5050,7 +5042,7 @@ void CTRexExtendedDriverBase40G::update_configuration(port_cfg_t * cfg){
}
-
+/* Add rule to send packets with protocol 'type', and ttl 'ttl' to rx queue 1 */
void CTRexExtendedDriverBase40G::add_rules(CPhyEthIF * _if,
enum rte_eth_flow_type type,
uint8_t ttl){
@@ -5075,7 +5067,11 @@ void CTRexExtendedDriverBase40G::add_rules(CPhyEthIF * _if,
filter.input.flow_type = type;
filter.input.ttl=ttl;
- /* any SCTP move to queue number 1 */
+ if (type == RTE_ETH_FLOW_TYPE_IPV4_OTHER) {
+ filter.input.flow.ip4_flow.l4_proto = IPPROTO_ICMP; // In this case we want filter for icmp packets
+ }
+
+ /* We want to place latency packets in queue 1 */
ret=rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR,
RTE_ETH_FILTER_ADD, (void*)&filter);
@@ -5104,7 +5100,9 @@ int CTRexExtendedDriverBase40G::configure_rx_filter_rules(CPhyEthIF * _if){
int CTRexExtendedDriverBase40G::configure_drop_queue(CPhyEthIF * _if){
- add_rules(_if,RTE_ETH_FLOW_TYPE_SCTPV4,0);
+ /* Configure queue for latency packets */
+ add_rules(_if,RTE_ETH_FLOW_TYPE_IPV4_OTHER,255);
+ add_rules(_if,RTE_ETH_FLOW_TYPE_SCTPV4,255);
return (0);
}
diff --git a/src/platform_cfg.cpp b/src/platform_cfg.cpp
index 547cc3ad..ca42aa31 100755
--- a/src/platform_cfg.cpp
+++ b/src/platform_cfg.cpp
@@ -35,8 +35,8 @@ void CPlatformMemoryYamlInfo::reset(){
m_mbuf[MBUF_64] = m_mbuf[MBUF_64]*2;
m_mbuf[MBUF_2048] = CONST_NB_MBUF_2_10G/2;
- m_mbuf[TRAFFIC_MBUF_64] = m_mbuf[MBUF_64]*2;
- m_mbuf[TRAFFIC_MBUF_2048] = CONST_NB_MBUF_2_10G*4;
+ m_mbuf[TRAFFIC_MBUF_64] = m_mbuf[MBUF_64] * 4;
+ m_mbuf[TRAFFIC_MBUF_2048] = CONST_NB_MBUF_2_10G * 8;
m_mbuf[MBUF_DP_FLOWS] = (1024*1024/2);
m_mbuf[MBUF_GLOBAL_FLOWS] =(10*1024/2);
diff --git a/src/publisher/trex_publisher.h b/src/publisher/trex_publisher.h
index 8d1be064..bd4392f7 100644
--- a/src/publisher/trex_publisher.h
+++ b/src/publisher/trex_publisher.h
@@ -39,10 +39,16 @@ public:
void publish_json(const std::string &s);
enum event_type_e {
- EVENT_PORT_STARTED = 0,
- EVENT_PORT_STOPPED = 1,
- EVENT_SERVER_STOPPED = 2,
- EVENT_PORT_FINISHED_TX = 3,
+ EVENT_PORT_STARTED = 0,
+ EVENT_PORT_STOPPED = 1,
+ EVENT_PORT_PAUSED = 2,
+ EVENT_PORT_RESUMED = 3,
+ EVENT_PORT_FINISHED_TX = 4,
+ EVENT_PORT_FORCE_ACQUIRED = 5,
+
+ EVENT_SERVER_STOPPED = 100,
+
+
};
void publish_event(event_type_e type, const Json::Value &data = Json::nullValue);
diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
index 9570aae7..a2d4c284 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
@@ -43,7 +43,7 @@ using namespace std;
trex_rpc_cmd_rc_e
TrexRpcCmdPing::_run(const Json::Value &params, Json::Value &result) {
- result["result"] = "ACK";
+ result["result"] = Json::objectValue;
return (TREX_RPC_CMD_OK);
}
@@ -198,10 +198,6 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value &params, Json::Value &result) {
}
- section["ports"][i]["owner"] = port->get_owner();
-
- section["ports"][i]["status"] = port->get_state_as_string();
-
}
return (TREX_RPC_CMD_OK);
@@ -224,7 +220,7 @@ TrexRpcCmdGetOwner::_run(const Json::Value &params, Json::Value &result) {
uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
- section["owner"] = port->get_owner();
+ section["owner"] = port->get_owner().get_name();
return (TREX_RPC_CMD_OK);
}
@@ -238,7 +234,7 @@ TrexRpcCmdAcquire::_run(const Json::Value &params, Json::Value &result) {
uint8_t port_id = parse_port(params, result);
- const string &new_owner = parse_string(params, "user", result);
+ const string &new_owner = parse_string(params, "user", result);
bool force = parse_bool(params, "force", result);
/* if not free and not you and not force - fail */
@@ -250,7 +246,7 @@ TrexRpcCmdAcquire::_run(const Json::Value &params, Json::Value &result) {
generate_execute_err(result, ex.what());
}
- result["result"] = port->get_owner_handler();
+ result["result"] = port->get_owner().get_handler();
return (TREX_RPC_CMD_OK);
}
@@ -272,7 +268,7 @@ TrexRpcCmdRelease::_run(const Json::Value &params, Json::Value &result) {
generate_execute_err(result, ex.what());
}
- result["result"] = "ACK";
+ result["result"] = Json::objectValue;
return (TREX_RPC_CMD_OK);
}
@@ -288,8 +284,6 @@ TrexRpcCmdGetPortStats::_run(const Json::Value &params, Json::Value &result) {
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
- result["result"]["status"] = port->get_state_as_string();
-
try {
port->encode_stats(result["result"]);
} catch (const TrexRpcException &ex) {
@@ -300,41 +294,25 @@ TrexRpcCmdGetPortStats::_run(const Json::Value &params, Json::Value &result) {
}
/**
- * request the server a sync about a specific user
+ * fetch the port status
+ *
+ * @author imarom (09-Dec-15)
+ *
+ * @param params
+ * @param result
*
+ * @return trex_rpc_cmd_rc_e
*/
trex_rpc_cmd_rc_e
-TrexRpcCmdSyncUser::_run(const Json::Value &params, Json::Value &result) {
-
- const string &user = parse_string(params, "user", result);
- bool sync_streams = parse_bool(params, "sync_streams", result);
-
- result["result"] = Json::arrayValue;
-
- for (auto port : get_stateless_obj()->get_port_list()) {
- if (port->get_owner() == user) {
-
- Json::Value owned_port;
+TrexRpcCmdGetPortStatus::_run(const Json::Value &params, Json::Value &result) {
+ uint8_t port_id = parse_port(params, result);
- owned_port["port_id"] = port->get_port_id();
- owned_port["handler"] = port->get_owner_handler();
- owned_port["state"] = port->get_state_as_string();
-
- /* if sync streams was asked - sync all the streams */
- if (sync_streams) {
- owned_port["streams"] = Json::arrayValue;
+ TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
- std::vector <TrexStream *> streams;
- port->get_object_list(streams);
+ result["result"]["owner"] = (port->get_owner().is_free() ? "" : port->get_owner().get_name());
+ result["result"]["state"] = port->get_state_as_string();
- for (auto stream : streams) {
- owned_port["streams"].append(stream->get_stream_json());
- }
- }
-
- result["result"].append(owned_port);
- }
- }
return (TREX_RPC_CMD_OK);
}
+
diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
index dea4c171..fa3d96b2 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -23,6 +23,7 @@ limitations under the License.
#include <trex_stream.h>
#include <trex_stateless.h>
#include <trex_stateless_port.h>
+#include <trex_streams_compiler.h>
#include <iostream>
@@ -52,7 +53,8 @@ static uint64_t str2num(const string &str) {
trex_rpc_cmd_rc_e
TrexRpcCmdAddStream::_run(const Json::Value &params, Json::Value &result) {
- uint8_t port_id = parse_int(params, "port_id", result);
+ uint8_t port_id = parse_port(params, result);
+
uint32_t stream_id = parse_int(params, "stream_id", result);
const Json::Value &section = parse_object(params, "stream", result);
@@ -122,7 +124,7 @@ TrexRpcCmdAddStream::_run(const Json::Value &params, Json::Value &result) {
generate_execute_err(result, ex.what());
}
- result["result"] = "ACK";
+ result["result"] = Json::objectValue;
return (TREX_RPC_CMD_OK);
}
@@ -296,15 +298,7 @@ TrexRpcCmdAddStream::validate_stream(const TrexStream *stream, Json::Value &resu
generate_execute_err(result, ss.str());
}
- /* port id should be between 0 and count - 1 */
- if (stream->m_port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- delete stream;
- generate_execute_err(result, ss.str());
- }
-
- /* add the stream to the port's stream table */
+ /* add the stream to the port's stream table */
TrexStatelessPort * port = get_stateless_obj()->get_port_by_id(stream->m_port_id);
/* does such a stream exists ? */
@@ -323,17 +317,11 @@ TrexRpcCmdAddStream::validate_stream(const TrexStream *stream, Json::Value &resu
**************************/
trex_rpc_cmd_rc_e
TrexRpcCmdRemoveStream::_run(const Json::Value &params, Json::Value &result) {
- uint8_t port_id = parse_byte(params, "port_id", result);
- uint32_t stream_id = parse_int(params, "stream_id", result);
-
-
- if (port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- generate_execute_err(result, ss.str());
- }
+ uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+
+ uint32_t stream_id = parse_int(params, "stream_id", result);
TrexStream *stream = port->get_stream_by_id(stream_id);
if (!stream) {
@@ -350,7 +338,7 @@ TrexRpcCmdRemoveStream::_run(const Json::Value &params, Json::Value &result) {
delete stream;
- result["result"] = "ACK";
+ result["result"] = Json::objectValue;
return (TREX_RPC_CMD_OK);
}
@@ -362,14 +350,8 @@ TrexRpcCmdRemoveStream::_run(const Json::Value &params, Json::Value &result) {
**************************/
trex_rpc_cmd_rc_e
TrexRpcCmdRemoveAllStreams::_run(const Json::Value &params, Json::Value &result) {
- uint8_t port_id = parse_byte(params, "port_id", result);
-
- if (port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- generate_execute_err(result, ss.str());
- }
+ uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
try {
@@ -379,7 +361,7 @@ TrexRpcCmdRemoveAllStreams::_run(const Json::Value &params, Json::Value &result)
}
- result["result"] = "ACK";
+ result["result"] = Json::objectValue;
return (TREX_RPC_CMD_OK);
}
@@ -393,27 +375,20 @@ trex_rpc_cmd_rc_e
TrexRpcCmdGetStreamList::_run(const Json::Value &params, Json::Value &result) {
std::vector<uint32_t> stream_list;
- uint8_t port_id = parse_byte(params, "port_id", result);
-
- if (port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- generate_execute_err(result, ss.str());
- }
-
- TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+ uint8_t port_id = parse_port(params, result);
+ TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
- port->get_id_list(stream_list);
+ port->get_id_list(stream_list);
- Json::Value json_list = Json::arrayValue;
+ Json::Value json_list = Json::arrayValue;
- for (auto stream_id : stream_list) {
- json_list.append(stream_id);
- }
+ for (auto stream_id : stream_list) {
+ json_list.append(stream_id);
+ }
- result["result"] = json_list;
+ result["result"] = json_list;
- return (TREX_RPC_CMD_OK);
+ return (TREX_RPC_CMD_OK);
}
/***************************
@@ -423,18 +398,13 @@ TrexRpcCmdGetStreamList::_run(const Json::Value &params, Json::Value &result) {
**************************/
trex_rpc_cmd_rc_e
TrexRpcCmdGetStream::_run(const Json::Value &params, Json::Value &result) {
- uint8_t port_id = parse_byte(params, "port_id", result);
- bool get_pkt = parse_bool(params, "get_pkt", result);
- uint32_t stream_id = parse_int(params, "stream_id", result);
-
- if (port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- generate_execute_err(result, ss.str());
- }
+ uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+ bool get_pkt = parse_bool(params, "get_pkt", result);
+ uint32_t stream_id = parse_int(params, "stream_id", result);
+
TrexStream *stream = port->get_stream_by_id(stream_id);
if (!stream) {
@@ -462,17 +432,11 @@ TrexRpcCmdGetStream::_run(const Json::Value &params, Json::Value &result) {
trex_rpc_cmd_rc_e
TrexRpcCmdStartTraffic::_run(const Json::Value &params, Json::Value &result) {
- uint8_t port_id = parse_byte(params, "port_id", result);
- double duration = parse_double(params, "duration", result);
-
- if (port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- generate_execute_err(result, ss.str());
- }
-
+ uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+ double duration = parse_double(params, "duration", result);
+
/* multiplier */
const Json::Value &mul_obj = parse_object(params, "mul", result);
@@ -493,7 +457,7 @@ TrexRpcCmdStartTraffic::_run(const Json::Value &params, Json::Value &result) {
generate_execute_err(result, ex.what());
}
- result["result"] = "ACK";
+ result["result"]["multiplier"] = port->get_multiplier();
return (TREX_RPC_CMD_OK);
}
@@ -504,14 +468,8 @@ TrexRpcCmdStartTraffic::_run(const Json::Value &params, Json::Value &result) {
**************************/
trex_rpc_cmd_rc_e
TrexRpcCmdStopTraffic::_run(const Json::Value &params, Json::Value &result) {
- uint8_t port_id = parse_byte(params, "port_id", result);
-
- if (port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- generate_execute_err(result, ss.str());
- }
+ uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
try {
@@ -520,7 +478,7 @@ TrexRpcCmdStopTraffic::_run(const Json::Value &params, Json::Value &result) {
generate_execute_err(result, ex.what());
}
- result["result"] = "ACK";
+ result["result"] = Json::objectValue;
return (TREX_RPC_CMD_OK);
}
@@ -531,17 +489,12 @@ TrexRpcCmdStopTraffic::_run(const Json::Value &params, Json::Value &result) {
**************************/
trex_rpc_cmd_rc_e
TrexRpcCmdGetAllStreams::_run(const Json::Value &params, Json::Value &result) {
- uint8_t port_id = parse_byte(params, "port_id", result);
- bool get_pkt = parse_bool(params, "get_pkt", result);
-
- if (port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- generate_execute_err(result, ss.str());
- }
-
+
+ uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+ bool get_pkt = parse_bool(params, "get_pkt", result);
+
std::vector <TrexStream *> streams;
port->get_object_list(streams);
@@ -573,14 +526,7 @@ TrexRpcCmdGetAllStreams::_run(const Json::Value &params, Json::Value &result) {
trex_rpc_cmd_rc_e
TrexRpcCmdPauseTraffic::_run(const Json::Value &params, Json::Value &result) {
- uint8_t port_id = parse_byte(params, "port_id", result);
-
- if (port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- generate_execute_err(result, ss.str());
- }
-
+ uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
try {
@@ -589,7 +535,7 @@ TrexRpcCmdPauseTraffic::_run(const Json::Value &params, Json::Value &result) {
generate_execute_err(result, ex.what());
}
- result["result"] = "ACK";
+ result["result"] = Json::objectValue;
return (TREX_RPC_CMD_OK);
}
@@ -601,14 +547,7 @@ TrexRpcCmdPauseTraffic::_run(const Json::Value &params, Json::Value &result) {
trex_rpc_cmd_rc_e
TrexRpcCmdResumeTraffic::_run(const Json::Value &params, Json::Value &result) {
- uint8_t port_id = parse_byte(params, "port_id", result);
-
- if (port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- generate_execute_err(result, ss.str());
- }
-
+ uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
try {
@@ -617,7 +556,7 @@ TrexRpcCmdResumeTraffic::_run(const Json::Value &params, Json::Value &result) {
generate_execute_err(result, ex.what());
}
- result["result"] = "ACK";
+ result["result"] = Json::objectValue;
return (TREX_RPC_CMD_OK);
}
@@ -629,14 +568,7 @@ TrexRpcCmdResumeTraffic::_run(const Json::Value &params, Json::Value &result) {
trex_rpc_cmd_rc_e
TrexRpcCmdUpdateTraffic::_run(const Json::Value &params, Json::Value &result) {
- uint8_t port_id = parse_byte(params, "port_id", result);
-
- if (port_id >= get_stateless_obj()->get_port_count()) {
- std::stringstream ss;
- ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1;
- generate_execute_err(result, ss.str());
- }
-
+ uint8_t port_id = parse_port(params, result);
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
/* multiplier */
@@ -656,8 +588,60 @@ TrexRpcCmdUpdateTraffic::_run(const Json::Value &params, Json::Value &result) {
generate_execute_err(result, ex.what());
}
- result["result"] = "ACK";
+ result["result"]["multiplier"] = port->get_multiplier();
return (TREX_RPC_CMD_OK);
}
+/***************************
+ * validate
+ *
+ * checks that the port
+ * attached streams are
+ * valid as a program
+ **************************/
+trex_rpc_cmd_rc_e
+TrexRpcCmdValidate::_run(const Json::Value &params, Json::Value &result) {
+ uint8_t port_id = parse_port(params, result);
+ TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+
+ const TrexStreamsGraphObj *graph = NULL;
+
+ try {
+ graph = port->validate();
+ }
+ catch (const TrexException &ex) {
+ generate_execute_err(result, ex.what());
+ }
+
+
+ result["result"]["rate"]["max_bps"] = graph->get_max_bps();
+ result["result"]["rate"]["max_pps"] = graph->get_max_pps();
+ result["result"]["rate"]["max_line_util"] = graph->get_max_bps() / port->get_port_speed_bps();
+
+ result["result"]["graph"]["expected_duration"] = graph->get_duration();
+ result["result"]["graph"]["events_count"] = (int)graph->get_events().size();
+
+ result["result"]["graph"]["events"] = Json::arrayValue;
+ Json::Value &events_json = result["result"]["graph"]["events"];
+
+ int index = 0;
+ for (const auto &ev : graph->get_events()) {
+ Json::Value ev_json;
+
+ ev_json["time_usec"] = ev.time;
+ ev_json["diff_bps"] = ev.diff_bps;
+ ev_json["diff_pps"] = ev.diff_pps;
+ ev_json["stream_id"] = ev.stream_id;
+
+ events_json.append(ev_json);
+
+ index++;
+ if (index >= 100) {
+ break;
+ }
+ }
+
+
+ return (TREX_RPC_CMD_OK);
+}
diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h
index b4f37e3b..c22ef390 100644
--- a/src/rpc-server/commands/trex_rpc_cmds.h
+++ b/src/rpc-server/commands/trex_rpc_cmds.h
@@ -77,7 +77,8 @@ TREX_RPC_CMD_DEFINE(TrexRpcCmdRelease, "release", 1, true);
/**
* port commands
*/
-TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortStats, "get_port_stats", 1, true);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortStats, "get_port_stats", 1, false);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortStatus, "get_port_status", 1, false);
/**
@@ -98,10 +99,10 @@ void parse_vm_instr_write_flow_var(const Json::Value &inst, TrexStream *stream,
);
-TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStreamList, "get_stream_list", 1, true);
-TREX_RPC_CMD_DEFINE(TrexRpcCmdGetAllStreams, "get_all_streams", 2, true);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStreamList, "get_stream_list", 1, false);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetAllStreams, "get_all_streams", 2, false);
-TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStream, "get_stream", 3, true);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStream, "get_stream", 3, false);
@@ -112,7 +113,6 @@ TREX_RPC_CMD_DEFINE(TrexRpcCmdResumeTraffic, "resume_traffic", 1, true);
TREX_RPC_CMD_DEFINE(TrexRpcCmdUpdateTraffic, "update_traffic", 2, true);
-TREX_RPC_CMD_DEFINE(TrexRpcCmdSyncUser, "sync_user", 2, false);
-
+TREX_RPC_CMD_DEFINE(TrexRpcCmdValidate, "validate", 2, false);
#endif /* __TREX_RPC_CMD_H__ */
diff --git a/src/rpc-server/trex_rpc_cmd.cpp b/src/rpc-server/trex_rpc_cmd.cpp
index af0db3f4..d4eef1f7 100644
--- a/src/rpc-server/trex_rpc_cmd.cpp
+++ b/src/rpc-server/trex_rpc_cmd.cpp
@@ -63,8 +63,12 @@ TrexRpcCommand::verify_ownership(const Json::Value &params, Json::Value &result)
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
- if (!port->verify_owner_handler(handler)) {
- generate_execute_err(result, "invalid handler provided. please pass the handler given when calling 'acquire' or take ownership");
+ if (port->get_owner().is_free()) {
+ generate_execute_err(result, "please acquire the port before modifying port state");
+ }
+
+ if (!port->get_owner().verify(handler)) {
+ generate_execute_err(result, "port is not owned by you or your current executing session");
}
}
@@ -92,6 +96,8 @@ TrexRpcCommand::type_to_str(field_type_e type) {
return "byte";
case FIELD_TYPE_UINT16:
return "uint16";
+ case FIELD_TYPE_UINT32:
+ return "uint32";
case FIELD_TYPE_BOOL:
return "bool";
case FIELD_TYPE_INT:
@@ -161,6 +167,18 @@ TrexRpcCommand::parse_uint16(const Json::Value &parent, int index, Json::Value &
return parent[index].asUInt();
}
+uint32_t
+TrexRpcCommand::parse_uint32(const Json::Value &parent, const std::string &name, Json::Value &result) {
+ check_field_type(parent, name, FIELD_TYPE_UINT32, result);
+ return parent[name].asUInt();
+}
+
+uint32_t
+TrexRpcCommand::parse_uint32(const Json::Value &parent, int index, Json::Value &result) {
+ check_field_type(parent, index, FIELD_TYPE_UINT32, result);
+ return parent[index].asUInt();
+}
+
int
TrexRpcCommand::parse_int(const Json::Value &parent, const std::string &name, Json::Value &result) {
check_field_type(parent, name, FIELD_TYPE_INT, result);
@@ -250,6 +268,12 @@ TrexRpcCommand::check_field_type_common(const Json::Value &field, const std::str
}
break;
+ case FIELD_TYPE_UINT32:
+ if ( (!field.isUInt()) || (field.asUInt() > 0xFFFFFFFF)) {
+ rc = false;
+ }
+ break;
+
case FIELD_TYPE_BOOL:
if (!field.isBool()) {
rc = false;
diff --git a/src/rpc-server/trex_rpc_cmd_api.h b/src/rpc-server/trex_rpc_cmd_api.h
index e93fb775..f81981d4 100644
--- a/src/rpc-server/trex_rpc_cmd_api.h
+++ b/src/rpc-server/trex_rpc_cmd_api.h
@@ -99,6 +99,7 @@ protected:
enum field_type_e {
FIELD_TYPE_BYTE,
FIELD_TYPE_UINT16,
+ FIELD_TYPE_UINT32,
FIELD_TYPE_INT,
FIELD_TYPE_DOUBLE,
FIELD_TYPE_BOOL,
@@ -136,6 +137,7 @@ protected:
*/
uint8_t parse_byte(const Json::Value &parent, const std::string &name, Json::Value &result);
uint16_t parse_uint16(const Json::Value &parent, const std::string &name, Json::Value &result);
+ uint32_t parse_uint32(const Json::Value &parent, const std::string &name, Json::Value &result);
int parse_int(const Json::Value &parent, const std::string &name, Json::Value &result);
double parse_double(const Json::Value &parent, const std::string &name, Json::Value &result);
bool parse_bool(const Json::Value &parent, const std::string &name, Json::Value &result);
@@ -145,6 +147,7 @@ protected:
uint8_t parse_byte(const Json::Value &parent, int index, Json::Value &result);
uint16_t parse_uint16(const Json::Value &parent, int index, Json::Value &result);
+ uint32_t parse_uint32(const Json::Value &parent, int index, Json::Value &result);
int parse_int(const Json::Value &parent, int index, Json::Value &result);
double parse_double(const Json::Value &parent, int index, Json::Value &result);
bool parse_bool(const Json::Value &parent, int index, Json::Value &result);
diff --git a/src/rpc-server/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp
index a65bbccf..82c723b7 100644
--- a/src/rpc-server/trex_rpc_cmds_table.cpp
+++ b/src/rpc-server/trex_rpc_cmds_table.cpp
@@ -41,8 +41,8 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() {
register_command(new TrexRpcCmdAcquire());
register_command(new TrexRpcCmdRelease());
register_command(new TrexRpcCmdGetPortStats());
-
- register_command(new TrexRpcCmdSyncUser());
+ register_command(new TrexRpcCmdGetPortStatus());
+
/* stream commands */
register_command(new TrexRpcCmdAddStream());
@@ -57,8 +57,11 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() {
register_command(new TrexRpcCmdPauseTraffic());
register_command(new TrexRpcCmdResumeTraffic());
register_command(new TrexRpcCmdUpdateTraffic());
+
+ register_command(new TrexRpcCmdValidate());
}
+
TrexRpcCommandsTable::~TrexRpcCommandsTable() {
for (auto cmd : m_rpc_cmd_table) {
delete cmd.second;
diff --git a/src/rpc-server/trex_rpc_req_resp_server.cpp b/src/rpc-server/trex_rpc_req_resp_server.cpp
index 9147f75d..eb7825ac 100644
--- a/src/rpc-server/trex_rpc_req_resp_server.cpp
+++ b/src/rpc-server/trex_rpc_req_resp_server.cpp
@@ -26,6 +26,7 @@ limitations under the License.
#include <unistd.h>
#include <sstream>
#include <iostream>
+#include <assert.h>
#include <zmq.h>
#include <json/json.h>
@@ -70,28 +71,14 @@ void TrexRpcServerReqRes::_rpc_thread_cb() {
/* server main loop */
while (m_is_running) {
- int msg_size = zmq_recv (m_socket, m_msg_buffer, sizeof(m_msg_buffer), 0);
-
- /* msg_size of -1 is an error - decode it */
- if (msg_size == -1) {
- /* normal shutdown and zmq_term was called */
- if (errno == ETERM) {
- break;
- } else {
- throw TrexRpcException("Unhandled error of zmq_recv");
- }
- }
+ std::string request;
- if (msg_size >= sizeof(m_msg_buffer)) {
- std::stringstream ss;
- ss << "RPC request of '" << msg_size << "' exceeds maximum message size which is '" << sizeof(m_msg_buffer) << "'";
- handle_server_error(ss.str());
- continue;
+ /* get the next request */
+ bool rc = fetch_one_request(request);
+ if (!rc) {
+ break;
}
- /* transform it to a string */
- std::string request((const char *)m_msg_buffer, msg_size);
-
verbose_json("Server Received: ", TrexJsonRpcV2Parser::pretty_json_str(request));
handle_request(request);
@@ -101,6 +88,35 @@ void TrexRpcServerReqRes::_rpc_thread_cb() {
zmq_close(m_socket);
}
+bool
+TrexRpcServerReqRes::fetch_one_request(std::string &msg) {
+
+ zmq_msg_t zmq_msg;
+ int rc;
+
+ rc = zmq_msg_init(&zmq_msg);
+ assert(rc == 0);
+
+ rc = zmq_msg_recv (&zmq_msg, m_socket, 0);
+
+ if (rc == -1) {
+ zmq_msg_close(&zmq_msg);
+ /* normal shutdown and zmq_term was called */
+ if (errno == ETERM) {
+ return false;
+ } else {
+ throw TrexRpcException("Unhandled error of zmq_recv");
+ }
+ }
+
+ const char *data = (const char *)zmq_msg_data(&zmq_msg);
+ size_t len = zmq_msg_size(&zmq_msg);
+ msg.append(data, len);
+
+ zmq_msg_close(&zmq_msg);
+ return true;
+}
+
/**
* stops the ZMQ based RPC server
*
diff --git a/src/rpc-server/trex_rpc_req_resp_server.h b/src/rpc-server/trex_rpc_req_resp_server.h
index bc38c0ef..2876206c 100644
--- a/src/rpc-server/trex_rpc_req_resp_server.h
+++ b/src/rpc-server/trex_rpc_req_resp_server.h
@@ -39,14 +39,12 @@ protected:
void _stop_rpc_thread();
private:
-
+ bool fetch_one_request(std::string &msg);
void handle_request(const std::string &request);
void handle_server_error(const std::string &specific_err);
- static const int RPC_MAX_MSG_SIZE = (200 * 1024);
void *m_context;
void *m_socket;
- uint8_t m_msg_buffer[RPC_MAX_MSG_SIZE];
};
diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp
index 95bdca0b..9770c735 100644
--- a/src/stateless/cp/trex_stateless_port.cpp
+++ b/src/stateless/cp/trex_stateless_port.cpp
@@ -57,7 +57,6 @@ TrexStatelessPort::TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api
m_port_id = port_id;
m_port_state = PORT_STATE_IDLE;
- clear_owner();
/* get the platform specific data */
api->get_interface_info(port_id, m_driver_name, m_speed);
@@ -86,17 +85,35 @@ TrexStatelessPort::TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api
*/
void
TrexStatelessPort::acquire(const std::string &user, bool force) {
- if ( (!is_free_to_aquire()) && (get_owner() != user) && (!force)) {
- throw TrexRpcException("port is already taken by '" + get_owner() + "'");
+
+ /* if port is free - just take it */
+ if (get_owner().is_free()) {
+ get_owner().own(user);
+ return;
+ }
+
+ if (force) {
+ get_owner().own(user);
+
+ /* inform the other client of the steal... */
+ Json::Value data;
+ data["port_id"] = m_port_id;
+ get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_FORCE_ACQUIRED, data);
+
+ } else {
+ /* not same user or session id and not force - report error */
+ if (get_owner().get_name() == user) {
+ throw TrexRpcException("port is already owned by another session of '" + user + "'");
+ } else {
+ throw TrexRpcException("port is already taken by '" + get_owner().get_name() + "'");
+ }
}
- set_owner(user);
}
void
TrexStatelessPort::release(void) {
- verify_state( ~(PORT_STATE_TX | PORT_STATE_PAUSE) );
- clear_owner();
+ get_owner().release();
}
/**
@@ -115,7 +132,7 @@ TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration)
/* on start - we can only provide absolute values */
assert(mul.m_op == TrexPortMultiplier::OP_ABS);
- double per_core_mul = calculate_effective_mul(mul);
+ double factor = calculate_effective_factor(mul);
/* fetch all the streams from the table */
vector<TrexStream *> streams;
@@ -123,12 +140,18 @@ TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration)
/* compiler it */
- TrexStreamsCompiler compiler;
- TrexStreamsCompiledObj *compiled_obj = new TrexStreamsCompiledObj(m_port_id, per_core_mul);
+ std::vector<TrexStreamsCompiledObj *> compiled_objs;
+ std::string fail_msg;
- bool rc = compiler.compile(streams, *compiled_obj);
+ TrexStreamsCompiler compiler;
+ bool rc = compiler.compile(m_port_id,
+ streams,
+ compiled_objs,
+ get_dp_core_count(),
+ factor,
+ &fail_msg);
if (!rc) {
- throw TrexRpcException("Failed to compile streams");
+ throw TrexRpcException(fail_msg);
}
/* generate a message to all the relevant DP cores to start transmitting */
@@ -137,21 +160,29 @@ TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration)
/* mark that DP event of stoppped is possible */
m_dp_events.wait_for_event(TrexDpPortEvent::EVENT_STOP, event_id);
- TrexStatelessCpToDpMsgBase *start_msg = new TrexStatelessDpStart(m_port_id, event_id, compiled_obj, duration);
-
- m_last_all_streams_continues = compiled_obj->get_all_streams_continues();
- m_last_duration =duration;
+ /* update object status */
+ m_factor = factor;
+ m_last_all_streams_continues = compiled_objs[0]->get_all_streams_continues();
+ m_last_duration = duration;
change_state(PORT_STATE_TX);
- send_message_to_dp(start_msg);
+
+ /* update the DP - messages will be freed by the DP */
+ int index = 0;
+ for (auto core_id : m_cores_id_list) {
+
+ TrexStatelessCpToDpMsgBase *start_msg = new TrexStatelessDpStart(m_port_id, event_id, compiled_objs[index], duration);
+ send_message_to_dp(core_id, start_msg);
+
+ index++;
+ }
+ /* update subscribers */
Json::Value data;
data["port_id"] = m_port_id;
get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_STARTED, data);
-
- /* save the per core multiplier for update messages */
- m_current_per_core_m = per_core_mul;
+
}
@@ -179,7 +210,7 @@ TrexStatelessPort::stop_traffic(void) {
/* generate a message to all the relevant DP cores to start transmitting */
TrexStatelessCpToDpMsgBase *stop_msg = new TrexStatelessDpStop(m_port_id);
- send_message_to_dp(stop_msg);
+ send_message_to_all_dp(stop_msg);
change_state(PORT_STATE_STREAMS);
@@ -202,11 +233,15 @@ TrexStatelessPort::pause_traffic(void) {
throw TrexRpcException(" pause is supported when duration is not enable is start command ");
}
- TrexStatelessCpToDpMsgBase *stop_msg = new TrexStatelessDpPause(m_port_id);
+ TrexStatelessCpToDpMsgBase *pause_msg = new TrexStatelessDpPause(m_port_id);
- send_message_to_dp(stop_msg);
+ send_message_to_all_dp(pause_msg);
change_state(PORT_STATE_PAUSE);
+
+ Json::Value data;
+ data["port_id"] = m_port_id;
+ get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_PAUSED, data);
}
void
@@ -215,11 +250,16 @@ TrexStatelessPort::resume_traffic(void) {
verify_state(PORT_STATE_PAUSE);
/* generate a message to all the relevant DP cores to start transmitting */
- TrexStatelessCpToDpMsgBase *stop_msg = new TrexStatelessDpResume(m_port_id);
+ TrexStatelessCpToDpMsgBase *resume_msg = new TrexStatelessDpResume(m_port_id);
- send_message_to_dp(stop_msg);
+ send_message_to_all_dp(resume_msg);
change_state(PORT_STATE_TX);
+
+
+ Json::Value data;
+ data["port_id"] = m_port_id;
+ get_stateless_obj()->get_publisher()->publish_event(TrexPublisher::EVENT_PORT_RESUMED, data);
}
void
@@ -230,19 +270,19 @@ TrexStatelessPort::update_traffic(const TrexPortMultiplier &mul) {
verify_state(PORT_STATE_TX | PORT_STATE_PAUSE);
/* generate a message to all the relevant DP cores to start transmitting */
- double new_per_core_m = calculate_effective_mul(mul);
+ double new_factor = calculate_effective_factor(mul);
switch (mul.m_op) {
case TrexPortMultiplier::OP_ABS:
- factor = new_per_core_m / m_current_per_core_m;
+ factor = new_factor / m_factor;
break;
case TrexPortMultiplier::OP_ADD:
- factor = (m_current_per_core_m + new_per_core_m) / m_current_per_core_m;
+ factor = (m_factor + new_factor) / m_factor;
break;
case TrexPortMultiplier::OP_SUB:
- factor = (m_current_per_core_m - new_per_core_m) / m_current_per_core_m;
+ factor = (m_factor - new_factor) / m_factor;
if (factor <= 0) {
throw TrexRpcException("Update request will lower traffic to less than zero");
}
@@ -255,9 +295,9 @@ TrexStatelessPort::update_traffic(const TrexPortMultiplier &mul) {
TrexStatelessCpToDpMsgBase *update_msg = new TrexStatelessDpUpdate(m_port_id, factor);
- send_message_to_dp(update_msg);
+ send_message_to_all_dp(update_msg);
- m_current_per_core_m *= factor;
+ m_factor *= factor;
}
@@ -310,27 +350,6 @@ TrexStatelessPort::change_state(port_state_e new_state) {
m_port_state = new_state;
}
-/**
- * generate a random connection handler
- *
- */
-std::string
-TrexStatelessPort::generate_handler() {
- std::stringstream ss;
-
- static const char alphanum[] =
- "0123456789"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz";
-
- /* generate 8 bytes of random handler */
- for (int i = 0; i < 8; ++i) {
- ss << alphanum[rand() % (sizeof(alphanum) - 1)];
- }
-
- return (ss.str());
-}
-
void
TrexStatelessPort::encode_stats(Json::Value &port) {
@@ -356,15 +375,22 @@ TrexStatelessPort::encode_stats(Json::Value &port) {
}
void
-TrexStatelessPort::send_message_to_dp(TrexStatelessCpToDpMsgBase *msg) {
+TrexStatelessPort::send_message_to_all_dp(TrexStatelessCpToDpMsgBase *msg) {
for (auto core_id : m_cores_id_list) {
-
- /* send the message to the core */
- CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingCpToDp(core_id);
- ring->Enqueue((CGenNode *)msg->clone());
+ send_message_to_dp(core_id, msg->clone());
}
+ /* original was not sent - delete it */
+ delete msg;
+}
+
+void
+TrexStatelessPort::send_message_to_dp(uint8_t core_id, TrexStatelessCpToDpMsgBase *msg) {
+
+ /* send the message to the core */
+ CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingCpToDp(core_id);
+ ring->Enqueue((CGenNode *)msg);
}
/**
@@ -393,7 +419,7 @@ TrexStatelessPort::on_dp_event_occured(TrexDpPortEvent::event_e event_type) {
}
uint64_t
-TrexStatelessPort::get_port_speed_bps() {
+TrexStatelessPort::get_port_speed_bps() const {
switch (m_speed) {
case TrexPlatformApi::SPEED_1G:
return (1LLU * 1000 * 1000 * 1000);
@@ -410,11 +436,11 @@ TrexStatelessPort::get_port_speed_bps() {
}
double
-TrexStatelessPort::calculate_effective_mul(const TrexPortMultiplier &mul) {
+TrexStatelessPort::calculate_effective_factor(const TrexPortMultiplier &mul) {
- /* for a simple factor request - calculate the multiplier per core */
+ /* for a simple factor request */
if (mul.m_type == TrexPortMultiplier::MUL_FACTOR) {
- return (mul.m_value / m_cores_id_list.size());
+ return (mul.m_value);
}
/* we now need the graph - generate it if we don't have it (happens once) */
@@ -424,19 +450,19 @@ TrexStatelessPort::calculate_effective_mul(const TrexPortMultiplier &mul) {
switch (mul.m_type) {
case TrexPortMultiplier::MUL_BPS:
- return ( (mul.m_value / m_graph_obj->get_max_bps()) / m_cores_id_list.size());
+ return (mul.m_value / m_graph_obj->get_max_bps());
case TrexPortMultiplier::MUL_PPS:
- return ( (mul.m_value / m_graph_obj->get_max_pps()) / m_cores_id_list.size());
+ return (mul.m_value / m_graph_obj->get_max_pps());
case TrexPortMultiplier::MUL_PERCENTAGE:
/* if abs percentage is from the line speed - otherwise its from the current speed */
if (mul.m_op == TrexPortMultiplier::OP_ABS) {
double required = (mul.m_value / 100.0) * get_port_speed_bps();
- return ( (required / m_graph_obj->get_max_bps()) / m_cores_id_list.size());
+ return (required / m_graph_obj->get_max_bps());
} else {
- return (m_current_per_core_m * (mul.m_value / 100.0));
+ return (m_factor * (mul.m_value / 100.0));
}
default:
@@ -518,3 +544,74 @@ TrexPortMultiplier(const std::string &type_str, const std::string &op_str, doubl
}
+const TrexStreamsGraphObj *
+TrexStatelessPort::validate(void) {
+
+ /* first compile the graph */
+
+ vector<TrexStream *> streams;
+ get_object_list(streams);
+
+ if (streams.size() == 0) {
+ throw TrexException("no streams attached to port");
+ }
+
+ TrexStreamsCompiler compiler;
+ std::vector<TrexStreamsCompiledObj *> compiled_objs;
+
+ std::string fail_msg;
+ bool rc = compiler.compile(m_port_id,
+ streams,
+ compiled_objs,
+ get_dp_core_count(),
+ 1.0,
+ &fail_msg);
+ if (!rc) {
+ throw TrexException(fail_msg);
+ }
+
+ for (auto obj : compiled_objs) {
+ delete obj;
+ }
+
+ /* now create a stream graph */
+ if (!m_graph_obj) {
+ generate_streams_graph();
+ }
+
+ return m_graph_obj;
+}
+
+
+/************* Trex Port Owner **************/
+
+TrexPortOwner::TrexPortOwner() {
+ m_is_free = true;
+
+ /* for handlers random generation */
+ srand(time(NULL));
+}
+
+/**
+ * generate a random connection handler
+ *
+ */
+std::string
+TrexPortOwner::generate_handler() {
+ std::stringstream ss;
+
+ static const char alphanum[] =
+ "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+
+ /* generate 8 bytes of random handler */
+ for (int i = 0; i < 8; ++i) {
+ ss << alphanum[rand() % (sizeof(alphanum) - 1)];
+ }
+
+ return (ss.str());
+}
+
+const std::string TrexPortOwner::g_unowned_name = "<FREE>";
+const std::string TrexPortOwner::g_unowned_handler = "";
diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h
index 45eb16e8..4988b46a 100644
--- a/src/stateless/cp/trex_stateless_port.h
+++ b/src/stateless/cp/trex_stateless_port.h
@@ -29,6 +29,77 @@ class TrexStatelessCpToDpMsgBase;
class TrexStreamsGraphObj;
class TrexPortMultiplier;
+/**
+ * TRex port owner can perform
+ * write commands
+ * while port is owned - others can
+ * do read only commands
+ *
+ */
+class TrexPortOwner {
+public:
+
+ TrexPortOwner();
+
+ /**
+ * is port free to acquire
+ */
+ bool is_free() {
+ return m_is_free;
+ }
+
+ void release() {
+ m_is_free = true;
+ m_owner_name = "";
+ m_handler = "";
+ }
+
+ bool is_owned_by(const std::string &user) {
+ return ( !m_is_free && (m_owner_name == user) );
+ }
+
+ void own(const std::string &owner_name) {
+
+ /* save user data */
+ m_owner_name = owner_name;
+
+ /* internal data */
+ m_handler = generate_handler();
+ m_is_free = false;
+ }
+
+ bool verify(const std::string &handler) {
+ return ( (!m_is_free) && (m_handler == handler) );
+ }
+
+ const std::string &get_name() {
+ return (!m_is_free ? m_owner_name : g_unowned_name);
+ }
+
+ const std::string &get_handler() {
+ return (!m_is_free ? m_handler : g_unowned_handler);
+ }
+
+
+private:
+ std::string generate_handler();
+
+ /* is this port owned by someone ? */
+ bool m_is_free;
+
+ /* user provided info */
+ std::string m_owner_name;
+
+ /* handler genereated internally */
+ std::string m_handler;
+
+
+ /* just references defaults... */
+ static const std::string g_unowned_name;
+ static const std::string g_unowned_handler;
+};
+
+
/**
* describes a stateless port
*
@@ -76,10 +147,20 @@ public:
void release(void);
/**
+ * validate the state of the port before start
+ * it will return a stream graph
+ * containing information about the streams
+ * configured on this port
+ *
+ * on error it throws TrexException
+ */
+ const TrexStreamsGraphObj *validate(void);
+
+ /**
* start traffic
* throws TrexException in case of an error
*/
- void start_traffic(const TrexPortMultiplier &mul, double duration = -1);
+ void start_traffic(const TrexPortMultiplier &mul, double duration);
/**
* stop traffic
@@ -130,29 +211,6 @@ public:
void get_properties(std::string &driver, TrexPlatformApi::driver_speed_e &speed);
- /**
- * query for ownership
- *
- */
- const std::string &get_owner() {
- return m_owner;
- }
-
- /**
- * owner handler
- * for the connection
- *
- */
- const std::string &get_owner_handler() {
- return m_owner_handler;
- }
-
-
- bool verify_owner_handler(const std::string &handler) {
-
- return ( (m_owner != "none") && (m_owner_handler == handler) );
-
- }
/**
* encode stats as JSON
@@ -172,6 +230,7 @@ public:
verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS);
m_stream_table.add_stream(stream);
+ delete_streams_graph();
change_state(PORT_STATE_STREAMS);
}
@@ -180,6 +239,7 @@ public:
verify_state(PORT_STATE_STREAMS);
m_stream_table.remove_stream(stream);
+ delete_streams_graph();
if (m_stream_table.size() == 0) {
change_state(PORT_STATE_IDLE);
@@ -190,6 +250,7 @@ public:
verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS);
m_stream_table.remove_and_delete_all_streams();
+ delete_streams_graph();
change_state(PORT_STATE_IDLE);
}
@@ -211,30 +272,34 @@ public:
}
-private:
-
-
-
/**
- * take ownership of the server array
- * this is static
- * ownership is total
- *
- */
- void set_owner(const std::string &owner) {
- m_owner = owner;
- m_owner_handler = generate_handler();
+ * returns the number of DP cores linked to this port
+ *
+ */
+ uint8_t get_dp_core_count() {
+ return m_cores_id_list.size();
}
- void clear_owner() {
- m_owner = "none";
- m_owner_handler = "";
+ /**
+ * returns the traffic multiplier currently being used by the DP
+ *
+ */
+ double get_multiplier() {
+ return (m_factor);
}
- bool is_free_to_aquire() {
- return (m_owner == "none");
+ /**
+ * get port speed in bits per second
+ *
+ */
+ uint64_t get_port_speed_bps() const;
+
+ TrexPortOwner & get_owner() {
+ return m_owner;
}
+private:
+
const std::vector<int> get_core_id_list () {
return m_cores_id_list;
@@ -246,7 +311,17 @@ private:
std::string generate_handler();
- void send_message_to_dp(TrexStatelessCpToDpMsgBase *msg);
+ /**
+ * send message to all cores using duplicate
+ *
+ */
+ void send_message_to_all_dp(TrexStatelessCpToDpMsgBase *msg);
+
+ /**
+ * send message to specific DP core
+ *
+ */
+ void send_message_to_dp(uint8_t core_id, TrexStatelessCpToDpMsgBase *msg);
/**
* triggered when event occurs
@@ -259,13 +334,9 @@ private:
* calculate effective M per core
*
*/
- double calculate_effective_mul(const TrexPortMultiplier &mul);
+ double calculate_effective_factor(const TrexPortMultiplier &mul);
- /**
- * get port speed in bits per second
- *
- */
- uint64_t get_port_speed_bps();
+
/**
* generates a graph of streams graph
@@ -284,25 +355,25 @@ private:
TrexStreamTable m_stream_table;
uint8_t m_port_id;
port_state_e m_port_state;
- std::string m_owner;
- std::string m_owner_handler;
std::string m_driver_name;
TrexPlatformApi::driver_speed_e m_speed;
/* holds the DP cores associated with this port */
- std::vector<int> m_cores_id_list;
+ std::vector<int> m_cores_id_list;
bool m_last_all_streams_continues;
double m_last_duration;
- double m_current_per_core_m;
+ double m_factor;
TrexDpPortEvents m_dp_events;
/* holds a graph of streams rate*/
const TrexStreamsGraphObj *m_graph_obj;
-};
+ /* owner information */
+ TrexPortOwner m_owner;
+};
/**
diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h
index c42d0985..529dcbe4 100644
--- a/src/stateless/cp/trex_stream.h
+++ b/src/stateless/cp/trex_stream.h
@@ -129,8 +129,9 @@ public:
}
/* create new stream */
- TrexStream * clone_as_dp(){
- TrexStream * dp=new TrexStream(m_type,m_port_id,m_stream_id);
+ TrexStream * clone_as_dp() const {
+
+ TrexStream *dp = new TrexStream(m_type,m_port_id,m_stream_id);
dp->m_has_vm = m_has_vm;
diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp
index c8aa1e40..478e09f8 100644
--- a/src/stateless/cp/trex_streams_compiler.cpp
+++ b/src/stateless/cp/trex_streams_compiler.cpp
@@ -142,8 +142,9 @@ private:
/**************************************
* stream compiled object
*************************************/
-TrexStreamsCompiledObj::TrexStreamsCompiledObj(uint8_t port_id, double mul) : m_port_id(port_id), m_mul(mul) {
- m_all_continues=false;
+TrexStreamsCompiledObj::TrexStreamsCompiledObj(uint8_t port_id) {
+ m_port_id = port_id;
+ m_all_continues = false;
}
TrexStreamsCompiledObj::~TrexStreamsCompiledObj() {
@@ -155,53 +156,40 @@ TrexStreamsCompiledObj::~TrexStreamsCompiledObj() {
void
-TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream){
+TrexStreamsCompiledObj::add_compiled_stream(TrexStream *stream){
obj_st obj;
- obj.m_stream = stream->clone_as_dp();
+ obj.m_stream = stream;
m_objs.push_back(obj);
}
-void
-TrexStreamsCompiledObj::add_compiled_stream(TrexStream * stream,
- uint32_t my_dp_id, int next_dp_id) {
- obj_st obj;
-
- obj.m_stream = stream->clone_as_dp();
- /* compress the id's*/
- obj.m_stream->fix_dp_stream_id(my_dp_id,next_dp_id);
-
- m_objs.push_back(obj);
-}
-
-void TrexStreamsCompiledObj::Dump(FILE *fd){
- for (auto obj : m_objs) {
- obj.m_stream->Dump(fd);
- }
-}
-
-
TrexStreamsCompiledObj *
TrexStreamsCompiledObj::clone() {
- /* use multiplier of 1 to avoid double mult */
- TrexStreamsCompiledObj *new_compiled_obj = new TrexStreamsCompiledObj(m_port_id, 1);
+ TrexStreamsCompiledObj *new_compiled_obj = new TrexStreamsCompiledObj(m_port_id);
/**
* clone each element
*/
for (auto obj : m_objs) {
- new_compiled_obj->add_compiled_stream(obj.m_stream);
+ TrexStream *new_stream = obj.m_stream->clone_as_dp();
+ new_compiled_obj->add_compiled_stream(new_stream);
}
- new_compiled_obj->m_mul = m_mul;
-
return new_compiled_obj;
+
}
+void TrexStreamsCompiledObj::Dump(FILE *fd){
+ for (auto obj : m_objs) {
+ obj.m_stream->Dump(fd);
+ }
+}
+
+
void
TrexStreamsCompiler::add_warning(const std::string &warning) {
m_warnings.push_back("*** warning: " + warning);
@@ -219,7 +207,7 @@ TrexStreamsCompiler::check_stream(const TrexStream *stream) {
/* cont. stream can point only on itself */
if (stream->get_type() == TrexStream::stCONTINUOUS) {
if (stream->m_next_stream_id != -1) {
- ss << "continous stream '" << stream->m_stream_id << "' cannot point on another stream";
+ ss << "continous stream '" << stream->m_stream_id << "' cannot point to another stream";
err(ss.str());
}
}
@@ -381,12 +369,14 @@ TrexStreamsCompiler::pre_compile_check(const std::vector<TrexStream *> &streams,
* stream compiler
*************************************/
bool
-TrexStreamsCompiler::compile(const std::vector<TrexStream *> &streams,
- TrexStreamsCompiledObj &obj,
- std::string *fail_msg) {
+TrexStreamsCompiler::compile(uint8_t port_id,
+ const std::vector<TrexStream *> &streams,
+ std::vector<TrexStreamsCompiledObj *> &objs,
+ uint8_t dp_core_count,
+ double factor,
+ std::string *fail_msg) {
#if 0
- fprintf(stdout,"------------pre compile \n");
for (auto stream : streams) {
stream->Dump(stdout);
}
@@ -398,7 +388,7 @@ TrexStreamsCompiler::compile(const std::vector<TrexStream *> &streams,
/* compile checks */
try {
- pre_compile_check(streams,nodes);
+ pre_compile_check(streams, nodes);
} catch (const TrexException &ex) {
if (fail_msg) {
*fail_msg = ex.what();
@@ -408,38 +398,94 @@ TrexStreamsCompiler::compile(const std::vector<TrexStream *> &streams,
return false;
}
+ /* check if all are cont. streams */
+ bool all_continues = true;
+ for (const auto stream : streams) {
+ if (stream->get_type() != TrexStream::stCONTINUOUS) {
+ all_continues = false;
+ break;
+ }
+ }
- bool all_continues=true;
- /* for now we do something trivial, */
+ /* allocate objects for all DP cores */
+ for (uint8_t i = 0; i < dp_core_count; i++) {
+ TrexStreamsCompiledObj *obj = new TrexStreamsCompiledObj(port_id);
+ obj->m_all_continues = all_continues;
+ objs.push_back(obj);
+ }
+
+ /* compile all the streams */
for (auto stream : streams) {
/* skip non-enabled streams */
if (!stream->m_enabled) {
continue;
}
- if (stream->get_type() != TrexStream::stCONTINUOUS ) {
- all_continues=false;
- }
-
- int new_id= nodes.get(stream->m_stream_id)->m_compressed_stream_id;
- assert(new_id>=0);
- uint32_t my_stream_id = (uint32_t)new_id;
- int my_next_stream_id=-1;
- if (stream->m_next_stream_id>=0) {
- my_next_stream_id=nodes.get(stream->m_next_stream_id)->m_compressed_stream_id;
- }
-
- /* add it */
- obj.add_compiled_stream(stream,
- my_stream_id,
- my_next_stream_id
- );
+
+ /* compile a single stream to all cores */
+ compile_stream(stream, factor, dp_core_count, objs, nodes);
}
- obj.m_all_continues =all_continues;
+
return true;
}
+/**
+ * compiles a single stream to DP objects
+ *
+ * @author imarom (03-Dec-15)
+ *
+ */
+void
+TrexStreamsCompiler::compile_stream(const TrexStream *stream,
+ double factor,
+ uint8_t dp_core_count,
+ std::vector<TrexStreamsCompiledObj *> &objs,
+ GraphNodeMap &nodes) {
+
+
+ /* fix the stream ids */
+ int new_id = nodes.get(stream->m_stream_id)->m_compressed_stream_id;
+ assert(new_id >= 0);
+
+ int new_next_id = -1;
+ if (stream->m_next_stream_id >= 0) {
+ new_next_id = nodes.get(stream->m_next_stream_id)->m_compressed_stream_id;
+ }
+
+ /* calculate rate */
+ double per_core_rate = (stream->m_pps * (factor / dp_core_count));
+ int per_core_burst_total_pkts = (stream->m_burst_total_pkts / dp_core_count);
+
+ std::vector<TrexStream *> per_core_streams(dp_core_count);
+
+ /* for each core - creates its own version of the stream */
+ for (uint8_t i = 0; i < dp_core_count; i++) {
+ TrexStream *dp_stream = stream->clone_as_dp();
+
+ /* fix stream ID */
+ dp_stream->fix_dp_stream_id(new_id, new_next_id);
+
+
+ /* adjust rate and packets count */
+ dp_stream->m_pps = per_core_rate;
+ dp_stream->m_burst_total_pkts = per_core_burst_total_pkts;
+
+ per_core_streams[i] = dp_stream;
+ }
+
+ /* take care of remainder from a burst */
+ int burst_remainder = stream->m_burst_total_pkts - (per_core_burst_total_pkts * dp_core_count);
+ per_core_streams[0]->m_burst_total_pkts += burst_remainder;
+
+ /* attach the compiled stream of every core to its object */
+ for (uint8_t i = 0; i < dp_core_count; i++) {
+ objs[i]->add_compiled_stream(per_core_streams[i]);
+ }
+
+
+}
+
/**************************************
* streams graph
*************************************/
@@ -490,6 +536,9 @@ TrexStreamsGraph::add_rate_events_for_stream_cont(double &offset_usec, const Tre
/* no more events after this stream */
offset_usec = -1;
+
+ /* also mark we have an inifite time */
+ m_graph_obj->m_expected_duration = -1;
}
/**
@@ -602,6 +651,7 @@ TrexStreamsGraph::generate_graph_for_one_root(uint32_t root_stream_id) {
/* loop detection */
auto search = loop_hash.find(stream->m_next_stream_id);
if (search != loop_hash.end()) {
+ m_graph_obj->on_loop_detection();
break;
}
@@ -674,6 +724,11 @@ TrexStreamsGraphObj::find_max_rate() {
max_rate_bps = std::max(max_rate_bps, current_rate_bps);
}
+ /* if not mark as inifite - get the last event time */
+ if (m_expected_duration != -1) {
+ m_expected_duration = m_rate_events.back().time;
+ }
+
m_max_pps = max_rate_pps;
m_max_bps = max_rate_bps;
}
diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h
index a4c12f8d..7fe2dbf2 100644
--- a/src/stateless/cp/trex_streams_compiler.h
+++ b/src/stateless/cp/trex_streams_compiler.h
@@ -38,9 +38,10 @@ class GraphNodeMap;
*/
class TrexStreamsCompiledObj {
friend class TrexStreamsCompiler;
+
public:
- TrexStreamsCompiledObj(uint8_t port_id, double m_mul);
+ TrexStreamsCompiledObj(uint8_t port_id);
~TrexStreamsCompiledObj();
struct obj_st {
@@ -56,32 +57,22 @@ public:
return (m_port_id);
}
- /**
- * clone the compiled object
- *
- */
- TrexStreamsCompiledObj * clone();
-
- double get_multiplier(){
- return (m_mul);
- }
-
bool get_all_streams_continues(){
return (m_all_continues);
}
void Dump(FILE *fd);
+ TrexStreamsCompiledObj* clone();
+
private:
- void add_compiled_stream(TrexStream * stream,
- uint32_t my_dp_id, int next_dp_id);
- void add_compiled_stream(TrexStream * stream);
+ void add_compiled_stream(TrexStream *stream);
+
std::vector<obj_st> m_objs;
bool m_all_continues;
uint8_t m_port_id;
- double m_mul;
};
class TrexStreamsCompiler {
@@ -93,7 +84,13 @@ public:
* @author imarom (28-Oct-15)
*
*/
- bool compile(const std::vector<TrexStream *> &streams, TrexStreamsCompiledObj &obj, std::string *fail_msg = NULL);
+ bool compile(uint8_t port_id,
+ const std::vector<TrexStream *> &streams,
+ std::vector<TrexStreamsCompiledObj *> &objs,
+ uint8_t dp_core_count = 1,
+ double factor = 1.0,
+ std::string *fail_msg = NULL);
+
/**
*
@@ -115,8 +112,13 @@ private:
void add_warning(const std::string &warning);
void err(const std::string &err);
+ void compile_stream(const TrexStream *stream,
+ double factor,
+ uint8_t dp_core_count,
+ std::vector<TrexStreamsCompiledObj *> &objs,
+ GraphNodeMap &nodes);
+
std::vector<std::string> m_warnings;
-
};
class TrexStreamsGraph;
@@ -131,6 +133,12 @@ class TrexStreamsGraphObj {
public:
+ TrexStreamsGraphObj() {
+ m_max_pps = 0;
+ m_max_bps = 0;
+ m_expected_duration = 0;
+ }
+
/**
* rate event is defined by those:
* time - the time of the event on the timeline
@@ -153,12 +161,21 @@ public:
return m_max_bps;
}
+ int get_duration() const {
+ return m_expected_duration;
+ }
+
const std::list<rate_event_st> & get_events() const {
return m_rate_events;
}
+
private:
+ void on_loop_detection() {
+ m_expected_duration = -1;
+ }
+
void add_rate_event(const rate_event_st &ev) {
m_rate_events.push_back(ev);
}
@@ -166,8 +183,9 @@ private:
void generate();
void find_max_rate();
- double m_max_pps;
- double m_max_bps;
+ double m_max_pps;
+ double m_max_bps;
+ int m_expected_duration;
/* list of rate events */
std::list<rate_event_st> m_rate_events;
diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp
index 8c0f03c8..142b38bf 100644
--- a/src/stateless/dp/trex_stateless_dp_core.cpp
+++ b/src/stateless/dp/trex_stateless_dp_core.cpp
@@ -490,7 +490,7 @@ TrexStatelessDpCore::add_stream(TrexStatelessDpPerPort * lp_port,
node->m_pause =0;
node->m_stream_type = stream->m_type;
- node->m_next_time_offset = 1.0 / (stream->get_pps() * comp->get_multiplier());
+ node->m_next_time_offset = 1.0 / stream->get_pps();
/* stateless specific fields */
switch ( stream->m_type ) {