utl_yaml.cpp revision c39cdf89
1/*
2 Hanoh Haim
3 Cisco Systems, Inc.
4*/
5
6/*
7Copyright (c) 2015-2016 Cisco Systems, Inc.
8
9Licensed under the Apache License, Version 2.0 (the "License");
10you may not use this file except in compliance with the License.
11You may obtain a copy of the License at
12
13    http://www.apache.org/licenses/LICENSE-2.0
14
15Unless required by applicable law or agreed to in writing, software
16distributed under the License is distributed on an "AS IS" BASIS,
17WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18See the License for the specific language governing permissions and
19limitations under the License.
20*/
21
22#include <istream>
23#include <fstream>
24#include "common/basic_utils.h"
25#include <common/Network/Packet/CPktCmn.h>
26#include "utl_yaml.h"
27
28#define INADDRSZ 4
29
30extern int my_inet_pton4(const char *src, unsigned char *dst);
31extern int my_inet_pton6(const char *src, unsigned char *dst);
32
33bool utl_yaml_read_ip_addr(const YAML::Node& node,
34                           const std::string &name,
35                           uint32_t & val){
36    std::string tmp;
37    uint32_t ip;
38    bool res=false;
39    if ( node.FindValue(name) ) {
40        node[name] >> tmp ;
41        if ( my_inet_pton4((char *)tmp.c_str(), (unsigned char *)&ip) ){
42            val=PKT_NTOHL(ip);
43            res=true;
44        }else{
45            printf(" Error: non valid ip %s \n",(char *)tmp.c_str());
46            exit(-1);
47        }
48    }
49    return (res);
50}
51
52bool utl_yaml_read_uint32(const YAML::Node& node,
53                          const std::string &name,
54                          uint32_t & val){
55    bool res=false;
56    if ( node.FindValue(name) ) {
57        node[name] >> val ;
58        res=true;
59    }
60    return (res);
61}
62
63bool utl_yaml_read_uint16(const YAML::Node& node,
64                          const std::string &name,
65                          uint16_t & val){
66    uint32_t val_tmp;
67    bool res=false;
68    if ( node.FindValue(name) ) {
69        node[name] >> val_tmp ;
70        val = (uint16_t)val_tmp;
71        res=true;
72    }
73
74    return (res);
75}
76
77static void
78split_str_by_delimiter(std::string str, char delim, std::vector<std::string> &tokens) {
79    size_t pos = 0;
80    std::string token;
81
82    while ((pos = str.find(delim)) != std::string::npos) {
83        token = str.substr(0, pos);
84        tokens.push_back(token);
85        str.erase(0, pos + 1);
86    }
87
88    if (str.size() > 0) {
89        tokens.push_back(str);
90    }
91}
92
93static bool mac2uint64(const std::string &mac_str, uint64_t &mac_num) {
94    std::vector<std::string> tokens;
95    uint64_t val;
96
97    split_str_by_delimiter(mac_str, ':', tokens);
98    if (tokens.size() != 6) {
99        return false;
100    }
101
102    val = 0;
103
104    for (int i = 0; i < 6 ; i++) {
105        char *endptr = NULL;
106        unsigned long octet = strtoul(tokens[i].c_str(), &endptr, 16);
107
108        if ( (*endptr != 0) || (octet > 0xff) ) {
109            return false;
110        }
111
112        val = (val << 8) + octet;
113    }
114
115    mac_num = val;
116
117    return true;
118}
119
120bool mac2vect(const std::string &mac_str, std::vector<uint8_t> &mac) {
121    std::vector<std::string> tokens;
122
123    split_str_by_delimiter(mac_str, ':', tokens);
124    if (tokens.size() != 6) {
125        return false;
126    }
127
128    for (int i = 0; i < 6 ; i++) {
129        char *endptr = NULL;
130        unsigned long octet = strtoul(tokens[i].c_str(), &endptr, 16);
131
132        if ( (*endptr != 0) || (octet > 0xff) ) {
133            return false;
134        }
135
136        mac.push_back(octet);
137    }
138
139    return true;
140}
141
142/************************
143 * YAML Parser Wrapper
144 *
145 ***********************/
146void
147YAMLParserWrapper::load(YAML::Node &root) {
148    std::stringstream ss;
149
150    /* first check file exists */
151    if (!utl_is_file_exists(m_filename)){
152        ss << "file '" << m_filename << "' does not exists";
153        throw std::runtime_error(ss.str());
154    }
155
156    std::ifstream fin(m_filename);
157
158    try {
159        YAML::Parser base_parser(fin);
160        base_parser.GetNextDocument(root);
161
162    } catch (const YAML::Exception &e) {
163        parse_err(e.what());
164    }
165}
166
167bool
168YAMLParserWrapper::parse_bool(const YAML::Node &node, const std::string &name, bool def) {
169    if (!node.FindValue(name)) {
170        return def;
171    }
172
173    return parse_bool(node, name);
174}
175
176bool
177YAMLParserWrapper::parse_bool(const YAML::Node &node, const std::string &name) {
178    try {
179        bool val;
180        node[name] >> val;
181        return (val);
182
183    } catch (const YAML::InvalidScalar &ex) {
184        parse_err("Expecting true/false for field '" + name + "'", node[name]);
185
186    } catch (const YAML::KeyNotFound &ex) {
187        parse_err("Can not locate mandatory field '" + name + "'", node);
188    }
189
190    assert(0);
191}
192
193const YAML::Node &
194YAMLParserWrapper::parse_list(const YAML::Node &node, const std::string &name) {
195
196    try {
197        const YAML::Node &val = node[name];
198        if (val.Type() != YAML::NodeType::Sequence) {
199            throw YAML::InvalidScalar(node[name].GetMark());
200        }
201        return val;
202
203    } catch (const YAML::InvalidScalar &ex) {
204        parse_err("Expecting sequence or list for field '" + name + "'", node[name]);
205
206    } catch (const YAML::KeyNotFound &ex) {
207        parse_err("Can not locate mandatory field '" + name + "'", node);
208    }
209
210    assert(0);
211}
212
213const YAML::Node &
214YAMLParserWrapper::parse_map(const YAML::Node &node, const std::string &name) {
215
216    try {
217        const YAML::Node &val = node[name];
218        if (val.Type() != YAML::NodeType::Map) {
219            throw YAML::InvalidScalar(node[name].GetMark());
220        }
221        return val;
222
223    } catch (const YAML::InvalidScalar &ex) {
224        parse_err("Expecting map for field '" + name + "'", node[name]);
225
226    } catch (const YAML::KeyNotFound &ex) {
227        parse_err("Can not locate mandatory field '" + name + "'", node);
228    }
229
230    assert(0);
231}
232
233uint32_t
234YAMLParserWrapper::parse_ip(const YAML::Node &node, const std::string &name) {
235    try {
236        std::string ip_str;
237        uint32_t    ip_num;
238
239        node[name] >> ip_str;
240        int rc = my_inet_pton4((char *)ip_str.c_str(), (unsigned char *)&ip_num);
241        if (!rc) {
242            parse_err("Invalid IP address: " + ip_str, node[name]);
243        }
244
245        return PKT_NTOHL(ip_num);
246
247    } catch (const YAML::InvalidScalar &ex) {
248        parse_err("Expecting valid IP address for field '" + name + "'", node[name]);
249
250    } catch (const YAML::KeyNotFound &ex) {
251        parse_err("Can not locate mandatory field '" + name + "'", node);
252    }
253
254    assert(0);
255}
256
257void
258YAMLParserWrapper::parse_ipv6(const YAML::Node &node, const std::string &name, unsigned char *ip_num) {
259    try {
260        std::string ip_str;
261
262        node[name] >> ip_str;
263        int rc = my_inet_pton6((char *)ip_str.c_str(), ip_num);
264        if (!rc) {
265            parse_err("Invalid IPv6 address: " + ip_str, node[name]);
266        }
267
268        // we want host order
269        for (int i = 0; i < 8; i++) {
270            ((uint16_t *) ip_num)[i] = PKT_NTOHS(((uint16_t *) ip_num)[i]);
271        }
272        return;
273
274    } catch (const YAML::InvalidScalar &ex) {
275        parse_err("Expecting valid IPv6 address for field '" + name + "'", node[name]);
276
277    } catch (const YAML::KeyNotFound &ex) {
278        parse_err("Can not locate mandatory field '" + name + "'", node);
279    }
280
281    assert(0);
282}
283
284uint64_t
285YAMLParserWrapper::parse_mac_addr(const YAML::Node &node, const std::string &name, uint64_t def) {
286    if (!node.FindValue(name)) {
287        return def;
288    }
289
290    return parse_mac_addr(node, name);
291}
292
293uint64_t
294YAMLParserWrapper::parse_mac_addr(const YAML::Node &node, const std::string &name) {
295
296    std::string mac_str;
297    uint64_t    mac_num;
298
299    try {
300
301        node[name] >> mac_str;
302        bool rc = mac2uint64(mac_str, mac_num);
303        if (!rc) {
304            parse_err("Invalid MAC address: " + mac_str, node[name]);
305        }
306        return mac_num;
307
308    } catch (const YAML::InvalidScalar &ex) {
309        parse_err("Expecting true/false for field '" + name + "'", node[name]);
310
311    } catch (const YAML::KeyNotFound &ex) {
312        parse_err("Can not locate mandatory field '" + name + "'", node);
313    }
314
315    assert(0);
316}
317
318uint64_t
319YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, uint64_t low, uint64_t high, uint64_t def) {
320    if (!node.FindValue(name)) {
321        return def;
322    }
323
324    return parse_uint(node, name, low, high);
325}
326
327uint64_t
328YAMLParserWrapper::parse_uint(const YAML::Node &node, const std::string &name, uint64_t low, uint64_t high) {
329
330    try {
331
332        uint64_t val;
333        node[name] >> val;
334
335        if ( (val < low) || (val > high) ) {
336            std::stringstream ss;
337            ss << "valid range for field '" << name << "' is: [" << low << " - " << high << "]";
338            parse_err(ss.str(), node[name]);
339        }
340
341        return (val);
342
343    } catch (const YAML::InvalidScalar &ex) {
344        parse_err("Expecting true/false for field '" + name + "'", node[name]);
345
346    } catch (const YAML::KeyNotFound &ex) {
347        parse_err("Can not locate mandatory field '" + name + "'", node);
348    }
349
350    assert(0);
351}
352
353void
354YAMLParserWrapper::parse_err(const std::string &err, const YAML::Node &node) const {
355    std::stringstream ss;
356
357    ss << "'" << m_filename << "' - YAML parsing error at line " << node.GetMark().line << ": ";
358    ss << err;
359
360    throw std::runtime_error(ss.str());
361}
362
363void
364YAMLParserWrapper::parse_err(const std::string &err) const {
365    std::stringstream ss;
366
367    ss << "'" << m_filename << "' - YAML parsing error: " << err;
368
369    throw std::runtime_error(ss.str());
370}
371