diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index 92d456d794..8cb6e39b60 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -2098,6 +2098,31 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx, } } +void +AllocEngine::getRemaining(const Lease6Ptr& lease, uint32_t& valid, + uint32_t& preferred) { + valid = 0; + preferred = 0; + if (!lease || (lease->state_ != Lease::STATE_DEFAULT)) { + return; + } + time_t now = time(0); + // Refuse time not going forward. + if (lease->cltt_ > now) { + return; + } + uint32_t age = now - lease->cltt_; + // Already expired. + if (age >= lease->valid_lft_) { + return; + } + valid = lease->valid_lft_ - age; + if (age >= lease->preferred_lft_) { + return; + } + preferred = lease->preferred_lft_ - age; +} + Lease6Collection AllocEngine::renewLeases6(ClientContext6& ctx) { try { @@ -4457,6 +4482,30 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr, } } +void +AllocEngine::getRemaining(const Lease4Ptr& lease, uint32_t& valid) { + valid = 0; + if (!lease || (lease->state_ != Lease::STATE_DEFAULT)) { + return; + } + // Always remain infinite lifetime leases. + if (lease->valid_lft_ == Lease::INFINITY_LFT) { + valid = Lease::INFINITY_LFT; + return; + } + time_t now = time(0); + // Refuse time not going forward. + if (lease->cltt_ > now) { + return; + } + uint32_t age = now - lease->cltt_; + // Already expired. + if (age >= lease->valid_lft_) { + return; + } + valid = lease->valid_lft_ - age; +} + Lease4Ptr AllocEngine::renewLease4(const Lease4Ptr& lease, AllocEngine::ClientContext4& ctx) { diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h index de0ce5d345..1e32036a5a 100644 --- a/src/lib/dhcpsrv/alloc_engine.h +++ b/src/lib/dhcpsrv/alloc_engine.h @@ -1555,6 +1555,20 @@ public: /// @return unsigned integer value of the offer lifetime to use. static uint32_t getOfferLft(const ClientContext4& ctx, bool only_on_discover = true); + /// @brief Set remaining valid life time. + /// + /// @param lease A pointer to the lease. + /// @param [out] valid The remaining valid life time or 0. + static void getRemaining(const Lease4Ptr& lease, uint32_t& valid); + + /// @brief Set remaining valid and preferred life times. + /// + /// @param lease A pointer to the lease. + /// @param [out] valid The remaining valid life time or 0. + /// @param [out] preferred The remaining preferred life time or 0. + static void getRemaining(const Lease6Ptr& lease, uint32_t& valid, + uint32_t& preferred); + private: /// @brief Offers the lease. diff --git a/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc index a58c39ccd5..560d6cff3b 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc @@ -4850,6 +4850,52 @@ TEST_F(AllocEngine4Test, getValidLft4) { } } +// Verifies that AllocEngine::getRemaining retuns the remaining lifetime value. +TEST_F(AllocEngine4Test, getRemaining) { + // No Lease. + uint32_t valid(1); + Lease4Ptr lease; + AllocEngine::getRemaining(lease, valid); + EXPECT_EQ(0, valid); + + // Unexpected state. + valid = 1; + uint8_t hwaddr_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }; + HWAddrPtr hwaddr(new HWAddr(hwaddr_data, sizeof(hwaddr_data), HTYPE_ETHER)); + uint8_t clientid[] = { 8, 7, 6, 5, 4, 3, 2, 1 }; + time_t now = time(0); + lease.reset(new Lease4(IOAddress("192.0.2.100"), hwaddr, clientid, + sizeof(clientid), 100, now, 1)); + lease->state_ = Lease::STATE_DECLINED; + AllocEngine::getRemaining(lease, valid); + EXPECT_EQ(0, valid); + + // Infinite lifetime. + lease->state_ = Lease::STATE_DEFAULT; + uint32_t infinity_lft = Lease::INFINITY_LFT; + lease->valid_lft_ = lease->current_valid_lft_ = infinity_lft; + AllocEngine::getRemaining(lease, valid); + EXPECT_EQ(infinity_lft, valid); + + // Time going backward. + lease->cltt_ = lease->current_cltt_ = now + 100; + lease->valid_lft_ = lease->current_valid_lft_ = 50; + AllocEngine::getRemaining(lease, valid); + EXPECT_EQ(0, valid); + + // Already expired. + valid = 1; + lease->cltt_ = lease->current_cltt_ = now - 100; + AllocEngine::getRemaining(lease, valid); + EXPECT_EQ(0, valid); + + // Valid case. + now = time(0); + lease->cltt_ = lease->current_cltt_ = now - 10; + AllocEngine::getRemaining(lease, valid); + EXPECT_NEAR(40, valid, 1); +} + // Verifies that AllocEngine::getValidLft(ctx4) returns the appropriate // lifetime value based on the context content. TEST_F(AllocEngine4Test, getTemplateClassValidLft4) { diff --git a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc index 24bd92174d..1bc3739c2c 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc @@ -6027,6 +6027,62 @@ TEST_F(AllocEngine6Test, getTemplateClassValidLifetime) { } } +// Verifies that AllocEngine::getRemaining retuns the remaining lifetime values. +TEST_F(AllocEngine6Test, getRemaining) { + // No Lease. + uint32_t valid(1); + uint32_t preferred(1); + Lease6Ptr lease; + AllocEngine::getRemaining(lease, valid, preferred); + EXPECT_EQ(0, valid); + EXPECT_EQ(0, preferred); + + // Unexpected state. + valid = 1; + preferred = 1; + DuidPtr duid(new DUID(vector(12, 0xff))); + const uint32_t iaid = 3568; + time_t now = time(0); + lease.reset(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"), duid, + iaid, 30, 50, 1)); + lease->state_ = Lease::STATE_DECLINED; + AllocEngine::getRemaining(lease, valid, preferred); + EXPECT_EQ(0, valid); + EXPECT_EQ(0, preferred); + + // Time going backward. + valid = 1; + preferred = 1; + lease->state_ = Lease::STATE_DEFAULT; + lease->cltt_ = lease->current_cltt_ = now + 100; + lease->valid_lft_ = lease->current_valid_lft_ = 50; + AllocEngine::getRemaining(lease, valid, preferred); + EXPECT_EQ(0, valid); + EXPECT_EQ(0, preferred); + + // Already expired. + valid = 1; + preferred = 1; + lease->cltt_ = lease->current_cltt_ = now - 100; + AllocEngine::getRemaining(lease, valid, preferred); + EXPECT_EQ(0, valid); + EXPECT_EQ(0, preferred); + + // Valid case. + now = time(0); + lease->cltt_ = lease->current_cltt_ = now - 10; + AllocEngine::getRemaining(lease, valid, preferred); + EXPECT_NEAR(40, valid, 1); + EXPECT_NEAR(20, preferred, 1); + + // No longer preferred. + now = time(0); + lease->cltt_ = lease->current_cltt_ = now - 40; + AllocEngine::getRemaining(lease, valid, preferred); + EXPECT_NEAR(10, valid, 1); + EXPECT_EQ(0, preferred); +} + // Verifies that AllocEngine::getLifetimes6() returns the appropriate // preferred lifetime value based on the context content. TEST_F(AllocEngine6Test, getPreferredLifetime) {