summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorIdo Barnea <ibarnea@cisco.com>2016-07-11 16:58:21 +0300
committerIdo Barnea <ibarnea@cisco.com>2016-07-12 16:06:29 +0300
commit7b9d10888594ca9fe1114309e53c0dea9089085b (patch)
tree564133e0a95a22c07be11540540cd627089cbea5 /src
parentcc5cc5631e9df4ef0eee9c26705208dfcf035e8c (diff)
NAT seq num randomization fully working
Diffstat (limited to 'src')
-rwxr-xr-xsrc/bp_gtest.cpp14
-rwxr-xr-xsrc/bp_sim.cpp21
-rwxr-xr-xsrc/bp_sim.h2
-rwxr-xr-xsrc/global_io_mode.cpp31
-rwxr-xr-xsrc/global_io_mode.h16
-rw-r--r--src/latency.cpp10
-rw-r--r--src/latency.h1
-rw-r--r--src/main_dpdk.cpp42
-rwxr-xr-xsrc/nat_check.cpp37
-rwxr-xr-xsrc/nat_check.h19
-rw-r--r--src/nat_check_flow_table.cpp314
-rw-r--r--src/nat_check_flow_table.h111
-rw-r--r--src/trex_defs.h3
13 files changed, 541 insertions, 80 deletions
diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp
index 3c6b2e40..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();
+};
//////////////////////////////////////////////////////////////
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index f46f2824..b229d9bf 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -761,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;
}
@@ -791,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);
}
@@ -2031,7 +2036,8 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::is_valid_template_loa
, " Please give different CAP file, or try different --learn-mode\n");
return kTCPLearnModeBadFlow;
}
- if ((pkt_0_indication.m_cap_ipg < LEARN_MODE_MIN_IPG / 1000) || (pkt_1_indication.m_cap_ipg < LEARN_MODE_MIN_IPG / 1000)) {
+ 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);
@@ -2300,10 +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;
-
-
-
- printf("%d: IPG:%f", i, lp_prev->m_pkt_indication.m_cap_ipg); //??? remove
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);
@@ -4177,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);
}
@@ -4228,6 +4235,7 @@ void CFlowGenListPerThread::handle_nat_msg(CGenNodeNatInfo * msg){
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();
@@ -4256,7 +4264,8 @@ void CFlowGenListPerThread::handle_nat_msg(CGenNodeNatInfo * msg){
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() ){
+ if (!node->is_external_is_eq_to_internal_ip() ||
+ node->get_nat_tcp_seq_diff_client() != 0) {
m_stats.m_nat_flow_learn_error++;
}
}
diff --git a/src/bp_sim.h b/src/bp_sim.h
index 49e0e8dc..13934d74 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -1871,8 +1871,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:
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/latency.cpp b/src/latency.cpp
index b9ce2177..768e161b 100644
--- a/src/latency.cpp
+++ b/src/latency.cpp
@@ -387,12 +387,6 @@ bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) {
if ( ! is_lateancy_pkt) {
-#if 0
- TCPHeader *tcp = (TCPHeader *)parser.m_l4; //????? remove
- if (parser.m_ipv4->getProtocol() == 0x6 && tcp->getSynFlag()) {
- tcp->dump(stdout); //???? remove
- }
-#endif
#ifdef NAT_TRACE_
printf(" %.3f RX : got packet !!! \n",now_sec() );
#endif
@@ -917,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 552b3999..63e50337 100644
--- a/src/latency.h
+++ b/src/latency.h
@@ -362,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/main_dpdk.cpp b/src/main_dpdk.cpp
index d5e7c9b5..099ebb3b 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -2439,8 +2439,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 ;
@@ -2559,8 +2561,10 @@ void CGlobalStats::dump_json(std::string & json, bool baseline){
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);
@@ -2596,7 +2600,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");
}
@@ -2604,28 +2613,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");
}
@@ -3647,8 +3661,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;
@@ -3677,8 +3693,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;
@@ -3700,8 +3718,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;
@@ -3959,9 +3979,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);
+ }
}
}
diff --git a/src/nat_check.cpp b/src/nat_check.cpp
index c7262e50..f3dd93d1 100755
--- a/src/nat_check.cpp
+++ b/src/nat_check.cpp
@@ -52,29 +52,6 @@ void CGenNodeNatInfo::init(){
m_cnt=0;
}
-bool CNatCheckFlowTableMap::find(uint64_t key, uint32 &val) {
- nat_check_flow_map_t::iterator iter;
- iter = m_map.find(key);
- if (iter != m_map.end() ) {
- val = (*iter).second;
- return true;
- }else{
- return false;
- }
-}
-
-void CNatCheckFlowTableMap::dump(FILE *fd) {
- nat_check_flow_map_iter_t it;
- uint32_t val;
- uint64_t key;
-
- for (it = m_map.begin(); it != m_map.end(); it++) {
- val = it->second;
- key = it->first;
- fprintf(fd, "%lx->%x\n", key, val);
- }
-}
-
void CNatStats::reset(){
m_total_rx=0;
m_total_msg=0;
@@ -207,21 +184,20 @@ void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4, bool
uint32_t dst_ip = ipv4->getDestIp();
uint16_t dst_port = tcp->getDestPort();
uint64_t map_key = (dst_ip << 16) + dst_port;
- m_fm.insert(map_key, tcp_ack);
+ 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_fm.find(map_key, val)) {
+ if (m_ft.erase(map_key, val)) {
get_info_from_tcp_ack(val, fid, thread_id);
thread_info = get_thread_info(thread_id);
- m_fm.erase(map_key);
} else {
+ // flow was not found in the table
thread_info = 0;
- // ??? Handle error
- // ??? handle aging of flow info
}
}
}
@@ -279,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 3b526c0b..18add5e0 100755
--- a/src/nat_check.h
+++ b/src/nat_check.h
@@ -29,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 )
@@ -211,22 +212,6 @@ public:
void Dump(FILE *fd);
};
-typedef std::map<uint64_t, uint32_t, std::less<uint64_t> > nat_check_flow_map_t;
-typedef nat_check_flow_map_t::iterator nat_check_flow_map_iter_t;
-
-class CNatCheckFlowTableMap {
-public:
- void erase(uint64_t key) {m_map.erase(key);}
- bool find(uint64_t fid, uint32_t &val);
- void insert(uint64_t key, uint32_t val) {m_map.insert(std::pair<uint64_t, uint32_t>(key, val));}
- void clear(void) {m_map.clear();}
- void dump(FILE *fd);
- uint64_t size(void) {return m_map.size();}
-
-public:
- nat_check_flow_map_t m_map;
-};
-
class CNatRxManager {
public:
@@ -248,7 +233,7 @@ private:
uint8_t m_max_threads;
CNatPerThreadInfo * m_per_thread;
CNatStats m_stats;
- CNatCheckFlowTableMap m_fm;
+ 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/trex_defs.h b/src/trex_defs.h
index bbf3f3ba..9abb38f5 100644
--- a/src/trex_defs.h
+++ b/src/trex_defs.h
@@ -35,6 +35,9 @@ 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;