From: Francis Dupont Date: Sat, 4 Nov 2017 09:12:17 +0000 (+0100) Subject: [5425] Checkpoint: code one, tests todo X-Git-Tag: trac5374_base~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=90a8c58d1a4ed66e2291f4ca5f255dd70501cf81;p=thirdparty%2Fkea.git [5425] Checkpoint: code one, tests todo --- diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index c7c08c371a..e6945c0aa7 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -144,19 +144,33 @@ AllocEngine::IterativeAllocator::increasePrefix(const isc::asiolink::IOAddress& 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_); @@ -166,58 +180,108 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet, // 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(*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(*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) @@ -228,6 +292,7 @@ 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"); @@ -241,6 +306,7 @@ AllocEngine::RandomAllocator::RandomAllocator(Lease::Type lease_type) isc::asiolink::IOAddress AllocEngine::RandomAllocator::pickAddress(const SubnetPtr&, + const ClientClasses&, const DuidPtr&, const IOAddress&) { isc_throw(NotImplemented, "Random allocator is not implemented"); @@ -677,7 +743,12 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // 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 - (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) { @@ -775,14 +846,23 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { // - 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 @@ -800,7 +880,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) { uint8_t prefix_len = 128; if (ctx.currentIA().type_ == Lease::TYPE_PD) { pool = boost::dynamic_pointer_cast( - subnet->getPool(ctx.currentIA().type_, candidate, false)); + subnet->getPool(ctx.currentIA().type_, ctx.query_->getClasses(), candidate)); if (pool) { prefix_len = pool->getLength(); } @@ -3214,10 +3294,19 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) { 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)) { diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h index e33b2f7056..d30e96008c 100644 --- a/src/lib/dhcpsrv/alloc_engine.h +++ b/src/lib/dhcpsrv/alloc_engine.h @@ -8,6 +8,7 @@ #define ALLOC_ENGINE_H #include +#include #include #include #include @@ -78,13 +79,19 @@ protected: /// 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. @@ -125,11 +132,13 @@ protected: /// @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: @@ -147,6 +156,20 @@ 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 @@ -164,12 +187,15 @@ protected: /// @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 @@ -191,7 +217,9 @@ protected: /// @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); }; diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index a2926ecf06..d57b94a894 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -378,6 +378,12 @@ PoolParser::parse(PoolStoragePtr pools, << " (" << option_data->getPosition() << ")"); } } + + // Client-class. + string client_class = getString(pool_structure, "client-class"); + if (!client_class.empty()) { + pool->allowClientClass(client_class); + } } //****************************** Pool4Parser ************************* @@ -870,6 +876,11 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) { 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_); } diff --git a/src/lib/dhcpsrv/parsers/shared_network_parser.cc b/src/lib/dhcpsrv/parsers/shared_network_parser.cc index 8a3cb14b31..65f201e439 100644 --- a/src/lib/dhcpsrv/parsers/shared_network_parser.cc +++ b/src/lib/dhcpsrv/parsers/shared_network_parser.cc @@ -71,8 +71,8 @@ SharedNetwork4Parser::parse(const data::ConstElementPtr& shared_network_data) { } } 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() << ")"); diff --git a/src/lib/dhcpsrv/pool.cc b/src/lib/dhcpsrv/pool.cc index 77cdc46121..1e3b622160 100644 --- a/src/lib/dhcpsrv/pool.cc +++ b/src/lib/dhcpsrv/pool.cc @@ -18,13 +18,35 @@ namespace dhcp { 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; @@ -90,6 +112,15 @@ Pool::toElement() const { 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 diff --git a/src/lib/dhcpsrv/pool.h b/src/lib/dhcpsrv/pool.h index 56d769891d..5254ea5ca5 100644 --- a/src/lib/dhcpsrv/pool.h +++ b/src/lib/dhcpsrv/pool.h @@ -8,6 +8,7 @@ #define POOL_H #include +#include #include #include #include @@ -106,6 +107,58 @@ public: 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. @@ -164,8 +217,22 @@ protected: /// @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 diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc index 837faed171..0e0f0baca7 100644 --- a/src/lib/dhcpsrv/subnet.cc +++ b/src/lib/dhcpsrv/subnet.cc @@ -134,6 +134,23 @@ Subnet::getPoolCapacity(Lease::Type type) const { } } +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(type)); + } +} + uint64_t Subnet::sumPoolCapacity(const PoolCollection& pools) const { uint64_t sum = 0; @@ -152,6 +169,28 @@ Subnet::sumPoolCapacity(const PoolCollection& pools) const { 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::max() - sum) { + return (std::numeric_limits::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"); @@ -329,6 +368,33 @@ const PoolPtr Subnet::getPool(Lease::Type type, const isc::asiolink::IOAddress& 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) diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h index 03b1f7784c..883aa229b6 100644 --- a/src/lib/dhcpsrv/subnet.h +++ b/src/lib/dhcpsrv/subnet.h @@ -54,26 +54,26 @@ public: /// @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 somewhere in the + /// @todo: Define map 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 somewhere in the + /// @todo: Define map 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 @@ -142,6 +142,17 @@ public: 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 @@ -169,6 +180,14 @@ public: /// @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") /// @@ -300,6 +319,13 @@ protected: /// @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. diff --git a/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc index ff216a6a77..ab02757247 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc @@ -326,7 +326,7 @@ TEST_F(AllocEngine4Test, IterativeAllocator) { 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)); } @@ -359,7 +359,7 @@ TEST_F(AllocEngine4Test, IterativeAllocator_manyPools4) { std::set 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 diff --git a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc index 1002958cfb..a8d80109ea 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc @@ -189,7 +189,7 @@ TEST_F(AllocEngine6Test, IterativeAllocator) { 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)); } } @@ -210,23 +210,23 @@ TEST_F(AllocEngine6Test, IterativeAllocatorAddrStep) { 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) { @@ -247,41 +247,41 @@ 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 @@ -289,7 +289,7 @@ TEST_F(AllocEngine6Test, IterativeAllocatorAddressIncrease) { 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()); @@ -379,7 +379,7 @@ TEST_F(AllocEngine6Test, IterativeAllocator_manyPools6) { std::set 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 diff --git a/src/lib/dhcpsrv/tests/alloc_engine_utils.h b/src/lib/dhcpsrv/tests/alloc_engine_utils.h index 426189eaaa..de3d8a2886 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine_utils.h +++ b/src/lib/dhcpsrv/tests/alloc_engine_utils.h @@ -409,6 +409,7 @@ public: 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 @@ -510,6 +511,7 @@ public: 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. };