2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-29 04:57:52 +00:00
kea/src/lib/dhcpsrv/tests/flq_allocator_unittest.cc
2025-08-20 17:39:15 +02:00

1107 lines
43 KiB
C++

// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
#include <asiolink/io_address.h>
#include <dhcp/hwaddr.h>
#include <dhcpsrv/flq_allocator.h>
#include <dhcpsrv/testutils/alloc_engine_utils.h>
#include <boost/make_shared.hpp>
#include <gtest/gtest.h>
using namespace isc::asiolink;
using namespace std;
namespace isc {
namespace dhcp {
namespace test {
/// @brief Test fixture class for the DHCPv4 Free Lease Queue allocator.
class FreeLeaseQueueAllocatorTest4 : public AllocEngine4Test {
public:
/// @brief Creates a DHCPv4 lease for an address and MAC address.
///
/// @param address Lease address.
/// @param hw_address_seed a seed from which the hardware address is generated.
/// @return Created lease pointer.
Lease4Ptr
createLease4(const IOAddress& address, uint64_t hw_address_seed) const {
vector<uint8_t> hw_address_vec(sizeof(hw_address_seed));
for (unsigned i = 0; i < sizeof(hw_address_seed); ++i) {
hw_address_vec[i] = (hw_address_seed >> i) & 0xFF;
}
auto hw_address = boost::make_shared<HWAddr>(hw_address_vec, HTYPE_ETHER);
auto lease = boost::make_shared<Lease4>(address, hw_address, ClientIdPtr(),
3600, time(0), subnet_->getID());
return (lease);
}
};
// Test that the allocator returns the correct type.
TEST_F(FreeLeaseQueueAllocatorTest4, getType) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_V4, subnet_);
EXPECT_EQ("flq", alloc.getType());
}
// Test populating free DHCPv4 leases to the queue.
TEST_F(FreeLeaseQueueAllocatorTest4, populateFreeAddressLeases) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_V4, subnet_);
auto& lease_mgr = LeaseMgrFactory::instance();
EXPECT_TRUE(lease_mgr.addLease((createLease4(IOAddress("192.0.2.100"), 0))));
EXPECT_TRUE(lease_mgr.addLease((createLease4(IOAddress("192.0.2.102"), 1))));
EXPECT_TRUE(lease_mgr.addLease((createLease4(IOAddress("192.0.2.104"), 2))));
EXPECT_TRUE(lease_mgr.addLease((createLease4(IOAddress("192.0.2.106"), 3))));
EXPECT_TRUE(lease_mgr.addLease((createLease4(IOAddress("192.0.2.108"), 4))));
EXPECT_NO_THROW(alloc.initAfterConfigure());
auto pool_state = boost::dynamic_pointer_cast<PoolFreeLeaseQueueAllocationState>(pool_->getAllocationState());
ASSERT_TRUE(pool_state);
EXPECT_FALSE(pool_state->exhausted());
double r = alloc.getOccupancyRate(IOAddress("192.0.2.101"), cc_);
EXPECT_EQ(.6, r);
r = alloc.getOccupancyRate(IOAddress("192.0.2.1"), cc_);
EXPECT_EQ(0., r);
std::set<IOAddress> addresses;
for (auto i = 0; i < 5; ++i) {
auto lease = pool_state->offerFreeLease();
ASSERT_FALSE(lease.isV4Zero());
addresses.insert(lease);
}
ASSERT_EQ(5, addresses.size());
EXPECT_EQ(1, addresses.count(IOAddress("192.0.2.101")));
EXPECT_EQ(1, addresses.count(IOAddress("192.0.2.103")));
EXPECT_EQ(1, addresses.count(IOAddress("192.0.2.105")));
EXPECT_EQ(1, addresses.count(IOAddress("192.0.2.107")));
EXPECT_EQ(1, addresses.count(IOAddress("192.0.2.109")));
}
// Test allocating IPv4 addresses when a subnet has a single pool.
TEST_F(FreeLeaseQueueAllocatorTest4, singlePool) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_V4, subnet_);
ASSERT_NO_THROW(alloc.initAfterConfigure());
// Remember returned addresses, so we can verify that unique addresses
// are returned.
std::set<IOAddress> addresses;
for (auto i = 0; i < 1000; ++i) {
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
addresses.insert(candidate);
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate, cc_));
}
// The pool comprises 10 addresses. All should be returned.
EXPECT_EQ(10, addresses.size());
}
// Test allocating IPv4 addresses and re-allocating these that are
// deleted (released).
TEST_F(FreeLeaseQueueAllocatorTest4, singlePoolWithAllocations) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_V4, subnet_);
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
// Remember returned addresses, so we can verify that unique addresses
// are returned.
std::map<IOAddress, Lease4Ptr> leases;
for (auto i = 0; i < 10; ++i) {
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
auto lease = createLease4(candidate, i);
leases[candidate] = lease;
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate, cc_));
EXPECT_TRUE(lease_mgr.addLease(lease));
}
// The pool comprises 10 addresses. All should be returned.
EXPECT_EQ(10, leases.size());
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
EXPECT_TRUE(candidate.isV4Zero());
double r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
EXPECT_EQ(1., r);
auto i = 0;
for (auto const& address_lease : leases) {
if (i % 2) {
EXPECT_TRUE(lease_mgr.deleteLease(address_lease.second));
}
++i;
}
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
EXPECT_EQ(.5, r);
for (auto j = 0; j < 5; ++j) {
candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate, cc_));
auto lease = createLease4(candidate, j);
EXPECT_TRUE(lease_mgr.addLease(lease));
}
candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
EXPECT_TRUE(candidate.isV4Zero());
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
EXPECT_EQ(1., r);
}
// Test allocating IPv4 addresses and re-allocating these that are
// reclaimed.
TEST_F(FreeLeaseQueueAllocatorTest4, singlePoolWithReclamations) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_V4, subnet_);
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
// Remember returned addresses, so we can verify that unique addresses
// are returned.
std::map<IOAddress, Lease4Ptr> leases;
for (auto i = 0; i < 10; ++i) {
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
auto lease = createLease4(candidate, i);
leases[candidate] = lease;
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate, cc_));
EXPECT_TRUE(lease_mgr.addLease(lease));
}
// The pool comprises 10 addresses. All should be returned.
EXPECT_EQ(10, leases.size());
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
EXPECT_TRUE(candidate.isV4Zero());
double r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
EXPECT_EQ(1., r);
auto i = 0;
for (auto const& address_lease : leases) {
if (i % 2) {
auto lease = address_lease.second;
lease->state_ = Lease::STATE_EXPIRED_RECLAIMED;
EXPECT_NO_THROW(lease_mgr.updateLease4(lease));
}
++i;
}
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
EXPECT_EQ(.5, r);
for (auto j = 0; j < 5; ++j) {
candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate, cc_));
auto lease = lease_mgr.getLease4(candidate);
lease->state_ = Lease::STATE_DEFAULT;
EXPECT_NO_THROW(lease_mgr.updateLease4(lease));
}
candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
EXPECT_TRUE(candidate.isV4Zero());
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
EXPECT_EQ(1., r);
}
// Test allocating DHCPv4 leases for many pools in a subnet.
TEST_F(FreeLeaseQueueAllocatorTest4, manyPools) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_V4, subnet_);
// Add several more pools.
for (int i = 1; i < 10; ++i) {
stringstream min, max;
min << "192.0.2." << i * 10;
max << "192.0.2." << i * 10 + 9;
auto pool = boost::make_shared<Pool4>(IOAddress(min.str()),
IOAddress(max.str()));
subnet_->addPool(pool);
}
// There are ten pools with 10 addresses each.
int total = 100;
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
double r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
// 1/100
EXPECT_EQ(.01, r);
std::set<IOAddress> addresses_set;
std::vector<IOAddress> addresses_vector;
std::vector<PoolPtr> pools_vector;
// Pick random addresses the number of times equal to the
// subnet capacity to ensure that all addresses are returned.
for (auto i = 0; i < total; ++i) {
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
addresses_set.insert(candidate);
addresses_vector.push_back(candidate);
auto lease = createLease4(candidate, i);
EXPECT_TRUE(lease_mgr.addLease(lease));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate, cc_));
pools_vector.push_back(subnet_->getPool(Lease::TYPE_V4, candidate));
}
// Make sure that unique addresses have been returned.
EXPECT_EQ(total, addresses_set.size());
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
EXPECT_EQ(1., r);
// Verify that the addresses are returned in the random order.
// Count how many times we found consecutive addresses. It should
// be 0 or close to 0.
size_t consecutive_addresses = 0;
for (unsigned k = 0; k < addresses_vector.size()-1; ++k) {
if (addresses_vector[k].toUint32() == addresses_vector[k+1].toUint32()-1) {
++consecutive_addresses;
}
}
// Ideally, the number of consecutive occurrences should be 0 but we
// allow some to make sure the test doesn't fall over sporadically.
EXPECT_LT(consecutive_addresses, addresses_vector.size()/4);
// Repeat similar check for pools. The pools should be picked in the
// random order too.
size_t consecutive_pools = 0;
for (unsigned k = 0; k < pools_vector.size()-1; ++k) {
// Check if the pools are adjacent (i.e., last address of the
// previous pool is a neighbor of the first address of the next
// pool).
if (pools_vector[k]->getLastAddress().toUint32()+1 ==
pools_vector[k+1]->getFirstAddress().toUint32()) {
++consecutive_pools;
}
}
EXPECT_LT(consecutive_pools, pools_vector.size()/2);
}
// Test that the allocator returns a zero address when there are no pools
// in a subnet.
TEST_F(FreeLeaseQueueAllocatorTest4, noPools) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_V4, subnet_);
subnet_->delPools(Lease::TYPE_V4);
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
EXPECT_TRUE(candidate.isV4Zero());
// rate is 0. because of the address can't be found, not from 0./0....
double r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
EXPECT_EQ(0., r);
}
// Test that the allocator respects client class guards.
TEST_F(FreeLeaseQueueAllocatorTest4, clientClasses) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_V4, subnet_);
// First pool only allows the client class foo.
pool_->allowClientClass("foo");
// Second pool. It only allows client class bar.
auto pool1 = boost::make_shared<Pool4>(IOAddress("192.0.2.120"),
IOAddress("192.0.2.129"));
pool1->allowClientClass("bar");
subnet_->addPool(pool1);
// Third pool. It only allows client class foo.
auto pool2 = boost::make_shared<Pool4>(IOAddress("192.0.2.140"),
IOAddress("192.0.2.149"));
pool2->allowClientClass("foo");
subnet_->addPool(pool2);
// Forth pool. It only allows client class bar.
auto pool3 = boost::make_shared<Pool4>(IOAddress("192.0.2.160"),
IOAddress("192.0.2.169"));
pool3->allowClientClass("bar");
subnet_->addPool(pool3);
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
// Remember offered addresses.
std::set<IOAddress> addresses_set;
// Simulate client's request belonging to the class bar.
cc_.insert("bar");
double r = alloc.getOccupancyRate(IOAddress("192.0.2.120"), cc_);
// 1/20
EXPECT_EQ(.05, r);
for (auto i = 0; i < 20; ++i) {
// Allocate random addresses and make sure they belong to the
// pools associated with the class bar.
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
EXPECT_FALSE(candidate.isV4Zero());
EXPECT_TRUE(lease_mgr.addLease(createLease4(candidate, i+50)));
addresses_set.insert(candidate);
EXPECT_TRUE(pool1->inRange(candidate) || pool3->inRange(candidate));
}
EXPECT_EQ(20, addresses_set.size());
r = alloc.getOccupancyRate(IOAddress("192.0.2.120"), cc_);
EXPECT_EQ(1., r);
addresses_set.clear();
// Simulate the case that the client also belongs to the class foo.
// All pools should now be available.
cc_.insert("foo");
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
// 21/40
EXPECT_EQ(.525, r);
for (auto i = 0; i < 20; ++i) {
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
addresses_set.insert(candidate);
EXPECT_TRUE(lease_mgr.addLease(createLease4(candidate, i+100)));
EXPECT_TRUE(subnet_->inRange(candidate));
}
EXPECT_EQ(20, addresses_set.size());
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
EXPECT_EQ(1., r);
// When the client does not belong to any client class the allocator
// can't offer any address to the client.
cc_.clear();
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
EXPECT_TRUE(candidate.isV4Zero());
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
EXPECT_EQ(0., r);
}
/// @brief Test fixture class for the DHCPv6 Free Lease Queue allocator.
class FreeLeaseQueueAllocatorTest6 : public AllocEngine6Test {
public:
/// @brief Creates a DHCPv6 lease for an address and DUID.
///
/// @param type lease type.
/// @param address Lease address.
/// @param duid_seed a seed from which the DUID is generated.
/// @return Created lease pointer.
Lease6Ptr
createLease6(Lease::Type type, const IOAddress& address, uint64_t duid_seed) const {
vector<uint8_t> duid_vec(sizeof(duid_seed));
for (unsigned i = 0; i < sizeof(duid_seed); ++i) {
duid_vec[i] = (duid_seed >> i) & 0xFF;
}
auto duid = boost::make_shared<DUID>(duid_vec);
auto lease = boost::make_shared<Lease6>(type, address, duid, 1, 1800,
3600, subnet_->getID());
return (lease);
}
};
// Test that the allocator returns the correct type.
TEST_F(FreeLeaseQueueAllocatorTest6, getType) {
FreeLeaseQueueAllocator allocNA(Lease::TYPE_NA, subnet_);
EXPECT_EQ("flq", allocNA.getType());
FreeLeaseQueueAllocator allocPD(Lease::TYPE_PD, subnet_);
EXPECT_EQ("flq", allocPD.getType());
}
// Test populating free DHCPv6 address leases to the queue.
TEST_F(FreeLeaseQueueAllocatorTest6, populateFreeAddressLeases) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_NA, subnet_);
auto& lease_mgr = LeaseMgrFactory::instance();
EXPECT_TRUE(lease_mgr.addLease((createLease6(Lease::TYPE_NA, IOAddress("2001:db8:1::10"), 0))));
EXPECT_TRUE(lease_mgr.addLease((createLease6(Lease::TYPE_NA, IOAddress("2001:db8:1::12"), 1))));
EXPECT_TRUE(lease_mgr.addLease((createLease6(Lease::TYPE_NA, IOAddress("2001:db8:1::14"), 2))));
EXPECT_TRUE(lease_mgr.addLease((createLease6(Lease::TYPE_NA, IOAddress("2001:db8:1::16"), 3))));
EXPECT_TRUE(lease_mgr.addLease((createLease6(Lease::TYPE_NA, IOAddress("2001:db8:1::18"), 4))));
EXPECT_NO_THROW(alloc.initAfterConfigure());
// Address getOccupancyRate is for IPv4 only.
double r = alloc.getOccupancyRate(IOAddress("2001:db8:1::10"), cc_);
EXPECT_EQ(0., r);
auto pool_state = boost::dynamic_pointer_cast<PoolFreeLeaseQueueAllocationState>(pool_->getAllocationState());
ASSERT_TRUE(pool_state);
EXPECT_FALSE(pool_state->exhausted());
std::set<IOAddress> addresses;
for (auto i = 0; i < 12; ++i) {
auto lease = pool_state->offerFreeLease();
ASSERT_FALSE(lease.isV6Zero());
addresses.insert(lease);
}
ASSERT_EQ(12, addresses.size());
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::11")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::13")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::15")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::17")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::19")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::1a")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::1b")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::1c")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::1d")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::1e")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::1f")));
EXPECT_EQ(1, addresses.count(IOAddress("2001:db8:1::20")));
}
// Test allocating IPv6 addresses when a subnet has a single pool.
TEST_F(FreeLeaseQueueAllocatorTest6, singlePool) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_NA, subnet_);
ASSERT_NO_THROW(alloc.initAfterConfigure());
// Remember returned addresses, so we can verify that unique addresses
// are returned.
std::set<IOAddress> addresses;
for (auto i = 0; i < 1000; ++i) {
IOAddress candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_FALSE(candidate.isV6Zero());
addresses.insert(candidate);
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_));
}
// The pool comprises 17 addresses. All should be returned.
EXPECT_EQ(17, addresses.size());
}
// Test allocating IPv6 addresses and re-allocating these that are
// deleted (released).
TEST_F(FreeLeaseQueueAllocatorTest6, singlePoolWithAllocations) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_NA, subnet_);
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
// Remember returned addresses, so we can verify that unique addresses
// are returned.
std::map<IOAddress, Lease6Ptr> leases;
for (auto i = 0; i < 17; ++i) {
IOAddress candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_FALSE(candidate.isV6Zero());
auto lease = createLease6(Lease::TYPE_NA, candidate, i);
leases[candidate] = lease;
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_));
EXPECT_TRUE(lease_mgr.addLease(lease));
}
// The pool comprises 17 addresses. All should be returned.
EXPECT_EQ(17, leases.size());
IOAddress candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_TRUE(candidate.isV6Zero());
auto i = 0;
for (auto const& address_lease : leases) {
if (i % 2) {
EXPECT_TRUE(lease_mgr.deleteLease(address_lease.second));
}
++i;
}
for (auto j = 0; j < 8; ++j) {
candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_));
auto lease = createLease6(Lease::TYPE_NA, candidate, i);
EXPECT_TRUE(lease_mgr.addLease(lease));
}
candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_TRUE(candidate.isV6Zero());
}
// Test allocating IPv6 addresses and re-allocating these that are
// reclaimed.
TEST_F(FreeLeaseQueueAllocatorTest6, singlePoolWithReclamations) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_NA, subnet_);
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
// Remember returned addresses, so we can verify that unique addresses
// are returned.
std::map<IOAddress, Lease6Ptr> leases;
for (auto i = 0; i < 17; ++i) {
IOAddress candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_FALSE(candidate.isV6Zero());
auto lease = createLease6(Lease::TYPE_NA, candidate, i);
leases[candidate] = lease;
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_));
EXPECT_TRUE(lease_mgr.addLease(lease));
}
// The pool comprises 17 addresses. All should be returned.
EXPECT_EQ(17, leases.size());
IOAddress candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_TRUE(candidate.isV6Zero());
auto i = 0;
for (auto const& address_lease : leases) {
if (i % 2) {
auto lease = address_lease.second;
lease->state_ = Lease::STATE_EXPIRED_RECLAIMED;
EXPECT_NO_THROW(lease_mgr.updateLease6(lease));
}
++i;
}
for (auto j = 0; j < 8; ++j) {
candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_));
auto lease = lease_mgr.getLease6(Lease::TYPE_NA, candidate);
lease->state_ = Lease::STATE_DEFAULT;
EXPECT_NO_THROW(lease_mgr.updateLease6(lease));
}
candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_TRUE(candidate.isV6Zero());
}
// Test allocating DHCPv6 leases for many pools in a subnet.
TEST_F(FreeLeaseQueueAllocatorTest6, manyPools) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_NA, subnet_);
// Add several more pools.
for (int i = 2; i < 10; ++i) {
stringstream min, max;
min << "2001:db8:1::" << hex << i * 16 + 1;
max << "2001:db8:1::" << hex << i * 16 + 16;
auto pool = boost::make_shared<Pool6>(Lease::TYPE_NA,
IOAddress(min.str()),
IOAddress(max.str()));
subnet_->addPool(pool);
}
// First pool (::10 - ::20) has 17 addresses.
// There are 8 extra pools with 16 addresses in each.
int total = 17 + 8 * 16;
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
std::set<IOAddress> addresses_set;
std::vector<IOAddress> addresses_vector;
std::vector<PoolPtr> pools_vector;
// Pick random addresses the number of times equal to the
// subnet capacity to ensure that all addresses are returned.
for (auto i = 0; i < total; ++i) {
IOAddress candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
addresses_set.insert(candidate);
addresses_vector.push_back(candidate);
auto lease = createLease6(Lease::TYPE_NA, candidate, i);
EXPECT_TRUE(lease_mgr.addLease(lease));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_));
pools_vector.push_back(subnet_->getPool(Lease::TYPE_NA, candidate));
}
// Make sure that unique addresses have been returned.
EXPECT_EQ(total, addresses_set.size());
// Verify that the addresses are returned in the random order.
// Count how many times we found consecutive addresses. It should
// be 0 or close to 0.
size_t consecutive_addresses = 0;
for (unsigned k = 0; k < addresses_vector.size()-1; ++k) {
if (IOAddress::increase(addresses_vector[k]) == addresses_vector[k+1]) {
++consecutive_addresses;
}
}
// Ideally, the number of consecutive occurrences should be 0 but we
// allow some to make sure the test doesn't fall over sporadically.
EXPECT_LT(consecutive_addresses, addresses_vector.size()/4);
// Repeat similar check for pools. The pools should be picked in the
// random order too.
size_t consecutive_pools = 0;
for (unsigned k = 0; k < pools_vector.size()-1; ++k) {
if (IOAddress::increase(pools_vector[k]->getLastAddress()) ==
pools_vector[k]->getFirstAddress()) {
++consecutive_pools;
}
}
EXPECT_LT(consecutive_pools, pools_vector.size()/2);
}
// Test that the allocator returns a zero address when there are no pools
// in a subnet.
TEST_F(FreeLeaseQueueAllocatorTest6, noPools) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_NA, subnet_);
subnet_->delPools(Lease::TYPE_NA);
IOAddress candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_TRUE(candidate.isV6Zero());
}
// Test that the allocator respects client class guards.
TEST_F(FreeLeaseQueueAllocatorTest6, clientClasses) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_NA, subnet_);
// First pool only allows the client class foo.
pool_->allowClientClass("foo");
// Second pool. It only allows client class bar.
auto pool1 = boost::make_shared<Pool6>(Lease::TYPE_NA,
IOAddress("2001:db8:1::120"),
IOAddress("2001:db8:1::129"));
pool1->allowClientClass("bar");
subnet_->addPool(pool1);
// Third pool. It only allows client class foo.
auto pool2 = boost::make_shared<Pool6>(Lease::TYPE_NA,
IOAddress("2001:db8:1::140"),
IOAddress("2001:db8:1::149"));
pool2->allowClientClass("foo");
subnet_->addPool(pool2);
// Forth pool. It only allows client class bar.
auto pool3 = boost::make_shared<Pool6>(Lease::TYPE_NA,
IOAddress("2001:db8:1::160"),
IOAddress("2001:db8:1::169"));
pool3->allowClientClass("bar");
subnet_->addPool(pool3);
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
// When the client does not belong to any client class the allocator
// can't offer any address to the client.
IOAddress candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_TRUE(candidate.isV6Zero());
// Remember offered addresses.
std::set<IOAddress> addresses_set;
// Simulate client's request belonging to the class bar.
cc_.insert("bar");
for (auto i = 0; i < 20; ++i) {
// Allocate random addresses and make sure they belong to the
// pools associated with the class bar.
candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
EXPECT_FALSE(candidate.isV6Zero());
EXPECT_TRUE(lease_mgr.addLease(createLease6(Lease::TYPE_NA, candidate, i+50)));
addresses_set.insert(candidate);
EXPECT_TRUE(pool1->inRange(candidate) || pool3->inRange(candidate));
}
EXPECT_EQ(20, addresses_set.size());
// Simulate the case that the client also belongs to the class foo.
// All pools should now be available.
cc_.insert("foo");
for (auto i = 0; i < 27; ++i) {
candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
addresses_set.insert(candidate);
EXPECT_TRUE(lease_mgr.addLease(createLease6(Lease::TYPE_NA, candidate, i+100)));
EXPECT_TRUE(subnet_->inRange(candidate));
}
EXPECT_EQ(47, addresses_set.size());
}
// Test populating free DHCPv6 prefix leases to the queue.
TEST_F(FreeLeaseQueueAllocatorTest6, populateFreePrefixDelegationLeases) {
subnet_->delPools(Lease::TYPE_PD);
FreeLeaseQueueAllocator alloc(Lease::TYPE_PD, subnet_);
auto pool = Pool6::create(Lease::TYPE_PD, IOAddress("2001:db8:2::"), 112, 120);
subnet_->addPool(pool);
auto& lease_mgr = LeaseMgrFactory::instance();
EXPECT_TRUE(lease_mgr.addLease((createLease6(Lease::TYPE_PD, IOAddress("2001:db8:2::"), 0))));
EXPECT_TRUE(lease_mgr.addLease((createLease6(Lease::TYPE_PD, IOAddress("2001:db8:2::1000"), 1))));
EXPECT_TRUE(lease_mgr.addLease((createLease6(Lease::TYPE_PD, IOAddress("2001:db8:2::2000"), 2))));
EXPECT_TRUE(lease_mgr.addLease((createLease6(Lease::TYPE_PD, IOAddress("2001:db8:2::3000"), 3))));
EXPECT_TRUE(lease_mgr.addLease((createLease6(Lease::TYPE_PD, IOAddress("2001:db8:2::4000"), 4))));
EXPECT_NO_THROW(alloc.initAfterConfigure());
auto pool_state = boost::dynamic_pointer_cast<PoolFreeLeaseQueueAllocationState>(pool->getAllocationState());
ASSERT_TRUE(pool_state);
EXPECT_FALSE(pool_state->exhausted());
double r = alloc.getOccupancyRate(IOAddress("2001:db8:2::"), 128, cc_);
EXPECT_EQ(5. / 256., r);
std::set<IOAddress> addresses;
for (auto i = 0; i < 256; ++i) {
auto lease = pool_state->offerFreeLease();
ASSERT_FALSE(lease.isV6Zero());
addresses.insert(lease);
}
ASSERT_EQ(251, addresses.size());
EXPECT_EQ(0, addresses.count(IOAddress("2001:db8:2::")));
EXPECT_EQ(0, addresses.count(IOAddress("2001:db8:2::1000")));
EXPECT_EQ(0, addresses.count(IOAddress("2001:db8:2::2000")));
EXPECT_EQ(0, addresses.count(IOAddress("2001:db8:2::3000")));
EXPECT_EQ(0, addresses.count(IOAddress("2001:db8:2::4000")));
}
// Test allocating delegated prefixes when a subnet has a single pool.
TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPool) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_PD, subnet_);
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
Pool6Ptr pool;
// Remember returned prefixes, so we can verify that unique addresses
// are returned.
std::set<IOAddress> prefixes;
for (auto i = 0; i < 65536; ++i) {
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
EXPECT_EQ(pd_pool_, pool);
EXPECT_TRUE(lease_mgr.addLease(createLease6(Lease::TYPE_PD, candidate, i)));
prefixes.insert(candidate);
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate, cc_));
}
// The pool comprises 65536 prefixes. All should be returned.
EXPECT_EQ(65536, prefixes.size());
double r = alloc.getOccupancyRate(IOAddress("2001:db8:1:2::"), 128, cc_);
EXPECT_EQ(1., r);
}
// Test allocating delegated prefixes and re-allocating these that are
// deleted (released).
TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPoolWithAllocations) {
// Remove the default pool because it is too large for this test case.
subnet_->delPools(Lease::TYPE_PD);
// Add a smaller pool.
auto pool = boost::make_shared<Pool6>(Lease::TYPE_PD,
IOAddress("3000::"),
120,
128);
subnet_->addPool(pool);
FreeLeaseQueueAllocator alloc(Lease::TYPE_PD, subnet_);
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
// Remember returned addresses, so we can verify that unique addresses
// are returned.
std::map<IOAddress, Lease6Ptr> leases;
for (auto i = 0; i < 256; ++i) {
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
EXPECT_FALSE(candidate.isV6Zero());
auto lease = createLease6(Lease::TYPE_PD, candidate, i);
leases[candidate] = lease;
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate, cc_));
EXPECT_TRUE(lease_mgr.addLease(lease));
}
// The pool comprises 256 delegated prefixes. All should be returned.
EXPECT_EQ(256, leases.size());
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
EXPECT_TRUE(candidate.isV6Zero());
double r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
EXPECT_EQ(1., r);
auto i = 0;
for (auto const& address_lease : leases) {
if (i % 2) {
EXPECT_TRUE(lease_mgr.deleteLease(address_lease.second));
}
++i;
}
r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
EXPECT_EQ(.5, r);
for (auto j = 0; j < 128; ++j) {
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate, cc_));
auto lease = createLease6(Lease::TYPE_PD, candidate, j);
EXPECT_TRUE(lease_mgr.addLease(lease));
}
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
EXPECT_TRUE(candidate.isV6Zero());
r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
EXPECT_EQ(1., r);
}
// Test allocating delegated prefixes and re-allocating these that are
// reclaimed.
TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPoolWithReclamations) {
// Remove the default pool because it is too large for this test case.
subnet_->delPools(Lease::TYPE_PD);
// Add a smaller pool.
auto pool = boost::make_shared<Pool6>(Lease::TYPE_PD,
IOAddress("3000::"),
120,
128);
subnet_->addPool(pool);
FreeLeaseQueueAllocator alloc(Lease::TYPE_PD, subnet_);
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
// Remember returned addresses, so we can verify that unique addresses
// are returned.
std::map<IOAddress, Lease6Ptr> leases;
for (auto i = 0; i < 256; ++i) {
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
EXPECT_FALSE(candidate.isV6Zero());
auto lease = createLease6(Lease::TYPE_PD, candidate, i);
leases[candidate] = lease;
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate, cc_));
EXPECT_TRUE(lease_mgr.addLease(lease));
}
// The pool comprises 256 delegated prefixes. All should be returned.
EXPECT_EQ(256, leases.size());
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
EXPECT_TRUE(candidate.isV6Zero());
double r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
EXPECT_EQ(1., r);
auto i = 0;
for (auto const& address_lease : leases) {
if (i % 2) {
auto lease = address_lease.second;
lease->state_ = Lease::STATE_EXPIRED_RECLAIMED;
EXPECT_NO_THROW(lease_mgr.updateLease6(lease));
}
++i;
}
r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
EXPECT_EQ(.5, r);
for (auto j = 0; j < 128; ++j) {
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate, cc_));
auto lease = lease_mgr.getLease6(Lease::TYPE_PD, candidate);
lease->state_ = Lease::STATE_DEFAULT;
EXPECT_NO_THROW(lease_mgr.updateLease6(lease));
}
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
EXPECT_TRUE(candidate.isV6Zero());
r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
EXPECT_EQ(1., r);
}
// Test allocating delegated prefixes from multiple pools.
TEST_F(FreeLeaseQueueAllocatorTest6, manyPdPools) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_PD, subnet_);
for (auto i = 0; i < 10; ++i) {
ostringstream s;
s << "300" << hex << i + 1 << "::";
auto pool = boost::make_shared<Pool6>(Lease::TYPE_PD,
IOAddress(s.str()),
120,
128);
subnet_->addPool(pool);
}
size_t total = 65536 + 10 * 256;
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
Pool6Ptr pool;
std::set<IOAddress> prefixes;
for (size_t i = 0; i < total; ++i) {
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
EXPECT_TRUE(pool);
EXPECT_FALSE(candidate.isV6Zero());
EXPECT_TRUE(lease_mgr.addLease(createLease6(Lease::TYPE_PD, candidate, i)));
prefixes.insert(candidate);
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate, cc_));
}
// Make sure that unique prefixes have been returned.
EXPECT_EQ(total, prefixes.size());
double r = alloc.getOccupancyRate(IOAddress("3001::"), 128, cc_);
EXPECT_EQ(1., r);
}
// Test allocating delegated prefixes from multiple pools.
TEST_F(FreeLeaseQueueAllocatorTest6, manyPdPoolsPreferLower) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_PD, subnet_);
for (auto i = 0; i < 10; ++i) {
ostringstream s;
s << "300" << hex << i + 1 << "::";
auto pool = boost::make_shared<Pool6>(Lease::TYPE_PD,
IOAddress(s.str()),
120,
128);
subnet_->addPool(pool);
}
size_t total = 65536;
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
Pool6Ptr pool;
std::set<IOAddress> prefixes;
for (size_t i = 0; i < total; ++i) {
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_LOWER, IOAddress("::"), 120);
EXPECT_FALSE(candidate.isV6Zero());
EXPECT_TRUE(lease_mgr.addLease(createLease6(Lease::TYPE_PD, candidate, i)));
prefixes.insert(candidate);
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate, cc_));
}
// Make sure that unique prefixes have been returned.
EXPECT_EQ(total, prefixes.size());
double r = alloc.getOccupancyRate(IOAddress("2001:db8:1:2::"), 120, cc_);
EXPECT_EQ(1., r);
r = alloc.getOccupancyRate(IOAddress("2001:db8:1:2::"), 128, cc_);
EXPECT_EQ(65536. / 68096., r);
r = alloc.getOccupancyRate(IOAddress("2001:db8:1:2::"), 64, cc_);
EXPECT_EQ(0., r);
}
// Test allocating delegated prefixes from multiple pools.
TEST_F(FreeLeaseQueueAllocatorTest6, manyPdPoolsPreferEqual) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_PD, subnet_);
for (auto i = 0; i < 10; ++i) {
ostringstream s;
s << "300" << hex << i + 1 << "::";
auto pool = boost::make_shared<Pool6>(Lease::TYPE_PD,
IOAddress(s.str()),
120,
128);
subnet_->addPool(pool);
}
size_t total = 10 * 256;
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
Pool6Ptr pool;
std::set<IOAddress> prefixes;
for (size_t i = 0; i < total; ++i) {
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_EQUAL, IOAddress("::"), 128);
EXPECT_FALSE(candidate.isV6Zero());
EXPECT_TRUE(lease_mgr.addLease(createLease6(Lease::TYPE_PD, candidate, i)));
prefixes.insert(candidate);
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate, cc_));
}
// Make sure that unique prefixes have been returned.
EXPECT_EQ(total, prefixes.size());
double r = alloc.getOccupancyRate(IOAddress("3001::"), 128, cc_);
EXPECT_EQ(2560. / 68096., r);
}
// Test allocating delegated prefixes from multiple pools.
TEST_F(FreeLeaseQueueAllocatorTest6, manyPdPoolsPreferHigher) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_PD, subnet_);
for (auto i = 0; i < 10; ++i) {
ostringstream s;
s << "300" << hex << i + 1 << "::";
auto pool = boost::make_shared<Pool6>(Lease::TYPE_PD,
IOAddress(s.str()),
120,
128);
subnet_->addPool(pool);
}
size_t total = 10 * 256;
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
Pool6Ptr pool;
std::set<IOAddress> prefixes;
for (size_t i = 0; i < total; ++i) {
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 64);
EXPECT_FALSE(candidate.isV6Zero());
EXPECT_TRUE(lease_mgr.addLease(createLease6(Lease::TYPE_PD, candidate, i)));
prefixes.insert(candidate);
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate, cc_));
}
// Make sure that unique prefixes have been returned.
EXPECT_EQ(total, prefixes.size());
double r = alloc.getOccupancyRate(IOAddress("3001::"), 128, cc_);
EXPECT_EQ(2560. / 68096., r);
}
// Test that the allocator respects client class guards.
TEST_F(FreeLeaseQueueAllocatorTest6, pdPoolsClientClasses) {
FreeLeaseQueueAllocator alloc(Lease::TYPE_PD, subnet_);
// First pool only allows the client class foo.
pd_pool_->allowClientClass("foo");
auto pool2 = boost::make_shared<Pool6>(Lease::TYPE_PD,
IOAddress("3000:1::"),
120,
128);
// Second pool only allows the client class bar.
pool2->allowClientClass("bar");
subnet_->addPool(pool2);
ASSERT_NO_THROW(alloc.initAfterConfigure());
auto& lease_mgr = LeaseMgrFactory::instance();
Pool6Ptr pool;
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 64);
EXPECT_TRUE(candidate.isV6Zero());
cc_.insert("bar");
for (auto i = 0; i < 256; ++i) {
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 64);
EXPECT_FALSE(candidate.isV6Zero());
EXPECT_TRUE(lease_mgr.addLease(createLease6(Lease::TYPE_PD, candidate, i)));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate));
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_PD, candidate, cc_));
}
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 64);
EXPECT_TRUE(candidate.isV6Zero());
double r = alloc.getOccupancyRate(IOAddress("3000:1::"), 128, cc_);
EXPECT_EQ(1., r);
cc_.insert("foo");
r = alloc.getOccupancyRate(IOAddress("3000:1::"), 128, cc_);
EXPECT_EQ(256. / 65792., r);
cc_.clear();
r = alloc.getOccupancyRate(IOAddress("3000:1::"), 128, cc_);
EXPECT_EQ(0., r);
}
} // end of isc::dhcp::test namespace
} // end of isc::dhcp namespace
} // end of isc namespace