return (IOAddress::fromBytes(AF_INET6, packed));
}
+isc::asiolink::IOAddress
+AllocEngine::IterativeAllocator::increaseAddress(const isc::asiolink::IOAddress& address,
+ bool prefix,
+ const uint8_t prefix_len) {
+ if (!prefix) {
+ return (IOAddress::increase(address));
+ } else {
+ return (increasePrefix(address, prefix_len));
+ }
+}
isc::asiolink::IOAddress
AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
+ const ClientClasses& client_classes,
const DuidPtr&,
const IOAddress&) {
// Is this prefix allocation?
bool prefix = pool_type_ == Lease::TYPE_PD;
+ uint8_t prefix_len = 0;
// Let's get the last allocated address. It is usually set correctly,
// but there are times when it won't be (like after removing a pool or
// perhaps restarting the server).
IOAddress last = subnet->getLastAllocated(pool_type_);
+ bool valid = true;
+ bool retrying = false;
const PoolCollection& pools = subnet->getPools(pool_type_);
// first we need to find a pool the last address belongs to.
PoolCollection::const_iterator it;
+ PoolCollection::const_iterator first = pools.end();
+ PoolPtr first_pool;
for (it = pools.begin(); it != pools.end(); ++it) {
+ if (!(*it)->clientSupported(client_classes)) {
+ continue;
+ }
+ if (first == pools.end()) {
+ first = it;
+ }
if ((*it)->inRange(last)) {
break;
}
}
+ // Caller checked this cannot happen
+ if (first == pools.end()) {
+ isc_throw(AllocFailed, "No allowed pools defined in selected subnet");
+ }
+
// last one was bogus for one of several reasons:
// - we just booted up and that's the first address we're allocating
// - a subnet was removed or other reconfiguration just completed
// - perhaps allocation algorithm was changed
+ // - last pool does not allow this client
if (it == pools.end()) {
- // ok to access first element directly. We checked that pools is non-empty
- IOAddress next = pools[0]->getFirstAddress();
- subnet->setLastAllocated(pool_type_, next);
- return (next);
+ it = first;
}
- // Ok, we have a pool that the last address belonged to, let's use it.
+ for (;;) {
+ // Trying next pool
+ if (retrying) {
+ for (; it != pools.end(); ++it) {
+ if ((*it)->clientSupported(client_classes)) {
+ break;
+ }
+ }
+ if (it == pools.end()) {
+ // Really out of luck today. That was the last pool.
+ break;
+ }
+ }
- IOAddress next("::");
- if (!prefix) {
- next = IOAddress::increase(last); // basically addr++
- } else {
- Pool6Ptr pool6 = boost::dynamic_pointer_cast<Pool6>(*it);
- if (!pool6) {
- // Something is gravely wrong here
- isc_throw(Unexpected, "Wrong type of pool: " << (*it)->toText()
- << " is not Pool6");
+ last = (*it)->getLastAllocated();
+ valid = (*it)->isLastAllocatedValid();
+ if (!valid && (last == (*it)->getFirstAddress())) {
+ // Pool was (re)initialized
+ (*it)->setLastAllocated(last);
+ subnet->setLastAllocated(pool_type_, last);
+ return (last);
}
- // Get the next prefix
- next = increasePrefix(last, pool6->getLength());
- }
- if ((*it)->inRange(next)) {
- // the next one is in the pool as well, so we haven't hit pool boundary yet
- subnet->setLastAllocated(pool_type_, next);
- return (next);
+ // still can be bogus
+ if (valid && !(*it)->inRange(last)) {
+ valid = false;
+ (*it)->resetLastAllocated();
+ (*it)->setLastAllocated((*it)->getFirstAddress());
+ }
+
+ if (valid) {
+ // Ok, we have a pool that the last address belonged to, let's use it.
+ if (prefix) {
+ Pool6Ptr pool6 = boost::dynamic_pointer_cast<Pool6>(*it);
+
+ if (!pool6) {
+ // Something is gravely wrong here
+ isc_throw(Unexpected, "Wrong type of pool: "
+ << (*it)->toText()
+ << " is not Pool6");
+ }
+ // Get the prefix length
+ prefix_len = pool6->getLength();
+ }
+
+ IOAddress next = increaseAddress(last, prefix, prefix_len);
+ if ((*it)->inRange(next)) {
+ // the next one is in the pool as well, so we haven't hit
+ // pool boundary yet
+ (*it)->setLastAllocated(next);
+ subnet->setLastAllocated(pool_type_, next);
+ return (next);
+ }
+
+ valid = false;
+ (*it)->resetLastAllocated();
+ }
+ // We hit pool boundary, let's try to jump to the next pool and try again
+ ++it;
+ retrying = true;
}
- // We hit pool boundary, let's try to jump to the next pool and try again
- ++it;
- if (it == pools.end()) {
- // Really out of luck today. That was the last pool. Let's rewind
- // to the beginning.
- next = pools[0]->getFirstAddress();
- subnet->setLastAllocated(pool_type_, next);
- return (next);
+ // Let's rewind to the beginning.
+ for (it = first; it != pools.end(); ++it) {
+ if ((*it)->clientSupported(client_classes)) {
+ (*it)->setLastAllocated((*it)->getFirstAddress());
+ (*it)->resetLastAllocated();
+ }
}
- // there is a next pool, let's try first address from it
- next = (*it)->getFirstAddress();
- subnet->setLastAllocated(pool_type_, next);
- return (next);
+ // ok to access first element directly. We checked that pools is non-empty
+ last = (*first)->getLastAllocated();
+ (*first)->setLastAllocated(last);
+ subnet->setLastAllocated(pool_type_, last);
+ return (last);
}
AllocEngine::HashedAllocator::HashedAllocator(Lease::Type lease_type)
isc::asiolink::IOAddress
AllocEngine::HashedAllocator::pickAddress(const SubnetPtr&,
+ const ClientClasses&,
const DuidPtr&,
const IOAddress&) {
isc_throw(NotImplemented, "Hashed allocator is not implemented");
isc::asiolink::IOAddress
AllocEngine::RandomAllocator::pickAddress(const SubnetPtr&,
+ const ClientClasses&,
const DuidPtr&,
const IOAddress&) {
isc_throw(NotImplemented, "Random allocator is not implemented");
// check if the hint is in pool and is available
// This is equivalent of subnet->inPool(hint), but returns the pool
pool = boost::dynamic_pointer_cast<Pool6>
- (subnet->getPool(ctx.currentIA().type_, hint, false));
+ (subnet->getPool(ctx.currentIA().type_, ctx.query_->getClasses(), hint));
+
+ // check if the pool is allowed
+ if (pool && !pool->clientSupported(ctx.query_->getClasses())) {
+ pool.reset();
+ }
if (pool) {
// - we find a free address
// - we find an address for which the lease has expired
// - we exhaust number of tries
- uint64_t max_attempts = (attempts_ > 0 ? attempts_ :
- subnet->getPoolCapacity(ctx.currentIA().type_));
+ uint64_t possible_attempts =
+ subnet->getPoolCapacity(ctx.currentIA().type_,
+ ctx.query_->getClasses());
+ // Try next subnet if there is no chance to get something
+ if (possible_attempts == 0) {
+ subnet = subnet->getNextSubnet(original_subnet);
+ continue;
+ }
+ uint64_t max_attempts = (attempts_ > 0 ? attempts_ : possible_attempts);
for (uint64_t i = 0; i < max_attempts; ++i) {
++total_attempts;
- IOAddress candidate = allocator->pickAddress(subnet, ctx.duid_,
+ IOAddress candidate = allocator->pickAddress(subnet,
+ ctx.query_->getClasses(),
+ ctx.duid_,
hint);
/// In-pool reservations: Check if this address is reserved for someone
uint8_t prefix_len = 128;
if (ctx.currentIA().type_ == Lease::TYPE_PD) {
pool = boost::dynamic_pointer_cast<Pool6>(
- subnet->getPool(ctx.currentIA().type_, candidate, false));
+ subnet->getPool(ctx.currentIA().type_, ctx.query_->getClasses(), candidate));
if (pool) {
prefix_len = pool->getLength();
}
client_id = ctx.clientid_;
}
- const uint64_t max_attempts = (attempts_ > 0 ? attempts_ :
- subnet->getPoolCapacity(Lease::TYPE_V4));
+ uint64_t possible_attempts =
+ subnet->getPoolCapacity(Lease::TYPE_V4,
+ ctx.query_->getClasses());
+ uint64_t max_attempts = (attempts_ > 0 ? attempts_ : possible_attempts);
+ // Skip trying if there is no chance to get something
+ if (possible_attempts == 0) {
+ max_attempts = 0;
+ }
+
for (uint64_t i = 0; i < max_attempts; ++i) {
- IOAddress candidate = allocator->pickAddress(subnet, client_id,
+ IOAddress candidate = allocator->pickAddress(subnet,
+ ctx.query_->getClasses(),
+ client_id,
ctx.requested_address_);
// If address is not reserved for another client, try to allocate it.
if (!addressReserved(candidate, ctx)) {
#define ALLOC_ENGINE_H
#include <asiolink/io_address.h>
+#include <dhcp/classify.h>
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
#include <dhcp/pkt4.h>
/// than pickResource(), because nobody would immediately know what the
/// resource means in this context.
///
+ /// Pools which are not allowed for client classes are skipped.
+ ///
/// @param subnet next address will be returned from pool of that subnet
+ /// @param client_classes list of classes client belongs to
+
/// @param duid Client's DUID
/// @param hint client's hint
///
/// @return the next address
virtual isc::asiolink::IOAddress
- pickAddress(const SubnetPtr& subnet, const DuidPtr& duid,
+ pickAddress(const SubnetPtr& subnet,
+ const ClientClasses& client_classes,
+ const DuidPtr& duid,
const isc::asiolink::IOAddress& hint) = 0;
/// @brief Default constructor.
/// @brief returns the next address from pools in a subnet
///
/// @param subnet next address will be returned from pool of that subnet
+ /// @param client_classes list of classes client belongs to
/// @param duid Client's DUID (ignored)
/// @param hint client's hint (ignored)
/// @return the next address
virtual isc::asiolink::IOAddress
pickAddress(const SubnetPtr& subnet,
+ const ClientClasses& client_classes,
const DuidPtr& duid,
const isc::asiolink::IOAddress& hint);
protected:
static isc::asiolink::IOAddress
increasePrefix(const isc::asiolink::IOAddress& prefix,
const uint8_t prefix_len);
+
+ /// @brief Returns the next address or prefix
+ ///
+ /// This method works for IPv4 addresses, IPv6 addresses and
+ /// IPv6 prefixes.
+ ///
+ /// @param address address or prefix to be increased
+ /// @param prefix true when the previous argument is a prefix
+ /// @param prefix_len length of the prefix
+ /// @return result address or prefix
+ static isc::asiolink::IOAddress
+ increaseAddress(const isc::asiolink::IOAddress& address,
+ bool prefix, const uint8_t prefix_len);
+
};
/// @brief Address/prefix allocator that gets an address based on a hash
/// @todo: Implement this method
///
/// @param subnet an address will be picked from pool of that subnet
+ /// @param client_classes list of classes client belongs to
/// @param duid Client's DUID
/// @param hint a hint (last address that was picked)
/// @return selected address
- virtual isc::asiolink::IOAddress pickAddress(const SubnetPtr& subnet,
- const DuidPtr& duid,
- const isc::asiolink::IOAddress& hint);
+ virtual isc::asiolink::IOAddress
+ pickAddress(const SubnetPtr& subnet,
+ const ClientClasses& client_classes,
+ const DuidPtr& duid,
+ const isc::asiolink::IOAddress& hint);
};
/// @brief Random allocator that picks address randomly
/// @param hint the last address that was picked (ignored)
/// @return a random address from the pool
virtual isc::asiolink::IOAddress
- pickAddress(const SubnetPtr& subnet, const DuidPtr& duid,
+ pickAddress(const SubnetPtr& subnet,
+ const ClientClasses& client_classes,
+ const DuidPtr& duid,
const isc::asiolink::IOAddress& hint);
};
<< " (" << option_data->getPosition() << ")");
}
}
+
+ // Client-class.
+ string client_class = getString(pool_structure, "client-class");
+ if (!client_class.empty()) {
+ pool->allowClientClass(client_class);
+ }
}
//****************************** Pool4Parser *************************
pool_->setContext(user_context_);
}
+ string client_class = getString(pd_pool_, "client-class");
+ if (!client_class.empty()) {
+ pool_->allowClientClass(client_class);
+ }
+
// Add the local pool to the external storage ptr.
pools->push_back(pool_);
}
}
} catch (const DhcpConfigError&) {
- // Position was already added
- throw;
+ // Position was already added
+ throw;
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, ex.what() << " ("
<< shared_network_data->getPosition() << ")");
Pool::Pool(Lease::Type type, const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
:id_(getNextID()), first_(first), last_(last), type_(type),
- capacity_(0), cfg_option_(new CfgOption()) {
+ capacity_(0), cfg_option_(new CfgOption()), white_list_(),
+ last_allocated_(first), last_allocated_valid_(false) {
}
bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
return (first_.smallerEqual(addr) && addr.smallerEqual(last_));
}
+bool Pool::clientSupported(const ClientClasses& classes) const {
+ if (white_list_.empty()) {
+ // There is no class defined for this pool, so we do
+ // support everyone.
+ return (true);
+ }
+
+ for (ClientClasses::const_iterator it = white_list_.begin();
+ it != white_list_.end(); ++it) {
+ if (classes.contains(*it)) {
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
+void Pool::allowClientClass(const ClientClass& class_name) {
+ white_list_.insert(class_name);
+}
+
std::string
Pool::toText() const {
std::stringstream tmp;
ConstCfgOptionPtr opts = getCfgOption();
map->set("option-data", opts->toElement());
return (map);
+
+ // Set client-class
+ const ClientClasses& cclasses = getClientClasses();
+ if (cclasses.size() > 1) {
+ isc_throw(ToElementError, "client-class has too many items: "
+ << cclasses.size());
+ } else if (!cclasses.empty()) {
+ map->set("client-class", Element::create(*cclasses.cbegin()));
+ }
}
data::ElementPtr
#define POOL_H
#include <asiolink/io_address.h>
+#include <dhcp/classify.h>
#include <dhcp/option6_pdexclude.h>
#include <boost/shared_ptr.hpp>
#include <cc/data.h>
user_context_ = ctx;
}
+ /// @Checks whether this pool supports client that belongs to
+ /// specified classes.
+ ///
+ /// @todo: currently doing the same than network which
+ /// is known to be improved.
+ ///
+ /// @param client_classes list of all classes the client belongs to
+ /// @return true if client can be supported, false otherwise
+ bool clientSupported(const ClientClasses& client_classes) const;
+
+ /// @brief Adds class class_name to the list of supported classes
+ ///
+ /// @param class_name client class to be supported by this pool
+ void allowClientClass(const ClientClass& class_name);
+
+ /// @brief returns the client class white list
+ ///
+ /// @note Currently white list is empty or has one element
+ /// @note The returned reference is only valid as long as the object
+ /// returned is valid.
+ ///
+ /// @return client classes @ref white_list_
+ const ClientClasses& getClientClasses() const {
+ return (white_list_);
+ }
+
+ /// @brief returns the last address that was tried from this pool
+ ///
+ /// @return address/prefix that was last tried from this pool
+ isc::asiolink::IOAddress getLastAllocated() const {
+ return last_allocated_;
+ }
+
+ /// @brief checks if the last address is valid
+ /// @return true if the last address is valid
+ bool isLastAllocatedValid() const {
+ return last_allocated_valid_;
+ }
+
+ /// @brief sets the last address that was tried from this pool
+ ///
+ /// @param addr address/prefix to that was tried last
+ void setLastAllocated(const isc::asiolink::IOAddress& addr) {
+ last_allocated_ = addr;
+ last_allocated_valid_ = true;
+ }
+
+ /// @brief resets the last address to invalid
+ void resetLastAllocated() {
+ last_allocated_valid_ = false;
+ }
+
/// @brief Unparse a pool object.
///
/// @return A pointer to unparsed pool configuration.
/// @brief Pointer to the option data configuration for this pool.
CfgOptionPtr cfg_option_;
+ /// @brief Optional definition of a client class
+ ///
+ /// @ref Network::white_list_
+ ClientClasses white_list_;
+
/// @brief Pointer to the user context (may be NULL)
data::ConstElementPtr user_context_;
+
+ /// @brief Last allocated address
+ /// See @ref isc::dhcp::subnet::last_allocated_ia_
+ /// Initialized and reset to first
+ isc::asiolink::IOAddress last_allocated_;
+
+ /// @brief Status of last allocated address
+ bool last_allocated_valid_;
+
};
/// @brief Pool information for IPv4 addresses
}
}
+uint64_t
+Subnet::getPoolCapacity(Lease::Type type,
+ const ClientClasses& client_classes) const {
+ switch (type) {
+ case Lease::TYPE_V4:
+ case Lease::TYPE_NA:
+ return sumPoolCapacity(pools_, client_classes);
+ case Lease::TYPE_TA:
+ return sumPoolCapacity(pools_ta_, client_classes);
+ case Lease::TYPE_PD:
+ return sumPoolCapacity(pools_pd_, client_classes);
+ default:
+ isc_throw(BadValue, "Unsupported pool type: "
+ << static_cast<int>(type));
+ }
+}
+
uint64_t
Subnet::sumPoolCapacity(const PoolCollection& pools) const {
uint64_t sum = 0;
return (sum);
}
+uint64_t
+Subnet::sumPoolCapacity(const PoolCollection& pools,
+ const ClientClasses& client_classes) const {
+ uint64_t sum = 0;
+ for (PoolCollection::const_iterator p = pools.begin(); p != pools.end(); ++p) {
+ if (!(*p)->clientSupported(client_classes)) {
+ continue;
+ }
+ uint64_t x = (*p)->getCapacity();
+
+ // Check if we can add it. If sum + x > uint64::max, then we would have
+ // overflown if we tried to add it.
+ if (x > std::numeric_limits<uint64_t>::max() - sum) {
+ return (std::numeric_limits<uint64_t>::max());
+ }
+
+ sum += x;
+ }
+
+ return (sum);
+}
+
void Subnet4::checkType(Lease::Type type) const {
if (type != Lease::TYPE_V4) {
isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
return (candidate);
}
+const PoolPtr Subnet::getPool(Lease::Type type,
+ const ClientClasses& client_classes,
+ const isc::asiolink::IOAddress& hint) const {
+ // check if the type is valid (and throw if it isn't)
+ checkType(type);
+
+ const PoolCollection& pools = getPools(type);
+
+ PoolPtr candidate;
+
+ if (!pools.empty()) {
+ PoolCollection::const_iterator ub =
+ std::upper_bound(pools.begin(), pools.end(), hint,
+ prefixLessThanFirstAddress);
+
+ if (ub != pools.begin()) {
+ --ub;
+ if ((*ub)->inRange(hint) && (*ub)->clientSupported(client_classes)) {
+ candidate = *ub;
+ }
+ }
+ }
+
+ // Return a pool or NULL if no match found.
+ return (candidate);
+}
+
void
Subnet::addPool(const PoolPtr& pool) {
// check if the type is valid (and throw if it isn't)
/// @return true if the address is in any of the pools
bool inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const;
- /// @brief returns the last address that was tried from this pool
+ /// @brief returns the last address that was tried from this subnet
///
/// This method returns the last address that was attempted to be allocated
/// from this subnet. This is used as helper information for the next
/// iteration of the allocation algorithm.
///
- /// @todo: Define map<SubnetID, IOAddress> somewhere in the
+ /// @todo: Define map<SubnetID, ClientClass, IOAddress> somewhere in the
/// AllocEngine::IterativeAllocator and keep the data there
///
/// @param type lease type to be returned
- /// @return address/prefix that was last tried from this pool
+ /// @return address/prefix that was last tried from this subnet
isc::asiolink::IOAddress getLastAllocated(Lease::Type type) const;
- /// @brief sets the last address that was tried from this pool
+ /// @brief sets the last address that was tried from this subnet
///
/// This method sets the last address that was attempted to be allocated
/// from this subnet. This is used as helper information for the next
/// iteration of the allocation algorithm.
///
- /// @todo: Define map<SubnetID, IOAddress> somewhere in the
+ /// @todo: Define map<SubnetID, ClientClass, IOAddress> somewhere in the
/// AllocEngine::IterativeAllocator and keep the data there
/// @param addr address/prefix to that was tried last
/// @param type lease type to be set
const PoolPtr getPool(Lease::Type type, const isc::asiolink::IOAddress& addr,
bool anypool = true) const;
+ /// @brief Returns a pool that specified address belongs to with classes
+ ///
+ /// Variant using only pools allowing given classes
+ ///
+ /// @param type pool type that the pool is looked for
+ /// @param client_classes client class list which must be allowed
+ /// @param addr address that the returned pool should cover (optional)
+ const PoolPtr getPool(Lease::Type type,
+ const ClientClasses& client_classes,
+ const isc::asiolink::IOAddress& addr) const;
+
/// @brief Returns a pool without any address specified
///
/// @param type pool type that the pool is looked for
/// @param type type of the lease
uint64_t getPoolCapacity(Lease::Type type) const;
+ /// @brief Returns the number of possible leases for specified lease type
+ /// allowed for a client which belongs to classes.
+ ///
+ /// @param type type of the lease
+ /// @param client_classes List of classes the client belongs to.
+ uint64_t getPoolCapacity(Lease::Type type,
+ const ClientClasses& client_classes) const;
+
/// @brief Returns textual representation of the subnet (e.g.
/// "2001:db8::/64")
///
/// @return sum of possible leases
uint64_t sumPoolCapacity(const PoolCollection& pools) const;
+ /// @brief returns a sum of possible leases in all pools allowing classes
+ /// @param pools list of pools
+ /// @param client_classes list of classes
+ /// @return sum of possible/allowed leases
+ uint64_t sumPoolCapacity(const PoolCollection& pools,
+ const ClientClasses& client_classes) const;
+
/// @brief Checks if the specified pool overlaps with an existing pool.
///
/// @param pool_type Pool type.
alloc(new NakedAllocEngine::IterativeAllocator(Lease::TYPE_V4));
for (int i = 0; i < 1000; ++i) {
- IOAddress candidate = alloc->pickAddress(subnet_, clientid_,
+ IOAddress candidate = alloc->pickAddress(subnet_, cc_, clientid_,
IOAddress("0.0.0.0"));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
}
std::set<IOAddress> generated_addrs;
int cnt = 0;
while (++cnt) {
- IOAddress candidate = alloc.pickAddress(subnet_, clientid_, IOAddress("0.0.0.0"));
+ IOAddress candidate = alloc.pickAddress(subnet_, cc_, clientid_, IOAddress("0.0.0.0"));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
// One way to easily verify that the iterative allocator really works is
alloc(new NakedAllocEngine::IterativeAllocator(Lease::TYPE_NA));
for (int i = 0; i < 1000; ++i) {
- IOAddress candidate = alloc->pickAddress(subnet_, duid_, IOAddress("::"));
+ IOAddress candidate = alloc->pickAddress(subnet_, cc_, duid_, IOAddress("::"));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
}
}
subnet_->addPool(pool3);
// Let's check the first pool (5 addresses here)
- EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:1::3", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:1::4", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:1::5", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::3", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::4", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::5", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
// The second pool is easy - only one address here
- EXPECT_EQ("2001:db8:1::100", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::100", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
// This is the third and last pool, with 2 addresses in it
- EXPECT_EQ("2001:db8:1::105", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:1::106", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::105", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::106", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
// We iterated over all addresses and reached to the end of the last pool.
// Let's wrap around and start from the beginning
- EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::1", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::2", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
}
TEST_F(AllocEngine6Test, IterativeAllocatorPrefixStep) {
// 2001:db8:2::/56 split into /64 prefixes (256 leases) (or 2001:db8:2:XX::)
// First pool check (Let's check over all 16 leases)
- EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:20::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:30::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:40::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:50::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:60::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:70::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:80::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:90::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:a0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:b0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:c0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:d0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:e0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:f0::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:20::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:30::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:40::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:50::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:60::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:70::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:80::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:90::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:a0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:b0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:c0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:d0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:e0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:f0::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
// Second pool (just one lease here)
- EXPECT_EQ("2001:db8:1::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:1::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
// Third pool (256 leases, let's check first and last explicitly and the
// rest over in a pool
- EXPECT_EQ("2001:db8:2::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:2::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
for (int i = 1; i < 255; i++) {
stringstream exp;
exp << "2001:db8:2:" << hex << i << dec << "::";
- EXPECT_EQ(exp.str(), alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ(exp.str(), alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
}
- EXPECT_EQ("2001:db8:2:ff::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:2:ff::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
// Ok, we've iterated over all prefixes in all pools. We now wrap around.
// We're looping over now (iterating over first pool again)
- EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
- EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
+ EXPECT_EQ("2001:db8:0:10::", alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::")).toText());
}
// This test verifies that the iterative allocator can step over addresses
NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_NA);
// Let's pick the first address
- IOAddress addr1 = alloc.pickAddress(subnet_, duid_, IOAddress("2001:db8:1::10"));
+ IOAddress addr1 = alloc.pickAddress(subnet_, cc_, duid_, IOAddress("2001:db8:1::10"));
// Check that we can indeed pick the first address from the pool
EXPECT_EQ("2001:db8:1::10", addr1.toText());
std::set<IOAddress> generated_addrs;
int cnt = 0;
while (++cnt) {
- IOAddress candidate = alloc.pickAddress(subnet_, duid_, IOAddress("::"));
+ IOAddress candidate = alloc.pickAddress(subnet_, cc_, duid_, IOAddress("::"));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
// One way to easily verify that the iterative allocator really works is
bool fqdn_fwd_; ///< Perform forward update for a lease.
bool fqdn_rev_; ///< Perform reverse update for a lease.
LeaseMgrFactory factory_; ///< pointer to LeaseMgr factory
+ ClientClasses cc_; ///< client classes
};
/// @brief Used in Allocation Engine tests for IPv4
Pool4Ptr pool_; ///< Pool belonging to subnet_
LeaseMgrFactory factory_; ///< Pointer to LeaseMgr factory
AllocEngine::ClientContext4 ctx_; ///< Context information passed to various
+ ClientClasses cc_; ///< Client classes
///< allocation engine functions.
};