Commit cb5533a1 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[master] Merge branch 'trac3711'

Conflicts:
	src/lib/asiolink/io_address.h
	src/lib/asiolink/tests/io_address_unittest.cc
parents c38e3c01 b811723e
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2010-2012, 2014-2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
......@@ -131,5 +131,55 @@ operator<<(std::ostream& os, const IOAddress& address) {
return (os);
}
IOAddress
IOAddress::subtract(const IOAddress& a, const IOAddress& b) {
if (a.getFamily() != b.getFamily()) {
isc_throw(BadValue, "Both addresses have to be the same family");
}
if (a.isV4()) {
// Subtracting v4 is easy. We have uint32_t operator.
return (IOAddress(static_cast<uint32_t>(a) - static_cast<uint32_t>(b)));
} else {
// v6 is more involved.
// Let's extract the raw data first.
vector<uint8_t> a_vec = a.toBytes();
vector<uint8_t> b_vec = b.toBytes();
// ... and prepare the result
vector<uint8_t> result(V6ADDRESS_LEN,0);
// Carry is a boolean, but to avoid its frequent casting, let's
// use uint8_t. Also, some would prefer to call it borrow, but I prefer
// carry. Somewhat relevant discussion here:
// http://en.wikipedia.org/wiki/Carry_flag#Carry_flag_vs._Borrow_flag
uint8_t carry = 0;
// Now perform subtraction with borrow.
for (int i = a_vec.size() - 1; i >= 0; --i) {
result[i] = a_vec[i] - b_vec[i] - carry;
carry = (a_vec[i] < b_vec[i] + carry);
}
return (fromBytes(AF_INET6, &result[0]));
}
}
IOAddress
IOAddress::increase(const IOAddress& addr) {
std::vector<uint8_t> packed(addr.toBytes());
// Start increasing the least significant byte
for (int i = packed.size() - 1; i >= 0; --i) {
// if we haven't overflowed (0xff -> 0x0), than we are done
if (++packed[i] != 0) {
break;
}
}
return (IOAddress::fromBytes(addr.getFamily(), &packed[0]));
}
} // namespace asiolink
} // namespace isc
......@@ -221,6 +221,47 @@ public:
return (nequals(other));
}
/// @brief Subtracts one address from another (a - b)
///
/// Treats addresses as integers and subtracts them. For example:
/// 192.0.2.5 - 192.0.2.0 = 0.0.0.5
/// fe80::abcd - fe80:: = ::abcd
///
/// It is possible to subtract greater from lesser address, e.g.
/// 192.168.56.10 - 192.168.67.20, but please do understand that
/// the address space is a finite field in mathematical sense, so
/// you may end up with a result that is greater then any of the
/// addresses you specified. Also, subtraction is not commutative,
/// so a - b != b - a.
///
/// This operation is essential for calculating the number of
/// leases in a pool, where we need to calculate (max - min).
/// @throw BadValue if addresses are of different family
/// @param a address to be subtracted from
/// @param b address to be subtracted
/// @return IOAddress object that represents the difference
static IOAddress subtract(const IOAddress& a, const IOAddress& b);
/// @brief Returns an address increased by one
///
/// This method works for both IPv4 and IPv6 addresses. For example,
/// increase 192.0.2.255 will become 192.0.3.0.
///
/// Address space is a finite field in the mathematical sense, so keep
/// in mind that the address space "loops". 255.255.255.255 increased
/// by one gives 0.0.0.0. The same is true for maximum value of IPv6
/// (all 1's) looping to ::.
///
/// @todo Determine if we have a use-case for increasing the address
/// by more than one. Increase by one is used in AllocEngine. This method
/// could take extra parameter that specifies the value by which the
/// address should be increased.
///
/// @param addr address to be increased
/// @return address increased by one
static IOAddress
increase(const IOAddress& addr);
/// \brief Converts IPv4 address to uint32_t
///
/// Will throw BadValue exception if that is not IPv4
......
// Copyright (C) 2011, 2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2012,2014-2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
......@@ -17,6 +17,7 @@
#include <asiolink/io_error.h>
#include <asiolink/io_address.h>
#include <exceptions/exceptions.h>
#include <algorithm>
#include <cstring>
......@@ -102,7 +103,7 @@ TEST(IOAddressTest, toBytesV6) {
const char* V6STRING = "2001:db8:1::dead:beef";
uint8_t V6[] = {
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef
0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef
};
std::vector<uint8_t> actual = IOAddress(V6STRING).toBytes();
......@@ -223,3 +224,77 @@ TEST(IOAddressTest, staticAddresses) {
EXPECT_EQ(IOAddress("255.255.255.255"), IOAddress::IPV4_BCAST_ADDRESS());
EXPECT_EQ(IOAddress("::"), IOAddress::IPV6_ZERO_ADDRESS());
}
// Tests whether address subtraction works correctly.
TEST(IOAddressTest, subtract) {
IOAddress addr1("192.0.2.12");
IOAddress addr2("192.0.2.5");
IOAddress addr3("192.0.2.0");
IOAddress addr4("0.0.2.1");
IOAddress any4("0.0.0.0");
IOAddress bcast("255.255.255.255");
EXPECT_EQ("0.0.0.7", IOAddress::subtract(addr1, addr2).toText());
EXPECT_EQ("0.0.0.12", IOAddress::subtract(addr1, addr3).toText());
// Subtracting 0.0.0.0 is like subtracting 0.
EXPECT_EQ("192.0.2.12", IOAddress::subtract(addr1, any4).toText());
EXPECT_EQ("192.0.2.13", IOAddress::subtract(addr1, bcast).toText());
EXPECT_EQ("191.255.255.255", IOAddress::subtract(addr3, addr4).toText());
// Let's check if we can subtract greater address from smaller.
// This will check if we can "loop"
EXPECT_EQ("255.255.255.251", IOAddress::subtract(addr3, addr2).toText());
IOAddress addr6("fe80::abcd");
IOAddress addr7("fe80::");
IOAddress addr8("fe80::1234");
IOAddress addr9("2001:db8::face");
IOAddress addr10("2001:db8::ffff:ffff:ffff:ffff");
IOAddress addr11("::1");
IOAddress any6("::");
EXPECT_EQ("::abcd", IOAddress::subtract(addr6, addr7).toText());
EXPECT_EQ("::9999", IOAddress::subtract(addr6, addr8).toText());
EXPECT_EQ("::ffff:ffff:ffff:531", IOAddress::subtract(addr10, addr9).toText());
// Subtract with borrow, extreme edition. Need to borrow one bit
// 112 times.
EXPECT_EQ("fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
IOAddress::subtract(addr7, addr11).toText());
// Now check if we can loop beyond :: (:: - ::1 is a lot of F's)
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
IOAddress::subtract(any6, addr11).toText());
// Subtracting :: is like subtracting 0.
EXPECT_EQ("2001:db8::face", IOAddress::subtract(addr9, any6).toText());
// Let's check if we can subtract greater address from smaller.
// This will check if we can "loop"
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:edcc",
IOAddress::subtract(addr7, addr8).toText());
// Inter-family relations are not allowed.
EXPECT_THROW(IOAddress::subtract(addr1, addr6), isc::BadValue);
EXPECT_THROW(IOAddress::subtract(addr6, addr1), isc::BadValue);
}
// Test checks whether an address can be increased.
TEST(IOAddressTest, increaseAddr) {
IOAddress addr1("192.0.2.12");
IOAddress any4("0.0.0.0");
IOAddress bcast("255.255.255.255");
IOAddress addr6("2001:db8::ffff:ffff:ffff:ffff");
IOAddress addr11("::1");
IOAddress any6("::");
IOAddress the_last_one("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
EXPECT_EQ("192.0.2.13", IOAddress::increase(addr1).toText());
EXPECT_EQ("0.0.0.1", IOAddress::increase(any4).toText());
EXPECT_EQ("0.0.0.0", IOAddress::increase(bcast).toText());
EXPECT_EQ("2001:db8:0:1::", IOAddress::increase(addr6).toText());
EXPECT_EQ("::2", IOAddress::increase(addr11).toText());
EXPECT_EQ("::1", IOAddress::increase(any6).toText());
EXPECT_EQ("::", IOAddress::increase(the_last_one).toText());
}
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012,2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
......@@ -15,6 +15,8 @@
#include <dhcpsrv/addr_utilities.h>
#include <exceptions/exceptions.h>
#include <vector>
#include <limits>
#include <string.h>
using namespace isc;
......@@ -205,5 +207,100 @@ isc::asiolink::IOAddress getNetmask4(uint8_t len) {
return (IOAddress(x));
}
uint64_t
addrsInRange(const isc::asiolink::IOAddress& min,
const isc::asiolink::IOAddress& max) {
if (min.getFamily() != max.getFamily()) {
isc_throw(BadValue, "Both addresses have to be the same family");
}
if (max < min) {
isc_throw(BadValue, min.toText() << " must not be greater than "
<< max.toText());
}
if (min.isV4()) {
// Let's explicitly cast last_ and first_ (IOAddress). This conversion is
// automatic, but let's explicitly cast it show that we moved to integer
// domain and addresses are now substractable.
uint64_t max_numeric = static_cast<uint32_t>(max);
uint64_t min_numeric = static_cast<uint32_t>(min);
// We can simply subtract the values. We need to increase the result
// by one, as both min and max are included in the range. So even if
// min == max, there's one address.
return (max_numeric - min_numeric + 1);
} else {
// Calculating the difference in v6 is more involved. Let's subtract
// one from the other. By subtracting min from max, we move the
// [a, b] range to the [0, (b-a)] range. We don't care about the beginning
// of the new range (it's always zero). The upper bound now specifies
// the number of addresses minus one.
IOAddress count = IOAddress::subtract(max, min);
// There's one very special case. Someone is trying to check how many
// IPv6 addresses are in IPv6 address space. He called this method
// with ::, ffff:ffff:ffff:fffff:ffff:ffff:ffff:ffff. The diff is also
// all 1s. Had we increased it by one, the address would flip to all 0s.
// This will not happen in a real world. Apparently, unit-tests are
// sometimes nastier then a real world.
static IOAddress max6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
if (count == max6) {
return (std::numeric_limits<uint64_t>::max());
}
// Increase it by one (a..a range still contains one address, even though
// a subtracted from a is zero).
count = IOAddress::increase(count);
// We don't have uint128, so for anything greater than 2^64, we'll just
// assume numeric_limits<uint64_t>::max. Let's do it the manual way.
const std::vector<uint8_t>& bin(count.toBytes());
// If any of the most significant 64 bits is set, we have more than
// 2^64 addresses and can't represent it even on uint64_t.
for (int i = 0 ; i < 8; i++) {
if (bin[i]) {
return (std::numeric_limits<uint64_t>::max());
}
}
// Ok, we're good. The pool is sanely sized. It may be huge, but at least
// that's something we can represent on uint64_t.
uint64_t numeric = 0;
for (int i = 8; i < 16; i++) {
numeric <<= 8;
numeric += bin[i];
}
return (numeric);
}
}
uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len) {
if (delegated_len < pool_len) {
return (0);
}
uint64_t count = delegated_len - pool_len;
if (count == 0) {
// If we want to delegate /64 out of /64 pool, we have only
// one prefix.
return (1);
} else if (count >= 64) {
// If the difference is greater than or equal 64, e.g. we want to
// delegate /96 out of /16 pool, the number is bigger than we can
// express, so we'll stick with maximum value of uint64_t.
return (std::numeric_limits<uint64_t>::max());
} else {
// Now count specifies the exponent (e.g. if the difference between the
// delegated and pool length is 4, we have 16 prefixes), so we need
// to calculate 2^(count - 1)
return ((static_cast<uint64_t>(2)) << (count - 1));
}
}
};
};
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012,2014-2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
......@@ -52,11 +52,37 @@ isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefi
isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
uint8_t len);
/// @brief generates an IPv4 netmask of specified length
/// @brief Generates an IPv4 netmask of specified length
/// @throw BadValue if len is greater than 32
/// @return netmask
isc::asiolink::IOAddress getNetmask4(uint8_t len);
/// @brief Returns number of available addresses in the specified range (min - max).
///
/// Note that for min equal max case, the number of addresses is one.
///
/// @throw BadValue if min and max are not of the same family (both must be
/// either IPv4 or IPv6) or if max < min.
///
/// @param min the first address in range
/// @param max the last address in range
/// @return number of addresses in range
uint64_t addrsInRange(const isc::asiolink::IOAddress& min,
const isc::asiolink::IOAddress& max);
/// @brief Returns number of available IPv6 prefixes in the specified prefix.
///
/// Note that if the answer is bigger than uint64_t can hold, it will return
/// the max value of uint64_t type.
///
/// Example: prefixesInRange(48, 64) returns 65536, as there are /48 pool
/// can be split into 65536 prefixes, each /64 large.
///
/// @param pool_len length of the pool in bits
/// @param delegated_len length of the prefixes to be delegated from the pool
/// @return number of prefixes in range
uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len);
};
};
......
......@@ -66,34 +66,6 @@ AllocEngine::IterativeAllocator::IterativeAllocator(Lease::Type lease_type)
:Allocator(lease_type) {
}
isc::asiolink::IOAddress
AllocEngine::IterativeAllocator::increaseAddress(const isc::asiolink::IOAddress& addr) {
// Get a buffer holding an address.
const std::vector<uint8_t>& vec = addr.toBytes();
// Get the address length.
const int len = vec.size();
// Since the same array will be used to hold the IPv4 and IPv6
// address we have to make sure that the size of the array
// we allocate will work for both types of address.
BOOST_STATIC_ASSERT(V4ADDRESS_LEN <= V6ADDRESS_LEN);
uint8_t packed[V6ADDRESS_LEN];
// Copy the address. It can be either V4 or V6.
std::memcpy(packed, &vec[0], len);
// Start increasing the least significant byte
for (int i = len - 1; i >= 0; --i) {
++packed[i];
// if we haven't overflowed (0xff -> 0x0), than we are done
if (packed[i] != 0) {
break;
}
}
return (IOAddress::fromBytes(addr.getFamily(), packed));
}
isc::asiolink::IOAddress
AllocEngine::IterativeAllocator::increasePrefix(const isc::asiolink::IOAddress& prefix,
const uint8_t prefix_len) {
......@@ -193,7 +165,7 @@ AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
IOAddress next("::");
if (!prefix) {
next = increaseAddress(last); // basically addr++
next = IOAddress::increase(last); // basically addr++
} else {
Pool6Ptr pool6 = boost::dynamic_pointer_cast<Pool6>(*it);
if (!pool6) {
......@@ -566,21 +538,12 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
// - we find an address for which the lease has expired
// - we exhaust number of tries
//
// @todo: Current code does not handle pool exhaustion well. It will be
// improved. Current problems:
// 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
// 10 addresses), we will iterate over it 100 times before giving up
// 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
// 3. the whole concept of infinite attempts is just asking for infinite loop
// We may consider some form or reference counting (this pool has X addresses
// left), but this has one major problem. We exactly control allocation
// moment, but we currently do not control expiration time at all
// Initialize the maximum number of attempts to pick and allocate an
// address. The value of 0 means "infinite", which is maximum uint32_t
// value.
uint32_t max_attempts = (attempts_ == 0) ?
std::numeric_limits<uint32_t>::max() : attempts_;
/// @todo: We used to use hardcoded number of attempts (100). Now we dynamically
/// calculate the number of possible leases in all pools in this subnet and
/// try that number of times at most. It would be useful to that value if
/// attempts_, specified by the user could override that value (and keep
/// dynamic if they're set to 0).
uint32_t max_attempts = ctx.subnet_->getPoolCapacity(ctx.type_);
for (uint32_t i = 0; i < max_attempts; ++i)
{
IOAddress candidate = allocator->pickAddress(ctx.subnet_, ctx.duid_, hint);
......@@ -1039,16 +1002,12 @@ AllocEngine::allocateLease4(const SubnetPtr& subnet, const ClientIdPtr& clientid
// - we find an address for which the lease has expired
// - we exhaust the number of tries
//
/// @todo: Current code does not handle pool exhaustion well. It will be
/// improved. Current problems:
/// 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
/// 10 addresses), we will iterate over it 100 times before giving up
/// 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
/// 3. the whole concept of infinite attempts is just asking for infinite loop
/// We may consider some form or reference counting (this pool has X addresses
/// left), but this has one major problem. We exactly control allocation
/// moment, but we currently do not control expiration time at all
unsigned int i = attempts_;
/// @todo: We used to use hardcoded number of attempts (100). Now we dynamically
/// calculate the number of possible leases in all pools in this subnet and
/// try that number of times at most. It would be useful to that value if
/// attempts_, specified by the user could override that value (and keep
/// dynamic if they're set to 0).
uint64_t i = subnet->getPoolCapacity(Lease::TYPE_V4);
do {
// Decrease the number of remaining attempts here so as we guarantee
// that it is decreased when the code below uses "continue".
......
......@@ -137,16 +137,6 @@ protected:
const isc::asiolink::IOAddress& hint);
protected:
/// @brief Returns an address increased by one
///
/// This method works for both IPv4 and IPv6 addresses. For example,
/// increase 192.0.2.255 will become 192.0.3.0.
///
/// @param addr address to be increased
/// @return address increased by one
static isc::asiolink::IOAddress
increaseAddress(const isc::asiolink::IOAddress& addr);
/// @brief Returns the next prefix
///
/// This method works for IPv6 addresses only. It increases
......
// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
......@@ -24,7 +24,8 @@ 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) {
:id_(getNextID()), first_(first), last_(last), type_(type),
capacity_(0) {
}
bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
......@@ -50,6 +51,12 @@ Pool4::Pool4(const isc::asiolink::IOAddress& first,
if (last < first) {
isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
}
// This is IPv4 pool, which only has one type. We can calculate
// the number of theoretically possible leases in it. As there's 2^32
// possible IPv4 addresses, we'll be able to accurately store that
// info.
capacity_ = addrsInRange(first, last);
}
Pool4::Pool4( const isc::asiolink::IOAddress& prefix, uint8_t prefix_len)
......@@ -67,8 +74,13 @@ Pool4::Pool4( const isc::asiolink::IOAddress& prefix, uint8_t prefix_len)
// Let's now calculate the last address in defined pool
last_ = lastAddrInPrefix(prefix, prefix_len);
}
// This is IPv4 pool, which only has one type. We can calculate
// the number of theoretically possible leases in it. As there's 2^32
// possible IPv4 addresses, we'll be able to accurately store that
// info.
capacity_ = addrsInRange(prefix, last_);
}
Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
......@@ -105,6 +117,11 @@ Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& first,
isc_throw(BadValue, "Invalid Pool6 type specified:"
<< static_cast<int>(type));
}
// Let's calculate the theoretical number of leases in this pool.
// If the pool is extremely large (i.e. contains more than 2^64 addresses,
// we'll just cap it at max value of uint64_t).
capacity_ = addrsInRange(first, last);
}
Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& prefix,
......@@ -123,7 +140,7 @@ Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& prefix,
if (prefix_len > delegated_len) {
isc_throw(BadValue, "Delegated length (" << static_cast<int>(delegated_len)
<< ") must be longer than prefix length ("
<< ") must be longer than or equal to prefix length ("
<< static_cast<int>(prefix_len) << ")");
}
......@@ -138,6 +155,11 @@ Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& prefix,
// Let's now calculate the last address in defined pool
last_ = lastAddrInPrefix(prefix, prefix_len);
// Let's calculate the theoretical number of leases in this pool.
// For addresses, we could use addrsInRange(prefix, last_), but it's
// much faster to do calculations on prefix lengths.
capacity_ = prefixesInRange(prefix_len, delegated_len);
}
std::string
......@@ -149,6 +171,5 @@ Pool6::toText() const {
return (tmp.str());
}
}; // end of isc::dhcp namespace
}; // end of isc namespace
// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2013,2015 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
......@@ -79,6 +79,14 @@ public:
virtual ~Pool() {
}
/// @brief Returns the number of all leases in this pool.
///
/// Note that this is the upper bound, assuming that no leases are used
/// and there are no host reservations. This is just a theoretical calculation.
/// @return number of possible leases in this pool
uint64_t getCapacity() const {
return (capacity_);
}
protected:
/// @brief protected constructor
......@@ -120,6 +128,14 @@ protected:
/// @brief defines a lease type that will be served from this pool
Lease::Type type_;
/// @brief Stores number of possible leases.
///
/// This could be calculated on the fly, but the calculations are somewhat
/// involved, so it is more efficient to calculate it once and just store
/// the result. Note that for very large pools, the number is capped at
/// max value of uint64_t.
uint64_t capacity_;
};
/// @brief Pool information for IPv4 addresses
......
......@@ -132,6 +132,40 @@ Subnet::toText() const {
return (tmp.str());
}
uint64_t
Subnet::getPoolCapacity(Lease::Type type) const {
switch (type) {
case Lease::TYPE_V4:
case Lease::TYPE_NA:
return sumPoolCapacity(pools_);
case Lease::TYPE_TA:
return sumPoolCapacity(pools_ta_);
case Lease::TYPE_PD:
return sumPoolCapacity(pools_pd_);
default:
isc_throw(BadValue, "Unsupported pool type: "
<< static_cast<int>(type));