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