Kea  2.5.2
subnet.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2023 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 <dhcp/option_space.h>
12 #include <dhcpsrv/dhcpsrv_log.h>
14 #include <dhcpsrv/flq_allocator.h>
19 #include <dhcpsrv/shared_network.h>
20 #include <dhcpsrv/subnet.h>
22 
23 #include <boost/lexical_cast.hpp>
24 #include <boost/make_shared.hpp>
25 
26 #include <algorithm>
27 #include <limits>
28 #include <sstream>
29 
30 using namespace isc::asiolink;
31 using namespace isc::data;
32 using namespace isc::dhcp;
33 using namespace isc::util;
34 
35 using namespace std;
36 
37 namespace {
38 
43 bool
44 prefixLessThanFirstAddress(const IOAddress& prefix,
45  const PoolPtr& pool) {
46  return (prefix < pool->getFirstAddress());
47 }
48 
57 bool
58 comparePoolFirstAddress(const PoolPtr& pool1,
59  const PoolPtr& pool2) {
60  return (pool1->getFirstAddress() < pool2->getFirstAddress());
61 }
62 
63 }
64 
65 namespace isc {
66 namespace dhcp {
67 
68 // This is an initial value of subnet-id. See comments in subnet.h for details.
69 SubnetID Subnet::static_id_ = 1;
70 
71 Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
72  const SubnetID id)
73  : id_(id == 0 ? generateNextID() : id), prefix_(prefix),
74  prefix_len_(len),
75  shared_network_name_() {
76  if ((id == 0) && (id_ == 1)) {
77  // Emit a warning on the first auto-numbered subnet.
79  .arg(toText());
80  }
81  if ((prefix.isV6() && len > 128) ||
82  (prefix.isV4() && len > 32)) {
84  "Invalid prefix length specified for subnet: " << len);
85  }
86 }
87 
88 bool
92 
93  return ((first <= addr) && (addr <= last));
94 }
95 
96 std::string
97 Subnet::toText() const {
98  std::stringstream tmp;
99  tmp << prefix_ << "/" << static_cast<unsigned int>(prefix_len_);
100  return (tmp.str());
101 }
102 
103 uint128_t
105  switch (type) {
106  case Lease::TYPE_V4:
107  case Lease::TYPE_NA:
108  return sumPoolCapacity(pools_);
109  case Lease::TYPE_TA:
110  return sumPoolCapacity(pools_ta_);
111  case Lease::TYPE_PD:
112  return sumPoolCapacity(pools_pd_);
113  default:
114  isc_throw(BadValue, "Unsupported pool type: "
115  << static_cast<int>(type));
116  }
117 }
118 
119 uint128_t
121  const ClientClasses& client_classes) const {
122  switch (type) {
123  case Lease::TYPE_V4:
124  case Lease::TYPE_NA:
125  return sumPoolCapacity(pools_, client_classes);
126  case Lease::TYPE_TA:
127  return sumPoolCapacity(pools_ta_, client_classes);
128  case Lease::TYPE_PD:
129  return sumPoolCapacity(pools_pd_, client_classes);
130  default:
131  isc_throw(BadValue, "Unsupported pool type: "
132  << static_cast<int>(type));
133  }
134 }
135 
136 uint128_t
138  const ClientClasses& client_classes,
139  Allocator::PrefixLenMatchType prefix_length_match,
140  uint8_t hint_prefix_length) const {
141  switch (type) {
142  case Lease::TYPE_V4:
143  case Lease::TYPE_NA:
144  return sumPoolCapacity(pools_, client_classes);
145  case Lease::TYPE_TA:
146  return sumPoolCapacity(pools_ta_, client_classes);
147  case Lease::TYPE_PD:
148  return sumPoolCapacity(pools_pd_, client_classes, prefix_length_match,
149  hint_prefix_length);
150  default:
151  isc_throw(BadValue, "Unsupported pool type: "
152  << static_cast<int>(type));
153  }
154 }
155 
156 uint128_t
158  uint128_t sum(0);
159  for (auto const& p : pools) {
160  uint128_t const c(p->getCapacity());
161 
162  // Check if we can add it. If sum + c > UINT128_MAX, then we would have
163  // overflown if we tried to add it.
164  if (c > numeric_limits<uint128_t>::max() - sum) {
165  return (numeric_limits<uint128_t>::max());
166  }
167 
168  sum += c;
169  }
170 
171  return (sum);
172 }
173 
174 uint128_t
176  const ClientClasses& client_classes) const {
177  uint128_t sum(0);
178  for (auto const& p : pools) {
179  if (!p->clientSupported(client_classes)) {
180  continue;
181  }
182 
183  uint128_t const c(p->getCapacity());
184 
185  // Check if we can add it. If sum + c > UINT128_MAX, then we would have
186  // overflown if we tried to add it.
187  if (c > numeric_limits<uint128_t>::max() - sum) {
188  return (numeric_limits<uint128_t>::max());
189  }
190 
191  sum += c;
192  }
193 
194  return (sum);
195 }
196 
197 uint128_t
199  const ClientClasses& client_classes,
200  Allocator::PrefixLenMatchType prefix_length_match,
201  uint8_t hint_prefix_length) const {
202  uint128_t sum(0);
203  for (auto const& p : pools) {
204  if (!p->clientSupported(client_classes)) {
205  continue;
206  }
207 
208  if (!Allocator::isValidPrefixPool(prefix_length_match, p,
209  hint_prefix_length)) {
210  continue;
211  }
212 
213  uint128_t const c(p->getCapacity());
214 
215  // Check if we can add it. If sum + c > UINT128_MAX, then we would have
216  // overflown if we tried to add it.
217  if (c > numeric_limits<uint128_t>::max() - sum) {
218  return (numeric_limits<uint128_t>::max());
219  }
220 
221  sum += c;
222  }
223 
224  return (sum);
225 }
226 
227 std::pair<IOAddress, uint8_t>
228 Subnet::parsePrefixCommon(const std::string& prefix) {
229  auto pos = prefix.find('/');
230  if ((pos == std::string::npos) ||
231  (pos == prefix.size() - 1) ||
232  (pos == 0)) {
233  isc_throw(BadValue, "unable to parse invalid prefix " << prefix);
234  }
235 
236  try {
237  IOAddress address(prefix.substr(0, pos));
238  int length = boost::lexical_cast<int>(prefix.substr(pos + 1));
239  return (std::make_pair(address, static_cast<int>(length)));
240 
241  } catch (...) {
242  isc_throw(BadValue, "unable to parse invalid prefix " << prefix);
243  }
244 }
245 
246 
247 void Subnet4::checkType(Lease::Type type) const {
248  if (type != Lease::TYPE_V4) {
249  isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
250  }
251 }
252 
253 Subnet4::Subnet4(const IOAddress& prefix, uint8_t length,
254  const Triplet<uint32_t>& t1,
255  const Triplet<uint32_t>& t2,
256  const Triplet<uint32_t>& valid_lifetime,
257  const SubnetID id)
258  : Subnet(prefix, length, id), Network4() {
259  if (!prefix.isV4()) {
260  isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
261  << " specified in subnet4");
262  }
263  // Timers.
264  setT1(t1);
265  setT2(t2);
266  setValid(valid_lifetime);
267 }
268 
270 Subnet4::create(const IOAddress& prefix, uint8_t length,
271  const Triplet<uint32_t>& t1,
272  const Triplet<uint32_t>& t2,
273  const Triplet<uint32_t>& valid_lifetime,
274  const SubnetID id) {
275  Subnet4Ptr subnet = boost::make_shared<Subnet4>
276  (prefix, length, t1, t2, valid_lifetime, id);
277  subnet->setAllocator(Lease::TYPE_V4,
278  boost::make_shared<IterativeAllocator>
279  (Lease::TYPE_V4, subnet));
280  subnet->setAllocationState(Lease::TYPE_V4,
282 
283  return (subnet);
284 }
285 
287 Subnet4::getNextSubnet(const Subnet4Ptr& first_subnet) const {
288  SharedNetwork4Ptr network;
289  getSharedNetwork(network);
290  if (network) {
291  return (network->getNextSubnet(first_subnet, getID()));
292  }
293 
294  return (Subnet4Ptr());
295 }
296 
298 Subnet4::getNextSubnet(const Subnet4Ptr& first_subnet,
299  const ClientClasses& client_classes) const {
300  SharedNetwork4Ptr network;
301  getSharedNetwork(network);
302  // We can only get next subnet if shared network has been defined for
303  // the current subnet.
304  if (network) {
305  Subnet4Ptr subnet;
306  do {
307  // Use subnet identifier of this subnet if this is the first
308  // time we're calling getNextSubnet. Otherwise, use the
309  // subnet id of the previously returned subnet.
310  SubnetID subnet_id = subnet ? subnet->getID() : getID();
311  subnet = network->getNextSubnet(first_subnet, subnet_id);
312  // If client classes match the subnet, return it. Otherwise,
313  // try another subnet.
314  if (subnet && subnet->clientSupported(client_classes)) {
315  return (subnet);
316  }
317  } while (subnet);
318  }
319 
320  // No subnet found.
321  return (Subnet4Ptr());
322 }
323 
324 
325 bool
327  NetworkPtr network;
328  getSharedNetwork(network);
329  if (network && !network->clientSupported(client_classes)) {
330  return (false);
331  }
332 
333  return (Network4::clientSupported(client_classes));
334 }
335 
337  // check if the type is valid (and throw if it isn't)
338  checkType(type);
339 
340  switch (type) {
341  case Lease::TYPE_V4:
342  case Lease::TYPE_NA:
343  return (pools_);
344  case Lease::TYPE_TA:
345  return (pools_ta_);
346  case Lease::TYPE_PD:
347  return (pools_pd_);
348  default:
349  isc_throw(BadValue, "Unsupported pool type: "
350  << static_cast<int>(type));
351  }
352 }
353 
355  // check if the type is valid (and throw if it isn't)
356  checkType(type);
357 
358  switch (type) {
359  case Lease::TYPE_V4:
360  case Lease::TYPE_NA:
361  return (pools_);
362  case Lease::TYPE_TA:
363  return (pools_ta_);
364  case Lease::TYPE_PD:
365  return (pools_pd_);
366  default:
367  isc_throw(BadValue, "Invalid pool type specified: "
368  << static_cast<int>(type));
369  }
370 }
371 
374  auto alloc = allocators_.find(type);
375 
376  if (alloc == allocators_.end()) {
377  isc_throw(BadValue, "no allocator initialized for pool type "
378  << Lease::typeToText(type));
379  }
380  return (alloc->second);
381 }
382 
383 void
385  allocators_[type] = allocator;
386 }
387 
390  auto state = allocation_states_.find(type);
391 
392  if (state == allocation_states_.end()) {
393  isc_throw(BadValue, "no allocation state initialized for pool type "
394  << Lease::typeToText(type));
395  }
396  return (state->second);
397 }
398 
399 void
401  allocation_states_[type] = allocation_state;
402 }
403 
405  bool anypool /* true */) const {
406  // check if the type is valid (and throw if it isn't)
407  checkType(type);
408 
409  const auto& pools = getPools(type);
410 
411  PoolPtr candidate;
412 
413  if (!pools.empty()) {
414  // Pools are sorted by their first prefixes. For example: 2001::,
415  // 2001::db8::, 3000:: etc. If our hint is 2001:db8:5:: we want to
416  // find the pool with the longest matching prefix, so: 2001:db8::,
417  // rather than 2001::. upper_bound returns the first pool with a prefix
418  // that is greater than 2001:db8:5::, i.e. 3000::. To find the longest
419  // matching prefix we use decrement operator to go back by one item.
420  // If returned iterator points to begin it means that prefixes in all
421  // pools are greater than out prefix, and thus there is no match.
422  auto ub =
423  std::upper_bound(pools.begin(), pools.end(), hint,
424  prefixLessThanFirstAddress);
425 
426  if (ub != pools.begin()) {
427  --ub;
428  if ((*ub)->inRange(hint)) {
429  candidate = *ub;
430  }
431  }
432 
433  // If we don't find anything better, then let's just use the first pool
434  if (!candidate && anypool) {
435  candidate = *pools.begin();
436  }
437  }
438 
439  // Return a pool or NULL if no match found.
440  return (candidate);
441 }
442 
443 void
445  for (auto allocator : allocators_) {
446  allocator.second->initAfterConfigure();
447  }
448 }
449 
451  const ClientClasses& client_classes,
452  const isc::asiolink::IOAddress& hint) const {
453  // check if the type is valid (and throw if it isn't)
454  checkType(type);
455 
456  const auto& pools = getPools(type);
457 
458  PoolPtr candidate;
459 
460  if (!pools.empty()) {
461  auto ub =
462  std::upper_bound(pools.begin(), pools.end(), hint,
463  prefixLessThanFirstAddress);
464 
465  if (ub != pools.begin()) {
466  --ub;
467  if ((*ub)->inRange(hint) &&
468  (*ub)->clientSupported(client_classes)) {
469  candidate = *ub;
470  }
471  }
472  }
473 
474  // Return a pool or NULL if no match found.
475  return (candidate);
476 }
477 
478 void
479 Subnet::addPool(const PoolPtr& pool) {
480  // check if the type is valid (and throw if it isn't)
481  checkType(pool->getType());
482 
483  // Check that the pool is in range with a subnet only if this is
484  // not a pool of IPv6 prefixes. The IPv6 prefixes delegated for
485  // the particular subnet don't need to match the prefix of the
486  // subnet.
487  if (pool->getType() != Lease::TYPE_PD) {
488  if (!inRange(pool->getFirstAddress()) || !inRange(pool->getLastAddress())) {
489  isc_throw(BadValue, "a pool of type "
490  << Lease::typeToText(pool->getType())
491  << ", with the following address range: "
492  << pool->getFirstAddress() << "-"
493  << pool->getLastAddress() << " does not match"
494  << " the prefix of a subnet: "
495  << prefix_ << "/" << static_cast<int>(prefix_len_)
496  << " to which it is being added");
497 
498  }
499  }
500 
501  bool overlaps = false;
502  if (pool->getType() == Lease::TYPE_V4) {
503  overlaps = poolOverlaps(Lease::TYPE_V4, pool);
504 
505  } else {
506  overlaps =
507  poolOverlaps(Lease::TYPE_NA, pool) ||
508  poolOverlaps(Lease::TYPE_PD, pool) ||
510  }
511 
512  if (overlaps) {
513  isc_throw(BadValue,"a pool of type "
514  << Lease::typeToText(pool->getType())
515  << ", with the following address range: "
516  << pool->getFirstAddress() << "-"
517  << pool->getLastAddress() << " overlaps with "
518  "an existing pool in the subnet: "
519  << prefix_ << "/" << static_cast<int>(prefix_len_)
520  << " to which it is being added");
521  }
522 
523  PoolCollection& pools_writable = getPoolsWritable(pool->getType());
524 
525  // Add the pool to the appropriate pools collection
526  pools_writable.push_back(pool);
527 
528  // Sort pools by first address.
529  std::sort(pools_writable.begin(), pools_writable.end(),
530  comparePoolFirstAddress);
531 }
532 
533 void
535  getPoolsWritable(type).clear();
536 }
537 
538 bool
540 
541  // Let's start with checking if it even belongs to that subnet.
542  if ((type != Lease::TYPE_PD) && !inRange(addr)) {
543  return (false);
544  }
545 
546  const auto& pools = getPools(type);
547  for (const auto& pool : pools) {
548  if (pool->inRange(addr)) {
549  return (true);
550  }
551  }
552  // There's no pool that address belongs to
553  return (false);
554 }
555 
556 bool
558  const isc::asiolink::IOAddress& addr,
559  const ClientClasses& client_classes) const {
560 
561  // Let's start with checking if it even belongs to that subnet.
562  if ((type != Lease::TYPE_PD) && !inRange(addr)) {
563  return (false);
564  }
565 
566  const auto& pools = getPools(type);
567  for (const auto& pool : pools) {
568  if (!pool->clientSupported(client_classes)) {
569  continue;
570  }
571  if (pool->inRange(addr)) {
572  return (true);
573  }
574  }
575  // There's no pool that address belongs to
576  return (false);
577 }
578 
579 bool
580 Subnet::poolOverlaps(const Lease::Type& pool_type, const PoolPtr& pool) const {
581  const auto& pools = getPools(pool_type);
582 
583  // If no pools, we don't overlap. Nothing to do.
584  if (pools.empty()) {
585  return (false);
586  }
587 
588  // We're going to insert a new pool, likely between two existing pools.
589  // So we're going to end up with the following case:
590  // |<---- pool1 ---->| |<-------- pool2 ------>| |<-- pool3 -->|
591  // F1 L1 F2 L2 F3 L3
592  // where pool1 and pool3 are existing pools, pool2 is a pool being
593  // inserted and "F"/"L" mark first and last address in the pools
594  // respectively. So the following conditions must be fulfilled:
595  // F2 > L1 and L2 < F3. Obviously, for any pool: F < L.
596 
597  // Search for pool3. We use F2 and upper_bound to find the F3 (upper_bound
598  // returns first pool in the sorted container which first address is
599  // greater than F2). prefixLessThanPoolAddress with the first argument
600  // set to "true" is the custom comparison function for upper_bound, which
601  // compares F2 with the first addresses of the existing pools.
602  const auto pool3_it =
603  std::upper_bound(pools.begin(), pools.end(), pool->getFirstAddress(),
604  prefixLessThanFirstAddress);
605 
606  // The upper_bound function returns a first pool which first address is
607  // greater than the address F2. However, it is also possible that there is a
608  // pool which first address is equal to F2. Such pool is also in conflict
609  // with a new pool. If the returned value is pools.begin() it means that all
610  // pools have greater first address than F2, thus none of the pools can have
611  // first address equal to F2. Otherwise, we'd need to check them for
612  // equality. However any pool has first address <= last address, so checking
613  // that the new pool first address is greater than the pool before pool3
614  // last address is enough. We now have to find the pool1. This pool should
615  // be right before the pool3 if there is any pool before pool3.
616  if (pool3_it != pools.begin()) {
617  PoolPtr pool1 = *(pool3_it - 1);
618  // F2 must be greater than L1, otherwise pools will overlap.
619  if (pool->getFirstAddress() <= pool1->getLastAddress()) {
620  return (true);
621  }
622  }
623 
624  // If returned value is unequal pools.end() it means that there is a pool3,
625  // with F3 > F2.
626  if (pool3_it != pools.end()) {
627  // Let's store the pointer to this pool.
628  PoolPtr pool3 = *pool3_it;
629  // F3 must be greater than L2, otherwise pools will overlap.
630  if (pool3->getFirstAddress() <= pool->getLastAddress()) {
631  return (true);
632  }
633  }
634 
635  return (false);
636 }
637 
638 Subnet6::Subnet6(const IOAddress& prefix, uint8_t length,
639  const Triplet<uint32_t>& t1,
640  const Triplet<uint32_t>& t2,
641  const Triplet<uint32_t>& preferred_lifetime,
642  const Triplet<uint32_t>& valid_lifetime,
643  const SubnetID id)
644  : Subnet(prefix, length, id), Network6() {
645  if (!prefix.isV6()) {
646  isc_throw(BadValue, "Non IPv6 prefix " << prefix
647  << " specified in subnet6");
648  }
649 
650  // Timers.
651  setT1(t1);
652  setT2(t2);
653  setPreferred(preferred_lifetime);
654  setValid(valid_lifetime);
655 }
656 
658 Subnet6::create(const IOAddress& prefix, uint8_t length,
659  const Triplet<uint32_t>& t1,
660  const Triplet<uint32_t>& t2,
661  const Triplet<uint32_t>& preferred_lifetime,
662  const Triplet<uint32_t>& valid_lifetime,
663  const SubnetID id) {
664  Subnet6Ptr subnet = boost::make_shared<Subnet6>
665  (prefix, length, t1, t2, preferred_lifetime, valid_lifetime, id);
666  // IA_NA
667  subnet->setAllocator(Lease::TYPE_NA,
668  boost::make_shared<IterativeAllocator>
669  (Lease::TYPE_NA, subnet));
670  subnet->setAllocationState(Lease::TYPE_NA,
672  // IA_TA
673  subnet->setAllocator(Lease::TYPE_TA,
674  boost::make_shared<IterativeAllocator>
675  (Lease::TYPE_TA, subnet));
676  subnet->setAllocationState(Lease::TYPE_TA,
678  // IA_PD
679  subnet->setAllocator(Lease::TYPE_PD,
680  boost::make_shared<IterativeAllocator>
681  (Lease::TYPE_PD, subnet));
682  subnet->setAllocationState(Lease::TYPE_PD,
684  return (subnet);
685 }
686 
687 void Subnet6::checkType(Lease::Type type) const {
688  if ((type != Lease::TYPE_NA) && (type != Lease::TYPE_TA) && (type != Lease::TYPE_PD)) {
689  isc_throw(BadValue, "Invalid Pool type: " << Lease::typeToText(type)
690  << "(" << static_cast<int>(type)
691  << "), must be TYPE_NA, TYPE_TA or TYPE_PD for Subnet6");
692  }
693 }
694 
696 Subnet6::getNextSubnet(const Subnet6Ptr& first_subnet) const {
697  SharedNetwork6Ptr network;
698  getSharedNetwork(network);
699  if (network) {
700  return (network->getNextSubnet(first_subnet, getID()));
701  }
702 
703  return (Subnet6Ptr());
704 }
705 
707 Subnet6::getNextSubnet(const Subnet6Ptr& first_subnet,
708  const ClientClasses& client_classes) const {
709  SharedNetwork6Ptr network;
710  getSharedNetwork(network);
711  // We can only get next subnet if shared network has been defined for
712  // the current subnet.
713  if (network) {
714  Subnet6Ptr subnet;
715  do {
716  // Use subnet identifier of this subnet if this is the first
717  // time we're calling getNextSubnet. Otherwise, use the
718  // subnet id of the previously returned subnet.
719  SubnetID subnet_id = subnet ? subnet->getID() : getID();
720  subnet = network->getNextSubnet(first_subnet, subnet_id);
721  // If client classes match the subnet, return it. Otherwise,
722  // try another subnet.
723  if (subnet && subnet->clientSupported(client_classes)) {
724  return (subnet);
725  }
726  } while (subnet);
727  }
728 
729  // No subnet found.
730  return (Subnet6Ptr());
731 }
732 
733 bool
735  NetworkPtr network;
736  getSharedNetwork(network);
737  if (network && !network->clientSupported(client_classes)) {
738  return (false);
739  }
740 
741  return (Network6::clientSupported(client_classes));
742 }
743 
747 
748  // Add user-context
749  contextToElement(map);
750 
751  // Set subnet id
752  SubnetID id = getID();
753  map->set("id", Element::create(static_cast<long long>(id)));
754 
755  // Set subnet
756  map->set("subnet", Element::create(toText()));
757 
758  return (map);
759 }
760 
761 void
763  auto allocator_type = getAllocatorType();
764  if (allocator_type.empty()) {
765  allocator_type = getDefaultAllocatorType();
766  }
767  if (allocator_type == "random") {
769  boost::make_shared<RandomAllocator>
770  (Lease::TYPE_V4, shared_from_this()));
772 
773  for (auto pool : pools_) {
774  pool->setAllocationState(PoolRandomAllocationState::create(pool));
775  }
776 
777  } else if (allocator_type == "flq") {
779  boost::make_shared<FreeLeaseQueueAllocator>
780  (Lease::TYPE_V4, shared_from_this()));
782 
783  for (auto pool : pools_) {
784  pool->setAllocationState(PoolFreeLeaseQueueAllocationState::create(pool));
785  }
786 
787  } else {
789  boost::make_shared<IterativeAllocator>
790  (Lease::TYPE_V4, shared_from_this()));
792  SubnetIterativeAllocationState::create(shared_from_this()));
793 
794  for (auto pool : pools_) {
795  pool->setAllocationState(PoolIterativeAllocationState::create(pool));
796  }
797  }
798 }
799 
802  // Prepare the map
804  ElementPtr network_map = Network4::toElement();
805 
806  merge(map, network_map);
807 
808  // Set DHCP4o6
809  const Cfg4o6& d4o6 = get4o6();
810  isc::data::merge(map, d4o6.toElement());
811 
812  // Set pools
813  const auto& pools = getPools(Lease::TYPE_V4);
814  ElementPtr pool_list = Element::createList();
815  for (const auto& pool : pools) {
816  // Add the formatted pool to the list
817  pool_list->add(pool->toElement());
818  }
819  map->set("pools", pool_list);
820 
821  return (map);
822 }
823 
824 std::pair<IOAddress, uint8_t>
825 Subnet4::parsePrefix(const std::string& prefix) {
826  std::pair<IOAddress, uint8_t> parsed = Subnet::parsePrefixCommon(prefix);
827  if (!parsed.first.isV4() || parsed.first.isV4Zero() ||
828  (parsed.second > 32) || (parsed.second == 0)) {
829  isc_throw(BadValue, "unable to parse invalid IPv4 prefix " << prefix);
830  }
831  return (parsed);
832 }
833 
834 void
836  auto allocator_type = getAllocatorType();
837  if (allocator_type.empty()) {
838  allocator_type = getDefaultAllocatorType();
839  }
840  if (allocator_type == "random") {
842  boost::make_shared<RandomAllocator>
843  (Lease::TYPE_NA, shared_from_this()));
845  boost::make_shared<RandomAllocator>
846  (Lease::TYPE_TA, shared_from_this()));
849 
850  } else if (allocator_type == "flq") {
851  isc_throw(BadValue, "Free Lease Queue allocator is not supported for IPv6 address pools");
852 
853  } else {
855  boost::make_shared<IterativeAllocator>
856  (Lease::TYPE_NA, shared_from_this()));
859  }
860 
861  auto pd_allocator_type = getPdAllocatorType();
862  if (pd_allocator_type.empty()) {
863  pd_allocator_type = getDefaultPdAllocatorType();
864  }
865  // Repeat the same for the delegated prefix allocator.
866  if (pd_allocator_type == "random") {
868  boost::make_shared<RandomAllocator>
869  (Lease::TYPE_PD, shared_from_this()));
871 
872  } else if (pd_allocator_type == "flq") {
874  boost::make_shared<FreeLeaseQueueAllocator>
875  (Lease::TYPE_PD, shared_from_this()));
877 
878  } else {
880  boost::make_shared<IterativeAllocator>
881  (Lease::TYPE_PD, shared_from_this()));
883  }
884  // Create allocation states for NA pools.
885  for (auto pool : pools_) {
886  if (allocator_type == "random") {
887  pool->setAllocationState(PoolRandomAllocationState::create(pool));
888  } else {
889  pool->setAllocationState(PoolIterativeAllocationState::create(pool));
890  }
891  }
892  // Create allocation states for TA pools.
893  for (auto pool : pools_ta_) {
894  if (allocator_type == "random") {
895  pool->setAllocationState(PoolRandomAllocationState::create(pool));
896  } else {
897  pool->setAllocationState(PoolIterativeAllocationState::create(pool));
898  }
899  }
900  // Create allocation states for PD pools.
901  for (auto pool : pools_pd_) {
902  if (pd_allocator_type == "random") {
903  pool->setAllocationState(PoolRandomAllocationState::create(pool));
904  } else if (pd_allocator_type == "flq") {
905  pool->setAllocationState(PoolFreeLeaseQueueAllocationState::create(pool));
906  } else {
907  pool->setAllocationState(PoolIterativeAllocationState::create(pool));
908  }
909  }
910 }
911 
914  // Prepare the map
916  ElementPtr network_map = Network6::toElement();
917 
918  merge(map, network_map);
919 
920  // Set pools
921  const auto& pools = getPools(Lease::TYPE_NA);
922  ElementPtr pool_list = Element::createList();
923  for (const auto& pool : pools) {
924  // Add the formatted pool to the list
925  pool_list->add(pool->toElement());
926  }
927  map->set("pools", pool_list);
928 
929  // Set pd-pools
930  const auto& pdpools = getPools(Lease::TYPE_PD);
931  ElementPtr pdpool_list = Element::createList();
932  for (const auto& pool : pdpools) {
933  // Add the formatted pool to the list
934  pdpool_list->add(pool->toElement());
935  }
936  map->set("pd-pools", pdpool_list);
937 
938  return (map);
939 }
940 
941 std::pair<IOAddress, uint8_t>
942 Subnet6::parsePrefix(const std::string& prefix) {
943  std::pair<IOAddress, uint8_t> parsed = Subnet::parsePrefixCommon(prefix);
944  if (!parsed.first.isV6() || parsed.first.isV6Zero() ||
945  (parsed.second > 128) || (parsed.second == 0)) {
946  isc_throw(BadValue, "unable to parse invalid IPv6 prefix " << prefix);
947  }
948  return (parsed);
949 }
950 
951 } // namespace dhcp
952 } // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:246
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:301
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:296
PrefixLenMatchType
Type of preferred PD-pool prefix length selection criteria.
Definition: allocator.h:61
static bool isValidPrefixPool(Allocator::PrefixLenMatchType prefix_length_match, PoolPtr pool, uint8_t hint_prefix_length)
Check if the pool matches the selection criteria relative to the provided hint prefix length.
Definition: allocator.cc:39
Container for storing client class names.
Definition: classify.h:108
Specialization of the Network object for DHCPv4 case.
Definition: network.h:1260
virtual data::ElementPtr toElement() const
Unparses network object.
Definition: network.cc:299
Specialization of the Network object for DHCPv6 case.
Definition: network.h:1421
util::Optional< std::string > getPdAllocatorType(const Inheritance &inheritance=Inheritance::ALL) const
Returns allocator type for prefix delegation.
Definition: network.h:1492
void setPreferred(const isc::util::Triplet< uint32_t > &preferred)
Sets new preferred lifetime for a network.
Definition: network.h:1446
virtual data::ElementPtr toElement() const
Unparses network object.
Definition: network.cc:351
util::Optional< std::string > getDefaultPdAllocatorType(const Inheritance &inheritance=Inheritance::ALL) const
Returns a default allocator type for prefix delegation.
Definition: network.h:1517
virtual bool clientSupported(const isc::dhcp::ClientClasses &client_classes) const
Checks whether this network supports client that belongs to specified classes.
Definition: network.cc:69
void setT2(const isc::util::Triplet< uint32_t > &t2)
Sets new rebind timer for a network.
Definition: network.h:416
util::Optional< std::string > getAllocatorType(const Inheritance &inheritance=Inheritance::ALL) const
Returns allocator type.
Definition: network.h:805
util::Optional< std::string > getDefaultAllocatorType(const Inheritance &inheritance=Inheritance::ALL) const
Returns a default allocator type.
Definition: network.h:830
void setT1(const isc::util::Triplet< uint32_t > &t1)
Sets new renew timer for a network.
Definition: network.h:401
void setValid(const isc::util::Triplet< uint32_t > &valid)
Sets new valid lifetime for a network.
Definition: network.h:386
static PoolFreeLeaseQueueAllocationStatePtr create(const PoolPtr &pool)
Factory function creating the state instance from a pool.
static PoolIterativeAllocationStatePtr create(const PoolPtr &pool)
Factory function creating the state instance from pool.
static PoolRandomAllocationStatePtr create(const PoolPtr &pool)
Factory function creating the state instance from pool.
virtual bool clientSupported(const isc::dhcp::ClientClasses &client_classes) const
Checks whether this subnet and parent shared network supports the client that belongs to specified cl...
Definition: subnet.cc:326
Subnet4Ptr getNextSubnet(const Subnet4Ptr &first_subnet) const
Returns next subnet within shared network.
Definition: subnet.cc:287
Cfg4o6 & get4o6()
Returns DHCP4o6 configuration parameters.
Definition: subnet.h:597
virtual void createAllocators()
Instantiates the allocator and its state.
Definition: subnet.cc:762
virtual data::ElementPtr toElement() const
Unparse a subnet object.
Definition: subnet.cc:801
static Subnet4Ptr create(const isc::asiolink::IOAddress &prefix, uint8_t length, const util::Triplet< uint32_t > &t1, const util::Triplet< uint32_t > &t2, const util::Triplet< uint32_t > &valid_lifetime, const SubnetID id)
Factory function creating an instance of the Subnet4.
Definition: subnet.cc:270
Subnet4(const isc::asiolink::IOAddress &prefix, uint8_t length, const util::Triplet< uint32_t > &t1, const util::Triplet< uint32_t > &t2, const util::Triplet< uint32_t > &valid_lifetime, const SubnetID id)
Constructor with all parameters.
Definition: subnet.cc:253
static std::pair< asiolink::IOAddress, uint8_t > parsePrefix(const std::string &prefix)
Converts subnet prefix to a pair of prefix/length pair.
Definition: subnet.cc:825
virtual bool clientSupported(const isc::dhcp::ClientClasses &client_classes) const
Checks whether this subnet and parent shared network supports the client that belongs to specified cl...
Definition: subnet.cc:734
static Subnet6Ptr create(const isc::asiolink::IOAddress &prefix, uint8_t length, const util::Triplet< uint32_t > &t1, const util::Triplet< uint32_t > &t2, const util::Triplet< uint32_t > &preferred_lifetime, const util::Triplet< uint32_t > &valid_lifetime, const SubnetID id)
Factory function creating an instance of the Subnet4.
Definition: subnet.cc:658
static std::pair< asiolink::IOAddress, uint8_t > parsePrefix(const std::string &prefix)
Converts subnet prefix to a pair of prefix/length pair.
Definition: subnet.cc:942
virtual void createAllocators()
Instantiates the allocators and their states.
Definition: subnet.cc:835
Subnet6Ptr getNextSubnet(const Subnet6Ptr &first_subnet) const
Returns next subnet within shared network.
Definition: subnet.cc:696
virtual data::ElementPtr toElement() const
Unparse a subnet object.
Definition: subnet.cc:913
Subnet6(const isc::asiolink::IOAddress &prefix, uint8_t length, const util::Triplet< uint32_t > &t1, const util::Triplet< uint32_t > &t2, const util::Triplet< uint32_t > &preferred_lifetime, const util::Triplet< uint32_t > &valid_lifetime, const SubnetID id)
Constructor with all parameters.
Definition: subnet.cc:638
static SubnetIterativeAllocationStatePtr create(const SubnetPtr &subnet)
Factory function creating the state instance from subnet.
isc::util::uint128_t getPoolCapacity(Lease::Type type) const
Returns the number of possible leases for specified lease type.
Definition: subnet.cc:104
isc::asiolink::IOAddress prefix_
a prefix of the subnet.
Definition: subnet.h:473
SubnetID getID() const
Returns unique ID for that subnet.
Definition: subnet.h:83
uint8_t prefix_len_
a prefix length of the subnet.
Definition: subnet.h:476
isc::util::uint128_t sumPoolCapacity(const PoolCollection &pools) const
Returns a sum of possible leases in all pools.
Definition: subnet.cc:157
virtual data::ElementPtr toElement() const
Unparse a subnet object.
Definition: subnet.cc:745
AllocatorPtr getAllocator(Lease::Type type) const
Returns lease allocator instance.
Definition: subnet.cc:373
PoolCollection pools_ta_
collection of IPv6 temporary address pools in that subnet.
Definition: subnet.h:467
void getSharedNetwork(SharedNetworkPtrType &shared_network) const
Retrieves pointer to a shared network associated with a subnet.
Definition: subnet.h:240
void initAllocatorsAfterConfigure()
Calls initAfterConfigure for each allocator.
Definition: subnet.cc:444
SubnetID id_
subnet-id
Definition: subnet.h:461
SubnetAllocationStatePtr getAllocationState(Lease::Type type) const
Returns subnet-specific allocation state.
Definition: subnet.cc:389
void addPool(const PoolPtr &pool)
Adds a new pool for the subnet.
Definition: subnet.cc:479
bool inRange(const isc::asiolink::IOAddress &addr) const
checks if specified address is in range.
Definition: subnet.cc:89
std::map< Lease::Type, AllocatorPtr > allocators_
Lease allocators used by the subnet.
Definition: subnet.h:482
virtual std::string toText() const
Returns textual representation of the subnet (e.g.
Definition: subnet.cc:97
void delPools(Lease::Type type)
Deletes all pools of specified type.
Definition: subnet.cc:534
static std::pair< asiolink::IOAddress, uint8_t > parsePrefixCommon(const std::string &prefix)
Converts subnet prefix to a pair of prefix/length pair.
Definition: subnet.cc:228
void setAllocator(Lease::Type type, const AllocatorPtr &allocator)
Sets new allocator instance.
Definition: subnet.cc:384
PoolCollection pools_
collection of IPv4 or non-temporary IPv6 pools in that subnet.
Definition: subnet.h:464
PoolCollection & getPoolsWritable(Lease::Type type)
Returns all pools (non-const variant).
Definition: subnet.cc:354
const PoolPtr getPool(Lease::Type type, const isc::asiolink::IOAddress &addr, bool anypool=true) const
Returns a pool that specified address belongs to.
Definition: subnet.cc:404
bool poolOverlaps(const Lease::Type &pool_type, const PoolPtr &pool) const
Checks if the specified pool overlaps with an existing pool.
Definition: subnet.cc:580
PoolCollection pools_pd_
collection of IPv6 prefix pools in that subnet.
Definition: subnet.h:470
const PoolCollection & getPools(Lease::Type type) const
Returns all pools (const variant).
Definition: subnet.cc:336
virtual void checkType(Lease::Type type) const =0
Checks if used pool type is valid.
std::map< Lease::Type, SubnetAllocationStatePtr > allocation_states_
Holds subnet-specific allocation state.
Definition: subnet.h:485
bool inPool(Lease::Type type, const isc::asiolink::IOAddress &addr) const
checks if the specified address is in pools.
Definition: subnet.cc:539
void setAllocationState(Lease::Type type, const SubnetAllocationStatePtr &allocation_state)
Sets subnet-specific allocation state.
Definition: subnet.cc:400
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
void merge(ElementPtr element, ConstElementPtr other)
Merges the data from other into element.
Definition: data.cc:1174
boost::shared_ptr< Element > ElementPtr
Definition: data.h:26
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition: subnet.h:498
boost::shared_ptr< Subnet6 > Subnet6Ptr
A pointer to a Subnet6 object.
Definition: subnet.h:663
std::vector< PoolPtr > PoolCollection
a container for either IPv4 or IPv6 Pools
Definition: pool.h:486
boost::shared_ptr< SharedNetwork6 > SharedNetwork6Ptr
Pointer to SharedNetwork6 object.
boost::shared_ptr< Pool > PoolPtr
a pointer to either IPv4 or IPv6 Pool
Definition: pool.h:483
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:25
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition: network.h:70
boost::shared_ptr< Allocator > AllocatorPtr
Defines a pointer to an allocator.
Definition: allocator.h:239
boost::shared_ptr< SubnetAllocationState > SubnetAllocationStatePtr
boost::shared_ptr< SharedNetwork4 > SharedNetwork4Ptr
Pointer to SharedNetwork4 object.
const isc::log::MessageID DHCPSRV_CONFIGURED_SUBNET_WITHOUT_ID
Definition: edns.h:19
boost::multiprecision::uint128_t uint128_t
Definition: bigints.h:21
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
This structure contains information about DHCP4o6 (RFC7341)
Definition: cfg_4o6.h:22
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
Definition: cfg_4o6.cc:22
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_V4
IPv4 lease.
Definition: lease.h:50
@ 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