Kea 3.1.9
sflq_allocator.cc
Go to the documentation of this file.
1// Copyright (C) 2026 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/dhcpsrv_log.h>
13#include <dhcpsrv/subnet.h>
14#include <util/stopwatch.h>
15#include <limits>
16
17using namespace isc::asiolink;
18using namespace isc::util;
19using namespace std;
20
21namespace isc {
22 bool sflq_in_use_ = false;
23}
24
25namespace isc {
26namespace dhcp {
27
30
31void
33 sflq_in_use_ = in_use;
34}
35
36bool
40
42 : Allocator(type, subnet), generator_() {
43 random_device rd;
44 generator_.seed(rd());
45}
46
47void
49 auto subnet = subnet_.lock();
50 auto const& pools = subnet->getPools(pool_type_);
51 if (pools.empty()) {
52 // If there are no pools there is nothing to do.
53 return;
54 }
55
56 // Set static class flag marking at least one pool is using SFlq.
57 setInUse(true);
58
59 for (const auto& pool : pools) {
60 switch (pool_type_) {
61 case Lease::TYPE_V4:
62 LeaseMgrFactory::instance().sflqCreateFlqPool4(pool->getFirstAddress(),
63 pool->getLastAddress(),
64 subnet->getID(), false);
65 break;
66 case Lease::TYPE_NA:
67 LeaseMgrFactory::instance().sflqCreateFlqPool6(pool->getFirstAddress(),
68 pool->getLastAddress(),
69 Lease::TYPE_NA, 128,
70 subnet->getID(), false);
71 break;
72 case Lease::TYPE_PD: {
73 auto pdpool = boost::dynamic_pointer_cast<Pool6>(pool);
74 LeaseMgrFactory::instance().sflqCreateFlqPool6(pool->getFirstAddress(),
75 pool->getLastAddress(),
76 Lease::TYPE_PD, pdpool->getLength(),
77 subnet->getID(), false);
78 break;
79 }
80 default:
81 ;
82 }
83 }
84}
85
87SharedFlqAllocator::pickAddressInternal(const ClientClasses& client_classes,
89 const IOAddress&) {
90 // Let's iterate over the subnet's pools and identify the ones that
91 // meet client class criteria.
92 auto subnet = subnet_.lock();
93 auto const& pools = subnet->getPools(pool_type_);
94 std::vector<PoolPtr> available;
95 for (auto const& pool : pools) {
96 // Check if the pool is allowed for the client's classes.
97 if (pool->clientSupported(client_classes)) {
98 available.push_back(pool);
99 }
100 }
101
102 // Try each pool in random order.
103 while (available.size()) {
104 // Get a random pool from the available ones.
105 auto offset = getRandomNumber(available.size() - 1);
106 PoolPtr const pool = available[offset];
107 switch (pool_type_) {
108 case Lease::TYPE_V4: {
109 // Ask the lease manager for a lease from the pool.
110 auto free_lease = LeaseMgrFactory::instance()
111 .sflqPickFreeLease4(pool->getFirstAddress(),
112 pool->getLastAddress());
113 if (!free_lease.isV4Zero()) {
114 getSubnetState()->setLastAllocatedTime();
115 return (free_lease);
116 }
117
118 break;
119 }
120 case Lease::TYPE_NA:{
121 auto free_lease = LeaseMgrFactory::instance()
122 .sflqPickFreeLease6(pool->getFirstAddress(),
123 pool->getLastAddress());
124 if (!free_lease.isV6Zero()) {
125 getSubnetState()->setLastAllocatedTime();
126 return (free_lease);
127 }
128
129 break;
130 }
131 case Lease::TYPE_PD:
132 isc_throw(Unexpected, "pickAddressInternal called for Lease::TYPE_PD");
133 break;
134 default:
135 isc_throw(Unexpected, "pickAddressInternal called for unknown lease type " << pool_type_);
136 break;
137 }
138
139 // Remove the exhausted pool from the list then try another one.
140 available.erase(available.begin() + offset);
141 }
142
143 // No address available.
146}
147
149SharedFlqAllocator::pickPrefixInternal(const ClientClasses& client_classes,
150 Pool6Ptr& /* pool6 */,
152 PrefixLenMatchType prefix_length_match,
153 const IOAddress&,
154 uint8_t hint_prefix_length) {
155 // Let's iterate over the subnet's pools and identify the ones that
156 // meet client class criteria.
157 auto subnet = subnet_.lock();
158 auto const& pools = subnet->getPools(pool_type_);
159 std::vector<PoolPtr> available;
160 for (auto const& pool : pools) {
161 // Check if the pool is allowed for the client's classes.
162 if (pool->clientSupported(client_classes)) {
163 if (!Allocator::isValidPrefixPool(prefix_length_match, pool,
164 hint_prefix_length)) {
165 continue;
166 }
167
168 available.push_back(pool);
169 }
170 }
171
172 // Try each pool in random order.
173 while (available.size()) {
174 // Get a random pool from the available ones.
175 auto offset = getRandomNumber(available.size() - 1);
176 PoolPtr const pool = available[offset];
177 switch(pool_type_) {
178 case Lease::TYPE_V4:
179 isc_throw(Unexpected, "pickPrefixInternal called for Lease::TYPE_V4");
180 break;
181 case Lease::TYPE_NA:
182 isc_throw(Unexpected, "pickPrefixInternal called for Lease::TYPE_NA");
183 break;
184 case Lease::TYPE_PD:{
185 // Ask the lease manager for a lease from the pool.
186 auto free_lease = LeaseMgrFactory::instance()
187 .sflqPickFreeLease6(pool->getFirstAddress(),
188 pool->getLastAddress());
189 if (!free_lease.isV6Zero()) {
190 getSubnetState()->setLastAllocatedTime();
191 return (free_lease);
192 }
193 }
194 break;
195 default:
196 isc_throw(Unexpected, "pickPrefixInternal called for unknown lease type " << pool_type_);
197 break;
198 }
199
200 // Remove the exhausted pool from the list then try another one.
201 available.erase(available.begin() + offset);
202 }
203
204 // No address available.
206}
207
208uint64_t
209SharedFlqAllocator::getRandomNumber(uint64_t limit) {
210 // Take the short path if there is only one number to randomize from.
211 if (limit == 0) {
212 return (0);
213 }
214 std::uniform_int_distribution<uint64_t> dist(0, limit);
215 return (dist(generator_));
216}
217
220 auto subnet = subnet_.lock();
221 if (!subnet->getAllocationState(pool_type_)) {
222 subnet->setAllocationState(Lease::TYPE_V4,
223 boost::make_shared<SubnetSflqAllocationState>());
224 }
225
227 state = boost::dynamic_pointer_cast<SubnetSflqAllocationState>
228 (subnet->getAllocationState(pool_type_));
229 if (!state) {
230 isc_throw(Unexpected, "SharedFlqAllocator::getSubnetState - wrong allocation state type");
231 }
232
233 return (state);
234}
235
236void
238 for (auto const& pool : subnet->getPools(Lease::TYPE_V4)) {
239 auto const& capacity(pool->getCapacity());
240 if (capacity > MAX_V4_POOL_SIZE) {
241 isc_throw(BadValue, "pool capacity " << capacity
242 << " exceeds limit of " << MAX_V4_POOL_SIZE
243 << " for shared-flq allocator on V4 pool "
244 << pool->toText());
245 }
246 }
247}
248
249void
251 if (subnet->getAllocatorType() == "shared-flq") {
252 for (auto const& pool : subnet->getPools(Lease::TYPE_NA)) {
253 auto const& capacity(pool->getCapacity());
254 if (capacity > MAX_V6_POOL_SIZE) {
255 isc_throw(BadValue, "pool capacity " << capacity
256 << " exceeds limit of " << MAX_V6_POOL_SIZE
257 << " for shared-flq allocator on V6 pool "
258 << pool->toText());
259 }
260 }
261 }
262
263 if (subnet->getPdAllocatorType() == "shared-flq") {
264 for (auto const& pool : subnet->getPools(Lease::TYPE_PD)) {
265 auto const& capacity(pool->getCapacity());
266 if (capacity > MAX_V6_POOL_SIZE) {
267 isc_throw(BadValue, "pool capacity " << capacity
268 << " exceeds limit of " << MAX_V6_POOL_SIZE
269 << " for shared-flq allocator on V6 pool "
270 << pool->toText());
271 }
272 }
273 }
274}
275
276} // end of namespace isc::dhcp
277} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown when an unexpected error condition occurs.
virtual void initAfterConfigureInternal()
Allocator-specific initialization function.
Definition allocator.h:202
Lease::Type pool_type_
Defines pool type allocation.
Definition allocator.h:256
Allocator(Lease::Type type, const WeakSubnetPtr &subnet)
Constructor.
Definition allocator.cc:17
WeakSubnetPtr subnet_
Weak pointer to the subnet owning the allocator.
Definition allocator.h:262
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:110
static TrackingLeaseMgr & instance()
Return current lease manager.
virtual asiolink::IOAddress sflqPickFreeLease4(asiolink::IOAddress start_address, asiolink::IOAddress end_address)
Finds a free V4 address within the given pool range.
virtual bool sflqCreateFlqPool4(asiolink::IOAddress start_address, asiolink::IOAddress end_address, SubnetID subnet_id, bool recreate=false)
Creates a v4 SFLQ Pool.
virtual asiolink::IOAddress sflqPickFreeLease6(asiolink::IOAddress start_address, asiolink::IOAddress end_address)
Finds a free V6 address/prefix within the given pool range.
virtual bool sflqCreateFlqPool6(asiolink::IOAddress start_address, asiolink::IOAddress end_address, Lease::Type lease_type, uint8_t delegated_len, SubnetID subnet_id, bool recreate=false)
Calls stored procedure to create an SFLQ pool for v6.
static void setInUse(bool in_use)
Sets the global in-use flag.
static bool inUse()
Returns the global in-use flag.
static void sanityChecksSflqAllocator6(Subnet6Ptr subnet)
Sanity checks the subnet and pool configuration for use with SFLQ.
static void sanityChecksSflqAllocator4(Subnet4Ptr subnet)
Sanity checks the subnet and pool configuration for use with SFLQ.
SubnetSflqAllocationStatePtr getSubnetState() const
Returns the allocation state for the subnet pool_type;.
static constexpr size_t MAX_V6_POOL_SIZE
Maximum capacity of a V6 pool supported by SFLQ.
SharedFlqAllocator(Lease::Type type, const WeakSubnetPtr &subnet)
Constructor.
static constexpr size_t MAX_V4_POOL_SIZE
Maximum capacity of a V4 pool supported by SFLQ.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition subnet.h:458
boost::weak_ptr< Subnet > WeakSubnetPtr
Weak pointer to the Subnet.
Definition allocator.h:32
boost::shared_ptr< Subnet6 > Subnet6Ptr
A pointer to a Subnet6 object.
Definition subnet.h:623
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:726
boost::shared_ptr< SubnetSflqAllocationState > SubnetSflqAllocationStatePtr
Type of the pointer to the SubnetSflqAllocationState.
boost::shared_ptr< Pool6 > Pool6Ptr
a pointer an IPv6 Pool
Definition pool.h:536
Defines the logger used by the top-level component of kea-lfc.
bool sflq_in_use_
Type
Type of lease or pool.
Definition lease.h:46
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition lease.h:49
@ TYPE_V4
IPv4 lease.
Definition lease.h:50
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition lease.h:47