Browse Source

[3913] Allocation engine extends the lifetime of the lease for Request.

Marcin Siodelski 9 years ago
parent
commit
6c489c3e41

+ 50 - 5
src/lib/dhcpsrv/alloc_engine.cc

@@ -289,10 +289,45 @@ AllocEngine::AllocatorPtr AllocEngine::getAllocator(Lease::Type type) {
     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_(""),
@@ -422,7 +457,7 @@ AllocEngine::allocateLeases6(ClientContext6& ctx) {
 
             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
@@ -719,7 +754,7 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, Lease6Collection& exis
         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
@@ -729,6 +764,13 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, Lease6Collection& exis
                     .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;
             }
         }
@@ -1186,12 +1228,14 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) {
     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())
@@ -1246,7 +1290,7 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) {
 }
 
 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) {
@@ -1255,7 +1299,8 @@ AllocEngine::updateFqdnData(ClientContext6& ctx, const Lease6Collection& leases)
         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);

+ 12 - 5
src/lib/dhcpsrv/alloc_engine.h

@@ -634,19 +634,26 @@ private:
                                 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

+ 112 - 0
src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc

@@ -601,6 +601,118 @@ TEST_F(AllocEngine6Test, requestReuseExpiredLease6) {
     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)

+ 1 - 1
src/lib/dhcpsrv/tests/alloc_engine_utils.cc

@@ -74,7 +74,7 @@ AllocEngine6Test::initSubnet(const asiolink::IOAddress& subnet,
                     const asiolink::IOAddress& pool_end) {
     CfgMgr& cfg_mgr = CfgMgr::instance();
 
-    subnet_ = Subnet6Ptr(new Subnet6(subnet, 56, 1, 2, 3, 4));
+    subnet_ = Subnet6Ptr(new Subnet6(subnet, 56, 100, 200, 300, 400));
     pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, pool_start, pool_end));
 
     subnet_->addPool(pool_);