1 // Copyright (C) 2012-2021 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>
10 #include <asiolink/addr_utilities.h>
11 #include <dhcp/option_space.h>
12 #include <dhcpsrv/shared_network.h>
13 #include <dhcpsrv/subnet.h>
14 #include <util/multi_threading_mgr.h>
15
16 #include <boost/lexical_cast.hpp>
17 #include <boost/make_shared.hpp>
18
19 #include <algorithm>
20 #include <sstream>
21
22 using namespace isc::asiolink;
23 using namespace isc::data;
24 using namespace isc::dhcp;
25 using namespace isc::util;
26
27 namespace {
28
29 /// @brief Function used in calls to std::upper_bound to check
30 /// if the specified prefix is lower than the first address a pool.
31 ///
32 /// @return true if prefix is lower than the first address in the pool.
33 bool
prefixLessThanFirstAddress(const IOAddress & prefix,const PoolPtr & pool)34 prefixLessThanFirstAddress(const IOAddress& prefix, const PoolPtr& pool) {
35 return (prefix < pool->getFirstAddress());
36 }
37
38 /// @brief Function used in calls to std::sort to compare first
39 /// prefixes of the two pools.
40 ///
41 /// @param pool1 First pool.
42 /// @param pool2 Second pool.
43 ///
44 /// @return true if first prefix of the first pool is smaller than
45 /// the first address of the second pool.
46 bool
comparePoolFirstAddress(const PoolPtr & pool1,const PoolPtr & pool2)47 comparePoolFirstAddress(const PoolPtr& pool1, const PoolPtr& pool2) {
48 return (pool1->getFirstAddress() < pool2->getFirstAddress());
49 };
50
51 }
52
53 namespace isc {
54 namespace dhcp {
55
56 // This is an initial value of subnet-id. See comments in subnet.h for details.
57 SubnetID Subnet::static_id_ = 1;
58
Subnet(const isc::asiolink::IOAddress & prefix,uint8_t len,const SubnetID id)59 Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
60 const SubnetID id)
61 : id_(id == 0 ? generateNextID() : id), prefix_(prefix),
62 prefix_len_(len),
63 last_allocated_ia_(lastAddrInPrefix(prefix, len)),
64 last_allocated_ta_(lastAddrInPrefix(prefix, len)),
65 last_allocated_pd_(lastAddrInPrefix(prefix, len)),
66 last_allocated_time_(),
67 shared_network_name_(),
68 mutex_(new std::mutex) {
69 if ((prefix.isV6() && len > 128) ||
70 (prefix.isV4() && len > 32)) {
71 isc_throw(BadValue,
72 "Invalid prefix length specified for subnet: " << len);
73 }
74
75 // Initialize timestamps for each lease type to negative infinity.
76 last_allocated_time_[Lease::TYPE_V4] = boost::posix_time::neg_infin;
77 last_allocated_time_[Lease::TYPE_NA] = boost::posix_time::neg_infin;
78 last_allocated_time_[Lease::TYPE_TA] = boost::posix_time::neg_infin;
79 last_allocated_time_[Lease::TYPE_PD] = boost::posix_time::neg_infin;
80 }
81
82 bool
inRange(const isc::asiolink::IOAddress & addr) const83 Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
84 IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
85 IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
86
87 return ((first <= addr) && (addr <= last));
88 }
89
getLastAllocated(Lease::Type type) const90 isc::asiolink::IOAddress Subnet::getLastAllocated(Lease::Type type) const {
91 if (MultiThreadingMgr::instance().getMode()) {
92 std::lock_guard<std::mutex> lock(*mutex_);
93 return (getLastAllocatedInternal(type));
94 } else {
95 return (getLastAllocatedInternal(type));
96 }
97 }
98
getLastAllocatedInternal(Lease::Type type) const99 isc::asiolink::IOAddress Subnet::getLastAllocatedInternal(Lease::Type type) const {
100 // check if the type is valid (and throw if it isn't)
101 checkType(type);
102
103 switch (type) {
104 case Lease::TYPE_V4:
105 case Lease::TYPE_NA:
106 return last_allocated_ia_;
107 case Lease::TYPE_TA:
108 return last_allocated_ta_;
109 case Lease::TYPE_PD:
110 return last_allocated_pd_;
111 default:
112 isc_throw(BadValue, "Pool type " << type << " not supported");
113 }
114 }
115
116 boost::posix_time::ptime
getLastAllocatedTime(const Lease::Type & lease_type) const117 Subnet::getLastAllocatedTime(const Lease::Type& lease_type) const {
118 if (MultiThreadingMgr::instance().getMode()) {
119 std::lock_guard<std::mutex> lock(*mutex_);
120 return (getLastAllocatedTimeInternal(lease_type));
121 } else {
122 return (getLastAllocatedTimeInternal(lease_type));
123 }
124 }
125
126 boost::posix_time::ptime
getLastAllocatedTimeInternal(const Lease::Type & lease_type) const127 Subnet::getLastAllocatedTimeInternal(const Lease::Type& lease_type) const {
128 auto t = last_allocated_time_.find(lease_type);
129 if (t != last_allocated_time_.end()) {
130 return (t->second);
131 }
132
133 // This shouldn't happen, because we have initialized the structure
134 // for all lease types.
135 return (boost::posix_time::neg_infin);
136 }
137
setLastAllocated(Lease::Type type,const isc::asiolink::IOAddress & addr)138 void Subnet::setLastAllocated(Lease::Type type,
139 const isc::asiolink::IOAddress& addr) {
140 if (MultiThreadingMgr::instance().getMode()) {
141 std::lock_guard<std::mutex> lock(*mutex_);
142 setLastAllocatedInternal(type, addr);
143 } else {
144 setLastAllocatedInternal(type, addr);
145 }
146 }
147
setLastAllocatedInternal(Lease::Type type,const isc::asiolink::IOAddress & addr)148 void Subnet::setLastAllocatedInternal(Lease::Type type,
149 const isc::asiolink::IOAddress& addr) {
150
151 // check if the type is valid (and throw if it isn't)
152 checkType(type);
153
154 switch (type) {
155 case Lease::TYPE_V4:
156 case Lease::TYPE_NA:
157 last_allocated_ia_ = addr;
158 break;
159 case Lease::TYPE_TA:
160 last_allocated_ta_ = addr;
161 break;
162 case Lease::TYPE_PD:
163 last_allocated_pd_ = addr;
164 break;
165 default:
166 isc_throw(BadValue, "Pool type " << type << " not supported");
167 }
168
169 // Update the timestamp of last allocation.
170 last_allocated_time_[type] = boost::posix_time::microsec_clock::universal_time();
171 }
172
173 std::string
toText() const174 Subnet::toText() const {
175 std::stringstream tmp;
176 tmp << prefix_ << "/" << static_cast<unsigned int>(prefix_len_);
177 return (tmp.str());
178 }
179
180 uint64_t
getPoolCapacity(Lease::Type type) const181 Subnet::getPoolCapacity(Lease::Type type) const {
182 switch (type) {
183 case Lease::TYPE_V4:
184 case Lease::TYPE_NA:
185 return sumPoolCapacity(pools_);
186 case Lease::TYPE_TA:
187 return sumPoolCapacity(pools_ta_);
188 case Lease::TYPE_PD:
189 return sumPoolCapacity(pools_pd_);
190 default:
191 isc_throw(BadValue, "Unsupported pool type: "
192 << static_cast<int>(type));
193 }
194 }
195
196 uint64_t
getPoolCapacity(Lease::Type type,const ClientClasses & client_classes) const197 Subnet::getPoolCapacity(Lease::Type type,
198 const ClientClasses& client_classes) const {
199 switch (type) {
200 case Lease::TYPE_V4:
201 case Lease::TYPE_NA:
202 return sumPoolCapacity(pools_, client_classes);
203 case Lease::TYPE_TA:
204 return sumPoolCapacity(pools_ta_, client_classes);
205 case Lease::TYPE_PD:
206 return sumPoolCapacity(pools_pd_, client_classes);
207 default:
208 isc_throw(BadValue, "Unsupported pool type: "
209 << static_cast<int>(type));
210 }
211 }
212
213 uint64_t
sumPoolCapacity(const PoolCollection & pools) const214 Subnet::sumPoolCapacity(const PoolCollection& pools) const {
215 uint64_t sum = 0;
216 for (PoolCollection::const_iterator p = pools.begin(); p != pools.end(); ++p) {
217 uint64_t x = (*p)->getCapacity();
218
219 // Check if we can add it. If sum + x > uint64::max, then we would have
220 // overflown if we tried to add it.
221 if (x > std::numeric_limits<uint64_t>::max() - sum) {
222 return (std::numeric_limits<uint64_t>::max());
223 }
224
225 sum += x;
226 }
227
228 return (sum);
229 }
230
231 uint64_t
sumPoolCapacity(const PoolCollection & pools,const ClientClasses & client_classes) const232 Subnet::sumPoolCapacity(const PoolCollection& pools,
233 const ClientClasses& client_classes) const {
234 uint64_t sum = 0;
235 for (PoolCollection::const_iterator p = pools.begin(); p != pools.end(); ++p) {
236 if (!(*p)->clientSupported(client_classes)) {
237 continue;
238 }
239 uint64_t x = (*p)->getCapacity();
240
241 // Check if we can add it. If sum + x > uint64::max, then we would have
242 // overflown if we tried to add it.
243 if (x > std::numeric_limits<uint64_t>::max() - sum) {
244 return (std::numeric_limits<uint64_t>::max());
245 }
246
247 sum += x;
248 }
249
250 return (sum);
251 }
252
253 std::pair<IOAddress, uint8_t>
parsePrefixCommon(const std::string & prefix)254 Subnet::parsePrefixCommon(const std::string& prefix) {
255 auto pos = prefix.find('/');
256 if ((pos == std::string::npos) ||
257 (pos == prefix.size() - 1) ||
258 (pos == 0)) {
259 isc_throw(BadValue, "unable to parse invalid prefix " << prefix);
260 }
261
262 try {
263 IOAddress address(prefix.substr(0, pos));
264 int length = boost::lexical_cast<int>(prefix.substr(pos + 1));
265 return (std::make_pair(address, static_cast<int>(length)));
266
267 } catch (...) {
268 isc_throw(BadValue, "unable to parse invalid prefix " << prefix);
269 }
270 }
271
272
checkType(Lease::Type type) const273 void Subnet4::checkType(Lease::Type type) const {
274 if (type != Lease::TYPE_V4) {
275 isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
276 }
277 }
278
Subnet4(const IOAddress & prefix,uint8_t length,const Triplet<uint32_t> & t1,const Triplet<uint32_t> & t2,const Triplet<uint32_t> & valid_lifetime,const SubnetID id)279 Subnet4::Subnet4(const IOAddress& prefix, uint8_t length,
280 const Triplet<uint32_t>& t1,
281 const Triplet<uint32_t>& t2,
282 const Triplet<uint32_t>& valid_lifetime,
283 const SubnetID id)
284 : Subnet(prefix, length, id), Network4() {
285 if (!prefix.isV4()) {
286 isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
287 << " specified in subnet4");
288 }
289
290 // Timers.
291 setT1(t1);
292 setT2(t2);
293 setValid(valid_lifetime);
294 }
295
296 Subnet4Ptr
create(const IOAddress & prefix,uint8_t length,const Triplet<uint32_t> & t1,const Triplet<uint32_t> & t2,const Triplet<uint32_t> & valid_lifetime,const SubnetID id)297 Subnet4::create(const IOAddress& prefix, uint8_t length,
298 const Triplet<uint32_t>& t1,
299 const Triplet<uint32_t>& t2,
300 const Triplet<uint32_t>& valid_lifetime,
301 const SubnetID id) {
302 Subnet4Ptr subnet = boost::make_shared<Subnet4>
303 (prefix, length, t1, t2, valid_lifetime, id);
304 return (subnet);
305 }
306
307 Subnet4Ptr
getNextSubnet(const Subnet4Ptr & first_subnet) const308 Subnet4::getNextSubnet(const Subnet4Ptr& first_subnet) const {
309 SharedNetwork4Ptr network;
310 getSharedNetwork(network);
311 if (network) {
312 return (network->getNextSubnet(first_subnet, getID()));
313 }
314
315 return (Subnet4Ptr());
316 }
317
318 Subnet4Ptr
getNextSubnet(const Subnet4Ptr & first_subnet,const ClientClasses & client_classes) const319 Subnet4::getNextSubnet(const Subnet4Ptr& first_subnet,
320 const ClientClasses& client_classes) const {
321 SharedNetwork4Ptr network;
322 getSharedNetwork(network);
323 // We can only get next subnet if shared network has been defined for
324 // the current subnet.
325 if (network) {
326 Subnet4Ptr subnet;
327 do {
328 // Use subnet identifier of this subnet if this is the first
329 // time we're calling getNextSubnet. Otherwise, use the
330 // subnet id of the previously returned subnet.
331 SubnetID subnet_id = subnet ? subnet->getID() : getID();
332 subnet = network->getNextSubnet(first_subnet, subnet_id);
333 // If client classes match the subnet, return it. Otherwise,
334 // try another subnet.
335 if (subnet && subnet->clientSupported(client_classes)) {
336 return (subnet);
337 }
338 } while (subnet);
339 }
340
341 // No subnet found.
342 return (Subnet4Ptr());
343 }
344
345
346 bool
clientSupported(const isc::dhcp::ClientClasses & client_classes) const347 Subnet4::clientSupported(const isc::dhcp::ClientClasses& client_classes) const {
348 NetworkPtr network;
349 getSharedNetwork(network);
350 if (network && !network->clientSupported(client_classes)) {
351 return (false);
352 }
353
354 return (Network4::clientSupported(client_classes));
355 }
356
getPools(Lease::Type type) const357 const PoolCollection& Subnet::getPools(Lease::Type type) const {
358 // check if the type is valid (and throw if it isn't)
359 checkType(type);
360
361 switch (type) {
362 case Lease::TYPE_V4:
363 case Lease::TYPE_NA:
364 return (pools_);
365 case Lease::TYPE_TA:
366 return (pools_ta_);
367 case Lease::TYPE_PD:
368 return (pools_pd_);
369 default:
370 isc_throw(BadValue, "Unsupported pool type: "
371 << static_cast<int>(type));
372 }
373 }
374
getPoolsWritable(Lease::Type type)375 PoolCollection& Subnet::getPoolsWritable(Lease::Type type) {
376 // check if the type is valid (and throw if it isn't)
377 checkType(type);
378
379 switch (type) {
380 case Lease::TYPE_V4:
381 case Lease::TYPE_NA:
382 return (pools_);
383 case Lease::TYPE_TA:
384 return (pools_ta_);
385 case Lease::TYPE_PD:
386 return (pools_pd_);
387 default:
388 isc_throw(BadValue, "Invalid pool type specified: "
389 << static_cast<int>(type));
390 }
391 }
392
getPool(Lease::Type type,const isc::asiolink::IOAddress & hint,bool anypool) const393 const PoolPtr Subnet::getPool(Lease::Type type, const isc::asiolink::IOAddress& hint,
394 bool anypool /* true */) const {
395 // check if the type is valid (and throw if it isn't)
396 checkType(type);
397
398 const PoolCollection& pools = getPools(type);
399
400 PoolPtr candidate;
401
402 if (!pools.empty()) {
403 // Pools are sorted by their first prefixes. For example: 2001::,
404 // 2001::db8::, 3000:: etc. If our hint is 2001:db8:5:: we want to
405 // find the pool with the longest matching prefix, so: 2001:db8::,
406 // rather than 2001::. upper_bound returns the first pool with a prefix
407 // that is greater than 2001:db8:5::, i.e. 3000::. To find the longest
408 // matching prefix we use decrement operator to go back by one item.
409 // If returned iterator points to begin it means that prefixes in all
410 // pools are greater than out prefix, and thus there is no match.
411 PoolCollection::const_iterator ub =
412 std::upper_bound(pools.begin(), pools.end(), hint,
413 prefixLessThanFirstAddress);
414
415 if (ub != pools.begin()) {
416 --ub;
417 if ((*ub)->inRange(hint)) {
418 candidate = *ub;
419 }
420 }
421
422 // If we don't find anything better, then let's just use the first pool
423 if (!candidate && anypool) {
424 candidate = *pools.begin();
425 }
426 }
427
428 // Return a pool or NULL if no match found.
429 return (candidate);
430 }
431
getPool(Lease::Type type,const ClientClasses & client_classes,const isc::asiolink::IOAddress & hint) const432 const PoolPtr Subnet::getPool(Lease::Type type,
433 const ClientClasses& client_classes,
434 const isc::asiolink::IOAddress& hint) const {
435 // check if the type is valid (and throw if it isn't)
436 checkType(type);
437
438 const PoolCollection& pools = getPools(type);
439
440 PoolPtr candidate;
441
442 if (!pools.empty()) {
443 PoolCollection::const_iterator ub =
444 std::upper_bound(pools.begin(), pools.end(), hint,
445 prefixLessThanFirstAddress);
446
447 if (ub != pools.begin()) {
448 --ub;
449 if ((*ub)->inRange(hint) &&
450 (*ub)->clientSupported(client_classes)) {
451 candidate = *ub;
452 }
453 }
454 }
455
456 // Return a pool or NULL if no match found.
457 return (candidate);
458 }
459
460 void
addPool(const PoolPtr & pool)461 Subnet::addPool(const PoolPtr& pool) {
462 // check if the type is valid (and throw if it isn't)
463 checkType(pool->getType());
464
465 // Check that the pool is in range with a subnet only if this is
466 // not a pool of IPv6 prefixes. The IPv6 prefixes delegated for
467 // the particular subnet don't need to match the prefix of the
468 // subnet.
469 if (pool->getType() != Lease::TYPE_PD) {
470 if (!inRange(pool->getFirstAddress()) || !inRange(pool->getLastAddress())) {
471 isc_throw(BadValue, "a pool of type "
472 << Lease::typeToText(pool->getType())
473 << ", with the following address range: "
474 << pool->getFirstAddress() << "-"
475 << pool->getLastAddress() << " does not match"
476 << " the prefix of a subnet: "
477 << prefix_ << "/" << static_cast<int>(prefix_len_)
478 << " to which it is being added");
479
480 }
481 }
482
483 bool overlaps = false;
484 if (pool->getType() == Lease::TYPE_V4) {
485 overlaps = poolOverlaps(Lease::TYPE_V4, pool);
486
487 } else {
488 overlaps =
489 poolOverlaps(Lease::TYPE_NA, pool) ||
490 poolOverlaps(Lease::TYPE_PD, pool) ||
491 poolOverlaps(Lease::TYPE_TA, pool);
492 }
493
494 if (overlaps) {
495 isc_throw(BadValue,"a pool of type "
496 << Lease::typeToText(pool->getType())
497 << ", with the following address range: "
498 << pool->getFirstAddress() << "-"
499 << pool->getLastAddress() << " overlaps with "
500 "an existing pool in the subnet: "
501 << prefix_ << "/" << static_cast<int>(prefix_len_)
502 << " to which it is being added");
503 }
504
505 PoolCollection& pools_writable = getPoolsWritable(pool->getType());
506
507 // Add the pool to the appropriate pools collection
508 pools_writable.push_back(pool);
509
510 // Sort pools by first address.
511 std::sort(pools_writable.begin(), pools_writable.end(),
512 comparePoolFirstAddress);
513 }
514
515 void
delPools(Lease::Type type)516 Subnet::delPools(Lease::Type type) {
517 getPoolsWritable(type).clear();
518 }
519
520 bool
inPool(Lease::Type type,const isc::asiolink::IOAddress & addr) const521 Subnet::inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const {
522
523 // Let's start with checking if it even belongs to that subnet.
524 if ((type != Lease::TYPE_PD) && !inRange(addr)) {
525 return (false);
526 }
527
528 const PoolCollection& pools = getPools(type);
529
530 for (PoolCollection::const_iterator pool = pools.begin();
531 pool != pools.end(); ++pool) {
532 if ((*pool)->inRange(addr)) {
533 return (true);
534 }
535 }
536 // There's no pool that address belongs to
537 return (false);
538 }
539
540 bool
inPool(Lease::Type type,const isc::asiolink::IOAddress & addr,const ClientClasses & client_classes) const541 Subnet::inPool(Lease::Type type,
542 const isc::asiolink::IOAddress& addr,
543 const ClientClasses& client_classes) const {
544
545 // Let's start with checking if it even belongs to that subnet.
546 if ((type != Lease::TYPE_PD) && !inRange(addr)) {
547 return (false);
548 }
549
550 const PoolCollection& pools = getPools(type);
551
552 for (PoolCollection::const_iterator pool = pools.begin();
553 pool != pools.end(); ++pool) {
554 if (!(*pool)->clientSupported(client_classes)) {
555 continue;
556 }
557 if ((*pool)->inRange(addr)) {
558 return (true);
559 }
560 }
561 // There's no pool that address belongs to
562 return (false);
563 }
564
565 bool
poolOverlaps(const Lease::Type & pool_type,const PoolPtr & pool) const566 Subnet::poolOverlaps(const Lease::Type& pool_type, const PoolPtr& pool) const {
567 const PoolCollection& pools = getPools(pool_type);
568
569 // If no pools, we don't overlap. Nothing to do.
570 if (pools.empty()) {
571 return (false);
572 }
573
574 // We're going to insert a new pool, likely between two existing pools.
575 // So we're going to end up with the following case:
576 // |<---- pool1 ---->| |<-------- pool2 ------>| |<-- pool3 -->|
577 // F1 L1 F2 L2 F3 L3
578 // where pool1 and pool3 are existing pools, pool2 is a pool being
579 // inserted and "F"/"L" mark first and last address in the pools
580 // respectively. So the following conditions must be fulfilled:
581 // F2 > L1 and L2 < F3. Obviously, for any pool: F < L.
582
583 // Search for pool3. We use F2 and upper_bound to find the F3 (upper_bound
584 // returns first pool in the sorted container which first address is
585 // greater than F2). prefixLessThanPoolAddress with the first argument
586 // set to "true" is the custom comparison function for upper_bound, which
587 // compares F2 with the first addresses of the existing pools.
588 PoolCollection::const_iterator pool3_it =
589 std::upper_bound(pools.begin(), pools.end(), pool->getFirstAddress(),
590 prefixLessThanFirstAddress);
591
592 // upper_bound returns a first pool which first address is greater than the
593 // address F2. However, it is also possible that there is a pool which first
594 // address is equal to F2. Such pool is also in conflict with a new pool.
595 // If the returned value is pools.begin() it means that all pools have greater
596 // first address than F2, thus none of the pools can have first address equal
597 // to F2. Otherwise, we'd need to check them for equality.
598 if (pool3_it != pools.begin()) {
599 // Go back one pool and check if addresses are equal.
600 PoolPtr pool3 = *(pool3_it - 1);
601 if (pool3->getFirstAddress() == pool->getFirstAddress()) {
602 return (true);
603 }
604 }
605
606 // If returned value is unequal pools.end() it means that there is a pool3,
607 // with F3 > F2.
608 if (pool3_it != pools.end()) {
609 // Let's store the pointer to this pool.
610 PoolPtr pool3 = *pool3_it;
611 // F3 must be greater than L2, otherwise pools will overlap.
612 if (pool3->getFirstAddress() <= pool->getLastAddress()) {
613 return (true);
614 }
615 }
616
617 // If L2 is ok, we now have to find the pool1. This pool should be
618 // right before the pool3 if there is any pool before pool3.
619 if (pool3_it != pools.begin()) {
620 PoolPtr pool1 = *(pool3_it - 1);
621 // F2 must be greater than L1.
622 if (pool->getFirstAddress() <= pool1->getLastAddress()) {
623 return (true);
624 }
625 }
626
627 return (false);
628 }
629
630
Subnet6(const IOAddress & prefix,uint8_t length,const Triplet<uint32_t> & t1,const Triplet<uint32_t> & t2,const Triplet<uint32_t> & preferred_lifetime,const Triplet<uint32_t> & valid_lifetime,const SubnetID id)631 Subnet6::Subnet6(const IOAddress& prefix, uint8_t length,
632 const Triplet<uint32_t>& t1,
633 const Triplet<uint32_t>& t2,
634 const Triplet<uint32_t>& preferred_lifetime,
635 const Triplet<uint32_t>& valid_lifetime,
636 const SubnetID id)
637 : Subnet(prefix, length, id), Network6() {
638 if (!prefix.isV6()) {
639 isc_throw(BadValue, "Non IPv6 prefix " << prefix
640 << " specified in subnet6");
641 }
642
643 // Timers.
644 setT1(t1);
645 setT2(t2);
646 setPreferred(preferred_lifetime);
647 setValid(valid_lifetime);
648 }
649
650 Subnet6Ptr
create(const IOAddress & prefix,uint8_t length,const Triplet<uint32_t> & t1,const Triplet<uint32_t> & t2,const Triplet<uint32_t> & preferred_lifetime,const Triplet<uint32_t> & valid_lifetime,const SubnetID id)651 Subnet6::create(const IOAddress& prefix, uint8_t length,
652 const Triplet<uint32_t>& t1,
653 const Triplet<uint32_t>& t2,
654 const Triplet<uint32_t>& preferred_lifetime,
655 const Triplet<uint32_t>& valid_lifetime,
656 const SubnetID id) {
657 Subnet6Ptr subnet = boost::make_shared<Subnet6>
658 (prefix, length, t1, t2, preferred_lifetime, valid_lifetime, id);
659 return (subnet);
660 }
661
checkType(Lease::Type type) const662 void Subnet6::checkType(Lease::Type type) const {
663 if ( (type != Lease::TYPE_NA) && (type != Lease::TYPE_TA) &&
664 (type != Lease::TYPE_PD)) {
665 isc_throw(BadValue, "Invalid Pool type: " << Lease::typeToText(type)
666 << "(" << static_cast<int>(type)
667 << "), must be TYPE_NA, TYPE_TA or TYPE_PD for Subnet6");
668 }
669 }
670
671 Subnet6Ptr
getNextSubnet(const Subnet6Ptr & first_subnet) const672 Subnet6::getNextSubnet(const Subnet6Ptr& first_subnet) const {
673 SharedNetwork6Ptr network;
674 getSharedNetwork(network);
675 if (network) {
676 return (network->getNextSubnet(first_subnet, getID()));
677 }
678
679 return (Subnet6Ptr());
680 }
681
682 Subnet6Ptr
getNextSubnet(const Subnet6Ptr & first_subnet,const ClientClasses & client_classes) const683 Subnet6::getNextSubnet(const Subnet6Ptr& first_subnet,
684 const ClientClasses& client_classes) const {
685 SharedNetwork6Ptr network;
686 getSharedNetwork(network);
687 // We can only get next subnet if shared network has been defined for
688 // the current subnet.
689 if (network) {
690 Subnet6Ptr subnet;
691 do {
692 // Use subnet identifier of this subnet if this is the first
693 // time we're calling getNextSubnet. Otherwise, use the
694 // subnet id of the previously returned subnet.
695 SubnetID subnet_id = subnet ? subnet->getID() : getID();
696 subnet = network->getNextSubnet(first_subnet, subnet_id);
697 // If client classes match the subnet, return it. Otherwise,
698 // try another subnet.
699 if (subnet && subnet->clientSupported(client_classes)) {
700 return (subnet);
701 }
702 } while (subnet);
703 }
704
705 // No subnet found.
706 return (Subnet6Ptr());
707 }
708
709 bool
clientSupported(const isc::dhcp::ClientClasses & client_classes) const710 Subnet6::clientSupported(const isc::dhcp::ClientClasses& client_classes) const {
711 NetworkPtr network;
712 getSharedNetwork(network);
713 if (network && !network->clientSupported(client_classes)) {
714 return (false);
715 }
716
717 return (Network6::clientSupported(client_classes));
718 }
719
720 data::ElementPtr
toElement() const721 Subnet::toElement() const {
722 ElementPtr map = Element::createMap();
723
724 // Add user-context
725 contextToElement(map);
726
727 // Set subnet id
728 SubnetID id = getID();
729 map->set("id", Element::create(static_cast<long long>(id)));
730
731 // Set subnet
732 map->set("subnet", Element::create(toText()));
733
734 return (map);
735 }
736
737 data::ElementPtr
toElement() const738 Subnet4::toElement() const {
739 // Prepare the map
740 ElementPtr map = Subnet::toElement();
741 ElementPtr network_map = Network4::toElement();
742
743 merge(map, network_map);
744
745 // Set DHCP4o6
746 const Cfg4o6& d4o6 = get4o6();
747 isc::data::merge(map, d4o6.toElement());
748
749 // Set pools
750 const PoolCollection& pools = getPools(Lease::TYPE_V4);
751 ElementPtr pool_list = Element::createList();
752 for (PoolCollection::const_iterator pool = pools.cbegin();
753 pool != pools.cend(); ++pool) {
754 // Add the elementized pool to the list
755 pool_list->add((*pool)->toElement());
756 }
757 map->set("pools", pool_list);
758
759 return (map);
760 }
761
762 std::pair<IOAddress, uint8_t>
parsePrefix(const std::string & prefix)763 Subnet4::parsePrefix(const std::string& prefix) {
764 std::pair<IOAddress, uint8_t> parsed = Subnet::parsePrefixCommon(prefix);
765 if (!parsed.first.isV4() || parsed.first.isV4Zero() ||
766 (parsed.second > 32) || (parsed.second == 0)) {
767 isc_throw(BadValue, "unable to parse invalid IPv4 prefix " << prefix);
768 }
769 return (parsed);
770 }
771
772 data::ElementPtr
toElement() const773 Subnet6::toElement() const {
774 // Prepare the map
775 ElementPtr map = Subnet::toElement();
776 ElementPtr network_map = Network6::toElement();
777
778 merge(map, network_map);
779
780 // Set pools
781 const PoolCollection& pools = getPools(Lease::TYPE_NA);
782 ElementPtr pool_list = Element::createList();
783 for (PoolCollection::const_iterator pool = pools.cbegin();
784 pool != pools.cend(); ++pool) {
785 // Add the elementized pool to the list
786 pool_list->add((*pool)->toElement());
787 }
788 map->set("pools", pool_list);
789
790 // Set pd-pools
791 const PoolCollection& pdpools = getPools(Lease::TYPE_PD);
792 ElementPtr pdpool_list = Element::createList();
793 for (PoolCollection::const_iterator pool = pdpools.cbegin();
794 pool != pdpools.cend(); ++pool) {
795 // Add the elementized pool to the list
796 pdpool_list->add((*pool)->toElement());
797 }
798 map->set("pd-pools", pdpool_list);
799
800 return (map);
801 }
802
803 std::pair<IOAddress, uint8_t>
parsePrefix(const std::string & prefix)804 Subnet6::parsePrefix(const std::string& prefix) {
805 std::pair<IOAddress, uint8_t> parsed = Subnet::parsePrefixCommon(prefix);
806 if (!parsed.first.isV6() || parsed.first.isV6Zero() ||
807 (parsed.second > 128) || (parsed.second == 0)) {
808 isc_throw(BadValue, "unable to parse invalid IPv6 prefix " << prefix);
809 }
810 return (parsed);
811 }
812
813 } // end of isc::dhcp namespace
814 } // end of isc namespace
815