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 
9 #include <asiolink/io_address.h>
11 #include <dhcpsrv/pool.h>
12 #include <sstream>
13 
14 using namespace isc::asiolink;
15 using namespace isc::data;
16 
17 namespace isc {
18 namespace dhcp {
19 
20 Pool::Pool(Lease::Type type, const isc::asiolink::IOAddress& first,
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 
27 bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
28  return (first_.smallerEqual(addr) && addr.smallerEqual(last_));
29 }
30 
31 bool Pool::clientSupported(const ClientClasses& classes) const {
32  return (client_class_.empty() || classes.contains(client_class_));
33 }
34 
35 void Pool::allowClientClass(const ClientClass& class_name) {
36  client_class_ = class_name;
37 }
38 
39 std::string
40 Pool::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 
66 Pool4::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 
90 Pool::toElement() const {
91  // Prepare the map
92  ElementPtr map = Element::createMap();
93 
94  // Set user-context
95  contextToElement(map);
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
124  ElementPtr map = Pool::toElement();
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 
195 Pool6::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 
247 void
248 Pool6::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
308  ElementPtr map = Pool::toElement();
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 
376 std::string
377 Pool6::toText() const {
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
isc::dhcp::ConstCfgOptionPtr
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
Definition: cfg_option.h:500
isc::dhcp::Pool::getClientClass
const ClientClass & getClientClass() const
returns the client class
Definition: pool.h:120
isc::dhcp::Pool6::getType
Lease::Type getType() const
returns pool type
Definition: pool.h:335
io_address.h
isc::dhcp::addrsInRange
uint64_t addrsInRange(const isc::asiolink::IOAddress &min, const isc::asiolink::IOAddress &max)
Returns number of available addresses in the specified range (min - max).
Definition: addr_utilities.cc:209
isc::dhcp::Pool6::toElement
virtual data::ElementPtr toElement() const
Unparse a Pool6 object.
Definition: pool.cc:306
isc::dhcp::Pool::last_
isc::asiolink::IOAddress last_
The last address in a pool.
Definition: pool.h:201
isc::dhcp::Pool::getLastAddress
const isc::asiolink::IOAddress & getLastAddress() const
Returns the last address in a pool.
Definition: pool.h:52
isc::dhcp::Lease::Type
Type
Type of lease or pool.
Definition: lease.h:38
isc::dhcp::prefixLengthFromRange
int prefixLengthFromRange(const isc::asiolink::IOAddress &min, const isc::asiolink::IOAddress &max)
Returns prefix length from the specified range (min - max).
Definition: addr_utilities.cc:280
isc::data
Definition: cfg_to_element.h:25
isc::dhcp::Pool::getRequiredClasses
const ClientClasses & getRequiredClasses() const
Returns classes which are required to be evaluated.
Definition: pool.h:134
isc::dhcp::CfgOption
Represents option data configuration for the DHCP server.
Definition: cfg_option.h:248
isc::dhcp::Pool::allowClientClass
void allowClientClass(const ClientClass &class_name)
Sets the supported class to class class_name.
Definition: pool.cc:35
isc::dhcp::Pool::type_
Lease::Type type_
defines a lease type that will be served from this pool
Definition: pool.h:204
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::dhcp::Pool6::getLength
uint8_t getLength() const
returns delegated prefix length
Definition: pool.h:344
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::dhcp::ClientClasses::cbegin
const_iterator cbegin() const
Iterator to the first element.
Definition: classify.h:81
isc::dhcp::Lease::TYPE_PD
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:41
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::dhcp::prefixesInRange
uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len)
Returns number of available IPv6 prefixes in the specified prefix.
Definition: addr_utilities.cc:350
isc::ToElementError
Cannot unparse error.
Definition: cfg_to_element.h:19
isc::dhcp::Pool::client_class_
ClientClass client_class_
Optional definition of a client class.
Definition: pool.h:220
pool.h
isc::dhcp::ClientClasses::contains
bool contains(const ClientClass &x) const
returns if class x belongs to the defined classes
Definition: classify.h:94
isc::dhcp::Lease::TYPE_TA
@ TYPE_TA
the lease contains temporary IPv6 address
Definition: lease.h:40
addr_utilities.h
isc::dhcp::ClientClasses::empty
bool empty() const
Check if classes is empty.
Definition: classify.h:68
isc::dhcp::Pool::clientSupported
bool clientSupported(const ClientClasses &client_classes) const
Checks whether this pool supports client that belongs to specified classes.
Definition: pool.cc:31
isc::data::UserContext::contextToElement
void contextToElement(data::ElementPtr map) const
Merge unparse a user_context object.
Definition: user_context.cc:15
isc::dhcp::Pool6::Pool6
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
isc::dhcp::Pool::getFirstAddress
const isc::asiolink::IOAddress & getFirstAddress() const
Returns the first address in a pool.
Definition: pool.h:46
isc::dhcp::Pool::getCfgOption
CfgOptionPtr getCfgOption()
Returns pointer to the option data configuration for this pool.
Definition: pool.h:90
isc::dhcp::ClientClasses::const_iterator
std::list< ClientClass >::const_iterator const_iterator
Type of iterators.
Definition: classify.h:47
isc::dhcp::ClientClass
std::string ClientClass
Defines a single class name.
Definition: classify.h:37
isc::dhcp::Option6PDExcludePtr
boost::shared_ptr< Option6PDExclude > Option6PDExcludePtr
Pointer to the Option6PDExclude object.
Definition: option6_pdexclude.h:124
isc::dhcp::Pool
base class for Pool4 and Pool6
Definition: pool.h:29
isc::dhcp::Pool6::getPrefixExcludeOption
Option6PDExcludePtr getPrefixExcludeOption() const
Returns instance of the pool specific Prefix Exclude option.
Definition: pool.h:352
isc::dhcp::Pool6::toText
virtual std::string toText() const
returns textual representation of the pool
Definition: pool.cc:377
isc::dhcp::Pool::first_
isc::asiolink::IOAddress first_
The first address in a pool.
Definition: pool.h:198
isc::dhcp::Pool::capacity_
uint64_t capacity_
Stores number of possible leases.
Definition: pool.h:212
isc::dhcp::lastAddrInPrefix
isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress &prefix, uint8_t len)
returns a last address in a given prefix
Definition: addr_utilities.cc:187
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
isc::dhcp::Lease::typeToText
static std::string typeToText(Type type)
returns text representation of a lease type
Definition: lease.cc:39
isc::dhcp::Pool::inRange
bool inRange(const isc::asiolink::IOAddress &addr) const
Checks if a given address is in the range.
Definition: pool.cc:27
isc::dhcp::Lease
a common structure for IPv4 and IPv6 leases
Definition: lease.h:35
isc::dhcp::Pool::toElement
virtual data::ElementPtr toElement() const
Unparse a pool object.
Definition: pool.cc:90
isc::dhcp::Pool::toText
virtual std::string toText() const
returns textual representation of the pool
Definition: pool.cc:40
isc::dhcp::Lease::TYPE_NA
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition: lease.h:39
isc::dhcp::Pool4::Pool4
Pool4(const isc::asiolink::IOAddress &first, const isc::asiolink::IOAddress &last)
the constructor for Pool4 "min-max" style definition
Definition: pool.cc:47
isc::dhcp::ClientClasses::cend
const_iterator cend() const
Iterator to the past the end element.
Definition: classify.h:86
isc::dhcp::Pool4::toElement
virtual data::ElementPtr toElement() const
Unparse a Pool4 object.
Definition: pool.cc:122
isc::dhcp::ClientClasses
Container for storing client class names.
Definition: classify.h:43