summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimarom <imarom@cisco.com>2016-06-27 15:31:00 +0300
committerimarom <imarom@cisco.com>2016-07-03 13:40:19 +0300
commit6535523a2768a5c867fd22b4fa62c7fb43fd9ad8 (patch)
treee6834cbe44dfb738f7a9c45503bde1b73aabadfa
parente7eb06bbeb882d8743ce0018938fb5af61aade2e (diff)
draft #2 for trex client config
-rw-r--r--src/trex_client_config.cpp131
-rw-r--r--src/trex_client_config.h95
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__ */