]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#2764] Added registering callbacks in allocators
authorMarcin Siodelski <marcin@isc.org>
Wed, 22 Feb 2023 20:35:49 +0000 (21:35 +0100)
committerMarcin Siodelski <msiodelski@gmail.com>
Tue, 14 Mar 2023 18:23:31 +0000 (19:23 +0100)
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.

src/lib/dhcpsrv/allocator.cc
src/lib/dhcpsrv/allocator.h
src/lib/dhcpsrv/cfg_subnets4.cc
src/lib/dhcpsrv/cfg_subnets4.h
src/lib/dhcpsrv/cfg_subnets6.cc
src/lib/dhcpsrv/cfg_subnets6.h
src/lib/dhcpsrv/dhcpsrv_messages.cc
src/lib/dhcpsrv/subnet.cc
src/lib/dhcpsrv/subnet.h
src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc
src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc

index 279abc9ce9b38feabf5d37ff971fbb3b654bb537..392c12c65daa0e2475b7458e1c6b0aa52119fbf2 100644 (file)
@@ -6,13 +6,35 @@
 
 #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) {
index 7967832e5d92b81edf5ef0427f5080798eb8ed5e..dd82ea8a43ed9e043c68a2114888a09b64f71f5a 100644 (file)
@@ -12,6 +12,7 @@
 #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>
@@ -70,13 +71,12 @@ public:
     /// @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.
     ///
@@ -148,6 +148,16 @@ public:
     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.
@@ -196,6 +206,9 @@ protected:
     /// @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_;
 
index 9e5c7a33ccbad6f4f69c39ca5bc4630a9625b504..846fbac50f841d780e6654f5c9b7abe77f1e973e 100644 (file)
@@ -571,6 +571,13 @@ CfgSubnets4::updateStatistics() {
     }
 }
 
+void
+CfgSubnets4::initAllocatorsAfterConfigure() {
+    for (auto subnet : subnets_) {
+        subnet->initAllocatorsAfterConfigure();
+    }
+}
+
 ElementPtr
 CfgSubnets4::toElement() const {
     ElementPtr result = Element::createList();
index d1d3c32184788b9335c06f24024de19c369c7789..dbacf943375bdaac185fd07ecb03ca2580a6bda2 100644 (file)
@@ -327,6 +327,9 @@ public:
     /// 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
index dcd4db83132bd1aa95d178be814fbc64d437c9a6..67252008071467435a31a0603b7305b9061d8b9d 100644 (file)
@@ -473,6 +473,13 @@ CfgSubnets6::updateStatistics() {
     }
 }
 
+void
+CfgSubnets6::initAllocatorsAfterConfigure() {
+    for (auto subnet : subnets_) {
+        subnet->initAllocatorsAfterConfigure();
+    }
+}
+
 ElementPtr
 CfgSubnets6::toElement() const {
     ElementPtr result = Element::createList();
index 54f377446004143770fd86b8c8dbf9bb29eafb08..72c023df443664675ea0662ea601240763a4381a 100644 (file)
@@ -277,6 +277,9 @@ public:
     /// 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
index 0f4475206d851b9929270760bd10143ce4c9786d..d8b0ab3de044ecaa431bc9972dfbf0dfef0ed783 100644 (file)
@@ -69,6 +69,8 @@ extern const isc::log::MessageID DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL = "DHC
 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";
@@ -321,6 +323,8 @@ const char* values[] = {
     "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.",
index 67f223c5cd106b23ef8d9c3691f9fc2e9dc17025..762589c0d80ccaef176164d5eb2185cba258604f 100644 (file)
@@ -423,6 +423,13 @@ const PoolPtr Subnet::getPool(Lease::Type type, const isc::asiolink::IOAddress&
     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 {
index 3e0291a4d557f84c02710a633dbf55a3dde396be..a388d5f18a69f35a05c27d57d308308cffc9d0fb 100644 (file)
@@ -316,6 +316,9 @@ public:
     /// @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.
index 2c484f46de6caa660e42c19f952d57904b7d753e..244fe355e2f25c1355fb35e96492873a5e0497a2 100644 (file)
@@ -19,6 +19,7 @@
 #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>
@@ -44,6 +45,30 @@ using namespace isc::util;
 
 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
@@ -2179,6 +2204,38 @@ TEST(CfgSubnets4Test, getLinks) {
     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:
index ddd1e417429158863c60566241033003e05d764d..c6c821af60d540060d10d5420dceb2c9748a980d 100644 (file)
@@ -15,6 +15,7 @@
 #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>
@@ -41,6 +42,30 @@ using namespace isc::util;
 
 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.
@@ -2101,6 +2126,39 @@ TEST(CfgSubnets6Test, getLinks) {
     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: