config_parser.cc 77 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916
  1. // Copyright (C) 2012-2013 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 <asiolink/io_address.h>
  15. #include <cc/data.h>
  16. #include <config/ccsession.h>
  17. #include <dhcp/libdhcp++.h>
  18. #include <dhcp6/config_parser.h>
  19. #include <dhcp6/dhcp6_log.h>
  20. #include <dhcp/iface_mgr.h>
  21. #include <dhcpsrv/cfgmgr.h>
  22. #include <dhcpsrv/dbaccess_parser.h>
  23. #include <dhcpsrv/dhcp_config_parser.h>
  24. #include <dhcpsrv/pool.h>
  25. #include <dhcpsrv/subnet.h>
  26. #include <dhcpsrv/triplet.h>
  27. #include <log/logger_support.h>
  28. #include <util/encode/hex.h>
  29. #include <util/strutil.h>
  30. #include <boost/algorithm/string.hpp>
  31. #include <boost/foreach.hpp>
  32. #include <boost/lexical_cast.hpp>
  33. #include <boost/scoped_ptr.hpp>
  34. #include <boost/shared_ptr.hpp>
  35. #include <iostream>
  36. #include <map>
  37. #include <vector>
  38. #include <stdint.h>
  39. using namespace std;
  40. using namespace isc;
  41. using namespace isc::data;
  42. using namespace isc::dhcp;
  43. using namespace isc::asiolink;
  44. namespace {
  45. // Forward declarations of some of the parser classes.
  46. // They are used to define pointer types for these classes.
  47. class BooleanParser;
  48. class StringParser;
  49. class Uint32Parser;
  50. // Pointers to various parser objects.
  51. typedef boost::shared_ptr<BooleanParser> BooleanParserPtr;
  52. typedef boost::shared_ptr<StringParser> StringParserPtr;
  53. typedef boost::shared_ptr<Uint32Parser> Uint32ParserPtr;
  54. /// @brief Factory method that will create a parser for a given element name
  55. typedef isc::dhcp::DhcpConfigParser* ParserFactory(const std::string& config_id);
  56. /// @brief Collection of factories that create parsers for specified element names
  57. typedef std::map<std::string, ParserFactory*> FactoryMap;
  58. /// @brief Storage for parsed boolean values.
  59. typedef std::map<string, bool> BooleanStorage;
  60. /// @brief Collection of elements that store uint32 values (e.g. renew-timer = 900).
  61. typedef std::map<string, uint32_t> Uint32Storage;
  62. /// @brief Collection of elements that store string values.
  63. typedef std::map<string, string> StringStorage;
  64. /// @brief Storage for option definitions.
  65. typedef OptionSpaceContainer<OptionDefContainer,
  66. OptionDefinitionPtr> OptionDefStorage;
  67. /// @brief Collection of address pools.
  68. ///
  69. /// This type is used as intermediate storage, when pools are parsed, but there is
  70. /// no subnet object created yet to store them.
  71. typedef std::vector<isc::dhcp::Pool6Ptr> PoolStorage;
  72. /// Collection of containers holding option spaces. Each container within
  73. /// a particular option space holds so-called option descriptors.
  74. typedef OptionSpaceContainer<Subnet::OptionContainer,
  75. Subnet::OptionDescriptor> OptionStorage;
  76. /// @brief Global uint32 parameters that will be used as defaults.
  77. Uint32Storage uint32_defaults;
  78. /// @brief global string parameters that will be used as defaults.
  79. StringStorage string_defaults;
  80. /// @brief Global storage for options that will be used as defaults.
  81. OptionStorage option_defaults;
  82. /// @brief Global storage for option definitions.
  83. OptionDefStorage option_def_intermediate;
  84. /// @brief a dummy configuration parser
  85. ///
  86. /// This is a debugging parser. It does not configure anything,
  87. /// will accept any configuration and will just print it out
  88. /// on commit. Useful for debugging existing configurations and
  89. /// adding new ones.
  90. class DebugParser : public DhcpConfigParser {
  91. public:
  92. /// @brief Constructor
  93. ///
  94. /// See @ref DhcpConfigParser class for details.
  95. ///
  96. /// @param param_name name of the parsed parameter
  97. DebugParser(const std::string& param_name)
  98. :param_name_(param_name) {
  99. }
  100. /// @brief builds parameter value
  101. ///
  102. /// See @ref DhcpConfigParser class for details.
  103. ///
  104. /// @param new_config pointer to the new configuration
  105. virtual void build(ConstElementPtr new_config) {
  106. std::cout << "Build for token: [" << param_name_ << "] = ["
  107. << value_->str() << "]" << std::endl;
  108. value_ = new_config;
  109. }
  110. /// @brief Pretends to apply the configuration.
  111. ///
  112. /// This is a method required by the base class. It pretends to apply the
  113. /// configuration, but in fact it only prints the parameter out.
  114. ///
  115. /// See @ref DhcpConfigParser class for details.
  116. virtual void commit() {
  117. // Debug message. The whole DebugParser class is used only for parser
  118. // debugging, and is not used in production code. It is very convenient
  119. // to keep it around. Please do not turn this cout into logger calls.
  120. std::cout << "Commit for token: [" << param_name_ << "] = ["
  121. << value_->str() << "]" << std::endl;
  122. }
  123. /// @brief factory that constructs DebugParser objects
  124. ///
  125. /// @param param_name name of the parameter to be parsed
  126. static DhcpConfigParser* factory(const std::string& param_name) {
  127. return (new DebugParser(param_name));
  128. }
  129. private:
  130. /// name of the parsed parameter
  131. std::string param_name_;
  132. /// pointer to the actual value of the parameter
  133. ConstElementPtr value_;
  134. };
  135. /// @brief A boolean value parser.
  136. ///
  137. /// This parser handles configuration values of the boolean type.
  138. /// Parsed values are stored in a provided storage. If no storage
  139. /// is provided then the build function throws an exception.
  140. class BooleanParser : public DhcpConfigParser {
  141. public:
  142. /// @brief Constructor.
  143. ///
  144. /// @param param_name name of the parameter.
  145. BooleanParser(const std::string& param_name)
  146. : storage_(NULL),
  147. param_name_(param_name),
  148. value_(false) {
  149. // Empty parameter name is invalid.
  150. if (param_name_.empty()) {
  151. isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
  152. << "empty parameter name provided");
  153. }
  154. }
  155. /// @brief Parse a boolean value.
  156. ///
  157. /// @param value a value to be parsed.
  158. ///
  159. /// @throw isc::InvalidOperation if a storage has not been set
  160. /// prior to calling this function
  161. /// @throw isc::dhcp::DhcpConfigError if a provided parameter's
  162. /// name is empty.
  163. virtual void build(ConstElementPtr value) {
  164. if (storage_ == NULL) {
  165. isc_throw(isc::InvalidOperation, "parser logic error:"
  166. << " storage for the " << param_name_
  167. << " value has not been set");
  168. } else if (param_name_.empty()) {
  169. isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
  170. << "empty parameter name provided");
  171. }
  172. // The Config Manager checks if user specified a
  173. // valid value for a boolean parameter: True or False.
  174. // It is then ok to assume that if str() does not return
  175. // 'true' the value is 'false'.
  176. value_ = (value->str() == "true") ? true : false;
  177. }
  178. /// @brief Put a parsed value to the storage.
  179. virtual void commit() {
  180. if (storage_ != NULL && !param_name_.empty()) {
  181. (*storage_)[param_name_] = value_;
  182. }
  183. }
  184. /// @brief Create an instance of the boolean parser.
  185. ///
  186. /// @param param_name name of the parameter for which the
  187. /// parser is created.
  188. static DhcpConfigParser* factory(const std::string& param_name) {
  189. return (new BooleanParser(param_name));
  190. }
  191. /// @brief Set the storage for parsed value.
  192. ///
  193. /// This function must be called prior to calling build.
  194. ///
  195. /// @param storage a pointer to the storage where parsed data
  196. /// is to be stored.
  197. void setStorage(BooleanStorage* storage) {
  198. storage_ = storage;
  199. }
  200. private:
  201. /// Pointer to the storage where parsed value is stored.
  202. BooleanStorage* storage_;
  203. /// Name of the parameter which value is parsed with this parser.
  204. std::string param_name_;
  205. /// Parsed value.
  206. bool value_;
  207. };
  208. /// @brief Configuration parser for uint32 parameters
  209. ///
  210. /// This class is a generic parser that is able to handle any uint32 integer
  211. /// type. By default it stores the value in external global container
  212. /// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
  213. /// in subnet config), it can be pointed to a different storage, using
  214. /// setStorage() method. This class follows the parser interface, laid out
  215. /// in its base class, @ref DhcpConfigParser.
  216. ///
  217. /// For overview of usability of this generic purpose parser, see
  218. /// @ref dhcpv6ConfigInherit page.
  219. ///
  220. /// @todo this class should be turned into the template class which
  221. /// will handle all uintX_types of data (see ticket #2415).
  222. class Uint32Parser : public DhcpConfigParser {
  223. public:
  224. /// @brief constructor for Uint32Parser
  225. ///
  226. /// @param param_name name of the configuration parameter being parsed
  227. Uint32Parser(const std::string& param_name)
  228. : storage_(&uint32_defaults),
  229. param_name_(param_name) {
  230. // Empty parameter name is invalid.
  231. if (param_name_.empty()) {
  232. isc_throw(DhcpConfigError, "parser logic error:"
  233. << "empty parameter name provided");
  234. }
  235. }
  236. /// @brief Parses configuration configuration parameter as uint32_t.
  237. ///
  238. /// @param value pointer to the content of parsed values
  239. /// @throw isc::dhcp::DhcpConfigError if failed to parse
  240. /// the configuration parameter as uint32_t value.
  241. virtual void build(ConstElementPtr value) {
  242. if (param_name_.empty()) {
  243. isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
  244. << "empty parameter name provided");
  245. }
  246. bool parse_error = false;
  247. // Cast the provided value to int64 value to check.
  248. int64_t int64value = 0;
  249. try {
  250. // Parsing the value as a int64 value allows to
  251. // check if the provided value is within the range
  252. // of uint32_t (is not negative or greater than
  253. // maximal uint32_t value).
  254. int64value = boost::lexical_cast<int64_t>(value->str());
  255. } catch (const boost::bad_lexical_cast&) {
  256. parse_error = true;
  257. }
  258. if (!parse_error) {
  259. // Check that the value is not out of bounds.
  260. if ((int64value < 0) ||
  261. (int64value > std::numeric_limits<uint32_t>::max())) {
  262. parse_error = true;
  263. } else {
  264. // A value is not out of bounds so let's cast it to
  265. // the uint32_t type.
  266. value_ = static_cast<uint32_t>(int64value);
  267. }
  268. }
  269. // Invalid value provided.
  270. if (parse_error) {
  271. isc_throw(isc::dhcp::DhcpConfigError, "Failed to parse value " << value->str()
  272. << " as unsigned 32-bit integer.");
  273. }
  274. }
  275. /// @brief Stores the parsed uint32_t value in a storage.
  276. virtual void commit() {
  277. if (storage_ != NULL) {
  278. // If a given parameter already exists in the storage we override
  279. // its value. If it doesn't we insert a new element.
  280. (*storage_)[param_name_] = value_;
  281. }
  282. }
  283. /// @brief Factory that constructs Uint32Parser objects.
  284. ///
  285. /// @param param_name name of the parameter to be parsed.
  286. static DhcpConfigParser* factory(const std::string& param_name) {
  287. return (new Uint32Parser(param_name));
  288. }
  289. /// @brief Sets storage for value of this parameter.
  290. ///
  291. /// See @ref dhcpv6ConfigInherit for details.
  292. ///
  293. /// @param storage pointer to the storage container.
  294. void setStorage(Uint32Storage* storage) {
  295. storage_ = storage;
  296. }
  297. private:
  298. /// pointer to the storage, where parsed value will be stored
  299. Uint32Storage* storage_;
  300. /// name of the parameter to be parsed
  301. std::string param_name_;
  302. /// the actual parsed value
  303. uint32_t value_;
  304. };
  305. /// @brief Configuration parser for string parameters
  306. ///
  307. /// This class is a generic parser that is able to handle any string
  308. /// parameter. By default it stores the value in an external global container
  309. /// (string_defaults). If used in smaller scopes (e.g. to parse parameters
  310. /// in subnet config), it can be pointed to a different storage, using the
  311. /// setStorage() method. This class follows the parser interface, laid out
  312. /// in its base class, @ref DhcpConfigParser.
  313. ///
  314. /// For overview of usability of this generic purpose parser, see
  315. /// @ref dhcpv6ConfigInherit page.
  316. class StringParser : public DhcpConfigParser {
  317. public:
  318. /// @brief constructor for StringParser
  319. ///
  320. /// @param param_name name of the configuration parameter being parsed
  321. StringParser(const std::string& param_name)
  322. : storage_(&string_defaults),
  323. param_name_(param_name) {
  324. // Empty parameter name is invalid.
  325. if (param_name_.empty()) {
  326. isc_throw(DhcpConfigError, "parser logic error:"
  327. << "empty parameter name provided");
  328. }
  329. }
  330. /// @brief parses parameter value
  331. ///
  332. /// Parses configuration parameter's value as string.
  333. ///
  334. /// @param value pointer to the content of parsed values
  335. /// @throws DhcpConfigError if the parsed parameter's name is empty.
  336. virtual void build(ConstElementPtr value) {
  337. if (param_name_.empty()) {
  338. isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
  339. << "empty parameter name provided");
  340. }
  341. value_ = value->str();
  342. boost::erase_all(value_, "\"");
  343. }
  344. /// @brief Stores the parsed value in a storage.
  345. virtual void commit() {
  346. if (storage_ != NULL && !param_name_.empty()) {
  347. // If a given parameter already exists in the storage we override
  348. // its value. If it doesn't we insert a new element.
  349. (*storage_)[param_name_] = value_;
  350. }
  351. }
  352. /// @brief Factory that constructs StringParser objects
  353. ///
  354. /// @param param_name name of the parameter to be parsed
  355. static DhcpConfigParser* factory(const std::string& param_name) {
  356. return (new StringParser(param_name));
  357. }
  358. /// @brief Sets storage for value of this parameter.
  359. ///
  360. /// See @ref dhcpv6ConfigInherit for details.
  361. ///
  362. /// @param storage pointer to the storage container
  363. void setStorage(StringStorage* storage) {
  364. storage_ = storage;
  365. }
  366. private:
  367. /// Pointer to the storage, where parsed value will be stored
  368. StringStorage* storage_;
  369. /// Name of the parameter to be parsed
  370. std::string param_name_;
  371. /// The actual parsed value
  372. std::string value_;
  373. };
  374. /// @brief parser for interface list definition
  375. ///
  376. /// This parser handles Dhcp6/interface entry.
  377. /// It contains a list of network interfaces that the server listens on.
  378. /// In particular, it can contain an entry called "all" or "any" that
  379. /// designates all interfaces.
  380. ///
  381. /// It is useful for parsing Dhcp6/interface parameter.
  382. class InterfaceListConfigParser : public DhcpConfigParser {
  383. public:
  384. /// @brief constructor
  385. ///
  386. /// As this is a dedicated parser, it must be used to parse
  387. /// "interface" parameter only. All other types will throw exception.
  388. ///
  389. /// @param param_name name of the configuration parameter being parsed
  390. /// @throw BadValue if supplied parameter name is not "interface"
  391. InterfaceListConfigParser(const std::string& param_name) {
  392. if (param_name != "interface") {
  393. isc_throw(isc::BadValue, "Internal error. Interface configuration "
  394. "parser called for the wrong parameter: " << param_name);
  395. }
  396. }
  397. /// @brief parses parameters value
  398. ///
  399. /// Parses configuration entry (list of parameters) and stores it in
  400. /// storage.
  401. ///
  402. /// @param value pointer to the content of parsed values
  403. virtual void build(ConstElementPtr value) {
  404. BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
  405. interfaces_.push_back(iface->str());
  406. }
  407. }
  408. /// @brief commits interfaces list configuration
  409. virtual void commit() {
  410. /// @todo: Implement per interface listening. Currently always listening
  411. /// on all interfaces.
  412. }
  413. /// @brief factory that constructs InterfaceListConfigParser objects
  414. ///
  415. /// @param param_name name of the parameter to be parsed
  416. static DhcpConfigParser* factory(const std::string& param_name) {
  417. return (new InterfaceListConfigParser(param_name));
  418. }
  419. private:
  420. /// contains list of network interfaces
  421. vector<string> interfaces_;
  422. };
  423. /// @brief parser for pool definition
  424. ///
  425. /// This parser handles pool definitions, i.e. a list of entries of one
  426. /// of two syntaxes: min-max and prefix/len. Pool6 objects are created
  427. /// and stored in chosen PoolStorage container.
  428. ///
  429. /// As there are no default values for pool, setStorage() must be called
  430. /// before build(). Otherwise an exception will be thrown.
  431. ///
  432. /// It is useful for parsing Dhcp6/subnet6[X]/pool parameters.
  433. class PoolParser : public DhcpConfigParser {
  434. public:
  435. /// @brief constructor.
  436. PoolParser(const std::string& /*param_name*/)
  437. : pools_(NULL) {
  438. // ignore parameter name, it is always Dhcp6/subnet6[X]/pool
  439. }
  440. /// @brief parses the actual list
  441. ///
  442. /// This method parses the actual list of interfaces.
  443. /// No validation is done at this stage, everything is interpreted as
  444. /// interface name.
  445. /// @param pools_list list of pools defined for a subnet
  446. /// @throw isc::InvalidOperation if storage was not specified
  447. /// (setStorage() not called)
  448. void build(ConstElementPtr pools_list) {
  449. // setStorage() should have been called before build
  450. if (!pools_) {
  451. isc_throw(isc::InvalidOperation, "parser logic error: no pool storage set,"
  452. " but pool parser asked to parse pools");
  453. }
  454. BOOST_FOREACH(ConstElementPtr text_pool, pools_list->listValue()) {
  455. // That should be a single pool representation. It should contain
  456. // text in the form prefix/len or first - last. Note that spaces
  457. // are allowed
  458. string txt = text_pool->stringValue();
  459. // first let's remove any whitespaces
  460. boost::erase_all(txt, " "); // space
  461. boost::erase_all(txt, "\t"); // tabulation
  462. // Is this prefix/len notation?
  463. size_t pos = txt.find("/");
  464. if (pos != string::npos) {
  465. IOAddress addr("::");
  466. uint8_t len = 0;
  467. try {
  468. addr = IOAddress(txt.substr(0, pos));
  469. // start with the first character after /
  470. string prefix_len = txt.substr(pos + 1);
  471. // It is lexically cast to int and then downcast to uint8_t.
  472. // Direct cast to uint8_t (which is really an unsigned char)
  473. // will result in interpreting the first digit as output
  474. // value and throwing exception if length is written on two
  475. // digits (because there are extra characters left over).
  476. // No checks for values over 128. Range correctness will
  477. // be checked in Pool6 constructor.
  478. len = boost::lexical_cast<int>(prefix_len);
  479. } catch (...) {
  480. isc_throw(DhcpConfigError, "failed to parse pool "
  481. "definition: " << text_pool->stringValue());
  482. }
  483. Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, addr, len));
  484. local_pools_.push_back(pool);
  485. continue;
  486. }
  487. // Is this min-max notation?
  488. pos = txt.find("-");
  489. if (pos != string::npos) {
  490. // using min-max notation
  491. IOAddress min(txt.substr(0, pos));
  492. IOAddress max(txt.substr(pos + 1));
  493. Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, min, max));
  494. local_pools_.push_back(pool);
  495. continue;
  496. }
  497. isc_throw(DhcpConfigError, "failed to parse pool definition:"
  498. << text_pool->stringValue() <<
  499. ". Does not contain - (for min-max) nor / (prefix/len)");
  500. }
  501. }
  502. /// @brief sets storage for value of this parameter
  503. ///
  504. /// See @ref dhcpv6ConfigInherit for details.
  505. ///
  506. /// @param storage pointer to the storage container
  507. void setStorage(PoolStorage* storage) {
  508. pools_ = storage;
  509. }
  510. /// @brief Stores the parsed values in a storage provided
  511. /// by an upper level parser.
  512. virtual void commit() {
  513. if (pools_) {
  514. // local_pools_ holds the values produced by the build function.
  515. // At this point parsing should have completed successfuly so
  516. // we can append new data to the supplied storage.
  517. pools_->insert(pools_->end(), local_pools_.begin(),
  518. local_pools_.end());
  519. }
  520. }
  521. /// @brief factory that constructs PoolParser objects
  522. ///
  523. /// @param param_name name of the parameter to be parsed
  524. static DhcpConfigParser* factory(const std::string& param_name) {
  525. return (new PoolParser(param_name));
  526. }
  527. private:
  528. /// @brief pointer to the actual Pools storage
  529. ///
  530. /// This is typically a storage somewhere in Subnet parser
  531. /// (an upper level parser).
  532. PoolStorage* pools_;
  533. /// A temporary storage for pools configuration. It is a
  534. /// storage where pools are stored by build function.
  535. PoolStorage local_pools_;
  536. };
  537. /// @brief Parser for option data value.
  538. ///
  539. /// This parser parses configuration entries that specify value of
  540. /// a single option. These entries include option name, option code
  541. /// and data carried by the option. The option data can be specified
  542. /// in one of the two available formats: binary value represented as
  543. /// a string of hexadecimal digits or a list of comma separated values.
  544. /// The format being used is controlled by csv-format configuration
  545. /// parameter. When setting this value to True, the latter format is
  546. /// used. The subsequent values in the CSV format apply to relevant
  547. /// option data fields in the configured option. For example the
  548. /// configuration: "data" : "192.168.2.0, 56, hello world" can be
  549. /// used to set values for the option comprising IPv4 address,
  550. /// integer and string data field. Note that order matters. If the
  551. /// order of values does not match the order of data fields within
  552. /// an option the configuration will not be accepted. If parsing
  553. /// is successful then an instance of an option is created and
  554. /// added to the storage provided by the calling class.
  555. class OptionDataParser : public DhcpConfigParser {
  556. public:
  557. /// @brief Constructor.
  558. ///
  559. /// Class constructor.
  560. OptionDataParser(const std::string&)
  561. : options_(NULL),
  562. // initialize option to NULL ptr
  563. option_descriptor_(false) { }
  564. /// @brief Parses the single option data.
  565. ///
  566. /// This method parses the data of a single option from the configuration.
  567. /// The option data includes option name, option code and data being
  568. /// carried by this option. Eventually it creates the instance of the
  569. /// option.
  570. ///
  571. /// @warning setStorage must be called with valid storage pointer prior
  572. /// to calling this method.
  573. ///
  574. /// @param option_data_entries collection of entries that define value
  575. /// for a particular option.
  576. /// @throw DhcpConfigError if invalid parameter specified in
  577. /// the configuration.
  578. /// @throw isc::InvalidOperation if failed to set storage prior to
  579. /// calling build.
  580. virtual void build(ConstElementPtr option_data_entries) {
  581. if (options_ == NULL) {
  582. isc_throw(isc::InvalidOperation, "Parser logic error: storage must be set before "
  583. "parsing option data.");
  584. }
  585. BOOST_FOREACH(ConfigPair param, option_data_entries->mapValue()) {
  586. ParserPtr parser;
  587. if (param.first == "name" || param.first == "data" ||
  588. param.first == "space") {
  589. boost::shared_ptr<StringParser>
  590. name_parser(dynamic_cast<StringParser*>(StringParser::factory(param.first)));
  591. if (name_parser) {
  592. name_parser->setStorage(&string_values_);
  593. parser = name_parser;
  594. }
  595. } else if (param.first == "code") {
  596. boost::shared_ptr<Uint32Parser>
  597. code_parser(dynamic_cast<Uint32Parser*>(Uint32Parser::factory(param.first)));
  598. if (code_parser) {
  599. code_parser->setStorage(&uint32_values_);
  600. parser = code_parser;
  601. }
  602. } else if (param.first == "csv-format") {
  603. boost::shared_ptr<BooleanParser>
  604. value_parser(dynamic_cast<BooleanParser*>(BooleanParser::factory(param.first)));
  605. if (value_parser) {
  606. value_parser->setStorage(&boolean_values_);
  607. parser = value_parser;
  608. }
  609. } else {
  610. isc_throw(DhcpConfigError,
  611. "parser error: option-data parameter not supported: "
  612. << param.first);
  613. }
  614. parser->build(param.second);
  615. // Before we can create an option we need to get the data from
  616. // the child parsers. The only way to do it is to invoke commit
  617. // on them so as they store the values in appropriate storages
  618. // that this class provided to them. Note that this will not
  619. // modify values stored in the global storages so the configuration
  620. // will remain consistent even parsing fails somewhere further on.
  621. parser->commit();
  622. }
  623. // Try to create the option instance.
  624. createOption();
  625. }
  626. /// @brief Commits option value.
  627. ///
  628. /// This function adds a new option to the storage or replaces an existing option
  629. /// with the same code.
  630. ///
  631. /// @throw isc::InvalidOperation if failed to set pointer to storage or failed
  632. /// to call build() prior to commit. If that happens data in the storage
  633. /// remain un-modified.
  634. virtual void commit() {
  635. if (options_ == NULL) {
  636. isc_throw(isc::InvalidOperation, "parser logic error: storage must be set before "
  637. "committing option data.");
  638. } else if (!option_descriptor_.option) {
  639. // Before we can commit the new option should be configured. If it is not
  640. // than somebody must have called commit() before build().
  641. isc_throw(isc::InvalidOperation, "parser logic error: no option has been configured and"
  642. " thus there is nothing to commit. Has build() been called?");
  643. }
  644. uint16_t opt_type = option_descriptor_.option->getType();
  645. Subnet::OptionContainerPtr options = options_->getItems(option_space_);
  646. // The getItems() should never return NULL pointer. If there are no
  647. // options configured for the particular option space a pointer
  648. // to an empty container should be returned.
  649. assert(options);
  650. Subnet::OptionContainerTypeIndex& idx = options->get<1>();
  651. // Try to find options with the particular option code in the main
  652. // storage. If found, remove these options because they will be
  653. // replaced with new one.
  654. Subnet::OptionContainerTypeRange range =
  655. idx.equal_range(opt_type);
  656. if (std::distance(range.first, range.second) > 0) {
  657. idx.erase(range.first, range.second);
  658. }
  659. // Append new option to the main storage.
  660. options_->addItem(option_descriptor_, option_space_);
  661. }
  662. /// @brief Set storage for the parser.
  663. ///
  664. /// Sets storage for the parser. This storage points to the
  665. /// vector of options and is used by multiple instances of
  666. /// OptionDataParser. Each instance creates exactly one object
  667. /// of dhcp::Option or derived type and appends it to this
  668. /// storage.
  669. ///
  670. /// @param storage pointer to the options storage
  671. void setStorage(OptionStorage* storage) {
  672. options_ = storage;
  673. }
  674. private:
  675. /// @brief Create option instance.
  676. ///
  677. /// Creates an instance of an option and adds it to the provided
  678. /// options storage. If the option data parsed by \ref build function
  679. /// are invalid or insufficient this function emits an exception.
  680. ///
  681. /// @warning this function does not check if options_ storage pointer
  682. /// is intitialized but this check is not needed here because it is done
  683. /// in the \ref build function.
  684. ///
  685. /// @throw DhcpConfigError if parameters provided in the configuration
  686. /// are invalid.
  687. void createOption() {
  688. // Option code is held in the uint32_t storage but is supposed to
  689. // be uint16_t value. We need to check that value in the configuration
  690. // does not exceed range of uint16_t and is not zero.
  691. uint32_t option_code = getParam<uint32_t>("code", uint32_values_);
  692. if (option_code == 0) {
  693. isc_throw(DhcpConfigError, "option code must not be zero."
  694. << " Option code '0' is reserved in DHCPv6.");
  695. } else if (option_code > std::numeric_limits<uint16_t>::max()) {
  696. isc_throw(DhcpConfigError, "invalid option code '" << option_code
  697. << "', it must not exceed '"
  698. << std::numeric_limits<uint16_t>::max() << "'");
  699. }
  700. // Check that the option name has been specified, is non-empty and does not
  701. // contain spaces.
  702. std::string option_name = getParam<std::string>("name", string_values_);
  703. if (option_name.empty()) {
  704. isc_throw(DhcpConfigError, "name of the option with code '"
  705. << option_code << "' is empty");
  706. } else if (option_name.find(" ") != std::string::npos) {
  707. isc_throw(DhcpConfigError, "invalid option name '" << option_name
  708. << "', space character is not allowed");
  709. }
  710. std::string option_space = getParam<std::string>("space", string_values_);
  711. if (!OptionSpace::validateName(option_space)) {
  712. isc_throw(DhcpConfigError, "invalid option space name '"
  713. << option_space << "' specified for option '"
  714. << option_name << "' (code '" << option_code
  715. << "')");
  716. }
  717. OptionDefinitionPtr def;
  718. if (option_space == "dhcp6" &&
  719. LibDHCP::isStandardOption(Option::V6, option_code)) {
  720. def = LibDHCP::getOptionDef(Option::V6, option_code);
  721. } else if (option_space == "dhcp4") {
  722. isc_throw(DhcpConfigError, "'dhcp4' option space name is reserved"
  723. << " for DHCPv4 server");
  724. } else {
  725. // If we are not dealing with a standard option then we
  726. // need to search for its definition among user-configured
  727. // options. They are expected to be in the global storage
  728. // already.
  729. OptionDefContainerPtr defs = option_def_intermediate.getItems(option_space);
  730. // The getItems() should never return the NULL pointer. If there are
  731. // no option definitions for the particular option space a pointer
  732. // to an empty container should be returned.
  733. assert(defs);
  734. const OptionDefContainerTypeIndex& idx = defs->get<1>();
  735. OptionDefContainerTypeRange range = idx.equal_range(option_code);
  736. if (std::distance(range.first, range.second) > 0) {
  737. def = *range.first;
  738. }
  739. if (!def) {
  740. isc_throw(DhcpConfigError, "definition for the option '"
  741. << option_space << "." << option_name
  742. << "' having code '" << option_code
  743. << "' does not exist");
  744. }
  745. }
  746. // Get option data from the configuration database ('data' field).
  747. const std::string option_data = getParam<std::string>("data", string_values_);
  748. const bool csv_format = getParam<bool>("csv-format", boolean_values_);
  749. // Transform string of hexadecimal digits into binary format.
  750. std::vector<uint8_t> binary;
  751. std::vector<std::string> data_tokens;
  752. if (csv_format) {
  753. // If the option data is specified as a string of comma
  754. // separated values then we need to split this string into
  755. // individual values - each value will be used to initialize
  756. // one data field of an option.
  757. data_tokens = isc::util::str::tokens(option_data, ",");
  758. } else {
  759. // Otherwise, the option data is specified as a string of
  760. // hexadecimal digits that we have to turn into binary format.
  761. try {
  762. util::encode::decodeHex(option_data, binary);
  763. } catch (...) {
  764. isc_throw(DhcpConfigError, "Parser error: option data is not a valid"
  765. << " string of hexadecimal digits: " << option_data);
  766. }
  767. }
  768. OptionPtr option;
  769. if (!def) {
  770. if (csv_format) {
  771. isc_throw(DhcpConfigError, "the CSV option data format can be"
  772. " used to specify values for an option that has a"
  773. " definition. The option with code " << option_code
  774. << " does not have a definition.");
  775. }
  776. // @todo We have a limited set of option definitions intiialized at the moment.
  777. // In the future we want to initialize option definitions for all options.
  778. // Consequently an error will be issued if an option definition does not exist
  779. // for a particular option code. For now it is ok to create generic option
  780. // if definition does not exist.
  781. OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
  782. binary));
  783. // The created option is stored in option_descriptor_ class member until the
  784. // commit stage when it is inserted into the main storage. If an option with the
  785. // same code exists in main storage already the old option is replaced.
  786. option_descriptor_.option = option;
  787. option_descriptor_.persistent = false;
  788. } else {
  789. // Option name should match the definition. The option name
  790. // may seem to be redundant but in the future we may want
  791. // to reference options and definitions using their names
  792. // and/or option codes so keeping the option name in the
  793. // definition of option value makes sense.
  794. if (def->getName() != option_name) {
  795. isc_throw(DhcpConfigError, "specified option name '"
  796. << option_name << "' does not match the "
  797. << "option definition: '" << option_space
  798. << "." << def->getName() << "'");
  799. }
  800. // Option definition has been found so let's use it to create
  801. // an instance of our option.
  802. try {
  803. OptionPtr option = csv_format ?
  804. def->optionFactory(Option::V6, option_code, data_tokens) :
  805. def->optionFactory(Option::V6, option_code, binary);
  806. Subnet::OptionDescriptor desc(option, false);
  807. option_descriptor_.option = option;
  808. option_descriptor_.persistent = false;
  809. } catch (const isc::Exception& ex) {
  810. isc_throw(DhcpConfigError, "option data does not match"
  811. << " option definition (space: " << option_space
  812. << ", code: " << option_code << "): "
  813. << ex.what());
  814. }
  815. }
  816. // All went good, so we can set the option space name.
  817. option_space_ = option_space;
  818. }
  819. /// Storage for uint32 values (e.g. option code).
  820. Uint32Storage uint32_values_;
  821. /// Storage for string values (e.g. option name or data).
  822. StringStorage string_values_;
  823. /// Storage for boolean values.
  824. BooleanStorage boolean_values_;
  825. /// Pointer to options storage. This storage is provided by
  826. /// the calling class and is shared by all OptionDataParser objects.
  827. OptionStorage* options_;
  828. /// Option descriptor holds newly configured option.
  829. isc::dhcp::Subnet::OptionDescriptor option_descriptor_;
  830. /// Option space name where the option belongs to.
  831. std::string option_space_;
  832. };
  833. /// @brief Parser for option data values within a subnet.
  834. ///
  835. /// This parser iterates over all entries that define options
  836. /// data for a particular subnet and creates a collection of options.
  837. /// If parsing is successful, all these options are added to the Subnet
  838. /// object.
  839. class OptionDataListParser : public DhcpConfigParser {
  840. public:
  841. /// @brief Constructor.
  842. ///
  843. /// Unless otherwise specified, parsed options will be stored in
  844. /// a global option container (option_default). That storage location
  845. /// is overriden on a subnet basis.
  846. OptionDataListParser(const std::string&)
  847. : options_(&option_defaults), local_options_() { }
  848. /// @brief Parses entries that define options' data for a subnet.
  849. ///
  850. /// This method iterates over all entries that define option data
  851. /// for options within a single subnet and creates options' instances.
  852. ///
  853. /// @param option_data_list pointer to a list of options' data sets.
  854. /// @throw DhcpConfigError if option parsing failed.
  855. void build(ConstElementPtr option_data_list) {
  856. BOOST_FOREACH(ConstElementPtr option_value, option_data_list->listValue()) {
  857. boost::shared_ptr<OptionDataParser> parser(new OptionDataParser("option-data"));
  858. // options_ member will hold instances of all options thus
  859. // each OptionDataParser takes it as a storage.
  860. parser->setStorage(&local_options_);
  861. // Build the instance of a single option.
  862. parser->build(option_value);
  863. // Store a parser as it will be used to commit.
  864. parsers_.push_back(parser);
  865. }
  866. }
  867. /// @brief Set storage for option instances.
  868. ///
  869. /// @param storage pointer to options storage.
  870. void setStorage(OptionStorage* storage) {
  871. options_ = storage;
  872. }
  873. /// @brief Commit all option values.
  874. ///
  875. /// This function invokes commit for all option values.
  876. void commit() {
  877. BOOST_FOREACH(ParserPtr parser, parsers_) {
  878. parser->commit();
  879. }
  880. // Parsing was successful and we have all configured
  881. // options in local storage. We can now replace old values
  882. // with new values.
  883. std::swap(local_options_, *options_);
  884. }
  885. /// @brief Create DhcpDataListParser object
  886. ///
  887. /// @param param_name param name.
  888. ///
  889. /// @return DhcpConfigParser object.
  890. static DhcpConfigParser* factory(const std::string& param_name) {
  891. return (new OptionDataListParser(param_name));
  892. }
  893. /// Pointer to options instances storage.
  894. OptionStorage* options_;
  895. /// Intermediate option storage. This storage is used by
  896. /// lower level parsers to add new options. Values held
  897. /// in this storage are assigned to main storage (options_)
  898. /// if overall parsing was successful.
  899. OptionStorage local_options_;
  900. /// Collection of parsers;
  901. ParserCollection parsers_;
  902. };
  903. /// @brief Parser for a single option definition.
  904. ///
  905. /// This parser creates an instance of a single option definition.
  906. class OptionDefParser: DhcpConfigParser {
  907. public:
  908. /// @brief Constructor.
  909. ///
  910. /// This constructor sets the pointer to the option definitions
  911. /// storage to NULL. It must be set to point to the actual storage
  912. /// before \ref build is called.
  913. OptionDefParser(const std::string&)
  914. : storage_(NULL) {
  915. }
  916. /// @brief Parses an entry that describes single option definition.
  917. ///
  918. /// @param option_def a configuration entry to be parsed.
  919. ///
  920. /// @throw DhcpConfigError if parsing was unsuccessful.
  921. void build(ConstElementPtr option_def) {
  922. if (storage_ == NULL) {
  923. isc_throw(DhcpConfigError, "parser logic error: storage must be set"
  924. " before parsing option definition data");
  925. }
  926. // Parse the elements that make up the option definition.
  927. BOOST_FOREACH(ConfigPair param, option_def->mapValue()) {
  928. std::string entry(param.first);
  929. ParserPtr parser;
  930. if (entry == "name" || entry == "type" || entry == "record-types" ||
  931. entry == "space" || entry == "encapsulate") {
  932. StringParserPtr
  933. str_parser(dynamic_cast<StringParser*>(StringParser::factory(entry)));
  934. if (str_parser) {
  935. str_parser->setStorage(&string_values_);
  936. parser = str_parser;
  937. }
  938. } else if (entry == "code") {
  939. Uint32ParserPtr
  940. code_parser(dynamic_cast<Uint32Parser*>(Uint32Parser::factory(entry)));
  941. if (code_parser) {
  942. code_parser->setStorage(&uint32_values_);
  943. parser = code_parser;
  944. }
  945. } else if (entry == "array") {
  946. BooleanParserPtr
  947. array_parser(dynamic_cast<BooleanParser*>(BooleanParser::factory(entry)));
  948. if (array_parser) {
  949. array_parser->setStorage(&boolean_values_);
  950. parser = array_parser;
  951. }
  952. } else {
  953. isc_throw(DhcpConfigError, "invalid parameter: " << entry);
  954. }
  955. parser->build(param.second);
  956. parser->commit();
  957. }
  958. // Create an instance of option definition.
  959. createOptionDef();
  960. // Get all items we collected so far for the particular option space.
  961. OptionDefContainerPtr defs = storage_->getItems(option_space_name_);
  962. // Check if there are any items with option code the same as the
  963. // one specified for the definition we are now creating.
  964. const OptionDefContainerTypeIndex& idx = defs->get<1>();
  965. const OptionDefContainerTypeRange& range =
  966. idx.equal_range(option_definition_->getCode());
  967. // If there are any items with this option code already we need
  968. // to issue an error because we don't allow duplicates for
  969. // option definitions within an option space.
  970. if (std::distance(range.first, range.second) > 0) {
  971. isc_throw(DhcpConfigError, "duplicated option definition for"
  972. << " code '" << option_definition_->getCode() << "'");
  973. }
  974. }
  975. /// @brief Stores the parsed option definition in the data store.
  976. void commit() {
  977. if (storage_ && option_definition_ &&
  978. OptionSpace::validateName(option_space_name_)) {
  979. storage_->addItem(option_definition_, option_space_name_);
  980. }
  981. }
  982. /// @brief Sets a pointer to the data store.
  983. ///
  984. /// The newly created instance of an option definition will be
  985. /// added to the data store given by the argument.
  986. ///
  987. /// @param storage pointer to the data store where the option definition
  988. /// will be added to.
  989. void setStorage(OptionDefStorage* storage) {
  990. storage_ = storage;
  991. }
  992. private:
  993. /// @brief Create option definition from the parsed parameters.
  994. void createOptionDef() {
  995. // Get the option space name and validate it.
  996. std::string space = getParam<std::string>("space", string_values_);
  997. if (!OptionSpace::validateName(space)) {
  998. isc_throw(DhcpConfigError, "invalid option space name '"
  999. << space << "'");
  1000. }
  1001. // Get other parameters that are needed to create the
  1002. // option definition.
  1003. std::string name = getParam<std::string>("name", string_values_);
  1004. uint32_t code = getParam<uint32_t>("code", uint32_values_);
  1005. std::string type = getParam<std::string>("type", string_values_);
  1006. bool array_type = getParam<bool>("array", boolean_values_);
  1007. std::string encapsulates = getParam<std::string>("encapsulate",
  1008. string_values_);
  1009. // Create option definition.
  1010. OptionDefinitionPtr def;
  1011. // We need to check if user has set encapsulated option space
  1012. // name. If so, different constructor will be used.
  1013. if (!encapsulates.empty()) {
  1014. // Arrays can't be used together with sub-options.
  1015. if (array_type) {
  1016. isc_throw(DhcpConfigError, "option '" << space << "."
  1017. << "name" << "', comprising an array of data"
  1018. << " fields may not encapsulate any option space");
  1019. } else if (encapsulates == space) {
  1020. isc_throw(DhcpConfigError, "option must not encapsulate"
  1021. << " an option space it belongs to: '"
  1022. << space << "." << name << "' is set to"
  1023. << " encapsulate '" << space << "'");
  1024. } else {
  1025. def.reset(new OptionDefinition(name, code, type,
  1026. encapsulates.c_str()));
  1027. }
  1028. } else {
  1029. def.reset(new OptionDefinition(name, code, type, array_type));
  1030. }
  1031. // The record-types field may carry a list of comma separated names
  1032. // of data types that form a record.
  1033. std::string record_types = getParam<std::string>("record-types",
  1034. string_values_);
  1035. // Split the list of record types into tokens.
  1036. std::vector<std::string> record_tokens =
  1037. isc::util::str::tokens(record_types, ",");
  1038. // Iterate over each token and add a record type into
  1039. // option definition.
  1040. BOOST_FOREACH(std::string record_type, record_tokens) {
  1041. try {
  1042. boost::trim(record_type);
  1043. if (!record_type.empty()) {
  1044. def->addRecordField(record_type);
  1045. }
  1046. } catch (const Exception& ex) {
  1047. isc_throw(DhcpConfigError, "invalid record type values"
  1048. << " specified for the option definition: "
  1049. << ex.what());
  1050. }
  1051. }
  1052. // Check the option definition parameters are valid.
  1053. try {
  1054. def->validate();
  1055. } catch (const isc::Exception& ex) {
  1056. isc_throw(DhcpConfigError, "invalid option definition"
  1057. << " parameters: " << ex.what());
  1058. }
  1059. // Option definition has been created successfully.
  1060. option_space_name_ = space;
  1061. option_definition_ = def;
  1062. }
  1063. /// Instance of option definition being created by this parser.
  1064. OptionDefinitionPtr option_definition_;
  1065. /// Name of the space the option definition belongs to.
  1066. std::string option_space_name_;
  1067. /// Pointer to a storage where the option definition will be
  1068. /// added when \ref commit is called.
  1069. OptionDefStorage* storage_;
  1070. /// Storage for boolean values.
  1071. BooleanStorage boolean_values_;
  1072. /// Storage for string values.
  1073. StringStorage string_values_;
  1074. /// Storage for uint32 values.
  1075. Uint32Storage uint32_values_;
  1076. };
  1077. /// @brief Parser for a list of option definitions.
  1078. ///
  1079. /// This parser iterates over all configuration entries that define
  1080. /// option definitions and creates instances of these definitions.
  1081. /// If the parsing is successful, the collection of created definitions
  1082. /// is put into the provided storage.
  1083. class OptionDefListParser : DhcpConfigParser {
  1084. public:
  1085. /// @brief Constructor.
  1086. ///
  1087. /// This constructor initializes the pointer to option definitions
  1088. /// storage to NULL value. This pointer has to be set to point to
  1089. /// the actual storage before the \ref build function is called.
  1090. OptionDefListParser(const std::string&) {
  1091. }
  1092. /// @brief Parse configuration entries.
  1093. ///
  1094. /// This function parses configuration entries and creates instances
  1095. /// of option definitions.
  1096. ///
  1097. /// @param option_def_list pointer to an element that holds entries
  1098. /// that define option definitions.
  1099. /// @throw DhcpConfigError if configuration parsing fails.
  1100. void build(ConstElementPtr option_def_list) {
  1101. // Clear existing items in the global storage.
  1102. // We are going to replace all of them.
  1103. option_def_intermediate.clearItems();
  1104. if (!option_def_list) {
  1105. isc_throw(DhcpConfigError, "parser error: a pointer to a list of"
  1106. << " option definitions is NULL");
  1107. }
  1108. BOOST_FOREACH(ConstElementPtr option_def, option_def_list->listValue()) {
  1109. boost::shared_ptr<OptionDefParser>
  1110. parser(new OptionDefParser("single-option-def"));
  1111. parser->setStorage(&option_def_intermediate);
  1112. parser->build(option_def);
  1113. parser->commit();
  1114. }
  1115. }
  1116. /// @brief Stores option definitions in the CfgMgr.
  1117. void commit() {
  1118. CfgMgr& cfg_mgr = CfgMgr::instance();
  1119. cfg_mgr.deleteOptionDefs();
  1120. // We need to move option definitions from the temporary
  1121. // storage to the global storage.
  1122. std::list<std::string> space_names =
  1123. option_def_intermediate.getOptionSpaceNames();
  1124. BOOST_FOREACH(std::string space_name, space_names) {
  1125. BOOST_FOREACH(OptionDefinitionPtr def,
  1126. *option_def_intermediate.getItems(space_name)) {
  1127. // All option definitions should be initialized to non-NULL
  1128. // values. The validation is expected to be made by the
  1129. // OptionDefParser when creating an option definition.
  1130. assert(def);
  1131. cfg_mgr.addOptionDef(def, space_name);
  1132. }
  1133. }
  1134. }
  1135. /// @brief Create an OptionDefListParser object.
  1136. ///
  1137. /// @param param_name configuration entry holding option definitions.
  1138. ///
  1139. /// @return OptionDefListParser object.
  1140. static DhcpConfigParser* factory(const std::string& param_name) {
  1141. return (new OptionDefListParser(param_name));
  1142. }
  1143. };
  1144. /// @brief this class parses a single subnet
  1145. ///
  1146. /// This class parses the whole subnet definition. It creates parsers
  1147. /// for received configuration parameters as needed.
  1148. class Subnet6ConfigParser : public DhcpConfigParser {
  1149. public:
  1150. /// @brief constructor
  1151. Subnet6ConfigParser(const std::string& ) {
  1152. // The parameter should always be "subnet", but we don't check
  1153. // against that here in case some wants to reuse this parser somewhere.
  1154. }
  1155. /// @brief parses parameter value
  1156. ///
  1157. /// @param subnet pointer to the content of subnet definition
  1158. ///
  1159. /// @throw isc::DhcpConfigError if subnet configuration parsing failed.
  1160. void build(ConstElementPtr subnet) {
  1161. BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
  1162. ParserPtr parser(createSubnet6ConfigParser(param.first));
  1163. // The actual type of the parser is unknown here. We have to discover
  1164. // the parser type here to invoke the corresponding setStorage function
  1165. // on it. We discover parser type by trying to cast the parser to various
  1166. // parser types and checking which one was successful. For this one
  1167. // a setStorage and build methods are invoked.
  1168. // Try uint32 type parser.
  1169. if (!buildParser<Uint32Parser, Uint32Storage >(parser, uint32_values_,
  1170. param.second) &&
  1171. // Try string type parser.
  1172. !buildParser<StringParser, StringStorage >(parser, string_values_,
  1173. param.second) &&
  1174. // Try pool parser.
  1175. !buildParser<PoolParser, PoolStorage >(parser, pools_,
  1176. param.second) &&
  1177. // Try option data parser.
  1178. !buildParser<OptionDataListParser, OptionStorage >(parser, options_,
  1179. param.second)) {
  1180. // Appropriate parsers are created in the createSubnet6ConfigParser
  1181. // and they should be limited to those that we check here for. Thus,
  1182. // if we fail to find a matching parser here it is a programming error.
  1183. isc_throw(DhcpConfigError, "failed to find suitable parser");
  1184. }
  1185. }
  1186. // In order to create new subnet we need to get the data out
  1187. // of the child parsers first. The only way to do it is to
  1188. // invoke commit on them because it will make them write
  1189. // parsed data into storages we have supplied.
  1190. // Note that triggering commits on child parsers does not
  1191. // affect global data because we supplied pointers to storages
  1192. // local to this object. Thus, even if this method fails
  1193. // later on, the configuration remains consistent.
  1194. BOOST_FOREACH(ParserPtr parser, parsers_) {
  1195. parser->commit();
  1196. }
  1197. // Create a subnet.
  1198. createSubnet();
  1199. }
  1200. /// @brief Adds the created subnet to a server's configuration.
  1201. void commit() {
  1202. if (subnet_) {
  1203. isc::dhcp::CfgMgr::instance().addSubnet6(subnet_);
  1204. }
  1205. }
  1206. private:
  1207. /// @brief Set storage for a parser and invoke build.
  1208. ///
  1209. /// This helper method casts the provided parser pointer to the specified
  1210. /// type. If the cast is successful it sets the corresponding storage for
  1211. /// this parser, invokes build on it and saves the parser.
  1212. ///
  1213. /// @tparam T parser type to which parser argument should be cast.
  1214. /// @tparam Y storage type for the specified parser type.
  1215. /// @param parser parser on which build must be invoked.
  1216. /// @param storage reference to a storage that will be set for a parser.
  1217. /// @param subnet subnet element read from the configuration and being parsed.
  1218. /// @return true if parser pointer was successfully cast to specialized
  1219. /// parser type provided as Y.
  1220. template<typename T, typename Y>
  1221. bool buildParser(const ParserPtr& parser, Y& storage, const ConstElementPtr& subnet) {
  1222. // We need to cast to T in order to set storage for the parser.
  1223. boost::shared_ptr<T> cast_parser = boost::dynamic_pointer_cast<T>(parser);
  1224. // It is common that this cast is not successful because we try to cast to all
  1225. // supported parser types as we don't know the type of a parser in advance.
  1226. if (cast_parser) {
  1227. // Cast, successful so we go ahead with setting storage and actual parse.
  1228. cast_parser->setStorage(&storage);
  1229. parser->build(subnet);
  1230. parsers_.push_back(parser);
  1231. // We indicate that cast was successful so as the calling function
  1232. // may skip attempts to cast to other parser types and proceed to
  1233. // next element.
  1234. return (true);
  1235. }
  1236. // It was not successful. Indicate that another parser type
  1237. // should be tried.
  1238. return (false);
  1239. }
  1240. /// @brief Append sub-options to an option.
  1241. ///
  1242. /// @param option_space a name of the encapsulated option space.
  1243. /// @param option option instance to append sub-options to.
  1244. void appendSubOptions(const std::string& option_space, OptionPtr& option) {
  1245. // Only non-NULL options are stored in option container.
  1246. // If this option pointer is NULL this is a serious error.
  1247. assert(option);
  1248. OptionDefinitionPtr def;
  1249. if (option_space == "dhcp6" &&
  1250. LibDHCP::isStandardOption(Option::V6, option->getType())) {
  1251. def = LibDHCP::getOptionDef(Option::V6, option->getType());
  1252. // Definitions for some of the standard options hasn't been
  1253. // implemented so it is ok to leave here.
  1254. if (!def) {
  1255. return;
  1256. }
  1257. } else {
  1258. const OptionDefContainerPtr defs =
  1259. option_def_intermediate.getItems(option_space);
  1260. const OptionDefContainerTypeIndex& idx = defs->get<1>();
  1261. const OptionDefContainerTypeRange& range =
  1262. idx.equal_range(option->getType());
  1263. // There is no definition so we have to leave.
  1264. if (std::distance(range.first, range.second) == 0) {
  1265. return;
  1266. }
  1267. def = *range.first;
  1268. // If the definition exists, it must be non-NULL.
  1269. // Otherwise it is a programming error.
  1270. assert(def);
  1271. }
  1272. // We need to get option definition for the particular option space
  1273. // and code. This definition holds the information whether our
  1274. // option encapsulates any option space.
  1275. // Get the encapsulated option space name.
  1276. std::string encapsulated_space = def->getEncapsulatedSpace();
  1277. // If option space name is empty it means that our option does not
  1278. // encapsulate any option space (does not include sub-options).
  1279. if (!encapsulated_space.empty()) {
  1280. // Get the sub-options that belong to the encapsulated
  1281. // option space.
  1282. const Subnet::OptionContainerPtr sub_opts =
  1283. option_defaults.getItems(encapsulated_space);
  1284. // Append sub-options to the option.
  1285. BOOST_FOREACH(Subnet::OptionDescriptor desc, *sub_opts) {
  1286. if (desc.option) {
  1287. option->addOption(desc.option);
  1288. }
  1289. }
  1290. }
  1291. }
  1292. /// @brief Create a new subnet using a data from child parsers.
  1293. ///
  1294. /// @throw isc::dhcp::DhcpConfigError if subnet configuration parsing failed.
  1295. void createSubnet() {
  1296. // Find a subnet string.
  1297. StringStorage::const_iterator it = string_values_.find("subnet");
  1298. if (it == string_values_.end()) {
  1299. isc_throw(DhcpConfigError,
  1300. "Mandatory subnet definition in subnet missing");
  1301. }
  1302. // Remove any spaces or tabs.
  1303. string subnet_txt = it->second;
  1304. boost::erase_all(subnet_txt, " ");
  1305. boost::erase_all(subnet_txt, "\t");
  1306. // The subnet format is prefix/len. We are going to extract
  1307. // the prefix portion of a subnet string to create IOAddress
  1308. // object from it. IOAddress will be passed to the Subnet's
  1309. // constructor later on. In order to extract the prefix we
  1310. // need to get all characters preceding "/".
  1311. size_t pos = subnet_txt.find("/");
  1312. if (pos == string::npos) {
  1313. isc_throw(DhcpConfigError,
  1314. "Invalid subnet syntax (prefix/len expected):" << it->second);
  1315. }
  1316. // Try to create the address object. It also validates that
  1317. // the address syntax is ok.
  1318. IOAddress addr(subnet_txt.substr(0, pos));
  1319. uint8_t len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
  1320. // Get all 'time' parameters using inheritance.
  1321. // If the subnet-specific value is defined then use it, else
  1322. // use the global value. The global value must always be
  1323. // present. If it is not, it is an internal error and exception
  1324. // is thrown.
  1325. Triplet<uint32_t> t1 = getParam("renew-timer");
  1326. Triplet<uint32_t> t2 = getParam("rebind-timer");
  1327. Triplet<uint32_t> pref = getParam("preferred-lifetime");
  1328. Triplet<uint32_t> valid = getParam("valid-lifetime");
  1329. // Get interface name. If it is defined, then the subnet is available
  1330. // directly over specified network interface.
  1331. string iface;
  1332. StringStorage::const_iterator iface_iter = string_values_.find("interface");
  1333. if (iface_iter != string_values_.end()) {
  1334. iface = iface_iter->second;
  1335. }
  1336. /// @todo: Convert this to logger once the parser is working reliably
  1337. stringstream tmp;
  1338. tmp << addr.toText() << "/" << (int)len
  1339. << " with params t1=" << t1 << ", t2=" << t2 << ", pref="
  1340. << pref << ", valid=" << valid;
  1341. LOG_INFO(dhcp6_logger, DHCP6_CONFIG_NEW_SUBNET).arg(tmp.str());
  1342. // Create a new subnet.
  1343. subnet_.reset(new Subnet6(addr, len, t1, t2, pref, valid));
  1344. // Add pools to it.
  1345. for (PoolStorage::iterator it = pools_.begin(); it != pools_.end(); ++it) {
  1346. subnet_->addPool(*it);
  1347. }
  1348. // Configure interface, if defined
  1349. if (!iface.empty()) {
  1350. if (!IfaceMgr::instance().getIface(iface)) {
  1351. isc_throw(DhcpConfigError, "Specified interface name " << iface
  1352. << " for subnet " << subnet_->toText() << " is not present"
  1353. << " in the system.");
  1354. }
  1355. subnet_->setIface(iface);
  1356. }
  1357. // We are going to move configured options to the Subnet object.
  1358. // Configured options reside in the container where options
  1359. // are grouped by space names. Thus we need to get all space names
  1360. // and iterate over all options that belong to them.
  1361. std::list<std::string> space_names = options_.getOptionSpaceNames();
  1362. BOOST_FOREACH(std::string option_space, space_names) {
  1363. // Get all options within a particular option space.
  1364. BOOST_FOREACH(Subnet::OptionDescriptor desc,
  1365. *options_.getItems(option_space)) {
  1366. // The pointer should be non-NULL. The validation is expected
  1367. // to be performed by the OptionDataParser before adding an
  1368. // option descriptor to the container.
  1369. assert(desc.option);
  1370. // We want to check whether an option with the particular
  1371. // option code has been already added. If so, we want
  1372. // to issue a warning.
  1373. Subnet::OptionDescriptor existing_desc =
  1374. subnet_->getOptionDescriptor("option_space",
  1375. desc.option->getType());
  1376. if (existing_desc.option) {
  1377. LOG_WARN(dhcp6_logger, DHCP6_CONFIG_OPTION_DUPLICATE)
  1378. .arg(desc.option->getType()).arg(addr.toText());
  1379. }
  1380. // Add sub-options (if any).
  1381. appendSubOptions(option_space, desc.option);
  1382. // In any case, we add the option to the subnet.
  1383. subnet_->addOption(desc.option, false, option_space);
  1384. }
  1385. }
  1386. // Check all global options and add them to the subnet object if
  1387. // they have been configured in the global scope. If they have been
  1388. // configured in the subnet scope we don't add global option because
  1389. // the one configured in the subnet scope always takes precedence.
  1390. space_names = option_defaults.getOptionSpaceNames();
  1391. BOOST_FOREACH(std::string option_space, space_names) {
  1392. // Get all global options for the particular option space.
  1393. BOOST_FOREACH(Subnet::OptionDescriptor desc,
  1394. *option_defaults.getItems(option_space)) {
  1395. // The pointer should be non-NULL. The validation is expected
  1396. // to be performed by the OptionDataParser before adding an
  1397. // option descriptor to the container.
  1398. assert(desc.option);
  1399. // Check if the particular option has been already added.
  1400. // This would mean that it has been configured in the
  1401. // subnet scope. Since option values configured in the
  1402. // subnet scope take precedence over globally configured
  1403. // values we don't add option from the global storage
  1404. // if there is one already.
  1405. Subnet::OptionDescriptor existing_desc =
  1406. subnet_->getOptionDescriptor(option_space, desc.option->getType());
  1407. if (!existing_desc.option) {
  1408. // Add sub-options (if any).
  1409. appendSubOptions(option_space, desc.option);
  1410. subnet_->addOption(desc.option, false, option_space);
  1411. }
  1412. }
  1413. }
  1414. }
  1415. /// @brief creates parsers for entries in subnet definition
  1416. ///
  1417. /// @param config_id name od the entry
  1418. ///
  1419. /// @return parser object for specified entry name
  1420. /// @throw isc::dhcp::DhcpConfigError if trying to create a parser
  1421. /// for unknown config element
  1422. DhcpConfigParser* createSubnet6ConfigParser(const std::string& config_id) {
  1423. FactoryMap factories;
  1424. factories["preferred-lifetime"] = Uint32Parser::factory;
  1425. factories["valid-lifetime"] = Uint32Parser::factory;
  1426. factories["renew-timer"] = Uint32Parser::factory;
  1427. factories["rebind-timer"] = Uint32Parser::factory;
  1428. factories["subnet"] = StringParser::factory;
  1429. factories["pool"] = PoolParser::factory;
  1430. factories["option-data"] = OptionDataListParser::factory;
  1431. factories["interface"] = StringParser::factory;
  1432. FactoryMap::iterator f = factories.find(config_id);
  1433. if (f == factories.end()) {
  1434. // Used for debugging only.
  1435. // return new DebugParser(config_id);
  1436. isc_throw(isc::dhcp::DhcpConfigError,
  1437. "parser error: subnet6 parameter not supported: "
  1438. << config_id);
  1439. }
  1440. return (f->second(config_id));
  1441. }
  1442. /// @brief Returns value for a given parameter (after using inheritance)
  1443. ///
  1444. /// This method implements inheritance. For a given parameter name, it first
  1445. /// checks if there is a global value for it and overwrites it with specific
  1446. /// value if such value was defined in subnet.
  1447. ///
  1448. /// @param name name of the parameter
  1449. /// @return triplet with the parameter name
  1450. /// @throw DhcpConfigError when requested parameter is not present
  1451. isc::dhcp::Triplet<uint32_t> getParam(const std::string& name) {
  1452. uint32_t value = 0;
  1453. bool found = false;
  1454. Uint32Storage::iterator global = uint32_defaults.find(name);
  1455. if (global != uint32_defaults.end()) {
  1456. value = global->second;
  1457. found = true;
  1458. }
  1459. Uint32Storage::iterator local = uint32_values_.find(name);
  1460. if (local != uint32_values_.end()) {
  1461. value = local->second;
  1462. found = true;
  1463. }
  1464. if (found) {
  1465. return (isc::dhcp::Triplet<uint32_t>(value));
  1466. } else {
  1467. isc_throw(isc::dhcp::DhcpConfigError, "Mandatory parameter " << name
  1468. << " missing (no global default and no subnet-"
  1469. << "specific value)");
  1470. }
  1471. }
  1472. /// storage for subnet-specific uint32 values
  1473. Uint32Storage uint32_values_;
  1474. /// storage for subnet-specific integer values
  1475. StringStorage string_values_;
  1476. /// storage for pools belonging to this subnet
  1477. PoolStorage pools_;
  1478. /// storage for options belonging to this subnet
  1479. OptionStorage options_;
  1480. /// parsers are stored here
  1481. ParserCollection parsers_;
  1482. /// Pointer to the created subnet object.
  1483. isc::dhcp::Subnet6Ptr subnet_;
  1484. };
  1485. /// @brief this class parses a list of subnets
  1486. ///
  1487. /// This is a wrapper parser that handles the whole list of Subnet6
  1488. /// definitions. It iterates over all entries and creates Subnet6ConfigParser
  1489. /// for each entry.
  1490. class Subnets6ListConfigParser : public DhcpConfigParser {
  1491. public:
  1492. /// @brief constructor
  1493. ///
  1494. Subnets6ListConfigParser(const std::string&) {
  1495. /// parameter name is ignored
  1496. }
  1497. /// @brief parses contents of the list
  1498. ///
  1499. /// Iterates over all entries on the list and creates a Subnet6ConfigParser
  1500. /// for each entry.
  1501. ///
  1502. /// @param subnets_list pointer to a list of IPv6 subnets
  1503. void build(ConstElementPtr subnets_list) {
  1504. // No need to define FactoryMap here. There's only one type
  1505. // used: Subnet6ConfigParser
  1506. BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
  1507. ParserPtr parser(new Subnet6ConfigParser("subnet"));
  1508. parser->build(subnet);
  1509. subnets_.push_back(parser);
  1510. }
  1511. }
  1512. /// @brief commits subnets definitions.
  1513. ///
  1514. /// Iterates over all Subnet6 parsers. Each parser contains definitions
  1515. /// of a single subnet and its parameters and commits each subnet separately.
  1516. void commit() {
  1517. // @todo: Implement more subtle reconfiguration than toss
  1518. // the old one and replace with the new one.
  1519. // remove old subnets
  1520. isc::dhcp::CfgMgr::instance().deleteSubnets6();
  1521. BOOST_FOREACH(ParserPtr subnet, subnets_) {
  1522. subnet->commit();
  1523. }
  1524. }
  1525. /// @brief Returns Subnet6ListConfigParser object
  1526. /// @param param_name name of the parameter
  1527. /// @return Subnets6ListConfigParser object
  1528. static DhcpConfigParser* factory(const std::string& param_name) {
  1529. return (new Subnets6ListConfigParser(param_name));
  1530. }
  1531. /// @brief collection of subnet parsers.
  1532. ParserCollection subnets_;
  1533. };
  1534. } // anonymous namespace
  1535. namespace isc {
  1536. namespace dhcp {
  1537. /// @brief creates global parsers
  1538. ///
  1539. /// This method creates global parsers that parse global parameters, i.e.
  1540. /// those that take format of Dhcp6/param1, Dhcp6/param2 and so forth.
  1541. ///
  1542. /// @param config_id pointer to received global configuration entry
  1543. /// @return parser for specified global DHCPv6 parameter
  1544. /// @throw NotImplemented if trying to create a parser for unknown config element
  1545. DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
  1546. FactoryMap factories;
  1547. factories["preferred-lifetime"] = Uint32Parser::factory;
  1548. factories["valid-lifetime"] = Uint32Parser::factory;
  1549. factories["renew-timer"] = Uint32Parser::factory;
  1550. factories["rebind-timer"] = Uint32Parser::factory;
  1551. factories["interface"] = InterfaceListConfigParser::factory;
  1552. factories["subnet6"] = Subnets6ListConfigParser::factory;
  1553. factories["option-data"] = OptionDataListParser::factory;
  1554. factories["option-def"] = OptionDefListParser::factory;
  1555. factories["version"] = StringParser::factory;
  1556. factories["lease-database"] = DbAccessParser::factory;
  1557. FactoryMap::iterator f = factories.find(config_id);
  1558. if (f == factories.end()) {
  1559. // Used for debugging only.
  1560. // return new DebugParser(config_id);
  1561. isc_throw(NotImplemented,
  1562. "Parser error: Global configuration parameter not supported: "
  1563. << config_id);
  1564. }
  1565. return (f->second(config_id));
  1566. }
  1567. ConstElementPtr
  1568. configureDhcp6Server(Dhcpv6Srv&, ConstElementPtr config_set) {
  1569. if (!config_set) {
  1570. ConstElementPtr answer = isc::config::createAnswer(1,
  1571. string("Can't parse NULL config"));
  1572. return (answer);
  1573. }
  1574. /// @todo: append most essential info here (like "2 new subnets configured")
  1575. string config_details;
  1576. LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_START).arg(config_set->str());
  1577. // Some of the values specified in the configuration depend on
  1578. // other values. Typically, the values in the subnet4 structure
  1579. // depend on the global values. Also, option values configuration
  1580. // must be performed after the option definitions configurations.
  1581. // Thus we group parsers and will fire them in the right order:
  1582. // all parsers other than subnet4 and option-data parser,
  1583. // option-data parser, subnet4 parser.
  1584. ParserCollection independent_parsers;
  1585. ParserPtr subnet_parser;
  1586. ParserPtr option_parser;
  1587. // The subnet parsers implement data inheritance by directly
  1588. // accessing global storage. For this reason the global data
  1589. // parsers must store the parsed data into global storages
  1590. // immediately. This may cause data inconsistency if the
  1591. // parsing operation fails after the global storage has been
  1592. // modified. We need to preserve the original global data here
  1593. // so as we can rollback changes when an error occurs.
  1594. Uint32Storage uint32_local(uint32_defaults);
  1595. StringStorage string_local(string_defaults);
  1596. OptionStorage option_local(option_defaults);
  1597. OptionDefStorage option_def_local(option_def_intermediate);
  1598. // answer will hold the result.
  1599. ConstElementPtr answer;
  1600. // rollback informs whether error occured and original data
  1601. // have to be restored to global storages.
  1602. bool rollback = false;
  1603. // config_pair holds ther details of the current parser when iterating over
  1604. // the parsers. It is declared outside the loop so in case of error, the
  1605. // name of the failing parser can be retrieved within the "catch" clause.
  1606. ConfigPair config_pair;
  1607. try {
  1608. // Make parsers grouping.
  1609. const std::map<std::string, ConstElementPtr>& values_map =
  1610. config_set->mapValue();
  1611. BOOST_FOREACH(config_pair, values_map) {
  1612. ParserPtr parser(createGlobalDhcpConfigParser(config_pair.first));
  1613. LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PARSER_CREATED)
  1614. .arg(config_pair.first);
  1615. if (config_pair.first == "subnet6") {
  1616. subnet_parser = parser;
  1617. } else if (config_pair.first == "option-data") {
  1618. option_parser = parser;
  1619. } else {
  1620. // Those parsers should be started before other
  1621. // parsers so we can call build straight away.
  1622. independent_parsers.push_back(parser);
  1623. parser->build(config_pair.second);
  1624. // The commit operation here may modify the global storage
  1625. // but we need it so as the subnet6 parser can access the
  1626. // parsed data.
  1627. parser->commit();
  1628. }
  1629. }
  1630. // The option values parser is the next one to be run.
  1631. std::map<std::string, ConstElementPtr>::const_iterator option_config =
  1632. values_map.find("option-data");
  1633. if (option_config != values_map.end()) {
  1634. option_parser->build(option_config->second);
  1635. option_parser->commit();
  1636. }
  1637. // The subnet parser is the last one to be run.
  1638. std::map<std::string, ConstElementPtr>::const_iterator subnet_config =
  1639. values_map.find("subnet6");
  1640. if (subnet_config != values_map.end()) {
  1641. subnet_parser->build(subnet_config->second);
  1642. }
  1643. } catch (const isc::Exception& ex) {
  1644. LOG_ERROR(dhcp6_logger, DHCP6_PARSER_FAIL)
  1645. .arg(config_pair.first).arg(ex.what());
  1646. answer = isc::config::createAnswer(1,
  1647. string("Configuration parsing failed: ") + ex.what());
  1648. // An error occured, so make sure that we restore original data.
  1649. rollback = true;
  1650. } catch (...) {
  1651. // for things like bad_cast in boost::lexical_cast
  1652. LOG_ERROR(dhcp6_logger, DHCP6_PARSER_EXCEPTION).arg(config_pair.first);
  1653. answer = isc::config::createAnswer(1,
  1654. string("Configuration parsing failed"));
  1655. // An error occured, so make sure that we restore original data.
  1656. rollback = true;
  1657. }
  1658. // So far so good, there was no parsing error so let's commit the
  1659. // configuration. This will add created subnets and option values into
  1660. // the server's configuration.
  1661. // This operation should be exception safe but let's make sure.
  1662. if (!rollback) {
  1663. try {
  1664. if (subnet_parser) {
  1665. subnet_parser->commit();
  1666. }
  1667. }
  1668. catch (const isc::Exception& ex) {
  1669. LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());
  1670. answer = isc::config::createAnswer(2,
  1671. string("Configuration commit failed:") + ex.what());
  1672. // An error occured, so make sure to restore the original data.
  1673. rollback = true;
  1674. } catch (...) {
  1675. // for things like bad_cast in boost::lexical_cast
  1676. LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_EXCEPTION);
  1677. answer = isc::config::createAnswer(2,
  1678. string("Configuration commit failed"));
  1679. // An error occured, so make sure to restore the original data.
  1680. rollback = true;
  1681. }
  1682. }
  1683. // Rollback changes as the configuration parsing failed.
  1684. if (rollback) {
  1685. std::swap(uint32_defaults, uint32_local);
  1686. std::swap(string_defaults, string_local);
  1687. std::swap(option_defaults, option_local);
  1688. std::swap(option_def_intermediate, option_def_local);
  1689. return (answer);
  1690. }
  1691. LOG_INFO(dhcp6_logger, DHCP6_CONFIG_COMPLETE).arg(config_details);
  1692. // Everything was fine. Configuration is successful.
  1693. answer = isc::config::createAnswer(0, "Configuration committed.");
  1694. return (answer);
  1695. }
  1696. }; // end of isc::dhcp namespace
  1697. }; // end of isc namespace