summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/bp_gtest.cpp86
-rwxr-xr-xsrc/bp_sim.cpp549
-rwxr-xr-xsrc/bp_sim.h198
-rwxr-xr-xsrc/common/Network/Packet/TcpHeader.h5
-rw-r--r--src/flow_stat.cpp26
-rwxr-xr-xsrc/global_io_mode.cpp31
-rwxr-xr-xsrc/global_io_mode.h16
-rwxr-xr-xsrc/gtest/tuple_gen_test.cpp75
-rw-r--r--src/internal_api/trex_platform_api.h10
-rw-r--r--src/latency.cpp15
-rw-r--r--src/latency.h35
-rw-r--r--src/mac_mapping.h60
-rwxr-xr-xsrc/main.cpp39
-rw-r--r--src/main_dpdk.cpp329
-rwxr-xr-xsrc/nat_check.cpp59
-rwxr-xr-xsrc/nat_check.h8
-rw-r--r--src/nat_check_flow_table.cpp314
-rw-r--r--src/nat_check_flow_table.h111
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp23
-rw-r--r--src/rpc-server/commands/trex_rpc_cmds.h1
-rw-r--r--src/rpc-server/trex_rpc_cmds_table.cpp1
-rw-r--r--src/sim/trex_sim_stateful.cpp25
-rw-r--r--src/stateless/cp/trex_stateless.cpp6
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.cpp12
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.h26
-rw-r--r--src/trex_client_config.cpp235
-rw-r--r--src/trex_client_config.h265
-rw-r--r--src/trex_defs.h7
-rw-r--r--src/trex_watchdog.cpp2
-rw-r--r--src/trex_watchdog.h6
-rwxr-xr-xsrc/tuple_gen.cpp185
-rwxr-xr-xsrc/tuple_gen.h194
-rwxr-xr-xsrc/utl_cpuu.cpp31
-rwxr-xr-xsrc/utl_cpuu.h17
-rwxr-xr-xsrc/utl_yaml.cpp267
-rwxr-xr-xsrc/utl_yaml.h55
36 files changed, 2449 insertions, 875 deletions
diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp
index 79ea2458..a1f80407 100755
--- a/src/bp_gtest.cpp
+++ b/src/bp_gtest.cpp
@@ -32,6 +32,7 @@ limitations under the License.
#include <common/cgen_map.h>
#include "platform_cfg.h"
#include "latency.h"
+#include "nat_check_flow_table.h"
int test_policer(){
CPolicer policer;
@@ -2400,7 +2401,20 @@ TEST_F(rx_check_system, rx_json) {
printf(" %s \n",json.c_str());
}
+class nat_check_flow_table : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+public:
+ CNatCheckFlowTable m_ft;
+};
+TEST_F(nat_check_flow_table, test1) {
+ m_ft.test();
+};
//////////////////////////////////////////////////////////////
@@ -2416,7 +2430,7 @@ public:
assert(ipv4->getTimeToLive()==255);
/* ip option packet */
printf(" rx got ip option packet ! \n");
- mg->handle_packet_ipv4(option,ipv4);
+ mg->handle_packet_ipv4(option, ipv4, true);
delay(10); // delay for queue flush
mg->handle_aging(); // flush the RxRing
}
@@ -2481,8 +2495,10 @@ protected:
m_flow_info.Delete();
}
public:
- CCapFileFlowInfo m_flow_info;
+ void load_cap_file_errors_helper(std::string cap_file, enum CCapFileFlowInfo::load_cap_file_err expect);
+public:
+ CCapFileFlowInfo m_flow_info;
};
TEST_F(file_flow_info, f1) {
@@ -2612,30 +2628,58 @@ TEST_F(file_flow_info, http_add_ipv6_option) {
po->preview.set_ipv6_mode_enable(false);
}
+void file_flow_info::load_cap_file_errors_helper(std::string cap_file, enum CCapFileFlowInfo::load_cap_file_err expect) {
+ enum CCapFileFlowInfo::load_cap_file_err err;
+
+ err = m_flow_info.load_cap_file(cap_file, 1, 0);
+ if (err == 0) err = m_flow_info.is_valid_template_load_time();
+ if (err != expect) {
+ printf("Error in testing file %s. Expected error to be %d, but it is %d\n", cap_file.c_str(), expect, err);
+ }
+ assert (err == expect);
+}
+
// Test error conditions when loading cap file
TEST_F(file_flow_info, load_cap_file_errors) {
- enum CCapFileFlowInfo::load_cap_file_err err;
- CParserOption * po =&CGlobalInfo::m_options;
- po->m_learn_mode = CParserOption::LEARN_MODE_TCP_ACK;
+ CParserOption *po = &CGlobalInfo::m_options;
- // file does not exist
- err = m_flow_info.load_cap_file("/tmp/not_exist",1,0);
- assert (err == CCapFileFlowInfo::kFileNotExist);
+ po->m_learn_mode = CParserOption::LEARN_MODE_DISABLED;
+ load_cap_file_errors_helper("/tmp/not_exist", CCapFileFlowInfo::kFileNotExist);
// file format not supported
- err = m_flow_info.load_cap_file("cap2/dns.yaml",1,0);
- assert (err == CCapFileFlowInfo::kFileNotExist);
- // udp in tcp learn mode
- err = m_flow_info.load_cap_file("./cap2/dns.pcap",1,0);
- assert (err == CCapFileFlowInfo::kNoTCPFromServer);
- // First TCP packet without syn
- err = m_flow_info.load_cap_file("./exp/tcp_no_syn.pcap",1,0);
- assert (err == CCapFileFlowInfo::kNoSyn);
- // TCP flags offset is too big
- err = m_flow_info.load_cap_file("./exp/many_ip_options.pcap",1,0);
- assert (err == CCapFileFlowInfo::kTCPOffsetTooBig);
+ load_cap_file_errors_helper("cap2/dns.yaml", CCapFileFlowInfo::kFileNotExist);
+ load_cap_file_errors_helper("cap2/dns.pcap", CCapFileFlowInfo::kOK);
+ load_cap_file_errors_helper("./exp/tcp_no_syn.pcap", CCapFileFlowInfo::kOK);
+ load_cap_file_errors_helper("./exp/many_ip_options.pcap", CCapFileFlowInfo::kOK);
// Non IP packet
- err = m_flow_info.load_cap_file("./exp/bad_not_ip.pcap",1,0);
- assert (err == CCapFileFlowInfo::kPktProcessFail);
+ load_cap_file_errors_helper("./exp/bad_not_ip.pcap", CCapFileFlowInfo::kPktProcessFail);
+ load_cap_file_errors_helper("./exp/tcp_2_pkts.pcap", CCapFileFlowInfo::kOK);
+ // more than 1 flow in cap file
+ load_cap_file_errors_helper("./exp/syn_attack.pcap", CCapFileFlowInfo::kCapFileErr);
+
+ po->m_learn_mode = CParserOption::LEARN_MODE_IP_OPTION;
+ load_cap_file_errors_helper("cap2/dns.pcap", CCapFileFlowInfo::kOK);
+ load_cap_file_errors_helper("./exp/tcp_no_syn.pcap", CCapFileFlowInfo::kOK);
+ load_cap_file_errors_helper("./exp/many_ip_options.pcap", CCapFileFlowInfo::kIPOptionNotAllowed);
+ load_cap_file_errors_helper("./exp/tcp_2_pkts.pcap", CCapFileFlowInfo::kOK);
+
+ po->m_learn_mode = CParserOption::LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND;
+ // udp in tcp learn mode
+ load_cap_file_errors_helper("cap2/dns.pcap", CCapFileFlowInfo::kNoTCPFromServer);
+ // no SYN in first packet
+ load_cap_file_errors_helper("./exp/tcp_no_syn.pcap", CCapFileFlowInfo::kNoSyn);
+ // TCP flags offset is too big. We don't allow IP option, so can comment this.
+ // open this if we do allow IP options in the future
+ // load_cap_file_errors_helper("./exp/many_ip_options.pcap", CCapFileFlowInfo::kTCPOffsetTooBig);
+ load_cap_file_errors_helper("./exp/tcp_2_pkts.pcap", CCapFileFlowInfo::kOK);
+ load_cap_file_errors_helper("./exp/no_tcp_syn_ack.pcap", CCapFileFlowInfo::kOK);
+
+ po->m_learn_mode = CParserOption::LEARN_MODE_TCP_ACK;
+ // too short. only two packets
+ load_cap_file_errors_helper("./exp/tcp_2_pkts.pcap", CCapFileFlowInfo::kTCPLearnModeBadFlow);
+ // no SYN+ACK
+ load_cap_file_errors_helper("./exp/no_tcp_syn_ack.pcap", CCapFileFlowInfo::kNoTCPSynAck);
+ // IPG between TCP handshake packets too low
+ load_cap_file_errors_helper("./exp/tcp_low_ipg.pcap", CCapFileFlowInfo::kTCPIpgTooLow);
}
//////////////////////////////////////////////////////////////
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index db90107d..b229d9bf 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -498,40 +498,23 @@ void CRteMemPool::dump_in_case_of_error(FILE *fd){
dump(fd);
}
-std::string CRteMemPool::add_to_json(
- std::string name,
- rte_mempool_t * pool,
- bool last){
+void CRteMemPool::add_to_json(Json::Value &json, std::string name, rte_mempool_t * pool){
uint32_t p_free = rte_mempool_count(pool);
uint32_t p_size = pool->size;
- char buff[200];
- sprintf(buff,"\"%s\":[%llu,%llu]",name.c_str(),(unsigned long long)p_free,(unsigned long long)p_size);
- std::string json = std::string(buff) + (last?std::string(""):std::string(","));
- return (json);
+ json[name].append((unsigned long long)p_free);
+ json[name].append((unsigned long long)p_size);
}
-std::string CRteMemPool::dump_as_json(uint8_t id,bool last){
-
- char buff[200];
- sprintf(buff,"\"socket-%d\":{", (int)id);
-
- std::string json=std::string(buff);
-
- json+=add_to_json("64b",m_small_mbuf_pool);
- json+=add_to_json("128b",m_mbuf_pool_128);
- json+=add_to_json("256b",m_mbuf_pool_256);
- json+=add_to_json("512b",m_mbuf_pool_512);
- json+=add_to_json("1024b",m_mbuf_pool_1024);
- json+=add_to_json("2048b",m_mbuf_pool_2048);
- json+=add_to_json("4096b",m_mbuf_pool_4096);
- json+=add_to_json("9kb",m_mbuf_pool_9k,true);
-
- json+="}" ;
- if (last==false) {
- json+="," ;
- }
- return (json);
+void CRteMemPool::dump_as_json(Json::Value &json){
+ add_to_json(json, "64b", m_small_mbuf_pool);
+ add_to_json(json, "128b", m_mbuf_pool_128);
+ add_to_json(json, "256b", m_mbuf_pool_256);
+ add_to_json(json, "512b", m_mbuf_pool_512);
+ add_to_json(json, "1024b", m_mbuf_pool_1024);
+ add_to_json(json, "2048b", m_mbuf_pool_2048);
+ add_to_json(json, "4096b", m_mbuf_pool_4096);
+ add_to_json(json, "9kb", m_mbuf_pool_9k);
}
@@ -548,30 +531,24 @@ void CRteMemPool::dump(FILE *fd){
DUMP_MBUF("mbuf_9k",m_mbuf_pool_9k);
}
-////////////////////////////////////////
-
-std::string CGlobalInfo::dump_pool_as_json(void){
+////////////////////////////////////////
- std::string json="\"mbuf_stats\":{";
+void CGlobalInfo::dump_pool_as_json(Json::Value &json){
CPlatformSocketInfo * lpSocket =&m_socket;
- int last_socket=-1;
- /* calc the last socket */
- int i;
- for (i=0; i<(int)MAX_SOCKETS_SUPPORTED; i++) {
+ for (int i=0; i<(int)MAX_SOCKETS_SUPPORTED; i++) {
if (lpSocket->is_sockets_enable((socket_id_t)i)) {
- last_socket=i;
+ std::string socket_id = "cpu-socket-" + std::to_string(i);
+ m_mem_pool[i].dump_as_json(json["mbuf_stats"][socket_id]);
}
}
+}
- for (i=0; i<(int)MAX_SOCKETS_SUPPORTED; i++) {
- if (lpSocket->is_sockets_enable((socket_id_t)i)) {
- json+=m_mem_pool[i].dump_as_json(i,last_socket==i?true:false);
- }
- }
- json+="},";
- return json;
+std::string CGlobalInfo::dump_pool_as_json_str(void){
+ Json::Value json;
+ dump_pool_as_json(json);
+ return (json.toStyledString());
}
void CGlobalInfo::free_pools(){
@@ -771,9 +748,8 @@ void CPreviewMode::Dump(FILE *fd){
fprintf(fd," 1g mode : %d\n", (int)get_1g_mode() );
fprintf(fd," zmq_publish : %d\n", (int)get_zmq_publish_enable() );
fprintf(fd," vlan_enable : %d\n", (int)get_vlan_mode_enable() );
+ fprintf(fd," client_cfg : %d\n", (int)get_is_client_cfg_enable() );
fprintf(fd," mbuf_cache_disable : %d\n", (int)isMbufCacheDisabled() );
- fprintf(fd," mac_ip_features : %d\n", (int)get_mac_ip_features_enable()?1:0 );
- fprintf(fd," mac_ip_map : %d\n", (int)get_mac_ip_mapping_enable()?1:0 );
fprintf(fd," vm mode : %d\n", (int)get_vm_one_queue_enable()?1:0 );
}
@@ -785,8 +761,10 @@ void CFlowGenStats::clear(){
m_total_close_flows =0;
m_nat_lookup_no_flow_id=0;
m_nat_lookup_remove_flow_id=0;
+ m_nat_lookup_wait_ack_state = 0;
m_nat_lookup_add_flow_id=0;
m_nat_flow_timeout=0;
+ m_nat_flow_timeout_wait_ack = 0;
m_nat_flow_learn_error=0;
}
@@ -815,9 +793,12 @@ void CFlowGenStats::dump(FILE *fd){
DP(m_nat_lookup_no_flow_id);
DP(m_nat_lookup_remove_flow_id);
+ DP(m_nat_lookup_wait_ack_state);
DP(m_nat_lookup_add_flow_id);
DP(m_nat_flow_timeout);
+ DP(m_nat_flow_timeout_wait_ack);
DP_name("active_nat",(m_nat_lookup_add_flow_id-m_nat_lookup_remove_flow_id));
+ DP_name("active_nat_wait_syn", (m_nat_lookup_add_flow_id - m_nat_lookup_wait_ack_state));
DP(m_nat_flow_learn_error);
}
@@ -1962,42 +1943,115 @@ typedef CTmpFlowInfo * flow_tmp_t;
typedef std::map<uint16_t, flow_tmp_t> flow_tmp_map_t;
typedef flow_tmp_map_t::iterator flow_tmp_map_iter_t;
-
-
-bool CCapFileFlowInfo::is_valid_template_load_time(std::string & err){
- err="";
+enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::is_valid_template_load_time(){
int i;
for (i=0; i<Size(); i++) {
CFlowPktInfo * lp= GetPacket((uint32_t)i);
CPacketIndication * lpd=&lp->m_pkt_indication;
if ( lpd->getEtherOffset() !=0 ){
- err=" supported template Ether offset start is 0 \n";
- return (false);
+ fprintf(stderr, "Error: Bad CAP file. Ether offset start is not 0 in packet %d \n", i+1);
+ return kPktNotSupp;
}
- if ( lpd->getIpOffset() !=14 ){
- err=" supported template ip offset is 14 \n";
- return (false);
- }
- if ( lpd->is_ipv6() ){
- if ( lpd->getTcpOffset() != (14+40) ){
- err=" supported template tcp/udp offset is 54, no ipv6 option header is supported \n";
- return (false);
+
+ if ( CGlobalInfo::is_learn_mode() ) {
+ // We change TCP ports. Need them to be in first 64 byte mbuf.
+ // Since we also add IP option, and rx-check feature might add another IP option, better not allow
+ // OP options in this mode. If needed this limitation can be refined a bit.
+ if ( lpd->getTcpOffset() - lpd->getIpOffset() != 20 ) {
+ fprintf(stderr, "Error: Bad CAP file. In learn (NAT) mode, no IP options allowed \n");
+ return kIPOptionNotAllowed;
}
- }else{
- if ( lpd->getTcpOffset() != (14+20) ){
- err=" supported template tcp/udp offset is 34, no ipv4 option is allowed in this version \n";
- return (false);
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP)) {
+ if (lpd->getIpProto() != IPPROTO_TCP && !lpd->m_desc.IsInitSide()) {
+ fprintf(stderr, "Error: In the chosen learn mode, all packets from server to client in CAP file should be TCP.\n");
+ fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n");
+ return kNoTCPFromServer;
+ }
}
}
}
if ( CGlobalInfo::is_learn_mode() ) {
- if ( GetPacket(0)->m_pkt_indication.m_desc.IsPluginEnable() ) {
- err="plugins are not supported with --learn mode \n";
- return(false);
+ CPacketIndication &pkt_0_indication = GetPacket(0)->m_pkt_indication;
+
+ if ( pkt_0_indication.m_desc.IsPluginEnable() ) {
+ fprintf(stderr, "Error: plugins are not supported with --learn mode \n");
+ return kPlugInWithLearn;
+ }
+
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP)) {
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
+ if (Size() < 3) {
+ fprintf(stderr
+ , "Error: In the chosen learn mode, need at least the 3 TCP handshake packets.\n");
+ fprintf(stderr
+ , " Please give different CAP file, or try different --learn-mode\n");
+ return kTCPLearnModeBadFlow;
+ }
+ }
+ CPacketIndication &pkt_1_indication = GetPacket(1)->m_pkt_indication;
+
+
+ // verify first packet is TCP SYN from client
+ TCPHeader *tcp = (TCPHeader *)(pkt_0_indication.getBasePtr() + pkt_0_indication.getTcpOffset());
+ if ( (! pkt_0_indication.m_desc.IsInitSide()) || (! tcp->getSynFlag()) ) {
+ fprintf(stderr, "Error: In the chosen learn mode, first TCP packet should be SYN from client side.\n");
+ fprintf(stderr, " In cap file, first packet side direction is %s. TCP header is:\n"
+ , pkt_0_indication.m_desc.IsInitSide() ? "outside":"inside");
+ tcp->dump(stderr);
+ fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n");
+ return kNoSyn;
+ }
+
+ // We want at least the TCP flags to be inside first mbuf
+ if (pkt_0_indication.getTcpOffset() + 14 > FIRST_PKT_SIZE) {
+ fprintf(stderr
+ , "Error: In the chosen learn mode, TCP flags offset should be less than %d, but it is %d.\n"
+ , FIRST_PKT_SIZE, pkt_0_indication.getTcpOffset() + 14);
+ fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n");
+ return kTCPOffsetTooBig;
+ }
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
+ // To support TCP seq randomization from server to client, we need second packet in flow to be the server SYN+ACK
+ bool error = false;
+ if (pkt_1_indication.getIpProto() != IPPROTO_TCP) {
+ error = true;
+ } else {
+ TCPHeader *tcp = (TCPHeader *)(pkt_1_indication.getBasePtr() + pkt_1_indication.getTcpOffset());
+ if ( (! tcp->getSynFlag()) || (! tcp->getAckFlag()) || ( pkt_1_indication.m_desc.IsInitSide())) {
+ error = true;
+ }
+ }
+ if (error) {
+ fprintf(stderr, "Error: In the chosen learn mode, second packet should be SYN+ACK from server.\n");
+ fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n");
+ return kNoTCPSynAck;
+ }
+
+ CPacketIndication &pkt_2_indication = GetPacket(2)->m_pkt_indication;
+ if ( (! pkt_2_indication.m_desc.IsInitSide()) ) {
+ fprintf(stderr
+ , "Error: Wrong third packet. In the chosen learn mode, need at least the 3 TCP handshake packets.\n");
+ fprintf(stderr
+ , " Please give different CAP file, or try different --learn-mode\n");
+ return kTCPLearnModeBadFlow;
+ }
+ if ((pkt_0_indication.m_cap_ipg < (double)LEARN_MODE_MIN_IPG / 1000)
+ || (pkt_1_indication.m_cap_ipg < (double)LEARN_MODE_MIN_IPG / 1000)) {
+ fprintf(stderr
+ , "Error: Bad cap file timings. In the chosen learn mode");
+ fprintf(stderr, "IPG between TCP handshake packets should be at least %d msec.\n", LEARN_MODE_MIN_IPG);
+ fprintf(stderr, " Current delay is %f between second and first, %f between third and second"
+ , pkt_0_indication.m_cap_ipg, pkt_1_indication.m_cap_ipg);
+ fprintf(stderr
+ , " Please give different CAP file, try different --learn-mode, or edit ipg parameters in template file\n");
+ return kTCPIpgTooLow;
+ }
+ }
}
}
- return(true);
+
+ return(kOK);
}
@@ -2085,6 +2139,13 @@ void CCapFileFlowInfo::update_info(){
if ( lp->m_pkt_indication.m_desc.IsBiDirectionalFlow() ){
lp->mask_as_learn();
}
+
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
+ // In this mode, we need to see the SYN+ACK as well.
+ lp = GetPacket(1);
+ assert(lp);
+ lp->m_pkt_indication.setTTL(TTL_RESERVE_DUPLICATE);
+ }
}
if ( ft.empty() )
@@ -2124,7 +2185,6 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st
m_total_errors=0;
CFlow * first_flow=0;
bool first_flow_fif_is_swap=false;
-
bool time_was_set=false;
double last_time=0.0;
CCapPktRaw raw_packet;
@@ -2199,35 +2259,10 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st
m_total_errors++;
}
}
-
- if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
- // in this mode, first TCP packet must be SYN from client.
- if (pkt_indication.getIpProto() == IPPROTO_TCP) {
- TCPHeader *tcp = (TCPHeader *)(pkt_indication.getBasePtr() + pkt_indication.getTcpOffset());
- if ( (! pkt_indication.m_desc.IsInitSide()) || (! tcp->getSynFlag()) ) {
- fprintf(stderr, "Error: In the chosen learn mode, first TCP packet should be SYN from client side.\n");
- fprintf(stderr, " In cap file, first packet side direction is %s. TCP header is:\n", pkt_indication.m_desc.IsInitSide() ? "outside":"inside");
- tcp->dump(stderr);
- fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n");
-
- return kNoSyn;
- }
- // We want at least the TCP flags to be inside first mbuf
- if (pkt_indication.getTcpOffset() + 14 > FIRST_PKT_SIZE) {
- fprintf(stderr, "Error: In the chosen learn mode, first TCP packet TCP flags offset should be less than %d, but it is %d.\n"
- , FIRST_PKT_SIZE, pkt_indication.getTcpOffset() + 14);
- fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n");
- return kTCPOffsetTooBig;
- }
- }
- }
-
}else{ /* no FIF */
-
pkt_indication.m_desc.SetFlowId(lpflow->flow_id);
if ( multi_flow_enable ==false ){
-
if (lpflow == first_flow) {
// add to
bool init_side=
@@ -2249,16 +2284,6 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st
}
}
-
- if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
- // This test must be down here, after initializing init side indication
- if (pkt_indication.getIpProto() != IPPROTO_TCP && !pkt_indication.m_desc.IsInitSide()) {
- fprintf(stderr, "Error: In the chosen learn mode, all packets from server to client in CAP file should be TCP.\n");
- fprintf(stderr, " Please give different CAP file, or try different --learn-mode\n");
- return kNoTCPFromServer;
- }
- }
-
}else{
fprintf(stderr, "ERROR packet %d is not supported, should be Ethernet/IP(0x0800)/(TCP|UDP) format try to convert it using Wireshark !\n",cnt);
return kPktNotSupp;
@@ -2269,7 +2294,6 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st
}
}
-
/* set the last */
CFlowPktInfo * last_pkt =GetPacket((uint32_t)(Size()-1));
last_pkt->m_pkt_indication.m_desc.SetIsLastPkt(true);
@@ -2282,9 +2306,6 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st
lp_prev->m_pkt_indication.m_cap_ipg = lp->m_pkt_indication.m_cap_ipg-
lp_prev->m_pkt_indication.m_cap_ipg;
-
-
-
if ( lp->m_pkt_indication.m_desc.IsInitSide() !=
lp_prev->m_pkt_indication.m_desc.IsInitSide()) {
lp_prev->m_pkt_indication.m_desc.SetRtt(true);
@@ -2449,26 +2470,6 @@ void CCapFileFlowInfo::Delete(){
RemoveAll();
}
-void operator >> (const YAML::Node& node, mac_mapping_t &fi) {
- utl_yaml_read_ip_addr(node,"ip", fi.ip);
- const YAML::Node& mac_info = node["mac"];
- for(unsigned i=0;i<mac_info.size();i++) {
- const YAML::Node & node_2 =mac_info;
- uint32_t value;
- node_2[i] >> value;
- fi.mac.mac[i] = value;
- }
-}
-
-void operator >> (const YAML::Node& node, std::map<uint32_t, mac_addr_align_t> &mac_info) {
- const YAML::Node& mac_node = node["items"];
- mac_mapping_t mac_mapping;
- for (unsigned i=0;i<mac_node.size();i++) {
- mac_node[i] >> mac_mapping;
- mac_info[mac_mapping.ip] = mac_mapping.mac;
- }
-}
-
void operator >> (const YAML::Node& node, CFlowYamlDpPkt & fi) {
uint32_t val;
node["pkt_id"] >> val;
@@ -3166,11 +3167,8 @@ bool CFlowGeneratorRec::Create(CFlowYamlInfo * info,
int res=m_flow_info.load_cap_file(info->m_name.c_str(),_id,m_info->m_plugin_id);
if ( res==0 ) {
fixup_ipg_if_needed();
- std::string err;
- /* verify that template are valid */
- bool is_valid=m_flow_info.is_valid_template_load_time(err);
- if (!is_valid) {
- printf("\n ERROR template file is not valid '%s' \n",err.c_str());
+
+ if (m_flow_info.is_valid_template_load_time() != 0) {
return (false);
}
m_flow_info.update_info();
@@ -3348,7 +3346,7 @@ bool CFlowGenListPerThread::Create(uint32_t thread_id,
/* split the clients to threads */
CTupleGenYamlInfo * tuple_gen = &m_flow_list->m_yaml_info.m_tuple_gen;
- m_smart_gen.Create(0,m_thread_id,m_flow_list->get_is_mac_conf());
+ m_smart_gen.Create(0,m_thread_id);
/* split the clients to threads using the mask */
CIpPortion portion;
@@ -3358,14 +3356,14 @@ bool CFlowGenListPerThread::Create(uint32_t thread_id,
portion);
m_smart_gen.add_client_pool(tuple_gen->m_client_pool[i].m_dist,
- portion.m_ip_start,
- portion.m_ip_end,
- get_longest_flow(i,true),
- get_total_kcps(i,true)*1000,
- &m_flow_list->m_mac_info,
- tuple_gen->m_client_pool[i].m_tcp_aging_sec,
- tuple_gen->m_client_pool[i].m_udp_aging_sec
- );
+ portion.m_ip_start,
+ portion.m_ip_end,
+ get_longest_flow(i,true),
+ get_total_kcps(i,true)*1000,
+ m_flow_list->m_client_config_info,
+ tuple_gen->m_client_pool[i].m_tcp_aging_sec,
+ tuple_gen->m_client_pool[i].m_udp_aging_sec
+ );
}
for (int i=0;i<tuple_gen->m_server_pool.size();i++) {
split_ips(m_thread_id, m_max_threads, getDualPortId(),
@@ -3744,11 +3742,11 @@ inline int CNodeGenerator::teardown(CFlowGenListPerThread * thread,
}
return (0);
}
-
+
template<int SCH_MODE>
-inline int CNodeGenerator::flush_file_realtime(dsec_t max_time,
+inline int CNodeGenerator::flush_file_realtime(dsec_t max_time,
dsec_t d_time,
bool always,
CFlowGenListPerThread * thread,
@@ -3767,9 +3765,9 @@ inline int CNodeGenerator::flush_file_realtime(dsec_t max_time,
sch_state_t state = scINIT;
node = m_p_queue.top();
- n_time = node->m_time + offset;
+ n_time = node->m_time + offset;
cur_time = now_sec();
-
+
while (state!=scTERMINATE) {
switch (state) {
@@ -3795,7 +3793,7 @@ inline int CNodeGenerator::flush_file_realtime(dsec_t max_time,
break;
}
node = m_p_queue.top();
- n_time = node->m_time + offset;
+ n_time = node->m_time + offset;
if ((n_time-cur_time)>EAT_WINDOW_DTIME) {
state=scINIT;
@@ -3805,7 +3803,7 @@ inline int CNodeGenerator::flush_file_realtime(dsec_t max_time,
break;
case scWAIT:
- do_sleep(cur_time,thread,n_time); // estimate loop
+ do_sleep(cur_time,thread,n_time); // estimate loop
state=scWORK;
break;
default:
@@ -3816,7 +3814,7 @@ inline int CNodeGenerator::flush_file_realtime(dsec_t max_time,
return (teardown(thread,always,old_offset,offset));
}
-FORCE_NO_INLINE int CNodeGenerator::flush_file_sim(dsec_t max_time,
+FORCE_NO_INLINE int CNodeGenerator::flush_file_sim(dsec_t max_time,
dsec_t d_time,
bool always,
CFlowGenListPerThread * thread,
@@ -3843,7 +3841,7 @@ FORCE_NO_INLINE int CNodeGenerator::flush_file_sim(dsec_t max_time,
return (teardown(thread,always,old_offset,0));
}
-int CNodeGenerator::flush_file(dsec_t max_time,
+int CNodeGenerator::flush_file(dsec_t max_time,
dsec_t d_time,
bool always,
CFlowGenListPerThread * thread,
@@ -3864,7 +3862,7 @@ int CNodeGenerator::flush_file(dsec_t max_time,
void CNodeGenerator::handle_flow_pkt(CGenNode *node, CFlowGenListPerThread *thread) {
- /*repeat and NAT is not supported */
+ /*repeat and NAT is not supported together */
if ( node->is_nat_first_state() ) {
node->set_nat_wait_state();
flush_one_node_to_file(node);
@@ -3875,7 +3873,7 @@ void CNodeGenerator::handle_flow_pkt(CGenNode *node, CFlowGenListPerThread *thre
if ( node->is_nat_wait_state() ) {
if (node->is_responder_pkt()) {
m_p_queue.pop();
- /* time out, need to free the flow and remove the association , we didn't get convertion yet*/
+ /* time out, need to free the flow and remove the association , we didn't get conversion yet*/
thread->terminate_nat_flows(node);
return;
@@ -3886,7 +3884,22 @@ void CNodeGenerator::handle_flow_pkt(CGenNode *node, CFlowGenListPerThread *thre
#endif
}
} else {
- assert(0);
+ if ( node->is_nat_wait_ack_state() ) {
+ if (node->is_initiator_pkt()) {
+ m_p_queue.pop();
+ /* time out, need to free the flow and remove the association , we didn't get conversion yet*/
+ thread->terminate_nat_flows(node);
+ return;
+
+ } else {
+ flush_one_node_to_file(node);
+#ifdef _DEBUG
+ update_stats(node);
+#endif
+ }
+ } else {
+ assert(0);
+ }
}
}
m_p_queue.pop();
@@ -4166,6 +4179,11 @@ int CFlowGenListPerThread::reschedule_flow(CGenNode *node){
void CFlowGenListPerThread::terminate_nat_flows(CGenNode *p){
m_stats.m_nat_flow_timeout++;
m_stats.m_nat_lookup_remove_flow_id++;
+ if (p->is_nat_wait_ack_state()) {
+ m_stats.m_nat_flow_timeout_wait_ack++;
+ } else {
+ m_stats.m_nat_lookup_wait_ack_state++;
+ }
m_flow_id_to_node_lookup.remove_no_lookup(p->get_short_fid());
free_last_flow_node( p);
}
@@ -4190,38 +4208,74 @@ void CFlowGenListPerThread::handle_latency_pkt_msg(CGenNodeLatencyPktInfo * msg)
m_node_gen.m_v_if->send_one_pkt((pkt_dir_t)msg->m_dir,msg->m_pkt);
}
-
void CFlowGenListPerThread::handle_nat_msg(CGenNodeNatInfo * msg){
int i;
+ bool first = true, second = true;
+
for (i=0; i<msg->m_cnt; i++) {
+ first = true;
+ second = true;
CNatFlowInfo * nat_msg=&msg->m_data[i];
CGenNode * node=m_flow_id_to_node_lookup.lookup(nat_msg->m_fid);
if (!node) {
- /* this should be move to a notification module */
- #ifdef NAT_TRACE_
+ /* this should be moved to a notification module */
+#ifdef NAT_TRACE_
printf(" ERORR not valid flow_id %d probably flow was aged \n",nat_msg->m_fid);
- #endif
+#endif
m_stats.m_nat_lookup_no_flow_id++;
continue;
}
- #ifdef NAT_TRACE_
- printf(" %.03f RX :set node %p:%x %x:%x:%x \n",now_sec() ,node,nat_msg->m_fid,nat_msg->m_external_ip,nat_msg->m_external_ip_server,nat_msg->m_external_port);
- #endif
- node->set_nat_ipv4_addr(nat_msg->m_external_ip);
- node->set_nat_ipv4_port(nat_msg->m_external_port);
- node->set_nat_ipv4_addr_server(nat_msg->m_external_ip_server);
-
- assert(node->is_nat_wait_state());
- if ( CGlobalInfo::is_learn_verify_mode() ){
- if (!node->is_external_is_eq_to_internal_ip() ){
- m_stats.m_nat_flow_learn_error++;
+
+ // Calculate diff between tcp seq of SYN packet, and TCP ack of SYN+ACK packet
+ // For supporting firewalls who do TCP seq num randomization
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP)) {
+ if (node->is_nat_wait_state()) {
+ char *syn_pkt = node->m_flow_info->GetPacket(0)->m_packet->raw;
+ TCPHeader *tcp = (TCPHeader *)(syn_pkt + node->m_pkt_info->m_pkt_indication.getFastTcpOffset());
+ node->set_nat_tcp_seq_diff_client(nat_msg->m_tcp_seq - tcp->getSeqNumber());
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
+ node->set_nat_wait_ack_state();
+ m_stats.m_nat_lookup_wait_ack_state++;
+ second = false;
+ } else {
+ node->set_nat_learn_state();
+ }
+ } else {
+ char *syn_ack_pkt = node->m_flow_info->GetPacket(1)->m_packet->raw;
+ TCPHeader *tcp = (TCPHeader *)(syn_ack_pkt + node->m_pkt_info->m_pkt_indication.getFastTcpOffset());
+ node->set_nat_tcp_seq_diff_server(nat_msg->m_tcp_seq - tcp->getSeqNumber());
+ assert(node->is_nat_wait_ack_state());
+ node->set_nat_learn_state();
+ first = false;
+ }
+ } else {
+ assert(node->is_nat_wait_state());
+ node->set_nat_learn_state();
+ }
+
+ if (first) {
+#ifdef NAT_TRACE_
+ printf(" %.03f RX :set node %p:%x %x:%x TCP diff %x\n"
+ , now_sec(), node,nat_msg->m_fid, nat_msg->m_external_ip, nat_msg->m_external_port
+ , node->get_nat_tcp_seq_diff_client());
+#endif
+
+ node->set_nat_ipv4_addr(nat_msg->m_external_ip);
+ node->set_nat_ipv4_port(nat_msg->m_external_port);
+
+ if ( CGlobalInfo::is_learn_verify_mode() ){
+ if (!node->is_external_is_eq_to_internal_ip() ||
+ node->get_nat_tcp_seq_diff_client() != 0) {
+ m_stats.m_nat_flow_learn_error++;
+ }
}
}
- node->set_nat_learn_state();
- /* remove from the hash */
- m_flow_id_to_node_lookup.remove_no_lookup(nat_msg->m_fid);
- m_stats.m_nat_lookup_remove_flow_id++;
+ if (second) {
+ /* remove from the hash */
+ m_flow_id_to_node_lookup.remove_no_lookup(nat_msg->m_fid);
+ m_stats.m_nat_lookup_remove_flow_id++;
+ }
}
}
@@ -4317,7 +4371,7 @@ void CFlowGenListPerThread::start_generate_stateful(std::string erf_file_name,
fprintf(stderr," nothing to generate no template loaded \n");
return;
}
-
+
m_preview_mode = preview;
m_node_gen.open_file(erf_file_name,&m_preview_mode);
dsec_t d_time_flow=get_delta_flow_is_sec();
@@ -4419,32 +4473,11 @@ void CFlowGenList::clean_p_thread_info(void){
m_threads_info.clear();
}
-
-
-int CFlowGenList::load_from_mac_file(std::string file_name) {
- if ( !utl_is_file_exists (file_name) ){
- printf(" ERROR no mac_file is set, file %s does not exist \n",file_name.c_str());
- exit(-1);
- }
- m_mac_info.set_configured(true);
-
- try {
- std::ifstream fin((char *)file_name.c_str());
- YAML::Parser parser(fin);
- YAML::Node doc;
-
- parser.GetNextDocument(doc);
- doc[0] >> m_mac_info.get_mac_info();
- } catch ( const std::exception& e ) {
- std::cout << e.what() << "\n";
- m_mac_info.clear();
- exit(-1);
- }
-
- return (0);
+int CFlowGenList::load_client_config_file(std::string file_name) {
+ m_client_config_info.load_yaml_file(file_name);
+ return (0);
}
-
int CFlowGenList::load_from_yaml(std::string file_name,
uint32_t num_threads){
uint8_t idx;
@@ -4524,6 +4557,16 @@ double CFlowGenList::GetCpuUtil(){
return (c/m_threads_info.size());
}
+double CFlowGenList::GetCpuUtilRaw(){
+ int i;
+ double c=0.0;
+ for (i=0; i<(int)m_threads_info.size(); i++) {
+ CFlowGenListPerThread * lp=m_threads_info[i];
+ c+=lp->m_cpu_cp_u.GetValRaw();
+ }
+ return (c/m_threads_info.size());
+}
+
void CFlowGenList::UpdateFast(){
@@ -4755,21 +4798,20 @@ bool CParserOption::is_valid_opt_val(int val, int min, int max, const std::strin
void CParserOption::dump(FILE *fd){
preview.Dump(fd);
- fprintf(fd," cfg file : %s \n",cfg_file.c_str());
- fprintf(fd," mac file : %s \n",mac_file.c_str());
- fprintf(fd," out file : %s \n",out_file.c_str());
- fprintf(fd," duration : %.0f \n",m_duration);
- fprintf(fd," factor : %.0f \n",m_factor);
- fprintf(fd," mbuf_factor : %.0f \n",m_mbuf_factor);
- fprintf(fd," latency : %d pkt/sec \n",m_latency_rate);
- fprintf(fd," zmq_port : %d \n",m_zmq_port);
- fprintf(fd," telnet_port : %d \n",m_telnet_port);
- fprintf(fd," expected_ports : %d \n",m_expected_portd);
+ fprintf(fd," cfg file : %s \n",cfg_file.c_str());
+ fprintf(fd," mac file : %s \n",client_cfg_file.c_str());
+ fprintf(fd," out file : %s \n",out_file.c_str());
+ fprintf(fd," client cfg file : %s \n",out_file.c_str());
+ fprintf(fd," duration : %.0f \n",m_duration);
+ fprintf(fd," factor : %.0f \n",m_factor);
+ fprintf(fd," mbuf_factor : %.0f \n",m_mbuf_factor);
+ fprintf(fd," latency : %d pkt/sec \n",m_latency_rate);
+ fprintf(fd," zmq_port : %d \n",m_zmq_port);
+ fprintf(fd," telnet_port : %d \n",m_telnet_port);
+ fprintf(fd," expected_ports : %d \n",m_expected_portd);
if (preview.get_vlan_mode_enable() ) {
- fprintf(fd," vlans : [%d,%d] \n",m_vlan_port[0],m_vlan_port[1]);
+ fprintf(fd," vlans : [%d,%d] \n",m_vlan_port[0],m_vlan_port[1]);
}
- fprintf(fd," mac spreading: %d \n",(int)m_mac_splitter);
-
int i;
for (i = 0; i < TREX_MAX_PORTS; i++) {
@@ -4782,6 +4824,15 @@ void CParserOption::dump(FILE *fd){
}
}
+void CParserOption::verify() {
+ /* check for mutual exclusion options */
+ if (preview.get_is_client_cfg_enable()) {
+ if (preview.get_vlan_mode_enable() || preview.get_mac_ip_overide_enable()) {
+ throw std::runtime_error("VLAN / MAC override cannot be combined with client configuration");
+ }
+ }
+}
+
#if 0
void CTupleGlobalGenerator::Dump(FILE *fd){
@@ -5068,37 +5119,68 @@ int CErfIFStl::send_node(CGenNode * _no_to_use){
return (0);
}
+void CErfIF::add_vlan(uint16_t vlan_id) {
+ uint8_t *buffer =(uint8_t *)m_raw->raw;
+ uint16_t vlan_protocol = EthernetHeader::Protocol::VLAN;
+ uint32_t vlan_tag = (vlan_protocol << 16) | vlan_id;
+ vlan_tag = PKT_HTONL(vlan_tag);
-int CErfIF::send_node(CGenNode * node){
+ /* insert vlan tag and adjust packet size */
+ memcpy(cbuff+4, buffer + 12, m_raw->pkt_len - 12);
+ memcpy(cbuff, &vlan_tag, 4);
+ memcpy(buffer + 12, cbuff, m_raw->pkt_len - 8);
- if ( m_preview_mode->getFileWrite() ){
+ m_raw->pkt_len += 4;
+}
- CFlowPktInfo * lp=node->m_pkt_info;
- rte_mbuf_t * m=lp->generate_new_mbuf(node);
- pkt_dir_t dir=node->cur_interface_dir();
+void CErfIF::apply_client_config(const ClientCfg *cfg, pkt_dir_t dir) {
+ assert(cfg);
+ uint8_t *p = (uint8_t *)m_raw->raw;
- fill_raw_packet(m,node,dir);
+ const ClientCfgDir &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
+
+ /* dst mac */
+ if (cfg_dir.has_dst_mac_addr()) {
+ memcpy(p, cfg_dir.get_dst_mac_addr(), 6);
+ }
+
+ /* src mac */
+ if (cfg_dir.has_src_mac_addr()) {
+ memcpy(p + 6, cfg_dir.get_src_mac_addr(), 6);
+ }
+
+ /* VLAN */
+ if (cfg_dir.has_vlan()) {
+ add_vlan(cfg_dir.get_vlan());
+ }
+}
+
+int CErfIF::send_node(CGenNode *node){
+
+ if (!m_preview_mode->getFileWrite()) {
+ return (0);
+ }
+
+ CFlowPktInfo *lp = node->m_pkt_info;
+ rte_mbuf_t *m = lp->generate_new_mbuf(node);
+ pkt_dir_t dir = node->cur_interface_dir();
+
+ fill_raw_packet(m, node, dir);
/* update mac addr dest/src 12 bytes */
uint8_t *p=(uint8_t *)m_raw->raw;
int p_id=(int)dir;
memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12);
- /* If vlan is enabled, add vlan header */
- if ( unlikely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){
- /* retrieve vlan ID and form vlan tag */
- uint8_t vlan_port = (node->m_src_ip &1);
- uint16_t vlan_protocol = EthernetHeader::Protocol::VLAN;
- uint16_t vlan_id = CGlobalInfo::m_options.m_vlan_port[vlan_port];
- uint32_t vlan_tag = (vlan_protocol << 16) | vlan_id;
- vlan_tag = PKT_HTONL(vlan_tag);
+ /* if a client configuration was provided - apply the config */
+ if (CGlobalInfo::m_options.preview.get_is_client_cfg_enable()) {
+ apply_client_config(node->m_client_cfg, dir);
- /* insert vlan tag and adjust packet size */
- memcpy(cbuff+4, p+12, m_raw->pkt_len-12);
- memcpy(cbuff, &vlan_tag, 4);
- memcpy(p+12, cbuff, m_raw->pkt_len-8);
- m_raw->pkt_len += 4;
+ } else if (CGlobalInfo::m_options.preview.get_vlan_mode_enable()) {
+ uint8_t vlan_port = (node->m_src_ip & 1);
+ uint16_t vlan_id = CGlobalInfo::m_options.m_vlan_port[vlan_port];
+ add_vlan(vlan_id);
}
//utl_DumpBuffer(stdout,p, 12,0);
@@ -5107,8 +5189,8 @@ int CErfIF::send_node(CGenNode * node){
BP_ASSERT(rc == 0);
rte_pktmbuf_free(m);
- }
- return (0);
+
+ return (0);
}
int CErfIF::flush_tx_queue(void){
@@ -6438,7 +6520,7 @@ void CGenNodeBase::free_base(){
CGenNodePCAP *p = (CGenNodePCAP *)this;
p->destroy();
return;
- }
+ }
if ( m_type == COMMAND ) {
CGenNodeCommand* p=(CGenNodeCommand*)this;
@@ -6446,4 +6528,3 @@ void CGenNodeBase::free_base(){
}
}
-
diff --git a/src/bp_sim.h b/src/bp_sim.h
index 18db61ca..b4ef54d1 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -59,6 +59,7 @@ limitations under the License.
#include "platform_cfg.h"
#include "flow_stat.h"
#include "trex_watchdog.h"
+#include "trex_client_config.h"
#include <trex_stateless_dp_core.h>
@@ -68,8 +69,6 @@ limitations under the License.
class CGenNodePCAP;
-#undef NAT_TRACE_
-
#define FORCE_NO_INLINE __attribute__ ((noinline))
#define FORCE_INLINE __attribute__((always_inline))
@@ -87,10 +86,6 @@ typedef struct {
*/
#define INET_PORTSTRLEN 5
-
-
-
-
/* VM commands */
class CMiniVMCmdBase {
@@ -186,6 +181,12 @@ inline int ip_to_str(uint32_t ip,char * str){
return(strlen(str));
}
+inline std::string ip_to_str(uint32_t ip) {
+ char tmp[INET_ADDRSTRLEN];
+ ip_to_str(ip, tmp);
+ return tmp;
+}
+
// Routine to create IPv6 address string
inline int ipv6_to_str(ipaddr_t *ip,char * str){
int idx=0;
@@ -627,7 +628,7 @@ public:
void set_mac_ip_overide_enable(bool enable){
btSetMaskBit32(m_flags,30,30,enable?1:0);
if (enable) {
- set_mac_ip_features_enable(enable);
+ set_slowpath_features_on(enable);
}
}
@@ -639,26 +640,27 @@ public:
btSetMaskBit32(m_flags,31,31,enable?1:0);
}
-
- bool get_mac_ip_features_enable(){
- return (btGetMaskBit32(m_flags1,0,0) ? true:false);
+ bool get_is_slowpath_features_on() {
+ return (btGetMaskBit32(m_flags1, 0, 0) ? true : false);
}
- void set_mac_ip_features_enable(bool enable){
- btSetMaskBit32(m_flags1,0,0,enable?1:0);
+ void set_slowpath_features_on(bool enable) {
+ btSetMaskBit32(m_flags1, 0, 0, enable ? 1 : 0);
}
- bool get_mac_ip_mapping_enable(){
- return (btGetMaskBit32(m_flags1,1,1) ? true:false);
+ bool get_is_client_cfg_enable() {
+ return (btGetMaskBit32(m_flags1, 1, 1) ? true : false);
}
- void set_mac_ip_mapping_enable(bool enable){
- btSetMaskBit32(m_flags1,1,1,enable?1:0);
+ void set_client_cfg_enable(bool enable){
+ btSetMaskBit32(m_flags1, 1, 1, enable ? 1 : 0);
if (enable) {
- set_mac_ip_features_enable(enable);
+ set_slowpath_features_on(enable);
}
}
+
+
bool get_vm_one_queue_enable(){
return (btGetMaskBit32(m_flags1,2,2) ? true:false);
}
@@ -684,16 +686,6 @@ public:
return (btGetMaskBit32(m_flags1,3,3) ? true:false);
}
-
- /* split mac is enabled */
- void setDestMacSplit(bool enable){
- btSetMaskBit32(m_flags1,4,4,enable?1:0);
- }
-
- bool getDestMacSplit(){
- return (btGetMaskBit32(m_flags1,4,4) ? true:false);
- }
-
/* split mac is enabled */
void setWDDisable(bool wd_disable){
btSetMaskBit32(m_flags1,6,6,wd_disable?1:0);
@@ -771,7 +763,10 @@ public:
LEARN_MODE_DISABLED=0,
LEARN_MODE_TCP_ACK=1,
LEARN_MODE_IP_OPTION=2,
- LEARN_MODE_MAX=LEARN_MODE_IP_OPTION
+ LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND=3,
+ LEARN_MODE_MAX=LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND,
+ // This is used to check if 1 or 3 exist
+ LEARN_MODE_TCP=100
};
public:
@@ -782,6 +777,7 @@ public:
m_latency_rate =0;
m_latency_mask =0xffffffff;
m_latency_prev=0;
+ m_wait_before_traffic=1;
m_zmq_port=4500;
m_telnet_port =4501;
m_platform_factor=1.0;
@@ -793,7 +789,6 @@ public:
m_io_mode=1;
m_run_flags=0;
prefix="";
- m_mac_splitter=0;
m_run_mode = RUN_MODE_INVALID;
m_l_pkt_mode = 0;
m_rx_thread_enabled = false;
@@ -812,6 +807,7 @@ public:
uint32_t m_latency_rate; /* pkt/sec for each thread/port zero disable */
uint32_t m_latency_mask;
uint32_t m_latency_prev;
+ uint32_t m_wait_before_traffic;
uint16_t m_rx_check_sample; /* the sample rate of flows */
uint16_t m_rx_check_hops;
uint16_t m_zmq_port;
@@ -819,7 +815,6 @@ public:
uint16_t m_expected_portd;
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_l_pkt_mode;
uint8_t m_learn_mode;
uint16_t m_debug_pkt_proto;
@@ -829,7 +824,7 @@ public:
std::string cfg_file;
- std::string mac_file;
+ std::string client_cfg_file;
std::string platform_cfg_file;
std::string out_file;
@@ -887,6 +882,8 @@ public:
}
void dump(FILE *fd);
bool is_valid_opt_val(int val, int min, int max, const std::string &opt_name);
+
+ void verify();
};
@@ -1196,13 +1193,10 @@ public:
void dump_in_case_of_error(FILE *fd);
- std::string dump_as_json(uint8_t id,bool last);
+ void dump_as_json(Json::Value &json);
private:
- std::string add_to_json(std::string name,
- rte_mempool_t * pool,
- bool last=false);
-
+ void add_to_json(Json::Value &json, std::string name, rte_mempool_t * pool);
public:
rte_mempool_t * m_small_mbuf_pool; /* pool for start packets */
@@ -1261,7 +1255,11 @@ public:
}
static inline bool is_learn_mode(CParserOption::trex_learn_mode_e mode){
- return ( (m_options.m_learn_mode == mode));
+ if (mode == CParserOption::LEARN_MODE_TCP) {
+ return ((m_options.m_learn_mode == CParserOption::LEARN_MODE_TCP_ACK_NO_SERVER_SEQ_RAND)
+ || (m_options.m_learn_mode == CParserOption::LEARN_MODE_TCP_ACK));
+ } else
+ return (m_options.m_learn_mode == mode);
}
static inline bool is_ipv6_enable(void){
@@ -1296,7 +1294,8 @@ public:
}
- static std::string dump_pool_as_json(void);
+ static void dump_pool_as_json(Json::Value &json);
+ static std::string dump_pool_as_json_str(void);
public:
@@ -1572,12 +1571,12 @@ public:
CTupleGeneratorSmart *m_tuple_gen;
// cache line 1 - 64bytes waste of space !
- uint32_t m_nat_external_ipv4; /* client */
- uint32_t m_nat_external_ipv4_server;
- uint16_t m_nat_external_port;
-
- uint16_t m_nat_pad[3];
- mac_addr_align_t m_src_mac;
+ uint32_t m_nat_external_ipv4; // NAT client IP
+ uint32_t m_nat_tcp_seq_diff_client; // support for firewalls that do TCP seq num randomization
+ uint32_t m_nat_tcp_seq_diff_server; // And some do seq num randomization for server->client also
+ uint16_t m_nat_external_port; // NAT client port
+ uint16_t m_nat_pad[1];
+ const ClientCfg *m_client_cfg;
uint32_t m_src_idx;
uint32_t m_dest_idx;
uint32_t m_end_of_cache_line[6];
@@ -1713,6 +1712,15 @@ public:
return (btGetMaskBit16(m_flags,4,3)==2?true:false) ;
}
+ // We saw first TCP SYN. Waiting for SYN+ACK
+ inline void set_nat_wait_ack_state() {
+ btSetMaskBit16(m_flags, 4, 3, 3);
+ }
+
+ inline bool is_nat_wait_ack_state(){
+ return (btGetMaskBit16(m_flags,4,3) == 3) ? true : false;
+ }
+
inline void set_nat_learn_state(){
m_type=FLOW_PKT; /* normal operation .. repeat might work too */
}
@@ -1726,14 +1734,21 @@ public:
return (m_thread_id);
}
- inline void set_nat_ipv4_addr_server(uint32_t ip){
- m_nat_external_ipv4_server =ip;
+ inline void set_nat_tcp_seq_diff_client(uint32_t diff) {
+ m_nat_tcp_seq_diff_client = diff;
+ }
+
+ inline uint32_t get_nat_tcp_seq_diff_client() {
+ return m_nat_tcp_seq_diff_client;
}
- inline uint32_t get_nat_ipv4_addr_server(){
- return ( m_nat_external_ipv4_server );
+ inline void set_nat_tcp_seq_diff_server(uint32_t diff) {
+ m_nat_tcp_seq_diff_server = diff;
}
+ inline uint32_t get_nat_tcp_seq_diff_server() {
+ return m_nat_tcp_seq_diff_server;
+ }
inline void set_nat_ipv4_addr(uint32_t ip){
m_nat_external_ipv4 =ip;
@@ -1754,8 +1769,7 @@ public:
bool is_external_is_eq_to_internal_ip(){
/* this API is used to check TRex itself */
if ( (get_nat_ipv4_addr() == m_src_ip ) &&
- (get_nat_ipv4_port()==m_src_port) &&
- ( get_nat_ipv4_addr_server() == m_dest_ip) ) {
+ (get_nat_ipv4_port()==m_src_port)) {
return (true);
}else{
return (false);
@@ -1869,8 +1883,10 @@ public:
uint64_t m_total_close_flows;
uint64_t m_nat_lookup_no_flow_id;
uint64_t m_nat_lookup_remove_flow_id;
+ uint64_t m_nat_lookup_wait_ack_state;
uint64_t m_nat_lookup_add_flow_id;
uint64_t m_nat_flow_timeout;
+ uint64_t m_nat_flow_timeout_wait_ack;
uint64_t m_nat_flow_learn_error;
public:
@@ -1923,7 +1939,8 @@ public:
protected:
-
+ void add_vlan(uint16_t vlan_id);
+ void apply_client_config(const ClientCfg *cfg, pkt_dir_t dir);
virtual void fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir);
CFileWriterBase * m_writer;
@@ -3017,6 +3034,8 @@ inline void CFlowPktInfo::update_pkt_info(char *p,
(void)et;
uint16_t src_port = node->m_src_port;
+ uint32_t tcp_seq_diff_client = 0;
+ uint32_t tcp_seq_diff_server = 0;
pkt_dir_t ip_dir = node->cur_pkt_ip_addr_dir();
pkt_dir_t port_dir = node->cur_pkt_port_addr_dir();
@@ -3037,7 +3056,6 @@ inline void CFlowPktInfo::update_pkt_info(char *p,
}else{
if ( unlikely ( CGlobalInfo::is_learn_mode() ) ){
-
if (m_pkt_indication.m_desc.IsLearn()) {
/* might be done twice */
#ifdef NAT_TRACE_
@@ -3046,42 +3064,48 @@ inline void CFlowPktInfo::update_pkt_info(char *p,
ipv4->setTimeToLive(TTL_RESERVE_DUPLICATE);
/* first ipv4 option add the info in case of learn packet, usualy only the first packet */
- if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION)) {
- CNatOption *lpNat =(CNatOption *)ipv4->getOption();
- lpNat->set_fid(node->get_short_fid());
- lpNat->set_thread_id(node->get_thread_id());
- } else {
- // This method only work on first TCP SYN
- if (ipv4->getProtocol() == IPPROTO_TCP) {
- TCPHeader *tcp = (TCPHeader *)(((uint8_t *)ipv4) + ipv4->getHeaderLength());
- if (tcp->getSynFlag()) {
- tcp->setAckNumber(CNatRxManager::calc_tcp_ack_val(node->get_short_fid(), node->get_thread_id()));
- }
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION)) {
+ CNatOption *lpNat =(CNatOption *)ipv4->getOption();
+ lpNat->set_fid(node->get_short_fid());
+ lpNat->set_thread_id(node->get_thread_id());
+ } else {
+ // This method only work on first TCP SYN
+ if (ipv4->getProtocol() == IPPROTO_TCP) {
+ TCPHeader *tcp = (TCPHeader *)(((uint8_t *)ipv4) + ipv4->getHeaderLength());
+ if (tcp->getSynFlag()) {
+ tcp->setAckNumber(CNatRxManager::calc_tcp_ack_val(node->get_short_fid(), node->get_thread_id()));
+ }
#ifdef NAT_TRACE_
- printf(" %.3f : flow_id: %x thread_id %x TCP ack %x\n",now_sec(), node->get_short_fid(), node->get_thread_id(), tcp->getAckNumber());
+ printf(" %.3f : flow_id: %x thread_id %x TCP ack %x seq %x\n"
+ ,now_sec(), node->get_short_fid(), node->get_thread_id(), tcp->getAckNumber()
+ , tcp->getSeqNumber());
#endif
- }
- }
+ }
+ }
}
/* in all cases update the ip using the outside ip */
if ( m_pkt_indication.m_desc.IsInitSide() ) {
#ifdef NAT_TRACE_
if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
- printf(" %.3f : DP : i %x:%x -> %x flow_id: %lx\n",now_sec(),node->m_src_ip,node->m_src_port,node->m_dest_ip,node->m_flow_id);
+ printf(" %.3f : DP : i %x:%x -> %x flow_id: %lx\n",now_sec(), node->m_src_ip
+ , node->m_src_port, node->m_dest_ip, node->m_flow_id);
}
#endif
+ tcp_seq_diff_server = node->get_nat_tcp_seq_diff_server();
ipv4->updateIpSrc(node->m_src_ip);
ipv4->updateIpDst(node->m_dest_ip);
- }else{
+ } else {
#ifdef NAT_TRACE_
if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
- printf(" %.3f : r %x -> %x:%x flow_id: %lx \n",now_sec(),node->m_dest_ip,node->m_src_ip,node->m_src_port,node->m_flow_id);
+ printf(" %.3f : r %x -> %x:%x flow_id: %lx \n", now_sec(), node->m_dest_ip
+ , node->m_src_ip, node->m_src_port, node->m_flow_id);
}
#endif
src_port = node->get_nat_ipv4_port();
- ipv4->updateIpSrc(node->get_nat_ipv4_addr_server());
+ tcp_seq_diff_client = node->get_nat_tcp_seq_diff_client();
+ ipv4->updateIpSrc(node->m_dest_ip);
ipv4->updateIpDst(node->get_nat_ipv4_addr());
}
@@ -3089,7 +3113,7 @@ inline void CFlowPktInfo::update_pkt_info(char *p,
#ifdef NAT_TRACE_
if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
if ( m_pkt_indication.m_desc.IsInitSide() ==false ){
- printf(" %.3f : pkt ==> %x:%x %x:%x \n",now_sec(),node->get_nat_ipv4_addr(),node->get_nat_ipv4_addr_server(),
+ printf(" %.3f : pkt ==> %x %x:%x \n",now_sec(),node->get_nat_ipv4_addr(),
node->get_nat_ipv4_port(),node->m_src_port);
}else{
printf(" %.3f : pkt ==> init pkt sent \n",now_sec());
@@ -3137,8 +3161,10 @@ inline void CFlowPktInfo::update_pkt_info(char *p,
/* replace port */
if ( port_dir == CLIENT_SIDE ) {
m_tcp->setSourcePort(src_port);
+ m_tcp->setAckNumber(m_tcp->getAckNumber() + tcp_seq_diff_server);
}else{
m_tcp->setDestPort(src_port);
+ m_tcp->setAckNumber(m_tcp->getAckNumber() + tcp_seq_diff_client);
}
#ifdef RTE_DPDK
@@ -3409,6 +3435,8 @@ public:
class CCapFileFlowInfo {
public:
+ const int LEARN_MODE_MIN_IPG = 10; // msec
+
enum load_cap_file_err {
kOK = 0,
kFileNotExist,
@@ -3416,9 +3444,14 @@ public:
kNoSyn,
kTCPOffsetTooBig,
kNoTCPFromServer,
+ kNoTCPSynAck,
+ kTCPLearnModeBadFlow,
kPktNotSupp,
kPktProcessFail,
- kCapFileErr
+ kCapFileErr,
+ kPlugInWithLearn,
+ kIPOptionNotAllowed,
+ kTCPIpgTooLow
};
bool Create();
@@ -3435,7 +3468,7 @@ public:
/* update flow info */
void update_info();
- bool is_valid_template_load_time(std::string & err);
+ enum CCapFileFlowInfo::load_cap_file_err is_valid_template_load_time();
void save_to_erf(std::string cap_file_name,int pcap);
@@ -3930,13 +3963,15 @@ public:
public:
int load_from_yaml(std::string csv_file,uint32_t num_threads);
- int load_from_mac_file(std::string csv_file);
+ int load_client_config_file(std::string file_name);
+
public:
void Dump(FILE *fd);
void DumpCsv(FILE *fd);
void DumpPktSize();
void UpdateFast();
double GetCpuUtil();
+ double GetCpuUtilRaw();
public:
double get_total_kcps();
@@ -3944,12 +3979,12 @@ public:
double get_total_tx_bps();
uint32_t get_total_repeat_flows();
double get_delta_flow_is_sec();
- bool get_is_mac_conf() { return m_mac_info.is_configured();}
+
public:
- std::vector<CFlowGeneratorRec *> m_cap_gen; /* global info */
- CFlowsYamlInfo m_yaml_info; /* global yaml*/
- std::vector<CFlowGenListPerThread *> m_threads_info;
- CFlowGenListMac m_mac_info;
+ std::vector<CFlowGeneratorRec *> m_cap_gen; /* global info */
+ CFlowsYamlInfo m_yaml_info; /* global yaml*/
+ std::vector<CFlowGenListPerThread *> m_threads_info;
+ ClientCfgDB m_client_config_info;
};
@@ -3989,9 +4024,8 @@ inline void CCapFileFlowInfo::generate_flow(CTupleTemplateGeneratorSmart * tup
node->m_src_idx = tuple.getClientId();
node->m_dest_idx = tuple.getServerId();
node->m_src_port = tuple.getClientPort();
- memcpy(&node->m_src_mac,
- tuple.getClientMac(),
- sizeof(mac_addr_align_t));
+ node->m_client_cfg = tuple.getClientCfg();
+
node->m_plugin_info =(void *)0;
if ( unlikely( CGlobalInfo::is_learn_mode() ) ){
diff --git a/src/common/Network/Packet/TcpHeader.h b/src/common/Network/Packet/TcpHeader.h
index c19cd262..97575a60 100755
--- a/src/common/Network/Packet/TcpHeader.h
+++ b/src/common/Network/Packet/TcpHeader.h
@@ -23,6 +23,11 @@ class TCPHeader
{
public:
+ enum TCPHeader_enum_t
+ {
+ TCP_INVALID_PORT = 0
+ };
+
TCPHeader(){}
TCPHeader(uint16_t argSourcePort,
diff --git a/src/flow_stat.cpp b/src/flow_stat.cpp
index 5503434f..8c2f2566 100644
--- a/src/flow_stat.cpp
+++ b/src/flow_stat.cpp
@@ -796,6 +796,9 @@ int CFlowStatRuleMgr::start_stream(TrexStream * stream) {
if (m_num_started_streams == 0) {
send_start_stop_msg_to_rx(true); // First transmitting stream. Rx core should start reading packets;
+ //also good time to zero global counters
+ memset(m_rx_cant_count_err, 0, sizeof(m_rx_cant_count_err));
+ memset(m_tx_cant_count_err, 0, sizeof(m_tx_cant_count_err));
// wait to make sure that message is acknowledged. RX core might be in deep sleep mode, and we want to
// start transmitting packets only after it is working, otherwise, packets will get lost.
@@ -910,7 +913,7 @@ int CFlowStatRuleMgr::stop_stream(TrexStream * stream) {
m_num_started_streams--;
assert (m_num_started_streams >= 0);
if (m_num_started_streams == 0) {
- send_start_stop_msg_to_rx(false); // No more transmittig streams. Rx core shoulde get into idle loop.
+ send_start_stop_msg_to_rx(false); // No more transmittig streams. Rx core should get into idle loop.
}
return 0;
}
@@ -947,6 +950,7 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo
tx_per_flow_t tx_stats[MAX_FLOW_STATS];
tx_per_flow_t tx_stats_payload[MAX_FLOW_STATS_PAYLOAD];
rfc2544_info_t rfc2544_info[MAX_FLOW_STATS_PAYLOAD];
+ CRxCoreErrCntrs rx_err_cntrs;
Json::FastWriter writer;
Json::Value s_root;
Json::Value l_root;
@@ -973,6 +977,7 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo
}
m_api->get_rfc2544_info(rfc2544_info, 0, m_max_hw_id_payload, false);
+ m_api->get_rx_err_cntrs(&rx_err_cntrs);
// read hw counters, and update
for (uint8_t port = 0; port < m_num_ports; port++) {
@@ -1046,10 +1051,21 @@ bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, boo
// general per port data
for (uint8_t port = 0; port < m_num_ports; port++) {
std::string str_port = static_cast<std::ostringstream*>( &(std::ostringstream() << int(port) ) )->str();
- if (m_rx_cant_count_err[port] != 0)
- s_data_section["port_data"][str_port]["rx_err"] = m_rx_cant_count_err[port];
- if (m_tx_cant_count_err[port] != 0)
- s_data_section["port_data"][str_port]["tx_err"] = m_tx_cant_count_err[port];
+ if ((m_rx_cant_count_err[port] != 0) || baseline)
+ s_data_section["global"]["rx_err"][str_port] = m_rx_cant_count_err[port];
+ if ((m_tx_cant_count_err[port] != 0) || baseline)
+ s_data_section["global"]["tx_err"][str_port] = m_tx_cant_count_err[port];
+ }
+
+ // payload rules rx errors
+ uint64_t tmp_cnt;
+ tmp_cnt = rx_err_cntrs.get_bad_header();
+ if (tmp_cnt || baseline) {
+ l_data_section["global"]["bad_hdr"] = Json::Value::UInt64(tmp_cnt);
+ }
+ tmp_cnt = rx_err_cntrs.get_old_flow();
+ if (tmp_cnt || baseline) {
+ l_data_section["global"]["old_flow"] = Json::Value::UInt64(tmp_cnt);
}
flow_stat_user_id_map_it_t it;
diff --git a/src/global_io_mode.cpp b/src/global_io_mode.cpp
index 2457599e..289863c9 100755
--- a/src/global_io_mode.cpp
+++ b/src/global_io_mode.cpp
@@ -103,6 +103,14 @@ bool CTrexGlobalIoMode::handle_io_modes(void){
m_g_mode=gNORMAL;
}
break;
+ case ccNat:
+ m_g_mode=gNAT;
+ m_nat_mode++;
+ if (m_nat_mode==natLAST) {
+ m_nat_mode = natDISABLE;
+ m_g_mode = gNORMAL;
+ }
+ break;
}
@@ -121,17 +129,18 @@ void CTrexGlobalIoMode::Dump(FILE *fd){
}
void CTrexGlobalIoMode::DumpHelp(FILE *fd){
- fprintf(fd,"Help for Interactive Commands - Trex \n" );
- fprintf(fd," d : Toggle, Disable all -> Noraml \n");
- fprintf(fd," n : Default mode all in Normal mode \n");
- fprintf(fd," h : Toggle, Help->Normal \n");
- fprintf(fd,"\n");
- fprintf(fd," p : Per ports Toggle mode, disable -> table -> normal \n");
- fprintf(fd," a : Global ports Toggle mode, disable -> enable \n");
- fprintf(fd," l : Latency Toggle mode, disable -> enable -> enhanced \n");
- fprintf(fd," r : Rx check Toggle mode, disable -> enable -> enhanced \n");
- fprintf(fd," m : memory stats , disable -> enable \n");
- fprintf(fd," Press h or 1 to go back to Normal mode \n");
+ fprintf(fd, "Help for Interactive Commands\n" );
+ fprintf(fd, " %c : Toggle, Disable all/Default \n", ccGDISABLE);
+ fprintf(fd, " %c : Go back to default mode \n", ccGNORAML);
+ fprintf(fd, " %c : Toggle, Help/Default \n", ccHELP);
+ fprintf(fd, "\n");
+ fprintf(fd, " %c : Per ports toggle disable -> table -> normal \n", ccGPP);
+ fprintf(fd, " %c : Global ports toggle disable/enable \n", ccGAP);
+ fprintf(fd, " %c : Latency toggle disable -> enable -> enhanced \n", ccGL);
+ fprintf(fd, " %c : Rx check toggle disable -> enable -> enhanced \n", ccGRC);
+ fprintf(fd, " %c : Memory stats toggle disable/enable \n", ccMem);
+ fprintf(fd, " %c : NAT pending flows toggle disable/enable \n", ccNat);
+ fprintf(fd, " Press %c or %c to go back to Normal mode \n", ccHELP, ccGNORAML);
}
diff --git a/src/global_io_mode.h b/src/global_io_mode.h
index 84b402b7..44fa4be5 100755
--- a/src/global_io_mode.h
+++ b/src/global_io_mode.h
@@ -48,12 +48,13 @@ public:
enum Chars{
ccHELP='h',
ccGDISABLE='d',
- ccGNORAML='n',
+ ccGNORAML='0',
ccGPP='p',
ccGAP='a',
ccGL='l',
ccGRC='r',
- ccMem='m'
+ ccMem='m',
+ ccNat='n'
};
enum CliDumpMode {
@@ -67,7 +68,8 @@ public:
gDISABLE=0, // no print at all
gHELP=1, // help
gNORMAL=2, // normal
- gMem=3
+ gMem=3,
+ gNAT
};
@@ -104,12 +106,20 @@ public:
};
typedef uint8_t RxCheckMode_t;
+ enum NatMode {
+ natDISABLE = 0,
+ natENABLE = 1,
+ natLAST = 2
+ };
+ typedef uint8_t NatMode_t;
+
Global_t m_g_mode;
bool m_g_disable_first;
PerPortCountersMode_t m_pp_mode;
AllPortCountersMode_t m_ap_mode;
LatecnyMode_t m_l_mode;
RxCheckMode_t m_rc_mode;
+ NatMode_t m_nat_mode;
public:
void set_mode(CliDumpMode mode);
diff --git a/src/gtest/tuple_gen_test.cpp b/src/gtest/tuple_gen_test.cpp
index f3b9fa1e..fa760c6d 100755
--- a/src/gtest/tuple_gen_test.cpp
+++ b/src/gtest/tuple_gen_test.cpp
@@ -25,6 +25,22 @@ limitations under the License.
/* TEST case for CClientInfo*/
+class CClientInfo : public CSimpleClientInfo<CIpInfo> {
+public:
+ CClientInfo() : CSimpleClientInfo<CIpInfo>(0) {
+
+ }
+};
+
+class CClientInfoL : public CSimpleClientInfo<CIpInfoL> {
+public:
+ CClientInfoL() : CSimpleClientInfo<CIpInfoL>(0) {
+
+ }
+};
+
+static ClientCfgDB g_dummy;
+
class CClientInfoUT {
public:
CClientInfoUT(CClientInfo *a) {
@@ -157,7 +173,7 @@ TEST(CClientInfoLTest, get_new_free_port) {
TEST(tuple_gen,clientPoolL) {
CClientPool gen;
gen.Create(cdSEQ_DIST,
- 0x10000001, 0x10000f01, 64000,1,NULL,false,
+ 0x10000001, 0x10000f01, 64000,1, g_dummy,
0,0);
CTupleBase result;
uint32_t result_src;
@@ -181,7 +197,7 @@ TEST(tuple_gen,clientPoolL) {
TEST(tuple_gen,clientPool) {
CClientPool gen;
gen.Create(cdSEQ_DIST,
- 0x10000001, 0x10000021, 64000,1000,NULL,false,
+ 0x10000001, 0x10000021, 64000,1000, g_dummy,
0,0);
CTupleBase result;
uint32_t result_src;
@@ -273,7 +289,7 @@ TEST(tuple_gen,GenerateTuple2) {
CClientPool c_gen;
CClientPool c_gen_2;
c_gen.Create(cdSEQ_DIST,
- 0x10000001, 0x1000000f, 64000,4,NULL,false,
+ 0x10000001, 0x1000000f, 64000,4, g_dummy,
0,0);
CServerPool s_gen;
CServerPool s_gen_2;
@@ -302,7 +318,7 @@ TEST(tuple_gen,GenerateTuple2) {
c_gen.Delete();
// EXPECT_EQ((size_t)0, gen.m_clients.size());
c_gen.Create(cdSEQ_DIST,
- 0x10000001, 0x1000000f, 64000,400,NULL,false,
+ 0x10000001, 0x1000000f, 64000,400, g_dummy,
0,0);
s_gen.Create(cdSEQ_DIST,
0x30000001, 0x30000001, 64000,10);
@@ -325,39 +341,6 @@ TEST(tuple_gen,GenerateTuple2) {
}
-TEST(tuple_gen,GenerateTupleMac) {
- CFlowGenList fl;
- fl.Create();
- fl.load_from_mac_file("avl/mac_uit.yaml");
-
- CClientPool gen;
- gen.Create(cdSEQ_DIST,
- 0x10000001, 0x1000000f, 64000,2, &fl.m_mac_info,true,0,0);
-
- CTupleBase result;
- uint32_t result_src;
- uint16_t result_port;
- mac_addr_align_t* result_mac;
- for(int i=0;i<10;i++) {
- gen.GenerateTuple(result);
- printf(" C:%x P:%d \n",result.getClient(),result.getClientPort());
-
- result_src = result.getClient();
- result_port = result.getClientPort();
- result_mac = result.getClientMac();
- EXPECT_EQ(result_src, (uint32_t)(0x10000001+i%2));
- EXPECT_EQ(result_port, 1024+i/2);
- printf("i:%d,mac:%d\n",i,result_mac->mac[3]);
- if (i%2==0)
- EXPECT_EQ(result_mac->mac[3], 5);
- else
- EXPECT_EQ(result_mac->mac[3], 1);
- }
-
- gen.Delete();
-// EXPECT_EQ((size_t)0, gen.m_clients.size());
-}
-
TEST(tuple_gen,split1) {
CIpPortion portion;
@@ -421,7 +404,7 @@ TEST(tuple_gen,split2) {
TEST(tuple_gen,template1) {
CTupleGeneratorSmart gen;
gen.Create(1, 1);
- gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0);
+ gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4, g_dummy, 0, 0);
gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false);
CTupleTemplateGeneratorSmart template_1;
template_1.Create(&gen,0,0);
@@ -446,7 +429,7 @@ TEST(tuple_gen,template1) {
TEST(tuple_gen,template2) {
CTupleGeneratorSmart gen;
gen.Create(1, 1);
- gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0);
+ gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,g_dummy,0,0);
gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false);
CTupleTemplateGeneratorSmart template_1;
template_1.Create(&gen,0,0);
@@ -475,7 +458,7 @@ TEST(tuple_gen,template2) {
TEST(tuple_gen,no_free) {
CTupleGeneratorSmart gen;
gen.Create(1, 1);
- gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000001,64000,4,NULL,0,0);
+ gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000001,64000,4,g_dummy,0,0);
gen.add_server_pool(cdSEQ_DIST,0x30000001,0x400000ff,64000,4,false);
CTupleTemplateGeneratorSmart template_1;
template_1.Create(&gen,0,0);
@@ -497,7 +480,7 @@ TEST(tuple_gen,no_free) {
TEST(tuple_gen,try_to_free) {
CTupleGeneratorSmart gen;
gen.Create(1, 1);
- gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000001,64000,4,NULL,0,0);
+ gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000001,64000,4,g_dummy,0,0);
gen.add_server_pool(cdSEQ_DIST,0x30000001,0x400000ff,64000,4,false);
CTupleTemplateGeneratorSmart template_1;
template_1.Create(&gen,0,0);
@@ -524,7 +507,7 @@ TEST(tuple_gen,try_to_free) {
TEST(tuple_gen_2,GenerateTuple) {
CTupleGeneratorSmart gen;
gen.Create(1, 1);
- gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000f01,64000,4,NULL,0,0);
+ gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000f01,64000,4,g_dummy,0,0);
gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false);
CTupleTemplateGeneratorSmart template_1;
template_1.Create(&gen,0,0);
@@ -552,7 +535,7 @@ TEST(tuple_gen_2,GenerateTuple) {
TEST(tuple_gen_2,GenerateTuple2) {
CTupleGeneratorSmart gen;
gen.Create(1, 1);
- gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0);
+ gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,g_dummy,0,0);
gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false);
CTupleTemplateGeneratorSmart template_1;
template_1.Create(&gen,0,0);
@@ -576,7 +559,7 @@ TEST(tuple_gen_2,GenerateTuple2) {
gen.Delete();
// EXPECT_EQ((size_t)0, gen.m_clients.size());
gen.Create(1, 1);
- gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0);
+ gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,g_dummy,0,0);
gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false);
template_1.Create(&gen,0,0);
for(int i=0;i<200;i++) {
@@ -599,7 +582,7 @@ TEST(tuple_gen_2,GenerateTuple2) {
TEST(tuple_gen_2,template1) {
CTupleGeneratorSmart gen;
gen.Create(1, 1);
- gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0);
+ gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,g_dummy,0,0);
gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false);
CTupleTemplateGeneratorSmart template_1;
template_1.Create(&gen,0,0);
@@ -626,7 +609,7 @@ TEST(tuple_gen_2,template1) {
TEST(tuple_gen_2,template2) {
CTupleGeneratorSmart gen;
gen.Create(1, 1);
- gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0);
+ gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,g_dummy,0,0);
gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false);
CTupleTemplateGeneratorSmart template_1;
template_1.Create(&gen,0,0);
diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h
index a52f9e60..7037584b 100644
--- a/src/internal_api/trex_platform_api.h
+++ b/src/internal_api/trex_platform_api.h
@@ -28,6 +28,7 @@ limitations under the License.
#include <string.h>
#include "flow_stat_parser.h"
#include "trex_defs.h"
+#include <json/json.h>
/**
* Global stats
@@ -148,6 +149,7 @@ public:
virtual int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset
, TrexPlatformApi::driver_stat_cap_e type) const = 0;
virtual int get_rfc2544_info(void *rfc2544_info, int min, int max, bool reset) const = 0;
+ virtual int get_rx_err_cntrs(void *rx_err_cntrs) const = 0;
virtual int reset_hw_flow_stats(uint8_t port_id) const = 0;
virtual void get_port_num(uint8_t &port_num) const = 0;
virtual int add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const = 0;
@@ -156,6 +158,8 @@ public:
virtual bool get_promiscuous(uint8_t port_id) const = 0;
virtual void flush_dp_messages() const = 0;
virtual int get_active_pgids(flow_stat_active_t &result) const = 0;
+ virtual int get_cpu_util_full(cpu_util_full_t &result) const = 0;
+ virtual int get_mbuf_util(Json::Value &result) const = 0;
virtual CFlowStatParser *get_flow_stat_parser() const = 0;
virtual ~TrexPlatformApi() {}
};
@@ -180,6 +184,7 @@ public:
int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset
, TrexPlatformApi::driver_stat_cap_e type) const;
int get_rfc2544_info(void *rfc2544_info, int min, int max, bool reset) const;
+ int get_rx_err_cntrs(void *rx_err_cntrs) const;
int reset_hw_flow_stats(uint8_t port_id) const;
void get_port_num(uint8_t &port_num) const;
int add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const;
@@ -188,6 +193,8 @@ public:
bool get_promiscuous(uint8_t port_id) const;
void flush_dp_messages() const;
int get_active_pgids(flow_stat_active_t &result) const;
+ int get_cpu_util_full(cpu_util_full_t &result) const;
+ int get_mbuf_util(Json::Value &result) const;
CFlowStatParser *get_flow_stat_parser() const;
};
@@ -237,6 +244,7 @@ public:
int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset
, TrexPlatformApi::driver_stat_cap_e type) const {return 0;};
virtual int get_rfc2544_info(void *rfc2544_info, int min, int max, bool reset) const {return 0;};
+ virtual int get_rx_err_cntrs(void *rx_err_cntrs) const {return 0;};
virtual int reset_hw_flow_stats(uint8_t port_id) const {return 0;};
virtual void get_port_num(uint8_t &port_num) const {port_num = 2;};
virtual int add_rx_flow_stat_rule(uint8_t port_id, uint8_t type, uint16_t proto, uint16_t id) const {return 0;}
@@ -252,6 +260,8 @@ public:
void flush_dp_messages() const {
}
int get_active_pgids(flow_stat_active_t &result) const {return 0;}
+ int get_cpu_util_full(cpu_util_full_t &result) const {return 0;}
+ int get_mbuf_util(Json::Value &result) const {return 0;}
CFlowStatParser *get_flow_stat_parser() const {return new CFlowStatParser();}
private:
diff --git a/src/latency.cpp b/src/latency.cpp
index 841913cf..768e161b 100644
--- a/src/latency.cpp
+++ b/src/latency.cpp
@@ -436,7 +436,7 @@ bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) {
m_no_ipv4_option++;
return (false);
}
- m_parent->get_nat_manager()->handle_packet_ipv4(lp,parser.m_ipv4);
+ m_parent->get_nat_manager()->handle_packet_ipv4(lp, parser.m_ipv4, true);
opt_len -= CNatOption::noOPTION_LEN;
opt_ptr += CNatOption::noOPTION_LEN;
break;
@@ -445,10 +445,11 @@ bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) {
return (false);
} // End of switch
} // End of while
- if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)
- && parser.IsNatInfoPkt()) {
- m_parent->get_nat_manager()->handle_packet_ipv4(NULL, parser.m_ipv4);
- }
+
+ bool first;
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP) && parser.IsNatInfoPkt(first)) {
+ m_parent->get_nat_manager()->handle_packet_ipv4(NULL, parser.m_ipv4, first);
+ }
return (true);
} // End of check for non-latency packet
@@ -910,6 +911,10 @@ void CLatencyManager::DumpShortRxCheck(FILE *fd){
}
}
+void CLatencyManager::dump_nat_flow_table(FILE *fd) {
+ m_nat_check_manager.Dump(fd);
+}
+
void CLatencyManager::rx_check_dump_json(std::string & json){
if ( get_is_rx_check_mode() ) {
m_rx_check_manager.dump_json(json );
diff --git a/src/latency.h b/src/latency.h
index 724621f0..63e50337 100644
--- a/src/latency.h
+++ b/src/latency.h
@@ -107,19 +107,27 @@ public:
}
// Check if this packet contains NAT info in TCP ack
- inline bool IsNatInfoPkt() {
- if (!m_ipv4 || (m_protocol != IPPROTO_TCP)) {
- return false;
- }
- if (! m_l4 || (m_l4 - rte_pktmbuf_mtod(m_m, uint8_t*) + TCP_HEADER_LEN) > m_m->data_len) {
- return false;
- }
- // If we are here, relevant fields from tcp header are guaranteed to be in first mbuf
- TCPHeader *tcp = (TCPHeader *)m_l4;
- if (!tcp->getSynFlag() || (tcp->getAckNumber() == 0)) {
- return false;
- }
- return true;
+ // first - set to true if this is the first packet of the flow. false otherwise.
+ // relevant only if return value is true
+ inline bool IsNatInfoPkt(bool &first) {
+ if (!m_ipv4 || (m_protocol != IPPROTO_TCP)) {
+ return false;
+ }
+ if (! m_l4 || (m_l4 - rte_pktmbuf_mtod(m_m, uint8_t*) + TCP_HEADER_LEN) > m_m->data_len) {
+ return false;
+ }
+ // If we are here, relevant fields from tcp header are guaranteed to be in first mbuf
+ // We want to handle SYN and SYN+ACK packets
+ TCPHeader *tcp = (TCPHeader *)m_l4;
+ if (! tcp->getSynFlag())
+ return false;
+
+ if (! tcp->getAckFlag()) {
+ first = true;
+ } else {
+ first = false;
+ }
+ return true;
}
public:
@@ -354,6 +362,7 @@ public:
void DumpRxCheck(FILE *fd); // dump all
void DumpShortRxCheck(FILE *fd); // dump short histogram of latency
+ void dump_nat_flow_table(FILE *fd);
void rx_check_dump_json(std::string & json);
uint16_t get_latency_header_offset(){
return ( m_pkt_gen.get_payload_offset() );
diff --git a/src/mac_mapping.h b/src/mac_mapping.h
deleted file mode 100644
index 84151e8c..00000000
--- a/src/mac_mapping.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef MAC_MAPPING_H_
-#define MAC_MAPPING_H_
-
-#define INUSED 0
-#define UNUSED 1
-typedef struct mac_addr_align_ {
-public:
- uint8_t mac[6];
- uint8_t inused;
- uint8_t pad;
-} mac_addr_align_t;
-
-typedef struct mac_mapping_ {
- mac_addr_align_t mac;
- uint32_t ip;
-} mac_mapping_t;
-
-class CFlowGenListMac {
-public:
- CFlowGenListMac() {
- set_configured(false);
- }
-
- std::map<uint32_t, mac_addr_align_t> &
- get_mac_info () {
- return m_mac_info;
- }
-
- bool is_configured() {
- return is_mac_info_configured;
- }
-
- void set_configured(bool is_conf) {
- is_mac_info_configured = is_conf;
- }
-
- void clear() {
- set_configured(false);
- m_mac_info.clear();
- }
-
- uint32_t is_mac_exist(uint32_t ip) {
- if (is_configured()) {
- return m_mac_info.count(ip);
- } else {
- return 0;
- }
- }
- mac_addr_align_t* get_mac_addr_by_ip(uint32_t ip) {
- if (is_mac_exist(ip)!=0) {
- return &(m_mac_info[ip]);
- }
- return NULL;
- }
-private:
- bool is_mac_info_configured;
- std::map<uint32_t, mac_addr_align_t> m_mac_info; /* global mac info loaded form mac_file*/
-};
-
-#endif //MAC_MAPPING_H_
diff --git a/src/main.cpp b/src/main.cpp
index 62eee880..de6cef45 100755
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,6 +22,7 @@ limitations under the License.
#include "bp_sim.h"
#include "os_time.h"
+#include "trex_client_config.h"
#include <unordered_map>
#include <string>
@@ -35,7 +36,7 @@ using namespace std;
// An enum for all the option types
enum { OPT_HELP, OPT_CFG, OPT_NODE_DUMP, OP_STATS,
- OPT_FILE_OUT, OPT_UT, OPT_PCAP, OPT_IPV6, OPT_MAC_FILE,
+ OPT_FILE_OUT, OPT_UT, OPT_PCAP, OPT_IPV6, OPT_CLIENT_CFG_FILE,
OPT_SL, OPT_DP_CORE_COUNT, OPT_DP_CORE_INDEX, OPT_LIMIT,
OPT_DRY_RUN};
@@ -61,22 +62,22 @@ typedef enum {
*/
static CSimpleOpt::SOption parser_options[] =
{
- { OPT_HELP, "-?", SO_NONE },
- { OPT_HELP, "-h", SO_NONE },
- { OPT_HELP, "--help", SO_NONE },
- { OPT_UT, "--ut", SO_NONE },
- { OP_STATS, "-s", SO_NONE },
- { OPT_CFG, "-f", SO_REQ_SEP },
- { OPT_MAC_FILE, "--mac", SO_REQ_SEP },
- { OPT_FILE_OUT , "-o", SO_REQ_SEP },
- { OPT_NODE_DUMP , "-v", SO_REQ_SEP },
- { OPT_PCAP, "--pcap", SO_NONE },
- { OPT_IPV6, "--ipv6", SO_NONE },
- { OPT_SL, "--sl", SO_NONE },
- { OPT_DP_CORE_COUNT, "--cores", SO_REQ_SEP },
- { OPT_DP_CORE_INDEX, "--core_index", SO_REQ_SEP },
- { OPT_LIMIT, "--limit", SO_REQ_SEP },
- { OPT_DRY_RUN, "--dry", SO_NONE },
+ { OPT_HELP, "-?", SO_NONE },
+ { OPT_HELP, "-h", SO_NONE },
+ { OPT_HELP, "--help", SO_NONE },
+ { OPT_UT, "--ut", SO_NONE },
+ { OP_STATS, "-s", SO_NONE },
+ { OPT_CFG, "-f", SO_REQ_SEP },
+ { OPT_CLIENT_CFG_FILE, "--client_cfg", SO_REQ_SEP },
+ { OPT_FILE_OUT , "-o", SO_REQ_SEP },
+ { OPT_NODE_DUMP , "-v", SO_REQ_SEP },
+ { OPT_PCAP, "--pcap", SO_NONE },
+ { OPT_IPV6, "--ipv6", SO_NONE },
+ { OPT_SL, "--sl", SO_NONE },
+ { OPT_DP_CORE_COUNT, "--cores", SO_REQ_SEP },
+ { OPT_DP_CORE_INDEX, "--core_index", SO_REQ_SEP },
+ { OPT_LIMIT, "--limit", SO_REQ_SEP },
+ { OPT_DRY_RUN, "--dry", SO_NONE },
SO_END_OF_OPTIONS
@@ -159,8 +160,8 @@ static int parse_options(int argc,
po->cfg_file = args.OptionArg();
break;
- case OPT_MAC_FILE:
- po->mac_file = args.OptionArg();
+ case OPT_CLIENT_CFG_FILE:
+ po->client_cfg_file = args.OptionArg();
break;
case OPT_FILE_OUT:
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 820371ab..7bff8253 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -141,8 +141,8 @@ public:
virtual int configure_drop_queue(CPhyEthIF * _if);
virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats)=0;
virtual void clear_extended_stats(CPhyEthIF * _if)=0;
- virtual int wait_for_stable_link()=0;
- virtual void wait_after_link_up(){};
+ virtual int wait_for_stable_link();
+ virtual void wait_after_link_up();
virtual bool flow_control_disable_supported(){return true;}
virtual bool hw_rx_stat_supported(){return false;}
virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes
@@ -538,6 +538,7 @@ enum { OPT_HELP,
OPT_ONLY_LATENCY,
OPT_1G_MODE,
OPT_LATENCY_PREVIEW ,
+ OPT_WAIT_BEFORE_TRAFFIC,
OPT_PCAP,
OPT_RX_CHECK,
OPT_IO_MODE,
@@ -548,12 +549,10 @@ enum { OPT_HELP,
OPT_L_PKT_MODE,
OPT_NO_FLOW_CONTROL,
OPT_RX_CHECK_HOPS,
- OPT_MAC_FILE,
+ OPT_CLIENT_CFG_FILE,
OPT_NO_KEYBOARD_INPUT,
- OPT_VLAN,
OPT_VIRT_ONE_TX_RX_QUEUE,
OPT_PREFIX,
- OPT_MAC_SPLIT,
OPT_SEND_DEBUG_PKT,
OPT_NO_WATCHDOG,
OPT_ALLOW_COREDUMP,
@@ -602,6 +601,7 @@ static CSimpleOpt::SOption parser_options[] =
{ OPT_1G_MODE, "-1g", SO_NONE },
{ OPT_LATENCY_PREVIEW , "-k", SO_REQ_SEP },
+ { OPT_WAIT_BEFORE_TRAFFIC , "-w", SO_REQ_SEP },
{ OPT_PCAP, "--pcap", SO_NONE },
{ OPT_RX_CHECK, "--rx-check", SO_REQ_SEP },
{ OPT_IO_MODE, "--iom", SO_REQ_SEP },
@@ -612,12 +612,10 @@ static CSimpleOpt::SOption parser_options[] =
{ OPT_LEARN_VERIFY, "--learn-verify", SO_NONE },
{ OPT_L_PKT_MODE, "--l-pkt-mode", SO_REQ_SEP },
{ OPT_NO_FLOW_CONTROL, "--no-flow-control-change", SO_NONE },
- { OPT_VLAN, "--vlan", SO_NONE },
- { OPT_MAC_FILE, "--mac", SO_REQ_SEP },
+ { OPT_CLIENT_CFG_FILE, "--client_cfg", SO_REQ_SEP },
{ OPT_NO_KEYBOARD_INPUT ,"--no-key", SO_NONE },
{ OPT_VIRT_ONE_TX_RX_QUEUE, "--vm-sim", SO_NONE },
{ OPT_PREFIX, "--prefix", SO_REQ_SEP },
- { OPT_MAC_SPLIT, "--mac-spread", SO_REQ_SEP },
{ OPT_SEND_DEBUG_PKT, "--send-debug-pkt", SO_REQ_SEP },
{ OPT_MBUF_FACTOR , "--mbuf-factor", SO_REQ_SEP },
{ OPT_NO_WATCHDOG , "--no-watchdog", SO_NONE },
@@ -644,7 +642,7 @@ static int usage(){
printf(" options \n\n");
- printf(" --mac [file] : YAML file with <client ip, mac addr> configuration \n");
+ printf(" --client_cfg [file] : YAML file which describes clients configuration\n");
printf(" \n\n");
printf(" -c [number of threads] : default is 1. number of threads to allocate for each dual ports. \n");
printf(" \n");
@@ -682,6 +680,8 @@ static int usage(){
printf(" \n");
printf(" -k [sec] : run latency test before starting the test. it will wait for x sec sending packet and x sec after that \n");
printf(" \n");
+ printf(" -w [sec] : wait between init of interfaces and sending traffic, default is 1\n");
+ printf(" \n");
printf(" --cfg [platform_yaml] : load and configure platform using this file see example in cfg/cfg_examplexx.yaml file \n");
printf(" this file is used to configure/mask interfaces cores affinity and mac addr \n");
@@ -690,9 +690,10 @@ static int usage(){
printf(" --ipv6 : work in ipv6 mode\n");
printf(" --learn (deprecated). Replaced by --learn-mode. To get older behaviour, use --learn-mode 2\n");
- printf(" --learn-mode [1-2] : Work in NAT environments, learn the dynamic NAT translation and ALG \n");
- printf(" 1 Use TCP ACK in first SYN to pass NAT translation information. Will work only for TCP streams. Initial SYN packet must be present in stream.\n");
+ printf(" --learn-mode [1-3] : Work in NAT environments, learn the dynamic NAT translation and ALG \n");
+ printf(" 1 Use TCP ACK in first SYN to pass NAT translation information. Will work only for TCP streams. Initial SYN packet must be first packet in stream.\n");
printf(" 2 Add special IP option to pass NAT translation information. Will not work on certain firewalls if they drop packets with IP options\n");
+ printf(" 3 Like 1, but without support for sequence number randomization in server->clien direction. Performance (flow/second) better than 1\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");
@@ -719,8 +720,6 @@ static int usage(){
printf(" --no-key : daemon mode, don't get input from keyboard \n");
printf(" --no-flow-control-change : By default TRex disables flow-control. If this option is given, it does not touch it\n");
printf(" --prefix : for multi trex, each instance should have a different name \n");
- printf(" --mac-spread : Spread the destination mac-order by this factor. e.g 2 will generate the traffic to 2 devices DEST-MAC ,DEST-MAC+1 \n");
- printf(" maximum is up to 128 devices \n");
printf(" --mbuf-factor : factor for packet memory \n");
printf(" \n");
printf(" --no-watchdog : disable watchdog \n");
@@ -745,7 +744,7 @@ static int usage(){
printf("\n");
printf("\n");
- printf(" Copyright (c) 2015-2015 Cisco Systems, Inc. \n");
+ printf(" Copyright (c) 2015-2016 Cisco Systems, Inc. \n");
printf(" \n");
printf(" Licensed under the Apache License, Version 2.0 (the 'License') \n");
printf(" you may not use this file except in compliance with the License. \n");
@@ -830,8 +829,8 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
po->preview.set_no_keyboard(true);
break;
- case OPT_MAC_FILE :
- po->mac_file = args.OptionArg();
+ case OPT_CLIENT_CFG_FILE :
+ po->client_cfg_file = args.OptionArg();
break;
case OPT_PLAT_CFG_FILE :
@@ -846,9 +845,6 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
po->preview.set_ipv6_mode_enable(true);
break;
- case OPT_VLAN:
- po->preview.set_vlan_mode_enable(true);
- break;
case OPT_LEARN :
po->m_learn_mode = CParserOption::LEARN_MODE_IP_OPTION;
@@ -954,6 +950,10 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
sscanf(args.OptionArg(),"%d", &po->m_latency_prev);
break;
+ case OPT_WAIT_BEFORE_TRAFFIC :
+ sscanf(args.OptionArg(),"%d", &po->m_wait_before_traffic);
+ break;
+
case OPT_PCAP:
po->preview.set_pcap_mode_enable(true);
break;
@@ -980,13 +980,6 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
po->prefix = args.OptionArg();
break;
- case OPT_MAC_SPLIT:
- sscanf(args.OptionArg(),"%d", &tmp_data);
- po->m_mac_splitter = (uint8_t)tmp_data;
- po->preview.set_mac_ip_features_enable(true);
- po->preview.setDestMacSplit(true);
- break;
-
case OPT_SEND_DEBUG_PKT:
sscanf(args.OptionArg(),"%d", &tmp_data);
po->m_debug_pkt_proto = (uint8_t)tmp_data;
@@ -1014,17 +1007,9 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
parse_err("Please provide single run mode (e.g. batch or interactive)");
}
- if ( po->m_mac_splitter > 128 ){
- std::stringstream ss;
- ss << "maximum mac spreading is 128 you set it to: " << po->m_mac_splitter;
- parse_err(ss.str());
- }
-
- if ( CGlobalInfo::is_learn_mode() ){
- if ( po->preview.get_ipv6_mode_enable() ){
- parse_err("--learn mode is not supported with --ipv6, beacuse there is not such thing NAT66 ( ipv6-ipv6) \n" \
- "if you think it is important,open a defect \n");
- }
+ if (CGlobalInfo::is_learn_mode() && po->preview.get_ipv6_mode_enable()) {
+ parse_err("--learn mode is not supported with --ipv6, beacuse there is not such thing NAT66 ( ipv6-ipv6) \n" \
+ "if you think it is important,open a defect \n");
}
if (po->preview.get_is_rx_check_enable() || po->is_latency_enabled() || CGlobalInfo::is_learn_mode()) {
@@ -1777,7 +1762,9 @@ public:
virtual void flush_dp_rx_queue(void);
virtual int flush_tx_queue(void);
__attribute__ ((noinline)) void flush_rx_queue();
- __attribute__ ((noinline)) void update_mac_addr(CGenNode * node,uint8_t *p);
+ __attribute__ ((noinline)) void handle_slowpath_features(CGenNode *node, rte_mbuf_t *m, uint8_t *p, pkt_dir_t dir);
+
+ void apply_client_cfg(const ClientCfg *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p);
bool process_rx_pkt(pkt_dir_t dir,rte_mbuf_t * m);
@@ -1810,6 +1797,8 @@ protected:
rte_mbuf_t *m,
CVirtualIFPerSideStats * lp_stats);
+ void add_vlan(rte_mbuf_t *m, uint16_t vlan_id);
+
protected:
uint8_t m_core_id;
uint16_t m_mbuf_cache;
@@ -2034,27 +2023,6 @@ void CCoreEthIF::send_one_pkt(pkt_dir_t dir,
lp_port->m_len = 0;
}
-
-void CCoreEthIF::update_mac_addr(CGenNode * node,uint8_t *p){
-
- if ( CGlobalInfo::m_options.preview.getDestMacSplit() ) {
- p[5]+= (node->m_src_ip % CGlobalInfo::m_options.m_mac_splitter);
- }
-
- if ( unlikely( CGlobalInfo::m_options.preview.get_mac_ip_mapping_enable() ) ) {
- /* mac mapping file is configured
- */
- if ( node->is_initiator_pkt() && (node->m_src_mac.inused==INUSED)) {
- memcpy(p+6, &node->m_src_mac.mac, 6);
- }
- } else if ( unlikely( CGlobalInfo::m_options.preview.get_mac_ip_overide_enable() ) ){
- /* client side */
- if ( node->is_initiator_pkt() ){
- *((uint32_t*)(p+6))=PKT_NTOHL(node->m_src_ip);
- }
- }
-}
-
int CCoreEthIFStateless::send_node_flow_stat(rte_mbuf *m, CGenNodeStateless * node_sl, CCorePerPort * lp_port
, CVirtualIFPerSideStats * lp_stats, bool is_const) {
// Defining this makes 10% percent packet loss. 1% packet reorder.
@@ -2180,8 +2148,59 @@ int CCoreEthIFStateless::handle_slow_path_node(CGenNode * no) {
return (-1);
}
+void CCoreEthIF::apply_client_cfg(const ClientCfg *cfg, rte_mbuf_t *m, pkt_dir_t dir, uint8_t *p) {
+
+ assert(cfg);
+
+ /* take the right direction config */
+ const ClientCfgDir &cfg_dir = ( (dir == CLIENT_SIDE) ? cfg->m_initiator : cfg->m_responder);
+
+ /* dst mac */
+ if (cfg_dir.has_dst_mac_addr()) {
+ memcpy(p, cfg_dir.get_dst_mac_addr(), 6);
+ }
+
+ /* src mac */
+ if (cfg_dir.has_src_mac_addr()) {
+ memcpy(p + 6, cfg_dir.get_src_mac_addr(), 6);
+ }
+
+ /* VLAN */
+ if (cfg_dir.has_vlan()) {
+ add_vlan(m, cfg_dir.get_vlan());
+ }
+}
+
+
+void CCoreEthIF::add_vlan(rte_mbuf_t *m, uint16_t vlan_id) {
+ m->ol_flags = PKT_TX_VLAN_PKT;
+ m->l2_len = 14;
+ m->vlan_tci = vlan_id;
+}
+
+/**
+ * slow path features goes here (avoid multiple IFs)
+ *
+ */
+void CCoreEthIF::handle_slowpath_features(CGenNode *node, rte_mbuf_t *m, uint8_t *p, pkt_dir_t dir) {
+
+
+ /* MAC ovverride */
+ if ( unlikely( CGlobalInfo::m_options.preview.get_mac_ip_overide_enable() ) ) {
+ /* client side */
+ if ( node->is_initiator_pkt() ) {
+ *((uint32_t*)(p+6)) = PKT_NTOHL(node->m_src_ip);
+ }
+ }
+
+ /* flag is faster than checking the node pointer (another cacheline) */
+ if ( unlikely(CGlobalInfo::m_options.preview.get_is_client_cfg_enable() ) ) {
+ apply_client_cfg(node->m_client_cfg, m, dir, p);
+ }
+
+}
-int CCoreEthIF::send_node(CGenNode * node){
+int CCoreEthIF::send_node(CGenNode * node) {
if ( unlikely( node->get_cache_mbuf() !=NULL ) ) {
pkt_dir_t dir;
@@ -2199,33 +2218,30 @@ int CCoreEthIF::send_node(CGenNode * node){
rte_mbuf_t * m=lp->generate_new_mbuf(node);
pkt_dir_t dir;
- bool single_port;
+ bool single_port;
- dir = node->cur_interface_dir();
+ dir = node->cur_interface_dir();
single_port = node->get_is_all_flow_from_same_dir() ;
+
if ( unlikely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){
/* which vlan to choose 0 or 1*/
uint8_t vlan_port = (node->m_src_ip &1);
-
- /* set the vlan */
- m->ol_flags = PKT_TX_VLAN_PKT;
- m->l2_len =14;
- uint16_t vlan_id = CGlobalInfo::m_options.m_vlan_port[vlan_port];
-
+ uint16_t vlan_id = CGlobalInfo::m_options.m_vlan_port[vlan_port];
if (likely( vlan_id >0 ) ) {
- m->vlan_tci = vlan_id;
dir = dir ^ vlan_port;
}else{
/* both from the same dir but with VLAN0 */
- m->vlan_tci = CGlobalInfo::m_options.m_vlan_port[0];
+ vlan_id = CGlobalInfo::m_options.m_vlan_port[0];
dir = dir ^ 0;
}
+
+ add_vlan(m, vlan_id);
}
- CCorePerPort * lp_port=&m_ports[dir];
- CVirtualIFPerSideStats * lp_stats = &m_stats[dir];
+ CCorePerPort *lp_port = &m_ports[dir];
+ CVirtualIFPerSideStats *lp_stats = &m_stats[dir];
if (unlikely(m==0)) {
lp_stats->m_tx_alloc_error++;
@@ -2233,19 +2249,17 @@ int CCoreEthIF::send_node(CGenNode * node){
}
/* update mac addr dest/src 12 bytes */
- uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*);
- uint8_t p_id=lp_port->m_port->get_port_id();
-
-
+ uint8_t *p = rte_pktmbuf_mtod(m, uint8_t*);
+ uint8_t p_id = lp_port->m_port->get_port_id();
+
memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12);
- /* if customer enables both mac_file and get_mac_ip_overide,
- * we will apply mac_file.
- */
- if ( unlikely(CGlobalInfo::m_options.preview.get_mac_ip_features_enable() ) ) {
- update_mac_addr(node,p);
+ /* when slowpath features are on */
+ if ( unlikely( CGlobalInfo::m_options.preview.get_is_slowpath_features_on() ) ) {
+ handle_slowpath_features(node, m, p, dir);
}
+
if ( unlikely( node->is_rx_check_enabled() ) ) {
lp_stats->m_tx_rx_check_pkt++;
lp->do_generate_new_mbuf_rxcheck(m, node, single_port);
@@ -2446,8 +2460,10 @@ public:
uint64_t m_active_sockets;
uint64_t m_total_nat_time_out;
+ uint64_t m_total_nat_time_out_wait_ack;
uint64_t m_total_nat_no_fid ;
uint64_t m_total_nat_active ;
+ uint64_t m_total_nat_syn_wait;
uint64_t m_total_nat_open ;
uint64_t m_total_nat_learn_error ;
@@ -2468,6 +2484,7 @@ public:
float m_active_flows;
float m_open_flows;
float m_cpu_util;
+ float m_cpu_util_raw;
float m_rx_cpu_util;
float m_bw_per_core;
uint8_t m_threads;
@@ -2477,7 +2494,7 @@ public:
public:
void Dump(FILE *fd,DumpFormat mode);
void DumpAllPorts(FILE *fd);
- void dump_json(std::string & json, bool baseline,uint32_t stats_tick);
+ void dump_json(std::string & json, bool baseline);
private:
std::string get_field(std::string name,float &f);
std::string get_field(std::string name,uint64_t &f);
@@ -2517,7 +2534,7 @@ std::string CGlobalStats::get_field_port(int port,std::string name,uint64_t &f){
}
-void CGlobalStats::dump_json(std::string & json, bool baseline,uint32_t stats_tick){
+void CGlobalStats::dump_json(std::string & json, bool baseline){
/* refactor this to JSON */
json="{\"name\":\"trex-global\",\"type\":0,";
@@ -2535,6 +2552,7 @@ void CGlobalStats::dump_json(std::string & json, bool baseline,uint32_t stats_ti
#define GET_FIELD_PORT(p,f) get_field_port(p,std::string(#f),lp->f)
json+=GET_FIELD(m_cpu_util);
+ json+=GET_FIELD(m_cpu_util_raw);
json+=GET_FIELD(m_bw_per_core);
json+=GET_FIELD(m_rx_cpu_util);
json+=GET_FIELD(m_platform_factor);
@@ -2564,8 +2582,10 @@ void CGlobalStats::dump_json(std::string & json, bool baseline,uint32_t stats_ti
json+=GET_FIELD(m_socket_util);
json+=GET_FIELD(m_total_nat_time_out);
+ json+=GET_FIELD(m_total_nat_time_out_wait_ack);
json+=GET_FIELD(m_total_nat_no_fid );
json+=GET_FIELD(m_total_nat_active );
+ json+=GET_FIELD(m_total_nat_syn_wait);
json+=GET_FIELD(m_total_nat_open );
json+=GET_FIELD(m_total_nat_learn_error);
@@ -2584,10 +2604,6 @@ void CGlobalStats::dump_json(std::string & json, bool baseline,uint32_t stats_ti
json+=GET_FIELD_PORT(i,m_total_rx_pps);
}
json+=m_template.dump_as_json("template");
- if ( stats_tick %4==0){
- json+=CGlobalInfo::dump_pool_as_json(); /* no need a feq update beacuse it trash the cores D cache, once in 2 sec */
- }
-
json+="\"unknown\":0}}" ;
}
@@ -2605,7 +2621,12 @@ void CGlobalStats::DumpAllPorts(FILE *fd){
fprintf (fd," Platform_factor : %2.1f \n",m_platform_factor);
fprintf (fd," Total-Tx : %s ",double_to_human_str(m_tx_bps,"bps",KBYE_1000).c_str());
if ( CGlobalInfo::is_learn_mode() ) {
- fprintf (fd," Nat_time_out : %8llu \n", (unsigned long long)m_total_nat_time_out);
+ fprintf (fd," NAT time out : %8llu", (unsigned long long)m_total_nat_time_out);
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
+ fprintf (fd," (%llu in wait for syn+ack)\n", (unsigned long long)m_total_nat_time_out_wait_ack);
+ } else {
+ fprintf (fd, "\n");
+ }
}else{
fprintf (fd,"\n");
}
@@ -2613,28 +2634,33 @@ void CGlobalStats::DumpAllPorts(FILE *fd){
fprintf (fd," Total-Rx : %s ",double_to_human_str(m_rx_bps,"bps",KBYE_1000).c_str());
if ( CGlobalInfo::is_learn_mode() ) {
- fprintf (fd," Nat_no_fid : %8llu \n", (unsigned long long)m_total_nat_no_fid);
+ fprintf (fd," NAT aged flow id: %8llu \n", (unsigned long long)m_total_nat_no_fid);
}else{
fprintf (fd,"\n");
}
fprintf (fd," Total-PPS : %s ",double_to_human_str(m_tx_pps,"pps",KBYE_1000).c_str());
if ( CGlobalInfo::is_learn_mode() ) {
- fprintf (fd," Total_nat_active: %8llu \n", (unsigned long long)m_total_nat_active);
+ fprintf (fd," Total NAT active: %8llu", (unsigned long long)m_total_nat_active);
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
+ fprintf (fd," (%llu waiting for syn)\n", (unsigned long long)m_total_nat_syn_wait);
+ } else {
+ fprintf (fd, "\n");
+ }
}else{
fprintf (fd,"\n");
}
fprintf (fd," Total-CPS : %s ",double_to_human_str(m_tx_cps,"cps",KBYE_1000).c_str());
if ( CGlobalInfo::is_learn_mode() ) {
- fprintf (fd," Total_nat_open : %8llu \n", (unsigned long long)m_total_nat_open);
+ fprintf (fd," Total NAT opened: %8llu \n", (unsigned long long)m_total_nat_open);
}else{
fprintf (fd,"\n");
}
fprintf (fd,"\n");
fprintf (fd," Expected-PPS : %s ",double_to_human_str(m_tx_expected_pps,"pps",KBYE_1000).c_str());
if ( CGlobalInfo::is_learn_verify_mode() ) {
- fprintf (fd," Nat_learn_errors: %8llu \n", (unsigned long long)m_total_nat_learn_error);
+ fprintf (fd," NAT learn errors: %8llu \n", (unsigned long long)m_total_nat_learn_error);
}else{
fprintf (fd,"\n");
}
@@ -3381,7 +3407,9 @@ int CGlobalTRex::ixgbe_prob_init(void){
if ( !CTRexExtendedDriverDb::Ins()->is_driver_exists(dev_info.driver_name) ){
- printf(" ERROR driver name %s is not supported \n",dev_info.driver_name);
+ printf(" Error: driver %s is not supported. Please consult the documentation for a list of supported drivers\n"
+ ,dev_info.driver_name);
+ exit(1);
}
int i;
@@ -3604,6 +3632,7 @@ void CGlobalTRex::get_stats(CGlobalStats & stats){
stats.m_num_of_ports = m_max_ports;
stats.m_cpu_util = m_fl.GetCpuUtil();
+ stats.m_cpu_util_raw = m_fl.GetCpuUtilRaw();
if (get_is_stateless()) {
stats.m_rx_cpu_util = m_rx_sl.get_cpu_util();
}
@@ -3655,8 +3684,10 @@ void CGlobalTRex::get_stats(CGlobalStats & stats){
uint64_t total_nat_time_out =0;
+ uint64_t total_nat_time_out_wait_ack =0;
uint64_t total_nat_no_fid =0;
uint64_t total_nat_active =0;
+ uint64_t total_nat_syn_wait = 0;
uint64_t total_nat_open =0;
uint64_t total_nat_learn_error=0;
@@ -3685,8 +3716,10 @@ void CGlobalTRex::get_stats(CGlobalStats & stats){
total_sockets += lpt->m_smart_gen.MaxSockets();
total_nat_time_out +=lpt->m_stats.m_nat_flow_timeout;
+ total_nat_time_out_wait_ack += lpt->m_stats.m_nat_flow_timeout_wait_ack;
total_nat_no_fid +=lpt->m_stats.m_nat_lookup_no_flow_id ;
total_nat_active +=lpt->m_stats.m_nat_lookup_add_flow_id - lpt->m_stats.m_nat_lookup_remove_flow_id;
+ total_nat_syn_wait += lpt->m_stats.m_nat_lookup_add_flow_id - lpt->m_stats.m_nat_lookup_wait_ack_state;
total_nat_open +=lpt->m_stats.m_nat_lookup_add_flow_id;
total_nat_learn_error +=lpt->m_stats.m_nat_flow_learn_error;
uint8_t port0 = lpt->getDualPortId() *2;
@@ -3708,8 +3741,10 @@ void CGlobalTRex::get_stats(CGlobalStats & stats){
}
stats.m_total_nat_time_out = total_nat_time_out;
+ stats.m_total_nat_time_out_wait_ack = total_nat_time_out_wait_ack;
stats.m_total_nat_no_fid = total_nat_no_fid;
stats.m_total_nat_active = total_nat_active;
+ stats.m_total_nat_syn_wait = total_nat_syn_wait;
stats.m_total_nat_open = total_nat_open;
stats.m_total_nat_learn_error = total_nat_learn_error;
@@ -3835,7 +3870,7 @@ CGlobalTRex::publish_async_data(bool sync_now, bool baseline) {
get_stats(m_stats);
}
- m_stats.dump_json(json, baseline,m_stats_cnt);
+ m_stats.dump_json(json, baseline);
m_zmq_publisher.publish_json(json);
/* generator json , all cores are the same just sample the first one */
@@ -3929,7 +3964,7 @@ CGlobalTRex::handle_slow_path(bool &was_stopped) {
if (m_io_modes.m_g_mode == CTrexGlobalIoMode::gMem) {
if ( m_stats_cnt%4==0) {
- fprintf (stdout," %s \n",CGlobalInfo::dump_pool_as_json().c_str());
+ fprintf (stdout," %s \n",CGlobalInfo::dump_pool_as_json_str().c_str());
}
}
@@ -3967,9 +4002,17 @@ CGlobalTRex::handle_slow_path(bool &was_stopped) {
m_mg.DumpRxCheck(stdout);
break;
}
-
}
-
+ }
+ }
+ if ( m_io_modes.m_g_mode == CTrexGlobalIoMode::gNAT ) {
+ if ( m_io_modes.m_nat_mode == CTrexGlobalIoMode::natENABLE ) {
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
+ fprintf(stdout, "NAT flow table info\n");
+ m_mg.dump_nat_flow_table(stdout);
+ } else {
+ fprintf(stdout, "\nThis is only relevant in --learn-mode %d\n", CParserOption::LEARN_MODE_TCP_ACK);
+ }
}
}
@@ -4221,12 +4264,24 @@ int CGlobalTRex::start_master_statefull() {
m_fl.Create();
m_fl.load_from_yaml(CGlobalInfo::m_options.cfg_file,get_cores_tx());
- if (CGlobalInfo::m_options.mac_file != "") {
- CGlobalInfo::m_options.preview.set_mac_ip_mapping_enable(true);
- m_fl.load_from_mac_file(CGlobalInfo::m_options.mac_file);
- m_fl.m_mac_info.set_configured(true);
- } else {
- m_fl.m_mac_info.set_configured(false);
+
+ /* client config */
+ if (CGlobalInfo::m_options.client_cfg_file != "") {
+ try {
+ m_fl.load_client_config_file(CGlobalInfo::m_options.client_cfg_file);
+ } catch (const std::runtime_error &e) {
+ std::cout << "\n*** " << e.what() << "\n\n";
+ exit(-1);
+ }
+ CGlobalInfo::m_options.preview.set_client_cfg_enable(true);
+ }
+
+ /* verify options */
+ try {
+ CGlobalInfo::m_options.verify();
+ } catch (const std::runtime_error &e) {
+ std::cout << "\n*** " << e.what() << "\n\n";
+ exit(-1);
}
m_expected_pps = m_fl.get_total_pps();
@@ -4860,6 +4915,18 @@ int main_test(int argc , char * argv[]){
return (0);
}
+void wait_x_sec(int sec) {
+ int i;
+ printf(" wait %d sec ", sec);
+ fflush(stdout);
+ for (i=0; i<sec; i++) {
+ delay(1000);
+ printf(".");
+ fflush(stdout);
+ }
+ printf("\n");
+ fflush(stdout);
+}
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
@@ -4870,32 +4937,28 @@ int CTRexExtendedDriverBase::configure_drop_queue(CPhyEthIF * _if) {
return (rte_eth_dev_rx_queue_stop(port_id, 0));
}
+int CTRexExtendedDriverBase::wait_for_stable_link() {
+ wait_x_sec(CGlobalInfo::m_options.m_wait_before_traffic);
+ return 0;
+}
+
+void CTRexExtendedDriverBase::wait_after_link_up() {
+ wait_x_sec(CGlobalInfo::m_options.m_wait_before_traffic);
+}
+
CFlowStatParser *CTRexExtendedDriverBase::get_flow_stat_parser() {
CFlowStatParser *parser = new CFlowStatParser();
assert (parser);
return parser;
}
-void wait_x_sec(int sec) {
- int i;
- printf(" wait %d sec ", sec);
- fflush(stdout);
- for (i=0; i<sec; i++) {
- delay(1000);
- printf(".");
- fflush(stdout);
- }
- printf("\n");
- fflush(stdout);
-}
-
// in 1G we need to wait if links became ready to soon
void CTRexExtendedDriverBase1G::wait_after_link_up(){
- wait_x_sec(7);
+ wait_x_sec(6 + CGlobalInfo::m_options.m_wait_before_traffic);
}
int CTRexExtendedDriverBase1G::wait_for_stable_link(){
- wait_x_sec(10);
+ wait_x_sec(9 + CGlobalInfo::m_options.m_wait_before_traffic);
return(0);
}
@@ -5277,7 +5340,7 @@ void CTRexExtendedDriverBase10G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFSta
}
int CTRexExtendedDriverBase10G::wait_for_stable_link(){
- delay(2000);
+ wait_x_sec(1 + CGlobalInfo::m_options.m_wait_before_traffic);
return (0);
}
@@ -5531,11 +5594,10 @@ void CTRexExtendedDriverBase40G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFSta
stats->f_ibytes = 0;
- stats->ierrors = stats1.ierrors + stats1.imissed + stats1.ibadcrc +
+ stats->ierrors = stats1.imissed + stats1.ibadcrc +
stats1.ibadlen +
stats1.ierrors +
stats1.oerrors +
- stats1.imcasts +
stats1.rx_nombuf +
stats1.tx_pause_xon +
stats1.rx_pause_xon +
@@ -5550,7 +5612,7 @@ void CTRexExtendedDriverBase40G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFSta
}
int CTRexExtendedDriverBase40G::wait_for_stable_link(){
- delay(2000);
+ wait_x_sec(1 + CGlobalInfo::m_options.m_wait_before_traffic);
return (0);
}
@@ -5605,11 +5667,10 @@ void CTRexExtendedDriverBase1GVm::get_extended_stats(CPhyEthIF * _if,CPhyEthIFSt
stats->f_ibytes = 0;
- stats->ierrors = stats1.ierrors + stats1.imissed + stats1.ibadcrc +
+ stats->ierrors = stats1.imissed + stats1.ibadcrc +
stats1.ibadlen +
stats1.ierrors +
stats1.oerrors +
- stats1.imcasts +
stats1.rx_nombuf +
stats1.tx_pause_xon +
stats1.rx_pause_xon +
@@ -5624,7 +5685,7 @@ void CTRexExtendedDriverBase1GVm::get_extended_stats(CPhyEthIF * _if,CPhyEthIFSt
}
int CTRexExtendedDriverBase1GVm::wait_for_stable_link(){
- delay(10);
+ wait_x_sec(CGlobalInfo::m_options.m_wait_before_traffic);
return (0);
}
@@ -5782,6 +5843,10 @@ int TrexDpdkPlatformApi::get_rfc2544_info(void *rfc2544_info, int min, int max,
return g_trex.m_rx_sl.get_rfc2544_info((rfc2544_info_t *)rfc2544_info, min, max, reset);
}
+int TrexDpdkPlatformApi::get_rx_err_cntrs(void *rx_err_cntrs) const {
+ return g_trex.m_rx_sl.get_rx_err_cntrs((CRxCoreErrCntrs *)rx_err_cntrs);
+}
+
int TrexDpdkPlatformApi::reset_hw_flow_stats(uint8_t port_id) const {
return g_trex.m_ports[port_id].reset_hw_flow_stats();
}
@@ -5812,6 +5877,20 @@ int TrexDpdkPlatformApi::get_active_pgids(flow_stat_active_t &result) const {
return g_trex.m_trex_stateless->m_rx_flow_stat.get_active_pgids(result);
}
+int TrexDpdkPlatformApi::get_cpu_util_full(cpu_util_full_t &cpu_util_full) const {
+ cpu_util_full.resize((int)g_trex.m_fl.m_threads_info.size());
+ for (int thread_id=0; thread_id<(int)g_trex.m_fl.m_threads_info.size(); thread_id++) {
+ CFlowGenListPerThread * lp=g_trex.m_fl.m_threads_info[thread_id];
+ lp->m_cpu_cp_u.GetHistory(cpu_util_full[thread_id]);
+ }
+ return 0;
+}
+
+int TrexDpdkPlatformApi::get_mbuf_util(Json::Value &mbuf_pool) const {
+ CGlobalInfo::dump_pool_as_json(mbuf_pool);
+ return 0;
+}
+
CFlowStatParser *TrexDpdkPlatformApi::get_flow_stat_parser() const {
return CTRexExtendedDriverDb::Ins()->get_drv()->get_flow_stat_parser();
}
diff --git a/src/nat_check.cpp b/src/nat_check.cpp
index 7e224430..f3dd93d1 100755
--- a/src/nat_check.cpp
+++ b/src/nat_check.cpp
@@ -41,7 +41,8 @@ void CGenNodeNatInfo::dump(FILE *fd){
int i;
for (i=0; i<m_cnt; i++) {
CNatFlowInfo * lp=&m_data[i];
- fprintf (fd," id:%d , external ip:%08x:%x , ex_port: %04x , fid: %d \n",i,lp->m_external_ip,lp->m_external_ip_server,lp->m_external_port,lp->m_fid);
+ fprintf (fd," id:%d , external ip:%08x , ex_port: %04x , TCP seq:%x fid: %d \n"
+ , i, lp->m_external_ip, lp->m_external_port, lp->m_tcp_seq, lp->m_fid);
}
}
@@ -51,7 +52,6 @@ void CGenNodeNatInfo::init(){
m_cnt=0;
}
-
void CNatStats::reset(){
m_total_rx=0;
m_total_msg=0;
@@ -147,14 +147,17 @@ void CNatRxManager::get_info_from_tcp_ack(uint32_t tcp_ack, uint32_t &fid, uint8
* option - pointer to our proprietary NAT info IP option.
* If it is NULL, the NAT info is in the TCP ACK number
* ipv4 - pointer to ipv4 header to extract info from.
+ * is_first - Is this the first packet of the flow or second. To handle firewalls that do
+ * TCP seq randomization on the server->client side, we also look at the second
+ * packet of the flow (SYN+ACK), and extract its seq num.
*/
-void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4) {
+void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4, bool is_first) {
CNatPerThreadInfo * thread_info;
uint32_t fid=0;
+ uint32_t tcp_seq;
/* Extract info from the packet ! */
uint32_t ext_ip = ipv4->getSourceIp();
- uint32_t ext_ip_server = ipv4->getDestIp();
uint8_t proto = ipv4->getProtocol();
/* must be TCP/UDP this is the only supported proto */
if (!( (proto==6) || (proto==17) )){
@@ -165,21 +168,48 @@ void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4) {
TCPHeader *tcp = (TCPHeader *) (((char *)ipv4)+ ipv4->getHeaderLength());
uint16_t ext_port = tcp->getSourcePort();
+ tcp_seq = tcp->getSeqNumber();
+
if (option) {
thread_info = get_thread_info(option->get_thread_id());
fid = option->get_fid();
} else {
- uint8_t thread_id;
- get_info_from_tcp_ack(tcp->getAckNumber(), fid, thread_id);
- thread_info = get_thread_info(thread_id);
+ uint8_t thread_id;
+
+ if (is_first) {
+ uint32_t tcp_ack = tcp->getAckNumber();
+ get_info_from_tcp_ack(tcp_ack, fid, thread_id);
+ thread_info = get_thread_info(thread_id);
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) {
+ uint32_t dst_ip = ipv4->getDestIp();
+ uint16_t dst_port = tcp->getDestPort();
+ uint64_t map_key = (dst_ip << 16) + dst_port;
+ double time_stamp = now_sec();
+ m_ft.insert(map_key, tcp_ack, time_stamp);
+ m_ft.clear_old(time_stamp - 1);
+ }
+ } else {
+ uint32_t val;
+ // server->client packet. IP/port reversed in regard to first SYN packet
+ uint64_t map_key = (ext_ip << 16) + ext_port;
+ if (m_ft.erase(map_key, val)) {
+ get_info_from_tcp_ack(val, fid, thread_id);
+ thread_info = get_thread_info(thread_id);
+ } else {
+ // flow was not found in the table
+ thread_info = 0;
+ }
+ }
}
+
if (unlikely(!thread_info)) {
return;
}
#ifdef NAT_TRACE_
- printf("rx msg ext ip : %08x:%08x ext port : %04x flow_id : %d \n",ext_ip,ext_ip_server,ext_port, fid);
+ printf("rx msg ext ip: %08x ext port: %04x TCP Seq: %08x flow_id : %d (%s) \n", ext_ip, ext_port, tcp_seq, fid
+ , is_first ? "first":"second");
#endif
CGenNodeNatInfo * node=thread_info->m_cur_nat_msg;
@@ -194,9 +224,13 @@ void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4) {
CNatFlowInfo * msg=node->get_next_msg();
/* fill the message */
- msg->m_external_ip = ext_ip;
- msg->m_external_ip_server = ext_ip_server;
- msg->m_external_port = ext_port;
+ if (is_first) {
+ msg->m_external_ip = ext_ip;
+ msg->m_external_port = ext_port;
+ } else {
+ msg->m_external_port = TCPHeader::TCP_INVALID_PORT;
+ }
+ msg->m_tcp_seq = tcp_seq;
msg->m_fid = fid;
msg->m_pad = 0xee;
@@ -221,7 +255,8 @@ void CNatStats::Dump(FILE *fd){
void CNatRxManager::Dump(FILE *fd){
- m_stats.Dump(stdout);
+ m_stats.Dump(fd);
+ m_ft.dump(fd);
}
void CNatRxManager::DumpShort(FILE *fd){
diff --git a/src/nat_check.h b/src/nat_check.h
index 133501ae..18add5e0 100755
--- a/src/nat_check.h
+++ b/src/nat_check.h
@@ -21,6 +21,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+#include <map>
#include "msg_manager.h"
#include <common/Network/Packet/TcpHeader.h>
#include <common/Network/Packet/UdpHeader.h>
@@ -28,6 +29,7 @@ limitations under the License.
#include <common/Network/Packet/IPv6Header.h>
#include <common/Network/Packet/EthernetHeader.h>
#include "os_time.h"
+#include "nat_check_flow_table.h"
// 2msec timeout
#define MAX_TIME_MSG_IN_QUEUE_SEC ( 0.002 )
@@ -121,7 +123,7 @@ private:
struct CNatFlowInfo {
uint32_t m_external_ip;
- uint32_t m_external_ip_server;
+ uint32_t m_tcp_seq;
uint32_t m_fid;
uint16_t m_external_port;
uint16_t m_pad;
@@ -210,13 +212,12 @@ public:
void Dump(FILE *fd);
};
-
class CNatRxManager {
public:
bool Create();
void Delete();
- void handle_packet_ipv4(CNatOption * option, IPHeader * ipv4);
+ void handle_packet_ipv4(CNatOption * option, IPHeader * ipv4, bool is_first);
void handle_aging();
void Dump(FILE *fd);
void DumpShort(FILE *fd);
@@ -232,6 +233,7 @@ private:
uint8_t m_max_threads;
CNatPerThreadInfo * m_per_thread;
CNatStats m_stats;
+ CNatCheckFlowTable m_ft;
};
diff --git a/src/nat_check_flow_table.cpp b/src/nat_check_flow_table.cpp
new file mode 100644
index 00000000..18ba8142
--- /dev/null
+++ b/src/nat_check_flow_table.cpp
@@ -0,0 +1,314 @@
+/*
+ Ido Barnea
+ Cisco Systems, Inc.
+*/
+
+/*
+ Copyright (c) 2016-2016 Cisco Systems, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include <assert.h>
+#include <stdint.h>
+#include <string>
+#include <iostream>
+#include <new>
+#include "nat_check_flow_table.h"
+/*
+ classes in this file:
+ CNatCheckFlowTableList - List implementation
+ CNatCheckFlowTableMap - Map implementation
+ CNatData - element of data that exists in the map and the list.
+ CNatCheckFlowTable - Wrapper class which is the interface to outside.
+ New element is always inserted to the list and map.
+ If element is removed, it is always removed from list and map together.
+ Map is used to lookup elemnt by key.
+ List is used to clean up old elements by timestamp. We guarantee the list is always sorted by timestamp,
+ since we always insert at the end, with increasing timestamp.
+*/
+
+std::ostream& operator<<(std::ostream& os, const CNatData &cn) {
+ os << "(" << &cn << ")" << "data:" << cn.m_data << " time:" << cn.m_timestamp;
+ os << " prev:" << cn.m_prev << " next:" << cn.m_next;
+ return os;
+}
+
+// map implementation
+CNatData *CNatCheckFlowTableMap::erase(uint64_t key) {
+ nat_check_flow_map_iter_no_const_t it = m_map.find(key);
+
+ if (it != m_map.end()) {
+ CNatData *val = it->second;
+ m_map.erase(it);
+ return val;
+ }
+
+ return NULL;
+}
+
+bool CNatCheckFlowTableMap::find(uint64_t key, uint32_t &val) {
+ nat_check_flow_map_iter_t it = m_map.find(key);
+
+ if (it != m_map.end()) {
+ CNatData *data = it->second;
+ val = data->get_data();
+ return true;
+ }
+
+ return false;
+}
+
+// for testing
+bool CNatCheckFlowTableMap::verify(uint32_t *arr, int size) {
+ uint32_t val = -1;
+ int real_size = 0;
+
+ for (int i = 0; i < size; i++) {
+ if (arr[i] == -1)
+ continue;
+ real_size++;
+ find(i, val);
+ if (val != arr[i])
+ return false;
+ }
+
+ if (m_map.size() != real_size) {
+ std::cout << "Error: Wrong map size " << m_map.size() << ". Should be " << real_size << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+CNatData * CNatCheckFlowTableMap::insert(uint64_t key, uint32_t val, double time) {
+ CNatData *elem = new CNatData;
+ assert(elem);
+ elem->set_data(val);
+ elem->set_key(key);
+ elem->set_timestamp(time);
+ std::pair<uint64_t, CNatData *> pair = std::pair<uint64_t, CNatData *>(key, elem);
+
+ if (m_map.insert(pair).second == false) {
+ delete elem;
+ return NULL;
+ } else {
+ return elem;
+ }
+}
+
+std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTableMap& cf) {
+ nat_check_flow_map_iter_t it;
+
+ os << "NAT check flow table map:\n";
+ for (it = cf.m_map.begin(); it != cf.m_map.end(); it++) {
+ CNatData *data = it->second;
+ uint32_t key = it->first;
+ os << " " << key << ":" << *data << std::endl;
+ }
+ return os;
+}
+
+void CNatCheckFlowTableList::dump_short(FILE *fd) {
+ fprintf(fd, "list:\n");
+ // this is not fully safe, since we call it from CP core, and rx core changes the list.
+ // It is usefull as a debug function
+ if (m_head) {
+ fprintf(fd, " head: time:%f key:%x data:%x\n", m_head->get_timestamp(), m_head->get_key(), m_head->get_data());
+ fprintf(fd, " tail: time:%f key:%x data:%x\n", m_tail->get_timestamp(), m_tail->get_key(), m_tail->get_data());
+ }
+}
+
+// list implementation
+// The list is always sorted by timestamp, since we always insert at the end, with increasing timestamp
+void CNatCheckFlowTableList::erase(CNatData *data) {
+ if (m_head == data) {
+ m_head = data->m_next;
+ }
+ if (m_tail == data) {
+ m_tail = data->m_prev;
+ }
+ if (data->m_prev) {
+ data->m_prev->m_next = data->m_next;
+ }
+ if (data->m_next) {
+ data->m_next->m_prev = data->m_prev;
+ }
+}
+
+// insert as last element in list
+void CNatCheckFlowTableList::insert(CNatData *data) {
+ data->m_prev = m_tail;
+ data->m_next = NULL;
+
+ if (m_tail != NULL) {
+ m_tail->m_next = data;
+ } else {
+ // if m_tail is NULL m_head is also NULL
+ m_head = data;
+ }
+ m_tail = data;
+}
+
+bool CNatCheckFlowTableList::verify(uint32_t *arr, int size) {
+ int index = -1;
+ CNatData *elem = m_head;
+ int count = 0;
+
+ while (index < size - 1) {
+ index++;
+ if (arr[index] == -1) {
+ continue;
+ }
+ count++;
+
+ if (elem->get_data() != arr[index]) {
+ return false;
+ }
+
+ if (elem == NULL) {
+ std::cout << "Too few items in list. Only " << count << std::endl;
+ return false;
+ }
+ elem = elem->m_next;
+ }
+
+ // We expect number of items in list to be like num of val!=-1 in arr
+ if (elem != NULL) {
+ std::cout << "Too many items in list" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTableList& cf) {
+ CNatData *it = cf.m_head;
+
+ os << "NAT check flow table list:\n";
+ os << " head:" << cf.m_head << " tail:" << cf.m_tail << std::endl;
+ while (it != NULL) {
+ os << " " << *it << std::endl;
+ it = it->m_next;
+ }
+
+ return os;
+}
+
+// flow table
+std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTable& cf) {
+ os << "========= Flow table start =========" << std::endl;
+ os << cf.m_map;
+ os << cf.m_list;
+ os << "========= Flow table end =========" << std::endl;
+
+ return os;
+}
+
+void CNatCheckFlowTable::clear_old(double time) {
+ CNatData *data = m_list.get_head();
+ uint32_t val;
+
+ while (data) {
+ if (data->get_timestamp() < time) {
+ erase(data->get_key(), val);
+ data = m_list.get_head();
+ } else {
+ break;
+ }
+ }
+}
+
+void CNatCheckFlowTable::dump(FILE *fd) {
+ fprintf(fd, "map size:%lu\n", m_map.size());
+ m_list.dump_short(fd);
+}
+
+bool CNatCheckFlowTable::erase(uint64_t key, uint32_t &val) {
+ CNatData *data = m_map.erase(key);
+
+ if (!data)
+ return false;
+
+ val = data->get_data();
+ m_list.erase(data);
+ delete data;
+
+ return true;
+}
+
+bool CNatCheckFlowTable::insert(uint64_t key, uint32_t val, double time) {
+ CNatData *res;
+
+ res = m_map.insert(key, val, time);
+ if (!res) {
+ return false;
+ } else {
+ m_list.insert(res);
+ }
+ return true;
+}
+
+CNatCheckFlowTable::~CNatCheckFlowTable() {
+ clear_old(UINT64_MAX);
+}
+
+bool CNatCheckFlowTable::test() {
+ uint32_t size = 100;
+ uint32_t arr[size];
+ int i;
+ uint32_t val;
+
+ for (i = 0; i < size; i++) {
+ arr[i] = i+200;
+ }
+
+ // insert some elements
+ for (i = 0; i < size; i++) {
+ val = arr[i];
+ assert(insert(i, val, i) == true);
+ }
+
+ // insert same elements. should fail
+ for (i = 0; i < size; i++) {
+ val = arr[i];
+ assert(insert(i, val, val) == false);
+ }
+
+ // remove element we did not insert
+ assert(erase(size, val) == false);
+
+ assert (m_map.verify(arr, size) == true);
+ assert (m_list.verify(arr, size) == true);
+
+ // remove even keys
+ for (i = 0; i < size; i += 2) {
+ assert(erase(i, val) == true);
+ assert (val == arr[i]);
+ arr[i] = -1;
+ }
+
+ assert (m_map.verify(arr, size) == true);
+ assert (m_list.verify(arr, size) == true);
+
+ // clear half of the old values (We removed the even already, so 1/4 should be left)
+ clear_old(size/2);
+ for (i = 0; i < size/2; i++) {
+ arr [i] = -1;
+ }
+
+ assert (m_map.verify(arr, size) == true);
+ assert (m_list.verify(arr, size) == true);
+
+ return true;
+}
diff --git a/src/nat_check_flow_table.h b/src/nat_check_flow_table.h
new file mode 100644
index 00000000..dddd45b6
--- /dev/null
+++ b/src/nat_check_flow_table.h
@@ -0,0 +1,111 @@
+/*
+ Ido Barnea
+ Cisco Systems, Inc.
+*/
+
+/*
+ Copyright (c) 2016-2016 Cisco Systems, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+#ifndef NAT_CHECK_FLOW_TABLE_H
+#define NAT_CHECK_FLOW_TABLE_H
+#include <map>
+
+class CNatData;
+class CNatCheckFlowTableList;
+
+typedef std::map<uint64_t, CNatData *, std::less<uint64_t> > nat_check_flow_map_t;
+typedef nat_check_flow_map_t::const_iterator nat_check_flow_map_iter_t;
+typedef nat_check_flow_map_t::iterator nat_check_flow_map_iter_no_const_t;
+
+// One element of list and map
+class CNatData {
+ friend class CNatCheckFlowTableList; // access m_next and m_prev
+ friend std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTableList& cf);
+ friend std::ostream& operator<<(std::ostream& os, const CNatData &cn);
+
+ public:
+ uint32_t get_data() {return m_data;}
+ void set_data(uint32_t val) {m_data = val;}
+ uint32_t get_key() {return m_key;}
+ void set_key(uint32_t val) {m_key = val;}
+ double get_timestamp() {return m_timestamp;}
+ void set_timestamp(double val) {m_timestamp = val;}
+ CNatData() {
+ m_next = NULL;
+ m_prev = NULL;
+ }
+
+ private:
+ double m_timestamp;
+ uint64_t m_key;
+ CNatData *m_prev;
+ CNatData *m_next;
+ uint32_t m_data;
+};
+
+class CNatCheckFlowTableMap {
+ friend class CNatCheckFlowTable;
+ friend std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTableMap& cf);
+
+ private:
+ void clear(void) {m_map.clear();}
+ CNatData *erase(uint64_t key);
+ bool find(uint64_t key, uint32_t &val);
+ CNatData *insert(uint64_t key, uint32_t val, double time);
+ bool verify(uint32_t *arr, int size);
+ uint64_t size(void) {return m_map.size();}
+
+ private:
+ nat_check_flow_map_t m_map;
+};
+
+class CNatCheckFlowTableList {
+ friend class CNatCheckFlowTable;
+ friend std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTableList& cf);
+
+ private:
+ void dump_short(FILE *fd);
+ void erase(CNatData *data);
+ CNatData *get_head() {return m_head;}
+ void insert(CNatData *data);
+ bool verify(uint32_t *arr, int size);
+
+ CNatCheckFlowTableList() {
+ m_head = NULL;
+ m_tail = NULL;
+ }
+
+ private:
+ CNatData *m_head;
+ CNatData *m_tail;
+};
+
+class CNatCheckFlowTable {
+ friend std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTable& cf);
+
+ public:
+ ~CNatCheckFlowTable();
+ void clear_old(double time);
+ void dump(FILE *fd);
+ bool erase(uint64_t key, uint32_t &val);
+ bool insert(uint64_t key, uint32_t val, double time);
+ bool test();
+
+ private:
+ CNatCheckFlowTableMap m_map;
+ CNatCheckFlowTableList m_list;
+};
+
+#endif
diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
index 68ea2587..27010e0e 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
@@ -157,6 +157,29 @@ TrexRpcCmdGetActivePGIds::_run(const Json::Value &params, Json::Value &result) {
return (TREX_RPC_CMD_OK);
}
+// get utilization of CPU per thread with up to 20 latest values + mbufs per socket
+trex_rpc_cmd_rc_e
+TrexRpcCmdGetUtilization::_run(const Json::Value &params, Json::Value &result) {
+ cpu_util_full_t cpu_util_full;
+
+ Json::Value &section = result["result"];
+
+ if (get_stateless_obj()->get_platform_api()->get_mbuf_util(section) != 0) {
+ return TREX_RPC_CMD_INTERNAL_ERR;
+ }
+
+ if (get_stateless_obj()->get_platform_api()->get_cpu_util_full(cpu_util_full) != 0) {
+ return TREX_RPC_CMD_INTERNAL_ERR;
+ }
+
+ for (int thread_id = 0; thread_id < cpu_util_full.size(); thread_id++) {
+ for (int history_id = 0; history_id < cpu_util_full[thread_id].size(); history_id++) {
+ section["cpu"][thread_id].append(cpu_util_full[thread_id][history_id]);
+ }
+ }
+ return (TREX_RPC_CMD_OK);
+}
+
/**
* get the CPU model
*
diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h
index affa65c1..2776727d 100644
--- a/src/rpc-server/commands/trex_rpc_cmds.h
+++ b/src/rpc-server/commands/trex_rpc_cmds.h
@@ -67,6 +67,7 @@ TREX_RPC_CMD_DEFINE(TrexRpcPublishNow, "publish_now", 2, false,
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetCmds, "get_supported_cmds", 0, false, APIClass::API_CLASS_TYPE_CORE);
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetVersion, "get_version", 0, false, APIClass::API_CLASS_TYPE_CORE);
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetActivePGIds, "get_active_pgids", 0, false, APIClass::API_CLASS_TYPE_CORE);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetUtilization, "get_utilization", 0, false, APIClass::API_CLASS_TYPE_CORE);
TREX_RPC_CMD_DEFINE_EXTENDED(TrexRpcCmdGetSysInfo, "get_system_info", 0, false, APIClass::API_CLASS_TYPE_CORE,
diff --git a/src/rpc-server/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp
index 7104792e..6144d265 100644
--- a/src/rpc-server/trex_rpc_cmds_table.cpp
+++ b/src/rpc-server/trex_rpc_cmds_table.cpp
@@ -39,6 +39,7 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() {
register_command(new TrexRpcCmdGetCmds());
register_command(new TrexRpcCmdGetVersion());
register_command(new TrexRpcCmdGetActivePGIds());
+ register_command(new TrexRpcCmdGetUtilization());
register_command(new TrexRpcCmdGetSysInfo());
register_command(new TrexRpcCmdGetOwner());
register_command(new TrexRpcCmdAcquire());
diff --git a/src/sim/trex_sim_stateful.cpp b/src/sim/trex_sim_stateful.cpp
index 88698cd1..7546644d 100644
--- a/src/sim/trex_sim_stateful.cpp
+++ b/src/sim/trex_sim_stateful.cpp
@@ -165,6 +165,24 @@ int load_list_of_cap_files(CParserOption * op){
CFlowGenList fl;
fl.Create();
fl.load_from_yaml(op->cfg_file,1);
+
+ if (op->client_cfg_file != "") {
+ try {
+ fl.load_client_config_file(op->client_cfg_file);
+ } catch (const std::runtime_error &e) {
+ std::cout << "\n*** " << e.what() << "\n\n";
+ exit(-1);
+ }
+ CGlobalInfo::m_options.preview.set_client_cfg_enable(true);
+ }
+
+ try {
+ CGlobalInfo::m_options.verify();
+ } catch (const std::runtime_error &e) {
+ std::cout << "\n*** " << e.what() << "\n\n";
+ exit(-1);
+ }
+
if ( op->preview.getVMode() >0 ) {
fl.DumpCsv(stdout);
}
@@ -596,5 +614,10 @@ int merge_2_cap_files_sip() {
int
SimStateful::run() {
assert( CMsgIns::Ins()->Create(4) );
- return load_list_of_cap_files(&CGlobalInfo::m_options);
+ try {
+ return load_list_of_cap_files(&CGlobalInfo::m_options);
+ } catch (const std::runtime_error &e) {
+ std::cout << "\n*** " << e.what() << "\n\n";
+ exit(-1);
+ }
}
diff --git a/src/stateless/cp/trex_stateless.cpp b/src/stateless/cp/trex_stateless.cpp
index 698ede90..8633897e 100644
--- a/src/stateless/cp/trex_stateless.cpp
+++ b/src/stateless/cp/trex_stateless.cpp
@@ -54,7 +54,11 @@ TrexStateless::TrexStateless(const TrexStatelessCfg &cfg) {
m_publisher = cfg.m_publisher;
/* API core version */
- m_api_classes[APIClass::API_CLASS_TYPE_CORE].init(APIClass::API_CLASS_TYPE_CORE, 1, 2);
+ const int API_VER_MAJOR = 1;
+ const int API_VER_MINOR = 3;
+ m_api_classes[APIClass::API_CLASS_TYPE_CORE].init(APIClass::API_CLASS_TYPE_CORE,
+ API_VER_MAJOR,
+ API_VER_MINOR);
}
/**
diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp
index 0bd601b6..853fc868 100644
--- a/src/stateless/rx/trex_stateless_rx_core.cpp
+++ b/src/stateless/rx/trex_stateless_rx_core.cpp
@@ -206,6 +206,7 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *
if (unlikely(fsp_head->magic != FLOW_STAT_PAYLOAD_MAGIC) || hw_id >= MAX_FLOW_STATS_PAYLOAD) {
good_packet = false;
+ m_err_cntrs.m_bad_header++;
} else {
curr_rfc2544 = &m_rfc2544[hw_id];
@@ -216,6 +217,7 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *
if (fsp_head->flow_seq == curr_rfc2544->get_prev_flow_seq()) {
// packet from previous flow using this hw_id that arrived late
good_packet = false;
+ m_err_cntrs.m_old_flow++;
} else {
if (curr_rfc2544->no_flow_seq()) {
// first packet we see from this flow
@@ -224,6 +226,7 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *
} else {
// garbage packet
good_packet = false;
+ m_err_cntrs.m_bad_header++;
}
}
}
@@ -278,9 +281,7 @@ void CRxCoreStateless::handle_rx_pkt(CLatencyManagerPerPortStl *lp, rte_mbuf_t *
}
} else {
hw_id = get_hw_id(ip_id);
- if (hw_id >= MAX_FLOW_STATS) {
- // increase some error counter
- } else {
+ if (hw_id < MAX_FLOW_STATS) {
lp->m_port.m_rx_pg_stat[hw_id].add_pkts(1);
lp->m_port.m_rx_pg_stat[hw_id].add_bytes(m->pkt_len + 4); // +4 for ethernet CRC
}
@@ -444,6 +445,11 @@ int CRxCoreStateless::get_rfc2544_info(rfc2544_info_t *rfc2544_info, int min, in
return 0;
}
+int CRxCoreStateless::get_rx_err_cntrs(CRxCoreErrCntrs *rx_err) {
+ *rx_err = m_err_cntrs;
+ return 0;
+}
+
void CRxCoreStateless::set_working_msg_ack(bool val) {
sanb_smp_memory_barrier();
m_ack_start_work_msg = val;
diff --git a/src/stateless/rx/trex_stateless_rx_core.h b/src/stateless/rx/trex_stateless_rx_core.h
index 209dc29f..fc66704e 100644
--- a/src/stateless/rx/trex_stateless_rx_core.h
+++ b/src/stateless/rx/trex_stateless_rx_core.h
@@ -95,6 +95,25 @@ class CRFC2544Info {
uint16_t m_prev_flow_seq;
};
+class CRxCoreErrCntrs {
+ friend CRxCoreStateless;
+
+ public:
+ uint64_t get_bad_header() {return m_bad_header;}
+ uint64_t get_old_flow() {return m_old_flow;}
+ CRxCoreErrCntrs() {
+ reset();
+ }
+ void reset() {
+ m_bad_header = 0;
+ m_old_flow = 0;
+ }
+
+ private:
+ uint64_t m_bad_header;
+ uint64_t m_old_flow;
+};
+
class CRxCoreStateless {
enum state_e {
STATE_IDLE,
@@ -109,7 +128,11 @@ class CRxCoreStateless {
int get_rx_stats(uint8_t port_id, rx_per_flow_t *rx_stats, int min, int max, bool reset
, TrexPlatformApi::driver_stat_cap_e type);
int get_rfc2544_info(rfc2544_info_t *rfc2544_info, int min, int max, bool reset);
- void work() {m_state = STATE_WORKING;}
+ int get_rx_err_cntrs(CRxCoreErrCntrs *rx_err);
+ void work() {
+ m_state = STATE_WORKING;
+ m_err_cntrs.reset(); // When starting to work, reset global counters
+ }
void idle() {m_state = STATE_IDLE;}
void quit() {m_state = STATE_QUIT;}
bool is_working() const {return (m_ack_start_work_msg == true);}
@@ -146,6 +169,7 @@ class CRxCoreStateless {
CCpuUtlCp m_cpu_cp_u;
// Used for acking "work" (go out of idle) messages from cp
volatile bool m_ack_start_work_msg __rte_cache_aligned;
+ CRxCoreErrCntrs m_err_cntrs;
CRFC2544Info m_rfc2544[MAX_FLOW_STATS_PAYLOAD];
};
#endif
diff --git a/src/trex_client_config.cpp b/src/trex_client_config.cpp
new file mode 100644
index 00000000..b56037ea
--- /dev/null
+++ b/src/trex_client_config.cpp
@@ -0,0 +1,235 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2016 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#include <stdexcept>
+#include <sstream>
+#include <fstream>
+
+#include <yaml-cpp/yaml.h>
+
+#include "utl_yaml.h"
+#include "trex_client_config.h"
+#include "common/basic_utils.h"
+#include "bp_sim.h"
+
+void
+ClientCfgEntry::dump() const {
+
+ std::cout << "IP start: " << ip_to_str(m_ip_start) << "\n";
+ std::cout << "IP end: " << ip_to_str(m_ip_end) << "\n";
+
+ //m_cfg.dump();
+
+ #if 0
+ std::cout << "Init. MAC addr: ";
+ for (int i = 0; i < 6; i++) {
+ printf("%lx:", ( (m_initiator.m_dst_mac >> ( (6-i) * 8)) & 0xFF ) );
+ }
+ std::cout << "\n";
+
+ std::cout << "Init. VLAN: " << m_initiator.m_vlan << "\n";
+
+ std::cout << "Res. MAC addr: ";
+ for (int i = 0; i < 6; i++) {
+ printf("%lx:", ( (m_responder.m_dst_mac >> ( (6-i) * 8)) & 0xFF ) );
+ }
+ std::cout << "\n";
+
+ std::cout << "Res. VLAN: " << m_responder.m_vlan << "\n";
+ #endif
+}
+
+
+/**
+ * loads a YAML file containing
+ * the client groups configuration
+ *
+ */
+void
+ClientCfgDB::load_yaml_file(const std::string &filename) {
+ std::stringstream ss;
+
+ m_groups.clear();
+ m_cache_group = NULL;
+
+ /* wrapper parser */
+ YAML::Node root;
+ YAMLParserWrapper parser(filename);
+ parser.load(root);
+
+ /* parse globals */
+ m_under_vlan = parser.parse_bool(root, "vlan");
+
+ const YAML::Node &groups = parser.parse_list(root, "groups");
+
+ /* parse each group */
+ for (int i = 0; i < groups.size(); i++) {
+ parse_single_group(parser, groups[i]);
+ }
+
+ verify(parser);
+
+ m_is_empty = false;
+
+}
+
+/**
+ * reads a single group of clients from YAML
+ *
+ */
+void
+ClientCfgDB::parse_single_group(YAMLParserWrapper &parser, const YAML::Node &node) {
+ ClientCfgEntry group;
+
+ /* ip_start */
+ group.m_ip_start = parser.parse_ip(node, "ip_start");
+
+ /* ip_end */
+ group.m_ip_end = parser.parse_ip(node, "ip_end");
+
+ /* sanity check */
+ if (group.m_ip_end < group.m_ip_start) {
+ parser.parse_err("ip_end must be >= ip_start", node);
+ }
+
+ const YAML::Node &init = parser.parse_map(node, "initiator");
+ const YAML::Node &resp = parser.parse_map(node, "responder");
+
+ parse_dir(parser, init, group.m_cfg.m_initiator);
+ parse_dir(parser, resp, group.m_cfg.m_responder);
+
+
+ group.m_count = parser.parse_uint(node, "count", 0, UINT64_MAX, 1);
+
+ /* add to map with copying */
+ m_groups[group.m_ip_start] = group;
+
+}
+
+void
+ClientCfgDB::parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, ClientCfgDir &dir) {
+ if (node.FindValue("src_mac")) {
+ dir.set_dst_mac_addr(parser.parse_mac_addr(node, "src_mac"));
+ }
+
+ if (node.FindValue("dst_mac")) {
+ dir.set_dst_mac_addr(parser.parse_mac_addr(node, "dst_mac"));
+ }
+
+ if (m_under_vlan) {
+ dir.set_vlan(parser.parse_uint(node, "vlan", 0, 0xfff));
+ } else {
+ if (node.FindValue("vlan")) {
+ parser.parse_err("VLAN config was disabled", node["vlan"]);
+ }
+ }
+}
+
+/**
+ * sanity checks
+ *
+ * @author imarom (28-Jun-16)
+ */
+void
+ClientCfgDB::verify(const YAMLParserWrapper &parser) const {
+ std::stringstream ss;
+ uint32_t monotonic = 0;
+
+ /* check that no interval overlaps */
+
+ /* all intervals do not overloap iff when sorted each start/end dots are strong monotonic */
+ for (const auto &p : m_groups) {
+ const ClientCfgEntry &group = p.second;
+
+ if ( (monotonic > 0 ) && (group.m_ip_start <= monotonic) ) {
+ ss << "IP '" << ip_to_str(group.m_ip_start) << "' - '" << ip_to_str(group.m_ip_end) << "' overlaps with other groups";
+ parser.parse_err(ss.str());
+ }
+
+ monotonic = group.m_ip_end;
+ }
+}
+
+/**
+ * lookup function
+ * should be fast
+ *
+ */
+ClientCfgEntry *
+ClientCfgDB::lookup(uint32_t ip) {
+
+ /* a cache to avoid constant search (usually its a range of IPs) */
+ if ( (m_cache_group) && (m_cache_group->contains(ip)) ) {
+ return m_cache_group;
+ }
+
+ /* clear the cache pointer */
+ m_cache_group = NULL;
+
+ std::map<uint32_t ,ClientCfgEntry>::iterator it;
+
+ /* upper bound fetchs the first greater element */
+ it = m_groups.upper_bound(ip);
+
+ /* if the first element in the map is bigger - its not in the map */
+ if (it == m_groups.begin()) {
+ return NULL;
+ }
+
+ /* go one back - we know it's not on begin so we have at least one back */
+ it--;
+
+ ClientCfgEntry &group = (*it).second;
+
+ /* because this is a non overlapping intervals
+ if IP exists it must be in this group
+ because if it exists in some other previous group
+ its end_range >= ip so start_range > ip
+ and so start_range is the upper_bound
+ */
+ if (group.contains(ip)) {
+ /* save as cache */
+ m_cache_group = &group;
+ return &group;
+ } else {
+ return NULL;
+ }
+
+}
+
+/**
+ * for convenience - search by IP as string
+ *
+ * @author imarom (28-Jun-16)
+ *
+ * @param ip
+ *
+ * @return ClientCfgEntry*
+ */
+ClientCfgEntry *
+ClientCfgDB::lookup(const std::string &ip) {
+ uint32_t addr = (uint32_t)inet_addr(ip.c_str());
+ addr = PKT_NTOHL(addr);
+
+ return lookup(addr);
+}
+
+
diff --git a/src/trex_client_config.h b/src/trex_client_config.h
new file mode 100644
index 00000000..a5bb83b3
--- /dev/null
+++ b/src/trex_client_config.h
@@ -0,0 +1,265 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2016 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#ifndef __TREX_CLIENT_CONFIG_H__
+#define __TREX_CLIENT_CONFIG_H__
+
+#include <stdint.h>
+#include <string>
+#include <map>
+
+class YAMLParserWrapper;
+
+
+/**
+ * client configuration per direction
+ *
+ * @author imarom (29-Jun-16)
+ */
+class ClientCfgDir {
+
+private:
+ enum {
+ HAS_SRC_MAC = 0x1,
+ HAS_DST_MAC = 0x2,
+ HAS_VLAN = 0x4,
+ };
+
+ uint8_t m_src_mac[6];
+ uint8_t m_dst_mac[6];
+ uint16_t m_vlan;
+ uint8_t m_bitfield;
+
+
+public:
+ ClientCfgDir() {
+ m_bitfield = 0;
+ }
+
+ bool has_src_mac_addr() const {
+ return (m_bitfield & HAS_SRC_MAC);
+ }
+
+ bool has_dst_mac_addr() const {
+ return (m_bitfield & HAS_DST_MAC);
+ }
+ bool has_vlan() const {
+ return (m_bitfield & HAS_VLAN);
+ }
+
+ void set_src_mac_addr(uint64_t mac_addr) {
+ for (int i = 0; i < 6; i++) {
+ m_src_mac[i] = ( mac_addr >> ((5 - i) * 8) ) & 0xFF;
+ }
+ m_bitfield |= HAS_SRC_MAC;
+ }
+
+ void set_dst_mac_addr(uint64_t mac_addr) {
+ for (int i = 0; i < 6; i++) {
+ m_dst_mac[i] = ( mac_addr >> ((5 - i) * 8) ) & 0xFF;
+ }
+ m_bitfield |= HAS_DST_MAC;
+ }
+
+ void set_vlan(uint16_t vlan_id) {
+ m_vlan = vlan_id;
+ m_bitfield |= HAS_VLAN;
+ }
+
+ /* updates a configuration with a group index member */
+
+ void update(uint32_t index) {
+ if (has_src_mac_addr()) {
+ mac_add(m_src_mac, index);
+ }
+
+ if (has_dst_mac_addr()) {
+ mac_add(m_dst_mac, index);
+ }
+ }
+
+ const uint8_t *get_src_mac_addr() const {
+ assert(has_src_mac_addr());
+ return m_src_mac;
+ }
+
+ const uint8_t *get_dst_mac_addr() const {
+ assert(has_dst_mac_addr());
+ return m_dst_mac;
+ }
+
+ uint16_t get_vlan() const {
+ assert(has_vlan());
+ return m_vlan;
+ }
+
+private:
+ /**
+ * transform MAC address to uint64_t
+ * performs add and return to MAC format
+ *
+ */
+ void mac_add(uint8_t *mac, uint32_t i) {
+ uint64_t tmp = 0;
+
+ for (int i = 0; i < 6; i++) {
+ tmp <<= 8;
+ tmp |= mac[i];
+ }
+
+ tmp += i;
+
+ for (int i = 0; i < 6; i++) {
+ mac[i] = ( tmp >> ((5 - i) * 8) ) & 0xFF;
+ }
+
+ }
+};
+
+/**
+ * single client config
+ *
+ */
+class ClientCfg {
+
+public:
+
+ void update(uint32_t index) {
+ m_initiator.update(index);
+ m_responder.update(index);
+ }
+
+ ClientCfgDir m_initiator;
+ ClientCfgDir m_responder;
+};
+
+/******************************** internal section ********************************/
+
+/**
+ * describes a single client config
+ * entry loaded from the config file
+ *
+ */
+class ClientCfgEntry {
+
+public:
+
+ ClientCfgEntry() {
+ reset();
+ }
+
+
+ void dump() const;
+
+ bool contains(uint32_t ip) const {
+ return ( (ip >= m_ip_start) && (ip <= m_ip_end) );
+ }
+
+ void reset() {
+ m_iterator = 0;
+ }
+
+
+ /**
+ * assings a client config from the group
+ * it will advance MAC addresses andf etc.
+ *
+ * @author imarom (27-Jun-16)
+ *
+ * @param info
+ */
+ void assign(ClientCfg &info) {
+ info = m_cfg;
+ info.update(m_iterator);
+
+ /* advance for the next assign */
+ m_iterator = (m_iterator + 1) % m_count;
+ }
+
+public:
+ uint32_t m_ip_start;
+ uint32_t m_ip_end;
+
+ ClientCfg m_cfg;
+
+ uint32_t m_count;
+
+private:
+ uint32_t m_iterator;
+};
+
+/**
+ * holds all the configured clients groups
+ *
+ */
+class ClientCfgDB {
+public:
+
+ ClientCfgDB() {
+ m_is_empty = true;
+ m_cache_group = NULL;
+ m_under_vlan = false;
+ }
+
+ /**
+ * if no config file was loaded
+ * this should return true
+ *
+ */
+ bool is_empty() {
+ return m_is_empty;
+ }
+
+ /**
+ * loads a YAML file
+ * configuration will be built
+ * according to the YAML config
+ *
+ */
+ void load_yaml_file(const std::string &filename);
+
+ /**
+ * lookup for a specific IP address for
+ * a group that contains this IP
+ *
+ */
+ ClientCfgEntry * lookup(uint32_t ip);
+ ClientCfgEntry * lookup(const std::string &ip);
+
+private:
+ void parse_single_group(YAMLParserWrapper &parser, const YAML::Node &node);
+ void parse_dir(YAMLParserWrapper &parser, const YAML::Node &node, ClientCfgDir &dir);
+
+ /**
+ * verify the YAML file loaded in valid
+ *
+ */
+ void verify(const YAMLParserWrapper &parser) const;
+
+ /* maps the IP start value to client groups */
+ std::map<uint32_t, ClientCfgEntry> m_groups;
+ bool m_under_vlan;
+
+ ClientCfgEntry *m_cache_group;
+ bool m_is_empty;
+};
+
+#endif /* __TREX_CLIENT_CONFIG_H__ */
+
diff --git a/src/trex_defs.h b/src/trex_defs.h
index 665c1edc..9abb38f5 100644
--- a/src/trex_defs.h
+++ b/src/trex_defs.h
@@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <set>
+#include <queue>
+#include <vector>
#ifndef __TREX_DEFS_H__
#define __TREX_DEFS_H__
@@ -33,8 +35,13 @@ limitations under the License.
#define UINT16_MAX 0xFFFF
#endif
+#ifndef UINT64_MAX
+ #define UINT64_MAX 0xFFFFFFFFFFFFFFFF
+#endif
typedef std::set<uint32_t> flow_stat_active_t;
typedef std::set<uint32_t>::iterator flow_stat_active_it_t;
+typedef std::vector<std::vector<uint8_t>> cpu_util_full_t;
+typedef std::vector<uint8_t> cpu_vct_t;
#endif
diff --git a/src/trex_watchdog.cpp b/src/trex_watchdog.cpp
index d099933b..88711b7a 100644
--- a/src/trex_watchdog.cpp
+++ b/src/trex_watchdog.cpp
@@ -92,7 +92,7 @@ std::string Backtrace(int skip = 1)
/* add the addr2line info */
std::stringstream addr2line;
- addr2line << "/usr/bin/addr2line -e " << get_exe_name() << " ";
+ addr2line << "/usr/bin/addr2line -s -e " << get_exe_name() << " ";
for (int i = skip; i < nFrames; i++) {
addr2line << callstack[i] << " ";
}
diff --git a/src/trex_watchdog.h b/src/trex_watchdog.h
index 1c948d56..af9a3993 100644
--- a/src/trex_watchdog.h
+++ b/src/trex_watchdog.h
@@ -117,15 +117,12 @@ private:
/* write fields are first */
volatile bool m_active;
volatile bool m_tickled;
- dsec_t m_ts;
-
int m_handle;
+ dsec_t m_ts;
double m_timeout_sec;
pthread_t m_tid;
std::string m_name;
- /* for for a full cacheline */
- uint8_t pad[15];
} __rte_cache_aligned;
@@ -203,6 +200,5 @@ private:
static bool g_signal_init;
};
-static_assert(sizeof(TrexMonitor) == RTE_CACHE_LINE_SIZE, "sizeof(TrexMonitor) != RTE_CACHE_LINE_SIZE" );
#endif /* __TREX_WATCHDOG_H__ */
diff --git a/src/tuple_gen.cpp b/src/tuple_gen.cpp
index d221a4d9..6861b73f 100755
--- a/src/tuple_gen.cpp
+++ b/src/tuple_gen.cpp
@@ -25,6 +25,7 @@ limitations under the License.
#include "tuple_gen.h"
#include <string.h>
#include "utl_yaml.h"
+#include "bp_sim.h"
void CServerPool::Create(IP_DIST_t dist_value,
uint32_t min_ip,
@@ -52,97 +53,117 @@ void CServerPool::Create(IP_DIST_t dist_value,
-void CClientPool::Create(IP_DIST_t dist_value,
- uint32_t min_ip,
- uint32_t max_ip,
- double l_flow,
- double t_cps,
- CFlowGenListMac* mac_info,
- bool has_mac_map,
- uint16_t tcp_aging,
- uint16_t udp_aging) {
- assert(max_ip>=min_ip);
+void CClientPool::Create(IP_DIST_t dist_value,
+ uint32_t min_ip,
+ uint32_t max_ip,
+ double l_flow,
+ double t_cps,
+ ClientCfgDB &client_info,
+ uint16_t tcp_aging,
+ uint16_t udp_aging) {
+
+ assert(max_ip >= min_ip);
+
set_dist(dist_value);
- uint32_t total_ip = max_ip - min_ip +1;
- uint32_t avail_ip = total_ip;
- if (has_mac_map && (mac_info!=NULL)) {
- for(int idx=0;idx<total_ip;idx++){
- mac_addr_align_t *mac_adr = NULL;
- mac_adr = mac_info->get_mac_addr_by_ip(min_ip+idx);
- if (mac_adr == NULL) {
- avail_ip--;
- }
- }
- }
- if (avail_ip!=0) {
- m_ip_info.resize(avail_ip);
+
+ uint32_t total_ip = max_ip - min_ip +1;
+ bool is_long_range = total_ip > (l_flow * t_cps / MAX_PORT);
+
+ m_ip_info.resize(total_ip);
+
+ /* if client info is empty - flat allocation o.w use configured clients */
+ if (client_info.is_empty()) {
+ allocate_simple_clients(min_ip, total_ip, is_long_range);
} else {
- printf("\n Error, invalid mac file is configured.\n");
- assert(0);
+ allocate_configured_clients(min_ip, total_ip, is_long_range, client_info);
}
- int skip_cnt=0;
- if (total_ip > ((l_flow*t_cps/MAX_PORT))) {
- if (has_mac_map) {
- skip_cnt=0;
- for(int idx=0;idx<total_ip;idx++){
- mac_addr_align_t *mac_adr = NULL;
- mac_adr = mac_info->get_mac_addr_by_ip( min_ip+idx);
- if (mac_adr != NULL) {
- m_ip_info[idx-skip_cnt] = new CClientInfoL(has_mac_map);
- m_ip_info[idx-skip_cnt]->set_ip(min_ip+idx);
- m_ip_info[idx-skip_cnt]->set_mac(mac_adr);
- } else {
- skip_cnt++;
- }
- }
+ m_tcp_aging = tcp_aging;
+ m_udp_aging = udp_aging;
+
+ CreateBase();
+}
+
+/**
+ * simple allocation of a client - no configuration was provided
+ *
+ * @author imarom (27-Jun-16)
+ *
+ * @param ip
+ * @param index
+ * @param is_long_range
+ */
+void CClientPool::allocate_simple_clients(uint32_t min_ip,
+ uint32_t total_ip,
+ bool is_long_range) {
+
+ /* simple creation of clients - no extended info */
+ for (uint32_t i = 0; i < total_ip; i++) {
+ uint32_t ip = min_ip + i;
+ if (is_long_range) {
+ m_ip_info[i] = new CSimpleClientInfo<CIpInfoL>(ip);
} else {
- for(int idx=0;idx<total_ip;idx++){
- m_ip_info[idx] = new CClientInfoL(has_mac_map);
- m_ip_info[idx]->set_ip(min_ip+idx);
- }
- }
- } else {
- if (has_mac_map) {
- skip_cnt=0;
- for(int idx=0;idx<total_ip;idx++){
- mac_addr_align_t *mac_adr = NULL;
- mac_adr = mac_info->get_mac_addr_by_ip(min_ip+idx);
- if (mac_adr != NULL) {
- m_ip_info[idx-skip_cnt] = new CClientInfo(has_mac_map);
- m_ip_info[idx-skip_cnt]->set_ip(min_ip+idx);
- m_ip_info[idx-skip_cnt]->set_mac(mac_adr);
- } else {
- skip_cnt++;
- }
- }
+ m_ip_info[i] = new CSimpleClientInfo<CIpInfo>(ip);
+ }
+ }
+
+}
+
+/**
+ * simple allocation of a client - no configuration was provided
+ *
+ * @author imarom (27-Jun-16)
+ *
+ * @param ip
+ * @param index
+ * @param is_long_range
+ */
+void CClientPool::allocate_configured_clients(uint32_t min_ip,
+ uint32_t total_ip,
+ bool is_long_range,
+ ClientCfgDB &client_info) {
+
+ for (uint32_t i = 0; i < total_ip; i++) {
+ uint32_t ip = min_ip + i;
+
+ /* lookup for the right group of clients */
+ ClientCfgEntry *group = client_info.lookup(ip);
+ if (!group) {
+ std::stringstream ss;
+ ss << "client configuration error: could not map IP '" << ip_to_str(ip) << "' to a group\n";
+ throw std::runtime_error(ss.str());
+ }
+
+ ClientCfg info;
+ group->assign(info);
+
+ if (is_long_range) {
+ m_ip_info[i] = new CConfiguredClientInfo<CIpInfoL>(ip, info);
} else {
- for(int idx=0;idx<total_ip;idx++){
- m_ip_info[idx] = new CClientInfo(has_mac_map);
- m_ip_info[idx]->set_ip(min_ip+idx);
- }
- }
-
+ m_ip_info[i] = new CConfiguredClientInfo<CIpInfo>(ip, info);
+ }
}
- m_tcp_aging = tcp_aging;
- m_udp_aging = udp_aging;
- CreateBase();
}
-bool CTupleGeneratorSmart::add_client_pool(IP_DIST_t client_dist,
- uint32_t min_client,
- uint32_t max_client,
- double l_flow,
- double t_cps,
- CFlowGenListMac* mac_info,
- uint16_t tcp_aging,
- uint16_t udp_aging){
+bool CTupleGeneratorSmart::add_client_pool(IP_DIST_t client_dist,
+ uint32_t min_client,
+ uint32_t max_client,
+ double l_flow,
+ double t_cps,
+ ClientCfgDB &client_info,
+ uint16_t tcp_aging,
+ uint16_t udp_aging) {
assert(max_client>=min_client);
CClientPool* pool = new CClientPool();
- pool->Create(client_dist, min_client, max_client,
- l_flow, t_cps, mac_info, m_has_mac_mapping,
- tcp_aging, udp_aging);
+ pool->Create(client_dist,
+ min_client,
+ max_client,
+ l_flow,
+ t_cps,
+ client_info,
+ tcp_aging,
+ udp_aging);
m_client_pool.push_back(pool);
return(true);
@@ -170,19 +191,17 @@ bool CTupleGeneratorSmart::add_server_pool(IP_DIST_t server_dist,
bool CTupleGeneratorSmart::Create(uint32_t _id,
- uint32_t thread_id,
- bool has_mac)
+ uint32_t thread_id)
+
{
m_thread_id = thread_id;
m_id = _id;
m_was_init=true;
- m_has_mac_mapping = has_mac;
return(true);
}
void CTupleGeneratorSmart::Delete(){
m_was_init=false;
- m_has_mac_mapping = false;
for (int idx=0;idx<m_client_pool.size();idx++) {
m_client_pool[idx]->Delete();
diff --git a/src/tuple_gen.h b/src/tuple_gen.h
index b2f6e34a..2491f489 100755
--- a/src/tuple_gen.h
+++ b/src/tuple_gen.h
@@ -37,15 +37,17 @@ limitations under the License.
#include "common/c_common.h"
#include <bitset>
#include <yaml-cpp/yaml.h>
-#include <mac_mapping.h>
+#include "trex_client_config.h"
#include <random>
class CTupleBase {
public:
+
CTupleBase() {
- m_client_mac.inused = UNUSED;
+ m_client_cfg = NULL;
}
+
uint32_t getClient() {
return m_client_ip;
}
@@ -83,22 +85,20 @@ public:
void setClientPort(uint16_t port) {
m_client_port = port;
}
- mac_addr_align_t* getClientMac() {
- return &m_client_mac;
+ void setClientCfg(ClientCfg *cfg) {
+ m_client_cfg = cfg;
}
- void setClientMac(mac_addr_align_t* mac_info) {
- if (mac_info != NULL) {
- memcpy(&m_client_mac, mac_info, sizeof(mac_addr_align_t));
- m_client_mac.inused = INUSED;
- } else {
- m_client_mac.inused = UNUSED;
- }
+ ClientCfg *getClientCfg() {
+ return m_client_cfg;
}
- void setClientTuple(uint32_t ip,mac_addr_align_t*mac,uint16_t port) {
+
+
+ void setClientTuple(uint32_t ip, ClientCfg *cfg, uint16_t port) {
setClient(ip);
- setClientMac(mac);
setClientPort(port);
+ setClientCfg(cfg);
}
+
void setClientAll2(uint32_t id, uint32_t ip,uint16_t port) {
setClientId(id);
setClient(ip);
@@ -121,9 +121,12 @@ public:
private:
uint32_t m_client_ip;
uint32_t m_client_idx;
+
uint32_t m_server_ip;
uint32_t m_server_idx;
- mac_addr_align_t m_client_mac;
+
+ ClientCfg *m_client_cfg;
+
uint16_t m_client_port;
uint16_t m_server_port;
};
@@ -171,8 +174,6 @@ typedef enum {
class CIpInfoBase {
public:
- virtual mac_addr_align_t* get_mac() { return NULL;}
- virtual void set_mac(mac_addr_align_t*){;}
virtual uint16_t get_new_free_port() = 0;
virtual void return_port(uint16_t a) = 0;
virtual void generate_tuple(CTupleBase & tuple) = 0;
@@ -303,76 +304,54 @@ class CIpInfo : public CIpInfoBase {
}
};
-class CClientInfo : public CIpInfo {
+
+/**
+ * a flat client info (no configuration)
+ *
+ * using template to avoid duplicating the code for CIpInfo and
+ * CIpInfoL
+ *
+ * @author imarom (27-Jun-16)
+ */
+template <typename T>
+class CSimpleClientInfo : public T {
+
public:
- CClientInfo (bool has_mac) {
- if (has_mac==true) {
- m_mac = new mac_addr_align_t();
- } else {
- m_mac = NULL;
- }
- }
- CClientInfo () {
- m_mac = NULL;
- }
+ CSimpleClientInfo(uint32_t ip) {
+ T::set_ip(ip);
+ }
- mac_addr_align_t* get_mac() {
- return m_mac;
- }
- void set_mac(mac_addr_align_t *mac) {
- memcpy(m_mac, mac, sizeof(mac_addr_align_t));
- }
- ~CClientInfo() {
- if (m_mac!=NULL){
- delete m_mac;
- m_mac=NULL;
- }
- }
-
- void generate_tuple(CTupleBase & tuple) {
- tuple.setClientTuple(m_ip, m_mac,
- get_new_free_port());
+ void generate_tuple(CTupleBase &tuple) {
+ tuple.setClientTuple(T::m_ip,
+ NULL,
+ T::get_new_free_port());
}
-private:
- mac_addr_align_t *m_mac;
};
-class CClientInfoL : public CIpInfoL {
-public:
- CClientInfoL (bool has_mac) {
- if (has_mac==true) {
- m_mac = new mac_addr_align_t();
- } else {
- m_mac = NULL;
- }
- }
- CClientInfoL () {
- m_mac = NULL;
- }
+/**
+ * a configured client object
+ *
+ * @author imarom (26-Jun-16)
+ */
+template <typename T>
+class CConfiguredClientInfo : public T {
- mac_addr_align_t* get_mac() {
- return m_mac;
+public:
+ CConfiguredClientInfo(uint32_t ip, const ClientCfg &cfg) : m_cfg(cfg) {
+ T::set_ip(ip);
}
- void set_mac(mac_addr_align_t *mac) {
- memcpy(m_mac, mac, sizeof(mac_addr_align_t));
+ void generate_tuple(CTupleBase &tuple) {
+ tuple.setClientTuple(T::m_ip,
+ &m_cfg,
+ T::get_new_free_port());
}
- ~CClientInfoL() {
- if (m_mac!=NULL){
- delete m_mac;
- m_mac=NULL;
- }
- }
-
- void generate_tuple(CTupleBase & tuple) {
- tuple.setClientTuple(m_ip, m_mac,
- get_new_free_port());
- }
private:
- mac_addr_align_t *m_mac;
+ ClientCfg m_cfg;
};
+
class CServerInfo : public CIpInfo {
void generate_tuple(CTupleBase & tuple) {
tuple.setServer(m_ip);
@@ -475,12 +454,6 @@ class CIpPool {
client->return_port(port);
}
- mac_addr_align_t * get_curr_mac() {
- return m_ip_info[m_cur_idx]->get_mac();
- }
- mac_addr_align_t *get_mac(uint32_t idx) {
- return m_ip_info[idx]->get_mac();
- }
public:
std::vector<CIpInfoBase*> m_ip_info;
@@ -536,19 +509,30 @@ public:
uint16_t get_udp_aging() {
return m_udp_aging;
}
- void Create(IP_DIST_t dist_value,
- uint32_t min_ip,
- uint32_t max_ip,
- double l_flow,
- double t_cps,
- CFlowGenListMac* mac_info,
- bool has_mac_map,
- uint16_t tcp_aging,
- uint16_t udp_aging);
+
+ void Create(IP_DIST_t dist_value,
+ uint32_t min_ip,
+ uint32_t max_ip,
+ double l_flow,
+ double t_cps,
+ ClientCfgDB &client_info,
+ uint16_t tcp_aging,
+ uint16_t udp_aging);
public:
uint16_t m_tcp_aging;
uint16_t m_udp_aging;
+
+private:
+ void allocate_simple_clients(uint32_t min_ip,
+ uint32_t total_ip,
+ bool is_long_range);
+
+ void allocate_configured_clients(uint32_t min_ip,
+ uint32_t total_ip,
+ bool is_long_range,
+ ClientCfgDB &client_info);
+
};
class CServerPoolBase {
@@ -685,10 +669,9 @@ public:
public:
CTupleGeneratorSmart(){
m_was_init=false;
- m_has_mac_mapping = false;
}
- bool Create(uint32_t _id,
- uint32_t thread_id, bool has_mac=false);
+
+ bool Create(uint32_t _id, uint32_t thread_id);
void Delete();
@@ -704,20 +687,22 @@ public:
return (total_alloc_error);
}
- bool add_client_pool(IP_DIST_t client_dist,
- uint32_t min_client,
- uint32_t max_client,
- double l_flow,
- double t_cps,
- CFlowGenListMac* mac_info,
- uint16_t tcp_aging,
- uint16_t udp_aging);
+ bool add_client_pool(IP_DIST_t client_dist,
+ uint32_t min_client,
+ uint32_t max_client,
+ double l_flow,
+ double t_cps,
+ ClientCfgDB &client_info,
+ uint16_t tcp_aging,
+ uint16_t udp_aging);
+
bool add_server_pool(IP_DIST_t server_dist,
- uint32_t min_server,
- uint32_t max_server,
- double l_flow,
- double t_cps,
- bool is_bundling);
+ uint32_t min_server,
+ uint32_t max_server,
+ double l_flow,
+ double t_cps,
+ bool is_bundling);
+
CClientPool* get_client_pool(uint8_t idx) {
return m_client_pool[idx];
}
@@ -736,7 +721,6 @@ private:
std::vector<CClientPool*> m_client_pool;
std::vector<CServerPoolBase*> m_server_pool;
bool m_was_init;
- bool m_has_mac_mapping;
};
class CTupleTemplateGeneratorSmart {
diff --git a/src/utl_cpuu.cpp b/src/utl_cpuu.cpp
index 4d75cf6f..7786356e 100755
--- a/src/utl_cpuu.cpp
+++ b/src/utl_cpuu.cpp
@@ -25,7 +25,9 @@ limitations under the License.
void CCpuUtlCp::Create(CCpuUtlDp * cdp){
m_dpcpu=cdp;
- m_cpu_util=0.0;
+ memset(m_cpu_util, 0, sizeof(m_cpu_util));
+ m_history_latest_index = 0;
+ m_cpu_util_lpf=0.0;
m_ticks=0;
m_work=0;
}
@@ -41,17 +43,34 @@ void CCpuUtlCp::Update(){
m_work++;
}
if (m_ticks==100) {
- double window_cpu_u = ((double)m_work/(double)m_ticks);
/* LPF*/
- m_cpu_util = (m_cpu_util*0.75)+(window_cpu_u*0.25);
+ m_cpu_util_lpf = (m_cpu_util_lpf*0.75)+((double)m_work*0.25);
+ AppendHistory(m_work);
m_ticks=0;
m_work=0;
-
}
}
-/* return cpu % */
+/* return cpu % Smoothed */
double CCpuUtlCp::GetVal(){
- return (m_cpu_util*100);
+ return (m_cpu_util_lpf);
+}
+
+/* return cpu % Raw */
+uint8_t CCpuUtlCp::GetValRaw(){
+ return (m_cpu_util[m_history_latest_index]);
}
+/* get cpu % utilization history */
+void CCpuUtlCp::GetHistory(cpu_vct_t &cpu_vct){
+ cpu_vct.clear();
+ for (int i = m_history_latest_index + m_history_size; i > m_history_latest_index; i--) {
+ cpu_vct.push_back(m_cpu_util[i % m_history_size]);
+ }
+}
+
+/* save last CPU % util in history */
+void CCpuUtlCp::AppendHistory(uint8_t val){
+ m_history_latest_index = (m_history_latest_index + 1) % m_history_size;
+ m_cpu_util[m_history_latest_index] = val;
+}
diff --git a/src/utl_cpuu.h b/src/utl_cpuu.h
index e5305783..109fff4f 100755
--- a/src/utl_cpuu.h
+++ b/src/utl_cpuu.h
@@ -22,6 +22,8 @@ limitations under the License.
*/
#include <stdint.h>
+#include <cstring>
+#include "trex_defs.h"
#include "os_time.h"
#include "mbuf.h"
@@ -56,13 +58,18 @@ public:
void Update();
/* return cpu % */
double GetVal();
-
+ uint8_t GetValRaw();
+ void GetHistory(cpu_vct_t &cpu_vct);
private:
- CCpuUtlDp * m_dpcpu;
- uint16_t m_ticks;
- uint16_t m_work;
+ void AppendHistory(uint8_t);
+ CCpuUtlDp * m_dpcpu;
+ uint8_t m_ticks;
+ uint8_t m_work;
- double m_cpu_util;
+ static const int m_history_size=20;
+ uint8_t m_cpu_util[m_history_size]; // history as cyclic array
+ uint8_t m_history_latest_index;
+ double m_cpu_util_lpf;
};
#endif
diff --git a/src/utl_yaml.cpp b/src/utl_yaml.cpp
index 828817e4..8352e887 100755
--- a/src/utl_yaml.cpp
+++ b/src/utl_yaml.cpp
@@ -21,7 +21,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-
+#include <istream>
+#include <fstream>
+#include "common/basic_utils.h"
#define INADDRSZ 4
@@ -65,8 +67,8 @@ static int my_inet_pton4(const char *src, unsigned char *dst)
bool utl_yaml_read_ip_addr(const YAML::Node& node,
- std::string name,
- uint32_t & val){
+ const std::string &name,
+ uint32_t & val){
std::string tmp;
uint32_t ip;
bool res=false;
@@ -83,8 +85,10 @@ bool utl_yaml_read_ip_addr(const YAML::Node& node,
return (res);
}
+
+
bool utl_yaml_read_uint32(const YAML::Node& node,
- std::string name,
+ const std::string &name,
uint32_t & val){
bool res=false;
if ( node.FindValue(name) ) {
@@ -95,8 +99,8 @@ bool utl_yaml_read_uint32(const YAML::Node& node,
}
bool utl_yaml_read_uint16(const YAML::Node& node,
- std::string name,
- uint16_t & val){
+ const std::string &name,
+ uint16_t & val){
uint32_t val_tmp;
bool res=false;
if ( node.FindValue(name) ) {
@@ -108,15 +112,250 @@ bool utl_yaml_read_uint16(const YAML::Node& node,
return (res);
}
-bool utl_yaml_read_bool(const YAML::Node& node,
- std::string name,
- bool & val){
- bool res=false;
- if ( node.FindValue(name) ) {
- node[name] >> val ;
- res=true;
+static void
+split_str_by_delimiter(std::string str, char delim, std::vector<std::string> &tokens) {
+ size_t pos = 0;
+ std::string token;
+
+ while ((pos = str.find(delim)) != std::string::npos) {
+ token = str.substr(0, pos);
+ tokens.push_back(token);
+ str.erase(0, pos + 1);
+ }
+
+ if (str.size() > 0) {
+ tokens.push_back(str);
+ }
+}
+
+static bool mac2uint64(const std::string &mac_str, uint64_t &mac_num) {
+ std::vector<std::string> tokens;
+ uint64_t val;
+
+ split_str_by_delimiter(mac_str, ':', tokens);
+ if (tokens.size() != 6) {
+ return false;
+ }
+
+ val = 0;
+
+ for (int i = 0; i < 6 ; i++) {
+ char *endptr = NULL;
+ unsigned long octet = strtoul(tokens[i].c_str(), &endptr, 16);
+
+ if ( (*endptr != 0) || (octet > 0xff) ) {
+ return false;
+ }
+
+ val = (val << 8) + octet;
}
- return( res);
+
+ mac_num = val;
+
+ return true;
}
+/************************
+ * YAML Parser Wrapper
+ *
+ ***********************/
+void
+YAMLParserWrapper::load(YAML::Node &root) {
+ std::stringstream ss;
+
+ /* first check file exists */
+ if (!utl_is_file_exists(m_filename)){
+ ss << "file '" << m_filename << "' does not exists";
+ throw std::runtime_error(ss.str());
+ }
+
+ std::ifstream fin(m_filename);
+
+ try {
+ YAML::Parser base_parser(fin);
+ base_parser.GetNextDocument(root);
+
+ } catch (const YAML::Exception &e) {
+ parse_err(e.what());
+ }
+}
+
+bool
+YAMLParserWrapper::parse_bool(const YAML::Node &node, const std::string &name, bool def) {
+ if (!node.FindValue(name)) {
+ return def;
+ }
+
+ return parse_bool(node, name);
+}
+
+bool
+YAMLParserWrapper::parse_bool(const YAML::Node &node, const std::string &name) {
+ try {
+ bool val;
+ node[name] >> val;
+ return (val);
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting true/false for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
+}
+
+const YAML::Node &
+YAMLParserWrapper::parse_list(const YAML::Node &node, const std::string &name) {
+
+ try {
+ const YAML::Node &val = node[name];
+ if (val.Type() != YAML::NodeType::Sequence) {
+ throw YAML::InvalidScalar(node[name].GetMark());
+ }
+ return val;
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting sequence/list for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
+}
+
+const YAML::Node &
+YAMLParserWrapper::parse_map(const YAML::Node &node, const std::string &name) {
+
+ try {
+ const YAML::Node &val = node[name];
+ if (val.Type() != YAML::NodeType::Map) {
+ throw YAML::InvalidScalar(node[name].GetMark());
+ }
+ return val;
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting map for field '" + name + "'", node[name]);
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
+}
+
+uint32_t
+YAMLParserWrapper::parse_ip(const YAML::Node &node, const std::string &name) {
+
+
+ try {
+ std::string ip_str;
+ uint32_t ip_num;
+
+ node[name] >> ip_str;
+ int rc = my_inet_pton4((char *)ip_str.c_str(), (unsigned char *)&ip_num);
+ if (!rc) {
+ parse_err("invalid IP address: " + ip_str, node[name]);
+ }
+
+ return PKT_NTOHL(ip_num);
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting valid IP address for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
+}
+
+uint64_t
+YAMLParserWrapper::parse_mac_addr(const YAML::Node &node, const std::string &name, uint64_t def) {
+ if (!node.FindValue(name)) {
+ return def;
+ }
+
+ return parse_mac_addr(node, name);
+}
+
+uint64_t
+YAMLParserWrapper::parse_mac_addr(const YAML::Node &node, const std::string &name) {
+
+ std::string mac_str;
+ uint64_t mac_num;
+
+ try {
+
+ node[name] >> mac_str;
+ bool rc = mac2uint64(mac_str, mac_num);
+ if (!rc) {
+ parse_err("invalid MAC address: " + mac_str, node[name]);
+ }
+ return mac_num;
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting true/false for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
+}
+
+uint64_t
+YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, uint64_t low, uint64_t high, uint64_t def) {
+ if (!node.FindValue(name)) {
+ return def;
+ }
+
+ return parse_uint(node, name, low, high);
+}
+
+uint64_t
+YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, uint64_t low, uint64_t high) {
+
+ try {
+
+ uint64_t val;
+ node[name] >> val;
+
+ if ( (val < low) || (val > high) ) {
+ std::stringstream ss;
+ ss << "valid range for field '" << name << "' is: [" << low << " - " << high << "]";
+ parse_err(ss.str(), node[name]);
+ }
+
+ return (val);
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting true/false for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
+}
+
+void
+YAMLParserWrapper::parse_err(const std::string &err, const YAML::Node &node) const {
+ std::stringstream ss;
+
+ ss << "'" << m_filename << "' - YAML parsing error at line " << node.GetMark().line << ": ";
+ ss << err;
+
+ throw std::runtime_error(ss.str());
+}
+
+void
+YAMLParserWrapper::parse_err(const std::string &err) const {
+ std::stringstream ss;
+
+ ss << "'" << m_filename << "' - YAML parsing error: " << err;
+
+ throw std::runtime_error(ss.str());
+}
diff --git a/src/utl_yaml.h b/src/utl_yaml.h
index 71655488..59104b21 100755
--- a/src/utl_yaml.h
+++ b/src/utl_yaml.h
@@ -24,23 +24,56 @@ limitations under the License.
#include <stdint.h>
#include <yaml-cpp/yaml.h>
-
+
+/* static methods - please prefer the wrapper over those */
bool utl_yaml_read_ip_addr(const YAML::Node& node,
- std::string name,
- uint32_t & val
- );
+ const std::string &name,
+ uint32_t & val);
bool utl_yaml_read_uint32(const YAML::Node& node,
- std::string name,
- uint32_t & val);
+ const std::string &name,
+ uint32_t & val);
+
bool utl_yaml_read_uint16(const YAML::Node& node,
- std::string name,
- uint16_t & val);
+ const std::string &name,
+ uint16_t & val);
+
+/* a thin wrapper to customize errors */
+class YAMLParserWrapper {
+public:
+ /* a header that will start every error message */
+ YAMLParserWrapper(const std::string &filename) : m_filename(filename) {
+ }
+
+ /**
+ * loads the file (while parsing it)
+ *
+ */
+ void load(YAML::Node &root);
+
+ /* bool */
+ bool parse_bool(const YAML::Node &node, const std::string &name);
+ bool parse_bool(const YAML::Node &node, const std::string &name, bool def);
-bool utl_yaml_read_bool(const YAML::Node& node,
- std::string name,
- bool & val);
+ const YAML::Node & parse_list(const YAML::Node &node, const std::string &name);
+ const YAML::Node & parse_map(const YAML::Node &node, const std::string &name);
+ uint32_t parse_ip(const YAML::Node &node, const std::string &name);
+ uint64_t parse_mac_addr(const YAML::Node &node, const std::string &name);
+ uint64_t parse_mac_addr(const YAML::Node &node, const std::string &name, uint64_t def);
+
+ uint64_t parse_uint(const YAML::Node &node, const std::string &name, uint64_t low = 0, uint64_t high = UINT64_MAX);
+ uint64_t parse_uint(const YAML::Node &node, const std::string &name, uint64_t low, uint64_t high, uint64_t def);
+
+
+public:
+ void parse_err(const std::string &err, const YAML::Node &node) const;
+ void parse_err(const std::string &err) const;
+
+
+private:
+ std::string m_filename;
+};
#endif