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