config_parser.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <stdint.h>
  15. #include <iostream>
  16. #include <vector>
  17. #include <map>
  18. #include <boost/foreach.hpp>
  19. #include <boost/shared_ptr.hpp>
  20. #include <boost/scoped_ptr.hpp>
  21. #include <boost/lexical_cast.hpp>
  22. #include <boost/algorithm/string.hpp>
  23. #include <cc/data.h>
  24. #include <asiolink/io_address.h>
  25. #include <dhcp6/config_parser.h>
  26. #include <dhcp/triplet.h>
  27. #include <dhcp/pool.h>
  28. #include <dhcp/subnet.h>
  29. #include <dhcp/cfgmgr.h>
  30. using namespace std;
  31. using namespace isc::data;
  32. using namespace isc::asiolink;
  33. namespace isc {
  34. namespace dhcp {
  35. typedef boost::shared_ptr<Dhcp6ConfigParser> ParserPtr;
  36. typedef pair<string, ConstElementPtr> ConfigPair;
  37. typedef std::vector<ParserPtr> ParserCollection;
  38. typedef Dhcp6ConfigParser* ParserFactory(const std::string& config_id);
  39. typedef std::map<std::string, ParserFactory*> FactoryMap;
  40. typedef std::map<string, uint32_t> Uint32Storage;
  41. /// @brief That is a map with global parameters that will be used as defaults
  42. Uint32Storage uint32_defaults;
  43. typedef std::map<string, string> StringStorage;
  44. StringStorage string_defaults;
  45. typedef std::vector<Pool6Ptr> PoolStorage;
  46. PoolStorage pool_defaults;
  47. /// @brief a dummy configuration parser
  48. ///
  49. /// It is a debugging parser. It does not configure anything,
  50. /// will accept any configuration and will just print it out
  51. /// on commit.
  52. class DummyParser : public Dhcp6ConfigParser {
  53. public:
  54. DummyParser(const std::string& param_name)
  55. :param_name_(param_name) {
  56. }
  57. virtual void build(ConstElementPtr new_config) {
  58. value_ = new_config;
  59. }
  60. virtual void commit() {
  61. // debug message. The whole DummyParser class is used only for parser
  62. // debugging, and is not used in production code. It is very convenient
  63. // to keep it around. Please do not turn this cout into logger calls
  64. std::cout << "Commit for token: [" << param_name_ << "] = ["
  65. << value_->str() << "]" << std::endl;
  66. }
  67. static Dhcp6ConfigParser* Factory(const std::string& param_name) {
  68. return (new DummyParser(param_name));
  69. }
  70. protected:
  71. std::string param_name_;
  72. ConstElementPtr value_;
  73. };
  74. class Uint32Parser : public Dhcp6ConfigParser {
  75. public:
  76. Uint32Parser(const std::string& param_name)
  77. :storage_(&uint32_defaults), param_name_(param_name) {
  78. }
  79. virtual void build(ConstElementPtr value) {
  80. try {
  81. value_ = boost::lexical_cast<uint32_t>(value->str());
  82. } catch (const boost::bad_lexical_cast &) {
  83. isc_throw(BadValue, "Failed to parse value " << value->str()
  84. << " as unsigned 32-bit integer.");
  85. }
  86. cout << "### storing " << param_name_ << "=" << value_ <<
  87. " in " << storage_ << endl;
  88. storage_->insert(pair<string, uint32_t>(param_name_, value_));
  89. }
  90. virtual void commit() {
  91. }
  92. static Dhcp6ConfigParser* Factory(const std::string& param_name) {
  93. return (new Uint32Parser(param_name));
  94. }
  95. void setStorage(Uint32Storage* storage) {
  96. storage_ = storage;
  97. }
  98. protected:
  99. Uint32Storage * storage_;
  100. std::string param_name_;
  101. uint32_t value_;
  102. };
  103. class StringParser : public Dhcp6ConfigParser {
  104. public:
  105. StringParser(const std::string& param_name)
  106. :storage_(&string_defaults), param_name_(param_name) {
  107. }
  108. virtual void build(ConstElementPtr value) {
  109. value_ = value->str();
  110. boost::erase_all(value_, "\"");
  111. storage_->insert(pair<string, string>(param_name_, value_));
  112. }
  113. virtual void commit() {
  114. }
  115. static Dhcp6ConfigParser* Factory(const std::string& param_name) {
  116. return (new StringParser(param_name));
  117. }
  118. void setStorage(StringStorage * storage) {
  119. storage_ = storage;
  120. }
  121. protected:
  122. StringStorage * storage_;
  123. std::string param_name_;
  124. std::string value_;
  125. };
  126. class InterfaceListConfigParser : public Dhcp6ConfigParser {
  127. public:
  128. InterfaceListConfigParser(const std::string& param_name) {
  129. if (param_name != "interface") {
  130. isc_throw(NotImplemented, "Internal error. Interface configuration "
  131. "parser called for the wrong parameter: " << param_name);
  132. }
  133. }
  134. virtual void build(ConstElementPtr value) {
  135. BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
  136. interfaces_.push_back(iface->str());
  137. cout << "#### Configured to listen on interface " << iface->str() << endl;
  138. }
  139. }
  140. virtual void commit() {
  141. /// @todo: Implement per interface listening. Currently always listening on all
  142. /// interfaces.
  143. }
  144. static Dhcp6ConfigParser* Factory(const std::string& param_name) {
  145. return (new InterfaceListConfigParser(param_name));
  146. }
  147. protected:
  148. vector<string> interfaces_;
  149. };
  150. class PoolParser : public Dhcp6ConfigParser {
  151. public:
  152. PoolParser(const std::string& /*param_name*/)
  153. :pools_(NULL) {
  154. // ignore parameter name, it is always Dhcp6/subnet6[X]/pool
  155. }
  156. void build(ConstElementPtr pools_list) {
  157. // setStorage() should have been called before build
  158. if (!pools_) {
  159. isc_throw(NotImplemented, "Parser logic error. No pool storage set,"
  160. " but pool parser asked to parse pools");
  161. }
  162. BOOST_FOREACH(ConstElementPtr text_pool, pools_list->listValue()) {
  163. // That should be a single pool representation. It should contain
  164. // text is form prefix/len or first - last. Note that spaces
  165. // are allowed
  166. string txt = text_pool->stringValue();
  167. // first let's remove any spaces or tabs
  168. boost::erase_all(txt, " ");
  169. boost::erase_all(txt, "\t");
  170. size_t pos = txt.find("/");
  171. if (pos != string::npos) {
  172. IOAddress addr("::");
  173. uint8_t len = 0;
  174. try {
  175. addr = IOAddress(txt.substr(0, pos));
  176. string num = txt.substr(pos+1);
  177. // it is lexical cast to int and then downcast to uint8_t
  178. // direct cast to uint8_t (which is really an unsigned char)
  179. // will result in interpreting the first digit as output
  180. // value and throwing exception if length written on two
  181. // digits (because there are extra characters left over)
  182. len = boost::lexical_cast<int>(num);
  183. } catch (...) {
  184. isc_throw(Dhcp6ConfigError, "Failed to parse pool "
  185. "definition: " << text_pool->stringValue());
  186. }
  187. cout << "#### Creating Pool6(TYPE_IA, " << addr.toText() << "/"
  188. << (int)len << ")" << endl;
  189. // using prefix/len notation
  190. Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, addr, len));
  191. pools_->push_back(pool);
  192. continue;
  193. }
  194. pos = txt.find("-");
  195. if (pos != string::npos) {
  196. IOAddress min(txt.substr(0,pos-1));
  197. IOAddress max(txt.substr(pos+1));
  198. cout << "#### Creating Pool6(TYPE_IA, " << min.toText() << ","
  199. << max.toText() << ")" << endl;
  200. Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, min, max));
  201. pools_->push_back(pool);
  202. continue;
  203. }
  204. isc_throw(Dhcp6ConfigError, "Failed to parse pool definition:"
  205. << text_pool->stringValue() <<
  206. ". Does not contain - (for min-max) nor / (prefix/len)");
  207. }
  208. }
  209. void setStorage(PoolStorage* storage) {
  210. pools_ = storage;
  211. }
  212. void commit() {}
  213. static Dhcp6ConfigParser* Factory(const std::string& param_name) {
  214. return (new PoolParser(param_name));
  215. }
  216. protected:
  217. PoolStorage * pools_;
  218. };
  219. /// @brief this class parses a single subnet
  220. class Subnet6ConfigParser : public Dhcp6ConfigParser {
  221. public:
  222. Subnet6ConfigParser(const std::string& param_name) {
  223. }
  224. void build(ConstElementPtr subnet) {
  225. cout << "#### Subnet6ConfigParser::build(): parsing: [" << subnet->str() << "]" << endl;
  226. BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
  227. ParserPtr parser(createSubnet6ConfigParser(param.first));
  228. // if this is an Uint32 parser, tell it to store the values
  229. // in values_, rather than in global storage
  230. boost::shared_ptr<Uint32Parser> uintParser =
  231. boost::dynamic_pointer_cast<Uint32Parser>(parser);
  232. if (uintParser) {
  233. uintParser->setStorage(&uint32_values_);
  234. }
  235. boost::shared_ptr<StringParser> stringParser =
  236. boost::dynamic_pointer_cast<StringParser>(parser);
  237. if (stringParser) {
  238. stringParser->setStorage(&string_values_);
  239. }
  240. boost::shared_ptr<PoolParser> poolParser =
  241. boost::dynamic_pointer_cast<PoolParser>(parser);
  242. if (poolParser) {
  243. poolParser->setStorage(&pools_);
  244. }
  245. parser->build(param.second);
  246. parsers_.push_back(parser);
  247. }
  248. // Ok, we now have subnet parsed
  249. }
  250. void commit() {
  251. StringStorage::const_iterator it = string_values_.find("subnet");
  252. cout << "#### Subnet6ConfigParser::commit() string_values_.size()="
  253. << string_values_.size() << endl;
  254. if (it == string_values_.end()) {
  255. isc_throw(Dhcp6ConfigError,
  256. "Mandatory subnet definition in subnet missing");
  257. }
  258. string subnet_txt = it->second;
  259. boost::erase_all(subnet_txt, " ");
  260. boost::erase_all(subnet_txt, "\t");
  261. size_t pos = subnet_txt.find("/");
  262. if (pos == string::npos) {
  263. isc_throw(Dhcp6ConfigError,
  264. "Invalid subnet syntax (prefix/len expected):" << it->second);
  265. }
  266. IOAddress addr(subnet_txt.substr(0, pos));
  267. uint8_t len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
  268. Triplet<uint32_t> t1 = getParam("renew-timer");
  269. Triplet<uint32_t> t2 = getParam("rebind-timer");
  270. Triplet<uint32_t> pref = getParam("preferred-lifetime");
  271. Triplet<uint32_t> valid = getParam("valid-lifetime");
  272. cout << "#### Adding subnet " << addr.toText() << "/" << (int)len
  273. << " with params t1=" << t1 << ", t2=" << t2 << ", pref="
  274. << pref << ", valid=" << valid << endl;
  275. Subnet6Ptr subnet(new Subnet6(addr, len, t1, t2, pref, valid));
  276. CfgMgr::instance().addSubnet6(subnet);
  277. }
  278. protected:
  279. Dhcp6ConfigParser* createSubnet6ConfigParser(const std::string& config_id) {
  280. FactoryMap factories;
  281. factories.insert(pair<string, ParserFactory*>(
  282. "preferred-lifetime", Uint32Parser::Factory));
  283. factories.insert(pair<string, ParserFactory*>(
  284. "valid-lifetime", Uint32Parser::Factory));
  285. factories.insert(pair<string, ParserFactory*>(
  286. "renew-timer", Uint32Parser::Factory));
  287. factories.insert(pair<string, ParserFactory*>(
  288. "rebind-timer", Uint32Parser::Factory));
  289. factories.insert(pair<string, ParserFactory*>(
  290. "subnet", StringParser::Factory));
  291. factories.insert(pair<string, ParserFactory*>(
  292. "pool", PoolParser::Factory));
  293. FactoryMap::iterator f = factories.find(config_id);
  294. if (f == factories.end()) {
  295. // Used for debugging only.
  296. // return new DummyParser(config_id);
  297. isc_throw(NotImplemented,
  298. "Parser error: Subnet6 parameter not supported: "
  299. << config_id);
  300. }
  301. return (f->second(config_id));
  302. }
  303. Triplet<uint32_t> getParam(const std::string& name) {
  304. uint32_t value = 0;
  305. bool found = false;
  306. Uint32Storage::iterator global = uint32_defaults.find(name);
  307. if (global != uint32_defaults.end()) {
  308. value = global->second;
  309. found = true;
  310. }
  311. Uint32Storage::iterator local = uint32_values_.find(name);
  312. if (local != uint32_values_.end()) {
  313. value = local->second;
  314. found = true;
  315. }
  316. if (found) {
  317. return (Triplet<uint32_t>(value));
  318. } else {
  319. isc_throw(Dhcp6ConfigError, "Mandatory parameter " << name
  320. << " missing (no global default and no subnet-"
  321. << "specific value)");
  322. }
  323. }
  324. Uint32Storage uint32_values_;
  325. StringStorage string_values_;
  326. PoolStorage pools_;
  327. ParserCollection parsers_;
  328. };
  329. /// @brief this class parses list of subnets
  330. class Subnets6ListConfigParser : public Dhcp6ConfigParser {
  331. public:
  332. Subnets6ListConfigParser(const std::string& param_name) {
  333. }
  334. void build(ConstElementPtr subnets_list) {
  335. // No need to define FactoryMap here. There's only one type
  336. // used: Subnet6ConfigParser
  337. BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
  338. ParserPtr parser(new Subnet6ConfigParser("subnet"));
  339. parser->build(subnet);
  340. subnets_.push_back(parser);
  341. }
  342. }
  343. void commit() {
  344. BOOST_FOREACH(ParserPtr subnet, subnets_) {
  345. subnet->commit();
  346. }
  347. }
  348. static Dhcp6ConfigParser* Factory(const std::string& param_name) {
  349. return (new Subnets6ListConfigParser(param_name));
  350. }
  351. ParserCollection subnets_;
  352. };
  353. /// @brief creates global parsers
  354. ///
  355. /// This method creates global parsers that parse global parameters, i.e.
  356. /// those that take format of Dhcp6/param1, Dhcp6/param2 and so forth.
  357. Dhcp6ConfigParser* createGlobalDhcp6ConfigParser(const std::string& config_id) {
  358. FactoryMap factories;
  359. //
  360. factories.insert(pair<string, ParserFactory*>(
  361. "preferred-lifetime", Uint32Parser::Factory));
  362. factories.insert(pair<string, ParserFactory*>(
  363. "valid-lifetime", Uint32Parser::Factory));
  364. factories.insert(pair<string, ParserFactory*>(
  365. "renew-timer", Uint32Parser::Factory));
  366. factories.insert(pair<string, ParserFactory*>(
  367. "rebind-timer", Uint32Parser::Factory));
  368. factories.insert(pair<string, ParserFactory*>(
  369. "interface", InterfaceListConfigParser::Factory));
  370. factories.insert(pair<string, ParserFactory*>(
  371. "subnet6", Subnets6ListConfigParser::Factory));
  372. factories.insert(pair<string, ParserFactory*>(
  373. "version", StringParser::Factory));
  374. FactoryMap::iterator f = factories.find(config_id);
  375. if (f == factories.end()) {
  376. // Used for debugging only.
  377. // return new DummyParser(config_id);
  378. isc_throw(NotImplemented,
  379. "Parser error: Global configuration parameter not supported: "
  380. << config_id);
  381. }
  382. return (f->second(config_id));
  383. }
  384. void
  385. configureDhcp6Server(Dhcpv6Srv& server, ConstElementPtr config_set) {
  386. if (!config_set) {
  387. isc_throw(Dhcp6ConfigError,
  388. "Null pointer is passed to configuration parser");
  389. }
  390. ParserCollection parsers;
  391. try {
  392. BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
  393. ParserPtr parser(createGlobalDhcp6ConfigParser(config_pair.first));
  394. parser->build(config_pair.second);
  395. parsers.push_back(parser);
  396. }
  397. } catch (const Dhcp6ConfigError& ex) {
  398. throw; // simply rethrowing it
  399. } catch (const isc::Exception& ex) {
  400. isc_throw(Dhcp6ConfigError, "Server configuration failed: " <<
  401. ex.what());
  402. }
  403. try {
  404. BOOST_FOREACH(ParserPtr parser, parsers) {
  405. parser->commit();
  406. }
  407. } catch (...) {
  408. isc_throw(Dhcp6ConfigError, "Unrecoverable error: "
  409. "a configuration parser threw in commit");
  410. }
  411. }
  412. }; // end of isc::dhcp namespace
  413. }; // end of isc namespace