diff options
author | 2016-01-14 04:42:05 +0200 | |
---|---|---|
committer | 2016-01-19 04:13:53 +0200 | |
commit | 62623efc5b700d58335fa994d2e2725863527575 (patch) | |
tree | f3140936cd979c7d609bbe91c539f681ddd8e552 | |
parent | eee866f42bd0fc8472e6295b4f26bd0697e59f1f (diff) |
Adding option to pass NAT info in TCP ACK of first SYN
-rwxr-xr-x | scripts/automation/regression/unit_tests/trex_nat_test.py | 22 | ||||
-rw-r--r-- | scripts/exp/bad_not_ip.pcap | bin | 0 -> 226 bytes | |||
-rwxr-xr-x | scripts/exp/http1_with_option-ex.pcap | bin | 35049 -> 35049 bytes | |||
-rw-r--r-- | scripts/exp/http1_with_option.pcap | bin | 35049 -> 0 bytes | |||
-rwxr-xr-x | scripts/exp/http1_with_option_ipv6-ex.pcap | bin | 35713 -> 35713 bytes | |||
-rw-r--r-- | scripts/exp/http1_with_option_ipv6.pcap | bin | 35713 -> 0 bytes | |||
-rw-r--r-- | scripts/exp/many_ip_options.pcap | bin | 0 -> 204 bytes | |||
-rw-r--r-- | scripts/exp/tcp_no_syn.pcap | bin | 0 -> 184 bytes | |||
-rwxr-xr-x | src/bp_gtest.cpp | 34 | ||||
-rwxr-xr-x | src/bp_sim.cpp | 191 | ||||
-rwxr-xr-x | src/bp_sim.h | 134 | ||||
-rwxr-xr-x | src/common/Network/Packet/TcpHeader.h | 2 | ||||
-rw-r--r-- | src/debug.cpp | 11 | ||||
-rw-r--r-- | src/latency.cpp | 7 | ||||
-rw-r--r-- | src/latency.h | 21 | ||||
-rwxr-xr-x | src/main_dpdk.cpp | 33 | ||||
-rwxr-xr-x | src/nat_check.cpp | 77 | ||||
-rwxr-xr-x | src/nat_check.h | 122 | ||||
-rwxr-xr-x | src/rx_check.cpp | 7 | ||||
-rwxr-xr-x | src/rx_check_header.cpp | 21 | ||||
-rwxr-xr-x | src/rx_check_header.h | 116 |
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 Binary files differnew file mode 100644 index 00000000..01a4d4a6 --- /dev/null +++ b/scripts/exp/bad_not_ip.pcap diff --git a/scripts/exp/http1_with_option-ex.pcap b/scripts/exp/http1_with_option-ex.pcap Binary files differindex ef5bf3c4..6981ff1b 100755 --- a/scripts/exp/http1_with_option-ex.pcap +++ b/scripts/exp/http1_with_option-ex.pcap diff --git a/scripts/exp/http1_with_option.pcap b/scripts/exp/http1_with_option.pcap Binary files differdeleted file mode 100644 index ef5bf3c4..00000000 --- a/scripts/exp/http1_with_option.pcap +++ /dev/null diff --git a/scripts/exp/http1_with_option_ipv6-ex.pcap b/scripts/exp/http1_with_option_ipv6-ex.pcap Binary files differindex f70c1114..82a14a05 100755 --- a/scripts/exp/http1_with_option_ipv6-ex.pcap +++ b/scripts/exp/http1_with_option_ipv6-ex.pcap diff --git a/scripts/exp/http1_with_option_ipv6.pcap b/scripts/exp/http1_with_option_ipv6.pcap Binary files differdeleted file mode 100644 index f70c1114..00000000 --- a/scripts/exp/http1_with_option_ipv6.pcap +++ /dev/null diff --git a/scripts/exp/many_ip_options.pcap b/scripts/exp/many_ip_options.pcap Binary files differnew file mode 100644 index 00000000..8fddf6e4 --- /dev/null +++ b/scripts/exp/many_ip_options.pcap diff --git a/scripts/exp/tcp_no_syn.pcap b/scripts/exp/tcp_no_syn.pcap Binary files differnew file mode 100644 index 00000000..fe0615ad --- /dev/null +++ b/scripts/exp/tcp_no_syn.pcap 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 |