return (alloc->second);
}
+} // end of isc::dhcp namespace
+} // end of isc namespace
+
+namespace {
+
+/// @brief Extends the lease lifetime.
+///
+/// This function is called to conditionally extend the lifetime of
+/// the DHCPv4 or DHCPv6 lease. It is envisaged that this function will
+/// make a decision if the lease lifetime should be extended, using
+/// a preconfigured threshold, which would indicate how many percent
+/// of the valid lifetime should have passed for the lease lifetime
+/// to be extended. The lease lifetime would not be extended if
+/// the threshold hasn't been reached.
+///
+/// @todo Currently this function always extends the lease lifetime.
+/// In the future, it will take the threshold value into account,
+/// once the threshold is configurable.
+///
+/// @param [out] lease A lease for which the lifetime should be
+/// extended.
+///
+/// @return true if the lease lifetime has been extended, false
+/// otherwise.
+bool
+conditionalExtendLifetime(Lease& lease) {
+ lease.cltt_ = time(NULL);
+ return (true);
+}
+
+} // end of anonymous namespace
+
// ##########################################################################
// # DHCPv6 lease allocation code starts here.
// ##########################################################################
+namespace isc {
+namespace dhcp {
+
AllocEngine::ClientContext6::ClientContext6()
: subnet_(), duid_(), iaid_(0), type_(Lease::TYPE_NA), hwaddr_(),
hints_(), fwd_dns_update_(false), rev_dns_update_(false), hostname_(""),
if (!leases.empty()) {
// Return old leases so the server can see what has changed.
- return (updateFqdnData(ctx, leases));
+ return (updateLeaseData(ctx, leases));
}
// If leases are empty at this stage, it means that we used to have
uint8_t prefix_len = resv->second.getPrefixLen();
// Check if already have this lease on the existing_leases list.
- for (Lease6Collection::const_iterator l = existing_leases.begin();
+ for (Lease6Collection::iterator l = existing_leases.begin();
l != existing_leases.end(); ++l) {
// Ok, we already have a lease for this reservation and it's usable
.arg(ctx.query_->getLabel())
.arg((*l)->typeToText((*l)->type_))
.arg((*l)->addr_.toText());
+
+ // If this is a real allocation, we may need to extend the lease
+ // lifetime.
+ if (!ctx.fake_allocation_ && conditionalExtendLifetime(**l)) {
+ LeaseMgrFactory::instance().updateLease6(*l);
+ }
+
return;
}
}
lease->valid_lft_ = ctx.subnet_->getValid();
lease->t1_ = ctx.subnet_->getT1();
lease->t2_ = ctx.subnet_->getT2();
- lease->cltt_ = time(NULL);
lease->hostname_ = ctx.hostname_;
lease->fqdn_fwd_ = ctx.fwd_dns_update_;
lease->fqdn_rev_ = ctx.rev_dns_update_;
lease->hwaddr_ = ctx.hwaddr_;
+ // Extend lease lifetime if it is time to extend it.
+ conditionalExtendLifetime(*lease);
+
LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE_DETAIL_DATA,
ALLOC_ENGINE_V6_EXTEND_NEW_LEASE_DATA)
.arg(ctx.query_->getLabel())
}
Lease6Collection
-AllocEngine::updateFqdnData(ClientContext6& ctx, const Lease6Collection& leases) {
+AllocEngine::updateLeaseData(ClientContext6& ctx, const Lease6Collection& leases) {
Lease6Collection updated_leases;
for (Lease6Collection::const_iterator lease_it = leases.begin();
lease_it != leases.end(); ++lease_it) {
lease->fqdn_rev_ = ctx.rev_dns_update_;
lease->hostname_ = ctx.hostname_;
if (!ctx.fake_allocation_ &&
- ((lease->fqdn_fwd_ != (*lease_it)->fqdn_fwd_) ||
+ (conditionalExtendLifetime(*lease) ||
+ (lease->fqdn_fwd_ != (*lease_it)->fqdn_fwd_) ||
(lease->fqdn_rev_ != (*lease_it)->fqdn_rev_) ||
(lease->hostname_ != (*lease_it)->hostname_))) {
ctx.changed_leases_.push_back(*lease_it);
ClientContext6& ctx,
uint8_t prefix_len);
- /// @brief Updates FQDN data for a collection of leases.
+ /// @brief Updates FQDN and Client's Last Tranmission Time for a collection
+ /// of leases.
+ ///
+ /// This method is executed when the server finds existing leases for a
+ /// client and updates some date for these leases if needed:
+ /// - client's last transmission time (cltt), if the lease to be returned
+ /// to the client should have its lifetime extended,
+ /// - FQDN data, when the client has negotiated new FQDN with the server.
///
/// @param ctx IPv6 client context (old versions of the leases that had
/// FQDN data changed will be stored in ctx.changed_leases_,
/// ctx.fwd_dns_update, ctx.rev_dns_update, ctx.hostname_
/// and ctx.fake_allocation_ will be used.
- /// @param leases Collection of leases for which FQDN data should be
+ /// @param leases Collection of leases for which lease data should be
/// updated.
///
- /// @return Collection of leases with updated FQDN data. Note that returned
+ /// @return Collection of leases with updated data. Note that returned
/// collection holds updated FQDN data even for fake allocation.
- Lease6Collection updateFqdnData(ClientContext6& ctx,
- const Lease6Collection& leases);
+ Lease6Collection updateLeaseData(ClientContext6& ctx,
+ const Lease6Collection& leases);
/// @brief Utility function that removes all leases with a specified address
/// @param container A collection of Lease6 pointers
EXPECT_EQ(100, stat->getInteger().first);
}
+// Checks if the lease lifetime is extended when the client sends the
+// Request.
+TEST_F(AllocEngine6Test, requestExtendLeaseLifetime) {
+ // Create a lease for the client.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::15"),
+ duid_, iaid_, 300, 400, 100, 200,
+ subnet_->getID(), HWAddrPtr(), 128));
+
+ // Allocated 200 seconds ago - half of the lifetime.
+ time_t lease_cltt = time(NULL) - 200;
+ lease->cltt_ = lease_cltt;
+
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Client should receive a lease.
+ Lease6Ptr new_lease = simpleAlloc6Test(pool_, IOAddress("::"), false);
+ ASSERT_TRUE(new_lease);
+
+ // And the lease lifetime should be extended.
+ EXPECT_GT(new_lease->cltt_, lease_cltt)
+ << "Lease lifetime was not extended, but it should";
+}
+
+// Checks if the lease lifetime is extended when the client sends the
+// Request and the client has a reservation for the lease.
+TEST_F(AllocEngine6Test, requestExtendLeaseLifetimeForReservation) {
+ // Create reservation for the client. This is in-pool reservation,
+ // as the pool is 2001:db8:1::10 - 2001:db8:1::20.
+ createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1c"), 128);
+
+ // Create a lease for the client.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1c"),
+ duid_, iaid_, 300, 400, 100, 200,
+ subnet_->getID(), HWAddrPtr(), 128));
+
+ // Allocated 200 seconds ago - half of the lifetime.
+ time_t lease_cltt = time(NULL) - 200;
+ lease->cltt_ = lease_cltt;
+
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Client should receive a lease.
+ Lease6Ptr new_lease = simpleAlloc6Test(pool_, IOAddress("::"), false);
+ ASSERT_TRUE(new_lease);
+
+ // And the lease lifetime should be extended.
+ EXPECT_GT(new_lease->cltt_, lease_cltt)
+ << "Lease lifetime was not extended, but it should";
+}
+
+// Checks if the lease lifetime is extended when the client sends the
+// Renew.
+TEST_F(AllocEngine6Test, renewExtendLeaseLifetime) {
+ // Create a lease for the client.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::15"),
+ duid_, iaid_, 300, 400, 100, 200,
+ subnet_->getID(), HWAddrPtr(), 128));
+
+ // Allocated 200 seconds ago - half of the lifetime.
+ time_t lease_cltt = time(NULL) - 200;
+ lease->cltt_ = lease_cltt;
+
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100);
+
+ // This is what the client will send in his renew message.
+ AllocEngine::HintContainer hints;
+ hints.push_back(make_pair(IOAddress("2001:db8:1::15"), 128));
+
+ // Client should receive a lease.
+ Lease6Collection renewed = renewTest(engine, pool_, hints, true);
+ ASSERT_EQ(1, renewed.size());
+
+ // And the lease lifetime should be extended.
+ EXPECT_GT(renewed[0]->cltt_, lease_cltt)
+ << "Lease lifetime was not extended, but it should";
+}
+
+// Checks if the lease lifetime is extended when the client sends the
+// Renew and the client has a reservation for the lease.
+TEST_F(AllocEngine6Test, renewExtendLeaseLifetimeForReservation) {
+ // Create reservation for the client. This is in-pool reservation,
+ // as the pool is 2001:db8:1::10 - 2001:db8:1::20.
+ createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::15"), 128);
+
+ // Create a lease for the client.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::15"),
+ duid_, iaid_, 300, 400, 100, 200,
+ subnet_->getID(), HWAddrPtr(), 128));
+
+ // Allocated 200 seconds ago - half of the lifetime.
+ time_t lease_cltt = time(NULL) - 200;
+ lease->cltt_ = lease_cltt;
+
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100);
+
+ // This is what the client will send in his renew message.
+ AllocEngine::HintContainer hints;
+ hints.push_back(make_pair(IOAddress("2001:db8:1::15"), 128));
+
+ // Client should receive a lease.
+ Lease6Collection renewed = renewTest(engine, pool_, hints, true);
+ ASSERT_EQ(1, renewed.size());
+
+ // And the lease lifetime should be extended.
+ EXPECT_GT(renewed[0]->cltt_, lease_cltt)
+ << "Lease lifetime was not extended, but it should";
+}
+
// --- v6 host reservation ---
// Checks that a client gets the address reserved (in-pool case)