123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #ifndef SUBNET_H
- #define SUBNET_H
- #include <asiolink/io_address.h>
- #include <dhcp/pool.h>
- #include <dhcp/triplet.h>
- #include <dhcp/option.h>
- #include <boost/shared_ptr.hpp>
- #include <boost/multi_index_container.hpp>
- #include <boost/multi_index/hashed_index.hpp>
- #include <boost/multi_index/sequenced_index.hpp>
- #include <boost/multi_index/mem_fun.hpp>
- #include <boost/multi_index/member.hpp>
- namespace isc {
- namespace dhcp {
- /// @brief a base class for Subnet4 and Subnet6
- ///
- /// This class presents a common base for IPv4 and IPv6 subnets.
- /// In a physical sense, a subnet defines a single network link with all devices
- /// attached to it. In most cases all devices attached to a single link can
- /// share the same parameters. Therefore Subnet holds several values that are
- /// typically shared by all hosts: renew timer (T1), rebind timer (T2) and
- /// leased addresses lifetime (valid-lifetime). It also holds the set
- /// of DHCP option instances configured for the subnet. These options are
- /// included in DHCP messages being sent to clients which are connected
- /// to the particular subnet.
- ///
- /// @todo: Implement support for options here
- /// @brief Unique indentifier for a subnet (both v4 and v6)
- typedef uint32_t SubnetID;
- class Subnet {
- public:
- /// @brief Option descriptor.
- ///
- /// Option descriptor holds information about option configured for
- /// a particular subnet. This information comprises the actual option
- /// instance and information whether this option is sent to DHCP client
- /// only on request (persistent = false) or always (persistent = true).
- struct OptionDescriptor {
- /// Option instance.
- OptionPtr option;
- /// Persistent flag, if true option is always sent to the client,
- /// if false option is sent to the client on request.
- bool persistent;
- /// @brief Constructor.
- ///
- /// @param opt option
- /// @param persist if true option is always sent.
- OptionDescriptor(OptionPtr& opt, bool persist)
- : option(opt), persistent(persist) {};
- /// @brief Constructor
- ///
- /// @param persist if true option is always sent.
- OptionDescriptor(bool persist)
- : option(OptionPtr()), persistent(persist) {};
- };
- /// @brief Extractor class to extract key with another key.
- ///
- /// This class solves the problem of accessing index key values
- /// that are stored in objects nested in other objects.
- /// Each OptionDescriptor structure contains the OptionPtr object.
- /// The value retured by one of its accessors (getType) is used
- /// as an indexing value in the multi_index_container defined below.
- /// There is no easy way to mark that value returned by Option::getType
- /// should be an index of this multi_index_container. There are standard
- /// key extractors such as 'member' or 'mem_fun' but they are not
- /// sufficient here. The former can be used to mark that member of
- /// the structure that is held in the container should be used as an
- /// indexing value. The latter can be used if the indexing value is
- /// a product of the class being held in the container. In this complex
- /// scenario when the indexing value is a product of the function that
- /// is wrapped by the structure, this new extractor template has to be
- /// defined. The template class provides a 'chain' of two extractors
- /// to access the value returned by nested object and to use it as
- /// indexing value.
- /// For some more examples of complex keys see:
- /// http://www.cs.brown.edu/~jwicks/boost/libs/multi_index/doc/index.html
- ///
- /// @tparam KeyExtractor1 extractor used to access data in
- /// OptionDescriptor::option
- /// @tparam KeyExtractor2 extractor used to access
- /// OptionDescriptor::option member.
- template<typename KeyExtractor1, typename KeyExtractor2>
- class KeyFromKey {
- public:
- typedef typename KeyExtractor1::result_type result_type;
- /// @brief Constructor.
- KeyFromKey()
- : key1_(KeyExtractor1()), key2_(KeyExtractor2()) { };
- /// @brief Extract key with another key.
- ///
- /// @param arg the key value.
- ///
- /// @tparam key value type.
- template<typename T>
- result_type operator() (T& arg) const {
- return (key1_(key2_(arg)));
- }
- private:
- KeyExtractor1 key1_; ///< key 1.
- KeyExtractor2 key2_; ///< key 2.
- };
- /// @brief Multi index container for DHCP option descriptors.
- ///
- /// This container comprises three indexes to access option
- /// descriptors:
- /// - sequenced index: used to access elements in the order they
- /// have been added to the container,
- /// - option type index: used to search option descriptors containing
- /// options with specific option code (aka option type).
- /// - persistency flag index: used to search option descriptors with
- /// 'persistent' flag set to true.
- ///
- /// This container is the equivalent of three separate STL containers:
- /// - std::list of all options,
- /// - std::multimap of options with option code used as a multimap key,
- /// - std::multimap of option descriptors with option persistency flag
- /// used as a multimap key.
- /// The major advantage of this container over 3 separate STL containers
- /// is automatic synchronization of all indexes when elements are added,
- /// removed or modified in the container. With separate containers,
- /// the synchronization would have to be guaranteed by the Subnet class
- /// code. This would increase code complexity and presumably it would
- /// be much harder to add new search criteria (indexes).
- ///
- /// @todo we may want to search for options using option spaces when
- /// they are implemented.
- ///
- /// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
- typedef boost::multi_index_container<
- // Container comprises elements of OptionDescriptor type.
- OptionDescriptor,
- // Here we start enumerating various indexes.
- boost::multi_index::indexed_by<
- // Sequenced index allows accessing elements in the same way
- // as elements in std::list.
- // Sequenced is an index #0.
- boost::multi_index::sequenced<>,
- // Start definition of index #1.
- boost::multi_index::hashed_non_unique<
- // KeyFromKey is the index key extractor that allows accessing
- // option type being held by the OptionPtr through
- // OptionDescriptor structure.
- KeyFromKey<
- // Use option type as the index key. The type is held
- // in OptionPtr object so we have to call Option::getType
- // to retrieve this key for each element.
- boost::multi_index::mem_fun<
- Option,
- uint16_t,
- &Option::getType
- >,
- // Indicate that OptionPtr is a member of
- // OptionDescriptor structure.
- boost::multi_index::member<
- OptionDescriptor,
- OptionPtr,
- &OptionDescriptor::option
- >
- >
- >,
- // Start definition of index #2.
- // Use 'persistent' struct member as a key.
- boost::multi_index::hashed_non_unique<
- boost::multi_index::member<
- OptionDescriptor,
- bool,
- &OptionDescriptor::persistent
- >
- >
- >
- > OptionContainer;
- /// Type of the index #1 - option type.
- typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
- /// Pair of iterators to represent the range of options having the
- /// same option type value. The first element in this pair represents
- /// the begining of the range, the second element represents the end.
- typedef std::pair<OptionContainerTypeIndex::const_iterator,
- OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
- /// Type of the index #2 - option persistency flag.
- typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
- /// @brief checks if specified address is in range
- bool inRange(const isc::asiolink::IOAddress& addr) const;
- /// @brief Add new option instance to the collection.
- ///
- /// @param option option instance.
- /// @param persistent if true, send an option regardless if client
- /// requested it or not.
- ///
- /// @throw isc::BadValue if invalid option provided.
- void addOption(OptionPtr& option, bool persistent = false);
- /// @brief Delete all options configured for the subnet.
- void delOptions();
- /// @brief checks if the specified address is in pools
- ///
- /// Note the difference between inSubnet() and inPool(). For a given
- /// subnet (e.g. 2001::/64) there may be one or more pools defined
- /// that may or may not cover entire subnet, e.g. pool 2001::1-2001::10).
- /// inPool() returning true implies inSubnet(), but the reverse implication
- /// is not always true. For the given example, 2001::1234:abcd would return
- /// true for inSubnet(), but false for inPool() check.
- ///
- /// @param addr this address will be checked if it belongs to any pools in
- /// that subnet
- /// @return true if the address is in any of the pools
- virtual bool inPool(const isc::asiolink::IOAddress& addr) const = 0;
- /// @brief return valid-lifetime for addresses in that prefix
- Triplet<uint32_t> getValid() const {
- return (valid_);
- }
- /// @brief returns T1 (renew timer), expressed in seconds
- Triplet<uint32_t> getT1() const {
- return (t1_);
- }
- /// @brief returns T2 (rebind timer), expressed in seconds
- Triplet<uint32_t> getT2() const {
- return (t2_);
- }
- /// @brief Return a collection of options.
- ///
- /// @return reference to collection of options configured for a subnet.
- /// The returned reference is valid as long as the Subnet object which
- /// returned it still exists.
- const OptionContainer& getOptions() const {
- return (options_);
- }
- /// @brief returns the last address that was tried from this pool
- ///
- /// This method returns the last address that was attempted to be allocated
- /// from this subnet. This is used as helper information for the next
- /// iteration of the allocation algorithm.
- ///
- /// @todo: Define map<SubnetID, IOAddress> somewhere in the
- /// AllocEngine::IterativeAllocator and keep the data there
- ///
- /// @return address that was last tried from this pool
- isc::asiolink::IOAddress getLastAllocated() const {
- return (last_allocated_);
- }
- /// @brief sets the last address that was tried from this pool
- ///
- /// This method sets the last address that was attempted to be allocated
- /// from this subnet. This is used as helper information for the next
- /// iteration of the allocation algorithm.
- ///
- /// @todo: Define map<SubnetID, IOAddress> somewhere in the
- /// AllocEngine::IterativeAllocator and keep the data there
- void setLastAllocated(const isc::asiolink::IOAddress& addr) {
- last_allocated_ = addr;
- }
- /// @brief returns unique ID for that subnet
- /// @return unique ID for that subnet
- SubnetID getID() const { return (id_); }
- protected:
- /// @brief protected constructor
- //
- /// By making the constructor protected, we make sure that noone will
- /// ever instantiate that class. Pool4 and Pool6 should be used instead.
- Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
- const Triplet<uint32_t>& t1,
- const Triplet<uint32_t>& t2,
- const Triplet<uint32_t>& valid_lifetime);
- /// @brief virtual destructor
- ///
- /// A virtual destructor is needed because other classes
- /// derive from this class.
- virtual ~Subnet() { };
- /// @brief returns the next unique Subnet-ID
- ///
- /// @return the next unique Subnet-ID
- static SubnetID getNextID() {
- static SubnetID id = 0;
- return (id++);
- }
- /// @brief Check if option is valid and can be added to a subnet.
- ///
- /// @param option option to be validated.
- virtual void validateOption(const OptionPtr& option) const = 0;
- /// @brief subnet-id
- ///
- /// Subnet-id is a unique value that can be used to find or identify
- /// a Subnet4 or Subnet6.
- SubnetID id_;
- /// @brief a prefix of the subnet
- isc::asiolink::IOAddress prefix_;
- /// @brief a prefix length of the subnet
- uint8_t prefix_len_;
- /// @brief a tripet (min/default/max) holding allowed renew timer values
- Triplet<uint32_t> t1_;
- /// @brief a tripet (min/default/max) holding allowed rebind timer values
- Triplet<uint32_t> t2_;
- /// @brief a tripet (min/default/max) holding allowed valid lifetime values
- Triplet<uint32_t> valid_;
- /// @brief a collection of DHCP options configured for a subnet.
- OptionContainer options_;
- /// @brief last allocated address
- ///
- /// This is the last allocated address that was previously allocated from
- /// this particular subnet. Some allocation algorithms (e.g. iterative) use
- /// that value, others do not. It should be noted that although the value
- /// is usually correct, there are cases when it is invalid, e.g. after
- /// removing a pool, restarting or changing allocation algorithms. For
- /// that purpose it should be only considered a help that should not be
- /// fully trusted.
- isc::asiolink::IOAddress last_allocated_;
- };
- /// @brief A configuration holder for IPv4 subnet.
- ///
- /// This class represents an IPv4 subnet.
- class Subnet4 : public Subnet {
- public:
- /// @brief Constructor with all parameters
- ///
- /// @param prefix Subnet4 prefix
- /// @param length prefix length
- /// @param t1 renewal timer (in seconds)
- /// @param t2 rebind timer (in seconds)
- /// @param valid_lifetime preferred lifetime of leases (in seconds)
- Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
- const Triplet<uint32_t>& t1,
- const Triplet<uint32_t>& t2,
- const Triplet<uint32_t>& valid_lifetime);
- /// @brief Returns a pool that specified address belongs to
- ///
- /// @param hint address that the returned pool should cover (optional)
- /// @return Pointer to found pool4 (or NULL)
- Pool4Ptr getPool4(const isc::asiolink::IOAddress& hint =
- isc::asiolink::IOAddress("0.0.0.0"));
- /// @brief Adds a new pool.
- /// @param pool pool to be added
- void addPool4(const Pool4Ptr& pool);
- /// @brief returns all pools
- ///
- /// The reference is only valid as long as the object that returned it.
- ///
- /// @return a collection of all pools
- const Pool4Collection& getPools() const {
- return pools_;
- }
- /// @brief checks if the specified address is in pools
- ///
- /// See the description in \ref Subnet::inPool().
- ///
- /// @param addr this address will be checked if it belongs to any pools in that subnet
- /// @return true if the address is in any of the pools
- bool inPool(const isc::asiolink::IOAddress& addr) const;
- protected:
- /// @brief Check if option is valid and can be added to a subnet.
- ///
- /// @param option option to be validated.
- ///
- /// @throw isc::BadValue if provided option is invalid.
- virtual void validateOption(const OptionPtr& option) const;
- /// @brief collection of pools in that list
- Pool4Collection pools_;
- };
- /// @brief A pointer to a Subnet4 object
- typedef boost::shared_ptr<Subnet4> Subnet4Ptr;
- /// @brief A collection of Subnet6 objects
- typedef std::vector<Subnet4Ptr> Subnet4Collection;
- /// @brief A configuration holder for IPv6 subnet.
- ///
- /// This class represents an IPv6 subnet.
- class Subnet6 : public Subnet {
- public:
- /// @brief Constructor with all parameters
- ///
- /// @param prefix Subnet6 prefix
- /// @param length prefix length
- /// @param t1 renewal timer (in seconds)
- /// @param t2 rebind timer (in seconds)
- /// @param preferred_lifetime preferred lifetime of leases (in seconds)
- /// @param valid_lifetime preferred lifetime of leases (in seconds)
- Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
- const Triplet<uint32_t>& t1,
- const Triplet<uint32_t>& t2,
- const Triplet<uint32_t>& preferred_lifetime,
- const Triplet<uint32_t>& valid_lifetime);
- /// @brief Returns preverred lifetime (in seconds)
- ///
- /// @return a triplet with preferred lifetime
- Triplet<uint32_t> getPreferred() const {
- return (preferred_);
- }
- /// @brief Returns a pool that specified address belongs to
- ///
- /// @param hint address that the returned pool should cover (optional)
- /// @return Pointer to found pool6 (or NULL)
- Pool6Ptr getPool6(const isc::asiolink::IOAddress& hint =
- isc::asiolink::IOAddress("::"));
- /// @brief Adds a new pool.
- /// @param pool pool to be added
- void addPool6(const Pool6Ptr& pool);
- /// @brief returns all pools
- ///
- /// The reference is only valid as long as the object that
- /// returned it.
- ///
- /// @return a collection of all pools
- const Pool6Collection& getPools() const {
- return pools_;
- }
- /// @brief checks if the specified address is in pools
- ///
- /// See the description in \ref Subnet::inPool().
- ///
- /// @param addr this address will be checked if it belongs to any pools in that subnet
- /// @return true if the address is in any of the pools
- bool inPool(const isc::asiolink::IOAddress& addr) const;
- protected:
- /// @brief Check if option is valid and can be added to a subnet.
- ///
- /// @param option option to be validated.
- ///
- /// @throw isc::BadValue if provided option is invalid.
- virtual void validateOption(const OptionPtr& option) const;
- /// @brief collection of pools in that list
- Pool6Collection pools_;
- /// @brief a triplet with preferred lifetime (in seconds)
- Triplet<uint32_t> preferred_;
- };
- /// @brief A pointer to a Subnet6 object
- typedef boost::shared_ptr<Subnet6> Subnet6Ptr;
- /// @brief A collection of Subnet6 objects
- typedef std::vector<Subnet6Ptr> Subnet6Collection;
- } // end of isc::dhcp namespace
- } // end of isc namespace
- #endif // SUBNET_T
|