mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[master] Merge branch 'trac3973'
This commit is contained in:
@@ -14,17 +14,24 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <dhcp/option_data_types.h>
|
||||
#include <dhcp_ddns/ncr_msg.h>
|
||||
#include <dhcpsrv/alloc_engine.h>
|
||||
#include <dhcpsrv/alloc_engine_log.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/d2_client_mgr.h>
|
||||
#include <dhcpsrv/dhcpsrv_log.h>
|
||||
#include <dhcpsrv/host_mgr.h>
|
||||
#include <dhcpsrv/host.h>
|
||||
#include <dhcpsrv/lease_mgr_factory.h>
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <stats/stats_mgr.h>
|
||||
#include <util/stopwatch.h>
|
||||
#include <hooks/server_hooks.h>
|
||||
#include <hooks/hooks_manager.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
@@ -34,6 +41,7 @@
|
||||
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::dhcp_ddns;
|
||||
using namespace isc::hooks;
|
||||
using namespace isc::stats;
|
||||
|
||||
@@ -1272,6 +1280,230 @@ AllocEngine::updateLeaseData(ClientContext6& ctx, const Lease6Collection& leases
|
||||
return (updated_leases);
|
||||
}
|
||||
|
||||
void
|
||||
AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeout,
|
||||
const bool remove_lease) {
|
||||
|
||||
LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
|
||||
ALLOC_ENGINE_V6_LEASES_RECLAMATION_START)
|
||||
.arg(max_leases)
|
||||
.arg(timeout);
|
||||
|
||||
// Create stopwatch and automatically start it to measure the time
|
||||
// taken by the routine.
|
||||
/// @todo Monitor time elapsed and return from the lease reclamation routine
|
||||
/// if it hits the timeout value.
|
||||
util::Stopwatch stopwatch;
|
||||
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
|
||||
|
||||
Lease6Collection leases;
|
||||
lease_mgr.getExpiredLeases6(leases, max_leases);
|
||||
|
||||
BOOST_FOREACH(Lease6Ptr lease, leases) {
|
||||
|
||||
try {
|
||||
/// @todo execute a lease6_expire hook here.
|
||||
|
||||
// Generate removal name change request for D2, if required.
|
||||
// This will return immediatelly if the DNS wasn't updated
|
||||
// when the lease was created.
|
||||
if (lease->duid_) {
|
||||
queueRemovalNameChangeRequest(lease, *(lease->duid_));
|
||||
}
|
||||
|
||||
// Reclaim the lease - depending on the configuration, set the
|
||||
// expired-reclaimed state or simply remove it.
|
||||
reclaimLeaseInDatabase<Lease6Ptr>(lease, remove_lease,
|
||||
boost::bind(&LeaseMgr::updateLease6,
|
||||
&lease_mgr, _1));
|
||||
|
||||
// Update statistics.
|
||||
|
||||
// Decrease number of assigned leases.
|
||||
if (lease->type_ == Lease::TYPE_NA) {
|
||||
// IA_NA
|
||||
StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
|
||||
lease->subnet_id_,
|
||||
"assigned-nas"),
|
||||
int64_t(-1));
|
||||
|
||||
} else if (lease->type_ == Lease::TYPE_PD) {
|
||||
// IA_PD
|
||||
StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
|
||||
lease->subnet_id_,
|
||||
"assigned-pds"),
|
||||
int64_t(-1));
|
||||
|
||||
}
|
||||
|
||||
// Increase total number of reclaimed leases.
|
||||
StatsMgr::instance().addValue("reclaimed-leases", int64_t(1));
|
||||
|
||||
// Increase number of reclaimed leases for a subnet.
|
||||
StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
|
||||
lease->subnet_id_,
|
||||
"reclaimed-leases"),
|
||||
int64_t(1));
|
||||
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V6_LEASE_RECLAMATION_FAILED)
|
||||
.arg(lease->addr_.toText())
|
||||
.arg(ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
// Stop measuring the time.
|
||||
stopwatch.stop();
|
||||
|
||||
// Mark completion of the lease reclamation routine and present some stats.
|
||||
LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
|
||||
ALLOC_ENGINE_V6_LEASES_RECLAMATION_COMPLETE)
|
||||
.arg(leases.size())
|
||||
.arg(stopwatch.logFormatTotalDuration());
|
||||
}
|
||||
|
||||
void
|
||||
AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeout,
|
||||
const bool remove_lease) {
|
||||
|
||||
LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
|
||||
ALLOC_ENGINE_V4_LEASES_RECLAMATION_START)
|
||||
.arg(max_leases)
|
||||
.arg(timeout);
|
||||
|
||||
// Create stopwatch and automatically start it to measure the time
|
||||
// taken by the routine.
|
||||
/// @todo Monitor time elapsed and return from the lease reclamation routine
|
||||
/// if it hits the timeout value.
|
||||
util::Stopwatch stopwatch;
|
||||
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
|
||||
|
||||
Lease4Collection leases;
|
||||
lease_mgr.getExpiredLeases4(leases, max_leases);
|
||||
|
||||
BOOST_FOREACH(Lease4Ptr lease, leases) {
|
||||
|
||||
try {
|
||||
/// @todo execute a lease4_expire hook here.
|
||||
|
||||
// Generate removal name change request for D2, if required.
|
||||
// This will return immediatelly if the DNS wasn't updated
|
||||
// when the lease was created.
|
||||
if (lease->client_id_) {
|
||||
// Client id takes precedence over HW address.
|
||||
queueRemovalNameChangeRequest(lease, lease->client_id_->getClientId());
|
||||
|
||||
} else {
|
||||
// Client id is not specified for the lease. Use HW address
|
||||
// instead.
|
||||
queueRemovalNameChangeRequest(lease, lease->hwaddr_);
|
||||
}
|
||||
|
||||
// Reclaim the lease - depending on the configuration, set the
|
||||
// expired-reclaimed state or simply remove it.
|
||||
reclaimLeaseInDatabase<Lease4Ptr>(lease, remove_lease,
|
||||
boost::bind(&LeaseMgr::updateLease4,
|
||||
&lease_mgr, _1));
|
||||
|
||||
// Update statistics.
|
||||
|
||||
// Decrease number of assigned addresses.
|
||||
StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
|
||||
lease->subnet_id_,
|
||||
"assigned-addresses"),
|
||||
int64_t(-1));
|
||||
|
||||
// Increase total number of reclaimed leases.
|
||||
StatsMgr::instance().addValue("reclaimed-leases", int64_t(1));
|
||||
|
||||
// Increase number of reclaimed leases for a subnet.
|
||||
StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
|
||||
lease->subnet_id_,
|
||||
"reclaimed-leases"),
|
||||
int64_t(1));
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V4_LEASE_RECLAMATION_FAILED)
|
||||
.arg(lease->addr_.toText())
|
||||
.arg(ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
// Stop measuring the time.
|
||||
stopwatch.stop();
|
||||
|
||||
// Mark completion of the lease reclamation routine and present some stats.
|
||||
LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
|
||||
ALLOC_ENGINE_V4_LEASES_RECLAMATION_COMPLETE)
|
||||
.arg(leases.size())
|
||||
.arg(stopwatch.logFormatTotalDuration());
|
||||
}
|
||||
|
||||
template<typename LeasePtrType, typename IdentifierType>
|
||||
void
|
||||
AllocEngine::queueRemovalNameChangeRequest(const LeasePtrType& lease,
|
||||
const IdentifierType& identifier) const {
|
||||
|
||||
// Check if there is a need for update.
|
||||
if (!lease || lease->hostname_.empty() || (!lease->fqdn_fwd_ && !lease->fqdn_rev_)
|
||||
|| !CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Create DHCID
|
||||
std::vector<uint8_t> hostname_wire;
|
||||
OptionDataTypeUtil::writeFqdn(lease->hostname_, hostname_wire, true);
|
||||
dhcp_ddns::D2Dhcid dhcid = D2Dhcid(identifier, hostname_wire);
|
||||
|
||||
// Create name change request.
|
||||
NameChangeRequestPtr ncr(new NameChangeRequest(isc::dhcp_ddns::CHG_REMOVE,
|
||||
lease->fqdn_fwd_, lease->fqdn_rev_,
|
||||
lease->hostname_,
|
||||
lease->addr_.toText(),
|
||||
dhcid, 0, lease->valid_lft_));
|
||||
// Send name change request.
|
||||
CfgMgr::instance().getD2ClientMgr().sendRequest(ncr);
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_REMOVAL_NCR_FAILED)
|
||||
.arg(lease->addr_.toText())
|
||||
.arg(ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename LeasePtrType>
|
||||
void AllocEngine::reclaimLeaseInDatabase(const LeasePtrType& lease,
|
||||
const bool remove_lease,
|
||||
const boost::function<void (const LeasePtrType&)>&
|
||||
lease_update_fun) const {
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
|
||||
|
||||
// Reclaim the lease - depending on the configuration, set the
|
||||
// expired-reclaimed state or simply remove it.
|
||||
if (remove_lease) {
|
||||
lease_mgr.deleteLease(lease->addr_);
|
||||
|
||||
} else {
|
||||
// Clear FQDN information as we have already sent the
|
||||
// name change request to remove the DNS record.
|
||||
lease->hostname_.clear();
|
||||
lease->fqdn_fwd_ = false;
|
||||
lease->fqdn_rev_ = false;
|
||||
lease->state_ = Lease::STATE_EXPIRED_RECLAIMED;
|
||||
lease_update_fun(lease);
|
||||
}
|
||||
|
||||
// Lease has been reclaimed.
|
||||
LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
|
||||
ALLOC_ENGINE_LEASE_RECLAIMED)
|
||||
.arg(lease->addr_.toText());
|
||||
}
|
||||
|
||||
|
||||
} // end of isc::dhcp namespace
|
||||
} // end of isc namespace
|
||||
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include <dhcpsrv/lease_mgr.h>
|
||||
#include <hooks/callout_handle.h>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
@@ -490,6 +491,52 @@ public:
|
||||
/// @return Returns renewed lease.
|
||||
Lease6Collection renewLeases6(ClientContext6& ctx);
|
||||
|
||||
/// @brief Reclaims expired IPv6 leases.
|
||||
///
|
||||
/// This method retrieves a collection of expired leases and reclaims them.
|
||||
/// See http://kea.isc.org/wiki/LeaseExpirationDesign#LeasesReclamationRoutine
|
||||
/// for the details.
|
||||
///
|
||||
/// This method is executed periodically to act upon expired leases. This
|
||||
/// includes for each lease:
|
||||
/// - executing "lease_expire6" hook,
|
||||
/// - removing DNS record for a lease,
|
||||
/// - reclaiming a lease in the database, i.e. setting its state to
|
||||
/// "expired-reclaimed" or removing it from the lease databse,
|
||||
/// - updating statistics of assigned and reclaimed leases
|
||||
///
|
||||
/// @param max_leases Maximum number of leases to be reclaimed.
|
||||
/// @param timeout Maximum amount of time that the reclaimation routine
|
||||
/// may be processing expired leases, expressed in seconds.
|
||||
/// @param remove_lease A boolean value indicating if the lease should
|
||||
/// be removed when it is reclaimed (if true) or it should be left in the
|
||||
/// database in the "expired-reclaimed" state (if false).
|
||||
void reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeout,
|
||||
const bool remove_lease);
|
||||
|
||||
/// @brief Reclaims expired IPv4 leases.
|
||||
///
|
||||
/// This method retrieves a collection of expired leases and reclaims them.
|
||||
/// See http://kea.isc.org/wiki/LeaseExpirationDesign#LeasesReclamationRoutine
|
||||
/// for the details.
|
||||
///
|
||||
/// This method is executed periodically to act upon expired leases. This
|
||||
/// includes for each lease:
|
||||
/// - executing "lease_expire6" hook,
|
||||
/// - removing DNS record for a lease,
|
||||
/// - reclaiming a lease in the database, i.e. setting its state to
|
||||
/// "expired-reclaimed" or removing it from the lease databse,
|
||||
/// - updating statistics of assigned and reclaimed leases
|
||||
///
|
||||
/// @param max_leases Maximum number of leases to be reclaimed.
|
||||
/// @param timeout Maximum amount of time that the reclaimation routine
|
||||
/// may be processing expired leases, expressed in seconds.
|
||||
/// @param remove_lease A boolean value indicating if the lease should
|
||||
/// be removed when it is reclaimed (if true) or it should be left in the
|
||||
/// database in the "expired-reclaimed" state (if false).
|
||||
void reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeout,
|
||||
const bool remove_lease);
|
||||
|
||||
/// @brief Attempts to find appropriate host reservation.
|
||||
///
|
||||
/// Attempts to find appropriate host reservation in HostMgr. If found, it
|
||||
@@ -663,6 +710,45 @@ private:
|
||||
/// @param lease IPv6 lease to be extended.
|
||||
void extendLease6(ClientContext6& ctx, Lease6Ptr lease);
|
||||
|
||||
/// @brief Sends removal name change reuqest to D2.
|
||||
///
|
||||
/// This method is exception safe.
|
||||
///
|
||||
/// @param lease Pointer to a lease for which NCR should be sent.
|
||||
/// @param identifier Identifier to be used to generate DHCID for
|
||||
/// the DNS update. For DHCPv4 it will be hardware address or client
|
||||
/// identifier. For DHCPv6 it will be a DUID.
|
||||
///
|
||||
/// @tparam LeasePtrType Pointer to a lease.
|
||||
/// @tparam IdentifierType HW Address, Client Identifier or DUID.
|
||||
template<typename LeasePtrType, typename IdentifierType>
|
||||
void queueRemovalNameChangeRequest(const LeasePtrType& lease,
|
||||
const IdentifierType& identifier) const;
|
||||
|
||||
/// @brief Marks lease as reclaimed in the database.
|
||||
///
|
||||
/// This method is called internally by the leases reclaimation routines.
|
||||
/// Depending on the value of the @c remove_lease parameter this method
|
||||
/// will delete the reclaimed lease from the database or set its sate
|
||||
/// to "expired-reclaimed". In the latter case it will also clear the
|
||||
/// FQDN information.
|
||||
///
|
||||
/// This method may throw exceptions if the operation on the lease database
|
||||
/// fails for any reason.
|
||||
///
|
||||
/// @param lease Pointer to the lease.
|
||||
/// @param remove_lease Boolean flag indicating if the lease should be
|
||||
/// removed from the database (if true).
|
||||
/// @param lease_update_fun Pointer to the function in the @c LeaseMgr to
|
||||
/// be used to update the lease if the @c remove_lease is set to false.
|
||||
///
|
||||
/// @tparam LeasePtrType One of the @c Lease6Ptr or @c Lease4Ptr.
|
||||
template<typename LeasePtrType>
|
||||
void reclaimLeaseInDatabase(const LeasePtrType& lease,
|
||||
const bool remove_lease,
|
||||
const boost::function<void (const LeasePtrType&)>&
|
||||
lease_update_fun) const;
|
||||
|
||||
public:
|
||||
|
||||
/// @brief Context information for the DHCPv4 lease allocation.
|
||||
|
@@ -14,6 +14,18 @@
|
||||
|
||||
$NAMESPACE isc::dhcp
|
||||
|
||||
% ALLOC_ENGINE_LEASE_RECLAIMED successfully reclaimed lease %1
|
||||
This debug message is logged when the allocation engine successfully
|
||||
reclaims a lease. The lease is now available for assignment.
|
||||
|
||||
% ALLOC_ENGINE_REMOVAL_NCR_FAILED sending removal name change request failed for lease %1: %2
|
||||
This error message is logged when sending a removal name change request
|
||||
to DHCP DDNS failed. This name change request is usually generated when
|
||||
the lease reclamation routine acts upon expired leases. If a lease being
|
||||
reclaimed has a corresponding DNS entry it needs to be removed.
|
||||
This message indicates that removal of the DNS entry has failed.
|
||||
Nevertheless the lease will be reclaimed.
|
||||
|
||||
% ALLOC_ENGINE_V4_ALLOC_ERROR %1: error during attempt to allocate an IPv4 address: %2
|
||||
An error occurred during an attempt to allocate an IPv4 address, the
|
||||
reason for the failure being contained in the message. The server will
|
||||
@@ -49,6 +61,27 @@ client sending the DHCPDISCOVER has a reservation for the specified
|
||||
address. The allocation engine will try to offer this address to
|
||||
the client.
|
||||
|
||||
% ALLOC_ENGINE_V4_LEASE_RECLAMATION_FAILED failed to reclaim the lease %1: %2
|
||||
This error message is logged when the allocation engine fails to
|
||||
reclaim an expired lease. The reason for the failure is included in the
|
||||
message. The error may be triggered in the lease expiration hook or
|
||||
while performing the operation on the lease database.
|
||||
|
||||
% ALLOC_ENGINE_V4_LEASES_RECLAMATION_COMPLETE reclaimed %1 leases in %2
|
||||
This debug message is logged when the allocation engine completes
|
||||
reclamation of a set of expired leases. The maximum number of leases
|
||||
to be reclaimed in a single pass of the lease reclamation routine
|
||||
is configurable using 'max-reclaim-leases' parameter. However,
|
||||
the number of reclaimed leases may also be limited by the timeout
|
||||
value, configured with 'max-reclaim-time'. The message includes the
|
||||
number of reclaimed leases and the total time.
|
||||
|
||||
% ALLOC_ENGINE_V4_LEASES_RECLAMATION_START starting reclamation of expired leases (limit = %1 leases or %2 seconds)
|
||||
This debug message is issued when the allocation engine starts the
|
||||
reclamation of the expired leases. The maximum number of leases to
|
||||
be reclaimed and the timeout is included in the message. If any of
|
||||
these values is 0, it means "unlimited".
|
||||
|
||||
% ALLOC_ENGINE_V4_OFFER_EXISTING_LEASE allocation engine will try to offer existing lease to the client %1
|
||||
This message is issued when the allocation engine determines that
|
||||
the client has a lease in the lease database, it doesn't have
|
||||
@@ -246,6 +279,27 @@ reserved for it.
|
||||
This informational message signals that the specified client was assigned the prefix
|
||||
reserved for it.
|
||||
|
||||
% ALLOC_ENGINE_V6_LEASE_RECLAMATION_FAILED failed to reclaim the lease %1: %2
|
||||
This error message is logged when the allocation engine fails to
|
||||
reclaim an expired lease. The reason for the failure is included in the
|
||||
message. The error may be triggered in the lease expiration hook or
|
||||
while performing the operation on the lease database.
|
||||
|
||||
% ALLOC_ENGINE_V6_LEASES_RECLAMATION_COMPLETE reclaimed %1 leases in %2
|
||||
This debug message is logged when the allocation engine completes
|
||||
reclamation of a set of expired leases. The maximum number of leases
|
||||
to be reclaimed in a single pass of the lease reclamation routine
|
||||
is configurable using 'max-reclaim-leases' parameter. However,
|
||||
the number of reclaimed leases may also be limited by the timeout
|
||||
value, configured with 'max-reclaim-time'. The message includes the
|
||||
number of reclaimed leases and the total time.
|
||||
|
||||
% ALLOC_ENGINE_V6_LEASES_RECLAMATION_START starting reclamation of expired leases (limit = %1 leases or %2 seconds)
|
||||
This debug message is issued when the allocation engine starts the
|
||||
reclamation of the expired leases. The maximum number of leases to
|
||||
be reclaimed and the timeout is included in the message. If any of
|
||||
these values is 0, it means "unlimited".
|
||||
|
||||
% ALLOC_ENGINE_V6_RENEW_HR allocating leases reserved for the client %1 as a result of Renew
|
||||
This debug message is issued when the allocation engine tries to
|
||||
allocate reserved leases for the client sending a Renew message.
|
||||
|
@@ -60,6 +60,7 @@ TESTS += libdhcpsrv_unittests
|
||||
libdhcpsrv_unittests_SOURCES = run_unittests.cc
|
||||
libdhcpsrv_unittests_SOURCES += addr_utilities_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += alloc_engine_utils.cc alloc_engine_utils.h
|
||||
libdhcpsrv_unittests_SOURCES += alloc_engine_expiration_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += alloc_engine_hooks_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += alloc_engine4_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += alloc_engine6_unittest.cc
|
||||
|
1301
src/lib/dhcpsrv/tests/alloc_engine_expiration_unittest.cc
Normal file
1301
src/lib/dhcpsrv/tests/alloc_engine_expiration_unittest.cc
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user