Kea 2.7.5
pool.cc
Go to the documentation of this file.
1// Copyright (C) 2012-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
11#include <dhcpsrv/pool.h>
12#include <boost/make_shared.hpp>
13#include <sstream>
14
15using namespace isc::asiolink;
16using namespace isc::data;
17
18namespace isc {
19namespace dhcp {
20
22 const isc::asiolink::IOAddress& last)
23 : id_(0), first_(first), last_(last), type_(type), capacity_(0),
24 cfg_option_(new CfgOption()) {
25}
26
27bool
29 return (first_ <= addr && addr <= last_);
30}
31
32bool
33Pool::clientSupported(const ClientClasses& classes) const {
34 return (client_classes_.empty() || client_classes_.intersects(classes));
35}
36
37void
39 if (!client_classes_.contains(class_name)) {
40 client_classes_.insert(class_name);
41 }
42}
43
44void
46 if (!additional_classes_.contains(class_name)) {
47 additional_classes_.insert(class_name);
48 }
49}
50
51std::string
52Pool::toText() const {
53 std::stringstream tmp;
54 tmp << "type=" << Lease::typeToText(type_) << ", " << first_
55 << "-" << last_;
56 return (tmp.str());
57}
58
60 const isc::asiolink::IOAddress& last)
61 : Pool(Lease::TYPE_V4, first, last) {
62 // check if specified address boundaries are sane
63 if (!first.isV4() || !last.isV4()) {
64 isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
65 }
66
67 if (last < first) {
68 isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
69 }
70
71 // This is IPv4 pool, which only has one type. We can calculate
72 // the number of theoretically possible leases in it. As there's 2^32
73 // possible IPv4 addresses, we'll be able to accurately store that
74 // info.
75 capacity_ = addrsInRange(first, last);
76}
77
78Pool4::Pool4(const isc::asiolink::IOAddress& prefix, uint8_t prefix_len)
79 : Pool(Lease::TYPE_V4, prefix, IOAddress("0.0.0.0")) {
80
81 // check if the prefix is sane
82 if (!prefix.isV4()) {
83 isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
84 }
85
86 // check if the prefix length is sane
87 if (prefix_len == 0 || prefix_len > 32) {
88 isc_throw(BadValue, "Invalid prefix length");
89 }
90
91 IOAddress first_address = firstAddrInPrefix(prefix, prefix_len);
92 if (first_address != prefix) {
93 isc_throw(BadValue, "Invalid Pool4 address boundaries: " << prefix
94 << " is not the first address in prefix: " << first_address
95 << "/" << static_cast<uint32_t>(prefix_len));
96 }
97
98 // Let's now calculate the last address in defined pool
99 last_ = lastAddrInPrefix(prefix, prefix_len);
100
101 // This is IPv4 pool, which only has one type. We can calculate
102 // the number of theoretically possible leases in it. As there's 2^32
103 // possible IPv4 addresses, we'll be able to accurately store that
104 // info.
105 capacity_ = addrsInRange(prefix, last_);
106}
107
109Pool4::create(const IOAddress& first, const IOAddress& last) {
110 return (boost::make_shared<Pool4>(first, last));
111}
112
114Pool4::create(const IOAddress& prefix, uint8_t prefix_len) {
115 return (boost::make_shared<Pool4>(prefix, prefix_len));
116}
117
120 // Prepare the map
122
123 // Set user-context
124 contextToElement(map);
125
126 // Set pool options
128 map->set("option-data", opts->toElement());
129
130 // Set client-classes
131 if (!client_classes_.empty()) {
132 map->set("client-classes", client_classes_.toElement());
133 }
134
135 // Set evaluate-additional-classes
136 if (!additional_classes_.empty()) {
137 map->set("evaluate-additional-classes",
139 }
140
141 if (id_) {
142 map->set("pool-id", Element::create(static_cast<long long>(id_)));
143 }
144
145 return (map);
146}
147
150 // Prepare the map
152
153 // Set pool
154 const IOAddress& first = getFirstAddress();
155 const IOAddress& last = getLastAddress();
156 std::string range = first.toText() + "-" + last.toText();
157
158 // Try to output a prefix (vs a range)
159 int prefix_len = prefixLengthFromRange(first, last);
160 if (prefix_len >= 0) {
161 std::ostringstream oss;
162 oss << first.toText() << "/" << prefix_len;
163 range = oss.str();
164 }
165
166 map->set("pool", Element::create(range));
167 return (map);
168}
169
171 const isc::asiolink::IOAddress& last)
172 : Pool(type, first, last), prefix_len_(128), pd_exclude_option_() {
173
174 // check if specified address boundaries are sane
175 if (!first.isV6() || !last.isV6()) {
176 isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
177 }
178
179 if ((type != Lease::TYPE_NA) && (type != Lease::TYPE_TA) &&
180 (type != Lease::TYPE_PD)) {
181 isc_throw(BadValue, "Invalid Pool6 type: " << static_cast<int>(type)
182 << ", must be TYPE_IA, TYPE_TA or TYPE_PD");
183 }
184
185 if (last < first) {
186 isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
187 // This check is a bit strict. If we decide that it is too strict,
188 // we need to comment it and uncomment lines below.
189 // On one hand, letting the user specify 2001::f - 2001::1 is nice, but
190 // on the other hand, 2001::1 may be a typo and the user really meant
191 // 2001::1:0 (or 1 followed by some hex digit), so a at least a warning
192 // would be useful.
193
194 // first_ = last;
195 // last_ = first;
196 }
197
198 // TYPE_PD is not supported by this constructor. first-last style
199 // parameters are for IA and TA only. There is another dedicated
200 // constructor for that (it uses prefix/length)
201 if ((type != Lease::TYPE_NA) && (type != Lease::TYPE_TA)) {
202 isc_throw(BadValue, "Invalid Pool6 type specified: "
203 << static_cast<int>(type));
204 }
205
206 // Let's calculate the theoretical number of leases in this pool.
207 // If the pool is extremely large (i.e. contains more than 2^64 addresses,
208 // we'll just cap it at max value of uint64_t).
209 capacity_ = addrsInRange(first, last);
210}
211
213 const uint8_t prefix_len, const uint8_t delegated_len /* = 128 */)
214 : Pool(type, prefix, IOAddress::IPV6_ZERO_ADDRESS()),
215 prefix_len_(delegated_len), pd_exclude_option_() {
216
217 init(type, prefix, prefix_len, delegated_len,
219}
220
221Pool6::Pool6(const asiolink::IOAddress& prefix, const uint8_t prefix_len,
222 const uint8_t delegated_len,
223 const asiolink::IOAddress& excluded_prefix,
224 const uint8_t excluded_prefix_len)
225 : Pool(Lease::TYPE_PD, prefix, IOAddress::IPV6_ZERO_ADDRESS()),
226 prefix_len_(delegated_len), pd_exclude_option_() {
227
228 init(Lease::TYPE_PD, prefix, prefix_len, delegated_len, excluded_prefix,
229 excluded_prefix_len);
230
231 // The excluded prefix can only be specified using this constructor.
232 // Therefore, the initialization of the excluded prefix is takes place
233 // here, rather than in the init(...) function.
234 if (!excluded_prefix.isV6()) {
235 isc_throw(BadValue, "excluded prefix must be an IPv6 prefix");
236 }
237
238 // An "unspecified" prefix should have both value and length equal to 0.
239 if ((excluded_prefix.isV6Zero() && (excluded_prefix_len != 0)) ||
240 (!excluded_prefix.isV6Zero() && (excluded_prefix_len == 0))) {
241 isc_throw(BadValue, "invalid excluded prefix "
242 << excluded_prefix << "/"
243 << static_cast<unsigned>(excluded_prefix_len));
244 }
245
246 // If excluded prefix has been specified.
247 if (!excluded_prefix.isV6Zero() && (excluded_prefix_len != 0)) {
248 // Excluded prefix length must not be greater than 128.
249 if (excluded_prefix_len > 128) {
250 isc_throw(BadValue, "excluded prefix length "
251 << static_cast<unsigned>(excluded_prefix_len)
252 << " must not be greater than 128");
253 }
254
255 // Excluded prefix must be a sub-prefix of a delegated prefix. First
256 // check the prefix length as it is less involved.
257 if (excluded_prefix_len <= prefix_len_) {
258 isc_throw(BadValue, "excluded prefix length "
259 << static_cast<unsigned>(excluded_prefix_len)
260 << " must be longer than the delegated prefix length "
261 << static_cast<unsigned>(prefix_len_));
262 }
263
269 }
270}
271
273Pool6::create(Lease::Type type, const IOAddress& first, const IOAddress& last) {
274 return (boost::make_shared<Pool6>(type, first, last));
275}
276
279 uint8_t prefix_len, uint8_t delegated_len) {
280 return (boost::make_shared<Pool6>(type, prefix, prefix_len, delegated_len));
281}
282
284Pool6::create(const IOAddress& prefix, const uint8_t prefix_len,
285 const uint8_t delegated_len, const IOAddress& excluded_prefix,
286 const uint8_t excluded_prefix_len) {
287 return (boost::make_shared<Pool6>(prefix, prefix_len,
288 delegated_len, excluded_prefix,
289 excluded_prefix_len));
290}
291
292void
293Pool6::init(const Lease::Type& type,
294 const asiolink::IOAddress& prefix,
295 const uint8_t prefix_len,
296 const uint8_t delegated_len,
297 const asiolink::IOAddress& excluded_prefix,
298 const uint8_t excluded_prefix_len) {
299 // Check if the prefix is sane
300 if (!prefix.isV6()) {
301 isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
302 }
303
304 // Check if the prefix length is sane
305 if (prefix_len == 0 || prefix_len > 128) {
306 isc_throw(BadValue, "Invalid prefix length: "
307 << static_cast<unsigned>(prefix_len));
308 }
309
310 if (prefix_len > delegated_len) {
311 isc_throw(BadValue, "Delegated length ("
312 << static_cast<int>(delegated_len)
313 << ") must be longer than or equal to prefix length ("
314 << static_cast<int>(prefix_len) << ")");
315 }
316
317 if ((type != Lease::TYPE_PD) && (delegated_len != 128)) {
318 isc_throw(BadValue, "For NA or TA pools, delegated prefix length must"
319 << " be 128.");
320 }
321
322 // excluded_prefix_len == 0 means there's no excluded prefix at all.
323 if (excluded_prefix_len && (excluded_prefix_len <= delegated_len)) {
324 isc_throw(BadValue, "Excluded prefix ("
325 << static_cast<int>(excluded_prefix_len)
326 << ") must be longer than the delegated prefix length ("
327 << static_cast<int>(delegated_len) << ")");
328 }
329
330 if (prefix_len != 128) {
331 IOAddress first_address = firstAddrInPrefix(prefix, prefix_len);
332 if (first_address != prefix) {
333 isc_throw(BadValue, "Invalid Pool6 address boundaries: " << prefix
334 << " is not the first address in prefix: " << first_address
335 << "/" << static_cast<uint32_t>(prefix_len));
336 }
337 }
338
341
342 // Let's now calculate the last address in defined pool
343 last_ = lastAddrInPrefix(prefix, prefix_len);
344
345 // Let's calculate the theoretical number of leases in this pool.
346 // For addresses, we could use addrsInRange(prefix, last_), but it's
347 // much faster to do calculations on prefix lengths.
348 capacity_ = prefixesInRange(prefix_len, delegated_len);
349
350 // If user specified an excluded prefix, create an option that will
351 // be sent to clients obtaining prefixes from this pool.
352 if (excluded_prefix_len > 0) {
353 pd_exclude_option_.reset(new Option6PDExclude(prefix, delegated_len,
354 excluded_prefix,
355 excluded_prefix_len));
356 }
357}
358
361 // Prepare the map
363
364 switch (getType()) {
365 case Lease::TYPE_NA: {
366 const IOAddress& first = getFirstAddress();
367 const IOAddress& last = getLastAddress();
368 std::string range = first.toText() + "-" + last.toText();
369
370 // Try to output a prefix (vs a range)
371 int prefix_len = prefixLengthFromRange(first, last);
372 if (prefix_len >= 0) {
373 std::ostringstream oss;
374 oss << first.toText() << "/" << prefix_len;
375 range = oss.str();
376 }
377
378 map->set("pool", Element::create(range));
379 break;
380 }
381 case Lease::TYPE_PD: {
382 // Set prefix
383 const IOAddress& prefix = getFirstAddress();
384 map->set("prefix", Element::create(prefix.toText()));
385
386 // Set prefix-len (get it from min - max)
387 const IOAddress& last = getLastAddress();
388 int prefix_len = prefixLengthFromRange(prefix, last);
389 if (prefix_len < 0) {
390 // The pool is bad: give up
391 isc_throw(ToElementError, "invalid prefix range "
392 << prefix.toText() << "-" << last.toText());
393 }
394 map->set("prefix-len", Element::create(prefix_len));
395
396 // Set delegated-len
397 uint8_t len = getLength();
398 map->set("delegated-len", Element::create(static_cast<int>(len)));
399
400 // Set excluded prefix
402 if (xopt) {
403 const IOAddress& xprefix = xopt->getExcludedPrefix(prefix, len);
404 map->set("excluded-prefix", Element::create(xprefix.toText()));
405
406 uint8_t xlen = xopt->getExcludedPrefixLength();
407 map->set("excluded-prefix-len",
408 Element::create(static_cast<int>(xlen)));
409 }
410 // Let's not insert empty excluded-prefix values. If we ever
411 // decide to insert it after all, here's the code to do it:
412 // else {
413 // map->set("excluded-prefix",
414 // Element::create(std::string("::")));
415 // map->set("excluded-prefix-len", Element::create(0));
417
418 break;
419 }
420 default:
421 isc_throw(ToElementError, "Lease type: " << getType()
422 << ", unsupported for Pool6");
423 break;
424 }
425
426 return (map);
427}
428
429std::string
431 std::ostringstream s;
432 s << "type=" << Lease::typeToText(type_) << ", " << first_
433 << "-" << last_ << ", delegated_len="
434 << static_cast<unsigned>(prefix_len_);
435
436 if (pd_exclude_option_) {
437 s << ", excluded_prefix="
438 << pd_exclude_option_->getExcludedPrefix(first_, prefix_len_).toText()
439 << "/"
440 << static_cast<unsigned>(pd_exclude_option_->getExcludedPrefixLength());
441 }
442 return (s.str());
443}
444
445} // namespace dhcp
446} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Cannot unparse error.
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
Represents option data configuration for the DHCP server.
Definition cfg_option.h:372
Container for storing client class names.
Definition classify.h:109
bool contains(const ClientClass &x) const
returns if class x belongs to the defined classes
Definition classify.cc:55
void insert(const ClientClass &class_name)
Insert an element.
Definition classify.h:159
bool empty() const
Check if classes is empty.
Definition classify.h:169
virtual isc::data::ElementPtr toElement() const
Returns all class names as an ElementPtr of type ListElement.
Definition classify.cc:95
bool intersects(const ClientClasses &cclasses) const
returns whether this container has at least one class in common with a given container.
Definition classify.cc:61
virtual data::ElementPtr toElement() const
Unparse a Pool4 object.
Definition pool.cc:149
Pool4(const isc::asiolink::IOAddress &first, const isc::asiolink::IOAddress &last)
the constructor for Pool4 "min-max" style definition
Definition pool.cc:59
static Pool4Ptr create(const isc::asiolink::IOAddress &first, const isc::asiolink::IOAddress &last)
Factory function for creating an instance of the Pool4.
Definition pool.cc:109
uint8_t getLength() const
returns delegated prefix length
Definition pool.h:427
virtual data::ElementPtr toElement() const
Unparse a Pool6 object.
Definition pool.cc:360
Option6PDExcludePtr getPrefixExcludeOption() const
Returns instance of the pool specific Prefix Exclude option.
Definition pool.h:435
static Pool6Ptr create(Lease::Type type, const isc::asiolink::IOAddress &first, const isc::asiolink::IOAddress &last)
Factory function for creating an instance of the Pool6.
Definition pool.cc:273
virtual std::string toText() const
returns textual representation of the pool
Definition pool.cc:430
Pool6(Lease::Type type, const isc::asiolink::IOAddress &first, const isc::asiolink::IOAddress &last)
the constructor for Pool6 "min-max" style definition
Definition pool.cc:170
Lease::Type getType() const
returns pool type
Definition pool.h:418
base class for Pool4 and Pool6
Definition pool.h:32
virtual data::ElementPtr toElement() const
Unparse a pool object.
Definition pool.cc:119
Pool(Lease::Type type, const isc::asiolink::IOAddress &first, const isc::asiolink::IOAddress &last)
protected constructor
Definition pool.cc:21
const isc::asiolink::IOAddress & getFirstAddress() const
Returns the first address in a pool.
Definition pool.h:61
ClientClasses additional_classes_
Additional classes.
Definition pool.h:224
uint64_t id_
pool-id
Definition pool.h:191
const isc::asiolink::IOAddress & getLastAddress() const
Returns the last address in a pool.
Definition pool.h:67
isc::util::uint128_t capacity_
Stores number of possible leases.
Definition pool.h:208
ClientClasses client_classes_
List of client classes allowed to use this pool.
Definition pool.h:219
void allowClientClass(const isc::dhcp::ClientClass &class_name)
Adds class clas_name to the allowed client classes list.
Definition pool.cc:38
isc::asiolink::IOAddress last_
The last address in a pool.
Definition pool.h:197
isc::asiolink::IOAddress first_
The first address in a pool.
Definition pool.h:194
CfgOptionPtr getCfgOption()
Returns pointer to the option data configuration for this pool.
Definition pool.h:104
virtual std::string toText() const
returns textual representation of the pool
Definition pool.cc:52
bool inRange(const isc::asiolink::IOAddress &addr) const
Checks if a given address is in the range.
Definition pool.cc:28
void addAdditionalClass(const ClientClass &class_name)
Adds class class_name to the additional classes list.
Definition pool.cc:45
bool clientSupported(const ClientClasses &client_classes) const
Checks whether this pool supports client that belongs to specified classes.
Definition pool.cc:33
Lease::Type type_
defines a lease type that will be served from this pool
Definition pool.h:200
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
boost::shared_ptr< Pool4 > Pool4Ptr
a pointer an IPv4 Pool
Definition pool.h:236
std::string ClientClass
Defines a single class name.
Definition classify.h:43
boost::shared_ptr< Option6PDExclude > Option6PDExcludePtr
Pointer to the Option6PDExclude object.
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
Definition cfg_option.h:835
boost::shared_ptr< Pool6 > Pool6Ptr
a pointer an IPv6 Pool
Definition pool.h:295
Defines the logger used by the top-level component of kea-lfc.
void contextToElement(data::ElementPtr map) const
Merge unparse a user_context object.
a common structure for IPv4 and IPv6 leases
Definition lease.h:31
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_NA
the lease contains non-temporary IPv6 address
Definition lease.h:47
static std::string typeToText(Type type)
returns text representation of a lease type
Definition lease.cc:55