Kea 3.1.1
limit_manager.cc
Go to the documentation of this file.
1// Copyright (C) 2022-2025 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 <cc/data.h>
10#include <dhcp/classify.h>
11#include <dhcpsrv/lease.h>
13#include <dhcpsrv/srv_config.h>
14#include <dhcpsrv/subnet_id.h>
17#include <util/dhcp_space.h>
18
19#include <string>
20
21using namespace isc::data;
22using namespace isc::dhcp;
23using namespace isc::util;
24
25using namespace std;
26
27namespace isc {
28namespace limits {
29
32 static LimitManager instance;
33 return (instance);
34}
35
36void
38 clocked_in_times_by_class_.clear();
39 clocked_in_times_by_subnet_id_.clear();
40}
41
42void
44 // Reset any packet accounting that had transpired so far.
45 clear();
46
47 // Parse the configuration to get the limits of interest.
49}
50
51void
52LimitManager::addClientClassesToLeaseContext(ClientClasses const& classes, LeasePtr const& lease) {
53 // The ConstElementPtr - ElementPtr division forces the copies below. Changes to the lease's
54 // user context are not expected so shallow copy is fine as it would have been to reuse the
55 // original user context. Feel free to get rid of the copying. Preferable to not resort to the
56 // undefined behavior that is const-cast + writing data to the memory freshly made mutable.
57
58 // Get a mutable user context.
59 ConstElementPtr user_context_source(lease->getContext());
60 ElementPtr user_context;
61 if (user_context_source) {
62 user_context = copy(user_context_source, 0);
63 } else {
64 user_context = Element::createMap();
65 }
66
67 // Get a mutable ISC element.
68 ConstElementPtr isc_source(user_context->get("ISC"));
70 if (isc_source) {
71 isc = copy(isc_source, 0);
72 } else {
73 isc = Element::createMap();
74 }
75 user_context->set("ISC", isc);
76
77 // Set the new client classes. Old ones are discarded.
78 isc->set("client-classes", classes.toElement());
79
80 // Set the modified user context in the lease.
81 lease->setContext(user_context);
82}
83
84void
86 // Parse the configuration to get the limits of interest.
87 address_limit_configuration_.parse(config);
88 prefix_limit_configuration_.parse(config);
89 rate_limit_configuration_.parse(config);
90}
91
92template <>
94LimitManager::clientClassLimitsToElement<DHCPv4>(SubClassRelationContainer const& classes,
95 Lease::Type const& /* lease_type */) {
97
98 for (auto const& c : classes) {
99 auto const& class_def = isc::dhcp::CfgMgr::instance().getCurrentCfg()->getClientClassDictionary()->findClass(c.class_def_);
100 if (!class_def) {
101 continue;
102 }
103
104 auto const& limit_cfg = address_limit_configuration_.parseUserContext(class_def->getContext());
105 if (limit_cfg) {
106 int64_t const limit_candidate(limit_cfg->intValue());
107 checkForLimitBoundaries<LeaseLimit>(limit_candidate);
108 // Get the limit.
109 LeaseLimit const limit(limit_candidate);
110
112 element->set("name", Element::create(c.class_));
113 element->set("address-limit", Element::create(limit));
114 result->add(element);
115 }
116 }
117
118 return (result);
119}
120
121template <>
123LimitManager::clientClassLimitsToElement<DHCPv6>(SubClassRelationContainer const& classes,
124 Lease::Type const& lease_type) {
126
127 auto get_configuration = [&]() -> Configuration<LeaseLimit>& {
128 if (lease_type == Lease::TYPE_PD) {
129 return (prefix_limit_configuration_);
130 } else {
131 return (address_limit_configuration_);
132 }
133 };
134
135 auto& config = get_configuration();
136
137 for (auto const& c : classes) {
138 auto const& class_def = isc::dhcp::CfgMgr::instance().getCurrentCfg()->getClientClassDictionary()->findClass(c.class_def_);
139 if (!class_def) {
140 continue;
141 }
142
143 auto& limit_cfg = config.parseUserContext(class_def->getContext());
144 if (limit_cfg) {
145 int64_t const limit_candidate(limit_cfg->intValue());
146 checkForLimitBoundaries<LeaseLimit>(limit_candidate);
147 // Get the limit.
148 LeaseLimit const limit(limit_candidate);
149
151 element->set("name", Element::create(c.class_));
152 element->set(config.key(), Element::create(limit));
153 result->add(element);
154 }
155 }
156
157 return (result);
158}
159
160template <>
162LimitManager::subnetLimitToElement<DHCPv4>(SubnetID const subnet_id,
163 Lease::Type const& /* lease_type */) {
165
166 auto const& subnet_cfg = isc::dhcp::CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(subnet_id);
167 if (subnet_cfg) {
168 auto const& limit_cfg = address_limit_configuration_.parseUserContext(subnet_cfg->getContext());
169 if (limit_cfg) {
170 int64_t const limit_candidate(limit_cfg->intValue());
171 checkForLimitBoundaries<LeaseLimit>(limit_candidate);
172 // Get the limit.
173 LeaseLimit const limit(limit_candidate);
174
175 result->set("id", Element::create(subnet_id));
176 result->set("address-limit", Element::create(limit));
177 }
178 }
179
180 return (result);
181}
182
183template <>
185LimitManager::subnetLimitToElement<DHCPv6>(SubnetID const subnet_id,
186 Lease::Type const& lease_type) {
188
189 std::string limit_name;
190 auto get_configuration = [&]() -> Configuration<LeaseLimit>& {
191 if (lease_type == Lease::TYPE_PD) {
192 limit_name = std::string("prefix-limit");
193 return (prefix_limit_configuration_);
194 } else {
195 limit_name = std::string("address-limit");
196 return (address_limit_configuration_);
197 }
198 };
199
200 auto& config = get_configuration();
201
202 auto const& subnet_cfg = isc::dhcp::CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(subnet_id);
203 if (subnet_cfg) {
204 auto const& limit_cfg = config.parseUserContext(subnet_cfg->getContext());
205 if (limit_cfg) {
206 int64_t const limit_candidate(limit_cfg->intValue());
207 checkForLimitBoundaries<LeaseLimit>(limit_candidate);
208 // Get the limit.
209 LeaseLimit const limit(limit_candidate);
210
211 result->set("id", Element::create(subnet_id));
212 result->set(limit_name, Element::create(limit));
213 }
214 }
215
216 return (result);
217}
218
219template <>
221LimitManager::subnetRateLimit<DHCPv4>(SubnetID const subnet_id) {
222 ConstElementPtr limit;
223
224 auto const& subnet_cfg = isc::dhcp::CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(subnet_id);
225 if (subnet_cfg) {
226 limit = rate_limit_configuration_.parseUserContext(subnet_cfg->getContext());
227 }
228
229 return (limit);
230}
231
232template <>
234LimitManager::subnetRateLimit<DHCPv6>(SubnetID const subnet_id) {
235 ConstElementPtr limit;
236
237 auto const& subnet_cfg = isc::dhcp::CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(subnet_id);
238 if (subnet_cfg) {
239 limit = rate_limit_configuration_.parseUserContext(subnet_cfg->getContext());
240 }
241
242 return (limit);
243}
244
245template <>
246string
247LimitManager::checkLeaseLimits<DHCPv4>(ConstElementPtr const& context) const {
248 return (LeaseMgrFactory::instance().checkLimits4(context));
249}
250
251template <>
252string
253LimitManager::checkLeaseLimits<DHCPv6>(ConstElementPtr const& context) const {
254 return (LeaseMgrFactory::instance().checkLimits6(context));
255}
256
257template <>
258void
259LimitManager::recountClassLeases<DHCPv4>() const {
260 if (isc::dhcp::LeaseMgrFactory::instance().getType() == "memfile") {
262 }
263}
264
265template <>
266void
267LimitManager::recountClassLeases<DHCPv6>() const {
268 if (isc::dhcp::LeaseMgrFactory::instance().getType() == "memfile") {
270 }
271}
272
273} // namespace limits
274} // namespace isc
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:304
Defines elements for storing the names of client classes.
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:304
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
Container for storing client class names.
Definition classify.h:110
virtual isc::data::ElementPtr toElement() const
Returns all class names as an ElementPtr of type ListElement.
Definition classify.cc:95
static TrackingLeaseMgr & instance()
Return current lease manager.
virtual void recountClassLeases4()=0
Recount the leases per class for V4 leases.
virtual void recountClassLeases6()=0
Recount the leases per class for V6 leases.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition data.cc:1420
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
boost::multi_index_container< SubClassRelation, boost::multi_index::indexed_by< boost::multi_index::sequenced< boost::multi_index::tag< TemplateClassSequenceTag > >, boost::multi_index::hashed_unique< boost::multi_index::tag< TemplateClassNameTag >, boost::multi_index::member< SubClassRelation, ClientClass, &SubClassRelation::class_def_ > > > > SubClassRelationContainer
the subclass multi-index.
Definition classify.h:104
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition subnet_id.h:25
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
Definition lease.h:25
uint32_t LeaseLimit
a single lease-limiting entry configured as an integer
Defines the logger used by the top-level component of kea-lfc.
Type
Type of lease or pool.
Definition lease.h:46
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition lease.h:49
isc::data::ConstElementPtr const parseUserContext(isc::data::ConstElementPtr const &user_context) const
Abstract method that takes a user context from any configuration element and returns the value of the...
Provides the capability to limit the number of leases or the response rate.
void parse(isc::dhcp::SrvConfigPtr const &config)
Fetches limits from the given Kea configuration.
void clear()
Clears the time series circular buffers in order to start over rate limiting.
void initialize(isc::dhcp::SrvConfigPtr const &config)
Reinitialize data structures required for limiting.
static LimitManager & instance()
singleton access function