cfg_option.h 17 KB

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