diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/trex_client_config.cpp | 131 | ||||
-rw-r--r-- | src/trex_client_config.h | 95 |
2 files changed, 200 insertions, 26 deletions
diff --git a/src/trex_client_config.cpp b/src/trex_client_config.cpp index f3084942..f9ad0e6c 100644 --- a/src/trex_client_config.cpp +++ b/src/trex_client_config.cpp @@ -31,18 +31,14 @@ limitations under the License. #include "bp_sim.h" void -ClientGroup::dump() { - char ip_str[100]; +ClientGroup::dump() const { - ip_to_str(m_ip_start, ip_str); - std::cout << "IP start: " << ip_str << "\n"; - - ip_to_str(m_ip_end, ip_str); - std::cout << "IP end: " << ip_str << "\n"; + std::cout << "IP start: " << ip_to_str(m_ip_start) << "\n"; + std::cout << "IP end: " << ip_to_str(m_ip_end) << "\n"; std::cout << "Init. MAC addr: "; for (int i = 0; i < 6; i++) { - printf("%x:", m_init_mac[i]); + printf("%lx:", ( (m_init_mac >> ( (6-i) * 8)) & 0xFF ) ); } std::cout << "\n"; @@ -50,13 +46,14 @@ ClientGroup::dump() { std::cout << "Res. MAC addr: "; for (int i = 0; i < 6; i++) { - printf("%x:", m_res_mac[i]); + printf("%lx:", ( (m_res_mac >> ( (6-i) * 8)) & 0xFF ) ); } std::cout << "\n"; std::cout << "Res. VLAN: " << m_res_vlan << "\n"; } + /** * loads a YAML file containing * the client groups configuration @@ -66,7 +63,7 @@ void ClientGroupsDB::load_yaml_file(const std::string &filename) { std::stringstream ss; - ss << "'" << filename << "' YAML parsing error: "; + m_filename = filename; if (!utl_is_file_exists(filename)){ ss << "file does not exists"; @@ -87,29 +84,30 @@ ClientGroupsDB::load_yaml_file(const std::string &filename) { /* ip_start */ rc = utl_yaml_read_ip_addr(root[i], "ip_start", group.m_ip_start); if (!rc) { - ss << "line " << mark.line << " - 'ip_start' field does not exists"; - throw std::runtime_error(ss.str()); + yaml_parse_err("'ip_start' field does not exists", &mark); } /* ip_end */ rc = utl_yaml_read_ip_addr(root[i], "ip_end", group.m_ip_end); if (!rc) { - ss << "line " << mark.line << " - 'ip_end' field does not exists"; - throw std::runtime_error(ss.str()); + yaml_parse_err("'ip_end' field does not exists", &mark); + } + + /* sanity check */ + if (group.m_ip_end <= group.m_ip_start) { + yaml_parse_err("IP group range must be positive and include at least one entry", &mark); } /* init_mac */ rc = utl_yaml_read_mac_addr(root[i], "init_mac", group.m_init_mac); if (!rc) { - ss << "line " << mark.line << " - 'init_mac' field does not exists"; - throw std::runtime_error(ss.str()); + yaml_parse_err("'init_mac' field does not exists", &mark); } /* res_mac */ rc = utl_yaml_read_mac_addr(root[i], "res_mac", group.m_res_mac); if (!rc) { - ss << "line " << mark.line << " - 'init_mac' field does not exists"; - throw std::runtime_error(ss.str()); + yaml_parse_err("'res_mac' field does not exists", &mark); } @@ -117,9 +115,98 @@ ClientGroupsDB::load_yaml_file(const std::string &filename) { root[i]["res_vlan"] >> group.m_res_vlan; root[i]["count"] >> group.m_count; - printf("\n"); - group.dump(); - printf("\n"); - //std::cout << root[i]["ip_start"] << "\n"; + + /* add to map with copying */ + m_groups[group.m_ip_start] = group; + } + + verify(); + + m_is_empty = false; + +} + +void +ClientGroupsDB::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; + + 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"; + yaml_parse_err(ss.str()); + } + + monotonic = group.m_ip_end; + } +} + +/** + * lookup function + * should be fast + * + */ +ClientGroup * +ClientGroupsDB::lookup(uint32_t ip) { + + /* check the cache */ + if ( (m_cache_group) && (m_cache_group->contains(ip)) ) { + return m_cache_group; + } + + std::map<uint32_t ,ClientGroup>::iterator it; + + it = m_groups.upper_bound(ip); + + /* if the first element in the map is bigger - its not in the map */ + if (it == m_groups.begin()) { + return NULL; + } + + /* go one back - we know it's not on begin so we have at least one back */ + it--; + + ClientGroup &group = (*it).second; + + /* because this is a non overlapping intervals + if IP exists it must be in this group + because if it exists in some other previous group + its end_range >= ip so start_range > ip + and so start_range is the upper_bound + */ + if (group.contains(ip)) { + /* save as cache */ + m_cache_group = &group; + return &group; + } else { + return NULL; + } + +} + +ClientGroup * +ClientGroupsDB::lookup(const std::string &ip) { + uint32_t addr = (uint32_t)inet_addr(ip.c_str()); + addr = PKT_NTOHL(addr); + + return lookup(addr); +} + + +void +ClientGroupsDB::yaml_parse_err(const std::string &err, const YAML::Mark *mark) const { + std::stringstream ss; + + if (mark) { + ss << "\n*** '" << m_filename << "' - YAML parsing error at line " << mark->line << ": "; + } else { + ss << "\n*** '" << m_filename << "' - YAML parsing error: "; } + + ss << err; + throw std::runtime_error(ss.str()); } diff --git a/src/trex_client_config.h b/src/trex_client_config.h index 27b11836..442d228b 100644 --- a/src/trex_client_config.h +++ b/src/trex_client_config.h @@ -26,25 +26,78 @@ limitations under the License. #include <map> /** + * single client config + * + * @author imarom (27-Jun-16) + */ +class ClientCfg { +public: + uint8_t m_init_mac[6]; + uint16_t m_init_vlan; + + uint8_t m_res_mac[6]; + uint16_t m_res_vlan; + +}; + +/** * describes a single client group * configuration */ class ClientGroup { public: + ClientGroup() { + reset(); + } + + + void dump() const; + + bool contains(uint32_t ip) const { + return ( (ip >= m_ip_start) && (ip <= m_ip_end) ); + } + + void reset() { + m_iterator = 0; + } + + /** + * assings a client config from the group + * it will advance MAC addresses andf etc. + * + * @author imarom (27-Jun-16) + * + * @param info + */ + void assign(ClientCfg &info) { + + for (int i = 0; i < 6; i++) { + info.m_init_mac[i] = ( (m_init_mac + m_iterator) >> ((5 - i) * 8) ) & 0xFF; + info.m_res_mac[i] = ( (m_res_mac + m_iterator) >> ((5 - i) * 8) ) & 0xFF; + } + + info.m_init_vlan = m_init_vlan; + info.m_res_vlan = m_res_vlan; + + /* advance */ + m_iterator = (m_iterator + 1) % m_count; + } + +public: uint32_t m_ip_start; uint32_t m_ip_end; - uint8_t m_init_mac[6]; + uint64_t m_init_mac; uint16_t m_init_vlan; - uint8_t m_res_mac[6]; + uint64_t m_res_mac; uint16_t m_res_vlan; uint32_t m_count; - - void dump(); +private: + uint32_t m_iterator; }; /** @@ -53,6 +106,21 @@ public: */ class ClientGroupsDB { public: + + ClientGroupsDB() { + m_is_empty = true; + m_cache_group = NULL; + } + + /** + * if no config file was loaded + * this should return true + * + */ + bool is_empty() { + return m_is_empty; + } + /** * loads a YAML file * configuration will be built @@ -61,10 +129,29 @@ public: */ void load_yaml_file(const std::string &filename); + /** + * lookup for a specific IP address for + * a group that contains this IP + * + */ + ClientGroup * lookup(uint32_t ip); + ClientGroup * lookup(const std::string &ip); private: + + void yaml_parse_err(const std::string &err, const YAML::Mark *mark = NULL) const; + + /** + * verify the YAML file loaded in valid + * + */ + void verify() const; + /* maps the IP start value to client groups */ std::map<uint32_t, ClientGroup> m_groups; + ClientGroup *m_cache_group; + std::string m_filename; + bool m_is_empty; }; #endif /* __TREX_CLIENT_CONFIG_H__ */ |