checkClientId(offer, clientid);
}
+// This test verifies that incoming DISCOVER can reuse an existing lease.
+TEST_F(Dhcpv4SrvTest, DiscoverReuse) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ boost::scoped_ptr<NakedDhcpv4Srv> srv;
+ ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
+
+ // Enable lease reuse.
+ subnet_->setCacheThreshold(.1);
+
+ const IOAddress addr("192.0.2.106");
+ const uint32_t temp_valid = subnet_->getValid();
+ const int delta = 100;
+ const time_t temp_timestamp = time(NULL) - delta;
+
+ // Generate client-id also sets client_id_ member
+ OptionPtr clientid = generateClientId();
+
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
+
+ // let's create a lease and put it in the LeaseMgr
+ uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
+ HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
+ Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
+ &client_id_->getDuid()[0], client_id_->getDuid().size(),
+ temp_valid, temp_timestamp, subnet_->getID()));
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
+
+ // Check that the lease is really in the database
+ Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
+ ASSERT_TRUE(l);
+
+ // Check that preferred, valid and cltt really set.
+ // Constructed lease looks as if it was assigned 10 seconds ago
+ EXPECT_EQ(l->valid_lft_, temp_valid);
+ EXPECT_EQ(l->cltt_, temp_timestamp);
+
+ // Let's create a DISCOVER
+ Pkt4Ptr dis = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 1234));
+ dis->setRemoteAddr(IOAddress(addr));
+ dis->addOption(clientid);
+ dis->setIface("eth0");
+ dis->setIndex(ETH0_INDEX);
+ dis->setHWAddr(hwaddr2);
+
+ // Pass it to the server and get an offer
+ Pkt4Ptr offer = srv->processDiscover(dis);
+
+ // Check if we get response at all
+ checkResponse(offer, DHCPOFFER, 1234);
+
+ // Check valid lifetime (temp_valid - age)
+ OptionUint32Ptr opt = boost::dynamic_pointer_cast<
+ OptionUint32>(offer->getOption(DHO_DHCP_LEASE_TIME));
+ ASSERT_TRUE(opt);
+ EXPECT_GE(subnet_->getValid() - delta, opt->getValue());
+ EXPECT_LE(subnet_->getValid() - delta - 10, opt->getValue());
+
+ // Check address
+ EXPECT_EQ(addr, offer->getYiaddr());
+
+ // Check T1
+ opt = boost::dynamic_pointer_cast<
+ OptionUint32>(offer->getOption(DHO_DHCP_RENEWAL_TIME));
+ ASSERT_TRUE(opt);
+ EXPECT_EQ(opt->getValue(), subnet_->getT1());
+
+ // Check T2
+ opt = boost::dynamic_pointer_cast<
+ OptionUint32>(offer->getOption(DHO_DHCP_REBINDING_TIME));
+ ASSERT_TRUE(opt);
+ EXPECT_EQ(opt->getValue(), subnet_->getT2());
+
+ // Check identifiers
+ checkServerId(offer, srv->getServerID());
+ checkClientId(offer, clientid);
+}
+
// Check that option 58 and 59 are not included if they are not specified.
TEST_F(Dhcpv4SrvTest, RequestNoTimers) {
IfaceMgrTestConfig test_config(true);
} // end of Renew*Lifetime
+// This test verifies that incoming RENEW can reuse an existing lease.
+TEST_F(Dhcpv4SrvTest, RenewReuse) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ boost::scoped_ptr<NakedDhcpv4Srv> srv;
+ ASSERT_NO_THROW(srv.reset(new NakedDhcpv4Srv(0)));
+
+ // Enable lease reuse.
+ subnet_->setCacheThreshold(.1);
+
+ const IOAddress addr("192.0.2.106");
+ const uint32_t temp_valid = subnet_->getValid();
+ const int delta = 100;
+ const time_t temp_timestamp = time(NULL) - delta;
+
+ // Generate client-id also sets client_id_ member
+ OptionPtr clientid = generateClientId();
+
+ // Check that the address we are about to use is indeed in pool
+ ASSERT_TRUE(subnet_->inPool(Lease::TYPE_V4, addr));
+
+ // let's create a lease and put it in the LeaseMgr
+ uint8_t hwaddr2_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
+ HWAddrPtr hwaddr2(new HWAddr(hwaddr2_data, sizeof(hwaddr2_data), HTYPE_ETHER));
+ Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2,
+ &client_id_->getDuid()[0], client_id_->getDuid().size(),
+ temp_valid, temp_timestamp, subnet_->getID()));
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
+
+ // Check that the lease is really in the database
+ Lease4Ptr l = LeaseMgrFactory::instance().getLease4(addr);
+ ASSERT_TRUE(l);
+
+ // Check that preferred, valid and cltt really set.
+ // Constructed lease looks as if it was assigned 10 seconds ago
+ EXPECT_EQ(l->valid_lft_, temp_valid);
+ EXPECT_EQ(l->cltt_, temp_timestamp);
+
+ // Let's create a RENEW
+ Pkt4Ptr req = Pkt4Ptr(new Pkt4(DHCPREQUEST, 1234));
+ req->setRemoteAddr(IOAddress(addr));
+ req->setYiaddr(addr);
+ req->setCiaddr(addr); // client's address
+ req->setIface("eth0");
+ req->setIndex(ETH0_INDEX);
+
+ req->addOption(clientid);
+ req->setHWAddr(hwaddr2);
+
+ // Pass it to the server and hope for a REPLY
+ Pkt4Ptr ack = srv->processRequest(req);
+
+ // Check if we get response at all
+ checkResponse(ack, DHCPACK, 1234);
+
+ // Check valid lifetime (temp_valid - age)
+ OptionUint32Ptr opt = boost::dynamic_pointer_cast<
+ OptionUint32>(ack->getOption(DHO_DHCP_LEASE_TIME));
+ ASSERT_TRUE(opt);
+ EXPECT_GE(subnet_->getValid() - delta, opt->getValue());
+ EXPECT_LE(subnet_->getValid() - delta - 10, opt->getValue());
+
+ // Check address
+ EXPECT_EQ(addr, ack->getYiaddr());
+
+ // Check T1
+ opt = boost::dynamic_pointer_cast<
+ OptionUint32>(ack->getOption(DHO_DHCP_RENEWAL_TIME));
+ ASSERT_TRUE(opt);
+ EXPECT_EQ(opt->getValue(), subnet_->getT1());
+
+ // Check T2
+ opt = boost::dynamic_pointer_cast<
+ OptionUint32>(ack->getOption(DHO_DHCP_REBINDING_TIME));
+ ASSERT_TRUE(opt);
+ EXPECT_EQ(opt->getValue(), subnet_->getT2());
+
+ // Check identifiers
+ checkServerId(ack, srv->getServerID());
+ checkClientId(ack, clientid);
+
+ // Check that the lease is really in the database
+ Lease4Ptr lease = checkLease(ack, clientid, req->getHWAddr(), addr);
+ ASSERT_TRUE(lease);
+
+ // Check that the lease was not updated
+ EXPECT_EQ(temp_timestamp, lease->cltt_);
+}
+
// This test verifies that the logic which matches server identifier in the
// received message with server identifiers used by a server works correctly:
// - a message with no server identifier is accepted,
checkCalloutHandleReset(client.getContext().query_);
}
+// This test verifies that the callout installed on the leases4_committed hook
+// point is executed as a result of DHCPREQUEST message sent to reuse an
+// an existing lease.
+TEST_F(HooksDhcpv4SrvTest, leases4CommittedReuse) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases4_committed", leases4_committed_callout));
+
+
+ // Modify the subnet to reuse leases.
+ subnet_->setCacheThreshold(.25);
+
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ client.setIfaceName("eth1");
+ client.setIfaceIndex(ETH1_INDEX);
+ ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<IOAddress>(new IOAddress("192.0.2.100"))));
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases4_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query4");
+ expected_argument_names.push_back("deleted_leases4");
+ expected_argument_names.push_back("leases4");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be returned.
+ ASSERT_TRUE(callback_lease4_);
+ EXPECT_EQ("192.0.2.100", callback_lease4_->addr_.toText());
+
+ // Deleted lease must not be present, because it is a new allocation.
+ EXPECT_FALSE(callback_deleted_lease4_);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client.getContext().query_);
+
+ resetCalloutBuffers();
+
+ // Renew the lease and make sure that the callout has been executed.
+ client.setState(Dhcp4Client::RENEWING);
+ ASSERT_NO_THROW(client.doRequest());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases4_committed", callback_name_);
+
+ // Renewed lease should not be present because it was renewed.
+ EXPECT_FALSE(callback_lease4_);
+
+ // Deleted lease must not be present, because it renews the same address.
+ EXPECT_FALSE(callback_deleted_lease4_);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Check if the callout handle state was reset after the callout.
+ checkCalloutHandleReset(client.getContext().query_);
+}
+
// This test verifies that it is possible to park a packet as a result of
// the leases4_committed callouts.
TEST_F(HooksDhcpv4SrvTest, leases4CommittedParkRequests) {
lease->hostname_ = ctx.hostname_;
// Add(update) the extended information on the lease.
- updateLease4ExtendedInfo(lease, ctx);
+ static_cast<void>(updateLease4ExtendedInfo(lease, ctx));
// Let's execute all callouts registered for lease4_select
if (ctx.callout_handle_ &&
ctx.old_lease_.reset(new Lease4(*old_values));
// Update the lease with the information from the context.
- updateLease4Information(lease, ctx);
+ // If there was no significant changes, try reuse.
+ if (!updateLease4Information(lease, ctx)) {
+ setLeaseRemainingLife(lease, ctx);
+ }
if (!ctx.fake_allocation_) {
// If the lease is expired we have to reclaim it before
/// DROP status does not make sense here.
}
- if (!ctx.fake_allocation_ && !skip) {
+ if (!ctx.fake_allocation_ && !skip && (lease->remaining_valid_lft_ == 0)) {
// for REQUEST we do update the lease
LeaseMgrFactory::instance().updateLease4(lease);
expired->state_ = Lease::STATE_DEFAULT;
}
- updateLease4Information(expired, ctx);
+ static_cast<void>(updateLease4Information(expired, ctx));
LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE_DETAIL_DATA,
ALLOC_ENGINE_V4_REUSE_EXPIRED_LEASE_DATA)
return (new_lease);
}
-void
+bool
AllocEngine::updateLease4Information(const Lease4Ptr& lease,
AllocEngine::ClientContext4& ctx) const {
- lease->subnet_id_ = ctx.subnet_->getID();
- lease->hwaddr_ = ctx.hwaddr_;
- lease->client_id_ = ctx.subnet_->getMatchClientId() ? ctx.clientid_ : ClientIdPtr();
+ bool changed = false;
+ if (lease->subnet_id_ != ctx.subnet_->getID()) {
+ changed = true;
+ lease->subnet_id_ = ctx.subnet_->getID();
+ }
+ if ((!ctx.hwaddr_ && lease->hwaddr_) ||
+ (ctx.hwaddr_ &&
+ (!lease->hwaddr_ || (*ctx.hwaddr_ != *lease->hwaddr_)))) {
+ changed = true;
+ lease->hwaddr_ = ctx.hwaddr_;
+ }
+ if (ctx.subnet_->getMatchClientId() && ctx.clientid_) {
+ if (!lease->client_id_ || (*ctx.clientid_ != *lease->client_id_)) {
+ changed = true;
+ lease->client_id_ = ctx.clientid_;
+ }
+ } else if (lease->client_id_) {
+ changed = true;
+ lease->client_id_ = ClientIdPtr();
+ }
lease->cltt_ = time(NULL);
if (ctx.query_->inClass("BOOTP")) {
// BOOTP uses infinite valid lifetime.
lease->valid_lft_ = ctx.subnet_->getValid();
}
}
+ // Reduced valid lifetime is a significant change.
+ if (lease->valid_lft_ < lease->current_valid_lft_) {
+ changed = true;
+ }
- lease->fqdn_fwd_ = ctx.fwd_dns_update_;
- lease->fqdn_rev_ = ctx.rev_dns_update_;
- lease->hostname_ = ctx.hostname_;
+ if ((lease->fqdn_fwd_ != ctx.fwd_dns_update_) ||
+ (lease->fqdn_rev_ != ctx.rev_dns_update_) ||
+ (lease->hostname_ != ctx.hostname_)) {
+ changed = true;
+ lease->fqdn_fwd_ = ctx.fwd_dns_update_;
+ lease->fqdn_rev_ = ctx.rev_dns_update_;
+ lease->hostname_ = ctx.hostname_;
+ }
// Add(update) the extended information on the lease.
- updateLease4ExtendedInfo(lease, ctx);
+ if (updateLease4ExtendedInfo(lease, ctx)) {
+ changed = true;
+ }
+
+ return (changed);
}
-void
+bool
AllocEngine::updateLease4ExtendedInfo(const Lease4Ptr& lease,
const AllocEngine::ClientContext4& ctx) const {
+ bool changed = false;
+
// If storage is not enabled then punt.
if (!ctx.subnet_->getStoreExtendedInfo()) {
- return;
+ return (changed);
}
// Look for relay agent information option (option 82)
OptionPtr rai = ctx.query_->getOption(DHO_DHCP_AGENT_OPTIONS);
if (!rai) {
// Pkt4 doesn't have it, so nothing to store (or update).
- return;
+ return (changed);
}
// Create a StringElement with the hex string for relay-agent-info.
}
// Add/replace the extended info entry.
- user_context->set("ISC", extended_info);
+ ConstElementPtr old_extended_info = user_context->get("ISC");
+ if (!old_extended_info || (*old_extended_info != *extended_info)) {
+ changed = true;
+ user_context->set("ISC", extended_info);
+ }
// Update the lease's user_context.
lease->setContext(user_context);
+
+ return (changed);
}
-void
+bool
AllocEngine::updateLease6ExtendedInfo(const Lease6Ptr& lease,
const AllocEngine::ClientContext6& ctx) const {
+ bool changed = false;
// If storage is not enabled then punt.
if (!ctx.subnet_->getStoreExtendedInfo()) {
- return;
+ return (changed);
}
// If we do not have relay information, then punt.
if (ctx.query_->relay_info_.empty()) {
- return;
+ return (changed);
}
// We need to convert the vector of RelayInfo instances in
}
// Add/replace the extended info entry.
- user_context->set("ISC", extended_info);
+ ConstElementPtr old_extended_info = user_context->get("ISC");
+ if (!old_extended_info || (*old_extended_info != *extended_info)) {
+ changed = true;
+ user_context->set("ISC", extended_info);
+ }
// Update the lease's user_context.
lease->setContext(user_context);
+
+ return (changed);
}
void
if (!subnet) {
return;
}
+ if (lease->state_ != Lease::STATE_DEFAULT) {
+ return;
+ }
// Always reuse infinite lifetime leases.
if (lease->valid_lft_ == Lease::INFINITY_LFT) {
}
// Refuse time not going forward.
- if (lease->cltt_ >= lease->current_cltt_) {
+ if (lease->cltt_ < lease->current_cltt_) {
return;
}
- uint32_t age = lease->current_cltt_ - lease->cltt_;
+ uint32_t age = lease->cltt_ - lease->current_cltt_;
// Already expired.
if (age >= lease->current_valid_lft_) {
return;
}
}
+ // No cache.
+ if (max_age == 0) {
+ return;
+ }
+
// Seems to be reusable.
lease->remaining_valid_lft_ = lease->current_valid_lft_ - age;
}
if (!subnet) {
return;
}
+ if (lease->state_ != Lease::STATE_DEFAULT) {
+ return;
+ }
// Refuse time not going forward.
- if (lease->cltt_ >= lease->current_cltt_) {
+ if (lease->cltt_ < lease->current_cltt_) {
return;
}
- uint32_t age = lease->current_cltt_ - lease->cltt_;
+ uint32_t age = lease->cltt_ - lease->current_cltt_;
// Already expired.
if (age >= lease->current_valid_lft_) {
return;
}
}
+ // No cache.
+ if (max_age == 0) {
+ return;
+ }
+
// Seems to be reusable.
if ((lease->remaining_preferred_lft_ == Lease::INFINITY_LFT) ||
(lease->remaining_preferred_lft_ == 0)) {
/// @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 updateLease4Information(const Lease4Ptr& lease,
+ /// @return True if there was a significant (e.g. other than cltt) change,
+ /// false otherwise.
+ bool updateLease4Information(const Lease4Ptr& lease,
ClientContext4& ctx) const;
protected:
/// @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,
+ /// @return True if there was a significant (e.g. other than cltt) change,
+ /// false otherwise.
+ bool updateLease4ExtendedInfo(const Lease4Ptr& lease,
const ClientContext4& ctx) const;
/// @brief Stores additional client query parameters on a V6 lease
/// @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,
+ /// @return True if there was a significant (e.g. other than cltt) change,
+ /// false otherwise.
+ bool updateLease6ExtendedInfo(const Lease6Ptr& lease,
const ClientContext6& ctx) const;
private:
std::string orig_context_json_; // user context the lease begins with
std::string rai_data_; // RAI option the client packet contains
std::string exp_context_json_; // expected user context on the lease
+ bool exp_ret; // expected returned value
};
// Test scenarios.
"no context, no rai",
"",
"",
- ""
+ "",
+ false
},
{
"some original context, no rai",
"{\"foo\": 123}",
"",
- "{\"foo\": 123}"
+ "{\"foo\": 123}",
+ false
},
{
"no original context, rai",
"",
"0x52050104aabbccdd",
"{ \"ISC\": { \"relay-agent-info\": \"0x52050104AABBCCDD\" } }",
+ true
},
{
"some original context, rai",
"{\"foo\": 123}",
"0x52050104aabbccdd",
- "{ \"ISC\": { \"relay-agent-info\": \"0x52050104AABBCCDD\" }, \"foo\": 123 }"
+ "{ \"ISC\": { \"relay-agent-info\": \"0x52050104AABBCCDD\" }, \"foo\": 123 }",
+ true
},
{
"original rai context, no rai",
"{ \"ISC\": { \"relay-agent-info\": \"0x52050104AABBCCDD\" } }",
"",
"{ \"ISC\": { \"relay-agent-info\": \"0x52050104AABBCCDD\" } }",
+ false
},
{
"original rai context, different rai",
"{ \"ISC\": { \"relay-agent-info\": \"0x52050104AABBCCDD\" } }",
"0x52050104ddeeffaa",
"{ \"ISC\": { \"relay-agent-info\": \"0x52050104DDEEFFAA\" } }",
+ true
}};
// Create the allocation engine, context and lease.
}
// Call AllocEngine::updateLease4ExtendeInfo().
- ASSERT_NO_THROW_LOG(engine.callUpdateLease4ExtendedInfo(lease, ctx));
+ bool ret = false;
+ ASSERT_NO_THROW_LOG(ret = engine.callUpdateLease4ExtendedInfo(lease, ctx));
+ ASSERT_EQ(scenario.exp_ret, ret);
// Verify the lease has the expected user context content.
if (!exp_context) {
}
}
+// This test checks if a lease can be reused in DHCPDISCOVER (fake allocation)
+// using cache threshold.
+TEST_F(AllocEngine4Test, discoverCacheThreshold4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ // Set valid lifetime to 500.
+ subnet_->setValid(500);
+
+ // Set the threshold to 25%.
+ subnet_->setCacheThreshold(.25);
+
+ IOAddress addr("192.0.2.105");
+ time_t now = time(NULL) - 100; // Allocated 100 seconds ago.
+ Lease4Ptr lease(new Lease4(addr, hwaddr_, clientid_,
+ 500, now, subnet_->getID()));
+ ASSERT_FALSE(lease->expired());
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Create a context for fake allocation.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, addr,
+ false, false, "", true);
+
+ ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234));
+ lease = engine->allocateLease4(ctx);
+ // Check that we got that single lease.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // The lease was reused.
+ time_t age = lease->cltt_ - now;
+ EXPECT_GE(age, 100);
+ EXPECT_LE(age, 110);
+ EXPECT_EQ(500 - age, lease->remaining_valid_lft_);
+
+ // Check other lease parameters.
+ EXPECT_EQ(lease->subnet_id_, subnet_->getID());
+ ASSERT_TRUE(lease->client_id_);
+ EXPECT_TRUE(*lease->client_id_ == *clientid_);
+ ASSERT_TRUE(lease->hwaddr_);
+ EXPECT_TRUE(*lease->hwaddr_ == *hwaddr_);
+}
+
+// This test checks if a lease can be reused in DHCPREQUEST (real allocation)
+// using cache threshold.
+TEST_F(AllocEngine4Test, requestCacheThreshold4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ // Set valid lifetime to 500.
+ subnet_->setValid(500);
+
+ // Set the threshold to 25%.
+ subnet_->setCacheThreshold(.25);
+
+ IOAddress addr("192.0.2.105");
+ time_t now = time(NULL) - 100; // Allocated 100 seconds ago.
+ Lease4Ptr lease(new Lease4(addr, hwaddr_, clientid_,
+ 500, now, subnet_->getID()));
+ ASSERT_FALSE(lease->expired());
+ // Copy the lease, so as it can be compared with.
+ Lease4Ptr original_lease(new Lease4(*lease));
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Create a context for real allocation.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, addr,
+ false, false, "", false);
+
+ ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+ lease = engine->allocateLease4(ctx);
+ // Check that we got that single lease.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // The lease was reused.
+ time_t age = lease->cltt_ - now;
+ EXPECT_GE(age, 100);
+ EXPECT_LE(age, 110);
+ EXPECT_EQ(500 - age, lease->remaining_valid_lft_);
+
+ // Check other lease parameters.
+ EXPECT_EQ(lease->subnet_id_, subnet_->getID());
+ ASSERT_TRUE(lease->client_id_);
+ EXPECT_TRUE(*lease->client_id_ == *clientid_);
+ ASSERT_TRUE(lease->hwaddr_);
+ EXPECT_TRUE(*lease->hwaddr_ == *hwaddr_);
+
+ // Check the lease was not updated in the database.
+ Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
+ ASSERT_TRUE(from_mgr);
+
+ detailCompareLease(original_lease, from_mgr);
+}
+
+/// We proved that there is no different from the "cache" feature between
+/// discovers and request at the exception of the lease database update.
+
+// This test checks if a lease can be reused in DHCPDISCOVER (fake allocation)
+// using cache max age.
+TEST_F(AllocEngine4Test, discoverCacheMaxAge4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ // Set valid lifetime to 500.
+ subnet_->setValid(500);
+
+ // Set the max age to 200.
+ subnet_->setCacheMaxAge(200);
+
+ IOAddress addr("192.0.2.105");
+ time_t now = time(NULL) - 100; // Allocated 100 seconds ago.
+ Lease4Ptr lease(new Lease4(addr, hwaddr_, clientid_,
+ 500, now, subnet_->getID()));
+ ASSERT_FALSE(lease->expired());
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Create a context for fake allocation.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, addr,
+ false, false, "", true);
+
+ ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234));
+ lease = engine->allocateLease4(ctx);
+ // Check that we got that single lease.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // The lease was reused.
+ time_t age = lease->cltt_ - now;
+ EXPECT_GE(age, 100);
+ EXPECT_LE(age, 110);
+ EXPECT_EQ(500 - age, lease->remaining_valid_lft_);
+
+ // Check other lease parameters.
+ EXPECT_EQ(lease->subnet_id_, subnet_->getID());
+ ASSERT_TRUE(lease->client_id_);
+ EXPECT_TRUE(*lease->client_id_ == *clientid_);
+ ASSERT_TRUE(lease->hwaddr_);
+ EXPECT_TRUE(*lease->hwaddr_ == *hwaddr_);
+}
+
+// This test checks if a lease can be reused in DHCPREQUEST (real allocation)
+// using both cache threshold and max age.
+TEST_F(AllocEngine4Test, requestCacheBoth4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ // Set valid lifetime to 500.
+ subnet_->setValid(500);
+
+ // Set the threshold to 25%.
+ subnet_->setCacheThreshold(.25);
+
+ // Set the max age to 200.
+ subnet_->setCacheMaxAge(200);
+
+ IOAddress addr("192.0.2.105");
+ time_t now = time(NULL) - 100; // Allocated 100 seconds ago.
+ Lease4Ptr lease(new Lease4(addr, hwaddr_, clientid_,
+ 500, now, subnet_->getID()));
+ ASSERT_FALSE(lease->expired());
+ // Copy the lease, so as it can be compared with.
+ Lease4Ptr original_lease(new Lease4(*lease));
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Create a context for real allocation.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, addr,
+ false, false, "", false);
+
+ ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+ lease = engine->allocateLease4(ctx);
+ // Check that we got that single lease.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // The lease was reused.
+ time_t age = lease->cltt_ - now;
+ EXPECT_GE(age, 100);
+ EXPECT_LE(age, 110);
+ EXPECT_EQ(500 - age, lease->remaining_valid_lft_);
+
+ // Check other lease parameters.
+ EXPECT_EQ(lease->subnet_id_, subnet_->getID());
+ ASSERT_TRUE(lease->client_id_);
+ EXPECT_TRUE(*lease->client_id_ == *clientid_);
+ ASSERT_TRUE(lease->hwaddr_);
+ EXPECT_TRUE(*lease->hwaddr_ == *hwaddr_);
+
+ // Check the lease was not updated in the database.
+ Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
+ ASSERT_TRUE(from_mgr);
+
+ detailCompareLease(original_lease, from_mgr);
+}
+
+// This test checks if a lease can't be reused in DHCPDISCOVER (fake allocation)
+// using too small cache threshold.
+TEST_F(AllocEngine4Test, discoverCacheBadThreshold4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ // Set valid lifetime to 500.
+ subnet_->setValid(500);
+
+ // Set the threshold to 10%.
+ subnet_->setCacheThreshold(.1);
+
+ IOAddress addr("192.0.2.105");
+ time_t now = time(NULL) - 100; // Allocated 100 seconds ago.
+ Lease4Ptr lease(new Lease4(addr, hwaddr_, clientid_,
+ 500, now, subnet_->getID()));
+ ASSERT_FALSE(lease->expired());
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Create a context for fake allocation.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, addr,
+ false, false, "", true);
+
+ ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234));
+ lease = engine->allocateLease4(ctx);
+ // Check that we got that single lease.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // The lease was not reused.
+ EXPECT_EQ(0, lease->remaining_valid_lft_);
+}
+
+// This test checks if a lease can't be reused in DHCPREQUEST (real allocation)
+// using too small cache max age.
+TEST_F(AllocEngine4Test, requestCacheBadMaxAge4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ // Set valid lifetime to 500.
+ subnet_->setValid(500);
+
+ // Set the max age to 50.
+ subnet_->setCacheMaxAge(50);
+
+ IOAddress addr("192.0.2.105");
+ time_t now = time(NULL) - 100; // Allocated 100 seconds ago.
+ Lease4Ptr lease(new Lease4(addr, hwaddr_, clientid_,
+ 500, now, subnet_->getID()));
+ ASSERT_FALSE(lease->expired());
+
+ // Create a context for real allocation.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, addr,
+ false, false, "", false);
+
+ ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+ lease = engine->allocateLease4(ctx);
+ // Check that we got that single lease.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // The lease was not reused.
+ EXPECT_EQ(0, lease->remaining_valid_lft_);
+
+ // Check the lease was updated in the database.
+ Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
+ ASSERT_TRUE(from_mgr);
+
+ detailCompareLease(lease, from_mgr);
+}
+
+// This test checks if a lease can't be reused in DHCPDISCOVER (fake allocation)
+// when the valid lifetime was reduced.
+TEST_F(AllocEngine4Test, discoverCacheReducedValid4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ // Set valid lifetime to 200.
+ subnet_->setValid(200);
+
+ // Set the threshold to 10%.
+ subnet_->setCacheThreshold(.1);
+
+ IOAddress addr("192.0.2.105");
+ time_t now = time(NULL) - 100; // Allocated 100 seconds ago.
+ Lease4Ptr lease(new Lease4(addr, hwaddr_, clientid_,
+ 500, now, subnet_->getID()));
+ ASSERT_FALSE(lease->expired());
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Create a context for fake allocation.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, addr,
+ false, false, "", true);
+
+ ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234));
+ lease = engine->allocateLease4(ctx);
+ // Check that we got that single lease.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // The lease was not reused.
+ EXPECT_EQ(0, lease->remaining_valid_lft_);
+}
+
+// This test checks if a lease can't be reused in DHCPREQUEST (real allocation)
+// when DDNS parameter changed.
+TEST_F(AllocEngine4Test, requestCacheFwdDDNS4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ // Set valid lifetime to 500.
+ subnet_->setValid(500);
+
+ // Set the max age to 200.
+ subnet_->setCacheMaxAge(200);
+
+ IOAddress addr("192.0.2.105");
+ time_t now = time(NULL) - 100; // Allocated 100 seconds ago.
+ Lease4Ptr lease(new Lease4(addr, hwaddr_, clientid_,
+ 500, now, subnet_->getID()));
+ ASSERT_FALSE(lease->expired());
+
+ // Create a context for real allocation with fwd_dns_update changed.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, addr,
+ true, false, "", false);
+
+ ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+ lease = engine->allocateLease4(ctx);
+ // Check that we got that single lease.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // The lease was not reused.
+ EXPECT_EQ(0, lease->remaining_valid_lft_);
+
+ // Check the lease was updated in the database.
+ Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
+ ASSERT_TRUE(from_mgr);
+
+ detailCompareLease(lease, from_mgr);
+}
+
+// This test checks if a lease can't be reused in DHCPDISCOVER (fake allocation)
+// when DDNS parameter changed.
+TEST_F(AllocEngine4Test, discoverCacheRevDDNS4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ // Set valid lifetime to 500.
+ subnet_->setValid(500);
+
+ // Set the threshold to 10%.
+ subnet_->setCacheThreshold(.1);
+
+ IOAddress addr("192.0.2.105");
+ time_t now = time(NULL) - 100; // Allocated 100 seconds ago.
+ Lease4Ptr lease(new Lease4(addr, hwaddr_, clientid_,
+ 500, now, subnet_->getID()));
+ ASSERT_FALSE(lease->expired());
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+ // Create a context for fake allocation with rev_dns_update changed.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, addr,
+ false, true, "", true);
+
+ ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234));
+ lease = engine->allocateLease4(ctx);
+ // Check that we got that single lease.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // The lease was not reused.
+ EXPECT_EQ(0, lease->remaining_valid_lft_);
+}
+
+// This test checks if a lease can't be reused in DHCPREQUEST (real allocation)
+// when hostname changed.
+TEST_F(AllocEngine4Test, requestCacheHostname4) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+ 0, false)));
+ ASSERT_TRUE(engine);
+
+ // Set valid lifetime to 500.
+ subnet_->setValid(500);
+
+ // Set the max age to 200.
+ subnet_->setCacheMaxAge(200);
+
+ IOAddress addr("192.0.2.105");
+ time_t now = time(NULL) - 100; // Allocated 100 seconds ago.
+ Lease4Ptr lease(new Lease4(addr, hwaddr_, clientid_,
+ 500, now, subnet_->getID(),
+ false, false, "foo"));
+ ASSERT_FALSE(lease->expired());
+
+ // Create a context for real allocation with fwd_dns_update changed.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, addr,
+ false, false, "bar", false);
+
+ ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+ lease = engine->allocateLease4(ctx);
+ // Check that we got that single lease.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(addr, lease->addr_);
+
+ // The lease was not reused.
+ EXPECT_EQ(0, lease->remaining_valid_lft_);
+ EXPECT_EQ("bar", lease->hostname_);
+
+ // Check the lease was updated in the database.
+ Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
+ ASSERT_TRUE(from_mgr);
+
+ detailCompareLease(lease, from_mgr);
+}
+
} // namespace test
} // namespace dhcp
} // namespace isc
std::string orig_context_json_; // user context the lease begins with
std::vector<Pkt6::RelayInfo> relays_; // vector of relays from pkt
std::string exp_context_json_; // expected user context on the lease
+ bool exp_ret; // expected returned value
};
// Test scenarios.
"no context, no relay",
"",
{},
- ""
+ "",
+ false
},
{
"some original context, no relay",
"{\"foo\": 123}",
{},
- "{\"foo\": 123}"
+ "{\"foo\": 123}",
+ false
},
{
"no original context, one relay",
"",
{ relay1_ },
"{ \"ISC\": { \"relays\": [ { \"hop\": 33, \"link\": \"2001:db8::1\","
- " \"options\": \"0x00C800080102030405060708\", \"peer\": \"2001:db8::2\" } ] } }"
+ " \"options\": \"0x00C800080102030405060708\", \"peer\": \"2001:db8::2\" } ] } }",
+ true
},
{
"some original context, one relay",
{ relay1_ },
"{ \"ISC\": { \"relays\": [ { \"hop\": 33, \"link\": \"2001:db8::1\","
" \"options\": \"0x00C800080102030405060708\", \"peer\": \"2001:db8::2\" } ] },"
- " \"foo\": 123 }"
+ " \"foo\": 123 }",
+ true
},
{
"no original context, two relays",
{ relay1_, relay2_ },
"{ \"ISC\": { \"relays\": [ { \"hop\": 33, \"link\": \"2001:db8::1\","
" \"options\": \"0x00C800080102030405060708\", \"peer\": \"2001:db8::2\" },"
- " {\"hop\": 77, \"link\": \"2001:db8::3\", \"peer\": \"2001:db8::4\" } ] } }"
+ " {\"hop\": 77, \"link\": \"2001:db8::3\", \"peer\": \"2001:db8::4\" } ] } }",
+ true
},
{
"original relay context, no relay",
" \"options\": \"0x00C800080102030405060708\", \"peer\": \"2001:db8::2\" } ] } }",
{},
"{ \"ISC\": { \"relays\": [ { \"hop\": 33, \"link\": \"2001:db8::1\","
- " \"options\": \"0x00C800080102030405060708\", \"peer\": \"2001:db8::2\" } ] } }"
+ " \"options\": \"0x00C800080102030405060708\", \"peer\": \"2001:db8::2\" } ] } }",
+ false
},
{
"original relay context, different relay",
" \"options\": \"0x00C800080102030405060708\", \"peer\": \"2001:db8::2\" } ] } }",
{ relay2_ },
"{ \"ISC\": { \"relays\": [ { \"hop\": 77, \"link\": \"2001:db8::3\","
- " \"peer\": \"2001:db8::4\" } ] } }"
+ " \"peer\": \"2001:db8::4\" } ] } }",
+ true
}};
// Allocate a lease.
ctx.query_->relay_info_ = scenario.relays_;
// Call AllocEngine::updateLease6ExtendeInfo().
- ASSERT_NO_THROW_LOG(engine_.callUpdateLease6ExtendedInfo(lease, ctx));
+ bool ret;
+ ASSERT_NO_THROW_LOG(ret = engine_.callUpdateLease6ExtendedInfo(lease, ctx));
+ ASSERT_EQ(scenario.exp_ret, ret);
// Verify the lease has the expected user context content.
if (!exp_context) {
/// @brief Wrapper method for invoking AllocEngine4::updateLease4ExtendedInfo().
/// @param lease lease to update
/// @param ctx current packet processing context
- void callUpdateLease4ExtendedInfo(const Lease4Ptr& lease,
+ /// @return the changed returned value
+ bool callUpdateLease4ExtendedInfo(const Lease4Ptr& lease,
AllocEngine::ClientContext4& ctx) const {
- updateLease4ExtendedInfo(lease,ctx);
+ return (updateLease4ExtendedInfo(lease, ctx));
}
/// @brief Wrapper method for invoking AllocEngine6::updateLease6ExtendedInfo().
/// @param lease lease to update
/// @param ctx current packet processing context
- void callUpdateLease6ExtendedInfo(const Lease6Ptr& lease,
+ /// @return the changed returned value
+ bool callUpdateLease6ExtendedInfo(const Lease6Ptr& lease,
AllocEngine::ClientContext6& ctx) const {
- updateLease6ExtendedInfo(lease,ctx);
+ return (updateLease6ExtendedInfo(lease, ctx));
}
};
EXPECT_TRUE(*lease->client_id_ == *clientid_);
}
EXPECT_TRUE(*lease->hwaddr_ == *hwaddr_);
+ EXPECT_EQ(0, lease->remaining_valid_lft_);
/// @todo: check cltt
}
///< allocation engine functions.
};
-}; // namespace test
-}; // namespace dhcp
-}; // namespace isc
+} // namespace test
+} // namespace dhcp
+} // namespace isc
#endif