subnet.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. // Copyright (C) 2012 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 SUBNET_H
  15. #define SUBNET_H
  16. #include <asiolink/io_address.h>
  17. #include <dhcp/pool.h>
  18. #include <dhcp/triplet.h>
  19. #include <dhcp/option.h>
  20. #include <boost/shared_ptr.hpp>
  21. #include <boost/multi_index_container.hpp>
  22. #include <boost/multi_index/hashed_index.hpp>
  23. #include <boost/multi_index/sequenced_index.hpp>
  24. #include <boost/multi_index/mem_fun.hpp>
  25. #include <boost/multi_index/member.hpp>
  26. namespace isc {
  27. namespace dhcp {
  28. /// @brief a base class for Subnet4 and Subnet6
  29. ///
  30. /// This class presents a common base for IPv4 and IPv6 subnets.
  31. /// In a physical sense, a subnet defines a single network link with all devices
  32. /// attached to it. In most cases all devices attached to a single link can
  33. /// share the same parameters. Therefore Subnet holds several values that are
  34. /// typically shared by all hosts: renew timer (T1), rebind timer (T2) and
  35. /// leased addresses lifetime (valid-lifetime). It also holds the set
  36. /// of DHCP option instances configured for the subnet. These options are
  37. /// included in DHCP messages being sent to clients which are connected
  38. /// to the particular subnet.
  39. class Subnet {
  40. public:
  41. /// @brief Option descriptor.
  42. ///
  43. /// Option descriptor holds information about option configured for
  44. /// a particular subnet. This information comprises the actual option
  45. /// instance and information whether this option is sent to DHCP client
  46. /// only on request (persistent = false) or always (persistent = true).
  47. struct OptionDescriptor {
  48. /// Option instance.
  49. OptionPtr option;
  50. /// Persistent flag, if true option is always sent to the client,
  51. /// if false option is sent to the client on request.
  52. bool persistent;
  53. /// @brief Constructor.
  54. ///
  55. /// @param opt option
  56. /// @param persist if true option is always sent.
  57. OptionDescriptor(OptionPtr& opt, bool persist)
  58. : option(opt), persistent(persist) {};
  59. };
  60. /// @brief Extractor class to extract key with another key.
  61. ///
  62. /// This class solves the problem of accessing index key values
  63. /// that are stored in objects nested in other objects.
  64. /// Each OptionDescriptor structure contains the OptionPtr object.
  65. /// The value retured by one of its accessors (getType) is used
  66. /// as an indexing value in the multi_index_container defined below.
  67. /// There is no easy way to mark that value returned by Option::getType
  68. /// should be an index of this multi_index_container. There are standard
  69. /// key extractors such as 'member' or 'mem_fun' but they are not
  70. /// sufficient here. The former can be used to mark that member of
  71. /// the structure that is held in the container should be used as an
  72. /// indexing value. The latter can be used if the indexing value is
  73. /// a product of the class being held in the container. In this complex
  74. /// scenario when the indexing value is a product of the function that
  75. /// is wrapped by the structure, this new extractor template has to be
  76. /// defined. The template class provides a 'chain' of two extractors
  77. /// to access the value returned by nested object and to use it as
  78. /// indexing value.
  79. /// For some more examples of complex keys see:
  80. /// http://www.cs.brown.edu/~jwicks/boost/libs/multi_index/doc/index.html
  81. ///
  82. /// @tparam KeyExtractor1 extractor used to access data in
  83. /// OptionDescriptor::option
  84. /// @tparam KeyExtractor2 extractor used to access
  85. /// OptionDescriptor::option member.
  86. template<typename KeyExtractor1, typename KeyExtractor2>
  87. class KeyFromKey {
  88. public:
  89. typedef typename KeyExtractor1::result_type result_type;
  90. /// @brief Constructor.
  91. KeyFromKey()
  92. : key1_(KeyExtractor1()), key2_(KeyExtractor2()) { };
  93. /// @brief Extract key with another key.
  94. ///
  95. /// @param arg the key value.
  96. ///
  97. /// @tparam key value type.
  98. template<typename T>
  99. result_type operator() (T& arg) const {
  100. return (key1_(key2_(arg)));
  101. }
  102. private:
  103. KeyExtractor1 key1_; ///< key 1.
  104. KeyExtractor2 key2_; ///< key 2.
  105. };
  106. /// @brief Multi index container for DHCP option descriptors.
  107. ///
  108. /// This container comprises three indexes to access option
  109. /// descriptors:
  110. /// - sequenced index: used to access elements in the order they
  111. /// have been added to the container,
  112. /// - option type index: used to search option descriptors containing
  113. /// options with specific option code (aka option type).
  114. /// - persistency flag index: used to search option descriptors with
  115. /// 'persistent' flag set to true.
  116. ///
  117. /// This container is the equivalent of three separate STL containers:
  118. /// - std::list of all options,
  119. /// - std::multimap of options with option code used as a multimap key,
  120. /// - std::multimap of option descriptors with option persistency flag
  121. /// used as a multimap key.
  122. /// The major advantage of this container over 3 separate STL containers
  123. /// is automatic synchronization of all indexes when elements are added,
  124. /// removed or modified in the container. With separate containers,
  125. /// the synchronization would have to be guaranteed by the Subnet class
  126. /// code. This would increase code complexity and presumably it would
  127. /// be much harder to add new search criteria (indexes).
  128. ///
  129. /// @todo we may want to search for options using option spaces when
  130. /// they are implemented.
  131. ///
  132. /// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
  133. typedef boost::multi_index_container<
  134. // Container comprises elements of OptionDescriptor type.
  135. OptionDescriptor,
  136. // Here we start enumerating various indexes.
  137. boost::multi_index::indexed_by<
  138. // Sequenced index allows accessing elements in the same way
  139. // as elements in std::list.
  140. // Sequenced is an index #0.
  141. boost::multi_index::sequenced<>,
  142. // Start definition of index #1.
  143. boost::multi_index::hashed_non_unique<
  144. // KeyFromKey is the index key extractor that allows accessing
  145. // option type being held by the OptionPtr through
  146. // OptionDescriptor structure.
  147. KeyFromKey<
  148. // Use option type as the index key. The type is held
  149. // in OptionPtr object so we have to call Option::getType
  150. // to retrieve this key for each element.
  151. boost::multi_index::mem_fun<
  152. Option,
  153. uint16_t,
  154. &Option::getType
  155. >,
  156. // Indicate that OptionPtr is a member of
  157. // OptionDescriptor structure.
  158. boost::multi_index::member<
  159. OptionDescriptor,
  160. OptionPtr,
  161. &OptionDescriptor::option
  162. >
  163. >
  164. >,
  165. // Start definition of index #2.
  166. // Use 'persistent' struct member as a key.
  167. boost::multi_index::hashed_non_unique<
  168. boost::multi_index::member<
  169. OptionDescriptor,
  170. bool,
  171. &OptionDescriptor::persistent
  172. >
  173. >
  174. >
  175. > OptionContainer;
  176. /// Type of the index #1 - option type.
  177. typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
  178. /// Pair of iterators to represent the range of options having the
  179. /// same option type value. The first element in this pair represents
  180. /// the begining of the range, the second element represents the end.
  181. typedef std::pair<OptionContainerTypeIndex::const_iterator,
  182. OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
  183. /// Type of the index #2 - option persistency flag.
  184. typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
  185. /// @brief checks if specified address is in range
  186. bool inRange(const isc::asiolink::IOAddress& addr) const;
  187. /// @brief Add new option instance to the collection.
  188. ///
  189. /// @param option option instance.
  190. /// @param persistent if true, send an option regardless if client
  191. /// requested it or not.
  192. ///
  193. /// @throw isc::BadValue if invalid option provided.
  194. void addOption(OptionPtr& option, bool persistent = false);
  195. /// @brief Delete all options configured for the subnet.
  196. void delOptions();
  197. /// @brief return valid-lifetime for addresses in that prefix
  198. Triplet<uint32_t> getValid() const {
  199. return (valid_);
  200. }
  201. /// @brief returns T1 (renew timer), expressed in seconds
  202. Triplet<uint32_t> getT1() const {
  203. return (t1_);
  204. }
  205. /// @brief returns T2 (rebind timer), expressed in seconds
  206. Triplet<uint32_t> getT2() const {
  207. return (t2_);
  208. }
  209. /// @brief Return a collection of options.
  210. ///
  211. /// @return reference to collection of options configured for a subnet.
  212. /// The returned reference is valid as long as the Subnet object which
  213. /// returned it still exists.
  214. const OptionContainer& getOptions() const {
  215. return (options_);
  216. }
  217. protected:
  218. /// @brief protected constructor
  219. //
  220. /// By making the constructor protected, we make sure that noone will
  221. /// ever instantiate that class. Pool4 and Pool6 should be used instead.
  222. Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
  223. const Triplet<uint32_t>& t1,
  224. const Triplet<uint32_t>& t2,
  225. const Triplet<uint32_t>& valid_lifetime);
  226. /// @brief virtual destructor
  227. ///
  228. /// A virtual destructor is needed because other classes
  229. /// derive from this class.
  230. virtual ~Subnet() { };
  231. /// @brief returns the next unique Subnet-ID
  232. ///
  233. /// @return the next unique Subnet-ID
  234. static uint32_t getNextID() {
  235. static uint32_t id = 0;
  236. return (id++);
  237. }
  238. /// @brief Check if option is valid and can be added to a subnet.
  239. ///
  240. /// @param option option to be validated.
  241. virtual void validateOption(const OptionPtr& option) const = 0;
  242. /// @brief subnet-id
  243. ///
  244. /// Subnet-id is a unique value that can be used to find or identify
  245. /// a Subnet4 or Subnet6.
  246. uint32_t id_;
  247. /// @brief a prefix of the subnet
  248. isc::asiolink::IOAddress prefix_;
  249. /// @brief a prefix length of the subnet
  250. uint8_t prefix_len_;
  251. /// @brief a tripet (min/default/max) holding allowed renew timer values
  252. Triplet<uint32_t> t1_;
  253. /// @brief a tripet (min/default/max) holding allowed rebind timer values
  254. Triplet<uint32_t> t2_;
  255. /// @brief a tripet (min/default/max) holding allowed valid lifetime values
  256. Triplet<uint32_t> valid_;
  257. /// @brief a collection of DHCP options configured for a subnet.
  258. OptionContainer options_;
  259. };
  260. /// @brief A configuration holder for IPv4 subnet.
  261. ///
  262. /// This class represents an IPv4 subnet.
  263. class Subnet4 : public Subnet {
  264. public:
  265. /// @brief Constructor with all parameters
  266. ///
  267. /// @param prefix Subnet4 prefix
  268. /// @param length prefix length
  269. /// @param t1 renewal timer (in seconds)
  270. /// @param t2 rebind timer (in seconds)
  271. /// @param valid_lifetime preferred lifetime of leases (in seconds)
  272. Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
  273. const Triplet<uint32_t>& t1,
  274. const Triplet<uint32_t>& t2,
  275. const Triplet<uint32_t>& valid_lifetime);
  276. /// @brief Returns a pool that specified address belongs to
  277. ///
  278. /// @param hint address that the returned pool should cover (optional)
  279. /// @return Pointer to found pool4 (or NULL)
  280. Pool4Ptr getPool4(const isc::asiolink::IOAddress& hint =
  281. isc::asiolink::IOAddress("0.0.0.0"));
  282. /// @brief Adds a new pool.
  283. /// @param pool pool to be added
  284. void addPool4(const Pool4Ptr& pool);
  285. /// @brief returns all pools
  286. ///
  287. /// The reference is only valid as long as the object that
  288. /// returned it.
  289. ///
  290. /// @return a collection of all pools
  291. const Pool4Collection& getPools() const {
  292. return pools_;
  293. }
  294. protected:
  295. /// @brief Check if option is valid and can be added to a subnet.
  296. ///
  297. /// @param option option to be validated.
  298. ///
  299. /// @throw isc::BadValue if provided option is invalid.
  300. virtual void validateOption(const OptionPtr& option) const;
  301. /// @brief collection of pools in that list
  302. Pool4Collection pools_;
  303. };
  304. /// @brief A pointer to a Subnet4 object
  305. typedef boost::shared_ptr<Subnet4> Subnet4Ptr;
  306. /// @brief A collection of Subnet6 objects
  307. typedef std::vector<Subnet4Ptr> Subnet4Collection;
  308. /// @brief A configuration holder for IPv6 subnet.
  309. ///
  310. /// This class represents an IPv6 subnet.
  311. class Subnet6 : public Subnet {
  312. public:
  313. /// @brief Constructor with all parameters
  314. ///
  315. /// @param prefix Subnet6 prefix
  316. /// @param length prefix length
  317. /// @param t1 renewal timer (in seconds)
  318. /// @param t2 rebind timer (in seconds)
  319. /// @param preferred_lifetime preferred lifetime of leases (in seconds)
  320. /// @param valid_lifetime preferred lifetime of leases (in seconds)
  321. Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
  322. const Triplet<uint32_t>& t1,
  323. const Triplet<uint32_t>& t2,
  324. const Triplet<uint32_t>& preferred_lifetime,
  325. const Triplet<uint32_t>& valid_lifetime);
  326. /// @brief Returns preverred lifetime (in seconds)
  327. ///
  328. /// @return a triplet with preferred lifetime
  329. Triplet<uint32_t> getPreferred() const {
  330. return (preferred_);
  331. }
  332. /// @brief Returns a pool that specified address belongs to
  333. ///
  334. /// @param hint address that the returned pool should cover (optional)
  335. /// @return Pointer to found pool6 (or NULL)
  336. Pool6Ptr getPool6(const isc::asiolink::IOAddress& hint =
  337. isc::asiolink::IOAddress("::"));
  338. /// @brief Adds a new pool.
  339. /// @param pool pool to be added
  340. void addPool6(const Pool6Ptr& pool);
  341. /// @brief returns all pools
  342. ///
  343. /// The reference is only valid as long as the object that
  344. /// returned it.
  345. ///
  346. /// @return a collection of all pools
  347. const Pool6Collection& getPools() const {
  348. return pools_;
  349. }
  350. protected:
  351. /// @brief Check if option is valid and can be added to a subnet.
  352. ///
  353. /// @param option option to be validated.
  354. ///
  355. /// @throw isc::BadValue if provided option is invalid.
  356. virtual void validateOption(const OptionPtr& option) const;
  357. /// @brief collection of pools in that list
  358. Pool6Collection pools_;
  359. /// @brief a triplet with preferred lifetime (in seconds)
  360. Triplet<uint32_t> preferred_;
  361. };
  362. /// @brief A pointer to a Subnet6 object
  363. typedef boost::shared_ptr<Subnet6> Subnet6Ptr;
  364. /// @brief A collection of Subnet6 objects
  365. typedef std::vector<Subnet6Ptr> Subnet6Collection;
  366. } // end of isc::dhcp namespace
  367. } // end of isc namespace
  368. #endif // SUBNET_T