diff options
author | 2016-06-29 10:35:54 +0300 | |
---|---|---|
committer | 2016-07-03 13:40:21 +0300 | |
commit | 1dfd42ceb79677e171d5dedcac34900776574000 (patch) | |
tree | ed1dfd5964d6fb2cde139a55f4ef482005edb13e /src | |
parent | f03fa158116cfd65659d14698c91446dc9bdb4c4 (diff) |
added enhanced parsing for the YAML wrapper module
Diffstat (limited to 'src')
-rwxr-xr-x | src/bp_sim.cpp | 10 | ||||
-rw-r--r-- | src/mac_mapping.h | 62 | ||||
-rwxr-xr-x | src/main.cpp | 36 | ||||
-rw-r--r-- | src/main_dpdk.cpp | 22 | ||||
-rw-r--r-- | src/trex_client_config.cpp | 128 | ||||
-rw-r--r-- | src/trex_client_config.h | 49 | ||||
-rwxr-xr-x | src/tuple_gen.cpp | 23 | ||||
-rwxr-xr-x | src/tuple_gen.h | 4 | ||||
-rwxr-xr-x | src/utl_yaml.cpp | 225 | ||||
-rwxr-xr-x | src/utl_yaml.h | 37 |
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 |