extern const isc::log::MessageID DHCP4_INIT_REBOOT = "DHCP4_INIT_REBOOT";
extern const isc::log::MessageID DHCP4_LEASE_ADVERT = "DHCP4_LEASE_ADVERT";
extern const isc::log::MessageID DHCP4_LEASE_ALLOC = "DHCP4_LEASE_ALLOC";
+extern const isc::log::MessageID DHCP4_LEASE_REUSE = "DHCP4_LEASE_REUSE";
extern const isc::log::MessageID DHCP4_MULTI_THREADING_INFO = "DHCP4_MULTI_THREADING_INFO";
extern const isc::log::MessageID DHCP4_NCR_CREATE = "DHCP4_NCR_CREATE";
extern const isc::log::MessageID DHCP4_NCR_CREATION_FAILED = "DHCP4_NCR_CREATION_FAILED";
"DHCP4_INIT_REBOOT", "%1: client is in INIT-REBOOT state and requests address %2",
"DHCP4_LEASE_ADVERT", "%1: lease %2 will be advertised",
"DHCP4_LEASE_ALLOC", "%1: lease %2 has been allocated for %3 seconds",
+ "DHCP4_LEASE_REUSE", "%1: lease %2 has been reused for %3 seconds",
"DHCP4_MULTI_THREADING_INFO", "enabled: %1, number of threads: %2, queue size: %3",
"DHCP4_NCR_CREATE", "%1: DDNS updates enabled, therefore sending name change requests",
"DHCP4_NCR_CREATION_FAILED", "%1: failed to generate name change requests for DNS: %2",
extern const isc::log::MessageID DHCP4_INIT_REBOOT;
extern const isc::log::MessageID DHCP4_LEASE_ADVERT;
extern const isc::log::MessageID DHCP4_LEASE_ALLOC;
+extern const isc::log::MessageID DHCP4_LEASE_REUSE;
extern const isc::log::MessageID DHCP4_MULTI_THREADING_INFO;
extern const isc::log::MessageID DHCP4_NCR_CREATE;
extern const isc::log::MessageID DHCP4_NCR_CREATION_FAILED;
contains the allocated IPv4 address. The third argument is the validity
lifetime.
+% DHCP4_LEASE_REUSE %1: lease %2 has been reused for %3 seconds
+This informational message indicates that the server successfully reused a
+lease in response to client's message. The lease information will
+be sent to the client in the DHCPACK message. The first argument contains the
+client and the transaction identification information. The second argument
+contains the allocated IPv4 address. The third argument is the validity
+lifetime.
+
% DHCP4_MULTI_THREADING_INFO enabled: %1, number of threads: %2, queue size: %3
This is a message listing some information about the multi-threading parameters
with which the server is running.
callout_handle->setArgument("query4", query);
Lease4CollectionPtr new_leases(new Lease4Collection());
- if (ctx->new_lease_) {
+ if (ctx->new_lease_ && (ctx->new_lease_->remaining_valid_lft_ == 0)) {
new_leases->push_back(ctx->new_lease_);
}
callout_handle->setArgument("leases4", new_leases);
// switched to a different subnet within a shared network.
postAllocateNameUpdate(ctx, lease, query, resp, client_name_changed);
+ // Reuse the lease if possible.
+ if (lease->remaining_valid_lft_ > 0) {
+ lease->valid_lft_ = lease->remaining_valid_lft_;
+ LOG_INFO(lease4_logger, DHCP4_LEASE_REUSE)
+ .arg(query->getLabel())
+ .arg(lease->addr_.toText())
+ .arg(Lease::lifetimeToText(lease->valid_lft_));
+ }
+
// IP Address Lease time (type 51)
OptionPtr opt(new OptionUint32(Option::V4, DHO_DHCP_LEASE_TIME,
lease->valid_lft_));
// implementation) and log an error.
try {
if (!ctx->fake_allocation_) {
+ // The lease can't be reused.
+ lease->remaining_valid_lft_ = 0;
+
// The lease update should be safe, because the lease should
// be already in the database. In most cases the exception
// would be thrown if the lease was missing.
extern const isc::log::MessageID DHCP6_LEASE_NA_WITHOUT_DUID = "DHCP6_LEASE_NA_WITHOUT_DUID";
extern const isc::log::MessageID DHCP6_LEASE_PD_WITHOUT_DUID = "DHCP6_LEASE_PD_WITHOUT_DUID";
extern const isc::log::MessageID DHCP6_LEASE_RENEW = "DHCP6_LEASE_RENEW";
+extern const isc::log::MessageID DHCP6_LEASE_REUSE = "DHCP6_LEASE_REUSE";
extern const isc::log::MessageID DHCP6_MULTI_THREADING_INFO = "DHCP6_MULTI_THREADING_INFO";
extern const isc::log::MessageID DHCP6_NOT_RUNNING = "DHCP6_NOT_RUNNING";
extern const isc::log::MessageID DHCP6_NO_INTERFACES = "DHCP6_NO_INTERFACES";
extern const isc::log::MessageID DHCP6_PD_LEASE_ALLOC = "DHCP6_PD_LEASE_ALLOC";
extern const isc::log::MessageID DHCP6_PD_LEASE_ALLOC_FAIL = "DHCP6_PD_LEASE_ALLOC_FAIL";
extern const isc::log::MessageID DHCP6_PD_LEASE_RENEW = "DHCP6_PD_LEASE_RENEW";
+extern const isc::log::MessageID DHCP6_PD_LEASE_REUSE = "DHCP6_PD_LEASE_REUSE";
extern const isc::log::MessageID DHCP6_PROCESS_IA_NA_EXTEND = "DHCP6_PROCESS_IA_NA_EXTEND";
extern const isc::log::MessageID DHCP6_PROCESS_IA_NA_RELEASE = "DHCP6_PROCESS_IA_NA_RELEASE";
extern const isc::log::MessageID DHCP6_PROCESS_IA_NA_REQUEST = "DHCP6_PROCESS_IA_NA_REQUEST";
"DHCP6_LEASE_NA_WITHOUT_DUID", "%1: address lease for address %2 does not have a DUID",
"DHCP6_LEASE_PD_WITHOUT_DUID", "%1: lease for prefix %2/%3 does not have a DUID",
"DHCP6_LEASE_RENEW", "%1: lease for address %2 and iaid=%3 has been allocated",
+ "DHCP6_LEASE_REUSE", "%1: lease for address %2 and iaid=%3 has been reused for %4 seconds",
"DHCP6_MULTI_THREADING_INFO", "enabled: %1, number of threads: %2, queue size: %3",
"DHCP6_NOT_RUNNING", "IPv6 DHCP server is not running",
"DHCP6_NO_INTERFACES", "failed to detect any network interfaces",
"DHCP6_PD_LEASE_ALLOC", "%1: lease for prefix %2/%3 and iaid=%4 has been allocated for %5 seconds",
"DHCP6_PD_LEASE_ALLOC_FAIL", "%1: failed to grant a prefix lease for iaid=%2",
"DHCP6_PD_LEASE_RENEW", "%1: lease for prefix %2/%3 and iaid=%4 has been allocated",
+ "DHCP6_PD_LEASE_REUSE", "%1: lease for prefix %2/%3 and iaid=%4 has been reused for %5 seconds",
"DHCP6_PROCESS_IA_NA_EXTEND", "%1: extending lease lifetime for IA_NA option with iaid=%2",
"DHCP6_PROCESS_IA_NA_RELEASE", "%1: releasing lease for IA_NA option with iaid=%2",
"DHCP6_PROCESS_IA_NA_REQUEST", "%1: server is processing IA_NA option with iaid=%2 and hint=%3",
extern const isc::log::MessageID DHCP6_LEASE_NA_WITHOUT_DUID;
extern const isc::log::MessageID DHCP6_LEASE_PD_WITHOUT_DUID;
extern const isc::log::MessageID DHCP6_LEASE_RENEW;
+extern const isc::log::MessageID DHCP6_LEASE_REUSE;
extern const isc::log::MessageID DHCP6_MULTI_THREADING_INFO;
extern const isc::log::MessageID DHCP6_NOT_RUNNING;
extern const isc::log::MessageID DHCP6_NO_INTERFACES;
extern const isc::log::MessageID DHCP6_PD_LEASE_ALLOC;
extern const isc::log::MessageID DHCP6_PD_LEASE_ALLOC_FAIL;
extern const isc::log::MessageID DHCP6_PD_LEASE_RENEW;
+extern const isc::log::MessageID DHCP6_PD_LEASE_REUSE;
extern const isc::log::MessageID DHCP6_PROCESS_IA_NA_EXTEND;
extern const isc::log::MessageID DHCP6_PROCESS_IA_NA_RELEASE;
extern const isc::log::MessageID DHCP6_PROCESS_IA_NA_REQUEST;
information. The remaining arguments hold the allocated address and
IAID.
+% DHCP6_LEASE_REUSE %1: lease for address %2 and iaid=%3 has been reused for %4 seconds
+This informational message indicates that in response to a client's
+message, the server successfully reused a non-temporary address
+lease. This is a normal behavior and indicates successful operation.
+The first argument includes the client and transaction identification
+information. The remaining arguments hold the allocated address,
+IAID and validity lifetime.
+
% DHCP6_MULTI_THREADING_INFO enabled: %1, number of threads: %2, queue size: %3
This is a message listing some information about the multi-threading parameters
with which the server is running.
information. The remaining arguments hold the allocated prefix,
prefix length and IAID.
+% DHCP6_PD_LEASE_REUSE %1: lease for prefix %2/%3 and iaid=%4 has been reused for %5 seconds
+This informational message indicates that in response to a client's
+message, the server successfully reused a prefix lease.
+This is a normal behavior and indicates successful operation.
+The first argument includes the client and transaction identification
+information. The remaining arguments hold the allocated prefix,
+prefix length, IAID and validity lifetime.
+
% DHCP6_PROCESS_IA_NA_EXTEND %1: extending lease lifetime for IA_NA option with iaid=%2
This message is logged when the server is starting to extend the lifetime
of the address lease associated with the particular IAID. The first argument
Lease6CollectionPtr new_leases(new Lease6Collection());
if (!ctx.new_leases_.empty()) {
- new_leases->assign(ctx.new_leases_.cbegin(),
- ctx.new_leases_.cend());
+ for (auto new_lease : ctx.new_leases_) {
+ if (new_lease->remaining_valid_lft_ == 0) {
+ new_leases->push_back(new_lease);
+ }
+ }
}
callout_handle->setArgument("leases6", new_leases);
.arg(query->getLabel())
.arg(lease->addr_.toText())
.arg(ia->getIAID());
- } else {
+ } else if (lease->remaining_valid_lft_ == 0) {
LOG_INFO(lease6_logger, DHCP6_LEASE_ALLOC)
.arg(query->getLabel())
.arg(lease->addr_.toText())
.arg(ia->getIAID())
.arg(Lease::lifetimeToText(lease->valid_lft_));
+ } else {
+ auto age = lease->valid_lft_ - lease->remaining_valid_lft_;
+ lease->valid_lft_ = lease->remaining_valid_lft_;
+ lease->preferred_lft_ -= age;
+ LOG_INFO(lease6_logger, DHCP6_LEASE_REUSE)
+ .arg(query->getLabel())
+ .arg(lease->addr_.toText())
+ .arg(ia->getIAID())
+ .arg(Lease::lifetimeToText(lease->valid_lft_));
}
LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_LEASE_DATA)
.arg(query->getLabel())
for (Lease6Collection::iterator l = leases.begin();
l != leases.end(); ++l) {
- // Check for new minimum lease time
- if (((*l)->preferred_lft_ > 0) && (min_preferred_lft > (*l)->preferred_lft_)) {
- min_preferred_lft = (*l)->preferred_lft_;
- }
-
// We have a lease! Let's wrap its content into IA_PD option
// with IAADDR suboption.
if (ctx.fake_allocation_) {
.arg((*l)->addr_.toText())
.arg(static_cast<int>((*l)->prefixlen_))
.arg(ia->getIAID());
- } else {
+ } else if ((*l)->remaining_valid_lft_ == 0) {
LOG_INFO(lease6_logger, DHCP6_PD_LEASE_ALLOC)
.arg(query->getLabel())
.arg((*l)->addr_.toText())
.arg(static_cast<int>((*l)->prefixlen_))
.arg(ia->getIAID())
.arg(Lease::lifetimeToText((*l)->valid_lft_));
+ } else {
+ auto age = (*l)->valid_lft_ - (*l)->remaining_valid_lft_;
+ (*l)->valid_lft_ = (*l)->remaining_valid_lft_;
+ (*l)->preferred_lft_ -= age;
+ LOG_INFO(lease6_logger, DHCP6_PD_LEASE_REUSE)
+ .arg(query->getLabel())
+ .arg((*l)->addr_.toText())
+ .arg(static_cast<int>((*l)->prefixlen_))
+ .arg(ia->getIAID())
+ .arg(Lease::lifetimeToText((*l)->valid_lft_));
+ }
+
+ // Check for new minimum lease time
+ if (((*l)->preferred_lft_ > 0) && (min_preferred_lft > (*l)->preferred_lft_)) {
+ min_preferred_lft = (*l)->preferred_lft_;
}
boost::shared_ptr<Option6IAPrefix>
(*l)->addr_, (*l)->preferred_lft_, (*l)->valid_lft_));
ia_rsp->addOption(iaaddr);
+ if ((*l)->remaining_valid_lft_ == 0) {
+ LOG_INFO(lease6_logger, DHCP6_LEASE_RENEW)
+ .arg(query->getLabel())
+ .arg((*l)->addr_.toText())
+ .arg(ia->getIAID());
+ } else {
+ auto age = (*l)->valid_lft_ - (*l)->remaining_valid_lft_;
+ (*l)->valid_lft_ = (*l)->remaining_valid_lft_;
+ (*l)->preferred_lft_ -= age;
+ LOG_INFO(lease6_logger, DHCP6_LEASE_REUSE)
+ .arg(query->getLabel())
+ .arg((*l)->addr_.toText())
+ .arg(ia->getIAID())
+ .arg(Lease::lifetimeToText((*l)->valid_lft_));
+ }
+
// Check for new minimum lease time
if (((*l)->preferred_lft_ > 0) && (min_preferred_lft > (*l)->preferred_lft_)) {
min_preferred_lft = (*l)->preferred_lft_;
}
- LOG_INFO(lease6_logger, DHCP6_LEASE_RENEW)
- .arg(query->getLabel())
- .arg((*l)->addr_.toText())
- .arg(ia->getIAID());
-
// Now remove this prefix from the hints list.
AllocEngine::Resource hint_type((*l)->addr_, (*l)->prefixlen_);
hints.erase(std::remove(hints.begin(), hints.end(), hint_type),
}
}
+ if ((*l)->remaining_valid_lft_ == 0) {
+ LOG_INFO(lease6_logger, DHCP6_PD_LEASE_RENEW)
+ .arg(query->getLabel())
+ .arg((*l)->addr_.toText())
+ .arg(static_cast<int>((*l)->prefixlen_))
+ .arg(ia->getIAID());
+ } else {
+ auto age = (*l)->valid_lft_ - (*l)->remaining_valid_lft_;
+ (*l)->valid_lft_ = (*l)->remaining_valid_lft_;
+ (*l)->preferred_lft_ -= age;
+ LOG_INFO(lease6_logger, DHCP6_PD_LEASE_REUSE)
+ .arg(query->getLabel())
+ .arg((*l)->addr_.toText())
+ .arg(static_cast<int>((*l)->prefixlen_))
+ .arg(ia->getIAID())
+ .arg(Lease::lifetimeToText((*l)->valid_lft_));
+ }
+
// Check for new minimum lease time
if (((*l)->preferred_lft_ > 0) && ((*l)->preferred_lft_ < min_preferred_lft)) {
min_preferred_lft = (*l)->preferred_lft_;
}
- LOG_INFO(lease6_logger, DHCP6_PD_LEASE_RENEW)
- .arg(query->getLabel())
- .arg((*l)->addr_.toText())
- .arg(static_cast<int>((*l)->prefixlen_))
- .arg(ia->getIAID());
-
// Now remove this prefix from the hints list.
AllocEngine::Resource hint_type((*l)->addr_, (*l)->prefixlen_);
hints.erase(std::remove(hints.begin(), hints.end(), hint_type),
(*l)->hostname_ = ctx.hostname_;
(*l)->fqdn_fwd_ = ctx.fwd_dns_update_;
(*l)->fqdn_rev_ = ctx.rev_dns_update_;
+ (*l)->remaining_valid_lft_ = 0;
LeaseMgrFactory::instance().updateLease6(*l);
}
}
lease->setContext(user_context);
}
+void
+AllocEngine::setLeaseRemainingLife(Lease& lease, const SubnetPtr& subnet) const {
+ // Sanity.
+ lease.remaining_valid_lft_ = 0;
+ if (!subnet) {
+ return;
+ }
+
+ // Always reuse infinite lifetime leases.
+ if (lease.valid_lft_ == Lease::INFINITY_LFT) {
+ lease.remaining_valid_lft_ = Lease::INFINITY_LFT;
+ }
+
+ // Refuse time going backward.
+ if (lease.cltt_ > lease.current_cltt_) {
+ return;
+ }
+ uint32_t age = lease.current_cltt_ - lease.cltt_;
+ // Already expired.
+ if (age > lease.current_valid_lft_) {
+ return;
+ }
+
+ // Try cache max age.
+ uint32_t max_age = 0;
+ if (!subnet->getCacheMaxAge().unspecified()) {
+ max_age = subnet->getCacheMaxAge().get();
+ if ((max_age == 0) || (age > max_age)) {
+ return;
+ }
+ }
+
+ // Try cache threshold.
+ if (!subnet->getCacheThreshold().unspecified()) {
+ double threshold = subnet->getCacheThreshold().get();
+ if ((threshold <= 0.) || (threshold > 1.)) {
+ return;
+ }
+ max_age = lease.valid_lft_ * threshold;
+ if (age > max_age) {
+ return;
+ }
+ }
+
+ // Seems to be reusable.
+ lease.remaining_valid_lft_ = lease.current_cltt_ - age;
+}
+
} // namespace dhcp
} // namespace isc
///
/// @param [out] lease A pointer to the lease to be updated.
/// @param ctx A context containing information from the server about the
+ /// client and its message.
void updateLease4ExtendedInfo(const Lease4Ptr& lease,
const ClientContext4& ctx) const;
///
/// @param [out] lease A pointer to the lease to be updated.
/// @param ctx A context containing information from the server about the
+ /// client and its message.
void updateLease6ExtendedInfo(const Lease6Ptr& lease,
const ClientContext6& ctx) const;
+private:
+
+ /// @brief Try to reuse an already allocated lease.
+ ///
+ /// This function computes and sets when acceptable the remaining
+ /// valid lifetime of an already allocated lease.
+ /// This uses the cache-threshold and cache-max-age parameters.
+ ///
+ /// A not zero value for the remaining valid lifetime means the
+ /// lease can reuse i.e.:
+ /// - the lease is not updated in the lease database.
+ /// - the previous value of the lease can be returned to the client.
+ ///
+ /// @param [in,out] lease The lease to be updated.
+ /// @param subnet A pointer to the lease subnet.
+ void setLeaseRemainingLife(Lease& lease, const SubnetPtr& subnet) const;
+
private:
/// @brief Number of consecutive DHCPv4 leases' reclamations after
const bool fqdn_fwd, const bool fqdn_rev,
const std::string& hostname, const HWAddrPtr& hwaddr)
: addr_(addr), valid_lft_(valid_lft), current_valid_lft_(valid_lft),
+ remaining_valid_lft_(0),
cltt_(cltt), current_cltt_(cltt), subnet_id_(subnet_id),
hostname_(boost::algorithm::to_lower_copy(hostname)), fqdn_fwd_(fqdn_fwd),
fqdn_rev_(fqdn_rev), hwaddr_(hwaddr), state_(STATE_DEFAULT) {
addr_ = other.addr_;
valid_lft_ = other.valid_lft_;
current_valid_lft_ = other.current_valid_lft_;
+ remaining_valid_lft_ = other.remaining_valid_lft_;
cltt_ = other.cltt_;
current_cltt_ = other.current_cltt_;
subnet_id_ = other.subnet_id_;
subnet_id_ == other.subnet_id_ &&
valid_lft_ == other.valid_lft_ &&
current_valid_lft_ == other.current_valid_lft_ &&
+ remaining_valid_lft_ == other.remaining_valid_lft_ &&
cltt_ == other.cltt_ &&
current_cltt_ == other.current_cltt_ &&
hostname_ == other.hostname_ &&
preferred_lft_ == other.preferred_lft_ &&
valid_lft_ == other.valid_lft_ &&
current_valid_lft_ == other.current_valid_lft_ &&
+ remaining_valid_lft_ == other.remaining_valid_lft_ &&
cltt_ == other.cltt_ &&
current_cltt_ == other.current_cltt_ &&
subnet_id_ == other.subnet_id_ &&
/// Expressed as number of seconds since cltt before update.
uint32_t current_valid_lft_;
+ /// @brief Remaining valid lifetime
+ ///
+ /// Expressed as number of seconds since current time, also
+ /// valid lifetime - age where age is old cltt - new cltt.
+ uint32_t remaining_valid_lft_;
+
/// @brief Client last transmission time
///
/// Specifies a timestamp giving the time when the last transmission from a