Commit b96a30b2 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[master] Merge branch 'trac2701'

parents bf86e0c9 fc64e5bb
......@@ -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_);
}
......
......@@ -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;
......
......@@ -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()) {
......
......@@ -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;
......
......@@ -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
......
......@@ -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);
......
// 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
......@@ -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) {
......
// 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_;
......
......@@ -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.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment