]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[3965] Added capability to remove expired-reclaimed leases.
authorMarcin Siodelski <marcin@isc.org>
Thu, 20 Aug 2015 10:21:26 +0000 (12:21 +0200)
committerMarcin Siodelski <marcin@isc.org>
Thu, 20 Aug 2015 10:21:26 +0000 (12:21 +0200)
src/lib/dhcpsrv/lease_mgr.h
src/lib/dhcpsrv/memfile_lease_mgr.cc
src/lib/dhcpsrv/memfile_lease_mgr.h
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h
src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

index ad277909b2bec74af6ba30ba725a905f923e7dd0..8166c52c2f020013329f83781c4242d65cbd5ace 100644 (file)
@@ -364,6 +364,20 @@ public:
     /// @return true if deletion was successful, false if no such lease exists
     virtual bool deleteLease(const isc::asiolink::IOAddress& addr) = 0;
 
+    /// @brief Deletes all expired and reclaimed DHCPv4 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases4(const uint32_t secs) = 0;
+
+    /// @brief Deletes all expired and reclaimed DHCPv6 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases6(const uint32_t secs) = 0;
+
     /// @brief Return backend type
     ///
     /// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
index 23c22b85bab8f54eb629fc90fe483b48d3e4a9f5..2aa71164366ddffb98664469c343e942bd8c3fed 100644 (file)
@@ -25,6 +25,7 @@
 #include <cstring>
 #include <errno.h>
 #include <iostream>
+#include <limits>
 #include <sstream>
 
 namespace {
@@ -513,7 +514,7 @@ Memfile_LeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases,
     // for the 'state' 'false' is less than 'true'. Also the leases with
     // expiration time lower than current time will be returned.
     Lease6StorageExpirationIndex::const_iterator ub =
-        index.upper_bound(boost::make_tuple(false, time_t(NULL)));
+        index.upper_bound(boost::make_tuple(false, time(NULL)));
 
     // Copy only the number of leases indicated by the max_leases parameter.
     for (Lease6StorageExpirationIndex::const_iterator lease = index.begin();
@@ -535,7 +536,7 @@ Memfile_LeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
     // for the 'state' 'false' is less than 'true'. Also the leases with
     // expiration time lower than current time will be returned.
     Lease4StorageExpirationIndex::const_iterator ub =
-        index.upper_bound(boost::make_tuple(false, time_t(NULL)));
+        index.upper_bound(boost::make_tuple(false, time(NULL)));
 
     // Copy only the number of leases indicated by the max_leases parameter.
     for (Lease4StorageExpirationIndex::const_iterator lease = index.begin();
@@ -645,6 +646,52 @@ Memfile_LeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
     }
 }
 
+void
+Memfile_LeaseMgr::deleteExpiredReclaimedLeases4(const uint32_t secs) {
+    deleteExpiredReclaimedLeases<Lease4StorageExpirationIndex>(secs, storage4_);
+}
+
+void
+Memfile_LeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) {
+    deleteExpiredReclaimedLeases<Lease6StorageExpirationIndex>(secs, storage6_);
+}
+
+template<typename IndexType, typename StorageType>
+void
+Memfile_LeaseMgr::deleteExpiredReclaimedLeases(const uint32_t secs,
+                                               StorageType& storage) const {
+    // Obtain the index which segragates leases by state and time.
+    IndexType& index = storage.template get<ExpirationIndexTag>();
+
+    // This returns the first element which is greater than the specified
+    // tuple (true, time(NULL) - secs). However, the range between the
+    // beginnng of the index and returned element also includes all the
+    // elements for which the first value is false (lease state is NOT
+    // reclaimed), because false < true. All elements between the
+    // beginning of the index and the element returned, for which the
+    // first value is true, represent the reclaimed leases which should
+    // be deleted, because their expiration time + secs has occured earlier
+    // than current time.
+    typename IndexType::const_iterator upper_limit =
+        index.upper_bound(boost::make_tuple(true, time(NULL) - secs));
+
+    // Now, we have to exclude all elements of the index which represent
+    // leases in the state other than reclaimed - with the first value
+    // in the index equal to false. Note that elements in the index are
+    // ordered from the lower to the higher ones. So, all elements with
+    // the first value of false are placed before the elements with the
+    // value of true. Hence, we have to find the first element which
+    // contains value of true. The time value is the lowest possible.
+    typename IndexType::const_iterator lower_limit =
+        index.upper_bound(boost::make_tuple(true, std::numeric_limits<int64_t>::min()));
+
+    // If there are some elements in this range, delete them.
+    if (std::distance(lower_limit, upper_limit) > 0) {
+        index.erase(lower_limit, upper_limit);
+    }
+}
+
+
 std::string
 Memfile_LeaseMgr::getDescription() const {
     return (std::string("This is a dummy memfile backend implementation.\n"
index 6be41bd93d3577f60d4848831df819ce1609d14c..6717862dbc370a58f56b66f9b4d3b9d56b06ee9e 100644 (file)
@@ -314,6 +314,46 @@ public:
     /// @return true if deletion was successful, false if no such lease exists
     virtual bool deleteLease(const isc::asiolink::IOAddress& addr);
 
+    /// @brief Deletes all expired-reclaimed DHCPv4 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases4(const uint32_t secs);
+
+    /// @brief Deletes all expired-reclaimed DHCPv6 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases6(const uint32_t secs);
+
+private:
+
+    /// @brief Deletes all expired-reclaimed leases.
+    ///
+    /// This private method is called by both of the public methods:
+    /// @c deleteExpiredReclaimedLeases4 and
+    /// @c deleteExpiredReclaimedLeases6 to remove all expired
+    /// reclaimed DHCPv4 or DHCPv6 leases respectively.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    /// @param storage Reference to the container where leases are held.
+    /// Some expired-reclaimed leases will be removed from this container.
+    ///
+    /// @tparam IndexType Index type to be used to search for the
+    /// expired-reclaimed leases, i.e.
+    /// @c Lease4StorageExpirationIndex or @c Lease6StorageExpirationIndex.
+    /// @tparam StorageType Type of storage where leases are held, i.e.
+    /// @c Lease4Storage or @c Lease6Storage.
+    template<typename IndexType, typename StorageType>
+    void deleteExpiredReclaimedLeases(const uint32_t secs,
+                                      StorageType& storage) const;
+
+public:
+
     /// @brief Return backend type
     ///
     /// Returns the type of the backend.
index de41f6ed25c3087bed80269d8281e9e2b561fe93..f8ef01fed05f6fdaa212107ee10f057f6c9123a6 100644 (file)
@@ -1665,7 +1665,7 @@ GenericLeaseMgrTest::testGetExpiredLeases4() {
     ASSERT_GE(leases.size(), 6);
 
     // Use the same current time for all leases.
-    time_t current_time = time_t(NULL);
+    time_t current_time = time(NULL);
 
     // Add them to the database
     for (size_t i = 0; i < leases.size(); ++i) {
@@ -1702,7 +1702,7 @@ GenericLeaseMgrTest::testGetExpiredLeases4() {
     }
 
     // Update current time for the next test.
-    current_time = time_t(NULL);
+    current_time = time(NULL);
     // Also, remove expired leases collected during the previous test.
     expired_leases.clear();
 
@@ -1785,7 +1785,7 @@ GenericLeaseMgrTest::testGetExpiredLeases6() {
     ASSERT_GE(leases.size(), 6);
 
     // Use the same current time for all leases.
-    time_t current_time = time_t(NULL);
+    time_t current_time = time(NULL);
 
     // Add them to the database
     for (size_t i = 0; i < leases.size(); ++i) {
@@ -1822,7 +1822,7 @@ GenericLeaseMgrTest::testGetExpiredLeases6() {
     }
 
     // Update current time for the next test.
-    current_time = time_t(NULL);
+    current_time = time(NULL);
     // Also, remove expired leases collected during the previous test.
     expired_leases.clear();
 
@@ -1897,6 +1897,163 @@ GenericLeaseMgrTest::testGetExpiredLeases6() {
     }
 }
 
+void
+GenericLeaseMgrTest::testDeleteExpiredReclaimedLeases4() {
+    // Get the leases to be used for the test.
+    vector<Lease4Ptr> leases = createLeases4();
+    // Make sure we have at least 6 leases there.
+    ASSERT_GE(leases.size(), 6);
+
+    time_t current_time = time(NULL);
+
+    // Add them to the database
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Mark every other lease as expired.
+        if (i % 2 == 0) {
+            // Set client last transmission time to the value older than the
+            // valid lifetime to make it expired. We also substract the value
+            // of 10, 20, 30, 40 etc, depending on the lease index. This
+            // simulates different expiration times for various leases.
+            leases[i]->cltt_ = current_time - leases[i]->valid_lft_ - i * 10;
+            // Set reclaimed state.
+            leases[i]->state_ = Lease::STATE_EXPIRED_RECLAIMED;
+
+        } else {
+            // Other leases are left as not expired - client last transmission
+            // time set to current time.
+            leases[i]->cltt_ = current_time;
+        }
+        ASSERT_TRUE(lmptr_->addLease(leases[i]));
+    }
+
+    // Keep reclaimed lease for 15 seconds after expiration.
+    const uint32_t lease_affinity_time = 15;
+
+    // Delete expired and reclaimed leases which have expired earlier than
+    // 15 seconds ago. This should affect leases with index 2, 3, 4 etc.
+    ASSERT_NO_THROW(lmptr_->deleteExpiredReclaimedLeases4(lease_affinity_time));
+
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Obtain lease from the server.
+        Lease4Ptr lease = lmptr_->getLease4(leases[i]->addr_);
+
+        // If the lease is reclaimed and the expiration time passed more than
+        // 15 seconds ago, the lease should have been deleted.
+        if (leases[i]->stateExpiredReclaimed() &&
+            ((leases[i]->getExpirationTime() + lease_affinity_time) < current_time)) {
+            EXPECT_FALSE(lease) << "Lease with index " << i
+                << " should have been deleted, but it was not";
+
+        } else {
+            // If the lease is not reclaimed or it has expired less than
+            // 15 seconds ago, the lease should still be there.
+            EXPECT_TRUE(lease) << "Lease with index " << i
+                << " shouldn't have been deleted, but it was";
+        }
+    }
+
+    // Make sure we can make another attempt, when there are no more leases
+    // to be deleted.
+    ASSERT_NO_THROW(lmptr_->deleteExpiredReclaimedLeases4(lease_affinity_time));
+
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Obtain lease from the server.
+        Lease4Ptr lease = lmptr_->getLease4(leases[i]->addr_);
+
+        // If the lease is reclaimed and the expiration time passed more than
+        // 15 seconds ago, the lease should have been deleted.
+        if (leases[i]->stateExpiredReclaimed() &&
+            ((leases[i]->getExpirationTime() + lease_affinity_time) < current_time)) {
+            EXPECT_FALSE(lease) << "Lease with index " << i
+                << " should have been deleted, but it was not";
+
+        } else {
+            // If the lease is not reclaimed or it has expired less than
+            // 15 seconds ago, the lease should still be there.
+            EXPECT_TRUE(lease) << "Lease with index " << i
+                << " shouldn't have been deleted, but it was";
+        }
+    }
+}
+
+void
+GenericLeaseMgrTest::testDeleteExpiredReclaimedLeases6() {
+    // Get the leases to be used for the test.
+    vector<Lease6Ptr> leases = createLeases6();
+    // Make sure we have at least 6 leases there.
+    ASSERT_GE(leases.size(), 6);
+
+    time_t current_time = time(NULL);
+
+    // Add them to the database
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Mark every other lease as expired.
+        if (i % 2 == 0) {
+            // Set client last transmission time to the value older than the
+            // valid lifetime to make it expired. We also substract the value
+            // of 10, 20, 30, 40 etc, depending on the lease index. This
+            // simulates different expiration times for various leases.
+            leases[i]->cltt_ = current_time - leases[i]->valid_lft_ - i * 10;
+            // Set reclaimed state.
+            leases[i]->state_ = Lease::STATE_EXPIRED_RECLAIMED;
+
+        } else {
+            // Other leases are left as not expired - client last transmission
+            // time set to current time.
+            leases[i]->cltt_ = current_time;
+        }
+        ASSERT_TRUE(lmptr_->addLease(leases[i]));
+    }
+
+    // Keep reclaimed lease for 15 seconds after expiration.
+    const uint32_t lease_affinity_time = 15;
+
+    // Delete expired and reclaimed leases which have expired earlier than
+    // 15 seconds ago. This should affect leases with index 2, 3, 4 etc.
+    ASSERT_NO_THROW(lmptr_->deleteExpiredReclaimedLeases6(lease_affinity_time));
+
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Obtain lease from the server.
+        Lease6Ptr lease = lmptr_->getLease6(leases[i]->type_, leases[i]->addr_);
+
+        // If the lease is reclaimed and the expiration time passed more than
+        // 15 seconds ago, the lease should have been deleted.
+        if (leases[i]->stateExpiredReclaimed() &&
+            ((leases[i]->getExpirationTime() + lease_affinity_time) < current_time)) {
+            EXPECT_FALSE(lease) << "Lease with index " << i
+                << " should have been deleted, but it was not";
+
+        } else {
+            // If the lease is not reclaimed or it has expired less than
+            // 15 seconds ago, the lease should still be there.
+            EXPECT_TRUE(lease) << "Lease with index " << i
+                << " shouldn't have been deleted, but it was";
+        }
+    }
+
+    // Make sure we can make another attempt, when there are no more leases
+    // to be deleted.
+    ASSERT_NO_THROW(lmptr_->deleteExpiredReclaimedLeases6(lease_affinity_time));
+
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Obtain lease from the server.
+        Lease6Ptr lease = lmptr_->getLease6(leases[i]->type_, leases[i]->addr_);
+
+        // If the lease is reclaimed and the expiration time passed more than
+        // 15 seconds ago, the lease should have been deleted.
+        if (leases[i]->stateExpiredReclaimed() &&
+            ((leases[i]->getExpirationTime() + lease_affinity_time) < current_time)) {
+            EXPECT_FALSE(lease) << "Lease with index " << i
+                << " should have been deleted, but it was not";
+
+        } else {
+            // If the lease is not reclaimed or it has expired less than
+            // 15 seconds ago, the lease should still be there.
+            EXPECT_TRUE(lease) << "Lease with index " << i
+                << " shouldn't have been deleted, but it was";
+        }
+    }
+}
 
 }; // namespace test
 }; // namespace dhcp
index 694ecf5c1d6a3cb49bb5376139ae0621cf89b8b3..933e59100219c852e35ed72c463ca916bf820304 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-215 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
@@ -285,6 +285,22 @@ public:
     /// - reclaimed leases are not returned.
     void testGetExpiredLeases6();
 
+    /// @brief Checks that selected expired-reclaimed DHCPv6 leases
+    /// are removed.
+    ///
+    /// This creates a number of DHCPv6 leases and marks some of them
+    /// as expired-reclaimed. It later verifies that the expired-reclaimed
+    /// leases can be removed.
+    void testDeleteExpiredReclaimedLeases6();
+
+    /// @brief Checks that selected expired-reclaimed DHCPv4 leases
+    /// are removed.
+    ///
+    /// This creates a number of DHCPv4 leases and marks some of them
+    /// as expired-reclaimed. It later verifies that the expired-reclaimed
+    /// leases can be removed.
+    void testDeleteExpiredReclaimedLeases4();
+
     /// @brief String forms of IPv4 addresses
     std::vector<std::string>  straddress4_;
 
index 84236b58d45bdceb821b432875bb8a2f048ff5d2..01ff896c2d7c28e3404d1037852884b4a7147541 100644 (file)
@@ -214,6 +214,26 @@ public:
         return (false);
     }
 
