cfg_option.h 17 KB

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