subnet.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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. ///
  40. /// @todo: Implement support for options here
  41. /// @brief Unique indentifier for a subnet (both v4 and v6)
  42. typedef uint32_t SubnetID;
  43. class Subnet {
  44. public:
  45. /// @brief Option descriptor.
  46. ///
  47. /// Option descriptor holds information about option configured for
  48. /// a particular subnet. This information comprises the actual option
  49. /// instance and information whether this option is sent to DHCP client
  50. /// only on request (persistent = false) or always (persistent = true).
  51. struct OptionDescriptor {
  52. /// Option instance.
  53. OptionPtr option;
  54. /// Persistent flag, if true option is always sent to the client,
  55. /// if false option is sent to the client on request.
  56. bool persistent;
  57. /// @brief Constructor.
  58. ///
  59. /// @param opt option
  60. /// @param persist if true option is always sent.
  61. OptionDescriptor(OptionPtr& opt, bool persist)
  62. : option(opt), persistent(persist) {};
  63. /// @brief Constructor
  64. ///
  65. /// @param persist if true option is always sent.
  66. OptionDescriptor(bool persist)
  67. : option(OptionPtr()), persistent(persist) {};
  68. };
  69. /// @brief Extractor class to extract key with another key.
  70. ///
  71. /// This class solves the problem of accessing index key values
  72. /// that are stored in objects nested in other objects.
  73. /// Each OptionDescriptor structure contains the OptionPtr object.
  74. /// The value retured by one of its accessors (getType) is used
  75. /// as an indexing value in the multi_index_container defined below.
  76. /// There is no easy way to mark that value returned by Option::getType
  77. /// should be an index of this multi_index_container. There are standard
  78. /// key extractors such as 'member' or 'mem_fun' but they are not
  79. /// sufficient here. The former can be used to mark that member of
  80. /// the structure that is held in the container should be used as an
  81. /// indexing value. The latter can be used if the indexing value is
  82. /// a product of the class being held in the container. In this complex
  83. /// scenario when the indexing value is a product of the function that
  84. /// is wrapped by the structure, this new extractor template has to be
  85. /// defined. The template class provides a 'chain' of two extractors
  86. /// to access the value returned by nested object and to use it as
  87. /// indexing value.
  88. /// For some more examples of complex keys see:
  89. /// http://www.cs.brown.edu/~jwicks/boost/libs/multi_index/doc/index.html
  90. ///
  91. /// @tparam KeyExtractor1 extractor used to access data in
  92. /// OptionDescriptor::option
  93. /// @tparam KeyExtractor2 extractor used to access
  94. /// OptionDescriptor::option member.
  95. template<typename KeyExtractor1, typename KeyExtractor2>
  96. class KeyFromKey {
  97. public:
  98. typedef typename KeyExtractor1::result_type result_type;
  99. /// @brief Constructor.
  100. KeyFromKey()
  101. : key1_(KeyExtractor1()), key2_(KeyExtractor2()) { };
  102. /// @brief Extract key with another key.
  103. ///
  104. /// @param arg the key value.
  105. ///
  106. /// @tparam key value type.
  107. template<typename T>
  108. result_type operator() (T& arg) const {
  109. return (key1_(key2_(arg)));
  110. }
  111. private:
  112. KeyExtractor1 key1_; ///< key 1.
  113. KeyExtractor2 key2_; ///< key 2.
  114. };
  115. /// @brief Multi index container for DHCP option descriptors.
  116. ///
  117. /// This container comprises three indexes to access option
  118. /// descriptors:
  119. /// - sequenced index: used to access elements in the order they
  120. /// have been added to the container,
  121. /// - option type index: used to search option descriptors containing
  122. /// options with specific option code (aka option type).
  123. /// - persistency flag index: used to search option descriptors with
  124. /// 'persistent' flag set to true.
  125. ///
  126. /// This container is the equivalent of three separate STL containers:
  127. /// - std::list of all options,
  128. /// - std::multimap of options with option code used as a multimap key,
  129. /// - std::multimap of option descriptors with option persistency flag
  130. /// used as a multimap key.
  131. /// The major advantage of this container over 3 separate STL containers
  132. /// is automatic synchronization of all indexes when elements are added,
  133. /// removed or modified in the container. With separate containers,
  134. /// the synchronization would have to be guaranteed by the Subnet class
  135. /// code. This would increase code complexity and presumably it would
  136. /// be much harder to add new search criteria (indexes).
  137. ///
  138. /// @todo we may want to search for options using option spaces when
  139. /// they are implemented.
  140. ///
  141. /// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
  142. typedef boost::multi_index_container<
  143. // Container comprises elements of OptionDescriptor type.
  144. OptionDescriptor,
  145. // Here we start enumerating various indexes.
  146. boost::multi_index::indexed_by<
  147. // Sequenced index allows accessing elements in the same way
  148. // as elements in std::list.
  149. // Sequenced is an index #0.
  150. boost::multi_index::sequenced<>,
  151. // Start definition of index #1.
  152. boost::multi_index::hashed_non_unique<
  153. // KeyFromKey is the index key extractor that allows accessing
  154. // option type being held by the OptionPtr through
  155. // OptionDescriptor structure.
  156. KeyFromKey<
  157. // Use option type as the index key. The type is held
  158. // in OptionPtr object so we have to call Option::getType
  159. // to retrieve this key for each element.
  160. boost::multi_index::mem_fun<
  161. Option,
  162. uint16_t,
  163. &Option::getType
  164. >,
  165. // Indicate that OptionPtr is a member of
  166. // OptionDescriptor structure.
  167. boost::multi_index::member<
  168. OptionDescriptor,
  169. OptionPtr,
  170. &OptionDescriptor::option
  171. >
  172. >
  173. >,
  174. // Start definition of index #2.
  175. // Use 'persistent' struct member as a key.
  176. boost::multi_index::hashed_non_unique<
  177. boost::multi_index::member<
  178. OptionDescriptor,
  179. bool,
  180. &OptionDescriptor::persistent
  181. >
  182. >
  183. >
  184. > OptionContainer;
  185. /// Type of the index #1 - option type.
  186. typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
  187. /// Pair of iterators to represent the range of options having the
  188. /// same option type value. The first element in this pair represents
  189. /// the begining of the range, the second element represents the end.
  190. typedef std::pair<OptionContainerTypeIndex::const_iterator,
  191. OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
  192. /// Type of the index #2 - option persistency flag.
  193. typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
  194. /// @brief checks if specified address is in range
  195. bool inRange(const isc::asiolink::IOAddress& addr) const;
  196. /// @brief Add new option instance to the collection.
  197. ///
  198. /// @param option option instance.
  199. /// @param persistent if true, send an option regardless if client
  200. /// requested it or not.
  201. ///
  202. /// @throw isc::BadValue if invalid option provided.
  203. void addOption(OptionPtr& option, bool persistent = false);
  204. /// @brief Delete all options configured for the subnet.
  205. void delOptions();
  206. /// @brief checks if the specified address is in pools
  207. ///
  208. /// Note the difference between inSubnet() and inPool(). For a given
  209. /// subnet (e.g. 2001::/64) there may be one or more pools defined
  210. /// that may or may not cover entire subnet, e.g. pool 2001::1-2001::10).
  211. /// inPool() returning true implies inSubnet(), but the reverse implication
  212. /// is not always true. For the given example, 2001::1234:abcd would return
  213. /// true for inSubnet(), but false for inPool() check.
  214. ///
  215. /// @param addr this address will be checked if it belongs to any pools in
  216. /// that subnet
  217. /// @return true if the address is in any of the pools
  218. virtual bool inPool(const isc::asiolink::IOAddress& addr) const = 0;
  219. /// @brief return valid-lifetime for addresses in that prefix
  220. Triplet<uint32_t> getValid() const {
  221. return (valid_);
  222. }
  223. /// @brief returns T1 (renew timer), expressed in seconds
  224. Triplet<uint32_t> getT1() const {
  225. return (t1_);
  226. }
  227. /// @brief returns T2 (rebind timer), expressed in seconds
  228. Triplet<uint32_t> getT2() const {
  229. return (t2_);
  230. }
  231. /// @brief Return a collection of options.
  232. ///
  233. /// @return reference to collection of options configured for a subnet.
  234. /// The returned reference is valid as long as the Subnet object which
  235. /// returned it still exists.
  236. const OptionContainer& getOptions() const {
  237. return (options_);
  238. }
  239. /// @brief returns the last address that was tried from this pool
  240. ///
  241. /// This method returns the last address that was attempted to be allocated
  242. /// from this subnet. This is used as helper information for the next
  243. /// iteration of the allocation algorithm.
  244. ///
  245. /// @todo: Define map<SubnetID, IOAddress> somewhere in the
  246. /// AllocEngine::IterativeAllocator and keep the data there
  247. ///
  248. /// @return address that was last tried from this pool
  249. isc::asiolink::IOAddress getLastAllocated() const {
  250. return (last_allocated_);
  251. }
  252. /// @brief sets the last address that was tried from this pool
  253. ///
  254. /// This method sets the last address that was attempted to be allocated
  255. /// from this subnet. This is used as helper information for the next
  256. /// iteration of the allocation algorithm.
  257. ///
  258. /// @todo: Define map<SubnetID, IOAddress> somewhere in the
  259. /// AllocEngine::IterativeAllocator and keep the data there
  260. void setLastAllocated(const isc::asiolink::IOAddress& addr) {
  261. last_allocated_ = addr;
  262. }
  263. /// @brief returns unique ID for that subnet
  264. /// @return unique ID for that subnet
  265. SubnetID getID() const { return (id_); }
  266. protected:
  267. /// @brief protected constructor
  268. //
  269. /// By making the constructor protected, we make sure that noone will
  270. /// ever instantiate that class. Pool4 and Pool6 should be used instead.
  271. Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
  272. const Triplet<uint32_t>& t1,
  273. const Triplet<uint32_t>& t2,
  274. const Triplet<uint32_t>& valid_lifetime);
  275. /// @brief virtual destructor
  276. ///
  277. /// A virtual destructor is needed because other classes
  278. /// derive from this class.
  279. virtual ~Subnet() { };
  280. /// @brief returns the next unique Subnet-ID
  281. ///
  282. /// @return the next unique Subnet-ID
  283. static SubnetID getNextID() {
  284. static SubnetID id = 0;
  285. return (id++);
  286. }
  287. /// @brief Check if option is valid and can be added to a subnet.
  288. ///
  289. /// @param option option to be validated.
  290. virtual void validateOption(const OptionPtr& option) const = 0;
  291. /// @brief subnet-id
  292. ///
  293. /// Subnet-id is a unique value that can be used to find or identify
  294. /// a Subnet4 or Subnet6.
  295. SubnetID id_;
  296. /// @brief a prefix of the subnet
  297. isc::asiolink::IOAddress prefix_;
  298. /// @brief a prefix length of the subnet
  299. uint8_t prefix_len_;
  300. /// @brief a tripet (min/default/max) holding allowed renew timer values
  301. Triplet<uint32_t> t1_;
  302. /// @brief a tripet (min/default/max) holding allowed rebind timer values
  303. Triplet<uint32_t> t2_;
  304. /// @brief a tripet (min/default/max) holding allowed valid lifetime values
  305. Triplet<uint32_t> valid_;
  306. /// @brief a collection of DHCP options configured for a subnet.
  307. OptionContainer options_;
  308. /// @brief last allocated address
  309. ///
  310. /// This is the last allocated address that was previously allocated from
  311. /// this particular subnet. Some allocation algorithms (e.g. iterative) use
  312. /// that value, others do not. It should be noted that although the value
  313. /// is usually correct, there are cases when it is invalid, e.g. after
  314. /// removing a pool, restarting or changing allocation algorithms. For
  315. /// that purpose it should be only considered a help that should not be
  316. /// fully trusted.
  317. isc::asiolink::IOAddress last_allocated_;
  318. };
  319. /// @brief A configuration holder for IPv4 subnet.
  320. ///
  321. /// This class represents an IPv4 subnet.
  322. class Subnet4 : public Subnet {
  323. public:
  324. /// @brief Constructor with all parameters
  325. ///
  326. /// @param prefix Subnet4 prefix
  327. /// @param length prefix length
  328. /// @param t1 renewal timer (in seconds)
  329. /// @param t2 rebind timer (in seconds)
  330. /// @param valid_lifetime preferred lifetime of leases (in seconds)
  331. Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
  332. const Triplet<uint32_t>& t1,
  333. const Triplet<uint32_t>& t2,
  334. const Triplet<uint32_t>& valid_lifetime);
  335. /// @brief Returns a pool that specified address belongs to
  336. ///
  337. /// @param hint address that the returned pool should cover (optional)
  338. /// @return Pointer to found pool4 (or NULL)
  339. Pool4Ptr getPool4(const isc::asiolink::IOAddress& hint =
  340. isc::asiolink::IOAddress("0.0.0.0"));
  341. /// @brief Adds a new pool.
  342. /// @param pool pool to be added
  343. void addPool4(const Pool4Ptr& pool);
  344. /// @brief returns all pools
  345. ///
  346. /// The reference is only valid as long as the object that returned it.
  347. ///
  348. /// @return a collection of all pools
  349. const Pool4Collection& getPools() const {
  350. return pools_;
  351. }
  352. /// @brief checks if the specified address is in pools
  353. ///
  354. /// See the description in \ref Subnet::inPool().
  355. ///
  356. /// @param addr this address will be checked if it belongs to any pools in that subnet
  357. /// @return true if the address is in any of the pools
  358. bool inPool(const isc::asiolink::IOAddress& addr) const;
  359. protected:
  360. /// @brief Check if option is valid and can be added to a subnet.
  361. ///
  362. /// @param option option to be validated.
  363. ///
  364. /// @throw isc::BadValue if provided option is invalid.
  365. virtual void validateOption(const OptionPtr& option) const;
  366. /// @brief collection of pools in that list
  367. Pool4Collection pools_;
  368. };
  369. /// @brief A pointer to a Subnet4 object
  370. typedef boost::shared_ptr<Subnet4> Subnet4Ptr;
  371. /// @brief A collection of Subnet6 objects
  372. typedef std::vector<Subnet4Ptr> Subnet4Collection;
  373. /// @brief A configuration holder for IPv6 subnet.
  374. ///
  375. /// This class represents an IPv6 subnet.
  376. class Subnet6 : public Subnet {
  377. public:
  378. /// @brief Constructor with all parameters
  379. ///
  380. /// @param prefix Subnet6 prefix
  381. /// @param length prefix length
  382. /// @param t1 renewal timer (in seconds)
  383. /// @param t2 rebind timer (in seconds)
  384. /// @param preferred_lifetime preferred lifetime of leases (in seconds)
  385. /// @param valid_lifetime preferred lifetime of leases (in seconds)
  386. Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
  387. const Triplet<uint32_t>& t1,
  388. const Triplet<uint32_t>& t2,
  389. const Triplet<uint32_t>& preferred_lifetime,
  390. const Triplet<uint32_t>& valid_lifetime);
  391. /// @brief Returns preverred lifetime (in seconds)
  392. ///
  393. /// @return a triplet with preferred lifetime
  394. Triplet<uint32_t> getPreferred() const {
  395. return (preferred_);
  396. }
  397. /// @brief Returns a pool that specified address belongs to
  398. ///
  399. /// @param hint address that the returned pool should cover (optional)
  400. /// @return Pointer to found pool6 (or NULL)
  401. Pool6Ptr getPool6(const isc::asiolink::IOAddress& hint =
  402. isc::asiolink::IOAddress("::"));
  403. /// @brief Adds a new pool.
  404. /// @param pool pool to be added
  405. void addPool6(const Pool6Ptr& pool);
  406. /// @brief returns all pools
  407. ///
  408. /// The reference is only valid as long as the object that
  409. /// returned it.
  410. ///
  411. /// @return a collection of all pools
  412. const Pool6Collection& getPools() const {
  413. return pools_;
  414. }
  415. /// @brief checks if the specified address is in pools
  416. ///
  417. /// See the description in \ref Subnet::inPool().
  418. ///
  419. /// @param addr this address will be checked if it belongs to any pools in that subnet
  420. /// @return true if the address is in any of the pools
  421. bool inPool(const isc::asiolink::IOAddress& addr) const;
  422. protected:
  423. /// @brief Check if option is valid and can be added to a subnet.
  424. ///
  425. /// @param option option to be validated.
  426. ///
  427. /// @throw isc::BadValue if provided option is invalid.
  428. virtual void validateOption(const OptionPtr& option) const;
  429. /// @brief collection of pools in that list
  430. Pool6Collection pools_;
  431. /// @brief a triplet with preferred lifetime (in seconds)
  432. Triplet<uint32_t> preferred_;
  433. };
  434. /// @brief A pointer to a Subnet6 object
  435. typedef boost::shared_ptr<Subnet6> Subnet6Ptr;
  436. /// @brief A collection of Subnet6 objects
  437. typedef std::vector<Subnet6Ptr> Subnet6Collection;
  438. } // end of isc::dhcp namespace
  439. } // end of isc namespace
  440. #endif // SUBNET_T