Kea: sflq_allocator.cc Source File

| Kea 3.2.0-git

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
9#include <asiolink/addr_utilities.h>
10#include <dhcpsrv/dhcpsrv_log.h>
11#include <dhcpsrv/sflq_allocator.h>
12#include <dhcpsrv/lease_mgr_factory.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
28constexpr size_t SharedFlqAllocator::MAX_V4_POOL_SIZE;
29constexpr size_t SharedFlqAllocator::MAX_V6_POOL_SIZE;
30
31void
32SharedFlqAllocator::setInUse(bool in_use) {
33 sflq_in_use_ = in_use;
34}
35
36bool
37SharedFlqAllocator::inUse() {
38 return (sflq_in_use_);
39}
40
41SharedFlqAllocator::SharedFlqAllocator(Lease::Type type, const WeakSubnetPtr& subnet)
42 : Allocator(type, subnet), generator_() {
43 random_device rd;
44 generator_.seed(rd());
45}
46
47void
48 SharedFlqAllocator::initAfterConfigureInternal() {
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
86 IOAddress
87SharedFlqAllocator::pickAddressInternal(const ClientClasses& client_classes,
88 const IdentifierBaseTypePtr&,
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.
144 return (pool_type_ == Lease::TYPE_V4 ? IOAddress::IPV4_ZERO_ADDRESS()
145 : IOAddress::IPV6_ZERO_ADDRESS());
146}
147
148 IOAddress
149SharedFlqAllocator::pickPrefixInternal(const ClientClasses& client_classes,
150 Pool6Ptr& /* pool6 */,
151 const IdentifierBaseTypePtr&,
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.
205 return (IOAddress::IPV6_ZERO_ADDRESS());
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
218 SubnetSflqAllocationStatePtr
219SharedFlqAllocator::getSubnetState() const {
220 auto subnet = subnet_.lock();
221 if (!subnet->getAllocationState(pool_type_)) {
222 subnet->setAllocationState(Lease::TYPE_V4,
223 boost::make_shared<SubnetSflqAllocationState>());
224 }
225
226 SubnetSflqAllocationStatePtr state;
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
237SharedFlqAllocator::sanityChecksSflqAllocator4(Subnet4Ptr subnet) {
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
250SharedFlqAllocator::sanityChecksSflqAllocator6(Subnet6Ptr subnet) {
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
addr_utilities.h
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition exceptions/exceptions.h:132
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition exceptions/exceptions.h:153
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic).
Definition io_address.h:53
isc::asiolink::IOAddress::IPV4_ZERO_ADDRESS
static const IOAddress & IPV4_ZERO_ADDRESS()
Returns an address set to all zeros.
Definition io_address.h:285
isc::asiolink::IOAddress::IPV6_ZERO_ADDRESS
static const IOAddress & IPV6_ZERO_ADDRESS()
Returns an IPv6 zero address.
Definition io_address.h:297
isc::dhcp::Allocator::initAfterConfigureInternal
virtual void initAfterConfigureInternal()
Allocator-specific initialization function.
Definition allocator.h:202
isc::dhcp::Allocator::pool_type_
Lease::Type pool_type_
Defines pool type allocation.
Definition allocator.h:256
isc::dhcp::Allocator::Allocator
Allocator(Lease::Type type, const WeakSubnetPtr &subnet)
Constructor.
Definition allocator.cc:17
isc::dhcp::Allocator::subnet_
WeakSubnetPtr subnet_
Weak pointer to the subnet owning the allocator.
Definition allocator.h:262
isc::dhcp::Allocator::isValidPrefixPool
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
isc::dhcp::ClientClasses
Container for storing client class names.
Definition classify.h:110
isc::dhcp::LeaseMgrFactory::instance
static TrackingLeaseMgr & instance()
Return current lease manager.
Definition lease_mgr_factory.cc:148
isc::dhcp::LeaseMgr::sflqPickFreeLease4
virtual asiolink::IOAddress sflqPickFreeLease4(asiolink::IOAddress start_address, asiolink::IOAddress end_address)
Finds a free V4 address within the given pool range.
Definition lease_mgr.cc:1996
isc::dhcp::LeaseMgr::sflqCreateFlqPool4
virtual bool sflqCreateFlqPool4(asiolink::IOAddress start_address, asiolink::IOAddress end_address, SubnetID subnet_id, bool recreate=false)
Creates a v4 SFLQ Pool.
Definition lease_mgr.cc:1991
isc::dhcp::LeaseMgr::sflqPickFreeLease6
virtual asiolink::IOAddress sflqPickFreeLease6(asiolink::IOAddress start_address, asiolink::IOAddress end_address)
Finds a free V6 address/prefix within the given pool range.
Definition lease_mgr.cc:2006
isc::dhcp::LeaseMgr::sflqCreateFlqPool6
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.
Definition lease_mgr.cc:2001
isc::dhcp::SharedFlqAllocator::setInUse
static void setInUse(bool in_use)
Sets the global in-use flag.
Definition sflq_allocator.cc:32
isc::dhcp::SharedFlqAllocator::inUse
static bool inUse()
Returns the global in-use flag.
Definition sflq_allocator.cc:37
isc::dhcp::SharedFlqAllocator::sanityChecksSflqAllocator6
static void sanityChecksSflqAllocator6(Subnet6Ptr subnet)
Sanity checks the subnet and pool configuration for use with SFLQ.
Definition sflq_allocator.cc:250
isc::dhcp::SharedFlqAllocator::sanityChecksSflqAllocator4
static void sanityChecksSflqAllocator4(Subnet4Ptr subnet)
Sanity checks the subnet and pool configuration for use with SFLQ.
Definition sflq_allocator.cc:237
isc::dhcp::SharedFlqAllocator::getSubnetState
SubnetSflqAllocationStatePtr getSubnetState() const
Returns the allocation state for the subnet pool_type;.
Definition sflq_allocator.cc:219
isc::dhcp::SharedFlqAllocator::MAX_V6_POOL_SIZE
static constexpr size_t MAX_V6_POOL_SIZE
Maximum capacity of a V6 pool supported by SFLQ.
Definition sflq_allocator.h:100
isc::dhcp::SharedFlqAllocator::SharedFlqAllocator
SharedFlqAllocator(Lease::Type type, const WeakSubnetPtr &subnet)
Constructor.
Definition sflq_allocator.cc:41
isc::dhcp::SharedFlqAllocator::MAX_V4_POOL_SIZE
static constexpr size_t MAX_V4_POOL_SIZE
Maximum capacity of a V4 pool supported by SFLQ.
Definition sflq_allocator.h:97
dhcpsrv_log.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
lease_mgr_factory.h
isc::asiolink
Definition addr_utilities.cc:170
isc::dhcp
Definition dhcp4/client_handler.cc:20
isc::dhcp::Subnet4Ptr
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition subnet.h:458
isc::dhcp::WeakSubnetPtr
boost::weak_ptr< Subnet > WeakSubnetPtr
Weak pointer to the Subnet.
Definition allocator.h:32
isc::dhcp::Subnet6Ptr
boost::shared_ptr< Subnet6 > Subnet6Ptr
A pointer to a Subnet6 object.
Definition subnet.h:623
isc::dhcp::IdentifierBaseTypePtr
boost::shared_ptr< IdentifierBaseType > IdentifierBaseTypePtr
Shared pointer to a IdentifierType.
Definition duid.h:34
isc::dhcp::PoolPtr
boost::shared_ptr< Pool > PoolPtr
a pointer to either IPv4 or IPv6 Pool
Definition pool.h:726
isc::dhcp::SubnetSflqAllocationStatePtr
boost::shared_ptr< SubnetSflqAllocationState > SubnetSflqAllocationStatePtr
Type of the pointer to the SubnetSflqAllocationState.
Definition sflq_allocation_state.h:25
isc::dhcp::Pool6Ptr
boost::shared_ptr< Pool6 > Pool6Ptr
a pointer an IPv6 Pool
Definition pool.h:536
isc::util
Definition time_utils.cc:43
isc
Defines the logger used by the top-level component of kea-lfc.
Definition check_exists_add.cc:18
isc::sflq_in_use_
bool sflq_in_use_
Definition sflq_allocator.cc:22
sflq_allocator.h
stopwatch.h
isc::dhcp::Lease::Type
Type
Type of lease or pool.
Definition lease.h:46
isc::dhcp::Lease::TYPE_PD
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition lease.h:49
isc::dhcp::Lease::TYPE_V4
@ TYPE_V4
IPv4 lease.
Definition lease.h:50
isc::dhcp::Lease::TYPE_NA
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition lease.h:47
subnet.h