Commit 681def28 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰

[3146] getLease6 renamed to getLeases6(), single lease getLease6() added

parent 95729b09
......@@ -1223,13 +1223,18 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
// will try to honour the hint, but it is just a hint - some other address
// may be used instead. If fake_allocation is set to false, the lease will
// be inserted into the LeaseMgr as well.
Lease6Ptr lease = alloc_engine_->allocateAddress6(subnet, duid,
ia->getIAID(),
hint,
do_fwd, do_rev,
hostname,
fake_allocation,
callout_handle);
Lease6Collection leases = alloc_engine_->allocateAddress6(subnet, duid,
ia->getIAID(),
hint,
do_fwd, do_rev,
hostname,
fake_allocation,
callout_handle);
/// @todo: Handle more than one lease
Lease6Ptr lease;
if (!leases.empty()) {
lease = *leases.begin();
}
// Create IA_NA that we will put in the response.
// Do not use OptionDefinition to create option's instance so
......
......@@ -195,7 +195,7 @@ AllocEngine::AllocEngine(AllocType engine_type, unsigned int attempts)
hook_index_lease6_select_ = Hooks.hook_index_lease6_select_;
}
Lease6Ptr
Lease6Collection
AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
......@@ -222,43 +222,52 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
}
// check if there's existing lease for that subnet/duid/iaid combination.
/// @todo: Make this generic
Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(
Lease6::LEASE_IA_NA, *duid, iaid, subnet->getID());
if (existing) {
// we have a lease already. This is a returning client, probably after
// his reboot.
/// @todo: Make this generic (cover temp. addrs and prefixes)
Lease6Collection existing = LeaseMgrFactory::instance().getLeases6(
Lease6::LEASE_IA_NA, *duid, iaid, subnet->getID());
if (!existing.empty()) {
// we have at least one lease already. This is a returning client,
// probably after his reboot.
return (existing);
}
// check if the hint is in pool and is available
if (subnet->inPool(hint)) {
existing = LeaseMgrFactory::instance().getLease6(Lease6::LEASE_IA_NA,
hint);
if (!existing) {
/// @todo: We support only one hint for now
Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(
Lease6::LEASE_IA_NA, hint);
if (!lease) {
/// @todo: check if the hint is reserved once we have host support
/// implemented
// the hint is valid and not currently used, let's create a lease for it
Lease6Ptr lease = createLease6(subnet, duid, iaid,
hint,
fwd_dns_update,
rev_dns_update, hostname,
callout_handle,
fake_allocation);
/// @todo: We support only one lease per ia for now
lease = createLease6(subnet, duid, iaid, hint, fwd_dns_update,
rev_dns_update, hostname, callout_handle,
fake_allocation);
// It can happen that the lease allocation failed (we could have lost
// the race condition. That means that the hint is lo longer usable and
// we need to continue the regular allocation path.
if (lease) {
return (lease);
/// @todo: We support only one lease per ia for now
Lease6Collection collection;
collection.push_back(lease);
return (collection);
}
} else {
if (existing->expired()) {
return (reuseExpiredLease(existing, subnet, duid, iaid,
if (lease->expired()) {
/// We found a lease and it is expired, so we can reuse it
/// @todo: We support only one lease per ia for now
lease = reuseExpiredLease(lease, subnet, duid, iaid,
fwd_dns_update, rev_dns_update,
hostname, callout_handle,
fake_allocation));
fake_allocation);
Lease6Collection collection;
collection.push_back(lease);
return (collection);
}
}
......@@ -297,7 +306,9 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
hostname,
callout_handle, fake_allocation);
if (lease) {
return (lease);
Lease6Collection collection;
collection.push_back(lease);
return (collection);
}
// Although the address was free just microseconds ago, it may have
......@@ -305,10 +316,13 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
// allocation attempts.
} else {
if (existing->expired()) {
return (reuseExpiredLease(existing, subnet, duid, iaid,
fwd_dns_update, rev_dns_update,
hostname, callout_handle,
fake_allocation));
existing = reuseExpiredLease(existing, subnet, duid, iaid,
fwd_dns_update, rev_dns_update,
hostname, callout_handle,
fake_allocation);
Lease6Collection collection;
collection.push_back(existing);
return (collection);
}
}
......@@ -326,7 +340,7 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
LOG_ERROR(dhcpsrv_logger, DHCPSRV_ADDRESS6_ALLOC_ERROR).arg(e.what());
}
return (Lease6Ptr());
return (Lease6Collection());
}
Lease4Ptr
......
......@@ -295,8 +295,8 @@ protected:
/// @param callout_handle a callout handle (used in hooks). A lease callouts
/// will be executed if this parameter is passed.
///
/// @return Allocated IPv6 lease (or NULL if allocation failed)
Lease6Ptr
/// @return Allocated IPv6 leases (may be empty if allocation failed)
Lease6Collection
allocateAddress6(const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
......
......@@ -130,6 +130,23 @@ std::string LeaseMgr::getParameter(const std::string& name) const {
return (param->second);
}
Lease6Ptr
LeaseMgr::getLease6(Lease6::LeaseType type, const DUID& duid,
uint32_t iaid, SubnetID subnet_id) const {
Lease6Collection col = getLeases6(type, duid, iaid, subnet_id);
if (col.size() > 1) {
isc_throw(MultipleRecords, "More than one lease found for type "
<< static_cast<int>(type) << ", duid "
<< duid.toText() << ", iaid " << iaid
<< " and subnet-id " << subnet_id);
}
if (col.empty()) {
return (Lease6Ptr());
}
return (*col.begin());
}
std::string
Lease6::toText() const {
ostringstream stream;
......
......@@ -551,20 +551,50 @@ public:
/// @param duid client DUID
/// @param iaid IA identifier
///
/// @return smart pointer to the lease (or NULL if a lease is not found)
/// @return Lease collection (may be empty if no lease is found)
virtual Lease6Collection getLease6(Lease6::LeaseType type, const DUID& duid,
uint32_t iaid) const = 0;
/// @brief Returns existing IPv6 lease for a given DUID+IA combination
///
/// There may be more than one address, temp. address or prefix
/// for specified duid/iaid/subnet-id tuple.
///
/// @param type specifies lease type: (NA, TA or PD)
/// @param duid client DUID
/// @param iaid IA identifier
/// @param subnet_id subnet id of the subnet the lease belongs to
///
/// @return smart pointer to the lease (or NULL if a lease is not found)
virtual Lease6Ptr getLease6(Lease6::LeaseType type, const DUID& duid,
uint32_t iaid, SubnetID subnet_id) const = 0;
/// @return Lease collection (may be empty if no lease is found)
virtual Lease6Collection getLeases6(Lease6::LeaseType type, const DUID& duid,
uint32_t iaid, SubnetID subnet_id) const = 0;
/// @brief returns zero or one IPv6 lease for a given duid+iaid+subnet_id
///
/// This function is mostly intended to be used in unit-tests during the
/// transition from single to multi address per IA. It may also be used
/// in other cases where at most one lease is expected in the database.
///
/// It is a wrapper around getLease6(), which returns a collection of
/// leases. That collection can be converted into a single pointer if
/// there are no leases (NULL pointer) or one lease (use that single lease).
/// If there are more leases in the collection, the function will
/// throw MultipleRecords exception.
///
/// Note: This method is not virtual on purpose. It is common for all
/// backends.
///
/// @param type specifies lease type: (NA, TA or PD)
/// @param duid client DUID
/// @param iaid IA identifier
/// @param subnet_id subnet id of the subnet the lease belongs to
///
/// @throw MultipleRecords if there is more than one lease matching
///
/// @return Lease pointer (or NULL if none is found)
Lease6Ptr getLease6(Lease6::LeaseType type, const DUID& duid,
uint32_t iaid, SubnetID subnet_id) const;
/// @brief Updates IPv4 lease.
///
......
......@@ -208,10 +208,10 @@ Memfile_LeaseMgr::getLease6(Lease6::LeaseType /* not used yet */,
return (Lease6Collection());
}
Lease6Ptr
Memfile_LeaseMgr::getLease6(Lease6::LeaseType /* not used yet */,
const DUID& duid, uint32_t iaid,
SubnetID subnet_id) const {
Lease6Collection
Memfile_LeaseMgr::getLeases6(Lease6::LeaseType /* not used yet */,
const DUID& duid, uint32_t iaid,
SubnetID subnet_id) const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID)
.arg(iaid).arg(subnet_id).arg(duid.toText());
......@@ -227,10 +227,14 @@ Memfile_LeaseMgr::getLease6(Lease6::LeaseType /* not used yet */,
idx.find(boost::make_tuple(duid.getDuid(), iaid, subnet_id));
// Lease was not found. Return empty pointer.
if (lease == idx.end()) {
return (Lease6Ptr());
return (Lease6Collection());
}
// Lease was found, return it to the caller.
return (Lease6Ptr(new Lease6(**lease)));
/// @todo: allow multiple leases for a single duid+iaid+subnet_id tuple
Lease6Collection collection;
collection.push_back(Lease6Ptr(new Lease6(**lease)));
return (collection);
}
void
......
......@@ -169,9 +169,9 @@ public:
/// @param iaid IA identifier
/// @param subnet_id identifier of the subnet the lease must belong to
///
/// @return smart pointer to the lease (or NULL if a lease is not found)
virtual Lease6Ptr getLease6(Lease6::LeaseType type, const DUID& duid,
uint32_t iaid, SubnetID subnet_id) const;
/// @return lease collection (may be empty if no lease is found)
virtual Lease6Collection getLeases6(Lease6::LeaseType type, const DUID& duid,
uint32_t iaid, SubnetID subnet_id) const;
/// @brief Updates IPv4 lease.
///
......
......@@ -1719,11 +1719,10 @@ MySqlLeaseMgr::getLease6(Lease6::LeaseType /* type - not used yet */,
return (result);
}
Lease6Ptr
MySqlLeaseMgr::getLease6(Lease6::LeaseType /* type - not used yet */,
const DUID& duid, uint32_t iaid,
SubnetID subnet_id) const {
Lease6Collection
MySqlLeaseMgr::getLeases6(Lease6::LeaseType /* type - not used yet */,
const DUID& duid, uint32_t iaid,
SubnetID subnet_id) const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
DHCPSRV_MYSQL_GET_IAID_SUBID_DUID)
.arg(iaid).arg(subnet_id).arg(duid.toText());
......@@ -1755,7 +1754,11 @@ MySqlLeaseMgr::getLease6(Lease6::LeaseType /* type - not used yet */,
Lease6Ptr result;
getLease(GET_LEASE6_DUID_IAID_SUBID, inbind, result);
return (result);
/// @todo: Implement getting one than more lease at the time
Lease6Collection collection;
collection.push_back(result);
return (collection);
}
// Update lease methods. These comprise common code that handles the actual
......
......@@ -289,7 +289,7 @@ public:
/// @param iaid IA identifier
/// @param subnet_id subnet id of the subnet the lease belongs to
///
/// @return smart pointer to the lease (or NULL if a lease is not found)
/// @return lease collection (may be empty if no lease is found)
///
/// @throw isc::BadValue record retrieved from database had an invalid
/// lease type field.
......@@ -298,8 +298,8 @@ public:
/// programming error.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual Lease6Ptr getLease6(Lease6::LeaseType type, const DUID& duid,
uint32_t iaid, SubnetID subnet_id) const;
virtual Lease6Collection getLeases6(Lease6::LeaseType type, const DUID& duid,
uint32_t iaid, SubnetID subnet_id) const;
/// @brief Updates IPv4 lease.
///
......
......@@ -89,6 +89,24 @@ public:
factory_.create("type=memfile");
}
/// @brief attempts to convert leases collection to a single lease
///
/// This operation makes sense if there is at most one lease in the
/// collection. Otherwise it will throw.
///
/// @param col collection of leases (zero or one leases allowed)
/// @throw MultipleRecords if there is more than one lease
/// @return Lease6 pointer (or NULL if collection was empty)
Lease6Ptr expectOneLease(const Lease6Collection& col) {
if (col.size() > 1) {
isc_throw(MultipleRecords, "More than one lease found in collection");
}
if (col.empty()) {
return (Lease6Ptr());
}
return (*col.begin());
}
/// @brief checks if Lease6 matches expected configuration
///
/// @param lease lease to be checked
......@@ -207,10 +225,10 @@ TEST_F(AllocEngine6Test, simpleAlloc6) {
ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
ASSERT_TRUE(engine);
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress("::"), false,
false, "",
false, CalloutHandlePtr());
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress("::"), false, false, "", false,
CalloutHandlePtr())));
// Check that we got a lease
ASSERT_TRUE(lease);
......@@ -233,10 +251,10 @@ TEST_F(AllocEngine6Test, fakeAlloc6) {
ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
ASSERT_TRUE(engine);
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress("::"), false,
false, "", true,
CalloutHandlePtr());
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress("::"), false, false, "", true,
CalloutHandlePtr())));
// Check that we got a lease
ASSERT_TRUE(lease);
......@@ -257,10 +275,10 @@ TEST_F(AllocEngine6Test, allocWithValidHint6) {
ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
ASSERT_TRUE(engine);
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress("2001:db8:1::15"),
false, false, "",
false, CalloutHandlePtr());
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress("2001:db8:1::15"), false,
false, "", false, CalloutHandlePtr())));
// Check that we got a lease
ASSERT_TRUE(lease);
......@@ -297,10 +315,11 @@ TEST_F(AllocEngine6Test, allocWithUsedHint6) {
// Another client comes in and request an address that is in pool, but
// unfortunately it is used already. The same address must not be allocated
// twice.
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress("2001:db8:1::1f"),
false, false, "",
false, CalloutHandlePtr());
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress("2001:db8:1::1f"), false, false, "",
false, CalloutHandlePtr())));
// Check that we got a lease
ASSERT_TRUE(lease);
......@@ -332,10 +351,11 @@ TEST_F(AllocEngine6Test, allocBogusHint6) {
// Client would like to get a 3000::abc lease, which does not belong to any
// supported lease. Allocation engine should ignore it and carry on
// with the normal allocation
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress("3000::abc"),
false, false, "",
false, CalloutHandlePtr());
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress("3000::abc"), false, false, "",
false, CalloutHandlePtr())));
// Check that we got a lease
ASSERT_TRUE(lease);
......@@ -361,17 +381,16 @@ TEST_F(AllocEngine6Test, allocateAddress6Nulls) {
ASSERT_TRUE(engine);
// Allocations without subnet are not allowed
Lease6Ptr lease = engine->allocateAddress6(Subnet6Ptr(), duid_, iaid_,
IOAddress("::"),
false, false, "", false,
CalloutHandlePtr());
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(
Subnet6Ptr(), duid_, iaid_, IOAddress("::"), false, false,
"", false, CalloutHandlePtr())));
ASSERT_FALSE(lease);
// Allocations without DUID are not allowed either
lease = engine->allocateAddress6(subnet_, DuidPtr(), iaid_,
IOAddress("::"),
false, false, "", false,
CalloutHandlePtr());
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
DuidPtr(), iaid_, IOAddress("::"), false, false, "", false,
CalloutHandlePtr())));
ASSERT_FALSE(lease);
}
......@@ -459,10 +478,10 @@ TEST_F(AllocEngine6Test, smallPool6) {
subnet_->addPool(pool_);
cfg_mgr.addSubnet6(subnet_);
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress("::"),
false, false, "",
false, CalloutHandlePtr());
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress("::"), false, false, "", false,
CalloutHandlePtr())));
// Check that we got that single lease
ASSERT_TRUE(lease);
......@@ -508,10 +527,10 @@ TEST_F(AllocEngine6Test, outOfAddresses6) {
// There is just a single address in the pool and allocated it to someone
// else, so the allocation should fail
Lease6Ptr lease2 = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress("::"),
false, false, "", false,
CalloutHandlePtr());
Lease6Ptr lease2;
EXPECT_NO_THROW(lease2 = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress("::"), false, false, "", false,
CalloutHandlePtr())));
EXPECT_FALSE(lease2);
}
......@@ -544,9 +563,9 @@ TEST_F(AllocEngine6Test, solicitReuseExpiredLease6) {
ASSERT_TRUE(lease->expired());
// CASE 1: Asking for any address
lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
false, false, "",
true, CalloutHandlePtr());
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress("::"), false, false, "", true,
CalloutHandlePtr())));
// Check that we got that single lease
ASSERT_TRUE(lease);
EXPECT_EQ(addr.toText(), lease->addr_.toText());
......@@ -555,10 +574,10 @@ TEST_F(AllocEngine6Test, solicitReuseExpiredLease6) {
checkLease6(lease);
// CASE 2: Asking specifically for this address
lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress(addr.toText()),
false, false, "",
true, CalloutHandlePtr());
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress(addr.toText()), false, false, "",
true, CalloutHandlePtr())));
// Check that we got that single lease
ASSERT_TRUE(lease);
EXPECT_EQ(addr.toText(), lease->addr_.toText());
......@@ -591,10 +610,9 @@ TEST_F(AllocEngine6Test, requestReuseExpiredLease6) {
ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
// A client comes along, asking specifically for this address
lease = engine->allocateAddress6(subnet_, duid_, iaid_,
IOAddress(addr.toText()),
false, false, "", false,
CalloutHandlePtr());
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress(addr.toText()), false, false, "",
false, CalloutHandlePtr())));
// Check that he got that single lease
ASSERT_TRUE(lease);
......@@ -1126,7 +1144,7 @@ TEST_F(AllocEngine4Test, renewLease4) {
// renew it.
ASSERT_FALSE(lease->expired());
lease = engine->renewLease4(subnet_, clientid_, hwaddr_, true,
true, "host.example.com.", lease,
true, "host.example.com.", lease,
callout_handle, false);
// Check that he got that single lease
ASSERT_TRUE(lease);
......@@ -1269,9 +1287,10 @@ TEST_F(HookAllocEngine6Test, lease6_select) {
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
false, false, "",
false, callout_handle);
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress("::"), false, false, "", false,
callout_handle)));
// Check that we got a lease
ASSERT_TRUE(lease);
......@@ -1339,9 +1358,10 @@ TEST_F(HookAllocEngine6Test, change_lease6_select) {
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
// Call allocateAddress6. Callouts should be triggered here.
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
false, false, "",
false, callout_handle);
Lease6Ptr lease;
EXPECT_NO_THROW(lease = expectOneLease(engine->allocateAddress6(subnet_,
duid_, iaid_, IOAddress("::"), false, false, "", false,
callout_handle)));
// Check that we got a lease
ASSERT_TRUE(lease);
......@@ -1584,6 +1604,4 @@ TEST_F(HookAllocEngine4Test, change_lease4_select) {
EXPECT_EQ(valid_override_, from_mgr->valid_lft_);
}
}; // End of anonymous namespace
......@@ -151,9 +151,9 @@ public:
/// @param subnet_id identifier of the subnet the lease must belong to
///
/// @return smart pointer to the lease (or NULL if a lease is not found)
virtual Lease6Ptr getLease6(Lease6::LeaseType /* not used yet */,
const DUID&, uint32_t, SubnetID) const {
return (Lease6Ptr());
virtual Lease6Collection getLeases6(Lease6::LeaseType /* not used yet */,
const DUID&, uint32_t, SubnetID) const {
return (Lease6Collection());
}
/// @brief Updates IPv4 lease.
......
......@@ -60,7 +60,7 @@ TEST_F(MemfileLeaseMgrTest, getTypeAndName) {
// Checks that adding/getting/deleting a Lease6 object works.
TEST_F(MemfileLeaseMgrTest, addGetDelete6) {
const LeaseMgr::ParameterMap pmap; // Empty parameter map
boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));
boost::scoped_ptr<LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));
IOAddress addr("2001:db8:1::456");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment