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

[3150] Support for different pool types in subnet implemented

parent 154fbc8f
......@@ -96,7 +96,7 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
// perhaps restarting the server).
IOAddress last = subnet->getLastAllocated(lease_type_);
const PoolCollection& pools = subnet->getPools();
const PoolCollection& pools = subnet->getPools(lease_type_);
if (pools.empty()) {
isc_throw(AllocFailed, "No pools defined in selected subnet");
......
......@@ -21,9 +21,9 @@ using namespace isc::asiolink;
namespace isc {
namespace dhcp {
Pool::Pool(const isc::asiolink::IOAddress& first,
Pool::Pool(PoolType type, const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
:id_(getNextID()), first_(first), last_(last) {
:id_(getNextID()), first_(first), last_(last), type_(type) {
}
bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
......@@ -32,7 +32,7 @@ bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
Pool4::Pool4(const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
:Pool(first, last) {
:Pool(Pool::TYPE_V4, first, last) {
// check if specified address boundaries are sane
if (!first.isV4() || !last.isV4()) {
isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
......@@ -43,9 +43,8 @@ Pool4::Pool4(const isc::asiolink::IOAddress& first,
}
}
Pool4::Pool4(const isc::asiolink::IOAddress& prefix,
uint8_t prefix_len)
:Pool(prefix, IOAddress("0.0.0.0")) {
Pool4::Pool4( const isc::asiolink::IOAddress& prefix, uint8_t prefix_len)
:Pool(Pool::TYPE_V4, prefix, IOAddress("0.0.0.0")) {
// check if the prefix is sane
if (!prefix.isV4()) {
......@@ -64,13 +63,19 @@ Pool4::Pool4(const isc::asiolink::IOAddress& prefix,
Pool6::Pool6(PoolType type, const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
:Pool(first, last), type_(type) {
:Pool(type, first, last) {
// check if specified address boundaries are sane
if (!first.isV6() || !last.isV6()) {
isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
}
if ( (type != Pool::TYPE_IA) && (type != Pool::TYPE_TA) &&
(type != Pool::TYPE_PD)) {
isc_throw(BadValue, "Invalid Pool6 type: " << static_cast<int>(type)
<< ", must be TYPE_IA, TYPE_TA or TYPE_PD");
}
if (last < first) {
isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
// This check is a bit strict. If we decide that it is too strict,
......@@ -95,8 +100,7 @@ Pool6::Pool6(PoolType type, const isc::asiolink::IOAddress& first,
Pool6::Pool6(PoolType type, const isc::asiolink::IOAddress& prefix,
uint8_t prefix_len, uint8_t delegated_len /* = 128 */)
:Pool(prefix, IOAddress("::")),
type_(type), prefix_len_(delegated_len) {
:Pool(type, prefix, IOAddress("::")), prefix_len_(delegated_len) {
// check if the prefix is sane
if (!prefix.isV6()) {
......
......@@ -77,6 +77,20 @@ public:
/// @return true, if the address is in pool
bool inRange(const isc::asiolink::IOAddress& addr) const;
/// @brief Returns pool type (v4, v6 non-temporary, v6 temp, v6 prefix)
/// @return returns pool type
PoolType getType() const {
return (type_);
}
/// @brief virtual destructor
///
/// We need Pool to be a polymorphic class, so we could dynamic cast
/// from PoolPtr to Pool6Ptr if we need to. A class becomes polymorphic,
/// when there is at least one virtual method.
virtual ~Pool() {
}
protected:
/// @brief protected constructor
......@@ -84,7 +98,12 @@ protected:
/// This constructor is protected to prevent anyone from instantiating
/// Pool class directly. Instances of Pool4 and Pool6 should be created
/// instead.
Pool(const isc::asiolink::IOAddress& first,
///
/// @param type type of the pool
/// @param first first address of a range
/// @param last last address of a range
Pool(PoolType type,
const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last);
/// @brief returns the next unique Pool-ID
......@@ -110,6 +129,9 @@ protected:
///
/// @todo: This field is currently not used.
std::string comments_;
/// @brief defines a pool type
PoolType type_;
};
/// @brief Pool information for IPv4 addresses
......@@ -136,9 +158,6 @@ public:
/// @brief a pointer an IPv4 Pool
typedef boost::shared_ptr<Pool4> Pool4Ptr;
/// @brief a container for IPv4 Pools
typedef std::vector<Pool4Ptr> Pool4Collection;
/// @brief Pool information for IPv6 addresses and prefixes
///
/// It holds information about pool6, i.e. a range of IPv6 address space that
......@@ -197,9 +216,6 @@ public:
}
private:
/// @brief defines a pool type
PoolType type_;
/// @brief Defines prefix length (for TYPE_PD only)
uint8_t prefix_len_;
};
......@@ -207,9 +223,6 @@ private:
/// @brief a pointer an IPv6 Pool
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;
......
......@@ -35,12 +35,12 @@ Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
last_allocated_pd_(lastAddrInPrefix(prefix, len)) {
if ((prefix.isV6() && len > 128) ||
(prefix.isV4() && len > 32)) {
isc_throw(BadValue,
isc_throw(BadValue,
"Invalid prefix length specified for subnet: " << len);
}
}
bool
bool
Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
......@@ -120,7 +120,7 @@ void Subnet::setLastAllocated(const isc::asiolink::IOAddress& addr,
}
}
std::string
std::string
Subnet::toText() const {
std::stringstream tmp;
tmp << prefix_.toText() << "/" << static_cast<unsigned int>(prefix_len_);
......@@ -138,39 +138,50 @@ Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
}
}
const PoolCollection& Subnet::getPools() const {
return pools_;
}
void
Subnet::addPool(const PoolPtr& pool) {
IOAddress first_addr = pool->getFirstAddress();
IOAddress last_addr = pool->getLastAddress();
if (!inRange(first_addr) || !inRange(last_addr)) {
isc_throw(BadValue, "Pool (" << first_addr.toText() << "-"
<< last_addr.toText()
<< " does not belong in this (" << prefix_.toText() << "/"
<< static_cast<int>(prefix_len_) << ") subnet4");
const PoolCollection& Subnet::getPools(Pool::PoolType type) const {
switch (type) {
case Pool::TYPE_V4:
case Pool::TYPE_IA:
return (pools_);
case Pool::TYPE_TA:
return (pools_ta_);
case Pool::TYPE_PD:
return (pools_pd_);
default:
isc_throw(BadValue, "Unsupported pool type: " << type);
}
}
/// @todo: Check that pools do not overlap
PoolPtr Subnet::getPool(Pool::PoolType type, isc::asiolink::IOAddress hint) {
pools_.push_back(pool);
}
PoolCollection* pools = NULL;
PoolPtr Subnet::getPool(isc::asiolink::IOAddress hint) {
switch (type) {
case Pool::TYPE_V4:
case Pool::TYPE_IA:
pools = &pools_;
break;
case Pool::TYPE_TA:
pools = &pools_ta_;
break;
case Pool::TYPE_PD:
pools = &pools_pd_;
break;
default:
isc_throw(BadValue, "Failed to select pools. Unknown pool type: "
<< type);
}
PoolPtr candidate;
for (PoolCollection::iterator pool = pools_.begin();
pool != pools_.end(); ++pool) {
for (PoolCollection::const_iterator pool = pools->begin();
pool != pools->end(); ++pool) {
// If we won't find anything better, then let's just use the first 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
// 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);
......@@ -179,30 +190,59 @@ PoolPtr Subnet::getPool(isc::asiolink::IOAddress hint) {
return (candidate);
}
void
void
Subnet::addPool(const PoolPtr& pool) {
IOAddress first_addr = pool->getFirstAddress();
IOAddress last_addr = pool->getLastAddress();
if (!inRange(first_addr) || !inRange(last_addr)) {
isc_throw(BadValue, "Pool (" << first_addr.toText() << "-"
<< last_addr.toText()
<< " does not belong in this (" << prefix_.toText() << "/"
<< static_cast<int>(prefix_len_) << ") subnet");
}
/// @todo: Check that pools do not overlap
switch (pool->getType()) {
case Pool::TYPE_V4:
case Pool::TYPE_IA:
pools_.push_back(pool);
return;
case Pool6::TYPE_TA:
pools_ta_.push_back(pool);
return;
case Pool6::TYPE_PD:
pools_pd_.push_back(pool);
return;
default:
isc_throw(BadValue, "Invalid pool type specified: "
<< static_cast<int>(pool->getType()));
}
}
void
Subnet::setIface(const std::string& iface_name) {
iface_ = iface_name;
}
std::string
std::string
Subnet::getIface() const {
return (iface_);
}
void
Subnet4::validateOption(const OptionPtr& option) const {
if (!option) {
isc_throw(isc::BadValue,
isc_throw(isc::BadValue,
"option configured for subnet must not be NULL");
} else if (option->getUniverse() != Option::V4) {
isc_throw(isc::BadValue,
isc_throw(isc::BadValue,
"expected V4 option to be added to the subnet");
}
}
bool
bool
Subnet::inPool(const isc::asiolink::IOAddress& addr) const {
// Let's start with checking if it even belongs to that subnet.
......@@ -210,7 +250,7 @@ Subnet::inPool(const isc::asiolink::IOAddress& addr) const {
return (false);
}
for (PoolCollection::const_iterator pool = pools_.begin();
for (PoolCollection::const_iterator pool = pools_.begin();
pool != pools_.end(); ++pool) {
if ((*pool)->inRange(addr)) {
return (true);
......@@ -236,10 +276,10 @@ Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
void
Subnet6::validateOption(const OptionPtr& option) const {
if (!option) {
isc_throw(isc::BadValue,
isc_throw(isc::BadValue,
"option configured for subnet must not be NULL");
} else if (option->getUniverse() != Option::V6) {
isc_throw(isc::BadValue,
isc_throw(isc::BadValue,
"expected V6 option to be added to the subnet");
}
}
......
......@@ -274,14 +274,20 @@ public:
/// @brief Returns a pool that specified address belongs to
///
/// If there is no pool that the address belongs to (hint is invalid), other
/// pool of specified type will be returned.
///
/// @param type pool type that the pool is looked for
/// @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);
/// @return found pool (or NULL)
PoolPtr getPool(Pool::PoolType type, isc::asiolink::IOAddress addr);
/// @brief Returns a pool without any address specified
///
/// @param type pool type that the pool is looked for
/// @return returns one of the pools defined
PoolPtr getAnyPool() {
return (getPool(default_pool()));
PoolPtr getAnyPool(Pool::PoolType type) {
return (getPool(type, default_pool()));
}
/// @brief Returns the default address that will be used for pool selection
......@@ -294,8 +300,9 @@ public:
///
/// The reference is only valid as long as the object that returned it.
///
/// @param type lease type to be set
/// @return a collection of all pools
const PoolCollection& getPools() const;
const PoolCollection& getPools(Pool::PoolType type) const;
/// @brief sets name of the network interface for directly attached networks
///
......@@ -348,9 +355,15 @@ protected:
/// a Subnet4 or Subnet6.
SubnetID id_;
/// @brief collection of pools in that list
/// @brief collection of IPv4 or non-temporary IPv6 pools in that subnet
PoolCollection pools_;
/// @brief collection of IPv6 temporary address pools in that subnet
PoolCollection pools_ta_;
/// @brief collection of IPv6 prefix pools in that subnet
PoolCollection pools_pd_;
/// @brief a prefix of the subnet
isc::asiolink::IOAddress prefix_;
......@@ -501,9 +514,6 @@ protected:
/// @brief specifies optional interface-id
OptionPtr interface_id_;
/// @brief collection of pools for non-temporary addresses
Pool6Collection pools_;
/// @brief a triplet with preferred lifetime (in seconds)
Triplet<uint32_t> preferred_;
};
......
......@@ -1119,7 +1119,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);
......
......@@ -69,7 +69,7 @@ TEST(Subnet4Test, Pool4InSubnet4) {
subnet->addPool(pool1);
// If there's only one pool, get that pool
PoolPtr mypool = subnet->getAnyPool();
PoolPtr mypool = subnet->getAnyPool(Pool::TYPE_V4);
EXPECT_EQ(mypool, pool1);
......@@ -78,12 +78,12 @@ TEST(Subnet4Test, Pool4InSubnet4) {
// If there are more than one pool and we didn't provide hint, we
// should get the first pool
mypool = subnet->getAnyPool();
mypool = subnet->getAnyPool(Pool::TYPE_V4);
EXPECT_EQ(mypool, pool1);
// If we provide a hint, we should get a pool that this hint belongs to
mypool = subnet->getPool(IOAddress("192.1.2.195"));
mypool = subnet->getPool(Pool::TYPE_V4, IOAddress("192.1.2.195"));
EXPECT_EQ(mypool, pool3);
......@@ -215,7 +215,7 @@ TEST(Subnet6Test, Pool6InSubnet6) {
subnet->addPool(pool1);
// If there's only one pool, get that pool
PoolPtr mypool = subnet->getAnyPool();
PoolPtr mypool = subnet->getAnyPool(Pool::TYPE_IA);
EXPECT_EQ(mypool, pool1);
......@@ -224,12 +224,12 @@ TEST(Subnet6Test, Pool6InSubnet6) {
// If there are more than one pool and we didn't provide hint, we
// should get the first pool
mypool = subnet->getAnyPool();
mypool = subnet->getAnyPool(Pool::TYPE_IA);
EXPECT_EQ(mypool, pool1);
// If we provide a hint, we should get a pool that this hint belongs to
mypool = subnet->getPool(IOAddress("2001:db8:1:3::dead:beef"));
mypool = subnet->getPool(Pool::TYPE_IA, IOAddress("2001:db8:1:3::dead:beef"));
EXPECT_EQ(mypool, pool3);
}
......
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