+    /// @brief Deletes all expired and reclaimed DHCPv4 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases4(const uint32_t) {
+        isc_throw(NotImplemented, "ConcreteLeaseMgr::deleteExpiredReclaimedLeases4"
+                  " is not implemented");
+    }
+
+    /// @brief Deletes all expired and reclaimed DHCPv6 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases6(const uint32_t) {
+        isc_throw(NotImplemented, "ConcreteLeaseMgr::deleteExpiredReclaimedLeases6"
+                  " is not implemented");
+    }
+
     /// @brief Returns backend type.
     ///
     /// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
index 9ae806c78c9d64ea8322b0ca415ba6c304174111..1467e353db9c8784dfef3e1cb631690ae435e888 100644 (file)
@@ -905,6 +905,18 @@ TEST_F(MemfileLeaseMgrTest, getExpiredLeases6) {
     testGetExpiredLeases6();
 }
 
+/// @brief Check that expired reclaimed DHCPv6 leases are removed.
+TEST_F(MemfileLeaseMgrTest, deleteExpiredReclaimedLeases6) {
+    startBackend(V6);
+    testDeleteExpiredReclaimedLeases6();
+}
+
+/// @brief Check that expired reclaimed DHCPv4 leases are removed.
+TEST_F(MemfileLeaseMgrTest, deleteExpiredReclaimedLeases4) {
+    startBackend(V4);
+    testDeleteExpiredReclaimedLeases4();
+}
+
 /// @brief Check that getLease6 methods discriminate by lease type.
 ///
 /// Adds six leases, two per lease type all with the same duid and iad but