summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimarom <imarom@cisco.com>2016-06-29 10:35:54 +0300
committerimarom <imarom@cisco.com>2016-07-03 13:40:21 +0300
commit1dfd42ceb79677e171d5dedcac34900776574000 (patch)
treeed1dfd5964d6fb2cde139a55f4ef482005edb13e
parentf03fa158116cfd65659d14698c91446dc9bdb4c4 (diff)
added enhanced parsing for the YAML wrapper module
-rwxr-xr-xsrc/bp_sim.cpp10
-rw-r--r--src/mac_mapping.h62
-rwxr-xr-xsrc/main.cpp36
-rw-r--r--src/main_dpdk.cpp22
-rw-r--r--src/trex_client_config.cpp128
-rw-r--r--src/trex_client_config.h49
-rwxr-xr-xsrc/tuple_gen.cpp23
-rwxr-xr-xsrc/tuple_gen.h4
-rwxr-xr-xsrc/utl_yaml.cpp225
-rwxr-xr-xsrc/utl_yaml.h37
10 files changed, 373 insertions, 223 deletions
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index abedf95c..2ebffb0d 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -5042,7 +5042,7 @@ void CErfIF::add_vlan(uint16_t vlan_id) {
/* 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);
+ memcpy(buffer + 12, cbuff, m_raw->pkt_len - 8);
m_raw->pkt_len += 4;
}
@@ -5052,11 +5052,11 @@ void CErfIF::apply_client_config(CGenNode *node, pkt_dir_t dir) {
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;
+ memcpy(p, node->m_client_cfg->m_initiator.m_dst_mac, 6);
+ vlan_id = node->m_client_cfg->m_responder.m_vlan;
} else {
- memcpy(p, node->m_client_cfg->m_res_mac, 6);
- vlan_id = node->m_client_cfg->m_res_vlan;
+ memcpy(p, node->m_client_cfg->m_responder.m_dst_mac, 6);
+ vlan_id = node->m_client_cfg->m_responder.m_vlan;
}
add_vlan(vlan_id);
diff --git a/src/mac_mapping.h b/src/mac_mapping.h
deleted file mode 100644
index ed9c5d88..00000000
--- a/src/mac_mapping.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef MAC_MAPPING_H_
-#define MAC_MAPPING_H_
-#if 0
-#define INUSED 0
-#define UNUSED 1
-typedef struct mac_addr_align_ {
-public:
- uint8_t mac[6];
- uint8_t inused;
- uint8_t pad;
-} mac_addr_align_t;
-
-typedef struct mac_mapping_ {
- mac_addr_align_t mac;
- uint32_t ip;
-} mac_mapping_t;
-
-class CFlowGenListMac {
-public:
- CFlowGenListMac() {
- set_configured(false);
- }
-
- std::map<uint32_t, mac_addr_align_t> &
- get_mac_info () {
- return m_mac_info;
- }
-
- bool is_configured() {
- return is_mac_info_configured;
- }
-
- void set_configured(bool is_conf) {
- is_mac_info_configured = is_conf;
- }
-
- void clear() {
- set_configured(false);
- m_mac_info.clear();
- }
-
- uint32_t is_mac_exist(uint32_t ip) {
- if (is_configured()) {
- return m_mac_info.count(ip);
- } else {
- return 0;
- }
- }
- mac_addr_align_t* get_mac_addr_by_ip(uint32_t ip) {
- if (is_mac_exist(ip)!=0) {
- return &(m_mac_info[ip]);
- }
- return NULL;
- }
-private:
- bool is_mac_info_configured;
- std::map<uint32_t, mac_addr_align_t> 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 90e48549..de6cef45 100755
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -36,7 +36,7 @@ using namespace std;
// An enum for all the option types
enum { OPT_HELP, OPT_CFG, OPT_NODE_DUMP, OP_STATS,
- OPT_FILE_OUT, OPT_UT, OPT_PCAP, OPT_IPV6, OPT_MAC_FILE,
+ OPT_FILE_OUT, OPT_UT, OPT_PCAP, OPT_IPV6, OPT_CLIENT_CFG_FILE,
OPT_SL, OPT_DP_CORE_COUNT, OPT_DP_CORE_INDEX, OPT_LIMIT,
OPT_DRY_RUN};
@@ -62,22 +62,22 @@ typedef enum {
*/
static CSimpleOpt::SOption parser_options[] =
{
- { OPT_HELP, "-?", SO_NONE },
- { OPT_HELP, "-h", SO_NONE },
- { OPT_HELP, "--help", SO_NONE },
- { OPT_UT, "--ut", SO_NONE },
- { OP_STATS, "-s", SO_NONE },
- { OPT_CFG, "-f", SO_REQ_SEP },
- { OPT_MAC_FILE, "--mac", SO_REQ_SEP },
- { OPT_FILE_OUT , "-o", SO_REQ_SEP },
- { OPT_NODE_DUMP , "-v", SO_REQ_SEP },
- { OPT_PCAP, "--pcap", SO_NONE },
- { OPT_IPV6, "--ipv6", SO_NONE },
- { OPT_SL, "--sl", SO_NONE },
- { OPT_DP_CORE_COUNT, "--cores", SO_REQ_SEP },
- { OPT_DP_CORE_INDEX, "--core_index", SO_REQ_SEP },
- { OPT_LIMIT, "--limit", SO_REQ_SEP },
- { OPT_DRY_RUN, "--dry", SO_NONE },
+ { OPT_HELP, "-?", SO_NONE },
+ { OPT_HELP, "-h", SO_NONE },
+ { OPT_HELP, "--help", SO_NONE },
+ { OPT_UT, "--ut", SO_NONE },
+ { OP_STATS, "-s", SO_NONE },
+ { OPT_CFG, "-f", SO_REQ_SEP },
+ { OPT_CLIENT_CFG_FILE, "--client_cfg", SO_REQ_SEP },
+ { OPT_FILE_OUT , "-o", SO_REQ_SEP },
+ { OPT_NODE_DUMP , "-v", SO_REQ_SEP },
+ { OPT_PCAP, "--pcap", SO_NONE },
+ { OPT_IPV6, "--ipv6", SO_NONE },
+ { OPT_SL, "--sl", SO_NONE },
+ { OPT_DP_CORE_COUNT, "--cores", SO_REQ_SEP },
+ { OPT_DP_CORE_INDEX, "--core_index", SO_REQ_SEP },
+ { OPT_LIMIT, "--limit", SO_REQ_SEP },
+ { OPT_DRY_RUN, "--dry", SO_NONE },
SO_END_OF_OPTIONS
@@ -160,7 +160,7 @@ static int parse_options(int argc,
po->cfg_file = args.OptionArg();
break;
- case OPT_MAC_FILE:
+ case OPT_CLIENT_CFG_FILE:
po->client_cfg_file = args.OptionArg();
break;
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index ad9858a2..0200df92 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -547,7 +547,7 @@ enum { OPT_HELP,
OPT_L_PKT_MODE,
OPT_NO_FLOW_CONTROL,
OPT_RX_CHECK_HOPS,
- OPT_MAC_FILE,
+ OPT_CLIENT_CFG_FILE,
OPT_NO_KEYBOARD_INPUT,
OPT_VLAN,
OPT_VIRT_ONE_TX_RX_QUEUE,
@@ -611,7 +611,7 @@ static CSimpleOpt::SOption parser_options[] =
{ OPT_L_PKT_MODE, "--l-pkt-mode", SO_REQ_SEP },
{ OPT_NO_FLOW_CONTROL, "--no-flow-control-change", SO_NONE },
{ OPT_VLAN, "--vlan", SO_NONE },
- { OPT_MAC_FILE, "--mac", SO_REQ_SEP },
+ { OPT_CLIENT_CFG_FILE, "--client_cfg", SO_REQ_SEP },
{ OPT_NO_KEYBOARD_INPUT ,"--no-key", SO_NONE },
{ OPT_VIRT_ONE_TX_RX_QUEUE, "--vm-sim", SO_NONE },
{ OPT_PREFIX, "--prefix", SO_REQ_SEP },
@@ -641,7 +641,7 @@ static int usage(){
printf(" options \n\n");
- printf(" --mac [file] : YAML file with <client ip, mac addr> configuration \n");
+ printf(" --client_cfg [file] : YAML file which describes clients configuration\n");
printf(" \n\n");
printf(" -c [number of threads] : default is 1. number of threads to allocate for each dual ports. \n");
printf(" \n");
@@ -825,8 +825,8 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
po->preview.set_no_keyboard(true);
break;
- case OPT_MAC_FILE :
- po->mac_file = args.OptionArg();
+ case OPT_CLIENT_CFG_FILE :
+ po->client_cfg_file = args.OptionArg();
break;
case OPT_PLAT_CFG_FILE :
@@ -1011,11 +1011,13 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
parse_err(ss.str());
}
- 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");
- }
+ if (CGlobalInfo::is_learn_mode() && 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");
+ }
+
+ if (CGlobalInfo::get_vlan_mode_enable() && (po->client_cfg_file != "") ) {
+ parse_err("--vlan and --client_cfg cannot be combined");
}
if (po->preview.get_is_rx_check_enable() || po->is_latency_enabled() || CGlobalInfo::is_learn_mode()) {
diff --git a/src/trex_client_config.cpp b/src/trex_client_config.cpp
index 9a5e4f6f..e726d47d 100644
--- a/src/trex_client_config.cpp
+++ b/src/trex_client_config.cpp
@@ -38,19 +38,19 @@ ClientCfgEntry::dump() const {
std::cout << "Init. MAC addr: ";
for (int i = 0; i < 6; i++) {
- printf("%lx:", ( (m_init_mac >> ( (6-i) * 8)) & 0xFF ) );
+ printf("%lx:", ( (m_initiator.m_dst_mac >> ( (6-i) * 8)) & 0xFF ) );
}
std::cout << "\n";
- std::cout << "Init. VLAN: " << m_init_vlan << "\n";
+ std::cout << "Init. VLAN: " << m_initiator.m_vlan << "\n";
std::cout << "Res. MAC addr: ";
for (int i = 0; i < 6; i++) {
- printf("%lx:", ( (m_res_mac >> ( (6-i) * 8)) & 0xFF ) );
+ printf("%lx:", ( (m_responder.m_dst_mac >> ( (6-i) * 8)) & 0xFF ) );
}
std::cout << "\n";
- std::cout << "Res. VLAN: " << m_res_vlan << "\n";
+ std::cout << "Res. VLAN: " << m_responder.m_vlan << "\n";
}
@@ -63,6 +63,9 @@ void
ClientCfgDB::load_yaml_file(const std::string &filename) {
std::stringstream ss;
+ m_groups.clear();
+ m_cache_group = NULL;
+
m_filename = filename;
if (!utl_is_file_exists(filename)){
@@ -71,61 +74,87 @@ ClientCfgDB::load_yaml_file(const std::string &filename) {
}
std::ifstream fin(filename);
- YAML::Parser parser(fin);
+ YAML::Parser base_parser(fin);
YAML::Node root;
- parser.GetNextDocument(root);
+ /* parse the YAML */
+ 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()));
- for (int i = 0; i < root.size(); i++) {
- const YAML::Mark &mark = root[i].GetMark();
- ClientCfgEntry group;
- bool rc;
+ }
- /* ip_start */
- rc = utl_yaml_read_ip_addr(root[i], "ip_start", group.m_ip_start);
- if (!rc) {
- yaml_parse_err("'ip_start' field does not exists", &mark);
- }
+ /* wrapper parser */
+ YAMLParserWrapper parser(m_filename);
- /* ip_end */
- rc = utl_yaml_read_ip_addr(root[i], "ip_end", group.m_ip_end);
- if (!rc) {
- yaml_parse_err("'ip_end' field does not exists", &mark);
- }
+ /* parse globals */
+ m_under_vlan = parser.parse_bool(root, "vlan");
- /* 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);
- }
+ const YAML::Node &groups = parser.parse_list(root, "groups");
- /* init_mac */
- rc = utl_yaml_read_mac_addr(root[i], "init_mac", group.m_init_mac);
- if (!rc) {
- yaml_parse_err("'init_mac' field does not exists", &mark);
- }
+ /* parse each group */
+ for (int i = 0; i < groups.size(); i++) {
+ parse_single_group(parser, groups[i]);
+ }
- /* res_mac */
- rc = utl_yaml_read_mac_addr(root[i], "res_mac", group.m_res_mac);
- if (!rc) {
- yaml_parse_err("'res_mac' field does not exists", &mark);
- }
+ verify();
+ m_is_empty = false;
- root[i]["init_vlan"] >> group.m_init_vlan;
- root[i]["res_vlan"] >> group.m_res_vlan;
- root[i]["count"] >> group.m_count;
+}
+/**
+ * reads a single group of clients from YAML
+ *
+ */
+void
+ClientCfgDB::parse_single_group(YAMLParserWrapper &parser, const YAML::Node &node) {
+ ClientCfgEntry group;
- /* add to map with copying */
- m_groups[group.m_ip_start] = group;
+ /* ip_start */
+ group.m_ip_start = parser.parse_ip(node, "ip_start");
+
+ /* ip_end */
+ group.m_ip_end = parser.parse_ip(node, "ip_end");
+
+ /* sanity check */
+ if (group.m_ip_end < group.m_ip_start) {
+ parser.parse_err("ip_end must be >= ip_start", node);
}
- verify();
+ const YAML::Node &init = parser.parse_map(node, "initiator");
+ const YAML::Node &resp = parser.parse_map(node, "responder");
- m_is_empty = false;
+ /* parse MACs */
+ group.m_initiator.m_dst_mac = parser.parse_mac_addr(init, "dst_mac");
+ group.m_responder.m_dst_mac = parser.parse_mac_addr(resp, "dst_mac");
+
+ if (m_under_vlan) {
+ group.m_initiator.m_vlan = parser.parse_uint(init, "vlan", 0, 0xfff);
+ group.m_responder.m_vlan = parser.parse_uint(resp, "vlan", 0, 0xfff);
+ } else {
+ if (init.FindValue("vlan")) {
+ parser.parse_err("VLAN config was disabled", init["vlan"]);
+ }
+ if (resp.FindValue("vlan")) {
+ parser.parse_err("VLAN config was disabled", resp["vlan"]);
+ }
+ }
+
+
+ group.m_count = parser.parse_uint(node, "count");
+
+ /* add to map with copying */
+ m_groups[group.m_ip_start] = group;
}
+/**
+ * sanity checks
+ *
+ * @author imarom (28-Jun-16)
+ */
void
ClientCfgDB::verify() const {
std::stringstream ss;
@@ -133,6 +162,7 @@ ClientCfgDB::verify() const {
/* check that no interval overlaps */
+ /* all intervals do not overloap iff when sorted each start/end dots are strong monotonic */
for (const auto &p : m_groups) {
const ClientCfgEntry &group = p.second;
@@ -153,13 +183,17 @@ ClientCfgDB::verify() const {
ClientCfgEntry *
ClientCfgDB::lookup(uint32_t ip) {
- /* check the cache */
+ /* a cache to avoid constant search (usually its a range of IPs) */
if ( (m_cache_group) && (m_cache_group->contains(ip)) ) {
return m_cache_group;
}
+ /* clear the cache pointer */
+ m_cache_group = NULL;
+
std::map<uint32_t ,ClientCfgEntry>::iterator it;
+ /* upper bound fetchs the first greater element */
it = m_groups.upper_bound(ip);
/* if the first element in the map is bigger - its not in the map */
@@ -188,6 +222,15 @@ ClientCfgDB::lookup(uint32_t ip) {
}
+/**
+ * for convenience - search by IP as string
+ *
+ * @author imarom (28-Jun-16)
+ *
+ * @param ip
+ *
+ * @return ClientCfgEntry*
+ */
ClientCfgEntry *
ClientCfgDB::lookup(const std::string &ip) {
uint32_t addr = (uint32_t)inet_addr(ip.c_str());
@@ -210,3 +253,4 @@ ClientCfgDB::yaml_parse_err(const std::string &err, const YAML::Mark *mark) cons
ss << err;
throw std::runtime_error(ss.str());
}
+
diff --git a/src/trex_client_config.h b/src/trex_client_config.h
index f934517d..b6e7d32d 100644
--- a/src/trex_client_config.h
+++ b/src/trex_client_config.h
@@ -25,19 +25,21 @@ limitations under the License.
#include <string>
#include <map>
+class YAMLParserWrapper;
+
/**
* 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;
-
+ struct dir_st {
+ uint8_t m_dst_mac[6];
+ uint16_t m_vlan;
+ };
+
+ dir_st m_initiator;
+ dir_st m_responder;
};
/**
@@ -73,15 +75,16 @@ public:
*/
void assign(ClientCfg &info) {
+ /* assigns MAC addrs as big endian */
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_initiator.m_dst_mac[i] = ( (m_initiator.m_dst_mac + m_iterator) >> ((5 - i) * 8) ) & 0xFF;
+ info.m_responder.m_dst_mac[i] = ( (m_responder.m_dst_mac + m_iterator) >> ((5 - i) * 8) ) & 0xFF;
}
- info.m_init_vlan = m_init_vlan;
- info.m_res_vlan = m_res_vlan;
+ info.m_initiator.m_vlan = m_initiator.m_vlan;
+ info.m_responder.m_vlan = m_responder.m_vlan;
- /* advance */
+ /* advance for the next assign */
m_iterator = (m_iterator + 1) % m_count;
}
@@ -89,28 +92,32 @@ public:
uint32_t m_ip_start;
uint32_t m_ip_end;
- uint64_t m_init_mac;
- uint16_t m_init_vlan;
+ struct cfg_dir_st {
+ //uint64_t m_src_mac;
+ uint64_t m_dst_mac;
+ uint16_t m_vlan;
+ };
- uint64_t m_res_mac;
- uint16_t m_res_vlan;
+ cfg_dir_st m_initiator;
+ cfg_dir_st m_responder;
- uint32_t m_count;
+ uint32_t m_count;
private:
uint32_t m_iterator;
};
/**
- * describes the DB of every client group
+ * holds all the configured clients groups
*
*/
class ClientCfgDB {
public:
ClientCfgDB() {
- m_is_empty = true;
+ m_is_empty = true;
m_cache_group = NULL;
+ m_under_vlan = false;
}
/**
@@ -139,7 +146,7 @@ public:
ClientCfgEntry * lookup(const std::string &ip);
private:
-
+ void parse_single_group(YAMLParserWrapper &parser, const YAML::Node &node);
void yaml_parse_err(const std::string &err, const YAML::Mark *mark = NULL) const;
/**
@@ -150,6 +157,8 @@ private:
/* maps the IP start value to client groups */
std::map<uint32_t, ClientCfgEntry> m_groups;
+ 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 c964955a..b8a54118 100755
--- a/src/tuple_gen.cpp
+++ b/src/tuple_gen.cpp
@@ -121,7 +121,7 @@ void CClientPool::allocate_simple_clients(uint32_t min_ip,
void CClientPool::allocate_configured_clients(uint32_t min_ip,
uint32_t total_ip,
bool is_long_range,
- ClientCfgDB &client_info) {
+ ClientCfgDB &client_info) {
for (uint32_t i = 0; i < total_ip; i++) {
uint32_t ip = min_ip + i;
@@ -129,8 +129,9 @@ void CClientPool::allocate_configured_clients(uint32_t min_ip,
/* 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);
+ std::stringstream ss;
+ ss << "*** client configuration error: could not map IP '" << ip_to_str(ip) << "' to a group\n";
+ throw std::runtime_error(ss.str());
}
ClientCfg info;
@@ -145,14 +146,14 @@ void CClientPool::allocate_configured_clients(uint32_t min_ip,
}
-bool CTupleGeneratorSmart::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 CTupleGeneratorSmart::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) {
assert(max_client>=min_client);
CClientPool* pool = new CClientPool();
pool->Create(client_dist,
diff --git a/src/tuple_gen.h b/src/tuple_gen.h
index 292d1794..2491f489 100755
--- a/src/tuple_gen.h
+++ b/src/tuple_gen.h
@@ -37,7 +37,6 @@ limitations under the License.
#include "common/c_common.h"
#include <bitset>
#include <yaml-cpp/yaml.h>
-#include <mac_mapping.h>
#include "trex_client_config.h"
#include <random>
@@ -670,8 +669,8 @@ public:
public:
CTupleGeneratorSmart(){
m_was_init=false;
- m_has_mac_mapping = false;
}
+
bool Create(uint32_t _id, uint32_t thread_id);
void Delete();
@@ -722,7 +721,6 @@ private:
std::vector<CClientPool*> m_client_pool;
std::vector<CServerPoolBase*> m_server_pool;
bool m_was_init;
- bool m_has_mac_mapping;
};
class CTupleTemplateGeneratorSmart {
diff --git a/src/utl_yaml.cpp b/src/utl_yaml.cpp
index bf30d661..22772ffe 100755
--- a/src/utl_yaml.cpp
+++ b/src/utl_yaml.cpp
@@ -83,6 +83,33 @@ bool utl_yaml_read_ip_addr(const YAML::Node& node,
return (res);
}
+
+
+bool utl_yaml_read_uint32(const YAML::Node& node,
+ const std::string &name,
+ uint32_t & val){
+ bool res=false;
+ if ( node.FindValue(name) ) {
+ node[name] >> val ;
+ res=true;
+ }
+ return (res);
+}
+
+bool utl_yaml_read_uint16(const YAML::Node& node,
+ const std::string &name,
+ uint16_t & val){
+ uint32_t val_tmp;
+ bool res=false;
+ if ( node.FindValue(name) ) {
+ node[name] >> val_tmp ;
+ val = (uint16_t)val_tmp;
+ res=true;
+ }
+
+ return (res);
+}
+
static void
split_str_by_delimiter(std::string str, char delim, std::vector<std::string> &tokens) {
size_t pos = 0;
@@ -99,23 +126,13 @@ split_str_by_delimiter(std::string str, char delim, std::vector<std::string> &to
}
}
-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;
-
+static bool mac2uint64(const std::string &mac_str, uint64_t &mac_num) {
std::vector<std::string> tokens;
- split_str_by_delimiter(mac_str, ':', tokens);
+ uint64_t val;
+ split_str_by_delimiter(mac_str, ':', tokens);
if (tokens.size() != 6) {
- throw YAML::InvalidScalar(node[name].GetMark());
+ return false;
}
val = 0;
@@ -125,51 +142,171 @@ bool utl_yaml_read_mac_addr(const YAML::Node &node,
unsigned long octet = strtoul(tokens[i].c_str(), &endptr, 16);
if ( (*endptr != 0) || (octet > 0xff) ) {
- throw YAML::InvalidScalar(node[name].GetMark());
+ return false;
}
- //mac_addr[i] = (uint8_t)octet;
val = (val << 8) + octet;
- }
-
+ }
+
+ mac_num = val;
+
return true;
}
+/************************
+ * YAML Parser Wrapper
+ *
+ ***********************/
+bool
+YAMLParserWrapper::parse_bool(const YAML::Node &node, const std::string &name, bool def) {
+ if (!node.FindValue(name)) {
+ return def;
+ }
-bool utl_yaml_read_uint32(const YAML::Node& node,
- const std::string &name,
- uint32_t & val){
- bool res=false;
- if ( node.FindValue(name) ) {
- node[name] >> val ;
- res=true;
+ return parse_bool(node, name);
+}
+
+bool
+YAMLParserWrapper::parse_bool(const YAML::Node &node, const std::string &name) {
+ try {
+ bool val;
+ node[name] >> val;
+ return (val);
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting true/false for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
}
- return (res);
+
+ assert(0);
}
-bool utl_yaml_read_uint16(const YAML::Node& node,
- const std::string &name,
- uint16_t & val){
- uint32_t val_tmp;
- bool res=false;
- if ( node.FindValue(name) ) {
- node[name] >> val_tmp ;
- val = (uint16_t)val_tmp;
- res=true;
+const YAML::Node &
+YAMLParserWrapper::parse_list(const YAML::Node &node, const std::string &name) {
+
+ try {
+ const YAML::Node &val = node[name];
+ if (val.Type() != YAML::NodeType::Sequence) {
+ throw YAML::InvalidScalar(node[name].GetMark());
+ }
+ return val;
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting sequence/list for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
}
- return (res);
+ assert(0);
}
-bool utl_yaml_read_bool(const YAML::Node& node,
- const std::string &name,
- bool & val){
- bool res=false;
- if ( node.FindValue(name) ) {
- node[name] >> val ;
- res=true;
+const YAML::Node &
+YAMLParserWrapper::parse_map(const YAML::Node &node, const std::string &name) {
+
+ try {
+ const YAML::Node &val = node[name];
+ if (val.Type() != YAML::NodeType::Map) {
+ throw YAML::InvalidScalar(node[name].GetMark());
+ }
+ return val;
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting map for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
+}
+
+uint32_t
+YAMLParserWrapper::parse_ip(const YAML::Node &node, const std::string &name) {
+
+
+ try {
+ std::string ip_str;
+ uint32_t ip_num;
+
+ node[name] >> ip_str;
+ int rc = my_inet_pton4((char *)ip_str.c_str(), (unsigned char *)&ip_num);
+ if (!rc) {
+ parse_err("invalid IP address: " + ip_str, node[name]);
+ }
+
+ return PKT_NTOHL(ip_num);
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting valid IP address for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
}
- return( res);
+
+ assert(0);
+}
+
+uint64_t
+YAMLParserWrapper::parse_mac_addr(const YAML::Node &node, const std::string &name) {
+
+ std::string mac_str;
+ uint64_t mac_num;
+
+ try {
+
+ node[name] >> mac_str;
+ bool rc = mac2uint64(mac_str, mac_num);
+ if (!rc) {
+ parse_err("invalid MAC address: " + mac_str, node[name]);
+ }
+ return mac_num;
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting true/false for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
}
+uint64_t
+YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, uint64_t low, uint64_t high) {
+
+ try {
+
+ uint64_t val;
+ node[name] >> val;
+
+ if ( (val < low) || (val > high) ) {
+ std::stringstream ss;
+ ss << "valid range for field '" << name << "' is: [" << low << " - " << high << "]";
+ parse_err(ss.str(), node[name]);
+ }
+
+ return (val);
+
+ } catch (const YAML::InvalidScalar &ex) {
+ parse_err("expecting true/false for field '" + name + "'", node[name]);
+
+ } catch (const YAML::KeyNotFound &ex) {
+ parse_err("cannot locate mandatory field '" + name + "'", node);
+ }
+
+ assert(0);
+}
+
+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 << err;
+
+ throw std::runtime_error(ss.str());
+}
diff --git a/src/utl_yaml.h b/src/utl_yaml.h
index 1ada1d66..8088c497 100755
--- a/src/utl_yaml.h
+++ b/src/utl_yaml.h
@@ -24,16 +24,13 @@ limitations under the License.
#include <stdint.h>
#include <yaml-cpp/yaml.h>
-
+
+/* static methods - please prefer the wrapper over those */
bool utl_yaml_read_ip_addr(const YAML::Node& node,
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,
const std::string &name,
uint32_t & val);
@@ -42,9 +39,33 @@ bool utl_yaml_read_uint16(const YAML::Node& node,
const std::string &name,
uint16_t & val);
-bool utl_yaml_read_bool(const YAML::Node& node,
- const std::string &name,
- bool & val);
+/* a thin wrapper to customize errors */
+class YAMLParserWrapper {
+public:
+ /* a header that will start every error message */
+ YAMLParserWrapper(const std::string &header) : m_header(header) {
+ }
+
+ /* bool */
+ bool parse_bool(const YAML::Node &node, const std::string &name);
+ bool parse_bool(const YAML::Node &node, const std::string &name, bool def);
+
+ const YAML::Node & parse_list(const YAML::Node &node, const std::string &name);
+ const YAML::Node & parse_map(const YAML::Node &node, const std::string &name);
+
+ uint32_t parse_ip(const YAML::Node &node, const std::string &name);
+ uint64_t parse_mac_addr(const YAML::Node &node, const std::string &name);
+
+ uint64_t parse_uint(const YAML::Node &node, const std::string &name, uint64_t low = 0, uint64_t high = UINT64_MAX);
+
+
+public:
+ void parse_err(const std::string &err, const YAML::Node &node) const;
+
+
+private:
+ std::string m_header;
+};
#endif