/// @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.)
#include <cstring>
#include <errno.h>
#include <iostream>
+#include <limits>
#include <sstream>
namespace {
// 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();
// 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();
}
}
+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"
/// @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.
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) {
}
// 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();
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) {
}
// 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();
}
}
+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
-// 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
/// - 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_;
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.)
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