cfg_option.h 17 KB

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