Kea 3.1.8
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 case Lease::TYPE_TA:{
122 auto free_lease = LeaseMgrFactory::instance()
123 .sflqPickFreeLease6(pool->getFirstAddress(),
124 pool->getLastAddress());
125 if (!free_lease.isV6Zero()) {
126 getSubnetState()->setLastAllocatedTime();
127 return (free_lease);
128 }
129
130 break;
131 }
132 case Lease::TYPE_PD:
133 isc_throw(Unexpected, "pickAddressInternal called for Lease::TYPE_PD");
134 break;
135 }
136
137 // Remove the exhausted pool from the list then try another one.
138 available.erase(available.begin() + offset);
139 }
140
141 // No address available.
144}
145
147SharedFlqAllocator::pickPrefixInternal(const ClientClasses& client_classes,
148 Pool6Ptr& /* pool6 */,
150 PrefixLenMatchType prefix_length_match,
151 const IOAddress&,
152 uint8_t hint_prefix_length) {
153 // Let's iterate over the subnet's pools and identify the ones that
154 // meet client class criteria.
155 auto subnet = subnet_.lock();
156 auto const& pools = subnet->getPools(pool_type_);
157 std::vector<PoolPtr> available;
158 for (auto const& pool : pools) {
159 // Check if the pool is allowed for the client's classes.
160 if (pool->clientSupported(client_classes)) {
161 if (!Allocator::isValidPrefixPool(prefix_length_match, pool,
162 hint_prefix_length)) {
163 continue;
164 }
165
166 available.push_back(pool);
167 }
168 }
169
170 // Try each pool in random order.
171 while (available.size()) {
172 // Get a random pool from the available ones.
173 auto offset = getRandomNumber(available.size() - 1);
174 PoolPtr const pool = available[offset];
175 switch(pool_type_) {
176 case Lease::TYPE_V4:
177 isc_throw(Unexpected, "pickAddressInternal called for Lease::TYPE_V4");
178 break;
179 case Lease::TYPE_NA:
180 case Lease::TYPE_TA:
181 isc_throw(Unexpected, "pickAddressInternal called for Lease::TYPE_NA");
182 break;
183 case Lease::TYPE_PD:
184 // Ask the lease manager for a lease from the pool.
185 auto free_lease = LeaseMgrFactory::instance()
186 .sflqPickFreeLease6(pool->getFirstAddress(),
187 pool->getLastAddress());
188 if (!free_lease.isV6Zero()) {
189 getSubnetState()->setLastAllocatedTime();
190 return (free_lease);
191 }
192
193 break;
194 }
195
196 // Remove the exhausted pool from the list then try another one.
197 available.erase(available.begin() + offset);
198 }
199
200 // No address available.
202}
203
204uint64_t
205SharedFlqAllocator::getRandomNumber(uint64_t limit) {
206 // Take the short path if there is only one number to randomize from.
207 if (limit == 0) {
208 return (0);
209 }
210 std::uniform_int_distribution<uint64_t> dist(0, limit);
211 return (dist(generator_));
212}
213
216 auto subnet = subnet_.lock();
217 if (!subnet->getAllocationState(pool_type_)) {
218 subnet->setAllocationState(Lease::TYPE_V4,
219 boost::make_shared<SubnetSflqAllocationState>());
220 }
221
223 state = boost::dynamic_pointer_cast<SubnetSflqAllocationState>
224 (subnet->getAllocationState(pool_type_));
225 if (!state) {
226 isc_throw(Unexpected, "SharedFlqAllocator::getSubnetState - wrong allocation state type");
227 }
228
229 return (state);
230}
231
232void
234 for (auto const& pool : subnet->getPools(Lease::TYPE_V4)) {
235 auto const& capacity(pool->getCapacity());
236 if (capacity > MAX_V4_POOL_SIZE) {
237 isc_throw(BadValue, "pool capacity " << capacity
238 << " exceeds limit of " << MAX_V4_POOL_SIZE
239 << " for shared-flq allocator on V4 pool "
240 << pool->toText());
241 }
242 }
243}
244
245void
247 if (subnet->getAllocatorType() == "shared-flq") {
248 for (auto const& pool : subnet->getPools(Lease::TYPE_NA)) {
249 auto const& capacity(pool->getCapacity());
250 if (capacity > MAX_V6_POOL_SIZE) {
251 isc_throw(BadValue, "pool capacity " << capacity
252 << " exceeds limit of " << MAX_V6_POOL_SIZE
253 << " for shared-flq allocator on V6 pool "
254 << pool->toText());
255 }
256 }
257 }
258
259 if (subnet->getPdAllocatorType() == "shared-flq") {
260 for (auto const& pool : subnet->getPools(Lease::TYPE_PD)) {
261 auto const& capacity(pool->getCapacity());
262 if (capacity > MAX_V6_POOL_SIZE) {
263 isc_throw(BadValue, "pool capacity " << capacity
264 << " exceeds limit of " << MAX_V6_POOL_SIZE
265 << " for shared-flq allocator on V6 pool "
266 << pool->toText());
267 }
268 }
269 }
270}
271
272} // end of namespace isc::dhcp
273} // 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:461
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:626
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_TA
the lease contains temporary IPv6 address
Definition lease.h:48
@ 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