From d49f3784270f142825fa4bd4ae96730401a2b871 Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Mon, 20 Jun 2016 10:58:10 +0300 Subject: better support for latency with field engine + some order with mbuf functions --- linux/ws_main.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux') diff --git a/linux/ws_main.py b/linux/ws_main.py index 3aee05db..6dccf597 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -124,6 +124,7 @@ main_src = SrcGroup(dir='src', 'trex_watchdog.cpp', 'pal/linux/pal_utl.cpp', 'pal/linux/mbuf.cpp', + 'pal/common/common_mbuf.cpp', 'sim/trex_sim_stateless.cpp', 'sim/trex_sim_stateful.cpp' ]); @@ -254,6 +255,7 @@ cxxflags_base =['-DWIN_UCODE_SIM', includes_path =''' ../src/pal/linux/ + ../src/pal/common/ ../src/ ../src/rpc-server/ ../src/stateless/cp/ -- cgit 1.2.3-korg From f03fa158116cfd65659d14698c91446dc9bdb4c4 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 27 Jun 2016 17:15:05 +0300 Subject: draft #3 of client config --- linux/ws_main.py | 3 +- src/bp_sim.cpp | 139 ++++++++++++++---------------- src/bp_sim.h | 32 ++++--- src/mac_mapping.h | 4 +- src/main.cpp | 3 +- src/main_dpdk.cpp | 3 + src/sim/trex_sim_stateful.cpp | 6 ++ src/trex_client_config.cpp | 24 +++--- src/trex_client_config.h | 25 +++--- src/tuple_gen.cpp | 170 ++++++++++++++++++++----------------- src/tuple_gen.h | 190 +++++++++++++++++++----------------------- src/utl_yaml.cpp | 69 +++++++++++++-- src/utl_yaml.h | 20 +++-- 13 files changed, 380 insertions(+), 308 deletions(-) (limited to 'linux') diff --git a/linux/ws_main.py b/linux/ws_main.py index 6dccf597..0ee2fd3b 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -97,7 +97,7 @@ bp_sim_main = SrcGroup(dir='src', bp_sim_gtest = SrcGroup(dir='src', src_list=[ 'bp_gtest.cpp', - 'gtest/tuple_gen_test.cpp', + #'gtest/tuple_gen_test.cpp', 'gtest/nat_test.cpp', 'gtest/trex_stateless_gtest.cpp' ]) @@ -122,6 +122,7 @@ main_src = SrcGroup(dir='src', 'flow_stat.cpp', 'flow_stat_parser.cpp', 'trex_watchdog.cpp', + 'trex_client_config.cpp', 'pal/linux/pal_utl.cpp', 'pal/linux/mbuf.cpp', 'pal/common/common_mbuf.cpp', diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index db90107d..abedf95c 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -2449,26 +2449,6 @@ void CCapFileFlowInfo::Delete(){ RemoveAll(); } -void operator >> (const YAML::Node& node, mac_mapping_t &fi) { - utl_yaml_read_ip_addr(node,"ip", fi.ip); - const YAML::Node& mac_info = node["mac"]; - for(unsigned i=0;i> value; - fi.mac.mac[i] = value; - } -} - -void operator >> (const YAML::Node& node, std::map &mac_info) { - const YAML::Node& mac_node = node["items"]; - mac_mapping_t mac_mapping; - for (unsigned i=0;i> mac_mapping; - mac_info[mac_mapping.ip] = mac_mapping.mac; - } -} - void operator >> (const YAML::Node& node, CFlowYamlDpPkt & fi) { uint32_t val; node["pkt_id"] >> val; @@ -3348,7 +3328,7 @@ bool CFlowGenListPerThread::Create(uint32_t thread_id, /* split the clients to threads */ CTupleGenYamlInfo * tuple_gen = &m_flow_list->m_yaml_info.m_tuple_gen; - m_smart_gen.Create(0,m_thread_id,m_flow_list->get_is_mac_conf()); + m_smart_gen.Create(0,m_thread_id); /* split the clients to threads using the mask */ CIpPortion portion; @@ -3358,14 +3338,14 @@ bool CFlowGenListPerThread::Create(uint32_t thread_id, portion); m_smart_gen.add_client_pool(tuple_gen->m_client_pool[i].m_dist, - portion.m_ip_start, - portion.m_ip_end, - get_longest_flow(i,true), - get_total_kcps(i,true)*1000, - &m_flow_list->m_mac_info, - tuple_gen->m_client_pool[i].m_tcp_aging_sec, - tuple_gen->m_client_pool[i].m_udp_aging_sec - ); + portion.m_ip_start, + portion.m_ip_end, + get_longest_flow(i,true), + get_total_kcps(i,true)*1000, + m_flow_list->m_client_config_info, + tuple_gen->m_client_pool[i].m_tcp_aging_sec, + tuple_gen->m_client_pool[i].m_udp_aging_sec + ); } for (int i=0;im_server_pool.size();i++) { split_ips(m_thread_id, m_max_threads, getDualPortId(), @@ -4419,32 +4399,16 @@ void CFlowGenList::clean_p_thread_info(void){ m_threads_info.clear(); } - - -int CFlowGenList::load_from_mac_file(std::string file_name) { - if ( !utl_is_file_exists (file_name) ){ - printf(" ERROR no mac_file is set, file %s does not exist \n",file_name.c_str()); - exit(-1); - } - m_mac_info.set_configured(true); - - try { - std::ifstream fin((char *)file_name.c_str()); - YAML::Parser parser(fin); - YAML::Node doc; - - parser.GetNextDocument(doc); - doc[0] >> m_mac_info.get_mac_info(); - } catch ( const std::exception& e ) { - std::cout << e.what() << "\n"; - m_mac_info.clear(); - exit(-1); - } - - return (0); +int CFlowGenList::load_client_config_file(std::string file_name) { + try { + m_client_config_info.load_yaml_file(file_name); + } catch (const std::exception& e) { + std::cout << e.what() << "\n"; + exit(-1); + } + return (0); } - int CFlowGenList::load_from_yaml(std::string file_name, uint32_t num_threads){ uint8_t idx; @@ -4756,7 +4720,7 @@ bool CParserOption::is_valid_opt_val(int val, int min, int max, const std::strin void CParserOption::dump(FILE *fd){ preview.Dump(fd); fprintf(fd," cfg file : %s \n",cfg_file.c_str()); - fprintf(fd," mac file : %s \n",mac_file.c_str()); + fprintf(fd," mac file : %s \n",client_cfg_file.c_str()); fprintf(fd," out file : %s \n",out_file.c_str()); fprintf(fd," duration : %.0f \n",m_duration); fprintf(fd," factor : %.0f \n",m_factor); @@ -5068,37 +5032,62 @@ int CErfIFStl::send_node(CGenNode * _no_to_use){ return (0); } +void CErfIF::add_vlan(uint16_t vlan_id) { + uint8_t *buffer =(uint8_t *)m_raw->raw; + uint16_t vlan_protocol = EthernetHeader::Protocol::VLAN; + uint32_t vlan_tag = (vlan_protocol << 16) | vlan_id; + vlan_tag = PKT_HTONL(vlan_tag); -int CErfIF::send_node(CGenNode * node){ + /* insert vlan tag and adjust packet size */ + memcpy(cbuff+4, buffer + 12, m_raw->pkt_len - 12); + memcpy(cbuff, &vlan_tag, 4); + memcpy(buffer + 12, cbuff, m_raw->pkt_len-8); - if ( m_preview_mode->getFileWrite() ){ + m_raw->pkt_len += 4; +} - CFlowPktInfo * lp=node->m_pkt_info; - rte_mbuf_t * m=lp->generate_new_mbuf(node); - pkt_dir_t dir=node->cur_interface_dir(); +void CErfIF::apply_client_config(CGenNode *node, pkt_dir_t dir) { + uint8_t *p =(uint8_t *)m_raw->raw; + uint16_t vlan_id; + + if (dir == CLIENT_SIDE) { + memcpy(p, node->m_client_cfg->m_init_mac, 6); + vlan_id = node->m_client_cfg->m_init_vlan; + } else { + memcpy(p, node->m_client_cfg->m_res_mac, 6); + vlan_id = node->m_client_cfg->m_res_vlan; + } + + add_vlan(vlan_id); + +} + +int CErfIF::send_node(CGenNode *node){ + + if (!m_preview_mode->getFileWrite()) { + return (0); + } - fill_raw_packet(m,node,dir); + CFlowPktInfo *lp = node->m_pkt_info; + rte_mbuf_t *m = lp->generate_new_mbuf(node); + pkt_dir_t dir = node->cur_interface_dir(); + + fill_raw_packet(m, node, dir); /* update mac addr dest/src 12 bytes */ uint8_t *p=(uint8_t *)m_raw->raw; int p_id=(int)dir; memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12); - /* If vlan is enabled, add vlan header */ - if ( unlikely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){ - /* retrieve vlan ID and form vlan tag */ - uint8_t vlan_port = (node->m_src_ip &1); - uint16_t vlan_protocol = EthernetHeader::Protocol::VLAN; - uint16_t vlan_id = CGlobalInfo::m_options.m_vlan_port[vlan_port]; - uint32_t vlan_tag = (vlan_protocol << 16) | vlan_id; - vlan_tag = PKT_HTONL(vlan_tag); + /* if a client configuration was provided - apply the config */ + if (node->m_client_cfg) { + apply_client_config(node, dir); - /* insert vlan tag and adjust packet size */ - memcpy(cbuff+4, p+12, m_raw->pkt_len-12); - memcpy(cbuff, &vlan_tag, 4); - memcpy(p+12, cbuff, m_raw->pkt_len-8); - m_raw->pkt_len += 4; + } else if (CGlobalInfo::m_options.preview.get_vlan_mode_enable()) { + uint8_t vlan_port = (node->m_src_ip & 1); + uint16_t vlan_id = CGlobalInfo::m_options.m_vlan_port[vlan_port]; + add_vlan(vlan_id); } //utl_DumpBuffer(stdout,p, 12,0); @@ -5107,8 +5096,8 @@ int CErfIF::send_node(CGenNode * node){ BP_ASSERT(rc == 0); rte_pktmbuf_free(m); - } - return (0); + + return (0); } int CErfIF::flush_tx_queue(void){ diff --git a/src/bp_sim.h b/src/bp_sim.h index e396a710..37263cb5 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -59,6 +59,7 @@ limitations under the License. #include "platform_cfg.h" #include "flow_stat.h" #include "trex_watchdog.h" +#include "trex_client_config.h" #include @@ -182,6 +183,12 @@ inline int ip_to_str(uint32_t ip,char * str){ return(strlen(str)); } +inline std::string ip_to_str(uint32_t ip) { + char tmp[INET_ADDRSTRLEN]; + ip_to_str(ip, tmp); + return tmp; +} + // Routine to create IPv6 address string inline int ipv6_to_str(ipaddr_t *ip,char * str){ int idx=0; @@ -817,7 +824,7 @@ public: std::string cfg_file; - std::string mac_file; + std::string client_cfg_file; std::string platform_cfg_file; std::string out_file; @@ -1565,7 +1572,7 @@ public: uint16_t m_nat_external_port; uint16_t m_nat_pad[3]; - mac_addr_align_t m_src_mac; + ClientCfg *m_client_cfg; uint32_t m_src_idx; uint32_t m_dest_idx; uint32_t m_end_of_cache_line[6]; @@ -1911,7 +1918,8 @@ public: protected: - + void add_vlan(uint16_t vlan_id); + void apply_client_config(CGenNode *node, pkt_dir_t dir); virtual void fill_raw_packet(rte_mbuf_t * m,CGenNode * node,pkt_dir_t dir); CFileWriterBase * m_writer; @@ -3874,7 +3882,8 @@ public: public: int load_from_yaml(std::string csv_file,uint32_t num_threads); - int load_from_mac_file(std::string csv_file); + int load_client_config_file(std::string file_name); + public: void Dump(FILE *fd); void DumpCsv(FILE *fd); @@ -3888,12 +3897,12 @@ public: double get_total_tx_bps(); uint32_t get_total_repeat_flows(); double get_delta_flow_is_sec(); - bool get_is_mac_conf() { return m_mac_info.is_configured();} + public: - std::vector m_cap_gen; /* global info */ - CFlowsYamlInfo m_yaml_info; /* global yaml*/ - std::vector m_threads_info; - CFlowGenListMac m_mac_info; + std::vector m_cap_gen; /* global info */ + CFlowsYamlInfo m_yaml_info; /* global yaml*/ + std::vector m_threads_info; + ClientCfgDB m_client_config_info; }; @@ -3933,9 +3942,8 @@ inline void CCapFileFlowInfo::generate_flow(CTupleTemplateGeneratorSmart * tup node->m_src_idx = tuple.getClientId(); node->m_dest_idx = tuple.getServerId(); node->m_src_port = tuple.getClientPort(); - memcpy(&node->m_src_mac, - tuple.getClientMac(), - sizeof(mac_addr_align_t)); + node->m_client_cfg = tuple.getClientCfg(); + node->m_plugin_info =(void *)0; if ( unlikely( CGlobalInfo::is_learn_mode() ) ){ diff --git a/src/mac_mapping.h b/src/mac_mapping.h index 84151e8c..ed9c5d88 100644 --- a/src/mac_mapping.h +++ b/src/mac_mapping.h @@ -1,6 +1,6 @@ #ifndef MAC_MAPPING_H_ #define MAC_MAPPING_H_ - +#if 0 #define INUSED 0 #define UNUSED 1 typedef struct mac_addr_align_ { @@ -57,4 +57,6 @@ private: std::map m_mac_info; /* global mac info loaded form mac_file*/ }; +/*********************************************************************************/ +#endif #endif //MAC_MAPPING_H_ diff --git a/src/main.cpp b/src/main.cpp index 62eee880..90e48549 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,6 +22,7 @@ limitations under the License. #include "bp_sim.h" #include "os_time.h" +#include "trex_client_config.h" #include #include @@ -160,7 +161,7 @@ static int parse_options(int argc, break; case OPT_MAC_FILE: - po->mac_file = args.OptionArg(); + po->client_cfg_file = args.OptionArg(); break; case OPT_FILE_OUT: diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 941612b1..ad9858a2 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -2022,9 +2022,12 @@ void CCoreEthIF::update_mac_addr(CGenNode * node,uint8_t *p){ if ( unlikely( CGlobalInfo::m_options.preview.get_mac_ip_mapping_enable() ) ) { /* mac mapping file is configured */ + #if 0 if ( node->is_initiator_pkt() && (node->m_src_mac.inused==INUSED)) { memcpy(p+6, &node->m_src_mac.mac, 6); } + #endif + } else if ( unlikely( CGlobalInfo::m_options.preview.get_mac_ip_overide_enable() ) ){ /* client side */ if ( node->is_initiator_pkt() ){ diff --git a/src/sim/trex_sim_stateful.cpp b/src/sim/trex_sim_stateful.cpp index 88698cd1..93eda2fe 100644 --- a/src/sim/trex_sim_stateful.cpp +++ b/src/sim/trex_sim_stateful.cpp @@ -165,6 +165,12 @@ int load_list_of_cap_files(CParserOption * op){ CFlowGenList fl; fl.Create(); fl.load_from_yaml(op->cfg_file,1); + + if (op->client_cfg_file != "") { + fl.load_client_config_file(op->client_cfg_file); + CGlobalInfo::m_options.preview.set_mac_ip_mapping_enable(true); + } + if ( op->preview.getVMode() >0 ) { fl.DumpCsv(stdout); } diff --git a/src/trex_client_config.cpp b/src/trex_client_config.cpp index f9ad0e6c..9a5e4f6f 100644 --- a/src/trex_client_config.cpp +++ b/src/trex_client_config.cpp @@ -31,7 +31,7 @@ limitations under the License. #include "bp_sim.h" void -ClientGroup::dump() const { +ClientCfgEntry::dump() const { std::cout << "IP start: " << ip_to_str(m_ip_start) << "\n"; std::cout << "IP end: " << ip_to_str(m_ip_end) << "\n"; @@ -60,7 +60,7 @@ ClientGroup::dump() const { * */ void -ClientGroupsDB::load_yaml_file(const std::string &filename) { +ClientCfgDB::load_yaml_file(const std::string &filename) { std::stringstream ss; m_filename = filename; @@ -78,7 +78,7 @@ ClientGroupsDB::load_yaml_file(const std::string &filename) { for (int i = 0; i < root.size(); i++) { const YAML::Mark &mark = root[i].GetMark(); - ClientGroup group; + ClientCfgEntry group; bool rc; /* ip_start */ @@ -127,14 +127,14 @@ ClientGroupsDB::load_yaml_file(const std::string &filename) { } void -ClientGroupsDB::verify() const { +ClientCfgDB::verify() const { std::stringstream ss; uint32_t monotonic = 0; /* check that no interval overlaps */ for (const auto &p : m_groups) { - const ClientGroup &group = p.second; + const ClientCfgEntry &group = p.second; if ( (monotonic > 0 ) && (group.m_ip_start <= monotonic) ) { ss << "IP '" << ip_to_str(group.m_ip_start) << "' - '" << ip_to_str(group.m_ip_end) << "' overlaps with other groups"; @@ -150,15 +150,15 @@ ClientGroupsDB::verify() const { * should be fast * */ -ClientGroup * -ClientGroupsDB::lookup(uint32_t ip) { +ClientCfgEntry * +ClientCfgDB::lookup(uint32_t ip) { /* check the cache */ if ( (m_cache_group) && (m_cache_group->contains(ip)) ) { return m_cache_group; } - std::map::iterator it; + std::map::iterator it; it = m_groups.upper_bound(ip); @@ -170,7 +170,7 @@ ClientGroupsDB::lookup(uint32_t ip) { /* go one back - we know it's not on begin so we have at least one back */ it--; - ClientGroup &group = (*it).second; + ClientCfgEntry &group = (*it).second; /* because this is a non overlapping intervals if IP exists it must be in this group @@ -188,8 +188,8 @@ ClientGroupsDB::lookup(uint32_t ip) { } -ClientGroup * -ClientGroupsDB::lookup(const std::string &ip) { +ClientCfgEntry * +ClientCfgDB::lookup(const std::string &ip) { uint32_t addr = (uint32_t)inet_addr(ip.c_str()); addr = PKT_NTOHL(addr); @@ -198,7 +198,7 @@ ClientGroupsDB::lookup(const std::string &ip) { void -ClientGroupsDB::yaml_parse_err(const std::string &err, const YAML::Mark *mark) const { +ClientCfgDB::yaml_parse_err(const std::string &err, const YAML::Mark *mark) const { std::stringstream ss; if (mark) { diff --git a/src/trex_client_config.h b/src/trex_client_config.h index 442d228b..f934517d 100644 --- a/src/trex_client_config.h +++ b/src/trex_client_config.h @@ -41,13 +41,14 @@ public: }; /** - * describes a single client group - * configuration + * describes a single client config + * entry loaded from the config file + * */ -class ClientGroup { +class ClientCfgEntry { public: - ClientGroup() { + ClientCfgEntry() { reset(); } @@ -104,10 +105,10 @@ private: * describes the DB of every client group * */ -class ClientGroupsDB { +class ClientCfgDB { public: - ClientGroupsDB() { + ClientCfgDB() { m_is_empty = true; m_cache_group = NULL; } @@ -134,8 +135,8 @@ public: * a group that contains this IP * */ - ClientGroup * lookup(uint32_t ip); - ClientGroup * lookup(const std::string &ip); + ClientCfgEntry * lookup(uint32_t ip); + ClientCfgEntry * lookup(const std::string &ip); private: @@ -148,10 +149,10 @@ private: void verify() const; /* maps the IP start value to client groups */ - std::map m_groups; - ClientGroup *m_cache_group; - std::string m_filename; - bool m_is_empty; + std::map m_groups; + ClientCfgEntry *m_cache_group; + std::string m_filename; + bool m_is_empty; }; #endif /* __TREX_CLIENT_CONFIG_H__ */ diff --git a/src/tuple_gen.cpp b/src/tuple_gen.cpp index d221a4d9..c964955a 100755 --- a/src/tuple_gen.cpp +++ b/src/tuple_gen.cpp @@ -25,6 +25,7 @@ limitations under the License. #include "tuple_gen.h" #include #include "utl_yaml.h" +#include "bp_sim.h" void CServerPool::Create(IP_DIST_t dist_value, uint32_t min_ip, @@ -52,81 +53,95 @@ void CServerPool::Create(IP_DIST_t dist_value, -void CClientPool::Create(IP_DIST_t dist_value, - uint32_t min_ip, - uint32_t max_ip, - double l_flow, - double t_cps, - CFlowGenListMac* mac_info, - bool has_mac_map, - uint16_t tcp_aging, - uint16_t udp_aging) { - assert(max_ip>=min_ip); +void CClientPool::Create(IP_DIST_t dist_value, + uint32_t min_ip, + uint32_t max_ip, + double l_flow, + double t_cps, + ClientCfgDB &client_info, + uint16_t tcp_aging, + uint16_t udp_aging) { + + assert(max_ip >= min_ip); + set_dist(dist_value); - uint32_t total_ip = max_ip - min_ip +1; - uint32_t avail_ip = total_ip; - if (has_mac_map && (mac_info!=NULL)) { - for(int idx=0;idxget_mac_addr_by_ip(min_ip+idx); - if (mac_adr == NULL) { - avail_ip--; - } - } - } - if (avail_ip!=0) { - m_ip_info.resize(avail_ip); + + uint32_t total_ip = max_ip - min_ip +1; + bool is_long_range = total_ip > (l_flow * t_cps / MAX_PORT); + + m_ip_info.resize(total_ip); + + /* if client info is empty - flat allocation o.w use configured clients */ + if (client_info.is_empty()) { + allocate_simple_clients(min_ip, total_ip, is_long_range); } else { - printf("\n Error, invalid mac file is configured.\n"); - assert(0); + allocate_configured_clients(min_ip, total_ip, is_long_range, client_info); } - int skip_cnt=0; - if (total_ip > ((l_flow*t_cps/MAX_PORT))) { - if (has_mac_map) { - skip_cnt=0; - for(int idx=0;idxget_mac_addr_by_ip( min_ip+idx); - if (mac_adr != NULL) { - m_ip_info[idx-skip_cnt] = new CClientInfoL(has_mac_map); - m_ip_info[idx-skip_cnt]->set_ip(min_ip+idx); - m_ip_info[idx-skip_cnt]->set_mac(mac_adr); - } else { - skip_cnt++; - } - } + m_tcp_aging = tcp_aging; + m_udp_aging = udp_aging; + + CreateBase(); +} + +/** + * simple allocation of a client - no configuration was provided + * + * @author imarom (27-Jun-16) + * + * @param ip + * @param index + * @param is_long_range + */ +void CClientPool::allocate_simple_clients(uint32_t min_ip, + uint32_t total_ip, + bool is_long_range) { + + /* simple creation of clients - no extended info */ + for (uint32_t i = 0; i < total_ip; i++) { + uint32_t ip = min_ip + i; + if (is_long_range) { + m_ip_info[i] = new CSimpleClientInfo(ip); } else { - for(int idx=0;idxset_ip(min_ip+idx); - } - } - } else { - if (has_mac_map) { - skip_cnt=0; - for(int idx=0;idxget_mac_addr_by_ip(min_ip+idx); - if (mac_adr != NULL) { - m_ip_info[idx-skip_cnt] = new CClientInfo(has_mac_map); - m_ip_info[idx-skip_cnt]->set_ip(min_ip+idx); - m_ip_info[idx-skip_cnt]->set_mac(mac_adr); - } else { - skip_cnt++; - } - } + m_ip_info[i] = new CSimpleClientInfo(ip); + } + } + +} + +/** + * simple allocation of a client - no configuration was provided + * + * @author imarom (27-Jun-16) + * + * @param ip + * @param index + * @param is_long_range + */ +void CClientPool::allocate_configured_clients(uint32_t min_ip, + uint32_t total_ip, + bool is_long_range, + ClientCfgDB &client_info) { + + for (uint32_t i = 0; i < total_ip; i++) { + uint32_t ip = min_ip + i; + + /* lookup for the right group of clients */ + ClientCfgEntry *group = client_info.lookup(ip); + if (!group) { + std::cout << "could not map " << ip_to_str(ip) << "\n"; + exit(-1); + } + + ClientCfg info; + group->assign(info); + + if (is_long_range) { + m_ip_info[i] = new CConfiguredClientInfo(ip, info); } else { - for(int idx=0;idxset_ip(min_ip+idx); - } - } - + m_ip_info[i] = new CConfiguredClientInfo(ip, info); + } } - m_tcp_aging = tcp_aging; - m_udp_aging = udp_aging; - CreateBase(); } @@ -135,14 +150,19 @@ bool CTupleGeneratorSmart::add_client_pool(IP_DIST_t client_dist, uint32_t max_client, double l_flow, double t_cps, - CFlowGenListMac* mac_info, + ClientCfgDB &client_info, uint16_t tcp_aging, uint16_t udp_aging){ assert(max_client>=min_client); CClientPool* pool = new CClientPool(); - pool->Create(client_dist, min_client, max_client, - l_flow, t_cps, mac_info, m_has_mac_mapping, - tcp_aging, udp_aging); + pool->Create(client_dist, + min_client, + max_client, + l_flow, + t_cps, + client_info, + tcp_aging, + udp_aging); m_client_pool.push_back(pool); return(true); @@ -170,19 +190,17 @@ bool CTupleGeneratorSmart::add_server_pool(IP_DIST_t server_dist, bool CTupleGeneratorSmart::Create(uint32_t _id, - uint32_t thread_id, - bool has_mac) + uint32_t thread_id) + { m_thread_id = thread_id; m_id = _id; m_was_init=true; - m_has_mac_mapping = has_mac; return(true); } void CTupleGeneratorSmart::Delete(){ m_was_init=false; - m_has_mac_mapping = false; for (int idx=0;idxDelete(); diff --git a/src/tuple_gen.h b/src/tuple_gen.h index b2f6e34a..292d1794 100755 --- a/src/tuple_gen.h +++ b/src/tuple_gen.h @@ -38,14 +38,17 @@ limitations under the License. #include #include #include +#include "trex_client_config.h" #include class CTupleBase { public: + CTupleBase() { - m_client_mac.inused = UNUSED; + m_client_cfg = NULL; } + uint32_t getClient() { return m_client_ip; } @@ -83,22 +86,20 @@ public: void setClientPort(uint16_t port) { m_client_port = port; } - mac_addr_align_t* getClientMac() { - return &m_client_mac; + void setClientCfg(ClientCfg *cfg) { + m_client_cfg = cfg; } - void setClientMac(mac_addr_align_t* mac_info) { - if (mac_info != NULL) { - memcpy(&m_client_mac, mac_info, sizeof(mac_addr_align_t)); - m_client_mac.inused = INUSED; - } else { - m_client_mac.inused = UNUSED; - } + ClientCfg *getClientCfg() { + return m_client_cfg; } - void setClientTuple(uint32_t ip,mac_addr_align_t*mac,uint16_t port) { + + + void setClientTuple(uint32_t ip, ClientCfg *cfg, uint16_t port) { setClient(ip); - setClientMac(mac); setClientPort(port); + setClientCfg(cfg); } + void setClientAll2(uint32_t id, uint32_t ip,uint16_t port) { setClientId(id); setClient(ip); @@ -121,9 +122,12 @@ public: private: uint32_t m_client_ip; uint32_t m_client_idx; + uint32_t m_server_ip; uint32_t m_server_idx; - mac_addr_align_t m_client_mac; + + ClientCfg *m_client_cfg; + uint16_t m_client_port; uint16_t m_server_port; }; @@ -171,8 +175,6 @@ typedef enum { class CIpInfoBase { public: - virtual mac_addr_align_t* get_mac() { return NULL;} - virtual void set_mac(mac_addr_align_t*){;} virtual uint16_t get_new_free_port() = 0; virtual void return_port(uint16_t a) = 0; virtual void generate_tuple(CTupleBase & tuple) = 0; @@ -303,76 +305,54 @@ class CIpInfo : public CIpInfoBase { } }; -class CClientInfo : public CIpInfo { + +/** + * a flat client info (no configuration) + * + * using template to avoid duplicating the code for CIpInfo and + * CIpInfoL + * + * @author imarom (27-Jun-16) + */ +template +class CSimpleClientInfo : public T { + public: - CClientInfo (bool has_mac) { - if (has_mac==true) { - m_mac = new mac_addr_align_t(); - } else { - m_mac = NULL; - } - } - CClientInfo () { - m_mac = NULL; - } + CSimpleClientInfo(uint32_t ip) { + T::set_ip(ip); + } - mac_addr_align_t* get_mac() { - return m_mac; - } - void set_mac(mac_addr_align_t *mac) { - memcpy(m_mac, mac, sizeof(mac_addr_align_t)); + void generate_tuple(CTupleBase &tuple) { + tuple.setClientTuple(T::m_ip, + NULL, + T::get_new_free_port()); } - ~CClientInfo() { - if (m_mac!=NULL){ - delete m_mac; - m_mac=NULL; - } - } - - void generate_tuple(CTupleBase & tuple) { - tuple.setClientTuple(m_ip, m_mac, - get_new_free_port()); - } -private: - mac_addr_align_t *m_mac; }; -class CClientInfoL : public CIpInfoL { -public: - CClientInfoL (bool has_mac) { - if (has_mac==true) { - m_mac = new mac_addr_align_t(); - } else { - m_mac = NULL; - } - } - CClientInfoL () { - m_mac = NULL; - } +/** + * a configured client object + * + * @author imarom (26-Jun-16) + */ +template +class CConfiguredClientInfo : public T { - mac_addr_align_t* get_mac() { - return m_mac; +public: + CConfiguredClientInfo(uint32_t ip, const ClientCfg &cfg) : m_cfg(cfg) { + T::set_ip(ip); } - void set_mac(mac_addr_align_t *mac) { - memcpy(m_mac, mac, sizeof(mac_addr_align_t)); + void generate_tuple(CTupleBase &tuple) { + tuple.setClientTuple(T::m_ip, + &m_cfg, + T::get_new_free_port()); } - ~CClientInfoL() { - if (m_mac!=NULL){ - delete m_mac; - m_mac=NULL; - } - } - - void generate_tuple(CTupleBase & tuple) { - tuple.setClientTuple(m_ip, m_mac, - get_new_free_port()); - } private: - mac_addr_align_t *m_mac; + ClientCfg m_cfg; }; + class CServerInfo : public CIpInfo { void generate_tuple(CTupleBase & tuple) { tuple.setServer(m_ip); @@ -475,12 +455,6 @@ class CIpPool { client->return_port(port); } - mac_addr_align_t * get_curr_mac() { - return m_ip_info[m_cur_idx]->get_mac(); - } - mac_addr_align_t *get_mac(uint32_t idx) { - return m_ip_info[idx]->get_mac(); - } public: std::vector m_ip_info; @@ -536,19 +510,30 @@ public: uint16_t get_udp_aging() { return m_udp_aging; } - void Create(IP_DIST_t dist_value, - uint32_t min_ip, - uint32_t max_ip, - double l_flow, - double t_cps, - CFlowGenListMac* mac_info, - bool has_mac_map, - uint16_t tcp_aging, - uint16_t udp_aging); + + void Create(IP_DIST_t dist_value, + uint32_t min_ip, + uint32_t max_ip, + double l_flow, + double t_cps, + ClientCfgDB &client_info, + uint16_t tcp_aging, + uint16_t udp_aging); public: uint16_t m_tcp_aging; uint16_t m_udp_aging; + +private: + void allocate_simple_clients(uint32_t min_ip, + uint32_t total_ip, + bool is_long_range); + + void allocate_configured_clients(uint32_t min_ip, + uint32_t total_ip, + bool is_long_range, + ClientCfgDB &client_info); + }; class CServerPoolBase { @@ -687,8 +672,7 @@ public: m_was_init=false; m_has_mac_mapping = false; } - bool Create(uint32_t _id, - uint32_t thread_id, bool has_mac=false); + bool Create(uint32_t _id, uint32_t thread_id); void Delete(); @@ -704,20 +688,22 @@ public: return (total_alloc_error); } - bool add_client_pool(IP_DIST_t client_dist, - uint32_t min_client, - uint32_t max_client, - double l_flow, - double t_cps, - CFlowGenListMac* mac_info, - uint16_t tcp_aging, - uint16_t udp_aging); + bool add_client_pool(IP_DIST_t client_dist, + uint32_t min_client, + uint32_t max_client, + double l_flow, + double t_cps, + ClientCfgDB &client_info, + uint16_t tcp_aging, + uint16_t udp_aging); + bool add_server_pool(IP_DIST_t server_dist, - uint32_t min_server, - uint32_t max_server, - double l_flow, - double t_cps, - bool is_bundling); + uint32_t min_server, + uint32_t max_server, + double l_flow, + double t_cps, + bool is_bundling); + CClientPool* get_client_pool(uint8_t idx) { return m_client_pool[idx]; } diff --git a/src/utl_yaml.cpp b/src/utl_yaml.cpp index 828817e4..bf30d661 100755 --- a/src/utl_yaml.cpp +++ b/src/utl_yaml.cpp @@ -21,7 +21,7 @@ See the License for the specific language governing permissions and limitations under the License. */ - +#include #define INADDRSZ 4 @@ -65,8 +65,8 @@ static int my_inet_pton4(const char *src, unsigned char *dst) bool utl_yaml_read_ip_addr(const YAML::Node& node, - std::string name, - uint32_t & val){ + const std::string &name, + uint32_t & val){ std::string tmp; uint32_t ip; bool res=false; @@ -83,8 +83,61 @@ bool utl_yaml_read_ip_addr(const YAML::Node& node, return (res); } +static void +split_str_by_delimiter(std::string str, char delim, std::vector &tokens) { + size_t pos = 0; + std::string token; + + while ((pos = str.find(delim)) != std::string::npos) { + token = str.substr(0, pos); + tokens.push_back(token); + str.erase(0, pos + 1); + } + + if (str.size() > 0) { + tokens.push_back(str); + } +} + +bool utl_yaml_read_mac_addr(const YAML::Node &node, + const std::string &name, + uint64_t &val) { + + std::string mac_str; + + if (!node.FindValue(name)) { + return false; + } + + node[name] >> mac_str; + + std::vector tokens; + split_str_by_delimiter(mac_str, ':', tokens); + + if (tokens.size() != 6) { + throw YAML::InvalidScalar(node[name].GetMark()); + } + + val = 0; + + for (int i = 0; i < 6 ; i++) { + char *endptr = NULL; + unsigned long octet = strtoul(tokens[i].c_str(), &endptr, 16); + + if ( (*endptr != 0) || (octet > 0xff) ) { + throw YAML::InvalidScalar(node[name].GetMark()); + } + + //mac_addr[i] = (uint8_t)octet; + val = (val << 8) + octet; + } + + return true; +} + + bool utl_yaml_read_uint32(const YAML::Node& node, - std::string name, + const std::string &name, uint32_t & val){ bool res=false; if ( node.FindValue(name) ) { @@ -95,8 +148,8 @@ bool utl_yaml_read_uint32(const YAML::Node& node, } bool utl_yaml_read_uint16(const YAML::Node& node, - std::string name, - uint16_t & val){ + const std::string &name, + uint16_t & val){ uint32_t val_tmp; bool res=false; if ( node.FindValue(name) ) { @@ -109,8 +162,8 @@ bool utl_yaml_read_uint16(const YAML::Node& node, } bool utl_yaml_read_bool(const YAML::Node& node, - std::string name, - bool & val){ + const std::string &name, + bool & val){ bool res=false; if ( node.FindValue(name) ) { node[name] >> val ; diff --git a/src/utl_yaml.h b/src/utl_yaml.h index 71655488..1ada1d66 100755 --- a/src/utl_yaml.h +++ b/src/utl_yaml.h @@ -27,19 +27,23 @@ limitations under the License. bool utl_yaml_read_ip_addr(const YAML::Node& node, - std::string name, - uint32_t & val - ); + const std::string &name, + uint32_t & val); + +bool utl_yaml_read_mac_addr(const YAML::Node &node, + const std::string &name, + uint64_t &val); bool utl_yaml_read_uint32(const YAML::Node& node, - std::string name, - uint32_t & val); + const std::string &name, + uint32_t & val); + bool utl_yaml_read_uint16(const YAML::Node& node, - std::string name, - uint16_t & val); + const std::string &name, + uint16_t & val); bool utl_yaml_read_bool(const YAML::Node& node, - std::string name, + const std::string &name, bool & val); -- cgit 1.2.3-korg From c6c4a4307a8a0ae17d3e26c9dc98b874dd5ee60b Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 3 Jul 2016 10:55:49 +0300 Subject: client config - cosmetics and gtest back on --- linux/ws_main.py | 2 +- src/bp_sim.cpp | 7 +--- src/gtest/tuple_gen_test.cpp | 75 +++++++++++++++++-------------------------- src/main_dpdk.cpp | 8 ++++- src/sim/trex_sim_stateful.cpp | 14 ++++++-- src/trex_client_config.cpp | 9 ++---- src/trex_client_config.h | 1 - src/tuple_gen.cpp | 2 +- src/utl_yaml.cpp | 4 +-- 9 files changed, 56 insertions(+), 66 deletions(-) (limited to 'linux') diff --git a/linux/ws_main.py b/linux/ws_main.py index 0ee2fd3b..2219522a 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -97,7 +97,7 @@ bp_sim_main = SrcGroup(dir='src', bp_sim_gtest = SrcGroup(dir='src', src_list=[ 'bp_gtest.cpp', - #'gtest/tuple_gen_test.cpp', + 'gtest/tuple_gen_test.cpp', 'gtest/nat_test.cpp', 'gtest/trex_stateless_gtest.cpp' ]) diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index ba8caf32..758778d9 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -4399,12 +4399,7 @@ void CFlowGenList::clean_p_thread_info(void){ } int CFlowGenList::load_client_config_file(std::string file_name) { - try { - m_client_config_info.load_yaml_file(file_name); - } catch (const std::exception& e) { - std::cout << e.what() << "\n"; - exit(-1); - } + m_client_config_info.load_yaml_file(file_name); return (0); } diff --git a/src/gtest/tuple_gen_test.cpp b/src/gtest/tuple_gen_test.cpp index f3b9fa1e..fa760c6d 100755 --- a/src/gtest/tuple_gen_test.cpp +++ b/src/gtest/tuple_gen_test.cpp @@ -25,6 +25,22 @@ limitations under the License. /* TEST case for CClientInfo*/ +class CClientInfo : public CSimpleClientInfo { +public: + CClientInfo() : CSimpleClientInfo(0) { + + } +}; + +class CClientInfoL : public CSimpleClientInfo { +public: + CClientInfoL() : CSimpleClientInfo(0) { + + } +}; + +static ClientCfgDB g_dummy; + class CClientInfoUT { public: CClientInfoUT(CClientInfo *a) { @@ -157,7 +173,7 @@ TEST(CClientInfoLTest, get_new_free_port) { TEST(tuple_gen,clientPoolL) { CClientPool gen; gen.Create(cdSEQ_DIST, - 0x10000001, 0x10000f01, 64000,1,NULL,false, + 0x10000001, 0x10000f01, 64000,1, g_dummy, 0,0); CTupleBase result; uint32_t result_src; @@ -181,7 +197,7 @@ TEST(tuple_gen,clientPoolL) { TEST(tuple_gen,clientPool) { CClientPool gen; gen.Create(cdSEQ_DIST, - 0x10000001, 0x10000021, 64000,1000,NULL,false, + 0x10000001, 0x10000021, 64000,1000, g_dummy, 0,0); CTupleBase result; uint32_t result_src; @@ -273,7 +289,7 @@ TEST(tuple_gen,GenerateTuple2) { CClientPool c_gen; CClientPool c_gen_2; c_gen.Create(cdSEQ_DIST, - 0x10000001, 0x1000000f, 64000,4,NULL,false, + 0x10000001, 0x1000000f, 64000,4, g_dummy, 0,0); CServerPool s_gen; CServerPool s_gen_2; @@ -302,7 +318,7 @@ TEST(tuple_gen,GenerateTuple2) { c_gen.Delete(); // EXPECT_EQ((size_t)0, gen.m_clients.size()); c_gen.Create(cdSEQ_DIST, - 0x10000001, 0x1000000f, 64000,400,NULL,false, + 0x10000001, 0x1000000f, 64000,400, g_dummy, 0,0); s_gen.Create(cdSEQ_DIST, 0x30000001, 0x30000001, 64000,10); @@ -325,39 +341,6 @@ TEST(tuple_gen,GenerateTuple2) { } -TEST(tuple_gen,GenerateTupleMac) { - CFlowGenList fl; - fl.Create(); - fl.load_from_mac_file("avl/mac_uit.yaml"); - - CClientPool gen; - gen.Create(cdSEQ_DIST, - 0x10000001, 0x1000000f, 64000,2, &fl.m_mac_info,true,0,0); - - CTupleBase result; - uint32_t result_src; - uint16_t result_port; - mac_addr_align_t* result_mac; - for(int i=0;i<10;i++) { - gen.GenerateTuple(result); - printf(" C:%x P:%d \n",result.getClient(),result.getClientPort()); - - result_src = result.getClient(); - result_port = result.getClientPort(); - result_mac = result.getClientMac(); - EXPECT_EQ(result_src, (uint32_t)(0x10000001+i%2)); - EXPECT_EQ(result_port, 1024+i/2); - printf("i:%d,mac:%d\n",i,result_mac->mac[3]); - if (i%2==0) - EXPECT_EQ(result_mac->mac[3], 5); - else - EXPECT_EQ(result_mac->mac[3], 1); - } - - gen.Delete(); -// EXPECT_EQ((size_t)0, gen.m_clients.size()); -} - TEST(tuple_gen,split1) { CIpPortion portion; @@ -421,7 +404,7 @@ TEST(tuple_gen,split2) { TEST(tuple_gen,template1) { CTupleGeneratorSmart gen; gen.Create(1, 1); - gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0); + gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4, g_dummy, 0, 0); gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false); CTupleTemplateGeneratorSmart template_1; template_1.Create(&gen,0,0); @@ -446,7 +429,7 @@ TEST(tuple_gen,template1) { TEST(tuple_gen,template2) { CTupleGeneratorSmart gen; gen.Create(1, 1); - gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0); + gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,g_dummy,0,0); gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false); CTupleTemplateGeneratorSmart template_1; template_1.Create(&gen,0,0); @@ -475,7 +458,7 @@ TEST(tuple_gen,template2) { TEST(tuple_gen,no_free) { CTupleGeneratorSmart gen; gen.Create(1, 1); - gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000001,64000,4,NULL,0,0); + gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000001,64000,4,g_dummy,0,0); gen.add_server_pool(cdSEQ_DIST,0x30000001,0x400000ff,64000,4,false); CTupleTemplateGeneratorSmart template_1; template_1.Create(&gen,0,0); @@ -497,7 +480,7 @@ TEST(tuple_gen,no_free) { TEST(tuple_gen,try_to_free) { CTupleGeneratorSmart gen; gen.Create(1, 1); - gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000001,64000,4,NULL,0,0); + gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000001,64000,4,g_dummy,0,0); gen.add_server_pool(cdSEQ_DIST,0x30000001,0x400000ff,64000,4,false); CTupleTemplateGeneratorSmart template_1; template_1.Create(&gen,0,0); @@ -524,7 +507,7 @@ TEST(tuple_gen,try_to_free) { TEST(tuple_gen_2,GenerateTuple) { CTupleGeneratorSmart gen; gen.Create(1, 1); - gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000f01,64000,4,NULL,0,0); + gen.add_client_pool(cdSEQ_DIST,0x10000001,0x10000f01,64000,4,g_dummy,0,0); gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false); CTupleTemplateGeneratorSmart template_1; template_1.Create(&gen,0,0); @@ -552,7 +535,7 @@ TEST(tuple_gen_2,GenerateTuple) { TEST(tuple_gen_2,GenerateTuple2) { CTupleGeneratorSmart gen; gen.Create(1, 1); - gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0); + gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,g_dummy,0,0); gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false); CTupleTemplateGeneratorSmart template_1; template_1.Create(&gen,0,0); @@ -576,7 +559,7 @@ TEST(tuple_gen_2,GenerateTuple2) { gen.Delete(); // EXPECT_EQ((size_t)0, gen.m_clients.size()); gen.Create(1, 1); - gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0); + gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,g_dummy,0,0); gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false); template_1.Create(&gen,0,0); for(int i=0;i<200;i++) { @@ -599,7 +582,7 @@ TEST(tuple_gen_2,GenerateTuple2) { TEST(tuple_gen_2,template1) { CTupleGeneratorSmart gen; gen.Create(1, 1); - gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0); + gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,g_dummy,0,0); gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false); CTupleTemplateGeneratorSmart template_1; template_1.Create(&gen,0,0); @@ -626,7 +609,7 @@ TEST(tuple_gen_2,template1) { TEST(tuple_gen_2,template2) { CTupleGeneratorSmart gen; gen.Create(1, 1); - gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,NULL,0,0); + gen.add_client_pool(cdSEQ_DIST,0x10000001,0x1000000f,64000,4,g_dummy,0,0); gen.add_server_pool(cdSEQ_DIST,0x30000001,0x40000001,64000,4,false); CTupleTemplateGeneratorSmart template_1; template_1.Create(&gen,0,0); diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 3827579b..4b086597 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -4188,8 +4188,14 @@ int CGlobalTRex::start_master_statefull() { m_fl.Create(); m_fl.load_from_yaml(CGlobalInfo::m_options.cfg_file,get_cores_tx()); + /* client config */ if (CGlobalInfo::m_options.client_cfg_file != "") { - m_fl.load_client_config_file(CGlobalInfo::m_options.client_cfg_file); + try { + m_fl.load_client_config_file(CGlobalInfo::m_options.client_cfg_file); + } catch (const std::runtime_error &e) { + std::cout << "\n*** " << e.what() << "\n\n"; + exit(-1); + } CGlobalInfo::m_options.preview.set_client_cfg_enable(true); } diff --git a/src/sim/trex_sim_stateful.cpp b/src/sim/trex_sim_stateful.cpp index 03538e58..7546644d 100644 --- a/src/sim/trex_sim_stateful.cpp +++ b/src/sim/trex_sim_stateful.cpp @@ -167,7 +167,12 @@ int load_list_of_cap_files(CParserOption * op){ fl.load_from_yaml(op->cfg_file,1); if (op->client_cfg_file != "") { - fl.load_client_config_file(op->client_cfg_file); + try { + fl.load_client_config_file(op->client_cfg_file); + } catch (const std::runtime_error &e) { + std::cout << "\n*** " << e.what() << "\n\n"; + exit(-1); + } CGlobalInfo::m_options.preview.set_client_cfg_enable(true); } @@ -609,5 +614,10 @@ int merge_2_cap_files_sip() { int SimStateful::run() { assert( CMsgIns::Ins()->Create(4) ); - return load_list_of_cap_files(&CGlobalInfo::m_options); + try { + return load_list_of_cap_files(&CGlobalInfo::m_options); + } catch (const std::runtime_error &e) { + std::cout << "\n*** " << e.what() << "\n\n"; + exit(-1); + } } diff --git a/src/trex_client_config.cpp b/src/trex_client_config.cpp index bb2b7772..8569cbf0 100644 --- a/src/trex_client_config.cpp +++ b/src/trex_client_config.cpp @@ -70,10 +70,8 @@ ClientCfgDB::load_yaml_file(const std::string &filename) { m_groups.clear(); m_cache_group = NULL; - m_filename = filename; - if (!utl_is_file_exists(filename)){ - ss << "*** file '" << filename << "' does not exists"; + ss << "file '" << filename << "' does not exists"; throw std::runtime_error(ss.str()); } @@ -85,12 +83,11 @@ ClientCfgDB::load_yaml_file(const std::string &filename) { try { base_parser.GetNextDocument(root); } catch (const std::runtime_error &ex) { - throw std::runtime_error("*** failed to parse client config file '" + filename + "'\n " + std::string(ex.what())); - + throw std::runtime_error("failed to parse client config file '" + filename + "'\n " + std::string(ex.what())); } /* wrapper parser */ - YAMLParserWrapper parser(m_filename); + YAMLParserWrapper parser(filename); /* parse globals */ m_under_vlan = parser.parse_bool(root, "vlan"); diff --git a/src/trex_client_config.h b/src/trex_client_config.h index bb378450..a5bb83b3 100644 --- a/src/trex_client_config.h +++ b/src/trex_client_config.h @@ -258,7 +258,6 @@ private: bool m_under_vlan; ClientCfgEntry *m_cache_group; - std::string m_filename; bool m_is_empty; }; diff --git a/src/tuple_gen.cpp b/src/tuple_gen.cpp index b8a54118..6861b73f 100755 --- a/src/tuple_gen.cpp +++ b/src/tuple_gen.cpp @@ -130,7 +130,7 @@ void CClientPool::allocate_configured_clients(uint32_t min_ip, ClientCfgEntry *group = client_info.lookup(ip); if (!group) { std::stringstream ss; - ss << "*** client configuration error: could not map IP '" << ip_to_str(ip) << "' to a group\n"; + ss << "client configuration error: could not map IP '" << ip_to_str(ip) << "' to a group\n"; throw std::runtime_error(ss.str()); } diff --git a/src/utl_yaml.cpp b/src/utl_yaml.cpp index 444031c6..66c83ac8 100755 --- a/src/utl_yaml.cpp +++ b/src/utl_yaml.cpp @@ -322,7 +322,7 @@ void YAMLParserWrapper::parse_err(const std::string &err, const YAML::Node &node) const { std::stringstream ss; - ss << "\n*** '" << m_header << "' - YAML parsing error at line " << node.GetMark().line << ": "; + ss << "'" << m_header << "' - YAML parsing error at line " << node.GetMark().line << ": "; ss << err; throw std::runtime_error(ss.str()); @@ -332,7 +332,7 @@ void YAMLParserWrapper::parse_err(const std::string &err) const { std::stringstream ss; - ss << "\n*** '" << m_header << "' - YAML parsing error: " << err; + ss << "'" << m_header << "' - YAML parsing error: " << err; throw std::runtime_error(ss.str()); } -- cgit 1.2.3-korg From 7b9d10888594ca9fe1114309e53c0dea9089085b Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Mon, 11 Jul 2016 16:58:21 +0300 Subject: NAT seq num randomization fully working --- linux/ws_main.py | 1 + linux_dpdk/ws_main.py | 1 + src/bp_gtest.cpp | 14 ++ src/bp_sim.cpp | 21 ++- src/bp_sim.h | 2 + src/global_io_mode.cpp | 31 +++-- src/global_io_mode.h | 16 ++- src/latency.cpp | 10 +- src/latency.h | 1 + src/main_dpdk.cpp | 42 +++++- src/nat_check.cpp | 37 +---- src/nat_check.h | 19 +-- src/nat_check_flow_table.cpp | 314 +++++++++++++++++++++++++++++++++++++++++++ src/nat_check_flow_table.h | 111 +++++++++++++++ src/trex_defs.h | 3 + 15 files changed, 543 insertions(+), 80 deletions(-) create mode 100644 src/nat_check_flow_table.cpp create mode 100644 src/nat_check_flow_table.h (limited to 'linux') diff --git a/linux/ws_main.py b/linux/ws_main.py index 2219522a..66d79d13 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -112,6 +112,7 @@ main_src = SrcGroup(dir='src', 'utl_yaml.cpp', 'rx_check_header.cpp', 'nat_check.cpp', + 'nat_check_flow_table.cpp', 'timer_wheel_pq.cpp', 'time_histogram.cpp', 'utl_json.cpp', diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py index 5bc00719..46d0424e 100755 --- a/linux_dpdk/ws_main.py +++ b/linux_dpdk/ws_main.py @@ -117,6 +117,7 @@ main_src = SrcGroup(dir='src', 'utl_json.cpp', 'utl_yaml.cpp', 'nat_check.cpp', + 'nat_check_flow_table.cpp', 'msg_manager.cpp', 'publisher/trex_publisher.cpp', 'pal/linux_dpdk/pal_utl.cpp', diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp index 3c6b2e40..a1f80407 100755 --- a/src/bp_gtest.cpp +++ b/src/bp_gtest.cpp @@ -32,6 +32,7 @@ limitations under the License. #include #include "platform_cfg.h" #include "latency.h" +#include "nat_check_flow_table.h" int test_policer(){ CPolicer policer; @@ -2400,7 +2401,20 @@ TEST_F(rx_check_system, rx_json) { printf(" %s \n",json.c_str()); } +class nat_check_flow_table : public testing::Test { + protected: + virtual void SetUp() { + } + virtual void TearDown() { + } +public: + CNatCheckFlowTable m_ft; +}; + +TEST_F(nat_check_flow_table, test1) { + m_ft.test(); +}; ////////////////////////////////////////////////////////////// diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index f46f2824..b229d9bf 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -761,8 +761,10 @@ void CFlowGenStats::clear(){ m_total_close_flows =0; m_nat_lookup_no_flow_id=0; m_nat_lookup_remove_flow_id=0; + m_nat_lookup_wait_ack_state = 0; m_nat_lookup_add_flow_id=0; m_nat_flow_timeout=0; + m_nat_flow_timeout_wait_ack = 0; m_nat_flow_learn_error=0; } @@ -791,9 +793,12 @@ void CFlowGenStats::dump(FILE *fd){ DP(m_nat_lookup_no_flow_id); DP(m_nat_lookup_remove_flow_id); + DP(m_nat_lookup_wait_ack_state); DP(m_nat_lookup_add_flow_id); DP(m_nat_flow_timeout); + DP(m_nat_flow_timeout_wait_ack); DP_name("active_nat",(m_nat_lookup_add_flow_id-m_nat_lookup_remove_flow_id)); + DP_name("active_nat_wait_syn", (m_nat_lookup_add_flow_id - m_nat_lookup_wait_ack_state)); DP(m_nat_flow_learn_error); } @@ -2031,7 +2036,8 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::is_valid_template_loa , " Please give different CAP file, or try different --learn-mode\n"); return kTCPLearnModeBadFlow; } - if ((pkt_0_indication.m_cap_ipg < LEARN_MODE_MIN_IPG / 1000) || (pkt_1_indication.m_cap_ipg < LEARN_MODE_MIN_IPG / 1000)) { + if ((pkt_0_indication.m_cap_ipg < (double)LEARN_MODE_MIN_IPG / 1000) + || (pkt_1_indication.m_cap_ipg < (double)LEARN_MODE_MIN_IPG / 1000)) { fprintf(stderr , "Error: Bad cap file timings. In the chosen learn mode"); fprintf(stderr, "IPG between TCP handshake packets should be at least %d msec.\n", LEARN_MODE_MIN_IPG); @@ -2300,10 +2306,6 @@ enum CCapFileFlowInfo::load_cap_file_err CCapFileFlowInfo::load_cap_file(std::st lp_prev->m_pkt_indication.m_cap_ipg = lp->m_pkt_indication.m_cap_ipg- lp_prev->m_pkt_indication.m_cap_ipg; - - - - printf("%d: IPG:%f", i, lp_prev->m_pkt_indication.m_cap_ipg); //??? remove if ( lp->m_pkt_indication.m_desc.IsInitSide() != lp_prev->m_pkt_indication.m_desc.IsInitSide()) { lp_prev->m_pkt_indication.m_desc.SetRtt(true); @@ -4177,6 +4179,11 @@ int CFlowGenListPerThread::reschedule_flow(CGenNode *node){ void CFlowGenListPerThread::terminate_nat_flows(CGenNode *p){ m_stats.m_nat_flow_timeout++; m_stats.m_nat_lookup_remove_flow_id++; + if (p->is_nat_wait_ack_state()) { + m_stats.m_nat_flow_timeout_wait_ack++; + } else { + m_stats.m_nat_lookup_wait_ack_state++; + } m_flow_id_to_node_lookup.remove_no_lookup(p->get_short_fid()); free_last_flow_node( p); } @@ -4228,6 +4235,7 @@ void CFlowGenListPerThread::handle_nat_msg(CGenNodeNatInfo * msg){ node->set_nat_tcp_seq_diff_client(nat_msg->m_tcp_seq - tcp->getSeqNumber()); if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { node->set_nat_wait_ack_state(); + m_stats.m_nat_lookup_wait_ack_state++; second = false; } else { node->set_nat_learn_state(); @@ -4256,7 +4264,8 @@ void CFlowGenListPerThread::handle_nat_msg(CGenNodeNatInfo * msg){ node->set_nat_ipv4_port(nat_msg->m_external_port); if ( CGlobalInfo::is_learn_verify_mode() ){ - if (!node->is_external_is_eq_to_internal_ip() ){ + if (!node->is_external_is_eq_to_internal_ip() || + node->get_nat_tcp_seq_diff_client() != 0) { m_stats.m_nat_flow_learn_error++; } } diff --git a/src/bp_sim.h b/src/bp_sim.h index 49e0e8dc..13934d74 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -1871,8 +1871,10 @@ public: uint64_t m_total_close_flows; uint64_t m_nat_lookup_no_flow_id; uint64_t m_nat_lookup_remove_flow_id; + uint64_t m_nat_lookup_wait_ack_state; uint64_t m_nat_lookup_add_flow_id; uint64_t m_nat_flow_timeout; + uint64_t m_nat_flow_timeout_wait_ack; uint64_t m_nat_flow_learn_error; public: diff --git a/src/global_io_mode.cpp b/src/global_io_mode.cpp index 2457599e..289863c9 100755 --- a/src/global_io_mode.cpp +++ b/src/global_io_mode.cpp @@ -103,6 +103,14 @@ bool CTrexGlobalIoMode::handle_io_modes(void){ m_g_mode=gNORMAL; } break; + case ccNat: + m_g_mode=gNAT; + m_nat_mode++; + if (m_nat_mode==natLAST) { + m_nat_mode = natDISABLE; + m_g_mode = gNORMAL; + } + break; } @@ -121,17 +129,18 @@ void CTrexGlobalIoMode::Dump(FILE *fd){ } void CTrexGlobalIoMode::DumpHelp(FILE *fd){ - fprintf(fd,"Help for Interactive Commands - Trex \n" ); - fprintf(fd," d : Toggle, Disable all -> Noraml \n"); - fprintf(fd," n : Default mode all in Normal mode \n"); - fprintf(fd," h : Toggle, Help->Normal \n"); - fprintf(fd,"\n"); - fprintf(fd," p : Per ports Toggle mode, disable -> table -> normal \n"); - fprintf(fd," a : Global ports Toggle mode, disable -> enable \n"); - fprintf(fd," l : Latency Toggle mode, disable -> enable -> enhanced \n"); - fprintf(fd," r : Rx check Toggle mode, disable -> enable -> enhanced \n"); - fprintf(fd," m : memory stats , disable -> enable \n"); - fprintf(fd," Press h or 1 to go back to Normal mode \n"); + fprintf(fd, "Help for Interactive Commands\n" ); + fprintf(fd, " %c : Toggle, Disable all/Default \n", ccGDISABLE); + fprintf(fd, " %c : Go back to default mode \n", ccGNORAML); + fprintf(fd, " %c : Toggle, Help/Default \n", ccHELP); + fprintf(fd, "\n"); + fprintf(fd, " %c : Per ports toggle disable -> table -> normal \n", ccGPP); + fprintf(fd, " %c : Global ports toggle disable/enable \n", ccGAP); + fprintf(fd, " %c : Latency toggle disable -> enable -> enhanced \n", ccGL); + fprintf(fd, " %c : Rx check toggle disable -> enable -> enhanced \n", ccGRC); + fprintf(fd, " %c : Memory stats toggle disable/enable \n", ccMem); + fprintf(fd, " %c : NAT pending flows toggle disable/enable \n", ccNat); + fprintf(fd, " Press %c or %c to go back to Normal mode \n", ccHELP, ccGNORAML); } diff --git a/src/global_io_mode.h b/src/global_io_mode.h index 84b402b7..44fa4be5 100755 --- a/src/global_io_mode.h +++ b/src/global_io_mode.h @@ -48,12 +48,13 @@ public: enum Chars{ ccHELP='h', ccGDISABLE='d', - ccGNORAML='n', + ccGNORAML='0', ccGPP='p', ccGAP='a', ccGL='l', ccGRC='r', - ccMem='m' + ccMem='m', + ccNat='n' }; enum CliDumpMode { @@ -67,7 +68,8 @@ public: gDISABLE=0, // no print at all gHELP=1, // help gNORMAL=2, // normal - gMem=3 + gMem=3, + gNAT }; @@ -104,12 +106,20 @@ public: }; typedef uint8_t RxCheckMode_t; + enum NatMode { + natDISABLE = 0, + natENABLE = 1, + natLAST = 2 + }; + typedef uint8_t NatMode_t; + Global_t m_g_mode; bool m_g_disable_first; PerPortCountersMode_t m_pp_mode; AllPortCountersMode_t m_ap_mode; LatecnyMode_t m_l_mode; RxCheckMode_t m_rc_mode; + NatMode_t m_nat_mode; public: void set_mode(CliDumpMode mode); diff --git a/src/latency.cpp b/src/latency.cpp index b9ce2177..768e161b 100644 --- a/src/latency.cpp +++ b/src/latency.cpp @@ -387,12 +387,6 @@ bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p) { if ( ! is_lateancy_pkt) { -#if 0 - TCPHeader *tcp = (TCPHeader *)parser.m_l4; //????? remove - if (parser.m_ipv4->getProtocol() == 0x6 && tcp->getSynFlag()) { - tcp->dump(stdout); //???? remove - } -#endif #ifdef NAT_TRACE_ printf(" %.3f RX : got packet !!! \n",now_sec() ); #endif @@ -917,6 +911,10 @@ void CLatencyManager::DumpShortRxCheck(FILE *fd){ } } +void CLatencyManager::dump_nat_flow_table(FILE *fd) { + m_nat_check_manager.Dump(fd); +} + void CLatencyManager::rx_check_dump_json(std::string & json){ if ( get_is_rx_check_mode() ) { m_rx_check_manager.dump_json(json ); diff --git a/src/latency.h b/src/latency.h index 552b3999..63e50337 100644 --- a/src/latency.h +++ b/src/latency.h @@ -362,6 +362,7 @@ public: void DumpRxCheck(FILE *fd); // dump all void DumpShortRxCheck(FILE *fd); // dump short histogram of latency + void dump_nat_flow_table(FILE *fd); void rx_check_dump_json(std::string & json); uint16_t get_latency_header_offset(){ return ( m_pkt_gen.get_payload_offset() ); diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index d5e7c9b5..099ebb3b 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -2439,8 +2439,10 @@ public: uint64_t m_active_sockets; uint64_t m_total_nat_time_out; + uint64_t m_total_nat_time_out_wait_ack; uint64_t m_total_nat_no_fid ; uint64_t m_total_nat_active ; + uint64_t m_total_nat_syn_wait; uint64_t m_total_nat_open ; uint64_t m_total_nat_learn_error ; @@ -2559,8 +2561,10 @@ void CGlobalStats::dump_json(std::string & json, bool baseline){ json+=GET_FIELD(m_socket_util); json+=GET_FIELD(m_total_nat_time_out); + json+=GET_FIELD(m_total_nat_time_out_wait_ack); json+=GET_FIELD(m_total_nat_no_fid ); json+=GET_FIELD(m_total_nat_active ); + json+=GET_FIELD(m_total_nat_syn_wait); json+=GET_FIELD(m_total_nat_open ); json+=GET_FIELD(m_total_nat_learn_error); @@ -2596,7 +2600,12 @@ void CGlobalStats::DumpAllPorts(FILE *fd){ fprintf (fd," Platform_factor : %2.1f \n",m_platform_factor); fprintf (fd," Total-Tx : %s ",double_to_human_str(m_tx_bps,"bps",KBYE_1000).c_str()); if ( CGlobalInfo::is_learn_mode() ) { - fprintf (fd," Nat_time_out : %8llu \n", (unsigned long long)m_total_nat_time_out); + fprintf (fd," NAT time out : %8llu", (unsigned long long)m_total_nat_time_out); + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { + fprintf (fd," (%llu in wait for syn+ack)\n", (unsigned long long)m_total_nat_time_out_wait_ack); + } else { + fprintf (fd, "\n"); + } }else{ fprintf (fd,"\n"); } @@ -2604,28 +2613,33 @@ void CGlobalStats::DumpAllPorts(FILE *fd){ fprintf (fd," Total-Rx : %s ",double_to_human_str(m_rx_bps,"bps",KBYE_1000).c_str()); if ( CGlobalInfo::is_learn_mode() ) { - fprintf (fd," Nat_no_fid : %8llu \n", (unsigned long long)m_total_nat_no_fid); + fprintf (fd," NAT aged flow id: %8llu \n", (unsigned long long)m_total_nat_no_fid); }else{ fprintf (fd,"\n"); } fprintf (fd," Total-PPS : %s ",double_to_human_str(m_tx_pps,"pps",KBYE_1000).c_str()); if ( CGlobalInfo::is_learn_mode() ) { - fprintf (fd," Total_nat_active: %8llu \n", (unsigned long long)m_total_nat_active); + fprintf (fd," Total NAT active: %8llu", (unsigned long long)m_total_nat_active); + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { + fprintf (fd," (%llu waiting for syn)\n", (unsigned long long)m_total_nat_syn_wait); + } else { + fprintf (fd, "\n"); + } }else{ fprintf (fd,"\n"); } fprintf (fd," Total-CPS : %s ",double_to_human_str(m_tx_cps,"cps",KBYE_1000).c_str()); if ( CGlobalInfo::is_learn_mode() ) { - fprintf (fd," Total_nat_open : %8llu \n", (unsigned long long)m_total_nat_open); + fprintf (fd," Total NAT opened: %8llu \n", (unsigned long long)m_total_nat_open); }else{ fprintf (fd,"\n"); } fprintf (fd,"\n"); fprintf (fd," Expected-PPS : %s ",double_to_human_str(m_tx_expected_pps,"pps",KBYE_1000).c_str()); if ( CGlobalInfo::is_learn_verify_mode() ) { - fprintf (fd," Nat_learn_errors: %8llu \n", (unsigned long long)m_total_nat_learn_error); + fprintf (fd," NAT learn errors: %8llu \n", (unsigned long long)m_total_nat_learn_error); }else{ fprintf (fd,"\n"); } @@ -3647,8 +3661,10 @@ void CGlobalTRex::get_stats(CGlobalStats & stats){ uint64_t total_nat_time_out =0; + uint64_t total_nat_time_out_wait_ack =0; uint64_t total_nat_no_fid =0; uint64_t total_nat_active =0; + uint64_t total_nat_syn_wait = 0; uint64_t total_nat_open =0; uint64_t total_nat_learn_error=0; @@ -3677,8 +3693,10 @@ void CGlobalTRex::get_stats(CGlobalStats & stats){ total_sockets += lpt->m_smart_gen.MaxSockets(); total_nat_time_out +=lpt->m_stats.m_nat_flow_timeout; + total_nat_time_out_wait_ack += lpt->m_stats.m_nat_flow_timeout_wait_ack; total_nat_no_fid +=lpt->m_stats.m_nat_lookup_no_flow_id ; total_nat_active +=lpt->m_stats.m_nat_lookup_add_flow_id - lpt->m_stats.m_nat_lookup_remove_flow_id; + total_nat_syn_wait += lpt->m_stats.m_nat_lookup_add_flow_id - lpt->m_stats.m_nat_lookup_wait_ack_state; total_nat_open +=lpt->m_stats.m_nat_lookup_add_flow_id; total_nat_learn_error +=lpt->m_stats.m_nat_flow_learn_error; uint8_t port0 = lpt->getDualPortId() *2; @@ -3700,8 +3718,10 @@ void CGlobalTRex::get_stats(CGlobalStats & stats){ } stats.m_total_nat_time_out = total_nat_time_out; + stats.m_total_nat_time_out_wait_ack = total_nat_time_out_wait_ack; stats.m_total_nat_no_fid = total_nat_no_fid; stats.m_total_nat_active = total_nat_active; + stats.m_total_nat_syn_wait = total_nat_syn_wait; stats.m_total_nat_open = total_nat_open; stats.m_total_nat_learn_error = total_nat_learn_error; @@ -3959,9 +3979,17 @@ CGlobalTRex::handle_slow_path(bool &was_stopped) { m_mg.DumpRxCheck(stdout); break; } - } - + } + } + if ( m_io_modes.m_g_mode == CTrexGlobalIoMode::gNAT ) { + if ( m_io_modes.m_nat_mode == CTrexGlobalIoMode::natENABLE ) { + if (CGlobalInfo::is_learn_mode(CParserOption::LEARN_MODE_TCP_ACK)) { + fprintf(stdout, "NAT flow table info\n"); + m_mg.dump_nat_flow_table(stdout); + } else { + fprintf(stdout, "\nThis is only relevant in --learn-mode %d\n", CParserOption::LEARN_MODE_TCP_ACK); + } } } diff --git a/src/nat_check.cpp b/src/nat_check.cpp index c7262e50..f3dd93d1 100755 --- a/src/nat_check.cpp +++ b/src/nat_check.cpp @@ -52,29 +52,6 @@ void CGenNodeNatInfo::init(){ m_cnt=0; } -bool CNatCheckFlowTableMap::find(uint64_t key, uint32 &val) { - nat_check_flow_map_t::iterator iter; - iter = m_map.find(key); - if (iter != m_map.end() ) { - val = (*iter).second; - return true; - }else{ - return false; - } -} - -void CNatCheckFlowTableMap::dump(FILE *fd) { - nat_check_flow_map_iter_t it; - uint32_t val; - uint64_t key; - - for (it = m_map.begin(); it != m_map.end(); it++) { - val = it->second; - key = it->first; - fprintf(fd, "%lx->%x\n", key, val); - } -} - void CNatStats::reset(){ m_total_rx=0; m_total_msg=0; @@ -207,21 +184,20 @@ void CNatRxManager::handle_packet_ipv4(CNatOption *option, IPHeader *ipv4, bool uint32_t dst_ip = ipv4->getDestIp(); uint16_t dst_port = tcp->getDestPort(); uint64_t map_key = (dst_ip << 16) + dst_port; - m_fm.insert(map_key, tcp_ack); + double time_stamp = now_sec(); + m_ft.insert(map_key, tcp_ack, time_stamp); + m_ft.clear_old(time_stamp - 1); } } else { uint32_t val; // server->client packet. IP/port reversed in regard to first SYN packet uint64_t map_key = (ext_ip << 16) + ext_port; - - if (m_fm.find(map_key, val)) { + if (m_ft.erase(map_key, val)) { get_info_from_tcp_ack(val, fid, thread_id); thread_info = get_thread_info(thread_id); - m_fm.erase(map_key); } else { + // flow was not found in the table thread_info = 0; - // ??? Handle error - // ??? handle aging of flow info } } } @@ -279,7 +255,8 @@ void CNatStats::Dump(FILE *fd){ void CNatRxManager::Dump(FILE *fd){ - m_stats.Dump(stdout); + m_stats.Dump(fd); + m_ft.dump(fd); } void CNatRxManager::DumpShort(FILE *fd){ diff --git a/src/nat_check.h b/src/nat_check.h index 3b526c0b..18add5e0 100755 --- a/src/nat_check.h +++ b/src/nat_check.h @@ -29,6 +29,7 @@ limitations under the License. #include #include #include "os_time.h" +#include "nat_check_flow_table.h" // 2msec timeout #define MAX_TIME_MSG_IN_QUEUE_SEC ( 0.002 ) @@ -211,22 +212,6 @@ public: void Dump(FILE *fd); }; -typedef std::map > nat_check_flow_map_t; -typedef nat_check_flow_map_t::iterator nat_check_flow_map_iter_t; - -class CNatCheckFlowTableMap { -public: - void erase(uint64_t key) {m_map.erase(key);} - bool find(uint64_t fid, uint32_t &val); - void insert(uint64_t key, uint32_t val) {m_map.insert(std::pair(key, val));} - void clear(void) {m_map.clear();} - void dump(FILE *fd); - uint64_t size(void) {return m_map.size();} - -public: - nat_check_flow_map_t m_map; -}; - class CNatRxManager { public: @@ -248,7 +233,7 @@ private: uint8_t m_max_threads; CNatPerThreadInfo * m_per_thread; CNatStats m_stats; - CNatCheckFlowTableMap m_fm; + CNatCheckFlowTable m_ft; }; diff --git a/src/nat_check_flow_table.cpp b/src/nat_check_flow_table.cpp new file mode 100644 index 00000000..18ba8142 --- /dev/null +++ b/src/nat_check_flow_table.cpp @@ -0,0 +1,314 @@ +/* + Ido Barnea + Cisco Systems, Inc. +*/ + +/* + Copyright (c) 2016-2016 Cisco Systems, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include "nat_check_flow_table.h" +/* + classes in this file: + CNatCheckFlowTableList - List implementation + CNatCheckFlowTableMap - Map implementation + CNatData - element of data that exists in the map and the list. + CNatCheckFlowTable - Wrapper class which is the interface to outside. + New element is always inserted to the list and map. + If element is removed, it is always removed from list and map together. + Map is used to lookup elemnt by key. + List is used to clean up old elements by timestamp. We guarantee the list is always sorted by timestamp, + since we always insert at the end, with increasing timestamp. +*/ + +std::ostream& operator<<(std::ostream& os, const CNatData &cn) { + os << "(" << &cn << ")" << "data:" << cn.m_data << " time:" << cn.m_timestamp; + os << " prev:" << cn.m_prev << " next:" << cn.m_next; + return os; +} + +// map implementation +CNatData *CNatCheckFlowTableMap::erase(uint64_t key) { + nat_check_flow_map_iter_no_const_t it = m_map.find(key); + + if (it != m_map.end()) { + CNatData *val = it->second; + m_map.erase(it); + return val; + } + + return NULL; +} + +bool CNatCheckFlowTableMap::find(uint64_t key, uint32_t &val) { + nat_check_flow_map_iter_t it = m_map.find(key); + + if (it != m_map.end()) { + CNatData *data = it->second; + val = data->get_data(); + return true; + } + + return false; +} + +// for testing +bool CNatCheckFlowTableMap::verify(uint32_t *arr, int size) { + uint32_t val = -1; + int real_size = 0; + + for (int i = 0; i < size; i++) { + if (arr[i] == -1) + continue; + real_size++; + find(i, val); + if (val != arr[i]) + return false; + } + + if (m_map.size() != real_size) { + std::cout << "Error: Wrong map size " << m_map.size() << ". Should be " << real_size << std::endl; + return false; + } + + return true; +} + +CNatData * CNatCheckFlowTableMap::insert(uint64_t key, uint32_t val, double time) { + CNatData *elem = new CNatData; + assert(elem); + elem->set_data(val); + elem->set_key(key); + elem->set_timestamp(time); + std::pair pair = std::pair(key, elem); + + if (m_map.insert(pair).second == false) { + delete elem; + return NULL; + } else { + return elem; + } +} + +std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTableMap& cf) { + nat_check_flow_map_iter_t it; + + os << "NAT check flow table map:\n"; + for (it = cf.m_map.begin(); it != cf.m_map.end(); it++) { + CNatData *data = it->second; + uint32_t key = it->first; + os << " " << key << ":" << *data << std::endl; + } + return os; +} + +void CNatCheckFlowTableList::dump_short(FILE *fd) { + fprintf(fd, "list:\n"); + // this is not fully safe, since we call it from CP core, and rx core changes the list. + // It is usefull as a debug function + if (m_head) { + fprintf(fd, " head: time:%f key:%x data:%x\n", m_head->get_timestamp(), m_head->get_key(), m_head->get_data()); + fprintf(fd, " tail: time:%f key:%x data:%x\n", m_tail->get_timestamp(), m_tail->get_key(), m_tail->get_data()); + } +} + +// list implementation +// The list is always sorted by timestamp, since we always insert at the end, with increasing timestamp +void CNatCheckFlowTableList::erase(CNatData *data) { + if (m_head == data) { + m_head = data->m_next; + } + if (m_tail == data) { + m_tail = data->m_prev; + } + if (data->m_prev) { + data->m_prev->m_next = data->m_next; + } + if (data->m_next) { + data->m_next->m_prev = data->m_prev; + } +} + +// insert as last element in list +void CNatCheckFlowTableList::insert(CNatData *data) { + data->m_prev = m_tail; + data->m_next = NULL; + + if (m_tail != NULL) { + m_tail->m_next = data; + } else { + // if m_tail is NULL m_head is also NULL + m_head = data; + } + m_tail = data; +} + +bool CNatCheckFlowTableList::verify(uint32_t *arr, int size) { + int index = -1; + CNatData *elem = m_head; + int count = 0; + + while (index < size - 1) { + index++; + if (arr[index] == -1) { + continue; + } + count++; + + if (elem->get_data() != arr[index]) { + return false; + } + + if (elem == NULL) { + std::cout << "Too few items in list. Only " << count << std::endl; + return false; + } + elem = elem->m_next; + } + + // We expect number of items in list to be like num of val!=-1 in arr + if (elem != NULL) { + std::cout << "Too many items in list" << std::endl; + return false; + } + + return true; +} + +std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTableList& cf) { + CNatData *it = cf.m_head; + + os << "NAT check flow table list:\n"; + os << " head:" << cf.m_head << " tail:" << cf.m_tail << std::endl; + while (it != NULL) { + os << " " << *it << std::endl; + it = it->m_next; + } + + return os; +} + +// flow table +std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTable& cf) { + os << "========= Flow table start =========" << std::endl; + os << cf.m_map; + os << cf.m_list; + os << "========= Flow table end =========" << std::endl; + + return os; +} + +void CNatCheckFlowTable::clear_old(double time) { + CNatData *data = m_list.get_head(); + uint32_t val; + + while (data) { + if (data->get_timestamp() < time) { + erase(data->get_key(), val); + data = m_list.get_head(); + } else { + break; + } + } +} + +void CNatCheckFlowTable::dump(FILE *fd) { + fprintf(fd, "map size:%lu\n", m_map.size()); + m_list.dump_short(fd); +} + +bool CNatCheckFlowTable::erase(uint64_t key, uint32_t &val) { + CNatData *data = m_map.erase(key); + + if (!data) + return false; + + val = data->get_data(); + m_list.erase(data); + delete data; + + return true; +} + +bool CNatCheckFlowTable::insert(uint64_t key, uint32_t val, double time) { + CNatData *res; + + res = m_map.insert(key, val, time); + if (!res) { + return false; + } else { + m_list.insert(res); + } + return true; +} + +CNatCheckFlowTable::~CNatCheckFlowTable() { + clear_old(UINT64_MAX); +} + +bool CNatCheckFlowTable::test() { + uint32_t size = 100; + uint32_t arr[size]; + int i; + uint32_t val; + + for (i = 0; i < size; i++) { + arr[i] = i+200; + } + + // insert some elements + for (i = 0; i < size; i++) { + val = arr[i]; + assert(insert(i, val, i) == true); + } + + // insert same elements. should fail + for (i = 0; i < size; i++) { + val = arr[i]; + assert(insert(i, val, val) == false); + } + + // remove element we did not insert + assert(erase(size, val) == false); + + assert (m_map.verify(arr, size) == true); + assert (m_list.verify(arr, size) == true); + + // remove even keys + for (i = 0; i < size; i += 2) { + assert(erase(i, val) == true); + assert (val == arr[i]); + arr[i] = -1; + } + + assert (m_map.verify(arr, size) == true); + assert (m_list.verify(arr, size) == true); + + // clear half of the old values (We removed the even already, so 1/4 should be left) + clear_old(size/2); + for (i = 0; i < size/2; i++) { + arr [i] = -1; + } + + assert (m_map.verify(arr, size) == true); + assert (m_list.verify(arr, size) == true); + + return true; +} diff --git a/src/nat_check_flow_table.h b/src/nat_check_flow_table.h new file mode 100644 index 00000000..dddd45b6 --- /dev/null +++ b/src/nat_check_flow_table.h @@ -0,0 +1,111 @@ +/* + Ido Barnea + Cisco Systems, Inc. +*/ + +/* + Copyright (c) 2016-2016 Cisco Systems, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +#ifndef NAT_CHECK_FLOW_TABLE_H +#define NAT_CHECK_FLOW_TABLE_H +#include + +class CNatData; +class CNatCheckFlowTableList; + +typedef std::map > nat_check_flow_map_t; +typedef nat_check_flow_map_t::const_iterator nat_check_flow_map_iter_t; +typedef nat_check_flow_map_t::iterator nat_check_flow_map_iter_no_const_t; + +// One element of list and map +class CNatData { + friend class CNatCheckFlowTableList; // access m_next and m_prev + friend std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTableList& cf); + friend std::ostream& operator<<(std::ostream& os, const CNatData &cn); + + public: + uint32_t get_data() {return m_data;} + void set_data(uint32_t val) {m_data = val;} + uint32_t get_key() {return m_key;} + void set_key(uint32_t val) {m_key = val;} + double get_timestamp() {return m_timestamp;} + void set_timestamp(double val) {m_timestamp = val;} + CNatData() { + m_next = NULL; + m_prev = NULL; + } + + private: + double m_timestamp; + uint64_t m_key; + CNatData *m_prev; + CNatData *m_next; + uint32_t m_data; +}; + +class CNatCheckFlowTableMap { + friend class CNatCheckFlowTable; + friend std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTableMap& cf); + + private: + void clear(void) {m_map.clear();} + CNatData *erase(uint64_t key); + bool find(uint64_t key, uint32_t &val); + CNatData *insert(uint64_t key, uint32_t val, double time); + bool verify(uint32_t *arr, int size); + uint64_t size(void) {return m_map.size();} + + private: + nat_check_flow_map_t m_map; +}; + +class CNatCheckFlowTableList { + friend class CNatCheckFlowTable; + friend std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTableList& cf); + + private: + void dump_short(FILE *fd); + void erase(CNatData *data); + CNatData *get_head() {return m_head;} + void insert(CNatData *data); + bool verify(uint32_t *arr, int size); + + CNatCheckFlowTableList() { + m_head = NULL; + m_tail = NULL; + } + + private: + CNatData *m_head; + CNatData *m_tail; +}; + +class CNatCheckFlowTable { + friend std::ostream& operator<<(std::ostream& os, const CNatCheckFlowTable& cf); + + public: + ~CNatCheckFlowTable(); + void clear_old(double time); + void dump(FILE *fd); + bool erase(uint64_t key, uint32_t &val); + bool insert(uint64_t key, uint32_t val, double time); + bool test(); + + private: + CNatCheckFlowTableMap m_map; + CNatCheckFlowTableList m_list; +}; + +#endif diff --git a/src/trex_defs.h b/src/trex_defs.h index bbf3f3ba..9abb38f5 100644 --- a/src/trex_defs.h +++ b/src/trex_defs.h @@ -35,6 +35,9 @@ limitations under the License. #define UINT16_MAX 0xFFFF #endif +#ifndef UINT64_MAX + #define UINT64_MAX 0xFFFFFFFFFFFFFFFF +#endif typedef std::set flow_stat_active_t; typedef std::set::iterator flow_stat_active_it_t; -- cgit 1.2.3-korg