summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Barnea <ibarnea@cisco.com>2016-01-14 04:42:05 +0200
committerIdo Barnea <ibarnea@cisco.com>2016-01-19 04:13:53 +0200
commit62623efc5b700d58335fa994d2e2725863527575 (patch)
treef3140936cd979c7d609bbe91c539f681ddd8e552
parenteee866f42bd0fc8472e6295b4f26bd0697e59f1f (diff)
Adding option to pass NAT info in TCP ACK of first SYN
-rwxr-xr-xscripts/automation/regression/unit_tests/trex_nat_test.py22
-rw-r--r--scripts/exp/bad_not_ip.pcapbin0 -> 226 bytes
-rwxr-xr-xscripts/exp/http1_with_option-ex.pcapbin35049 -> 35049 bytes
-rw-r--r--scripts/exp/http1_with_option.pcapbin35049 -> 0 bytes
-rwxr-xr-xscripts/exp/http1_with_option_ipv6-ex.pcapbin35713 -> 35713 bytes
-rw-r--r--scripts/exp/http1_with_option_ipv6.pcapbin35713 -> 0 bytes
-rw-r--r--scripts/exp/many_ip_options.pcapbin0 -> 204 bytes
-rw-r--r--scripts/exp/tcp_no_syn.pcapbin0 -> 184 bytes
-rwxr-xr-xsrc/bp_gtest.cpp34
-rwxr-xr-xsrc/bp_sim.cpp191
-rwxr-xr-xsrc/bp_sim.h134
-rwxr-xr-xsrc/common/Network/Packet/TcpHeader.h2
-rw-r--r--src/debug.cpp11
-rw-r--r--src/latency.cpp7
-rw-r--r--src/latency.h21
-rwxr-xr-xsrc/main_dpdk.cpp33
-rwxr-xr-xsrc/nat_check.cpp77
-rwxr-xr-xsrc/nat_check.h122
-rwxr-xr-xsrc/rx_check.cpp7
-rwxr-xr-xsrc/rx_check_header.cpp21
-rwxr-xr-xsrc/rx_check_header.h116
21 files changed, 465 insertions, 333 deletions
diff --git a/scripts/automation/regression/unit_tests/trex_nat_test.py b/scripts/automation/regression/unit_tests/trex_nat_test.py
index 9fe12507..c70c03a1 100755
--- a/scripts/automation/regression/unit_tests/trex_nat_test.py
+++ b/scripts/automation/regression/unit_tests/trex_nat_test.py
@@ -90,29 +90,35 @@ class CTRexNat_Test(CTRexGeneral_Test):#(unittest.TestCase):
pass
- def test_nat_simple(self):
+ def test_nat_simple_mode1(self):
+ self.nat_simple_helper(learn_mode=1)
+
+ def test_nat_simple_mode2(self):
+ self.nat_simple_helper(learn_mode=2)
+
+ def nat_simple_helper(self, learn_mode=1):
# test initializtion
self.router.configure_basic_interfaces()
- stat_route_dict = self.get_benchmark_param('stat_route_dict')
+ stat_route_dict = self.get_benchmark_param('stat_route_dict', test_name="test_nat_simple")
stat_route_obj = CStaticRouteConfig(stat_route_dict)
self.router.config_static_routing(stat_route_obj, mode = "config")
- nat_dict = self.get_benchmark_param('nat_dict')
+ nat_dict = self.get_benchmark_param('nat_dict', test_name="test_nat_simple")
nat_obj = CNatConfig(nat_dict)
self.router.config_nat(nat_obj)
# self.trex.set_yaml_file('cap2/http_simple.yaml')
- mult = self.get_benchmark_param('multiplier')
- core = self.get_benchmark_param('cores')
+ mult = self.get_benchmark_param('multiplier', test_name="test_nat_simple")
+ core = self.get_benchmark_param('cores', test_name="test_nat_simple")
# trex_res = self.trex.run(nc=False,multiplier = mult, cores = core, duration = 100, l = 1000, learn = True)
ret = self.trex.start_trex(
c = core,
m = mult,
- learn = True,
- d = 100,
+ learn_mode = learn_mode,
+ d = 100,
f = 'cap2/http_simple.yaml',
l = 1000)
@@ -124,7 +130,7 @@ class CTRexNat_Test(CTRexGeneral_Test):#(unittest.TestCase):
print trex_res.get_latest_dump()
trex_nat_stats = trex_res.get_last_value("trex-global.data", ".*nat.*") # extract all nat data
- if self.get_benchmark_param('allow_timeout_dev'):
+ if self.get_benchmark_param('allow_timeout_dev', test_name="test_nat_simple"):
nat_timeout_ratio = trex_nat_stats['m_total_nat_time_out']/trex_nat_stats['m_total_nat_open']
if nat_timeout_ratio > 0.005:
self.fail('TRex nat_timeout ratio %f > 0.5%%' % nat_timeout_ratio)
diff --git a/scripts/exp/bad_not_ip.pcap b/scripts/exp/bad_not_ip.pcap
new file mode 100644
index 00000000..01a4d4a6
--- /dev/null
+++ b/scripts/exp/bad_not_ip.pcap
Binary files differ
diff --git a/scripts/exp/http1_with_option-ex.pcap b/scripts/exp/http1_with_option-ex.pcap
index ef5bf3c4..6981ff1b 100755
--- a/scripts/exp/http1_with_option-ex.pcap
+++ b/scripts/exp/http1_with_option-ex.pcap
Binary files differ
diff --git a/scripts/exp/http1_with_option.pcap b/scripts/exp/http1_with_option.pcap
deleted file mode 100644
index ef5bf3c4..00000000
--- a/scripts/exp/http1_with_option.pcap
+++ /dev/null
Binary files differ
diff --git a/scripts/exp/http1_with_option_ipv6-ex.pcap b/scripts/exp/http1_with_option_ipv6-ex.pcap
index f70c1114..82a14a05 100755
--- a/scripts/exp/http1_with_option_ipv6-ex.pcap
+++ b/scripts/exp/http1_with_option_ipv6-ex.pcap
Binary files differ
diff --git a/scripts/exp/http1_with_option_ipv6.pcap b/scripts/exp/http1_with_option_ipv6.pcap
deleted file mode 100644
index f70c1114..00000000
--- a/scripts/exp/http1_with_option_ipv6.pcap
+++ /dev/null
Binary files differ
diff --git a/scripts/exp/many_ip_options.pcap b/scripts/exp/many_ip_options.pcap
new file mode 100644
index 00000000..8fddf6e4
--- /dev/null
+++ b/scripts/exp/many_ip_options.pcap
Binary files differ
diff --git a/scripts/exp/tcp_no_syn.pcap b/scripts/exp/tcp_no_syn.pcap
new file mode 100644
index 00000000..fe0615ad
--- /dev/null
+++ b/scripts/exp/tcp_no_syn.pcap
Binary files differ
diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp
index 005801c4..8d6a7b83 100755
--- a/src/bp_gtest.cpp
+++ b/src/bp_gtest.cpp
@@ -2076,7 +2076,7 @@ int CRxCheckIF::send_node(CGenNode * node){
memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12);
if ( unlikely( node->is_rx_check_enabled() ) ) {
- lp->do_generate_new_mbuf_rxcheck(m,node,p_id,m_one_dir);
+ lp->do_generate_new_mbuf_rxcheck(m, node, m_one_dir);
}
fill_pkt(m_raw,m);
@@ -2432,12 +2432,12 @@ class nat_check_system : public testing::Test {
CParserOption * po =&CGlobalInfo::m_options;
po->preview.setVMode(0);
po->preview.setFileWrite(true);
- po->preview.set_lean_mode_enable(true);
+ po->m_learn_mode = CParserOption::LEARN_MODE_IP_OPTION;
}
virtual void TearDown() {
CParserOption * po =&CGlobalInfo::m_options;
- po->preview.set_lean_mode_enable(false);
+ po->m_learn_mode = CParserOption::LEARN_MODE_DISABLED;
m_mg.Delete();
}
public:
@@ -2609,9 +2609,31 @@ TEST_F(file_flow_info, http_add_ipv6_option) {
po->preview.set_ipv6_mode_enable(false);
}
-
-
-
+// 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;
+
+ // file does not exist
+ err = m_flow_info.load_cap_file("/tmp/not_exist",1,0);
+ assert (err == 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);
+ // Non IP packet
+ err = m_flow_info.load_cap_file("./exp/bad_not_ip.pcap",1,0);
+ assert (err == CCapFileFlowInfo::kPktProcessFail);
+}
//////////////////////////////////////////////////////////////
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index 31ce0440..a7fadf93 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -1469,7 +1469,11 @@ void CFlowTableManagerBase::Dump(FILE *fd){
m_stats.Dump(fd);
}
-CFlow * CFlowTableManagerBase::process(CFlowKey & key,bool &is_fif ){
+// Return flow that has given key. If flow does not exist, create one, and add to CFlow data structure.
+// key - key to lookup by.
+// is_fif - return: true if flow did not exist (This is the first packet we see in this flow).
+// false if flow already existed
+CFlow * CFlowTableManagerBase::process(const CFlowKey & key, bool & is_fif) {
m_stats.m_lookup++;
is_fif=false;
CFlow * lp=lookup(key);
@@ -1490,7 +1494,6 @@ CFlow * CFlowTableManagerBase::process(CFlowKey & key,bool &is_fif ){
return (lp);
}
-
bool CFlowTableMap::Create(int max_size){
m_stats.Clear();
return (true);
@@ -1500,7 +1503,7 @@ void CFlowTableMap::Delete(){
remove_all();
}
-void CFlowTableMap::remove(CFlowKey & key ){
+void CFlowTableMap::remove(const CFlowKey & key ) {
CFlow *lp=lookup(key);
if ( lp ) {
delete lp;
@@ -1513,7 +1516,7 @@ void CFlowTableMap::remove(CFlowKey & key ){
}
-CFlow * CFlowTableMap::lookup(CFlowKey & key ){
+CFlow * CFlowTableMap::lookup(const CFlowKey & key ) {
flow_map_t::iterator iter;
iter = m_map.find(key);
if (iter != m_map.end() ) {
@@ -1523,7 +1526,7 @@ CFlow * CFlowTableMap::lookup(CFlowKey & key ){
}
}
-CFlow * CFlowTableMap::add(CFlowKey & key ){
+CFlow * CFlowTableMap::add(const CFlowKey & key ) {
CFlow * flow = new CFlow();
m_map.insert(flow_map_t::value_type(key,flow));
return (flow);
@@ -1559,7 +1562,6 @@ uint64_t CFlowTableMap::count(){
*/
void CFlowPktInfo::do_generate_new_mbuf_rxcheck(rte_mbuf_t * m,
CGenNode * node,
- pkt_dir_t dir,
bool single_port){
/* retrieve size of rx-check header, must be multiple of 8 */
@@ -1630,18 +1632,18 @@ void CFlowPktInfo::do_generate_new_mbuf_rxcheck(rte_mbuf_t * m,
rxhdr->m_time_stamp = os_get_hr_tick_32();
}
rxhdr->m_magic = RX_CHECK_MAGIC;
- rxhdr->m_flow_id = node->m_flow_id | ( ( (uint64_t)(desc->getFlowId() & 0xf))<<52 ) ; // include thread_id, node->flow_id, sub_flow in case of multi-flow template
- rxhdr->m_flags = 0;
+ rxhdr->m_flow_id = node->m_flow_id | ( ( (uint64_t)(desc->getFlowId() & 0xf))<<52 ) ; // include thread_id, node->flow_id, sub_flow in case of multi-flow template
+ rxhdr->m_flags = 0;
rxhdr->m_aging_sec = desc->GetMaxFlowTimeout();
rxhdr->m_template_id = (uint8_t)desc->getId();
/* add the flow packets goes to the same port */
if (single_port) {
- rxhdr->m_pkt_id = desc->getFlowPktNum();
+ rxhdr->m_pkt_id = desc->getFlowPktNum();
rxhdr->m_flow_size = desc->GetMaxPktsPerFlow();
}else{
- rxhdr->m_pkt_id = desc->GetDirInfo()->GetPktNum();
+ rxhdr->m_pkt_id = desc->GetDirInfo()->GetPktNum();
rxhdr->m_flow_size = desc->GetDirInfo()->GetMaxPkts();
/* set dir */
rxhdr->set_dir(desc->IsInitSide()?1:0);
@@ -1704,27 +1706,27 @@ char * CFlowPktInfo::push_ipv4_option_offline(uint8_t bytes){
return (p);
}
-
void CFlowPktInfo::mask_as_learn(){
CNatOption *lpNat;
- if ( m_pkt_indication.is_ipv6() ){
+ if ( m_pkt_indication.is_ipv6() ) {
lpNat=(CNatOption *)push_ipv6_option_offline(CNatOption::noOPTION_LEN);
lpNat->set_init_ipv6_header();
lpNat->set_fid(0);
lpNat->set_thread_id(0);
- }else{
- lpNat=(CNatOption *)push_ipv4_option_offline(CNatOption::noOPTION_LEN);
- lpNat->set_init_ipv4_header();
- lpNat->set_fid(0);
- lpNat->set_thread_id(0);
- m_pkt_indication.l3.m_ipv4->updateCheckSum();
+ } else {
+ if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION)) {
+ // Make space in IPv4 header for NAT option
+ lpNat=(CNatOption *)push_ipv4_option_offline(CNatOption::noOPTION_LEN);
+ lpNat->set_init_ipv4_header();
+ lpNat->set_fid(0);
+ lpNat->set_thread_id(0);
+ m_pkt_indication.l3.m_ipv4->updateCheckSum();
+ }
+ /* learn is true */
+ m_pkt_indication.m_desc.SetLearn(true);
}
- /* learn is true */
- m_pkt_indication.m_desc.SetLearn(true);
-
}
-
char * CFlowPktInfo::push_ipv6_option_offline(uint8_t bytes){
/* must be align by 8*/
@@ -1769,7 +1771,7 @@ char * CFlowPktInfo::push_ipv6_option_offline(uint8_t bytes){
void CFlowPktInfo::alloc_const_mbuf(){
if ( m_packet->pkt_len > FIRST_PKT_SIZE ) {
- /* pkt size in bigger than FIRST_PKT_SIZE let's create a offline buffer */
+ /* pkt size is bigger than FIRST_PKT_SIZE let's create an offline buffer */
int i;
for (i=0; i<MAX_SOCKETS_SUPPORTED; i++) {
if ( CGlobalInfo::m_socket.is_sockets_enable(i) ){
@@ -2023,7 +2025,7 @@ void CCapFileFlowInfo::update_info(){
}
-int CCapFileFlowInfo::load_cap_file(std::string cap_file,uint16_t _id,uint8_t plugin_id){
+enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::string cap_file, uint16_t _id, uint8_t plugin_id) {
RemoveAll();
fprintf(stdout," -- loading cap file %s \n",cap_file.c_str());
@@ -2033,7 +2035,7 @@ int CCapFileFlowInfo::load_cap_file(std::string cap_file,uint16_t _id,uint8_t pl
if (lp == 0) {
printf(" ERROR file %s does not exist or not supported \n",(char *)cap_file.c_str());
- return (-1);
+ return kFileNotExist;
}
bool multi_flow_enable =( (plugin_id!=0)?true:false);
@@ -2064,8 +2066,8 @@ int CCapFileFlowInfo::load_cap_file(std::string cap_file,uint16_t _id,uint8_t pl
time_was_set=true;
}else{
if (raw_packet.get_time()<last_time) {
- printf(" ERROR not valid pcap file,timestamp is negative at packet %d \n",cnt);
- exit(-1);
+ fprintf(stderr, "Error: Non valid pcap file. Timestamp is negative at packet %d\n", cnt);
+ return kNegTimestamp;
}
last_time=raw_packet.get_time();
}
@@ -2094,41 +2096,56 @@ int CCapFileFlowInfo::load_cap_file(std::string cap_file,uint16_t _id,uint8_t pl
pkt_indication.setTTL(TTL_RESERVE_DUPLICATE-4);
}
+ // Validation for first packet in flow
if (is_fif) {
-
lpflow->flow_id = m_total_flows;
-
pkt_indication.m_desc.SetFlowId(lpflow->flow_id);
if (m_total_flows == 0) {
- /* first flow */
- first_flow =lpflow;/* save it for single flow support , to signal error */
- lpflow->is_fif_swap =pkt_indication.m_desc.IsSwapTuple();
- first_flow_fif_is_swap = pkt_indication.m_desc.IsSwapTuple();
- pkt_indication.m_desc.SetInitSide(true);
- Append(&pkt_indication);
- m_total_flows++;
-
- }else{
- if ( multi_flow_enable ){
-
- lpflow->is_fif_swap = pkt_indication.m_desc.IsSwapTuple();
- /* in respect to the first flow */
-
- bool init_side_in_repect_to_first_flow =
- ((first_flow_fif_is_swap?true:false) == lpflow->is_fif_swap)?true:false;
-
- pkt_indication.m_desc.SetInitSide(init_side_in_repect_to_first_flow);
+ /* first flow */
+ first_flow =lpflow;/* save it for single flow support , to signal error */
+ lpflow->is_fif_swap =pkt_indication.m_desc.IsSwapTuple();
+ first_flow_fif_is_swap = pkt_indication.m_desc.IsSwapTuple();
+ pkt_indication.m_desc.SetInitSide(true);
Append(&pkt_indication);
m_total_flows++;
-
- }else{
- printf(" more than one flow in this cap ignore it !! \n");
- pkt_indication.m_flow_key.Dump(stdout);
- m_total_errors++;
+ } else {
+ if ( multi_flow_enable ) {
+ lpflow->is_fif_swap = pkt_indication.m_desc.IsSwapTuple();
+ /* in respect to the first flow */
+ bool init_side_in_repect_to_first_flow =
+ ((first_flow_fif_is_swap?true:false) == lpflow->is_fif_swap)?true:false;
+ pkt_indication.m_desc.SetInitSide(init_side_in_repect_to_first_flow);
+ Append(&pkt_indication);
+ m_total_flows++;
+ } else {
+ printf("More than one flow in this cap. Ignoring it !! \n");
+ pkt_indication.m_flow_key.Dump(stderr);
+ 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 */
@@ -2157,13 +2174,23 @@ int CCapFileFlowInfo::load_cap_file(std::string cap_file,uint16_t _id,uint8_t pl
}
}
+
+ 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{
- printf("ERROR packet %d is not supported, should be IP(0x0800)/TCP/UDP format try to convert it using Wireshark !\n",cnt);
- exit(-1);
+ fprintf(stderr, "ERROR packet %d is not supported, should be IP(0x0800)/TCP/UDP format try to convert it using Wireshark !\n",cnt);
+ return kPktNotSupp;
}
}else{
- printf("ERROR packet %d is not supported, should be IP(0x0800)/TCP/UDP format try to convert it using Wireshark !\n",cnt);
- exit(-1);
+ fprintf(stderr, "ERROR packet %d is not supported, should be IP(0x0800)/TCP/UDP format try to convert it using Wireshark !\n",cnt);
+ return kPktProcessFail;
}
}
@@ -2205,10 +2232,10 @@ int CCapFileFlowInfo::load_cap_file(std::string cap_file,uint16_t _id,uint8_t pl
delete lp;
if ( m_total_errors > 0 ) {
parser.m_counter.Dump(stdout);
- printf(" ERORR in one of the cap file, you should have one flow per cap file or valid plugin \n");
- return(-1);
+ fprintf(stderr, " ERORR in one of the cap file, you should have one flow per cap file or valid plugin \n");
+ return kCapFileErr;
}
- return (0);
+ return kOK;
}
void CCapFileFlowInfo::update_pcap_mode(){
@@ -4455,8 +4482,20 @@ double CBwMeasure::add(uint64_t size) {
+/*
+ * Test if option value is within allowed range.
+ * val - Value to test
+ * min, max - minimum, maximum allowed values.
+ * opt_name - option name for error report.
+ */
+bool CParserOption::is_valid_opt_val(int val, int min, int max, const std::string &opt_name) {
+ if (val < min || val > max) {
+ std::cerr << "Value " << val << " for option " << opt_name << " is out of range. Should be (" << min << "-" << max << ")." << std::endl;
+ return false;
+ }
-
+ return true;
+}
void CParserOption::dump(FILE *fd){
preview.Dump(fd);
@@ -4514,7 +4553,7 @@ void CTupleGlobalGenerator::Delete(){
#endif
static uint32_t get_rand_32(uint32_t MinimumRange ,
- uint32_t MaximumRange );
+ uint32_t MaximumRange );
#if 0
@@ -4636,23 +4675,20 @@ static uint32_t get_rand_32(uint32_t MinimumRange,
static uint32_t get_rand_32(uint32_t MinimumRange,
uint32_t MaximumRange) {
+ enum {RANDS_NUM = 2 , RAND_MAX_BITS = 0xf , UNSIGNED_INT_BITS = 0x20 , TWO_BITS_MASK = 0x3};
+ const double TWO_POWER_32_BITS = 0x10000000 * (double)0x10;
+ uint32_t RandomNumber = 0;
- enum {RANDS_NUM = 2 , RAND_MAX_BITS = 0xf , UNSIGNED_INT_BITS = 0x20 , TWO_BITS_MASK = 0x3};
-
- const double TWO_POWER_32_BITS = 0x10000000 * (double)0x10;
-
- uint32_t RandomNumber = 0;
- for (int i = 0 ; i < RANDS_NUM;i++) {
- RandomNumber = (RandomNumber<<RAND_MAX_BITS) + rand();
- }
-
- RandomNumber = (RandomNumber<<(UNSIGNED_INT_BITS - RAND_MAX_BITS * RANDS_NUM)) + (rand() | TWO_BITS_MASK);
+ for (int i = 0 ; i < RANDS_NUM;i++) {
+ RandomNumber = (RandomNumber<<RAND_MAX_BITS) + rand();
+ }
+ RandomNumber = (RandomNumber<<(UNSIGNED_INT_BITS - RAND_MAX_BITS * RANDS_NUM)) + (rand() | TWO_BITS_MASK);
- uint32_t Range;
- if ((Range = MaximumRange - MinimumRange) == 0xffffffff) {
- return RandomNumber;
- }
- return (uint32_t)(((Range + 1) / TWO_POWER_32_BITS * RandomNumber) + MinimumRange );
+ uint32_t Range;
+ if ((Range = MaximumRange - MinimumRange) == 0xffffffff) {
+ return RandomNumber;
+ }
+ return (uint32_t)(((Range + 1) / TWO_POWER_32_BITS * RandomNumber) + MinimumRange );
}
@@ -6078,4 +6114,3 @@ void CGenNodeBase::free_base(){
}
}
-
diff --git a/src/bp_sim.h b/src/bp_sim.h
index b9a42027..9f08cdc9 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -6,7 +6,7 @@
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 Cisco Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -20,13 +20,13 @@ 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 <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <vector>
#include <algorithm>
#include <map>
-#include <string>
#include <iostream>
#include <fstream>
#include <string>
@@ -34,7 +34,6 @@ limitations under the License.
#include "mbuf.h"
#include <common/c_common.h>
#include <common/captureFile.h>
-#include <string>
#include <common/Network/Packet/TcpHeader.h>
#include <common/Network/Packet/UdpHeader.h>
#include <common/Network/Packet/IcmpHeader.h>
@@ -62,7 +61,6 @@ limitations under the License.
#undef NAT_TRACE_
-
static inline double
usec_to_sec(double usec) {
return (usec / (1000 * 1000));
@@ -473,7 +471,7 @@ public:
/* learn & verify mode */
- void set_lean_and_verify_mode_enable(bool enable){
+ void set_learn_and_verify_mode_enable(bool enable){
btSetMaskBit32(m_flags,5,5,enable?1:0);
}
@@ -481,17 +479,6 @@ public:
return (btGetMaskBit32(m_flags,5,5) ? true:false);
}
-
- /* learn mode */
- void set_lean_mode_enable(bool enable){
- btSetMaskBit32(m_flags,6,6,enable?1:0);
- }
-
- bool get_learn_mode_enable(){
- return (btGetMaskBit32(m_flags,6,6) ? true:false);
- }
-
-
/* IPv6 enable/disable */
void set_ipv6_mode_enable(bool enable){
btSetMaskBit32(m_flags,7,7,enable?1:0);
@@ -732,6 +719,13 @@ public:
RUN_MODE_INTERACTIVE
};
+ enum trex_learn_mode_e {
+ LEARN_MODE_DISABLED=0,
+ LEARN_MODE_TCP_ACK=1,
+ LEARN_MODE_IP_OPTION=2,
+ LEARN_MODE_MAX=LEARN_MODE_IP_OPTION
+ };
+
public:
CParserOption(){
m_factor=1.0;
@@ -776,6 +770,7 @@ public:
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;
trex_run_mode_e m_run_mode;
@@ -837,6 +832,7 @@ public:
return (m_l_pkt_mode);
}
void dump(FILE *fd);
+ bool is_valid_opt_val(int val, int min, int max, const std::string &opt_name);
};
@@ -1190,11 +1186,15 @@ public:
static inline bool is_learn_verify_mode(){
- return ( m_options.preview.get_learn_mode_enable() && m_options.preview.get_learn_and_verify_mode_enable());
+ return ( (m_options.m_learn_mode != CParserOption::LEARN_MODE_DISABLED) && m_options.preview.get_learn_and_verify_mode_enable());
}
static inline bool is_learn_mode(){
- return ( m_options.preview.get_learn_mode_enable() );
+ return ( (m_options.m_learn_mode != CParserOption::LEARN_MODE_DISABLED));
+ }
+
+ static inline bool is_learn_mode(CParserOption::trex_learn_mode_e mode){
+ return ( (m_options.m_learn_mode == mode));
}
static inline bool is_ipv6_enable(void){
@@ -1628,10 +1628,8 @@ public:
}
public:
-
-
inline uint32_t get_short_fid(void){
- return ((uint32_t)m_flow_id);
+ return (((uint32_t)m_flow_id) & NAT_FLOW_ID_MASK);
}
inline uint8_t get_thread_id(void){
@@ -2236,6 +2234,7 @@ public:
btSetMaskBit32(m_flags,12,8,flow_id);
}
+
inline uint16_t getFlowId(){
return ( ( uint16_t)btGetMaskBit32(m_flags,12,8));
}
@@ -2527,6 +2526,14 @@ public:
}
}
+ uint8_t getIpProto(){
+ BP_ASSERT(l3.m_ipv4);
+ if (is_ipv6()) {
+ return(l3.m_ipv6->getNextHdr());
+ }else{
+ return(l3.m_ipv4->getProtocol());
+ }
+ }
uint8_t getFastEtherOffset(void){
return (m_ether_offset);
@@ -2624,15 +2631,15 @@ public:
virtual bool Create(int max_size)=0;
virtual void Delete()=0;
public:
- CFlow * process(CFlowKey & key,bool &is_fif );
- virtual void remove(CFlowKey & key )=0;
+ CFlow * process(const CFlowKey & key,bool &is_fif );
+ virtual void remove(const CFlowKey & key )=0;
virtual void remove_all()=0;
virtual uint64_t count()=0;
public:
void Dump(FILE *fd);
protected:
- virtual CFlow * lookup(CFlowKey & key )=0;
- virtual CFlow * add(CFlowKey & key )=0;
+ virtual CFlow * lookup(const CFlowKey & key )=0;
+ virtual CFlow * add(const CFlowKey & key )=0;
//virtual IterateFlows(CFlowTableInterator * iter)=0;
protected:
@@ -2650,11 +2657,11 @@ class CFlowTableMap : public CFlowTableManagerBase {
public:
virtual bool Create(int max_size);
virtual void Delete();
- virtual void remove(CFlowKey & key );
+ virtual void remove(const CFlowKey & key );
protected:
- virtual CFlow * lookup(CFlowKey & key );
- virtual CFlow * add(CFlowKey & key );
+ virtual CFlow * lookup(const CFlowKey & key );
+ virtual CFlow * add(const CFlowKey & key );
virtual void remove_all(void);
uint64_t count(void);
private:
@@ -2689,7 +2696,6 @@ public:
/* new packet with rx check info in IP option */
void do_generate_new_mbuf_rxcheck(rte_mbuf_t * m,
CGenNode * node,
- pkt_dir_t dir,
bool single_port);
inline rte_mbuf_t * do_generate_new_mbuf_ex(CGenNode * node,CFlowInfo * flow_info);
@@ -2869,41 +2875,53 @@ inline void CFlowPktInfo::update_pkt_info(char *p,
if (m_pkt_indication.m_desc.IsLearn()) {
/* might be done twice */
- #ifdef NAT_TRACE_
+#ifdef NAT_TRACE_
printf(" %.3f : DP : learn packet !\n",now_sec());
- #endif
+#endif
ipv4->setTimeToLive(TTL_RESERVE_DUPLICATE);
/* first ipv4 option add the info in case of learn packet, usualy only the first packet */
- CNatOption *lpNat =(CNatOption *)ipv4->getOption();
- lpNat->set_fid(node->get_short_fid());
- lpNat->set_thread_id(node->get_thread_id());
- lpNat->set_rx_check(node->is_rx_check_enabled());
+ 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());
+#endif
+ }
+ }
}
/* in call cases update the ip using the outside ip */
if ( m_pkt_indication.m_desc.IsInitSide() ) {
- #ifdef NAT_TRACE_
+#ifdef NAT_TRACE_
if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
- printf(" %.3f : DP : i %x:%x -> %x flow_id: %x\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
+#endif
ipv4->updateIpSrc(node->m_src_ip);
ipv4->updateIpDst(node->m_dest_ip);
}else{
- #ifdef NAT_TRACE_
+#ifdef NAT_TRACE_
if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
- printf(" %.3f : r %x -> %x:%x flow_id: %x \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
+#endif
src_port = node->get_nat_ipv4_port();
ipv4->updateIpSrc(node->get_nat_ipv4_addr_server());
ipv4->updateIpDst(node->get_nat_ipv4_addr());
}
/* TBD remove this */
- #ifdef NAT_TRACE_
+#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(),
@@ -2912,24 +2930,24 @@ inline void CFlowPktInfo::update_pkt_info(char *p,
printf(" %.3f : pkt ==> init pkt sent \n",now_sec());
}
}
- #endif
+#endif
}else{
if ( ip_dir == CLIENT_SIDE ) {
- #ifdef NAT_TRACE_
+#ifdef NAT_TRACE_
if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
printf(" %.3f : i %x:%x -> %x \n",now_sec(),node->m_src_ip,node->m_src_port,node->m_dest_ip);
}
- #endif
+#endif
ipv4->updateIpSrc(node->m_src_ip);
ipv4->updateIpDst(node->m_dest_ip);
}else{
- #ifdef NAT_TRACE_
+#ifdef NAT_TRACE_
if (node->m_flags != CGenNode::NODE_FLAGS_LATENCY ) {
printf(" %.3f : r %x -> %x:%x \n",now_sec(),node->m_dest_ip,node->m_src_ip,node->m_src_port);
}
- #endif
+#endif
ipv4->updateIpSrc(node->m_dest_ip);
ipv4->updateIpDst(node->m_src_ip);
}
@@ -3182,6 +3200,18 @@ public:
class CCapFileFlowInfo {
public:
+ enum load_cap_file_err {
+ kOK = 0,
+ kFileNotExist,
+ kNegTimestamp,
+ kNoSyn,
+ kTCPOffsetTooBig,
+ kNoTCPFromServer,
+ kPktNotSupp,
+ kPktProcessFail,
+ kCapFileErr
+ };
+
bool Create();
void Delete();
uint64_t Size(void){
@@ -3191,7 +3221,7 @@ public:
void Append(CPacketIndication * pkt_indication);
void RemoveAll();
void dump_pkt_sizes(void);
- int load_cap_file(std::string cap_file,uint16_t _id,uint8_t plugin_id);
+ enum load_cap_file_err load_cap_file(std::string cap_file, uint16_t _id, uint8_t plugin_id);
/* update flow info */
void update_info();
@@ -3224,12 +3254,8 @@ public:
void get_total_memory(CCCapFileMemoryUsage & memory);
public:
- void update_min_ipg(dsec_t min_ipg,
- dsec_t override_ipg);
-
+ void update_min_ipg(dsec_t min_ipg, dsec_t override_ipg);
void update_pcap_mode();
-
-public:
void Dump(FILE *fd);
private:
@@ -3746,7 +3772,7 @@ inline void CCapFileFlowInfo::generate_flow(CTupleTemplateGeneratorSmart * tup
if ( lp->m_pkt_indication.m_desc.IsBiDirectionalFlow() ) {
/* we are in learn mode */
CFlowGenListPerThread * lpThread=gen->Parent();
- lpThread->associate((uint32_t)flow_id,node); /* assosiate flow_id=>node */
+ lpThread->associate(((uint32_t)flow_id) & NAT_FLOW_ID_MASK, node); /* associate flow_id=>node */
node->set_nat_first_state();
}
}
diff --git a/src/common/Network/Packet/TcpHeader.h b/src/common/Network/Packet/TcpHeader.h
index e07df927..c19cd262 100755
--- a/src/common/Network/Packet/TcpHeader.h
+++ b/src/common/Network/Packet/TcpHeader.h
@@ -17,7 +17,7 @@ limitations under the License.
#define _TCP_HEADER_H_
#include "PacketHeaderBase.h"
-
+#define TCP_HEADER_LEN 20
class TCPHeader
{
diff --git a/src/debug.cpp b/src/debug.cpp
index e5e207e1..ed4900f9 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -98,9 +98,12 @@ int CTrexDebug::rcv_send_all(int queue_id) {
rte_mbuf_t *CTrexDebug::create_test_pkt(int pkt_type) {
uint8_t proto;
int pkt_size = 0;
- // uint8_t dst_mac[6] = {0xd4, 0x8c, 0xb5, 0xc9, 0x54, 0x2b};
- uint8_t dst_mac[6] = {0x79, 0xa2, 0xe6, 0xd5, 0x39, 0x25};
- uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02};
+ // ASA 2
+ uint8_t dst_mac[6] = {0x74, 0xa2, 0xe6, 0xd5, 0x39, 0x25};
+ uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02};
+ // ASA 1
+ // uint8_t dst_mac[6] = {0xd4, 0x8c, 0xb5, 0xc9, 0x54, 0x2b};
+ // uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x0};
uint16_t l2_proto = 0x0008;
uint8_t ip_header[] = {
0x45,0x02,0x00,0x30,
@@ -127,7 +130,7 @@ rte_mbuf_t *CTrexDebug::create_test_pkt(int pkt_type) {
0xe7
};
uint8_t tcp_header[] = {0xab, 0xcd, 0x00, 0x80, // src, dst ports
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // seq num, ack num
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // seq num, ack num
0x50, 0x00, 0xff, 0xff, // Header size, flags, window size
0x00, 0x00, 0x00, 0x00, // checksum ,urgent pointer
};
diff --git a/src/latency.cpp b/src/latency.cpp
index 3969c357..b213690f 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) {
case CNatOption::noIPV4_OPTION:
/* NAT learn option header */
CNatOption *lp;
- if ( ( !CGlobalInfo::is_learn_mode() ) ||
+ if ( ( !CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_IP_OPTION) ) ||
(opt_len < CNatOption::noOPTION_LEN) ) {
m_seq_error++;
return (false);
@@ -455,9 +455,14 @@ 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);
+ }
return (true);
} // End of check for non-latency packet
+ // learn for latency packets. We only have one flow for latency, so translation is for it.
if ( CGlobalInfo::is_learn_mode() && (m_nat_learn ==false) ) {
do_learn(parser.m_ipv4->getSourceIp());
}
diff --git a/src/latency.h b/src/latency.h
index 59481a59..cbb67dbd 100644
--- a/src/latency.h
+++ b/src/latency.h
@@ -88,15 +88,34 @@ public:
uint8_t getTTl();
uint16_t getPktSize();
+ // Check if packet contains latency data
inline bool IsLatencyPkt(uint8_t *p) {
+ if (! p)
+ return false;
+
latency_header * h=(latency_header *)(p);
if ( (h->magic & 0xffffff00) != LATENCY_MAGIC ){
- return (false);
+ return false;
}
return true;
}
+ // 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;
+ }
public:
IPHeader * m_ipv4;
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index aba15c28..7cbe7f2b 100755
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -495,6 +495,7 @@ enum { OPT_HELP,
OPT_IO_MODE,
OPT_IPV6,
OPT_LEARN,
+ OPT_LEARN_MODE,
OPT_LEARN_VERIFY,
OPT_L_PKT_MODE,
OPT_NO_FLOW_CONTROL,
@@ -555,6 +556,7 @@ static CSimpleOpt::SOption parser_options[] =
{ OPT_RX_CHECK_HOPS, "--hops", SO_REQ_SEP },
{ OPT_IPV6, "--ipv6", SO_NONE },
{ OPT_LEARN, "--learn", SO_NONE },
+ { OPT_LEARN_MODE, "--learn-mode", SO_REQ_SEP },
{ 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 },
@@ -630,8 +632,10 @@ static int usage(){
printf(" \n");
printf(" --ipv6 : work in ipv6 mode\n");
-
- printf(" --learn : Work in NAT environments, learn the dynamic NAT translation and ALG \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(" 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(" --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");
@@ -792,16 +796,27 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
break;
case OPT_LEARN :
- po->preview.set_lean_mode_enable(true);
+ po->m_learn_mode = CParserOption::LEARN_MODE_IP_OPTION;
+ break;
+
+ case OPT_LEARN_MODE :
+ sscanf(args.OptionArg(),"%d", &tmp_data);
+ if (! po->is_valid_opt_val(tmp_data, CParserOption::LEARN_MODE_DISABLED, CParserOption::LEARN_MODE_MAX, "--learn-mode")) {
+ exit(-1);
+ }
+ po->m_learn_mode = (uint8_t)tmp_data;
break;
case OPT_LEARN_VERIFY :
- po->preview.set_lean_mode_enable(true);
- po->preview.set_lean_and_verify_mode_enable(true);
+ po->m_learn_mode = CParserOption::LEARN_MODE_IP_OPTION;
+ po->preview.set_learn_and_verify_mode_enable(true);
break;
case OPT_L_PKT_MODE :
sscanf(args.OptionArg(),"%d", &tmp_data);
+ if (! po->is_valid_opt_val(tmp_data, 0, L_PKT_SUBMODE_0_SEQ, "--l-pkt-mode")) {
+ exit(-1);
+ }
po->m_l_pkt_mode=(uint8_t)tmp_data;
break;
@@ -932,7 +947,7 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
parse_err(ss.str());
}
- if ( po->preview.get_learn_mode_enable() ){
+ 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");
@@ -2044,7 +2059,7 @@ int CCoreEthIF::send_node(CGenNode * node){
if ( unlikely( node->is_rx_check_enabled() ) ) {
lp_stats->m_tx_rx_check_pkt++;
- lp->do_generate_new_mbuf_rxcheck(m,node,dir,single_port);
+ lp->do_generate_new_mbuf_rxcheck(m, node, single_port);
lp_stats->m_template.inc_template( node->get_template_id( ));
}else{
// cache only if it is not sample as this is more complex mbuf struct
@@ -4160,7 +4175,7 @@ int main_test(int argc , char * argv[]){
update_global_info_from_platform_file();
- /* it is not a mistake , give the user higher priorty over the configuration file */
+ /* It is not a mistake. Give the user higher priorty over the configuration file */
parse_options(argc, argv, &CGlobalInfo::m_options ,false);
@@ -4212,7 +4227,7 @@ int main_test(int argc , char * argv[]){
if (po->preview.get_is_rx_check_enable() && (po->m_rx_check_sampe< get_min_sample_rate()) ) {
po->m_rx_check_sampe = get_min_sample_rate();
- printf("Warning rx check sample rate should be lower than %d setting it to %d\n",get_min_sample_rate(),get_min_sample_rate());
+ printf("Warning:rx check sample rate should not be lower than %d. Setting it to %d\n",get_min_sample_rate(),get_min_sample_rate());
}
/* set dump mode */
diff --git a/src/nat_check.cpp b/src/nat_check.cpp
index 170d2de6..7e224430 100755
--- a/src/nat_check.cpp
+++ b/src/nat_check.cpp
@@ -1,13 +1,10 @@
-#include <stdint.h>
-#include "nat_check.h"
-#include "bp_sim.h"
/*
Hanoh Haim
Cisco Systems, Inc.
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 Cisco Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -21,6 +18,21 @@ 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.
*/
+/*
+This file is for testing devices implementing NAT.
+For each flow, we need to learn the NAT translation in order to send server responses.
+Algorithm is as described below:
+We send first packet from client, and look at it on other side to see how it was changed. Then we configure
+the server flow with the appropriate change. To keep track of which flow the packet belongs to, we attach to the
+first packet of each flow, flow id and thread id (thread handling the flow).
+Information attaching method can be chosen be using --learn-mode option.
+The information is attached either in special IP option, or in ACK number of first SYN packet.
+*/
+
+#include <stdint.h>
+#include <common/basic_utils.h>
+#include "nat_check.h"
+#include "bp_sim.h"
void CGenNodeNatInfo::dump(FILE *fd){
@@ -122,14 +134,24 @@ void CNatRxManager::flush_node(CNatPerThreadInfo * thread_info){
thread_info->m_cur_nat_msg=0;
}
+void CNatRxManager::get_info_from_tcp_ack(uint32_t tcp_ack, uint32_t &fid, uint8_t &thread_info) {
+ thread_info = (uint8_t) tcp_ack;
+ fid = (tcp_ack >> 8) & NAT_FLOW_ID_MASK;
+}
-void CNatRxManager::handle_packet_ipv4(CNatOption * option,
- IPHeader * ipv4){
+/*
+ * We handle NAT info. Extracting IP src/dst and protocol from the packet.
+ * Adding the information to a msg to be sent to the thread handling this flow.
+ * Thread and flow info is extracted from IP packet. Either from IP option or TCP ACK.
+ * Parameters:
+ * 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.
+ */
+void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4) {
+ CNatPerThreadInfo * thread_info;
+ uint32_t fid=0;
- CNatPerThreadInfo * thread_info=get_thread_info(option->get_thread_id());
- if (!thread_info) {
- return;
- }
/* Extract info from the packet ! */
uint32_t ext_ip = ipv4->getSourceIp();
uint32_t ext_ip_server = ipv4->getDestIp();
@@ -140,12 +162,25 @@ void CNatRxManager::handle_packet_ipv4(CNatOption * option,
return;
}
/* we support only TCP/UDP so take the source port , post IP header */
- UDPHeader * udp= (UDPHeader *) (((char *)ipv4)+ ipv4->getHeaderLength());
- uint16_t ext_port = udp->getSourcePort();
- #ifdef NAT_TRACE_
- printf("rx msg ext ip : %08x:%08x ext port : %04x flow_id : %d \n",ext_ip,ext_ip_server,ext_port,option->get_fid());
- #endif
+ TCPHeader *tcp = (TCPHeader *) (((char *)ipv4)+ ipv4->getHeaderLength());
+ uint16_t ext_port = tcp->getSourcePort();
+
+ 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);
+ }
+ 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);
+#endif
CGenNodeNatInfo * node=thread_info->m_cur_nat_msg;
if ( !node ){
@@ -162,7 +197,7 @@ void CNatRxManager::handle_packet_ipv4(CNatOption * option,
msg->m_external_ip = ext_ip;
msg->m_external_ip_server = ext_ip_server;
msg->m_external_port = ext_port;
- msg->m_fid = option->get_fid();
+ msg->m_fid = fid;
msg->m_pad = 0xee;
if ( node->is_full() ){
@@ -193,5 +228,11 @@ void CNatRxManager::DumpShort(FILE *fd){
fprintf(fd,"nat check msgs: %lu, errors: %lu \n",m_stats.m_total_msg,m_stats.get_errs() );
}
-
-
+void CNatOption::dump(FILE *fd) {
+ fprintf(fd," op : %x \n",get_option_type());
+ fprintf(fd," ol : %x \n",get_option_len());
+ fprintf(fd," thread_id : %x \n",get_thread_id());
+ fprintf(fd," magic : %x \n",get_magic());
+ fprintf(fd," fid : %x \n",get_fid());
+ utl_DumpBuffer(stdout,(void *)&u.m_data[0],8,0);
+}
diff --git a/src/nat_check.h b/src/nat_check.h
index a500ddaf..133501ae 100755
--- a/src/nat_check.h
+++ b/src/nat_check.h
@@ -21,18 +21,103 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-#include "rx_check_header.h"
#include "msg_manager.h"
#include <common/Network/Packet/TcpHeader.h>
#include <common/Network/Packet/UdpHeader.h>
#include <common/Network/Packet/IPHeader.h>
#include <common/Network/Packet/IPv6Header.h>
#include <common/Network/Packet/EthernetHeader.h>
-
-
+#include "os_time.h"
// 2msec timeout
#define MAX_TIME_MSG_IN_QUEUE_SEC ( 0.002 )
+#define NAT_FLOW_ID_MASK 0x00ffffff
+
+class CNatOption {
+public:
+ enum {
+ noIPV4_OPTION = 0x10, /* dummy IPV4 option */
+ noOPTION_LEN = 0x8,
+ noIPV4_MAGIC = 0xEE,
+ noIPV4_MAGIC_RX = 0xED,
+
+ noIPV6_OPTION_LEN = (noOPTION_LEN/8)-1,
+ noIPV6_OPTION = 0x3C, /*IPv6-Opts Destination Options for IPv6 RFC 2460*/
+ };
+
+ void set_option_type(uint8_t id) {
+ u.m_data[0 ] =id;
+ }
+
+ uint8_t get_option_type() {
+ return (u.m_data[0]);
+ }
+
+ void set_option_len(uint8_t len) {
+ u.m_data[1] = len;
+ }
+ uint8_t get_option_len(){
+ return ( u.m_data[1]);
+ }
+
+ void set_thread_id(uint8_t thread_id) {
+ u.m_data[3] = thread_id;
+ }
+
+ uint8_t get_thread_id() {
+ return (u.m_data[3]);
+ }
+
+ void set_magic(uint8_t magic){
+ u.m_data[2] = magic;
+ }
+
+ uint8_t get_magic(){
+ return (u.m_data[2]);
+ }
+
+ void set_fid(uint32_t fid) {
+ u.m_data_uint32[1] = fid & NAT_FLOW_ID_MASK;
+ }
+
+ uint32_t get_fid() {
+ return (u.m_data_uint32[1]);
+ }
+
+ bool is_valid_ipv4_magic_op0(void){
+ return ( ( PKT_NTOHL( u.m_data_uint32[0] )& 0xFFFFFF00 ) ==
+ (CNatOption::noIPV4_OPTION <<24) + (CNatOption::noOPTION_LEN<<16) + (CNatOption::noIPV4_MAGIC<<8) ?true:false);
+ }
+
+ bool is_valid_ipv4_magic(void) {
+ return (is_valid_ipv4_magic_op0());
+ }
+
+ bool is_valid_ipv6_magic(void) {
+ return ( ( PKT_NTOHL( u.m_data_uint32[0] )& 0x00FFFF00 ) ==
+ (CNatOption::noIPV6_OPTION_LEN<<16) + (CNatOption::noIPV4_MAGIC<<8) ?true:false);
+
+ }
+
+ void set_init_ipv4_header() {
+ set_option_type(CNatOption::noIPV4_OPTION);
+ set_option_len(CNatOption::noOPTION_LEN);
+ set_magic(CNatOption::noIPV4_MAGIC);
+ }
+
+ void set_init_ipv6_header(void){
+ set_option_len(noIPV6_OPTION_LEN);
+ set_magic(CNatOption::noIPV4_MAGIC);
+ }
+
+ void dump(FILE *fd);
+
+private:
+ union u_ {
+ uint8_t m_data[8];
+ uint32_t m_data_uint32[2];
+ } u;
+};
struct CNatFlowInfo {
uint32_t m_external_ip;
@@ -46,31 +131,28 @@ struct CNatFlowInfo {
/* size of 64 bytes */
#define MAX_NAT_FLOW_INFO (7)
#define MAX_PKT_MSG_INFO (26)
-
#else
#define MAX_NAT_FLOW_INFO (8)
#define MAX_PKT_MSG_INFO (30)
#endif
-
/*
!!! WARNING - CGenNodeNatInfo !!
this struct should be in the same size of CGenNode beacuse allocator is global .
*/
-
-struct CGenNodeNatInfo : public CGenNodeMsgBase {
+struct CGenNodeNatInfo : public CGenNodeMsgBase {
uint8_t m_pad;
uint16_t m_cnt;
//uint32_t m_pad2;
- #if __x86_64__
+ #if __x86_64__
uint32_t m_pad3;
- #endif
+ #endif
CNatFlowInfo m_data[MAX_NAT_FLOW_INFO];
public:
- CNatFlowInfo * get_next_msg(){
+ CNatFlowInfo * get_next_msg() {
CNatFlowInfo * lp=&m_data[m_cnt];
m_cnt++;
return (lp);
@@ -84,12 +166,12 @@ public:
void dump(FILE *fd);
};
-struct CGenNodeLatencyPktInfo : public CGenNodeMsgBase {
+struct CGenNodeLatencyPktInfo : public CGenNodeMsgBase {
uint8_t m_dir;
uint16_t m_latency_offset;
- #if __x86_64__
+ #if __x86_64__
uint32_t m_pad3;
- #endif
+#endif
struct rte_mbuf * m_pkt;
uint32_t m_pad4[MAX_PKT_MSG_INFO];
@@ -100,7 +182,7 @@ struct CGenNodeLatencyPktInfo : public CGenNodeMsgBase {
try to put as many messages */
class CNatPerThreadInfo {
public:
- CNatPerThreadInfo(){
+ CNatPerThreadInfo() {
m_last_time=0;
m_cur_nat_msg=0;
m_ring=0;
@@ -114,8 +196,6 @@ public:
class CNatStats {
public:
- void reset();
-public:
uint64_t m_total_rx;
uint64_t m_total_msg;
/* errors */
@@ -123,6 +203,7 @@ public:
uint64_t m_err_no_valid_proto;
uint64_t m_err_queue_full;
public:
+ void reset();
uint64_t get_errs(){
return (m_err_no_valid_thread_id+m_err_no_valid_proto+m_err_queue_full);
}
@@ -135,11 +216,14 @@ class CNatRxManager {
public:
bool Create();
void Delete();
- void handle_packet_ipv4(CNatOption * option,
- IPHeader * ipv4);
+ void handle_packet_ipv4(CNatOption * option, IPHeader * ipv4);
void handle_aging();
- void Dump(FILE *fd);
+ void Dump(FILE *fd);
void DumpShort(FILE *fd);
+ static inline uint32_t calc_tcp_ack_val(uint32_t fid, uint8_t thread_id) {
+ return ((fid & NAT_FLOW_ID_MASK) << 8) | thread_id;
+ }
+ void get_info_from_tcp_ack(uint32_t tcp_ack, uint32_t &fid, uint8_t &thread_id);
private:
CNatPerThreadInfo * get_thread_info(uint8_t thread_id);
void flush_node(CNatPerThreadInfo * thread_info);
diff --git a/src/rx_check.cpp b/src/rx_check.cpp
index 59b42e1a..7e81ef28 100755
--- a/src/rx_check.cpp
+++ b/src/rx_check.cpp
@@ -1,12 +1,10 @@
-#include "rx_check.h"
-#include "utl_json.h"
/*
Hanoh Haim
Cisco Systems, Inc.
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 Cisco Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -21,6 +19,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+#include "rx_check.h"
+#include "utl_json.h"
+
void CRxCheckFlowTableStats::Clear(){
m_total_rx_bytes=0;
diff --git a/src/rx_check_header.cpp b/src/rx_check_header.cpp
index 5934ee15..fbf094e2 100755
--- a/src/rx_check_header.cpp
+++ b/src/rx_check_header.cpp
@@ -1,12 +1,10 @@
-#include "rx_check_header.h"
-#include <common/basic_utils.h>
/*
Hanoh Haim
Cisco Systems, Inc.
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 Cisco Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -20,8 +18,8 @@ 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 "os_time.h"
+#include "rx_check_header.h"
void CRx_check_header::dump(FILE *fd){
@@ -37,16 +35,3 @@ void CRx_check_header::dump(FILE *fd){
fprintf(fd," flow_id : %lx \n",m_flow_id);
fprintf(fd," flags : %x \n",m_flags);
}
-
-
-
-void CNatOption::dump(FILE *fd){
-
- fprintf(fd," op : %x \n",get_option_type());
- fprintf(fd," ol : %x \n",get_option_len());
- fprintf(fd," thread_id : %x \n",get_thread_id());
- fprintf(fd," magic : %x \n",get_magic());
- fprintf(fd," fid : %x \n",get_fid());
- utl_DumpBuffer(stdout,(void *)&u.m_data[0],8,0);
-}
-
diff --git a/src/rx_check_header.h b/src/rx_check_header.h
index 54af2451..95dc60ad 100755
--- a/src/rx_check_header.h
+++ b/src/rx_check_header.h
@@ -1,12 +1,10 @@
-#ifndef RX_CHECK_HEADER
-#define RX_CHECK_HEADER
/*
Hanoh Haim
Cisco Systems, Inc.
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 Cisco Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -21,15 +19,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+#ifndef RX_CHECK_HEADER
+#define RX_CHECK_HEADER
#include <stdint.h>
#include <stdio.h>
#include <common/bitMan.h>
#include <common/Network/Packet/CPktCmn.h>
-
-#include "os_time.h"
-
#define RX_CHECK_LEN (sizeof(struct CRx_check_header))
// IPv4 option type:
@@ -103,113 +100,6 @@ public:
void dump(FILE *fd);
};
-
-class CNatOption {
-public:
- enum {
- noIPV4_OPTION = 0x10, /* dummy IPV4 option */
- noOPTION_LEN = 0x8,
- noIPV4_MAGIC = 0xEE,
- noIPV4_MAGIC_RX = 0xED,
-
- noIPV6_OPTION_LEN = (noOPTION_LEN/8)-1,
- noIPV6_OPTION = 0x3C, /*IPv6-Opts Destination Options for IPv6 RFC 2460*/
- };
- void set_option_type(uint8_t id){
- u.m_data[0]=id;
- }
- uint8_t get_option_type(){
- return (u.m_data[0]);
- }
-
- void set_option_len(uint8_t len){
- u.m_data[1]=len;
- }
- uint8_t get_option_len(){
- return ( u.m_data[1]);
- }
-
- void set_thread_id(uint8_t thread_id){
- u.m_data[3]=thread_id;
- }
- uint8_t get_thread_id(){
- return (u.m_data[3]);
- }
-
- void set_magic(uint8_t magic){
- u.m_data[2]=magic;
- }
-
- uint8_t get_magic(){
- return (u.m_data[2]);
- }
-
- void set_rx_check(bool enable){
- if (enable) {
- set_magic(CNatOption::noIPV4_MAGIC_RX);
- }else{
- set_magic(CNatOption::noIPV4_MAGIC);
- }
- }
- bool is_rx_check(){
- if (get_magic() ==CNatOption::noIPV4_MAGIC_RX) {
- return(true);
- }else{
- return (false);
- }
- }
-
-
- void set_fid(uint32_t fid){
- u.m_data_uint32[1]=fid;
- }
- uint32_t get_fid(){
- return (u.m_data_uint32[1]);
- }
-
- bool is_valid_ipv4_magic_op0(void){
- return ( ( PKT_NTOHL( u.m_data_uint32[0] )& 0xFFFFFF00 ) ==
- (CNatOption::noIPV4_OPTION <<24) + (CNatOption::noOPTION_LEN<<16) + (CNatOption::noIPV4_MAGIC<<8) ?true:false);
- }
-
- bool is_valid_ipv4_magic_op1(void){
- return ( ( PKT_NTOHL( u.m_data_uint32[0] )& 0xFFFFFF00 ) ==
- (CNatOption::noIPV4_OPTION <<24) + (CNatOption::noOPTION_LEN<<16) + (CNatOption::noIPV4_MAGIC_RX<<8) ?true:false);
- }
-
- bool is_valid_ipv4_magic(void){
- return (is_valid_ipv4_magic_op0() ||is_valid_ipv4_magic_op1() );
- }
-
-
- bool is_valid_ipv6_magic(void){
- return ( ( PKT_NTOHL( u.m_data_uint32[0] )& 0x00FFFF00 ) ==
- (CNatOption::noIPV6_OPTION_LEN<<16) + (CNatOption::noIPV4_MAGIC<<8) ?true:false);
-
- }
-
- void set_init_ipv4_header(){
- set_option_type(CNatOption::noIPV4_OPTION);
- set_option_len(CNatOption::noOPTION_LEN);
- set_magic(CNatOption::noIPV4_MAGIC);
- }
-
- void set_init_ipv6_header(void){
- set_option_len(noIPV6_OPTION_LEN);
- set_magic(CNatOption::noIPV4_MAGIC);
- }
-
- void dump(FILE *fd);
-
-
-private:
- union u_ {
- uint8_t m_data[8];
- uint32_t m_data_uint32[2];
- } u;
-};
-
-
#endif