Calculating the values is controlled by the following three parameters.
- ``calculate-tee-times`` - when true, T1 and T2 will be calculated as
- percentages of the valid lease time. It defaults to false.
+ percentages of the valid lease time. It defaults to false and
+ is ignored for infinite (0xFFFFFFFF) valid lease times.
- ``t1-percent`` - the percentage of the valid lease time to use for
T1. It is expressed as a real number between 0.0 and 1.0 and must be
Calculation of the values is controlled by the following three parameters:
- ``calculate-tee-times`` - when true, T1 and T2 will be calculated as
- percentages of the valid lease time. It defaults to true.
+ percentages of the valid lease time. It defaults to true and is
+ ignored for infinite (0xFFFFFFFF) valid lease times.
- ``t1-percent`` - the percentage of the valid lease time to use for
T1. It is expressed as a real number between 0.0 and 1.0 and must be
// If T2 is explicitly configured we'll use try value.
if (!subnet->getT2().unspecified()) {
t2_time = subnet->getT2();
+ } else if (lease->valid_lft_ == Lease::INFINITY_LFT) {
+ // Do not calculate with infinite values.
+ t2_time = subnet->getT2();
} else if (subnet->getCalculateTeeTimes()) {
// Calculating tee times is enabled, so calculated it.
t2_time = static_cast<uint32_t>(round(subnet->getT2Percent() * (lease->valid_lft_)));
// If T1 is explicitly configured we'll use try value.
if (!subnet->getT1().unspecified()) {
t1_time = subnet->getT1();
+ } else if (lease->valid_lft_== Lease::INFINITY_LFT) {
+ // Do not calculate with infinite values.
+ t1_time = subnet->getT1();
} else if (subnet->getCalculateTeeTimes()) {
// Calculating tee times is enabled, so calculate it.
t1_time = static_cast<uint32_t>(round(subnet->getT1Percent() * (lease->valid_lft_)));
// If T2 is explicitly configured we'll use that value.
if (!subnet->getT2().unspecified()) {
t2_time = subnet->getT2();
+ } else if (preferred_lft == Lease::INFINITY_LFT) {
+ // Do not calculate with infinite values.
+ t2_time = subnet->getT2();
} else if (subnet->getCalculateTeeTimes()) {
// Calculating tee times is enabled, so calculate it.
t2_time = static_cast<uint32_t>(round(subnet->getT2Percent() * preferred_lft));
// If T1 is explicitly configured we'll use try value.
if (!subnet->getT1().unspecified()) {
t1_time = subnet->getT1();
+ } else if (preferred_lft == Lease::INFINITY_LFT) {
+ // Do not calculate with infinite values.
+ t1_time = subnet->getT1();
} else if (subnet->getCalculateTeeTimes()) {
// Calculating tee times is enabled, so calculate it.
t1_time = static_cast<uint32_t>(round(subnet->getT1Percent() * preferred_lft));
if (!ctx.currentIA().hints_.empty() &&
ctx.currentIA().hints_[0].getPreferred()) {
uint32_t preferred = ctx.currentIA().hints_[0].getPreferred();
- expired->preferred_lft_ = ctx.subnet_->getPreferred().get(preferred);
+ if ((preferred == Lease::INFINITY_LFT) &&
+ ctx.subnet_->getAllowStaticLeases()) {
+ expired->preferred_lft_ = Lease::INFINITY_LFT;
+ } else {
+ expired->preferred_lft_ =
+ ctx.subnet_->getPreferred().get(preferred);
+ }
} else {
expired->preferred_lft_ = ctx.subnet_->getPreferred();
}
if (!ctx.currentIA().hints_.empty() &&
ctx.currentIA().hints_[0].getValid()) {
uint32_t valid = ctx.currentIA().hints_[0].getValid();
- expired->valid_lft_ = ctx.subnet_->getValid().get(valid);
+ if ((valid == Lease::INFINITY_LFT) &&
+ ctx.subnet_->getAllowStaticLeases()) {
+ expired->valid_lft_ = Lease::INFINITY_LFT;
+ } else {
+ expired->valid_lft_ = ctx.subnet_->getValid().get(valid);
+ }
} else {
expired->valid_lft_ = ctx.subnet_->getValid();
}
if (!ctx.currentIA().hints_.empty() &&
ctx.currentIA().hints_[0].getPreferred()) {
preferred = ctx.currentIA().hints_[0].getPreferred();
- preferred = ctx.subnet_->getPreferred().get(preferred);
+ if ((preferred != Lease::INFINITY_LFT) ||
+ !ctx.subnet_->getAllowStaticLeases()) {
+ preferred = ctx.subnet_->getPreferred().get(preferred);
+ }
}
uint32_t valid = ctx.subnet_->getValid();
if (!ctx.currentIA().hints_.empty() &&
ctx.currentIA().hints_[0].getValid()) {
valid = ctx.currentIA().hints_[0].getValid();
- valid = ctx.subnet_->getValid().get(valid);
+ if ((valid != Lease::INFINITY_LFT) ||
+ !ctx.subnet_->getAllowStaticLeases()) {
+ valid = ctx.subnet_->getValid().get(valid);
+ }
}
Lease6Ptr lease(new Lease6(ctx.currentIA().type_, addr, ctx.duid_,
ctx.currentIA().iaid_, preferred,
if (!ctx.currentIA().hints_.empty() &&
ctx.currentIA().hints_[0].getPreferred()) {
uint32_t preferred = ctx.currentIA().hints_[0].getPreferred();
- lease->preferred_lft_ = ctx.subnet_->getPreferred().get(preferred);
+ if ((preferred == Lease::INFINITY_LFT) &&
+ ctx.subnet_->getAllowStaticLeases()) {
+ lease->preferred_lft_ = Lease::INFINITY_LFT;
+ } else {
+ lease->preferred_lft_ = ctx.subnet_->getPreferred().get(preferred);
+ }
} else {
lease->preferred_lft_ = ctx.subnet_->getPreferred();
}
if (!ctx.currentIA().hints_.empty() &&
ctx.currentIA().hints_[0].getValid()) {
uint32_t valid = ctx.currentIA().hints_[0].getValid();
- lease->valid_lft_ = ctx.subnet_->getValid().get(valid);
+ if ((valid == Lease::INFINITY_LFT) &&
+ ctx.subnet_->getAllowStaticLeases()) {
+ lease->valid_lft_ = Lease::INFINITY_LFT;
+ } else {
+ lease->valid_lft_ = ctx.subnet_->getValid().get(valid);
+ }
} else {
lease->valid_lft_ = ctx.subnet_->getValid();
}
opt_lft = boost::dynamic_pointer_cast<OptionInt<uint32_t> >(opt);
}
if (opt_lft) {
- valid_lft = ctx.subnet_->getValid().get(opt_lft->getValue());
+ uint32_t valid = opt_lft->getValue();
+ if ((valid == Lease::INFINITY_LFT) &&
+ ctx.subnet_->getAllowStaticLeases()) {
+ valid_lft = Lease::INFINITY_LFT;
+ } else {
+ valid_lft = ctx.subnet_->getValid().get(valid);
+ }
}
time_t now = time(NULL);
opt_lft = boost::dynamic_pointer_cast<OptionInt<uint32_t> >(opt);
}
if (opt_lft) {
- lease->valid_lft_ = ctx.subnet_->getValid().get(opt_lft->getValue());
+ uint32_t valid = opt_lft->getValue();
+ if ((valid == Lease::INFINITY_LFT) &&
+ ctx.subnet_->getAllowStaticLeases()) {
+ lease->valid_lft_ = Lease::INFINITY_LFT;
+ } else {
+ lease->valid_lft_ = ctx.subnet_->getValid().get(valid);
+ }
} else {
lease->valid_lft_ = ctx.subnet_->getValid();
}
detailCompareLease(lease, from_mgr);
}
+// This test checks that simple allocation handles static leases.
+TEST_F(AllocEngine4Test, staticAlloc4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
+ false, true, "somehost.example.com.", false);
+ subnet_->setValid(Triplet<uint32_t>(1, 3, 5));
+ subnet_->setAllowStaticLeases(true);
+ ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+
+ // Speficy an infinite valid lifetime.
+ uint32_t infinity_lft = Lease::INFINITY_LFT;
+ OptionUint32Ptr opt(new OptionUint32(Option::V4, DHO_DHCP_LEASE_TIME,
+ infinity_lft));
+ ctx.query_->addOption(opt);
+
+ Lease4Ptr lease = engine->allocateLease4(ctx);
+ // The new lease has been allocated, so the old lease should not exist.
+ EXPECT_FALSE(ctx.old_lease_);
+
+ // Check that we got a lease
+ ASSERT_TRUE(lease);
+
+ // Do all checks on the lease
+ checkLease4(lease, true);
+
+ // Check the valid lifetime has the wanted value.
+ EXPECT_EQ(infinity_lft, lease->valid_lft_);
+
+ // Check that the lease is indeed in LeaseMgr
+ Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
+ ASSERT_TRUE(from_mgr);
+
+ // Now check that the lease in LeaseMgr has the same parameters
+ detailCompareLease(lease, from_mgr);
+}
+
// This test checks if the fake allocation (for DHCPDISCOVER) can succeed
TEST_F(AllocEngine4Test, fakeAlloc4) {
boost::scoped_ptr<AllocEngine> engine;
EXPECT_EQ(subnet_->getValid().getMax(), lease2->valid_lft_);
}
+// This test checks simple renewal handles static leases.
+TEST_F(AllocEngine4Test, staticRenew4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
+ false, true, "somehost.example.com.", false);
+ subnet_->setValid(Triplet<uint32_t>(1, 3, 5));
+ subnet_->setAllowStaticLeases(true);
+ ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+
+ // Speficy the valid lifetime we want, as it is greater than the max value
+ // we'll get this max value instead.
+ uint32_t infinity_lft = Lease::INFINITY_LFT;
+ OptionUint32Ptr opt(new OptionUint32(Option::V4, DHO_DHCP_LEASE_TIME,
+ infinity_lft));
+ ctx.query_->addOption(opt);
+
+ Lease4Ptr lease = engine->allocateLease4(ctx);
+
+ // Check that we got a lease and it's sane
+ ASSERT_TRUE(lease);
+ checkLease4(lease, true);
+
+ // Check the valid lifetime has the max value.
+ EXPECT_EQ(infinity_lft, lease->valid_lft_);
+
+ // The new lease has been allocated, so the old lease should not exist.
+ EXPECT_FALSE(ctx.old_lease_);
+
+ // Do it again, this should amount to the renew of an existing lease
+ Lease4Ptr lease2 = engine->allocateLease4(ctx);
+
+ // Check that we got a lease and it's sane
+ ASSERT_TRUE(lease2);
+ checkLease4(lease2, true);
+
+ // Lease already existed, so old_lease should be set.
+ EXPECT_TRUE(ctx.old_lease_);
+
+ // Check the renewed valid lifetime has the infinite value.
+ EXPECT_EQ(infinity_lft, lease2->valid_lft_);
+}
+
// This test verifies that the allocator picks addresses that belong to the
// pool
TEST_F(AllocEngine4Test, IterativeAllocator) {
simpleAlloc6Test(pd_pool_, IOAddress("::"), 500, 600, 400, 500);
}
+// This test checks that simple allocation handles static leases.
+TEST_F(AllocEngine6Test, staticAlloc6) {
+ uint32_t infinity_lft = Lease::INFINITY_LFT;
+ simpleAlloc6Test(pool_, IOAddress("::"), infinity_lft, infinity_lft,
+ infinity_lft, infinity_lft);
+}
+
// This test checks if the simple PD allocation (REQUEST) can succeed
// and the stats counter is properly bumped by 1
TEST_F(AllocEngine6Test, pdSimpleAlloc6) {
EXPECT_EQ(500, lease->valid_lft_);
}
+// This test checks if an expired lease can be reused using infinite lifetimes.
+TEST_F(AllocEngine6Test, staticReuseExpiredLease6) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+ ASSERT_TRUE(engine);
+
+ IOAddress addr("2001:db8:1::ad");
+
+ // Create one subnet with a pool holding one address.
+ initSubnet(IOAddress("2001:db8:1::"), addr, addr);
+ subnet_->setPreferred(Triplet<uint32_t>(200, 300, 400));
+ subnet_->setValid(Triplet<uint32_t>(300, 400, 500));
+ subnet_->setAllowStaticLeases(true);
+
+ // Initialize FQDN data for the lease.
+ initFqdn("myhost.example.com", true, true);
+
+ // Just a different duid
+ DuidPtr other_duid = DuidPtr(new DUID(vector<uint8_t>(12, 0xff)));
+ const uint32_t other_iaid = 3568;
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, other_duid, other_iaid,
+ 501, 502, subnet_->getID(),
+ HWAddrPtr(), 0));
+ lease->cltt_ = time(NULL) - 500; // Allocated 500 seconds ago
+ lease->valid_lft_ = 495; // Lease was valid for 495 seconds
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Make sure that we really created expired lease
+ ASSERT_TRUE(lease->expired());
+
+ // Asking specifically for this address with zero lifetimes
+ AllocEngine::ClientContext6 ctx2(subnet_, duid_, false, false, "", true,
+ Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234)));
+ ctx2.currentIA().iaid_ = iaid_;
+ uint32_t infinity_lft = Lease::INFINITY_LFT;
+ ctx2.currentIA().addHint(addr, 128, infinity_lft, infinity_lft);
+
+ EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx2)));
+
+ // Check that we got that single lease
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // Check lifetimes: infinite values are expected.
+ EXPECT_EQ(infinity_lft, lease->preferred_lft_);
+ EXPECT_EQ(infinity_lft, lease->valid_lft_);
+}
+
// This test checks if an expired lease can be reused in REQUEST (actual allocation)
TEST_F(AllocEngine6Test, requestReuseExpiredLease6) {
boost::scoped_ptr<AllocEngine> engine;
EXPECT_EQ(500, renewed[0]->valid_lft_);
}
+// Checks that a renewed lease handles static leases.
+TEST_F(AllocEngine6Test, staticRenewLeaseLifetime) {
+ // Create a lease for the client.
+ Lease6Ptr lease(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::15"),
+ duid_, iaid_, 300, 400,
+ 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);
+ subnet_->setPreferred(Triplet<uint32_t>(200, 300, 400));
+ subnet_->setValid(Triplet<uint32_t>(300, 400, 500));
+ subnet_->setAllowStaticLeases(true);
+
+ // This is what the client will send in his renew message.
+ AllocEngine::HintContainer hints;
+ uint32_t infinity_lft = Lease::INFINITY_LFT;
+ hints.push_back(AllocEngine::Resource(IOAddress("2001:db8:1::15"),
+ 128, infinity_lft, infinity_lft));
+
+ // Client should receive a lease.
+ Lease6Collection renewed = renewTest(engine, pool_, hints, true, 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 that infinite values are used for lifetimes.
+ EXPECT_EQ(infinity_lft, renewed[0]->preferred_lft_);
+ EXPECT_EQ(infinity_lft, renewed[0]->valid_lft_);
+}
+
// 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) {
ctx.currentIA().addHint(hint, expected_len, preferred, valid);
subnet_->setPreferred(Triplet<uint32_t>(200, 300, 400));
subnet_->setValid(Triplet<uint32_t>(300, 400, 500));
+ uint32_t infinity_lft = Lease::INFINITY_LFT;
+ subnet_->setAllowStaticLeases(exp_valid == infinity_lft);
// Set some non-standard callout status to make sure it doesn't affect the
// allocation.
}
// Do all checks on the lease
- checkLease6(duid_, lease, type, expected_len, true, true);
+ checkLease6(duid_, lease, type, expected_len, true, true,
+ exp_valid == infinity_lft);
// Check expected preferred and valid lifetimes.
EXPECT_EQ(exp_preferred, lease->preferred_lft_);
Lease6Collection
AllocEngine6Test::renewTest(AllocEngine& engine, const Pool6Ptr& pool,
AllocEngine::HintContainer& hints,
- bool in_pool) {
+ bool in_pool, bool is_static) {
Lease::Type type = pool->getType();
uint8_t expected_len = pool->getLength();
for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) {
// Do all checks on the lease
- checkLease6(duid_, *it, type, expected_len, in_pool, in_pool);
+ checkLease6(duid_, *it, type, expected_len,
+ in_pool, in_pool, is_static);
// Check that context has been updated with allocated addresses or
// prefixes.
/// @param exp_type expected lease type
/// @param exp_pd_len expected prefix length
/// @param expected_in_subnet whether the lease is expected to be in subnet
- /// @param expected_in_pool whether the lease is expected to be in dynamic
+ /// @param expected_in_pool whether the lease is expected to be in pool
+ /// @param expected_static whether the lease is expected to be static
void checkLease6(const DuidPtr& duid, const Lease6Ptr& lease,
Lease::Type exp_type, uint8_t exp_pd_len = 128,
bool expected_in_subnet = true,
- bool expected_in_pool = true) {
+ bool expected_in_pool = true,
+ bool expected_static = false) {
// that is belongs to the right subnet
EXPECT_EQ(lease->subnet_id_, subnet_->getID());
// that it have proper parameters
EXPECT_EQ(exp_type, lease->type_);
EXPECT_EQ(iaid_, lease->iaid_);
- if (subnet_->getValid().getMin() == subnet_->getValid().getMax()) {
+ if (expected_static) {
+ EXPECT_EQ(0xffffffff, lease->valid_lft_);
+ } else if (subnet_->getValid().getMin() == subnet_->getValid().getMax()) {
EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
} else {
EXPECT_LE(subnet_->getValid().getMin(), lease->valid_lft_);
EXPECT_GE(subnet_->getValid().getMax(), lease->valid_lft_);
}
- if (subnet_->getPreferred().getMin() == subnet_->getPreferred().getMax()) {
+ if (expected_static) {
+ EXPECT_EQ(0xffffffff, lease->preferred_lft_);
+ } else if (subnet_->getPreferred().getMin() == subnet_->getPreferred().getMax()) {
EXPECT_EQ(subnet_->getPreferred(), lease->preferred_lft_);
} else {
EXPECT_LE(subnet_->getPreferred().getMin(), lease->preferred_lft_);
/// @param pool pool from which the lease will be allocated from
/// @param hints address to be used as a hint
/// @param in_pool specifies whether the lease is expected to be in pool
+ /// @param is_static specifies whether the lease is expected to be static
/// @return allocated lease(s) (may be empty)
Lease6Collection renewTest(AllocEngine& engine, const Pool6Ptr& pool,
AllocEngine::HintContainer& hints,
- bool in_pool = true);
+ bool in_pool = true,
+ bool is_static = false);
/// @brief Checks if the address allocation with a hint that is in range,
/// in pool, but is currently used, can succeed
/// @brief checks if Lease4 matches expected configuration
///
/// @param lease lease to be checked
- void checkLease4(const Lease4Ptr& lease) {
+ /// @param expected_static whether the lease is expected to be static
+ void checkLease4(const Lease4Ptr& lease, bool expected_static = false) {
// Check that is belongs to the right subnet
EXPECT_EQ(lease->subnet_id_, subnet_->getID());
EXPECT_TRUE(subnet_->inRange(lease->addr_));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, lease->addr_));
// Check that it has proper parameters
- if (subnet_->getValid().getMin() == subnet_->getValid().getMax()) {
+ if (expected_static) {
+ EXPECT_EQ(0xffffffff, lease->valid_lft_);
+ } else if (subnet_->getValid().getMin() == subnet_->getValid().getMax()) {
EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
} else {
EXPECT_LE(subnet_->getValid().getMin(), lease->valid_lft_);