Kea 1.5.0
pool.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2018 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 <sstream>
13
14using namespace isc::asiolink;
15using namespace isc::data;
16
17namespace isc {
18namespace dhcp {
19
21 const isc::asiolink::IOAddress& last)
22 :id_(getNextID()), first_(first), last_(last), type_(type),
23 capacity_(0), cfg_option_(new CfgOption()), client_class_(""),
24 last_allocated_(first), last_allocated_valid_(false) {
25}
26
27bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
28 return (first_.smallerEqual(addr) && addr.smallerEqual(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 // Let's now calculate the last address in defined pool
80 last_ = lastAddrInPrefix(prefix, prefix_len);
81
82 // This is IPv4 pool, which only has one type. We can calculate
83 // the number of theoretically possible leases in it. As there's 2^32
84 // possible IPv4 addresses, we'll be able to accurately store that
85 // info.
86 capacity_ = addrsInRange(prefix, last_);
87}
88
91 // Prepare the map
93
94 // Set user-context
96
97 // Set pool options
99 map->set("option-data", opts->toElement());
100
101 // Set client-class
102 const ClientClass& cclass = getClientClass();
103 if (!cclass.empty()) {
104 map->set("client-class", Element::create(cclass));
105 }
106
107 // Set require-client-classes
108 const ClientClasses& classes = getRequiredClasses();
109 if (!classes.empty()) {
110 ElementPtr class_list =Element::createList();
111 for (ClientClasses::const_iterator it = classes.cbegin();
112 it != classes.cend(); ++it) {
113 class_list->add(Element::create(*it));
114 }
115 map->set("require-client-classes", class_list);
116 }
117
118 return (map);
119}
120
123 // Prepare the map
125
126 // Set pool
127 const IOAddress& first = getFirstAddress();
128 const IOAddress& last = getLastAddress();
129 std::string range = first.toText() + "-" + last.toText();
130
131 // Try to output a prefix (vs a range)
132 int prefix_len = prefixLengthFromRange(first, last);
133 if (prefix_len >= 0) {
134 std::ostringstream oss;
135 oss << first.toText() << "/" << prefix_len;
136 range = oss.str();
137 }
138
139 map->set("pool", Element::create(range));
140 return (map);
141}
142
143
145 const isc::asiolink::IOAddress& last)
146 : Pool(type, first, last), prefix_len_(128), pd_exclude_option_() {
147
148 // check if specified address boundaries are sane
149 if (!first.isV6() || !last.isV6()) {
150 isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
151 }
152
153 if ( (type != Lease::TYPE_NA) && (type != Lease::TYPE_TA) &&
154 (type != Lease::TYPE_PD)) {
155 isc_throw(BadValue, "Invalid Pool6 type: " << static_cast<int>(type)
156 << ", must be TYPE_IA, TYPE_TA or TYPE_PD");
157 }
158
159 if (last < first) {
160 isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
161 // This check is a bit strict. If we decide that it is too strict,
162 // we need to comment it and uncomment lines below.
163 // On one hand, letting the user specify 2001::f - 2001::1 is nice, but
164 // on the other hand, 2001::1 may be a typo and the user really meant
165 // 2001::1:0 (or 1 followed by some hex digit), so a at least a warning
166 // would be useful.
167
168 // first_ = last;
169 // last_ = first;
170 }
171
172 // TYPE_PD is not supported by this constructor. first-last style
173 // parameters are for IA and TA only. There is another dedicated
174 // constructor for that (it uses prefix/length)
175 if ((type != Lease::TYPE_NA) && (type != Lease::TYPE_TA)) {
176 isc_throw(BadValue, "Invalid Pool6 type specified: "
177 << static_cast<int>(type));
178 }
179
180 // Let's calculate the theoretical number of leases in this pool.
181 // If the pool is extremely large (i.e. contains more than 2^64 addresses,
182 // we'll just cap it at max value of uint64_t).
183 capacity_ = addrsInRange(first, last);
184}
185
187 const uint8_t prefix_len, const uint8_t delegated_len /* = 128 */)
188 : Pool(type, prefix, IOAddress::IPV6_ZERO_ADDRESS()),
189 prefix_len_(delegated_len), pd_exclude_option_() {
190
191 init(type, prefix, prefix_len, delegated_len,
193}
194
195Pool6::Pool6(const asiolink::IOAddress& prefix, const uint8_t prefix_len,
196 const uint8_t delegated_len,
197 const asiolink::IOAddress& excluded_prefix,
198 const uint8_t excluded_prefix_len)
199 : Pool(Lease::TYPE_PD, prefix, IOAddress::IPV6_ZERO_ADDRESS()),
200 prefix_len_(delegated_len), pd_exclude_option_() {
201
202 init(Lease::TYPE_PD, prefix, prefix_len, delegated_len, excluded_prefix,
203 excluded_prefix_len);
204
205 // The excluded prefix can only be specified using this constructor.
206 // Therefore, the initialization of the excluded prefix is takes place
207 // here, rather than in the init(...) function.
208 if (!excluded_prefix.isV6()) {
209 isc_throw(BadValue, "excluded prefix must be an IPv6 prefix");
210 }
211
212 // An "unspecified" prefix should have both value and length equal to 0.
213 if ((excluded_prefix.isV6Zero() && (excluded_prefix_len != 0)) ||
214 (!excluded_prefix.isV6Zero() && (excluded_prefix_len == 0))) {
215 isc_throw(BadValue, "invalid excluded prefix "
216 << excluded_prefix << "/"
217 << static_cast<unsigned>(excluded_prefix_len));
218 }
219
220 // If excluded prefix has been specified.
221 if (!excluded_prefix.isV6Zero() && (excluded_prefix_len != 0)) {
222
223 // Excluded prefix length must not be greater than 128.
224 if (excluded_prefix_len > 128) {
225 isc_throw(BadValue, "excluded prefix length "
226 << static_cast<unsigned>(excluded_prefix_len)
227 << " must not be greater than 128");
228 }
229
230 // Excluded prefix must be a sub-prefix of a delegated prefix. First
231 // check the prefix length as it is less involved.
232 if (excluded_prefix_len <= prefix_len_) {
233 isc_throw(BadValue, "excluded prefix length "
234 << static_cast<unsigned>(excluded_prefix_len)
235 << " must be lower than the delegated prefix length "
236 << static_cast<unsigned>(prefix_len_));
237 }
238
244 }
245}
246
247void
248Pool6::init(const Lease::Type& type,
249 const asiolink::IOAddress& prefix,
250 const uint8_t prefix_len,
251 const uint8_t delegated_len,
252 const asiolink::IOAddress& excluded_prefix,
253 const uint8_t excluded_prefix_len) {
254 // Check if the prefix is sane
255 if (!prefix.isV6()) {
256 isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
257 }
258
259 // Check if the prefix length is sane
260 if (prefix_len == 0 || prefix_len > 128) {
261 isc_throw(BadValue, "Invalid prefix length: "
262 << static_cast<unsigned>(prefix_len));
263 }
264
265 if (prefix_len > delegated_len) {
266 isc_throw(BadValue, "Delegated length ("
267 << static_cast<int>(delegated_len)
268 << ") must be longer than or equal to prefix length ("
269 << static_cast<int>(prefix_len) << ")");
270 }
271
272 if ( ( (type == Lease::TYPE_NA) || (type == Lease::TYPE_TA)) &&
273 (delegated_len != 128)) {
274 isc_throw(BadValue, "For IA or TA pools, delegated prefix length must"
275 << " be 128.");
276 }
277
278 // excluded_prefix_len == 0 means there's no excluded prefix at all.
279 if (excluded_prefix_len && (excluded_prefix_len < delegated_len)) {
280 isc_throw(BadValue, "Excluded prefix (" << static_cast<int>(excluded_prefix_len)
281 << ") must be longer than the delegated prefix length ("
282 << static_cast<int>(delegated_len));
283 }
284
287
288 // Let's now calculate the last address in defined pool
289 last_ = lastAddrInPrefix(prefix, prefix_len);
290
291 // Let's calculate the theoretical number of leases in this pool.
292 // For addresses, we could use addrsInRange(prefix, last_), but it's
293 // much faster to do calculations on prefix lengths.
294 capacity_ = prefixesInRange(prefix_len, delegated_len);
295
296 // If user specified an excluded prefix, create an option that will
297 // be sent to clients obtaining prefixes from this pool.
298 if (excluded_prefix_len > 0) {
299 pd_exclude_option_.reset(new Option6PDExclude(prefix, delegated_len,
300 excluded_prefix,
301 excluded_prefix_len));
302 }
303}
304
307 // Prepare the map
309
310 switch (getType()) {
311 case Lease::TYPE_NA: {
312 const IOAddress& first = getFirstAddress();
313 const IOAddress& last = getLastAddress();
314 std::string range = first.toText() + "-" + last.toText();
315
316 // Try to output a prefix (vs a range)
317 int prefix_len = prefixLengthFromRange(first, last);
318 if (prefix_len >= 0) {
319 std::ostringstream oss;
320 oss << first.toText() << "/" << prefix_len;
321 range = oss.str();
322 }
323
324 map->set("pool", Element::create(range));
325 break;
326 }
327 case Lease::TYPE_PD: {
328 // Set prefix
329 const IOAddress& prefix = getFirstAddress();
330 map->set("prefix", Element::create(prefix.toText()));
331
332 // Set prefix-len (get it from min - max)
333 const IOAddress& last = getLastAddress();
334 int prefix_len = prefixLengthFromRange(prefix, last);
335 if (prefix_len < 0) {
336 // The pool is bad: give up
337 isc_throw(ToElementError, "invalid prefix range "
338 << prefix.toText() << "-" << last.toText());
339 }
340 map->set("prefix-len", Element::create(prefix_len));
341
342 // Set delegated-len
343 uint8_t len = getLength();
344 map->set("delegated-len", Element::create(static_cast<int>(len)));
345
346 // Set excluded prefix
348 if (xopt) {
349 const IOAddress& xprefix = xopt->getExcludedPrefix(prefix, len);
350 map->set("excluded-prefix", Element::create(xprefix.toText()));
351
352 uint8_t xlen = xopt->getExcludedPrefixLength();
353 map->set("excluded-prefix-len",
354 Element::create(static_cast<int>(xlen)));
355 }
356 // Let's not insert empty excluded-prefix values. If we ever
357 // decide to insert it after all, here's the code to do it:
358 // else {
359 // map->set("excluded-prefix",
360 // Element::create(std::string("::")));
361 // map->set("excluded-prefix-len", Element::create(0));
363
364 break;
365 }
366 default:
367 isc_throw(ToElementError, "Lease type: " << getType()
368 << ", unsupported for Pool6");
369 break;
370 }
371
372 return (map);
373}
374
375
376std::string
378 std::ostringstream s;
379 s << "type=" << Lease::typeToText(type_) << ", " << first_
380 << "-" << last_ << ", delegated_len="
381 << static_cast<unsigned>(prefix_len_);
382
383 if (pd_exclude_option_) {
384 s << ", excluded_prefix_len="
385 << static_cast<unsigned>(pd_exclude_option_->getExcludedPrefixLength());
386 }
387 return (s.str());
388}
389
390}; // end of isc::dhcp namespace
391}; // end of isc namespace
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:223
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:268
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:263
Represents option data configuration for the DHCP server.
Definition: cfg_option.h:248
Container for storing client class names.
Definition: classify.h:43
bool contains(const ClientClass &x) const
returns if class x belongs to the defined classes
Definition: classify.h:94
std::list< ClientClass >::const_iterator const_iterator
Type of iterators.
Definition: classify.h:47
bool empty() const
Check if classes is empty.
Definition: classify.h:68
const_iterator cbegin() const
Iterator to the first element.
Definition: classify.h:81
const_iterator cend() const
Iterator to the past the end element.
Definition: classify.h:86
virtual data::ElementPtr toElement() const
Unparse a Pool4 object.
Definition: pool.cc:122
Pool4(const isc::asiolink::IOAddress &first, const isc::asiolink::IOAddress &last)
the constructor for Pool4 "min-max" style definition
Definition: pool.cc:47
uint8_t getLength() const
returns delegated prefix length
Definition: pool.h:344
virtual data::ElementPtr toElement() const
Unparse a Pool6 object.
Definition: pool.cc:306
Option6PDExcludePtr getPrefixExcludeOption() const
Returns instance of the pool specific Prefix Exclude option.
Definition: pool.h:352
virtual std::string toText() const
returns textual representation of the pool
Definition: pool.cc:377
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:144
Lease::Type getType() const
returns pool type
Definition: pool.h:335
base class for Pool4 and Pool6
Definition: pool.h:29
virtual data::ElementPtr toElement() const
Unparse a pool object.
Definition: pool.cc:90
Pool(Lease::Type type, const isc::asiolink::IOAddress &first, const isc::asiolink::IOAddress &last)
protected constructor
Definition: pool.cc:20
const isc::asiolink::IOAddress & getFirstAddress() const
Returns the first address in a pool.
Definition: pool.h:46
void allowClientClass(const ClientClass &class_name)
Sets the supported class to class class_name.
Definition: pool.cc:35
const isc::asiolink::IOAddress & getLastAddress() const
Returns the last address in a pool.
Definition: pool.h:52
const ClientClass & getClientClass() const
returns the client class
Definition: pool.h:120
const ClientClasses & getRequiredClasses() const
Returns classes which are required to be evaluated.
Definition: pool.h:134
isc::asiolink::IOAddress last_
The last address in a pool.
Definition: pool.h:201
uint64_t capacity_
Stores number of possible leases.
Definition: pool.h:212
isc::asiolink::IOAddress first_
The first address in a pool.
Definition: pool.h:198
CfgOptionPtr getCfgOption()
Returns pointer to the option data configuration for this pool.
Definition: pool.h:90
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:220
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:204
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:22
std::string ClientClass
Defines a single class name.
Definition: classify.h:37
uint64_t addrsInRange(const isc::asiolink::IOAddress &min, const isc::asiolink::IOAddress &max)
Returns number of available addresses in the specified range (min - max).
boost::shared_ptr< Option6PDExclude > Option6PDExcludePtr
Pointer to the Option6PDExclude object.
uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len)
Returns number of available IPv6 prefixes in the specified prefix.
int prefixLengthFromRange(const isc::asiolink::IOAddress &min, const isc::asiolink::IOAddress &max)
Returns prefix length from the specified range (min - max).
isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress &prefix, uint8_t len)
returns a last address in a given prefix
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
Definition: cfg_option.h:500
Defines the logger used by the top-level component of kea-dhcp-ddns.
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:35
Type
Type of lease or pool.
Definition: lease.h:38
@ TYPE_TA
the lease contains temporary IPv6 address
Definition: lease.h:40
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:41
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition: lease.h:39
static std::string typeToText(Type type)
returns text representation of a lease type
Definition: lease.cc:39