cfg_option.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. // Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #ifndef CFG_OPTION_H
  7. #define CFG_OPTION_H
  8. #include <dhcp/option.h>
  9. #include <dhcp/option_space_container.h>
  10. #include <dhcpsrv/key_from_key.h>
  11. #include <boost/multi_index_container.hpp>
  12. #include <boost/multi_index/hashed_index.hpp>
  13. #include <boost/multi_index/sequenced_index.hpp>
  14. #include <boost/multi_index/mem_fun.hpp>
  15. #include <boost/multi_index/member.hpp>
  16. #include <boost/shared_ptr.hpp>
  17. #include <stdint.h>
  18. #include <string>
  19. #include <set>
  20. #include <list>
  21. namespace isc {
  22. namespace dhcp {
  23. /// @brief Option descriptor.
  24. ///
  25. /// Option descriptor holds instance of an option and additional information
  26. /// for this option. This information comprises whether this option is sent
  27. /// to DHCP client only on request (persistent = false) or always
  28. /// (persistent = true).
  29. struct OptionDescriptor {
  30. /// @brief Option instance.
  31. OptionPtr option_;
  32. /// @briefPersistence flag.
  33. ///
  34. /// If true option is always sent to the client, if false option is
  35. /// sent to the client on request.
  36. bool persistent_;
  37. /// @brief Option value in textual (CSV) format.
  38. ///
  39. /// This field is used to convey option value in human readable format,
  40. /// the same as used to specify option value in the server configuration.
  41. /// This value is optional and can be held in the host reservations
  42. /// database instead of the binary format.
  43. ///
  44. /// Note that this value is carried in the option descriptor, rather than
  45. /// @c Option instance because it is a server specific value.
  46. ///
  47. /// An example of the formatted value is: 2001:db8:1::1, 23, some text
  48. /// for the option which carries IPv6 address, a number and a text.
  49. std::string formatted_value_;
  50. /// @brief Constructor.
  51. ///
  52. /// @param opt option
  53. /// @param persist if true option is always sent.
  54. /// @param formatted_value option value in the textual format. Default
  55. /// value is empty indicating that the value is not set.
  56. OptionDescriptor(const OptionPtr& opt, bool persist,
  57. const std::string& formatted_value = "")
  58. : option_(opt), persistent_(persist),
  59. formatted_value_(formatted_value) {};
  60. /// @brief Constructor
  61. ///
  62. /// @param persist if true option is always sent.
  63. OptionDescriptor(bool persist)
  64. : option_(OptionPtr()), persistent_(persist),
  65. formatted_value_() {};
  66. /// @brief Checks if the one descriptor is equal to another.
  67. ///
  68. /// @param other Other option descriptor to compare to.
  69. ///
  70. /// @return true if descriptors equal, false otherwise.
  71. bool equals(const OptionDescriptor& other) const;
  72. /// @brief Equality operator.
  73. ///
  74. /// @param other Other option descriptor to compare to.
  75. ///
  76. /// @return true if descriptors equal, false otherwise.
  77. bool operator==(const OptionDescriptor& other) const {
  78. return (equals(other));
  79. }
  80. /// @brief Inequality operator.
  81. ///
  82. /// @param other Other option descriptor to compare to.
  83. ///
  84. /// @return true if descriptors unequal, false otherwise.
  85. bool operator!=(const OptionDescriptor& other) const {
  86. return (!equals(other));
  87. }
  88. };
  89. /// A pointer to option descriptor.
  90. typedef boost::shared_ptr<OptionDescriptor> OptionDescriptorPtr;
  91. /// @brief Multi index container for DHCP option descriptors.
  92. ///
  93. /// This container comprises three indexes to access option
  94. /// descriptors:
  95. /// - sequenced index: used to access elements in the order they
  96. /// have been added to the container,
  97. /// - option type index: used to search option descriptors containing
  98. /// options with specific option code (aka option type).
  99. /// - persistency flag index: used to search option descriptors with
  100. /// 'persistent' flag set to true.
  101. ///
  102. /// This container is the equivalent of three separate STL containers:
  103. /// - std::list of all options,
  104. /// - std::multimap of options with option code used as a multimap key,
  105. /// - std::multimap of option descriptors with option persistency flag
  106. /// used as a multimap key.
  107. /// The major advantage of this container over 3 separate STL containers
  108. /// is automatic synchronization of all indexes when elements are added,
  109. /// removed or modified in the container. With separate containers,
  110. /// the synchronization would have to be guaranteed by the Subnet class
  111. /// code. This would increase code complexity and presumably it would
  112. /// be much harder to add new search criteria (indexes).
  113. ///
  114. /// @todo we may want to search for options using option spaces when
  115. /// they are implemented.
  116. ///
  117. /// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
  118. typedef boost::multi_index_container<
  119. // Container comprises elements of OptionDescriptor type.
  120. OptionDescriptor,
  121. // Here we start enumerating various indexes.
  122. boost::multi_index::indexed_by<
  123. // Sequenced index allows accessing elements in the same way
  124. // as elements in std::list.
  125. // Sequenced is an index #0.
  126. boost::multi_index::sequenced<>,
  127. // Start definition of index #1.
  128. boost::multi_index::hashed_non_unique<
  129. // KeyFromKeyExtractor is the index key extractor that allows
  130. // accessing option type being held by the OptionPtr through
  131. // OptionDescriptor structure.
  132. KeyFromKeyExtractor<
  133. // Use option type as the index key. The type is held
  134. // in OptionPtr object so we have to call Option::getType
  135. // to retrieve this key for each element.
  136. boost::multi_index::const_mem_fun<
  137. Option,
  138. uint16_t,
  139. &Option::getType
  140. >,
  141. // Indicate that OptionPtr is a member of
  142. // OptionDescriptor structure.
  143. boost::multi_index::member<
  144. OptionDescriptor,
  145. OptionPtr,
  146. &OptionDescriptor::option_
  147. >
  148. >
  149. >,
  150. // Start definition of index #2.
  151. // Use 'persistent' struct member as a key.
  152. boost::multi_index::hashed_non_unique<
  153. boost::multi_index::member<
  154. OptionDescriptor,
  155. bool,
  156. &OptionDescriptor::persistent_
  157. >
  158. >
  159. >
  160. > OptionContainer;
  161. /// Pointer to the OptionContainer object.
  162. typedef boost::shared_ptr<OptionContainer> OptionContainerPtr;
  163. /// Type of the index #1 - option type.
  164. typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
  165. /// Pair of iterators to represent the range of options having the
  166. /// same option type value. The first element in this pair represents
  167. /// the beginning of the range, the second element represents the end.
  168. typedef std::pair<OptionContainerTypeIndex::const_iterator,
  169. OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
  170. /// Type of the index #2 - option persistency flag.
  171. typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
  172. /// @brief Represents option data configuration for the DHCP server.
  173. ///
  174. /// This class holds a collection of options to be sent to a DHCP client.
  175. /// Options are grouped by the option space or vendor identifier (for
  176. /// vendor options).
  177. ///
  178. /// The server configuration allows for specifying two distinct collections
  179. /// of options: global options and per-subnet options in which some options
  180. /// may overlap.
  181. ///
  182. /// The collection of global options specify options being sent to the client
  183. /// belonging to any subnets, i.e. global options are "inherited" by all
  184. /// subnets.
  185. ///
  186. /// The per-subnet options are configured for a particular subnet and are sent
  187. /// to clients which belong to this subnet. The values of the options specified
  188. /// for a particular subnet override the values of the global options.
  189. ///
  190. /// This class represents a single collection of options (either global or
  191. /// per-subnet). Each subnet holds its own object of the @c CfgOption type. The
  192. /// @c CfgMgr holds a @c CfgOption object representing global options.
  193. ///
  194. /// Note that having a separate copy of the @c CfgOption to represent global
  195. /// options is useful when the client requests stateless configuration from
  196. /// the DHCP server and no subnet is selected for this client. This client
  197. /// will only receive global options.
  198. class CfgOption {
  199. public:
  200. /// @brief default constructor
  201. CfgOption();
  202. /// @brief Indicates the object is empty
  203. ///
  204. /// @return true when the object is empty
  205. bool empty() const;
  206. /// @name Methods and operators used for comparing objects.
  207. ///
  208. //@{
  209. /// @brief Check if configuration is equal to other configuration.
  210. ///
  211. /// @param other An object holding configuration to compare to.
  212. ///
  213. /// @return true if configurations are equal, false otherwise.
  214. bool equals(const CfgOption& other) const;
  215. /// @brief Equality operator.
  216. ///
  217. /// @param other An object holding configuration to compare to.
  218. ///
  219. /// @return true if configurations are equal, false otherwise.
  220. bool operator==(const CfgOption& other) const {
  221. return (equals(other));
  222. }
  223. /// @brief Inequality operator.
  224. ///
  225. /// @param other An object holding configuration to compare to.
  226. ///
  227. /// @return true if configurations are unequal, false otherwise.
  228. bool operator!=(const CfgOption& other) const {
  229. return (!equals(other));
  230. }
  231. //@}
  232. /// @brief Adds instance of the option to the configuration.
  233. ///
  234. /// There are two types of options which may be passed to this method:
  235. /// - vendor options
  236. /// - non-vendor options
  237. ///
  238. /// The non-vendor options are grouped by the name of the option space
  239. /// (specified in textual format). The vendor options are grouped by the
  240. /// vendor identifier, which is a 32-bit unsigned integer value.
  241. ///
  242. /// In order to add new vendor option to the list the option space name
  243. /// (last argument of this method) should be specified as "vendor-X" where
  244. /// "X" is a 32-bit unsigned integer, e.g. "vendor-1234". Options for which
  245. /// the @c option_space argument doesn't follow this format are added as
  246. /// non-vendor options.
  247. ///
  248. /// @param option Pointer to the option being added.
  249. /// @param persistent Boolean value which specifies if the option should
  250. /// be sent to the client regardless if requested (true), or nor (false)
  251. /// @param option_space Option space name.
  252. ///
  253. /// @throw isc::BadValue if the option space is invalid.
  254. void add(const OptionPtr& option, const bool persistent,
  255. const std::string& option_space);
  256. /// @brief A variant of the method which takes option descriptor as an
  257. /// argument.
  258. ///
  259. /// This method works exactly the same as the other variant, but it takes
  260. /// option descriptor as an argument.
  261. ///
  262. /// @param desc Option descriptor holding option instance and other
  263. /// parameters pertaining to this option.
  264. /// @param option_space Option space name.
  265. ///
  266. /// @throw isc::BadValue if the option space is invalid.
  267. void add(const OptionDescriptor& desc, const std::string& option_space);
  268. /// @brief Merges this configuration to another configuration.
  269. ///
  270. /// This method iterates over the configuration items held in this
  271. /// configuration and copies them to the configuration specified
  272. /// as a parameter. If an item exists in the destination it is not
  273. /// copied.
  274. ///
  275. /// @note: this method is not longer used so should become private.
  276. ///
  277. /// @param [out] other Configuration object to merge to.
  278. void mergeTo(CfgOption& other) const;
  279. /// @brief Copies this configuration to another configuration.
  280. ///
  281. /// This method copies options configuration to another object.
  282. ///
  283. /// @param [out] other An object to copy the configuration to.
  284. void copyTo(CfgOption& other) const;
  285. /// @brief Appends encapsulated options to top-level options.
  286. ///
  287. /// This method iterates over the top-level options (from "dhcp4"
  288. /// and "dhcp6" option space) and checks which option spaces these
  289. /// options encapsulate. For each encapsulated option space, the
  290. /// options from this option space are appended to top-level options.
  291. void encapsulate();
  292. /// @brief Returns all options for the specified option space.
  293. ///
  294. /// This method will not return vendor options, i.e. having option space
  295. /// name in the format of "vendor-X" where X is 32-bit unsiged integer.
  296. /// See @c getAll(uint32_t) for vendor options.
  297. ///
  298. /// @param option_space Name of the option space.
  299. ///
  300. /// @return Pointer to the container holding returned options. This
  301. /// container is empty if no options have been found.
  302. OptionContainerPtr getAll(const std::string& option_space) const;
  303. /// @brief Returns vendor options for the specified vendor id.
  304. ///
  305. /// @param vendor_id Vendor id for which options are to be returned.
  306. ///
  307. /// @return Pointer to the container holding returned options. This
  308. /// container is empty if no options have been found.
  309. OptionContainerPtr getAll(const uint32_t vendor_id) const;
  310. /// @brief Returns option for the specified key and option code.
  311. ///
  312. /// The key should be a string, in which case it specifies an option space
  313. /// name, or an uint32_t value, in which case it specifies a vendor
  314. /// identifier.
  315. ///
  316. /// @note If there are multiple options with the same key, only one will
  317. /// be returned. No indication will be given of the presence of others,
  318. /// and the instance returned is not determinable.
  319. ///
  320. /// @param key Option space name or vendor identifier.
  321. /// @param option_code Code of the option to be returned.
  322. /// @tparam Selector one of: @c std::string or @c uint32_t
  323. ///
  324. /// @return Descriptor of the option. If option hasn't been found, the
  325. /// descriptor holds NULL option.
  326. template<typename Selector>
  327. OptionDescriptor get(const Selector& key,
  328. const uint16_t option_code) const {
  329. // Check for presence of options.
  330. OptionContainerPtr options = getAll(key);
  331. if (!options || options->empty()) {
  332. return (OptionDescriptor(false));
  333. }
  334. // Some options present, locate the one we are interested in.
  335. const OptionContainerTypeIndex& idx = options->get<1>();
  336. OptionContainerTypeIndex::const_iterator od_itr = idx.find(option_code);
  337. if (od_itr == idx.end()) {
  338. return (OptionDescriptor(false));
  339. }
  340. return (*od_itr);
  341. }
  342. /// @brief Returns a list of all configured option space names.
  343. std::list<std::string> getOptionSpaceNames() const {
  344. return (options_.getOptionSpaceNames());
  345. }
  346. /// @brief Returns a list of all configured vendor identifiers.
  347. std::list<uint32_t> getVendorIds() const {
  348. return (vendor_options_.getOptionSpaceNames());
  349. }
  350. /// @brief Returns a list of option space names for configured vendor ids.
  351. ///
  352. /// For each vendor-id the option space name returned is constructed
  353. /// as "vendor-<vendor-id>".
  354. std::list<std::string> getVendorIdsSpaceNames() const;
  355. private:
  356. /// @brief Appends encapsulated options to the options in an option space.
  357. ///
  358. /// This method appends sub-options to the options belonging to the
  359. /// particular option space. For example: if the option space "foo"
  360. /// is specified, this function will go over all options belonging to
  361. /// "foo" and will check which option spaces they encapsulate. For each
  362. /// such option it will retrieve options for these option spaces and append
  363. /// as sub-options to options belonging to "foo".
  364. ///
  365. /// @param option_space Name of the option space containing option to
  366. /// which encapsulated options are appended.
  367. void encapsulateInternal(const std::string& option_space);
  368. /// @brief Merges data from two option containers.
  369. ///
  370. /// This method merges options from one option container to another
  371. /// option container. This function is templated because containers
  372. /// may use different type of selectors. For non-vendor options
  373. /// the selector is of the @c std::string type, for vendor options
  374. /// the selector is of the @c uint32_t type.
  375. ///
  376. /// @param src_container Reference to a container from which the data
  377. /// will be merged.
  378. /// @param [out] dest_container Reference to a container to which the
  379. /// data will be merged.
  380. /// @tparam Type of the selector: @c std::string or @c uint32_t.
  381. template <typename Selector>
  382. void mergeInternal(const OptionSpaceContainer<OptionContainer,
  383. OptionDescriptor, Selector>& src_container,
  384. OptionSpaceContainer<OptionContainer,
  385. OptionDescriptor, Selector>& dest_container) const;
  386. /// @brief Type of the container holding options grouped by option space.
  387. typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
  388. std::string> OptionSpaceCollection;
  389. /// @brief Container holding options grouped by option space.
  390. OptionSpaceCollection options_;
  391. /// @brief Type of the container holding options grouped by vendor id.
  392. typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
  393. uint32_t> VendorOptionSpaceCollection;
  394. /// @brief Container holding options grouped by vendor id.
  395. VendorOptionSpaceCollection vendor_options_;
  396. };
  397. /// @name Pointers to the @c CfgOption objects.
  398. //@{
  399. /// @brief Non-const pointer.
  400. typedef boost::shared_ptr<CfgOption> CfgOptionPtr;
  401. /// @brief Const pointer.
  402. typedef boost::shared_ptr<const CfgOption> ConstCfgOptionPtr;
  403. /// @brief Const pointer list.
  404. typedef std::list<ConstCfgOptionPtr> CfgOptionList;
  405. //@}
  406. }
  407. }
  408. #endif // CFG_OPTION_H