The function is intended to run at the end of the server configuration.
It should iterate over the subnets and for each allocator register suitable
callbacks in the LeaseMgr. Currently, it is no-op.
#include <config.h>
#include <dhcpsrv/allocator.h>
+#include <dhcpsrv/lease_mgr_factory.h>
using namespace isc::util;
namespace isc {
namespace dhcp {
-bool Allocator::isValidPrefixPool(Allocator::PrefixLenMatchType prefix_length_match,
+Allocator::Allocator(Lease::Type type, const WeakSubnetPtr& subnet)
+ : pool_type_(type),
+ subnet_id_(0),
+ subnet_(subnet) {
+ // Remember subnet ID in a separate variable. It may be needed in
+ // the destructor where the subnet weak pointer is unavailable.
+ subnet_id_ = subnet_.lock()->getID();
+}
+
+Allocator::~Allocator() {
+ if (!LeaseMgrFactory::haveInstance()) {
+ // If there is no lease manager instance, the callbacks are
+ // gone already anyway.
+ return;
+ }
+ // Remove the callbacks.
+ auto& lease_mgr = LeaseMgrFactory::instance();
+ lease_mgr.unregisterCallbacks(subnet_id_, pool_type_);
+}
+
+bool
+Allocator::isValidPrefixPool(Allocator::PrefixLenMatchType prefix_length_match,
PoolPtr pool, uint8_t hint_prefix_length) {
auto pool6 = boost::dynamic_pointer_cast<Pool6>(pool);
if (!pool6) {
#include <dhcp/duid.h>
#include <exceptions/exceptions.h>
#include <dhcpsrv/lease.h>
+#include <dhcpsrv/subnet_id.h>
#include <dhcpsrv/pool.h>
#include <util/multi_threading_mgr.h>
#include <boost/shared_ptr.hpp>
/// @param type specifies pool type (addresses, temporary addresses
/// or prefixes).
/// @param subnet weak pointer to the subnet owning the allocator.
- Allocator(Lease::Type type, const WeakSubnetPtr& subnet)
- : pool_type_(type),
- subnet_(subnet) {
- }
+ Allocator(Lease::Type type, const WeakSubnetPtr& subnet);
- /// @brief Virtual destructor
- virtual ~Allocator() = default;
+ /// @brief Virtual destructor.
+ ///
+ /// Removes all LeaseMgr callbacks it installed.
+ virtual ~Allocator();
/// @brief Picks an address.
///
static bool isValidPrefixPool(Allocator::PrefixLenMatchType prefix_length_match,
PoolPtr pool, uint8_t hint_prefix_length);
+ /// @brief Performs allocator initialization after server's reconfiguration.
+ ///
+ /// Some allocators install callbacks in the lease manager to keep track of
+ /// the lease allocations. These callbacks may only be installed when the
+ /// lease manager instance is available (i.e., when the server finishes the
+ /// reconfiguration). Such callbacks can be installed in this function.
+ ///
+ /// In this function, the allocators can also re-build their allocation states.
+ virtual void initAfterConfigure() {};
+
private:
/// @brief Picks an address.
/// @brief Defines pool type allocation
Lease::Type pool_type_;
+ /// @brief ID of a subnet to which the allocator belongs.
+ SubnetID subnet_id_;
+
/// @brief Weak pointer to the subnet owning the allocator.
WeakSubnetPtr subnet_;
}
}
+void
+CfgSubnets4::initAllocatorsAfterConfigure() {
+ for (auto subnet : subnets_) {
+ subnet->initAllocatorsAfterConfigure();
+ }
+}
+
ElementPtr
CfgSubnets4::toElement() const {
ElementPtr result = Element::createList();
/// configuration and also subnet-ids may change.
void removeStatistics();
+ /// @brief Calls @c initAllocatorsAfterConfigure for each subnet.
+ void initAllocatorsAfterConfigure();
+
/// @brief Unparse a configuration object
///
/// @return a pointer to unparsed configuration
}
}
+void
+CfgSubnets6::initAllocatorsAfterConfigure() {
+ for (auto subnet : subnets_) {
+ subnet->initAllocatorsAfterConfigure();
+ }
+}
+
ElementPtr
CfgSubnets6::toElement() const {
ElementPtr result = Element::createList();
/// configuration and also subnet-ids may change.
void removeStatistics();
+ /// @brief Calls @c initAllocatorsAfterConfigure for each subnet.
+ void initAllocatorsAfterConfigure();
+
/// @brief Unparse a configuration object
///
/// @return a pointer to unparsed configuration
extern const isc::log::MessageID DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED = "DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED";
extern const isc::log::MessageID DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL = "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL";
extern const isc::log::MessageID DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED = "DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED";
+extern const isc::log::MessageID DHCPSRV_LEASE_MGR_CALLBACK_EXCEPTION = "DHCPSRV_LEASE_MGR_CALLBACK_EXCEPTION";
+extern const isc::log::MessageID DHCPSRV_LEASE_MGR_CALLBACK_UNKNOWN_EXCEPTION = "DHCPSRV_LEASE_MGR_CALLBACK_UNKNOWN_EXCEPTION";
extern const isc::log::MessageID DHCPSRV_LEASE_SANITY_FAIL = "DHCPSRV_LEASE_SANITY_FAIL";
extern const isc::log::MessageID DHCPSRV_LEASE_SANITY_FAIL_DISCARD = "DHCPSRV_LEASE_SANITY_FAIL_DISCARD";
extern const isc::log::MessageID DHCPSRV_LEASE_SANITY_FIXED = "DHCPSRV_LEASE_SANITY_FIXED";
"DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED", "extended info for lease %1 was upgraded",
"DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL", "extended info for lease %1 failed checks (%2)",
"DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED", "extended info for lease %1 was upgraded",
+ "DHCPSRV_LEASE_MGR_CALLBACK_EXCEPTION", "exception occurred in a lease manager callback for callback type %1, subnet id %2, and lease %3: %4",
+ "DHCPSRV_LEASE_MGR_CALLBACK_UNKNOWN_EXCEPTION", "unknown exception occurred in a lease manager callback for callback type %1, subnet id %2, and lease %3",
"DHCPSRV_LEASE_SANITY_FAIL", "The lease %1 with subnet-id %2 failed subnet-id checks (%3).",
"DHCPSRV_LEASE_SANITY_FAIL_DISCARD", "The lease %1 with subnet-id %2 failed subnet-id checks (%3) and was dropped.",
"DHCPSRV_LEASE_SANITY_FIXED", "The lease %1 with subnet-id %2 failed subnet-id checks, but was corrected to subnet-id %3.",
return (candidate);
}
+void
+Subnet::initAllocatorsAfterConfigure() {
+ for (auto allocator : allocators_) {
+ allocator.second->initAfterConfigure();
+ }
+}
+
const PoolPtr Subnet::getPool(Lease::Type type,
const ClientClasses& client_classes,
const isc::asiolink::IOAddress& hint) const {
/// @param allocation_state allocation state instance.
void setAllocationState(Lease::Type type, const SubnetAllocationStatePtr& allocation_state);
+ /// @brief Calls @c initAfterConfigure for each allocator.
+ void initAllocatorsAfterConfigure();
+
protected:
/// @brief Protected constructor.
#include <dhcpsrv/parsers/dhcp_parsers.h>
#include <dhcpsrv/cfg_shared_networks.h>
#include <dhcpsrv/cfg_subnets4.h>
+#include <dhcpsrv/iterative_allocator.h>
#include <dhcpsrv/shared_network.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_id.h>
namespace {
+/// @brief An allocator recording calls to @c initAfterConfigure.
+class InitRecordingAllocator : public IterativeAllocator {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// @param type specifies the type of allocated leases.
+ /// @param subnet weak pointer to the subnet owning the allocator.
+ InitRecordingAllocator(Lease::Type type, const WeakSubnetPtr& subnet)
+ : IterativeAllocator(type, subnet), callcount_(0) {
+ }
+
+ /// @brief Increases the call count of this function.
+ ///
+ /// The call count can be later examined to check whether or not
+ /// the function was called.
+ virtual void initAfterConfigure() {
+ ++callcount_;
+ };
+
+ /// @brief Call count of the @c initAllocatorsAfterConfigure.
+ int callcount_;
+};
+
/// @brief Verifies that a set of subnets contains a given a subnet
///
/// @param cfg_subnets set of subnets in which to look
EXPECT_EQ(24, link_len);
}
+// This test verifies that for each subnet in the configuration it calls
+// the initAllocatorAfterConfigure function.
+TEST(CfgSubnets4Test, initAllocatorsAfterConfigure) {
+ CfgSubnets4 cfg;
+
+ // Create 4 subnets.
+ Subnet4Ptr subnet0(new Subnet4(IOAddress("0.0.0.0"),
+ 24, 1, 2, 3, SubnetID(111)));
+ Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.1.0"),
+ 26, 1, 2, 3, SubnetID(1)));
+ Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.0"),
+ 26, 1, 2, 3, SubnetID(2)));
+ Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.3.0"),
+ 26, 1, 2, 3, SubnetID(3)));
+
+ auto allocator0 = boost::make_shared<InitRecordingAllocator>(Lease::TYPE_V4, subnet0);
+ subnet0->setAllocator(Lease::TYPE_V4, allocator0);
+
+ auto allocator2 = boost::make_shared<InitRecordingAllocator>(Lease::TYPE_V4, subnet2);
+ subnet2->setAllocator(Lease::TYPE_V4, allocator2);
+
+ cfg.add(subnet0);
+ cfg.add(subnet1);
+ cfg.add(subnet2);
+ cfg.add(subnet3);
+
+ cfg.initAllocatorsAfterConfigure();
+
+ EXPECT_EQ(1, allocator0->callcount_);
+ EXPECT_EQ(1, allocator2->callcount_);
+}
+
/// @brief Test fixture for parsing v4 Subnets that can verify log output.
class Subnet4ParserTest : public LogContentTest {
public:
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/cfg_shared_networks.h>
#include <dhcpsrv/cfg_subnets6.h>
+#include <dhcpsrv/iterative_allocator.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcpsrv/parsers/dhcp_parsers.h>
#include <dhcpsrv/subnet.h>
namespace {
+/// @brief An allocator recording calls to @c initAfterConfigure.
+class InitRecordingAllocator : public IterativeAllocator {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// @param type specifies the type of allocated leases.
+ /// @param subnet weak pointer to the subnet owning the allocator.
+ InitRecordingAllocator(Lease::Type type, const WeakSubnetPtr& subnet)
+ : IterativeAllocator(type, subnet), callcount_(0) {
+ }
+
+ /// @brief Increases the call count of this function.
+ ///
+ /// The call count can be later examined to check whether or not
+ /// the function was called.
+ virtual void initAfterConfigure() {
+ ++callcount_;
+ };
+
+ /// @brief Call count of the @c initAllocatorsAfterConfigure.
+ int callcount_;
+};
+
/// @brief Generates interface id option.
///
/// @param text Interface id in a textual format.
EXPECT_EQ(48, link_len);
}
+// This test verifies that for each subnet in the configuration it calls
+// the registerLeaseMgrCallback function.
+TEST(CfgSubnets6Test, initAllocatorsAfterConfigure) {
+ CfgSubnets6 cfg;
+
+ // Create 4 subnets.
+ Subnet6Ptr subnet0(new Subnet6(IOAddress("2001:db8:1::"),
+ 64, 1, 2, 3, 4, SubnetID(111)));
+ Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:2::"),
+ 64, 1, 2, 3, 4, SubnetID(1)));
+ Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:3::"),
+ 64, 1, 2, 3, 4, SubnetID(2)));
+ Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:4::"),
+ 64, 1, 2, 3, 4, SubnetID(3)));
+
+ auto allocator0 = boost::make_shared<InitRecordingAllocator>(Lease::TYPE_NA, subnet0);
+ subnet0->setAllocator(Lease::TYPE_NA, allocator0);
+
+ auto allocator2 = boost::make_shared<InitRecordingAllocator>(Lease::TYPE_PD, subnet2);
+ subnet2->setAllocator(Lease::TYPE_PD, allocator2);
+
+ cfg.add(subnet0);
+ cfg.add(subnet1);
+ cfg.add(subnet2);
+ cfg.add(subnet3);
+
+ cfg.initAllocatorsAfterConfigure();
+
+ EXPECT_EQ(1, allocator0->callcount_);
+ EXPECT_EQ(1, allocator2->callcount_);
+}
+
+
/// @brief Test fixture for parsing v6 Subnets that can verify log output.
class Subnet6ParserTest : public LogContentTest {
public: