Commit 17553447 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[2320] Subnet4 and Subnet6 have much more common code now.

parent 5054d0ed
......@@ -891,7 +891,7 @@ public:
Subnet4Ptr subnet(new Subnet4(addr, len, t1, t2, valid));
for (PoolStorage::iterator it = pools_.begin(); it != pools_.end(); ++it) {
subnet->addPool4(*it);
subnet->addPool(*it);
}
const Subnet::OptionContainer& options = subnet->getOptions();
......
......@@ -922,7 +922,7 @@ public:
Subnet6Ptr subnet(new Subnet6(addr, len, t1, t2, pref, valid));
for (PoolStorage::iterator it = pools_.begin(); it != pools_.end(); ++it) {
subnet->addPool6(*it);
subnet->addPool(*it);
}
const Subnet::OptionContainer& options = subnet->getOptions();
......
......@@ -71,7 +71,7 @@ public:
subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 48, 1000,
2000, 3000, 4000));
pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
subnet_->addPool6(pool_);
subnet_->addPool(pool_);
CfgMgr::instance().addSubnet6(subnet_);
}
......
......@@ -58,7 +58,7 @@ AllocEngine::IterativeAllocator::increaseAddress(const isc::asiolink::IOAddress&
isc::asiolink::IOAddress
AllocEngine::IterativeAllocator::pickAddress(const Subnet6Ptr& subnet,
AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
const DuidPtr&,
const IOAddress&) {
......@@ -67,14 +67,14 @@ AllocEngine::IterativeAllocator::pickAddress(const Subnet6Ptr& subnet,
// perhaps restaring the server).
IOAddress last = subnet->getLastAllocated();
const Pool6Collection& pools = subnet->getPools();
const PoolCollection& pools = subnet->getPools();
if (pools.empty()) {
isc_throw(AllocFailed, "No pools defined in selected subnet");
}
// first we need to find a pool the last address belongs to.
Pool6Collection::const_iterator it;
PoolCollection::const_iterator it;
for (it = pools.begin(); it != pools.end(); ++it) {
if ((*it)->inRange(last)) {
break;
......@@ -124,9 +124,9 @@ AllocEngine::HashedAllocator::HashedAllocator()
isc::asiolink::IOAddress
AllocEngine::HashedAllocator::pickAddress(const Subnet6Ptr&,
const DuidPtr&,
const IOAddress&) {
AllocEngine::HashedAllocator::pickAddress(const SubnetPtr&,
const DuidPtr&,
const IOAddress&) {
isc_throw(NotImplemented, "Hashed allocator is not implemented");
}
......@@ -137,9 +137,9 @@ AllocEngine::RandomAllocator::RandomAllocator()
isc::asiolink::IOAddress
AllocEngine::RandomAllocator::pickAddress(const Subnet6Ptr&,
const DuidPtr&,
const IOAddress&) {
AllocEngine::RandomAllocator::pickAddress(const SubnetPtr&,
const DuidPtr&,
const IOAddress&) {
isc_throw(NotImplemented, "Random allocator is not implemented");
}
......@@ -191,7 +191,7 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
/// implemented
// the hint is valid and not currently used, let's create a lease for it
Lease6Ptr lease = createLease(subnet, duid, iaid, hint, fake_allocation);
Lease6Ptr lease = createLease6(subnet, duid, iaid, hint, 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
......@@ -235,7 +235,7 @@ AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
if (!existing) {
// there's no existing lease for selected candidate, so it is
// free. Let's allocate it.
Lease6Ptr lease = createLease(subnet, duid, iaid, candidate,
Lease6Ptr lease = createLease6(subnet, duid, iaid, candidate,
fake_allocation);
if (lease) {
return (lease);
......@@ -300,11 +300,11 @@ Lease6Ptr AllocEngine::reuseExpiredLease(Lease6Ptr& expired,
return (expired);
}
Lease6Ptr AllocEngine::createLease(const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
const IOAddress& addr,
bool fake_allocation /*= false */ ) {
Lease6Ptr AllocEngine::createLease6(const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
const IOAddress& addr,
bool fake_allocation /*= false */ ) {
Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid, iaid,
subnet->getPreferred(), subnet->getValid(),
......
......@@ -66,7 +66,7 @@ protected:
/// again if necessary. The number of times this method is called will
/// increase as the number of available leases will decrease.
virtual isc::asiolink::IOAddress
pickAddress(const Subnet6Ptr& subnet, const DuidPtr& duid,
pickAddress(const SubnetPtr& subnet, const DuidPtr& duid,
const isc::asiolink::IOAddress& hint) = 0;
/// @brief virtual destructor
......@@ -96,7 +96,7 @@ protected:
/// @param hint client's hint (ignored)
/// @return the next address
virtual isc::asiolink::IOAddress
pickAddress(const Subnet6Ptr& subnet,
pickAddress(const SubnetPtr& subnet,
const DuidPtr& duid,
const isc::asiolink::IOAddress& hint);
private:
......@@ -125,7 +125,7 @@ protected:
/// @param duid Client's DUID
/// @param hint a hint (last address that was picked)
/// @return selected address
virtual isc::asiolink::IOAddress pickAddress(const Subnet6Ptr& subnet,
virtual isc::asiolink::IOAddress pickAddress(const SubnetPtr& subnet,
const DuidPtr& duid,
const isc::asiolink::IOAddress& hint);
};
......@@ -148,7 +148,7 @@ protected:
/// @param hint the last address that was picked (ignored)
/// @return a random address from the pool
virtual isc::asiolink::IOAddress
pickAddress(const Subnet6Ptr& subnet, const DuidPtr& duid,
pickAddress(const SubnetPtr& subnet, const DuidPtr& duid,
const isc::asiolink::IOAddress& hint);
};
......@@ -174,6 +174,24 @@ protected:
/// we give up (0 means unlimited)
AllocEngine(AllocType engine_type, unsigned int attempts);
/// @brief Allocates an IPv4 lease
///
/// This method uses currently selected allocator to pick an address from
/// specified subnet, creates a lease for that address and then inserts
/// it into LeaseMgr (if this allocation is not fake).
///
/// @param subnet subnet the allocation should come from
/// @param clientid Client identifier
/// @param hint a hint that the client provided
/// @param fake_allocation is this real i.e. REQUEST (false) or just picking
/// an address for DISCOVER that is not really allocated (true)
/// @return Allocated IPv4 lease (or NULL if allocation failed)
Lease4Ptr
allocateAddress4(const SubnetPtr& subnet,
const DuidPtr& clientid,
const isc::asiolink::IOAddress& hint,
bool fake_allocation);
/// @brief Allocates an IPv6 lease
///
/// This method uses currently selected allocator to pick an address from
......@@ -181,7 +199,7 @@ protected:
/// it into LeaseMgr (if this allocation is not fake).
///
/// @param subnet subnet the allocation should come from
/// @param duid Client'd DUID
/// @param duid Client's DUID
/// @param iaid iaid field from the IA_NA container that client sent
/// @param hint a hint that the client provided
/// @param fake_allocation is this real i.e. REQUEST (false) or just picking
......@@ -198,6 +216,23 @@ protected:
virtual ~AllocEngine();
private:
/// @brief creates a lease and inserts it in LeaseMgr if necessary
///
/// Creates a lease based on specified parameters and tries to insert it
/// into the database. That may fail in some cases, i.e. when there is another
/// allocation process and we lost a race to a specific lease.
///
/// @param subnet subnet the lease is allocated from
/// @param clientid client identifier
/// @param addr an address that was selected and is confirmed to be available
/// @param fake_allocation is this real i.e. REQUEST (false) or just picking
/// an address for DISCOVER that is not really allocated (true)
/// @return allocated lease (or NULL in the unlikely case of the lease just
/// becomed unavailable)
Lease4Ptr createLease4(const Subnet4Ptr& subnet, const DuidPtr& clientid,
const isc::asiolink::IOAddress& addr,
bool fake_allocation = false);
/// @brief creates a lease and inserts it in LeaseMgr if necessary
///
/// Creates a lease based on specified parameters and tries to insert it
......@@ -212,11 +247,28 @@ private:
/// an address for SOLICIT that is not really allocated (true)
/// @return allocated lease (or NULL in the unlikely case of the lease just
/// becomed unavailable)
Lease6Ptr createLease(const Subnet6Ptr& subnet, const DuidPtr& duid,
uint32_t iaid, const isc::asiolink::IOAddress& addr,
bool fake_allocation = false);
Lease6Ptr createLease6(const Subnet6Ptr& subnet, const DuidPtr& duid,
uint32_t iaid, const isc::asiolink::IOAddress& addr,
bool fake_allocation = false);
/// @brief reuses expired IPv4 lease
///
/// Updates existing expired lease with new information. Lease database
/// is updated if this is real (i.e. REQUEST, fake_allocation = false), not
/// dummy allocation request (i.e. DISCOVER, fake_allocation = true).
///
/// @param expired old, expired lease
/// @param subnet subnet the lease is allocated from
/// @param clientid client identifier
/// @param fake_allocation is this real i.e. REQUEST (false) or just picking
/// an address for DISCOVER that is not really allocated (true)
/// @return refreshed lease
/// @throw BadValue if trying to recycle lease that is still valid
Lease4Ptr reuseExpiredLease(Lease4Ptr& expired, const Subnet4Ptr& subnet,
const DuidPtr& clientid,
bool fake_allocation = false);
/// @brief reuses expired lease
/// @brief reuses expired IPv6 lease
///
/// Updates existing expired lease with new information. Lease database
/// is updated if this is real (i.e. REQUEST, fake_allocation = false), not
......
......@@ -179,6 +179,13 @@ typedef boost::shared_ptr<Pool6> Pool6Ptr;
/// @brief a container for IPv6 Pools
typedef std::vector<Pool6Ptr> Pool6Collection;
/// @brief a pointer to either IPv4 or IPv6 Pool
typedef boost::shared_ptr<Pool> PoolPtr;
/// @brief a container for either IPv4 or IPv6 Pools
typedef std::vector<PoolPtr> PoolCollection;
} // end of isc::dhcp namespace
} // end of isc namespace
......
......@@ -71,7 +71,7 @@ Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
}
}
void Subnet4::addPool4(const Pool4Ptr& pool) {
void Subnet::addPool(const PoolPtr& pool) {
IOAddress first_addr = pool->getFirstAddress();
IOAddress last_addr = pool->getLastAddress();
......@@ -86,9 +86,16 @@ void Subnet4::addPool4(const Pool4Ptr& pool) {
pools_.push_back(pool);
}
Pool4Ptr Subnet4::getPool4(const isc::asiolink::IOAddress& hint /* = IOAddress("::")*/ ) {
Pool4Ptr candidate;
for (Pool4Collection::iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
PoolPtr Subnet::getPool(isc::asiolink::IOAddress hint) {
if (dynamic_cast<Subnet6*>(this)) {
if (hint.toText() == "::") {
hint = IOAddress("0.0.0.0");
}
}
PoolPtr candidate;
for (PoolCollection::iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
// if we won't find anything better, then let's just use the first pool
if (!candidate) {
......@@ -104,6 +111,7 @@ Pool4Ptr Subnet4::getPool4(const isc::asiolink::IOAddress& hint /* = IOAddress("
return (candidate);
}
void
Subnet4::validateOption(const OptionPtr& option) const {
if (!option) {
......@@ -113,14 +121,14 @@ Subnet4::validateOption(const OptionPtr& option) const {
}
}
bool Subnet4::inPool(const isc::asiolink::IOAddress& addr) const {
bool Subnet::inPool(const isc::asiolink::IOAddress& addr) const {
// Let's start with checking if it even belongs to that subnet.
if (!inRange(addr)) {
return (false);
}
for (Pool4Collection::const_iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
for (PoolCollection::const_iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
if ((*pool)->inRange(addr)) {
return (true);
}
......@@ -142,39 +150,6 @@ Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
}
}
void Subnet6::addPool6(const Pool6Ptr& pool) {
IOAddress first_addr = pool->getFirstAddress();
IOAddress last_addr = pool->getLastAddress();
if (!inRange(first_addr) || !inRange(last_addr)) {
isc_throw(BadValue, "Pool6 (" << first_addr.toText() << "-" << last_addr.toText()
<< " does not belong in this (" << prefix_ << "/" << prefix_len_
<< ") subnet6");
}
/// @todo: Check that pools do not overlap
pools_.push_back(pool);
}
Pool6Ptr Subnet6::getPool6(const isc::asiolink::IOAddress& hint /* = IOAddress("::")*/ ) {
Pool6Ptr candidate;
for (Pool6Collection::iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
// if we won't find anything better, then let's just use the first pool
if (!candidate) {
candidate = *pool;
}
// if the client provided a pool and there's a pool that hint is valid in,
// then let's use that pool
if ((*pool)->inRange(hint)) {
return (*pool);
}
}
return (candidate);
}
void
Subnet6::validateOption(const OptionPtr& option) const {
if (!option) {
......@@ -184,21 +159,5 @@ Subnet6::validateOption(const OptionPtr& option) const {
}
}
bool Subnet6::inPool(const isc::asiolink::IOAddress& addr) const {
// Let's start with checking if it even belongs to that subnet.
if (!inRange(addr)) {
return (false);
}
for (Pool6Collection::const_iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
if ((*pool)->inRange(addr)) {
return (true);
}
}
// there's no pool that address belongs to
return (false);
}
} // end of isc::dhcp namespace
} // end of isc namespace
......@@ -235,7 +235,7 @@ public:
/// @param addr this address will be checked if it belongs to any pools in
/// that subnet
/// @return true if the address is in any of the pools
virtual bool inPool(const isc::asiolink::IOAddress& addr) const = 0;
bool inPool(const isc::asiolink::IOAddress& addr) const;
/// @brief return valid-lifetime for addresses in that prefix
Triplet<uint32_t> getValid() const {
......@@ -298,6 +298,26 @@ public:
return (std::make_pair(prefix_, prefix_len_));
}
/// @brief Adds a new pool.
/// @param pool pool to be added
void addPool(const PoolPtr& pool);
/// @brief Returns a pool that specified address belongs to
///
/// @param addr address that the returned pool should cover (optional)
/// @return Pointer to found Pool4 or Pool6 (or NULL)
PoolPtr getPool(isc::asiolink::IOAddress addr =
isc::asiolink::IOAddress("::"));
/// @brief returns all pools
///
/// The reference is only valid as long as the object that returned it.
///
/// @return a collection of all pools
const PoolCollection& getPools() const {
return pools_;
}
/// @brief returns textual representation of the subnet (e.g. "2001:db8::/64")
///
/// @return textual representation
......@@ -338,6 +358,9 @@ protected:
/// a Subnet4 or Subnet6.
SubnetID id_;
/// @brief collection of pools in that list
PoolCollection pools_;
/// @brief a prefix of the subnet
isc::asiolink::IOAddress prefix_;
......@@ -368,6 +391,9 @@ protected:
isc::asiolink::IOAddress last_allocated_;
};
/// @brief A generic pointer to either Subnet4 or Subnet6 object
typedef boost::shared_ptr<Subnet> SubnetPtr;
/// @brief A configuration holder for IPv4 subnet.
///
/// This class represents an IPv4 subnet.
......@@ -386,34 +412,6 @@ public:
const Triplet<uint32_t>& t2,
const Triplet<uint32_t>& valid_lifetime);
/// @brief Returns a pool that specified address belongs to
///
/// @param hint address that the returned pool should cover (optional)
/// @return Pointer to found pool4 (or NULL)
Pool4Ptr getPool4(const isc::asiolink::IOAddress& hint =
isc::asiolink::IOAddress("0.0.0.0"));
/// @brief Adds a new pool.
/// @param pool pool to be added
void addPool4(const Pool4Ptr& pool);
/// @brief returns all pools
///
/// The reference is only valid as long as the object that returned it.
///
/// @return a collection of all pools
const Pool4Collection& getPools() const {
return pools_;
}
/// @brief checks if the specified address is in pools
///
/// See the description in \ref Subnet::inPool().
///
/// @param addr this address will be checked if it belongs to any pools in that subnet
/// @return true if the address is in any of the pools
bool inPool(const isc::asiolink::IOAddress& addr) const;
protected:
/// @brief Check if option is valid and can be added to a subnet.
......@@ -423,8 +421,6 @@ protected:
/// @throw isc::BadValue if provided option is invalid.
virtual void validateOption(const OptionPtr& option) const;
/// @brief collection of pools in that list
Pool4Collection pools_;
};
/// @brief A pointer to a Subnet4 object
......@@ -461,35 +457,6 @@ public:
return (preferred_);
}
/// @brief Returns a pool that specified address belongs to
///
/// @param hint address that the returned pool should cover (optional)
/// @return Pointer to found pool6 (or NULL)
Pool6Ptr getPool6(const isc::asiolink::IOAddress& hint =
isc::asiolink::IOAddress("::"));
/// @brief Adds a new pool.
/// @param pool pool to be added
void addPool6(const Pool6Ptr& pool);
/// @brief returns all pools
///
/// The reference is only valid as long as the object that
/// returned it.
///
/// @return a collection of all pools
const Pool6Collection& getPools() const {
return pools_;
}
/// @brief checks if the specified address is in pools
///
/// See the description in \ref Subnet::inPool().
///
/// @param addr this address will be checked if it belongs to any pools in that subnet
/// @return true if the address is in any of the pools
bool inPool(const isc::asiolink::IOAddress& addr) const;
protected:
/// @brief Check if option is valid and can be added to a subnet.
......
......@@ -63,7 +63,7 @@ public:
subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::10"),
IOAddress("2001:db8:1::20")));
subnet_->addPool6(pool_);
subnet_->addPool(pool_);
cfg_mgr.addSubnet6(subnet_);
factory_.create("type=memfile");
......@@ -280,7 +280,7 @@ TEST_F(AllocEngineTest, IterativeAllocator_manyPools) {
Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, IOAddress(min.str()),
IOAddress(max.str())));
// cout << "Adding pool: " << min.str() << "-" << max.str() << endl;
subnet_->addPool6(pool);
subnet_->addPool(pool);
}
int total = 17 + 8*9; // first pool (::10 - ::20) has 17 addresses in it,
......@@ -334,7 +334,7 @@ TEST_F(AllocEngineTest, smallPool) {
// Create configuration similar to other tests, but with a single address pool
subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, addr, addr)); // just a single address
subnet_->addPool6(pool_);
subnet_->addPool(pool_);
cfg_mgr.addSubnet6(subnet_);
Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
......@@ -370,7 +370,7 @@ TEST_F(AllocEngineTest, outOfAddresses) {
// Create configuration similar to other tests, but with a single address pool
subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, addr, addr)); // just a single address
subnet_->addPool6(pool_);
subnet_->addPool(pool_);
cfg_mgr.addSubnet6(subnet_);
// Just a different duid
......@@ -401,7 +401,7 @@ TEST_F(AllocEngineTest, solicitReuseExpiredLease) {
// Create configuration similar to other tests, but with a single address pool
subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, addr, addr)); // just a single address
subnet_->addPool6(pool_);
subnet_->addPool(pool_);
cfg_mgr.addSubnet6(subnet_);
// Just a different duid
......@@ -444,7 +444,7 @@ TEST_F(AllocEngineTest, requestReuseExpiredLease) {
// Create configuration similar to other tests, but with a single address pool
subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, addr, addr)); // just a single address
subnet_->addPool6(pool_);
subnet_->addPool(pool_);
cfg_mgr.addSubnet6(subnet_);
// Let's create an expired lease
......
......@@ -61,28 +61,28 @@ TEST(Subnet4Test, Pool4InSubnet4) {
Subnet4Ptr subnet(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3));
Pool4Ptr pool1(new Pool4(IOAddress("192.1.2.0"), 25));
Pool4Ptr pool2(new Pool4(IOAddress("192.1.2.128"), 26));
Pool4Ptr pool3(new Pool4(IOAddress("192.1.2.192"), 30));
PoolPtr pool1(new Pool4(IOAddress("192.1.2.0"), 25));
PoolPtr pool2(new Pool4(IOAddress("192.1.2.128"), 26));
PoolPtr pool3(new Pool4(IOAddress("192.1.2.192"), 30));
subnet->addPool4(pool1);
subnet->addPool(pool1);
// If there's only one pool, get that pool
Pool4Ptr mypool = subnet->getPool4();
PoolPtr mypool = subnet->getPool();
EXPECT_EQ(mypool, pool1);
subnet->addPool4(pool2);
subnet->addPool4(pool3);
subnet->addPool(pool2);
subnet->addPool(pool3);
// If there are more than one pool and we didn't provide hint, we
// should get the first pool
mypool = subnet->getPool4();
mypool = subnet->getPool();
EXPECT_EQ(mypool, pool1);
// If we provide a hint, we should get a pool that this hint belongs to
mypool = subnet->getPool4(IOAddress("192.1.2.195"));
mypool = subnet->getPool(IOAddress("192.1.2.195"));
EXPECT_EQ(mypool, pool3);
......@@ -94,16 +94,16 @@ TEST(Subnet4Test, Subnet4_Pool4_checks) {
// this one is in subnet
Pool4Ptr pool1(new Pool4(IOAddress("192.255.0.0"), 16));
subnet->addPool4(pool1);
subnet->addPool(pool1);
// this one is larger than the subnet!
Pool4Ptr pool2(new Pool4(IOAddress("193.0.0.0"), 24));
EXPECT_THROW(subnet->addPool4(pool2), BadValue);
EXPECT_THROW(subnet->addPool(pool2), BadValue);
// this one is totally out of blue
Pool4Ptr pool3(new Pool4(IOAddress("1.2.3.4"), 16));
EXPECT_THROW(subnet->addPool4(pool3), BadValue);
EXPECT_THROW(subnet->addPool(pool3), BadValue);
}
TEST(Subnet4Test, addInvalidOption) {
......@@ -130,7 +130,7 @@ TEST(Subnet4Test, inRangeinPool) {
// this one is in subnet
Pool4Ptr pool1(new Pool4(IOAddress("192.2.0.0"), 16));
subnet->addPool4(pool1);
subnet->addPool(pool1);
// 192.1.1.1 belongs to the subnet...