Kea 2.7.5
random_allocator.cc
Go to the documentation of this file.
1// Copyright (C) 2022-2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <dhcpsrv/subnet.h>
11#include <algorithm>
12#include <random>
13
14using namespace isc::asiolink;
15using namespace std;
16
17namespace isc {
18namespace dhcp {
19
21 : Allocator(type, subnet), generator_() {
22 random_device rd;
23 generator_.seed(rd());
24}
25
27RandomAllocator::pickAddressInternal(const ClientClasses& client_classes,
29 const IOAddress&) {
30 auto subnet = subnet_.lock();
31 auto const& pools = subnet->getPools(pool_type_);
32
33 // Let's first iterate over the pools and identify the ones that
34 // meet client class criteria. Then, segregate these pools into
35 // the ones that still have available addresses and exhausted
36 // ones.
37 std::vector<uint64_t> available;
38 std::vector<uint64_t> exhausted;
39 for (auto i = 0; i < pools.size(); ++i) {
40 // Check if the pool is allowed for the client's classes.
41 if (pools[i]->clientSupported(client_classes)) {
42 // Get or create the pool state.
43 auto state = getPoolState(pools[i]);
44 if (state->getPermutation()->exhausted()) {
45 // Pool is exhausted. It means that all addresses from
46 // this pool have been offered. It doesn't mean that
47 // leases are allocated for all these addresses. It
48 // only means that all have been picked from the pool.
49 exhausted.push_back(i);
50 } else {
51 // There are still available addresses in this pool. It
52 // means that not all of them have been offered.
53 available.push_back(i);
54 }
55 }
56 }
57 // Find a suitable pool.
58 PoolPtr pool;
59 if (!available.empty()) {
60 // There are pools with available addresses. Let's randomly
61 // pick one of these pools and get next available address.
62 pool = pools[available[getRandomNumber(available.size() - 1)]];
63
64 } else if (!exhausted.empty()) {
65 // All pools have been exhausted. We will start offering the same
66 // addresses from these pools. We need to reset the permutations
67 // of the exhausted pools.
68 for (auto const& e : exhausted) {
69 getPoolState(pools[e])->getPermutation()->reset();
70 }
71 // Get random pool from those we just reset.
72 pool = pools[exhausted[getRandomNumber(exhausted.size() - 1)]];
73 }
74
75 // If pool has been found, let's get next address.
76 if (pool) {
77 auto done = false;
78 return (getPoolState(pool)->getPermutation()->next(done));
79 }
80
81 // No pool available. There are no pools or client classes do
82 // not match.
83 return (pool_type_ == Lease::TYPE_V4 ? IOAddress::IPV4_ZERO_ADDRESS() : IOAddress::IPV6_ZERO_ADDRESS());
84}
85
87RandomAllocator::pickPrefixInternal(const ClientClasses& client_classes,
88 Pool6Ptr& pool6,
90 PrefixLenMatchType prefix_length_match,
91 const IOAddress&,
92 uint8_t hint_prefix_length) {
93 auto subnet = subnet_.lock();
94 auto const& pools = subnet->getPools(pool_type_);
95
96 // Let's first iterate over the pools and identify the ones that
97 // meet client class criteria. Then, segragate these pools into
98 // the ones that still have available addresses and exhausted
99 // ones.
100 std::vector<uint64_t> available;
101 std::vector<uint64_t> exhausted;
102 for (auto i = 0; i < pools.size(); ++i) {
103 // Check if the pool is allowed for the client's classes.
104 if (pools[i]->clientSupported(client_classes)) {
105 if (!Allocator::isValidPrefixPool(prefix_length_match, pools[i],
106 hint_prefix_length)) {
107 continue;
108 }
109 // Get or create the pool state.
110 auto state = getPoolState(pools[i]);
111 if (state->getPermutation()->exhausted()) {
112 // Pool is exhausted. It means that all prefixes from
113 // this pool have been offered. It doesn't mean that
114 // leases are allocated for all these prefixes. It
115 // only means that all have been picked from the pool.
116 exhausted.push_back(i);
117 } else {
118 // There are still available prefixes in this pool. It
119 // means that not all of them have been offered.
120 available.push_back(i);
121 }
122 }
123 }
124 // Find a suitable pool.
125 PoolPtr pool;
126 if (!available.empty()) {
127 // There are pools with available prefixes. Let's randomly
128 // pick one of these pools and get next available prefix.
129 pool = pools[available[getRandomNumber(available.size() - 1)]];
130
131 } else if (!exhausted.empty()) {
132 // All pools have been exhausted. We will start offering the same
133 // prefixes from these pools. We need to reset the permutations
134 // of the exhausted pools.
135 for (auto const& e : exhausted) {
136 getPoolState(pools[e])->getPermutation()->reset();
137 }
138 // Get random pool from those we just reset.
139 pool = pools[exhausted[getRandomNumber(exhausted.size() - 1)]];
140 }
141
142 // If pool has been found, let's get next prefix.
143 if (pool) {
144 auto done = false;
145 pool6 = boost::dynamic_pointer_cast<Pool6>(pool);
146
147 if (!pool6) {
148 // Something is gravely wrong here
149 isc_throw(Unexpected, "Wrong type of pool: "
150 << (pool)->toText()
151 << " is not Pool6");
152 }
153 return (getPoolState(pool)->getPermutation()->next(done));
154 }
155
156 // No pool available. There are no pools or client classes do
157 // not match.
159}
160
162RandomAllocator::getPoolState(const PoolPtr& pool) const {
163 if (!pool->getAllocationState()) {
164 pool->setAllocationState(PoolRandomAllocationState::create(pool));
165 }
166 return (boost::dynamic_pointer_cast<PoolRandomAllocationState>(pool->getAllocationState()));
167}
168
169uint64_t
170RandomAllocator::getRandomNumber(uint64_t limit) {
171 // Take the short path if there is only one number to randomize from.
172 if (limit == 0) {
173 return 0;
174 }
175 std::uniform_int_distribution<uint64_t> dist(0, limit);
176 return (dist(generator_));
177}
178
179} // end of namespace isc::dhcp
180} // end of namespace isc
A generic exception that is thrown when an unexpected error condition occurs.
Base class for all address/prefix allocation algorithms.
Definition allocator.h:57
Lease::Type pool_type_
Defines pool type allocation.
Definition allocator.h:226
WeakSubnetPtr subnet_
Weak pointer to the subnet owning the allocator.
Definition allocator.h:232
static bool isValidPrefixPool(Allocator::PrefixLenMatchType prefix_length_match, PoolPtr pool, uint8_t hint_prefix_length)
Check if the pool matches the selection criteria relative to the provided hint prefix length.
Definition allocator.cc:38
Container for storing client class names.
Definition classify.h:108
static PoolRandomAllocationStatePtr create(const PoolPtr &pool)
Factory function creating the state instance from pool.
RandomAllocator(Lease::Type type, const WeakSubnetPtr &subnet)
Constructor.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< PoolRandomAllocationState > PoolRandomAllocationStatePtr
Type of the pointer to the PoolRandomAllocationState.
boost::weak_ptr< Subnet > WeakSubnetPtr
Weak pointer to the Subnet.
Definition allocator.h:32
boost::shared_ptr< IdentifierBaseType > IdentifierBaseTypePtr
Shared pointer to a IdentifierType.
Definition duid.h:34
boost::shared_ptr< Pool > PoolPtr
a pointer to either IPv4 or IPv6 Pool
Definition pool.h:488
boost::shared_ptr< Pool6 > Pool6Ptr
a pointer an IPv6 Pool
Definition pool.h:298
Defines the logger used by the top-level component of kea-lfc.
Type
Type of lease or pool.
Definition lease.h:46
@ TYPE_V4
IPv4 lease.
Definition lease.h:50