Browse Source

Merge branch 'master' of git+ssh://git.bind10.isc.org/var/bind10/git/bind10

Michal 'vorner' Vaner 12 years ago
parent
commit
725dea7f0e

+ 2 - 2
src/lib/dhcp/duid.cc

@@ -41,7 +41,7 @@ DUID::DUID(const uint8_t* data, size_t len) {
     duid_ = std::vector<uint8_t>(data, data + len);
 }
 
-const std::vector<uint8_t> DUID::getDuid() const {
+std::vector<uint8_t> DUID::getDuid() const {
     return (duid_);
 }
 
@@ -91,7 +91,7 @@ ClientId::ClientId(const uint8_t *clientid, size_t len)
 }
 
 // Returns a copy of client-id data
-const std::vector<uint8_t> ClientId::getClientId() const {
+std::vector<uint8_t> ClientId::getClientId() const {
     return (duid_);
 }
 

+ 2 - 2
src/lib/dhcp/duid.h

@@ -58,7 +58,7 @@ class DUID {
     /// returned it. In any case, this method should be used only sporadically.
     /// If there are frequent uses, we must implement some other method
     /// (e.g. storeSelf()) that will avoid data copying.
-    const std::vector<uint8_t> getDuid() const;
+    std::vector<uint8_t> getDuid() const;
 
     /// @brief Returns the DUID type
     DUIDType getType() const;
@@ -105,7 +105,7 @@ public:
     ClientId(const uint8_t* clientid, size_t len);
 
     /// @brief Returns reference to the client-id data
-    const std::vector<uint8_t> getClientId() const;
+    std::vector<uint8_t> getClientId() const;
 
     /// @brief Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
     std::string toText() const;

+ 0 - 4
src/lib/dhcp/option_definition.cc

@@ -109,8 +109,6 @@ OptionPtr
 OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
                                 OptionBufferConstIter begin,
                                 OptionBufferConstIter end) const {
-    validate();
-
     try {
         switch(type_) {
         case OPT_EMPTY_TYPE:
@@ -200,8 +198,6 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
 OptionPtr
 OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
                                 const std::vector<std::string>& values) const {
-    validate();
-
     OptionBuffer buf;
     if (!array_type_ && type_ != OPT_RECORD_TYPE) {
         if (values.empty()) {

+ 19 - 3
src/lib/dhcp/option_definition.h

@@ -255,6 +255,13 @@ public:
 
     /// @brief Check if the option definition is valid.
     ///
+    /// Note that it is a responsibility of the code that created
+    /// the OptionDefinition object to validate that it is valid.
+    /// This function will not be called internally anywhere in this
+    /// class to verify that the option definition is valid. Using
+    /// invalid option definition to create an instance of the
+    /// DHCP option leads to undefined behavior.
+    ///
     /// @throw MalformedOptionDefinition option definition is invalid.
     void validate() const;
 
@@ -274,13 +281,16 @@ public:
     /// provided chunk of buffer. This function may be used to
     /// create option which is to be sent in the outgoing packet.
     ///
+    /// @warning calling this function on invalid option definition
+    /// yields undefined behavior. Use \ref validate to test that
+    /// the option definition is valid.
+    ///
     /// @param u option universe (V4 or V6).
     /// @param type option type.
     /// @param begin beginning of the option buffer.
     /// @param end end of the option buffer.
     ///
     /// @return instance of the DHCP option.
-    /// @throw MalformedOptionDefinition if option definition is invalid.
     /// @throw InvalidOptionValue if data for the option is invalid.
     OptionPtr optionFactory(Option::Universe u, uint16_t type,
                             OptionBufferConstIter begin,
@@ -292,12 +302,15 @@ public:
     /// whole provided buffer. This function may be used to
     /// create option which is to be sent in the outgoing packet.
     ///
+    /// @warning calling this function on invalid option definition
+    /// yields undefined behavior. Use \ref validate to test that
+    /// the option definition is valid.
+    ///
     /// @param u option universe (V4 or V6).
     /// @param type option type.
     /// @param buf option buffer.
     ///
     /// @return instance of the DHCP option.
-    /// @throw MalformedOptionDefinition if option definition is invalid.
     /// @throw InvalidOptionValue if data for the option is invalid.
     OptionPtr optionFactory(Option::Universe u, uint16_t type,
                             const OptionBuffer& buf = OptionBuffer()) const;
@@ -316,12 +329,15 @@ public:
     /// must be tokenized into the vector of string values and this vector
     /// can be supplied to this function.
     ///
+    /// @warning calling this function on invalid option definition
+    /// yields undefined behavior. Use \ref validate to test that
+    /// the option definition is valid.
+    ///
     /// @param u option universe (V4 or V6).
     /// @param type option type.
     /// @param values a vector of values to be used to set data for an option.
     ///
     /// @return instance of the DHCP option.
-    /// @throw MalformedOptionDefinition if option definition is invalid.
     /// @throw InvalidOptionValue if data for the option is invalid.
     OptionPtr optionFactory(Option::Universe u, uint16_t type,
                             const std::vector<std::string>& values) const;

+ 1 - 0
src/lib/dhcpsrv/Makefile.am

@@ -37,6 +37,7 @@ libb10_dhcpsrv_la_SOURCES += dbaccess_parser.cc dbaccess_parser.h
 libb10_dhcpsrv_la_SOURCES += dhcpsrv_log.cc dhcpsrv_log.h
 libb10_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
 libb10_dhcpsrv_la_SOURCES += dhcp_config_parser.h
+libb10_dhcpsrv_la_SOURCES += key_from_key.h
 libb10_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h
 libb10_dhcpsrv_la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h
 libb10_dhcpsrv_la_SOURCES += memfile_lease_mgr.cc memfile_lease_mgr.h

+ 3 - 1
src/lib/dhcpsrv/alloc_engine.cc

@@ -285,8 +285,9 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
         }
 
         // Check if there's existing lease for that subnet/clientid/hwaddr combination.
-        Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(hwaddr->hwaddr_, subnet->getID());
+        Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(*hwaddr, subnet->getID());
         if (existing) {
+            std::cout << "Got lease using HWADdr" << std::endl;
             // We have a lease already. This is a returning client, probably after
             // its reboot.
             existing = renewLease4(subnet, clientid, hwaddr, existing, fake_allocation);
@@ -301,6 +302,7 @@ AllocEngine::allocateAddress4(const SubnetPtr& subnet,
         if (clientid) {
             existing = LeaseMgrFactory::instance().getLease4(*clientid, subnet->getID());
             if (existing) {
+            std::cout << "Got lease using Clientid" << std::endl;
                 // we have a lease already. This is a returning client, probably after
                 // its reboot.
                 existing = renewLease4(subnet, clientid, hwaddr, existing, fake_allocation);

+ 82 - 0
src/lib/dhcpsrv/key_from_key.h

@@ -0,0 +1,82 @@
+// Copyright (C) 2013 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 KEY_FROM_KEY_H
+#define KEY_FROM_KEY_H
+
+#include <functional>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Utility class which cascades two key extractors.
+///
+/// The key extractor (a.k.a. key extraction class) is used by the
+/// key-based indices to obtain the indexing keys from the elements of
+/// a multi_index_container. The standard key extractors can be used
+/// to retrieve indexing key values by accessing members or methods
+/// exposed by the elements (objects or structures) stored in a
+/// multi_index_container. For example, if a container holds objects
+/// of type A, then the public members of object A or its accessors can
+/// be used by the standard extractor classes such as "member" or
+/// "const_mem_fun" respectively. Assume more complex scenario, where
+/// multi_index_container holds objects of a type A, object A exposes
+/// its public member B, which in turn exposes the accessor function
+/// returning object C. One may want to use the value C (e.g. integer)
+/// to index objects A in the container. This can't be solved by using
+/// standard key extractors because object C is nested in B and thus
+/// it is not directly accessible from A. However, it is possible
+/// to specify two distinct key extractors, one used to extract value
+/// C from B, another one to extract value B from A. These two extractors
+/// can be then wrapped by another key extractor which can be used
+/// to obtain index key C from object A. This key extractor is implemented
+/// as a functor class. The functor calls functors specified as
+/// template parameters to retrieve the index value from the cascaded
+/// structure.
+///
+/// @tparam KeyExtractor1 extractor used to extract the key value from
+/// the object containing it.
+/// @tparam KeyExtractor2 extractor used to extract the nested object
+/// containing a key.
+template<typename KeyExtractor1, typename KeyExtractor2>
+class KeyFromKeyExtractor {
+public:
+    typedef typename KeyExtractor1::result_type result_type;
+
+    /// @brief Constructor.
+    KeyFromKeyExtractor()
+        : key1_(KeyExtractor1()), key2_(KeyExtractor2()) { };
+
+    /// @brief Extract key value from the object hierarchy.
+    ///
+    /// @param arg the key value.
+    ///
+    /// @tparam key value type.
+    template<typename T>
+    result_type operator() (T& arg) const {
+        return (key1_(key2_(arg)));
+    }
+private:
+    /// Key Extractor used to extract the key value from the
+    /// object containing it.
+    KeyExtractor1 key1_;
+    /// Key Extractor used to extract the nested object
+    /// containing a key.
+    KeyExtractor2 key2_;
+};
+
+} // end of isc::dhcp namespace
+} // end of isc namespace
+
+#endif // KEY_FROM_KEY_H

+ 46 - 26
src/lib/dhcpsrv/memfile_lease_mgr.cc

@@ -56,7 +56,9 @@ Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) cons
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_GET_ADDR4).arg(addr.toText());
 
-    Lease4Storage::iterator l = storage4_.find(addr);
+    typedef Lease4Storage::nth_index<0>::type SearchIndex;
+    const SearchIndex& idx = storage4_.get<0>();
+    Lease4Storage::iterator l = idx.find(addr);
     if (l == storage4_.end()) {
         return (Lease4Ptr());
     } else {
@@ -77,16 +79,22 @@ Lease4Ptr Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr,
               DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
         .arg(hwaddr.toText());
 
-    Lease4Storage::iterator l;
-    for (l = storage4_.begin(); l != storage4_.end(); ++l) {
-        if ( ((*l)->hwaddr_ == hwaddr.hwaddr_) &&
-             ((*l)->subnet_id_ == subnet_id)) {
-            return (*l);
-        }
+    // We are going to use index #1 of the multi index container.
+    // We define SearchIndex locally in this function because
+    // currently only this function uses this index.
+    typedef Lease4Storage::nth_index<1>::type SearchIndex;
+    // Get the index.
+    const SearchIndex& idx = storage4_.get<1>();
+    // Try to find the lease using HWAddr and subnet id.
+    SearchIndex::const_iterator lease =
+        idx.find(boost::make_tuple(hwaddr.hwaddr_, subnet_id));
+    // Lease was not found. Return empty pointer to the caller.
+    if (lease == idx.end()) {
+        return Lease4Ptr();
     }
 
-    // not found
-    return (Lease4Ptr());
+    // Lease was found. Return it to the caller.
+    return (*lease);
 }
 
 Lease4Collection Memfile_LeaseMgr::getLease4(const ClientId& clientid) const {
@@ -100,16 +108,22 @@ Lease4Ptr Memfile_LeaseMgr::getLease4(const ClientId& client_id,
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
               .arg(client_id.toText());
-    Lease4Storage::iterator l;
-    for (l = storage4_.begin(); l != storage4_.end(); ++l) {
-        if ( (*(*l)->client_id_ == client_id) &&
-             ((*l)->subnet_id_ == subnet_id)) {
-            return (*l);
-        }
-    }
 
-    // not found
-    return (Lease4Ptr());
+    // We are going to use index #2 of the multi index container.
+    // We define SearchIndex locally in this function because
+    // currently only this function uses this index.
+    typedef Lease4Storage::nth_index<2>::type SearchIndex;
+    // Get the index.
+    const SearchIndex& idx = storage4_.get<2>();
+    // Try to get the lease using client id and subnet id.
+    SearchIndex::const_iterator lease =
+        idx.find(boost::make_tuple(client_id.getClientId(), subnet_id));
+    // Lease was not found. Return empty pointer to the caller.
+    if (lease == idx.end()) {
+        return Lease4Ptr();
+    }
+    // Lease was found. Return it to the caller.
+    return (*lease);
 }
 
 Lease6Ptr Memfile_LeaseMgr::getLease6(
@@ -139,15 +153,21 @@ Lease6Ptr Memfile_LeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
               DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID)
               .arg(iaid).arg(subnet_id).arg(duid.toText());
 
-    /// @todo: Slow, naive implementation. Write it using additional indexes
-    for (Lease6Storage::iterator l = storage6_.begin(); l != storage6_.end(); ++l) {
-        if ( (*((*l)->duid_) == duid) &&
-             ( (*l)->iaid_ == iaid) &&
-             ( (*l)->subnet_id_ == subnet_id)) {
-            return (*l);
-        }
+    // We are going to use index #1 of the multi index container.
+    // We define SearchIndex locally in this function because
+    // currently only this function uses this index.
+    typedef Lease6Storage::nth_index<1>::type SearchIndex;
+    // Get the index.
+    const SearchIndex& idx = storage6_.get<1>();
+    // Try to get the lease using the DUID, IAID and Subnet ID.
+    SearchIndex::const_iterator lease =
+        idx.find(boost::make_tuple(duid.getDuid(), iaid, subnet_id));
+    // Lease was not found. Return empty pointer.
+    if (lease == idx.end()) {
+        return (Lease6Ptr());
     }
-    return (Lease6Ptr());
+    // Lease was found, return it to the caller.
+    return (*lease);
 }
 
 void Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {

+ 97 - 16
src/lib/dhcpsrv/memfile_lease_mgr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 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
@@ -16,12 +16,14 @@
 #define MEMFILE_LEASE_MGR_H
 
 #include <dhcp/hwaddr.h>
+#include <dhcpsrv/key_from_key.h>
 #include <dhcpsrv/lease_mgr.h>
 
 #include <boost/multi_index/indexed_by.hpp>
 #include <boost/multi_index/member.hpp>
 #include <boost/multi_index/ordered_index.hpp>
 #include <boost/multi_index_container.hpp>
+#include <boost/multi_index/composite_key.hpp>
 
 namespace isc {
 namespace dhcp {
@@ -220,29 +222,108 @@ public:
 
 protected:
 
-    typedef boost::multi_index_container< // this is a multi-index container...
-    Lease6Ptr, // it will hold shared_ptr to leases6
-        boost::multi_index::indexed_by< // and will be sorted by
-            // IPv6 address that are unique. That particular key is a member
-            // of the Lease6 structure, is of type IOAddress and can be accessed
-            // by doing &Lease6::addr_
+    // This is a multi-index container, which holds elements that can
+    // be accessed using different search indexes.
+    typedef boost::multi_index_container<
+        // It holds pointers to Lease6 objects.
+        Lease6Ptr,
+        boost::multi_index::indexed_by<
+            // Specification of the first index starts here.
+            // This index sorts leases by IPv6 addresses represented as
+            // IOAddress objects.
             boost::multi_index::ordered_unique<
                 boost::multi_index::member<Lease, isc::asiolink::IOAddress, &Lease::addr_>
+            >,
+
+            // Specification of the second index starts here.
+            boost::multi_index::ordered_unique<
+                // This is a composite index that will be used to search for
+                // the lease using three attributes: DUID, IAID, Subnet Id.
+                boost::multi_index::composite_key<
+                    Lease6,
+                    // The DUID value can't be directly accessed from the Lease6
+                    // object because it is wrapped with the DUID object (actually
+                    // pointer to this object). Therefore we need to use
+                    // KeyFromKeyExtractor class to extract the DUID value from
+                    // this cascaded structure.
+                    KeyFromKeyExtractor<
+                        // The value of the DUID is accessed by the getDuid() method
+                        // from the DUID object.
+                        boost::multi_index::const_mem_fun<DUID, std::vector<uint8_t>,
+                                                          &DUID::getDuid>,
+                        // The DUID object is stored in the duid_ member of the
+                        // Lease6 object.
+                        boost::multi_index::member<Lease6, DuidPtr, &Lease6::duid_>
+                    >,
+                    // The two other ingredients of this index are IAID and
+                    // subnet id.
+                    boost::multi_index::member<Lease6, uint32_t, &Lease6::iaid_>,
+                    boost::multi_index::member<Lease, SubnetID, &Lease::subnet_id_>
+                >
             >
         >
-    > Lease6Storage; // Let the whole contraption be called Lease6Storage.
-
-    typedef boost::multi_index_container< // this is a multi-index container...
-    Lease4Ptr, // it will hold shared_ptr to leases6
-        boost::multi_index::indexed_by< // and will be sorted by
-            // IPv6 address that are unique. That particular key is a member
-            // of the Lease6 structure, is of type IOAddress and can be accessed
-            // by doing &Lease6::addr_
+     > Lease6Storage; // Specify the type name of this container.
+
+    // This is a multi-index container, which holds elements that can
+    // be accessed using different search indexes.
+    typedef boost::multi_index_container<
+        // It holds pointers to Lease4 objects.
+        Lease4Ptr, 
+        // Specification of search indexes starts here.
+        boost::multi_index::indexed_by<
+            // Specification of the first index starts here.
+            // This index sorts leases by IPv4 addresses represented as
+            // IOAddress objects.
             boost::multi_index::ordered_unique<
+                // The IPv4 address are held in addr_ members that belong to
+                // Lease class.
                 boost::multi_index::member<Lease, isc::asiolink::IOAddress, &Lease::addr_>
+            >,
+
+            // Specification of the second index starts here.
+            boost::multi_index::ordered_unique<
+                // This is a composite index that combines two attributes of the
+                // Lease4 object: hardware address and subnet id.
+                boost::multi_index::composite_key<
+                    Lease4,
+                    // The hardware address is held in the hwaddr_ member of the
+                    // Lease4 object.
+                    boost::multi_index::member<Lease4, std::vector<uint8_t>,
+                                               &Lease4::hwaddr_>,
+                    // The subnet id is held in the subnet_id_ member of Lease4
+                    // class. Note that the subnet_id_ is defined in the base
+                    // class (Lease) so we have to point to this class rather
+                    // than derived class: Lease4.
+                    boost::multi_index::member<Lease, SubnetID, &Lease::subnet_id_>
+                >
+            >,
+
+            // Specification of the third index starts here.
+            boost::multi_index::ordered_unique<
+                // This is a composite index that uses two values to search for a
+                // lease: client id and subnet id.
+                boost::multi_index::composite_key<
+                    Lease4,
+                    // The client id value is not directly accessible through the
+                    // Lease4 object as it is wrapped with the ClientIdPtr object.
+                    // Therefore we use the KeyFromKeyExtractor class to access
+                    // client id through this cascaded structure. The client id
+                    // is used as an index value.
+                    KeyFromKeyExtractor<
+                        // Specify that the vector holding client id value can be obtained
+                        // from the ClientId object.
+                        boost::multi_index::const_mem_fun<ClientId, std::vector<uint8_t>,
+                                                          &ClientId::getClientId>,
+                        // Specify that the ClientId object (actually pointer to it) can
+                        // be accessed by the client_id_ member of Lease4 class.
+                        boost::multi_index::member<Lease4, ClientIdPtr, &Lease4::client_id_>
+                    >,
+                    // The subnet id is accessed through the subnet_id_ member.
+                    boost::multi_index::member<Lease, uint32_t, &Lease::subnet_id_>
+                >
             >
         >
-    > Lease4Storage; // Let the whole contraption be called Lease6Storage.
+    > Lease4Storage; // Specify the type name for this container.
 
     /// @brief stores IPv4 leases
     Lease4Storage storage4_;

+ 4 - 52
src/lib/dhcpsrv/subnet.h

@@ -24,6 +24,7 @@
 
 #include <asiolink/io_address.h>
 #include <dhcp/option.h>
+#include <dhcpsrv/key_from_key.h>
 #include <dhcpsrv/option_space_container.h>
 #include <dhcpsrv/pool.h>
 #include <dhcpsrv/triplet.h>
@@ -82,55 +83,6 @@ public:
     /// A pointer to option descriptor.
     typedef boost::shared_ptr<OptionDescriptor> OptionDescriptorPtr;
 
-    /// @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
@@ -169,10 +121,10 @@ public:
             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
+                // KeyFromKeyExtractor is the index key extractor that allows
+                // accessing option type being held by the OptionPtr through
                 // OptionDescriptor structure.
-                KeyFromKey<
+                KeyFromKeyExtractor<
                     // 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.