subnet.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. // Copyright (C) 2012-2017 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. #include <config.h>
  7. #include <asiolink/io_address.h>
  8. #include <dhcp/option_space.h>
  9. #include <dhcpsrv/addr_utilities.h>
  10. #include <dhcpsrv/subnet.h>
  11. #include <algorithm>
  12. #include <sstream>
  13. using namespace isc::asiolink;
  14. using namespace isc::data;
  15. using namespace isc::dhcp;
  16. namespace {
  17. /// @brief Function used in calls to std::upper_bound to check
  18. /// if the specified prefix is lower than the first address a pool.
  19. ///
  20. /// @return true if prefix is lower than the first address in the pool.
  21. bool
  22. prefixLessThanFirstAddress(const IOAddress& prefix, const PoolPtr& pool) {
  23. return (prefix < pool->getFirstAddress());
  24. }
  25. /// @brief Function used in calls to std::sort to compare first
  26. /// prefixes of the two pools.
  27. ///
  28. /// @param pool1 First pool.
  29. /// @param pool2 Second pool.
  30. ///
  31. /// @return true if first prefix of the first pool is smaller than
  32. /// the first address of the second pool.
  33. bool
  34. comparePoolFirstAddress(const PoolPtr& pool1, const PoolPtr& pool2) {
  35. return (pool1->getFirstAddress() < pool2->getFirstAddress());
  36. };
  37. }
  38. namespace isc {
  39. namespace dhcp {
  40. // This is an initial value of subnet-id. See comments in subnet.h for details.
  41. SubnetID Subnet::static_id_ = 1;
  42. Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
  43. const Triplet<uint32_t>& t1,
  44. const Triplet<uint32_t>& t2,
  45. const Triplet<uint32_t>& valid_lifetime,
  46. const isc::dhcp::Subnet::RelayInfo& relay,
  47. const SubnetID id)
  48. :id_(id == 0 ? generateNextID() : id), prefix_(prefix), prefix_len_(len),
  49. t1_(t1), t2_(t2), valid_(valid_lifetime),
  50. last_allocated_ia_(lastAddrInPrefix(prefix, len)),
  51. last_allocated_ta_(lastAddrInPrefix(prefix, len)),
  52. last_allocated_pd_(lastAddrInPrefix(prefix, len)), relay_(relay),
  53. host_reservation_mode_(HR_ALL), cfg_option_(new CfgOption())
  54. {
  55. if ((prefix.isV6() && len > 128) ||
  56. (prefix.isV4() && len > 32)) {
  57. isc_throw(BadValue,
  58. "Invalid prefix length specified for subnet: " << len);
  59. }
  60. }
  61. Subnet::RelayInfo::RelayInfo(const isc::asiolink::IOAddress& addr)
  62. :addr_(addr) {
  63. }
  64. bool
  65. Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
  66. IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
  67. IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
  68. return ((first <= addr) && (addr <= last));
  69. }
  70. void
  71. Subnet::setRelayInfo(const isc::dhcp::Subnet::RelayInfo& relay) {
  72. relay_ = relay;
  73. }
  74. bool
  75. Subnet::clientSupported(const isc::dhcp::ClientClasses& classes) const {
  76. if (white_list_.empty()) {
  77. return (true); // There is no class defined for this subnet, so we do
  78. // support everyone.
  79. }
  80. for (ClientClasses::const_iterator it = white_list_.begin();
  81. it != white_list_.end(); ++it) {
  82. if (classes.contains(*it)) {
  83. return (true);
  84. }
  85. }
  86. return (false);
  87. }
  88. void
  89. Subnet::allowClientClass(const isc::dhcp::ClientClass& class_name) {
  90. white_list_.insert(class_name);
  91. }
  92. isc::asiolink::IOAddress Subnet::getLastAllocated(Lease::Type type) const {
  93. // check if the type is valid (and throw if it isn't)
  94. checkType(type);
  95. switch (type) {
  96. case Lease::TYPE_V4:
  97. case Lease::TYPE_NA:
  98. return last_allocated_ia_;
  99. case Lease::TYPE_TA:
  100. return last_allocated_ta_;
  101. case Lease::TYPE_PD:
  102. return last_allocated_pd_;
  103. default:
  104. isc_throw(BadValue, "Pool type " << type << " not supported");
  105. }
  106. }
  107. void Subnet::setLastAllocated(Lease::Type type,
  108. const isc::asiolink::IOAddress& addr) {
  109. // check if the type is valid (and throw if it isn't)
  110. checkType(type);
  111. switch (type) {
  112. case Lease::TYPE_V4:
  113. case Lease::TYPE_NA:
  114. last_allocated_ia_ = addr;
  115. return;
  116. case Lease::TYPE_TA:
  117. last_allocated_ta_ = addr;
  118. return;
  119. case Lease::TYPE_PD:
  120. last_allocated_pd_ = addr;
  121. return;
  122. default:
  123. isc_throw(BadValue, "Pool type " << type << " not supported");
  124. }
  125. }
  126. std::string
  127. Subnet::toText() const {
  128. std::stringstream tmp;
  129. tmp << prefix_ << "/" << static_cast<unsigned int>(prefix_len_);
  130. return (tmp.str());
  131. }
  132. uint64_t
  133. Subnet::getPoolCapacity(Lease::Type type) const {
  134. switch (type) {
  135. case Lease::TYPE_V4:
  136. case Lease::TYPE_NA:
  137. return sumPoolCapacity(pools_);
  138. case Lease::TYPE_TA:
  139. return sumPoolCapacity(pools_ta_);
  140. case Lease::TYPE_PD:
  141. return sumPoolCapacity(pools_pd_);
  142. default:
  143. isc_throw(BadValue, "Unsupported pool type: "
  144. << static_cast<int>(type));
  145. }
  146. }
  147. uint64_t
  148. Subnet::sumPoolCapacity(const PoolCollection& pools) const {
  149. uint64_t sum = 0;
  150. for (PoolCollection::const_iterator p = pools.begin(); p != pools.end(); ++p) {
  151. uint64_t x = (*p)->getCapacity();
  152. // Check if we can add it. If sum + x > uint64::max, then we would have
  153. // overflown if we tried to add it.
  154. if (x > std::numeric_limits<uint64_t>::max() - sum) {
  155. return (std::numeric_limits<uint64_t>::max());
  156. }
  157. sum += x;
  158. }
  159. return (sum);
  160. }
  161. void Subnet4::checkType(Lease::Type type) const {
  162. if (type != Lease::TYPE_V4) {
  163. isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
  164. }
  165. }
  166. Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
  167. const Triplet<uint32_t>& t1,
  168. const Triplet<uint32_t>& t2,
  169. const Triplet<uint32_t>& valid_lifetime,
  170. const SubnetID id)
  171. : Subnet(prefix, length, t1, t2, valid_lifetime, RelayInfo(IOAddress("0.0.0.0")), id),
  172. siaddr_(IOAddress("0.0.0.0")), match_client_id_(true) {
  173. if (!prefix.isV4()) {
  174. isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
  175. << " specified in subnet4");
  176. }
  177. }
  178. void Subnet4::setSiaddr(const isc::asiolink::IOAddress& siaddr) {
  179. if (!siaddr.isV4()) {
  180. isc_throw(BadValue, "Can't set siaddr to non-IPv4 address "
  181. << siaddr);
  182. }
  183. siaddr_ = siaddr;
  184. }
  185. isc::asiolink::IOAddress Subnet4::getSiaddr() const {
  186. return (siaddr_);
  187. }
  188. const PoolCollection& Subnet::getPools(Lease::Type type) const {
  189. // check if the type is valid (and throw if it isn't)
  190. checkType(type);
  191. switch (type) {
  192. case Lease::TYPE_V4:
  193. case Lease::TYPE_NA:
  194. return (pools_);
  195. case Lease::TYPE_TA:
  196. return (pools_ta_);
  197. case Lease::TYPE_PD:
  198. return (pools_pd_);
  199. default:
  200. isc_throw(BadValue, "Unsupported pool type: "
  201. << static_cast<int>(type));
  202. }
  203. }
  204. PoolCollection& Subnet::getPoolsWritable(Lease::Type type) {
  205. // check if the type is valid (and throw if it isn't)
  206. checkType(type);
  207. switch (type) {
  208. case Lease::TYPE_V4:
  209. case Lease::TYPE_NA:
  210. return (pools_);
  211. case Lease::TYPE_TA:
  212. return (pools_ta_);
  213. case Lease::TYPE_PD:
  214. return (pools_pd_);
  215. default:
  216. isc_throw(BadValue, "Invalid pool type specified: "
  217. << static_cast<int>(type));
  218. }
  219. }
  220. const PoolPtr Subnet::getPool(Lease::Type type, const isc::asiolink::IOAddress& hint,
  221. bool anypool /* true */) const {
  222. // check if the type is valid (and throw if it isn't)
  223. checkType(type);
  224. const PoolCollection& pools = getPools(type);
  225. PoolPtr candidate;
  226. if (!pools.empty()) {
  227. // Pools are sorted by their first prefixes. For example: 2001::,
  228. // 2001::db8::, 3000:: etc. If our hint is 2001:db8:5:: we want to
  229. // find the pool with the longest matching prefix, so: 2001:db8::,
  230. // rather than 2001::. upper_bound returns the first pool with a prefix
  231. // that is greater than 2001:db8:5::, i.e. 3000::. To find the longest
  232. // matching prefix we use decrement operator to go back by one item.
  233. // If returned iterator points to begin it means that prefixes in all
  234. // pools are greater than out prefix, and thus there is no match.
  235. PoolCollection::const_iterator ub =
  236. std::upper_bound(pools.begin(), pools.end(), hint,
  237. prefixLessThanFirstAddress);
  238. if (ub != pools.begin()) {
  239. --ub;
  240. if ((*ub)->inRange(hint)) {
  241. candidate = *ub;
  242. }
  243. }
  244. // If we don't find anything better, then let's just use the first pool
  245. if (!candidate && anypool) {
  246. candidate = *pools.begin();
  247. }
  248. }
  249. // Return a pool or NULL if no match found.
  250. return (candidate);
  251. }
  252. void
  253. Subnet::addPool(const PoolPtr& pool) {
  254. // check if the type is valid (and throw if it isn't)
  255. checkType(pool->getType());
  256. // Check that the pool is in range with a subnet only if this is
  257. // not a pool of IPv6 prefixes. The IPv6 prefixes delegated for
  258. // the particular subnet don't need to match the prefix of the
  259. // subnet.
  260. if (pool->getType() != Lease::TYPE_PD) {
  261. if (!inRange(pool->getFirstAddress()) || !inRange(pool->getLastAddress())) {
  262. isc_throw(BadValue, "a pool of type "
  263. << Lease::typeToText(pool->getType())
  264. << ", with the following address range: "
  265. << pool->getFirstAddress() << "-"
  266. << pool->getLastAddress() << " does not match"
  267. << " the prefix of a subnet: "
  268. << prefix_ << "/" << static_cast<int>(prefix_len_)
  269. << " to which it is being added");
  270. }
  271. }
  272. bool overlaps = false;
  273. if (pool->getType() == Lease::TYPE_V4) {
  274. overlaps = poolOverlaps(Lease::TYPE_V4, pool);
  275. } else {
  276. overlaps =
  277. poolOverlaps(Lease::TYPE_NA, pool) ||
  278. poolOverlaps(Lease::TYPE_PD, pool) ||
  279. poolOverlaps(Lease::TYPE_TA, pool);
  280. }
  281. if (overlaps) {
  282. isc_throw(BadValue,"a pool of type "
  283. << Lease::typeToText(pool->getType())
  284. << ", with the following address range: "
  285. << pool->getFirstAddress() << "-"
  286. << pool->getLastAddress() << " overlaps with "
  287. "an existing pool in the subnet: "
  288. << prefix_ << "/" << static_cast<int>(prefix_len_)
  289. << " to which it is being added");
  290. }
  291. PoolCollection& pools_writable = getPoolsWritable(pool->getType());
  292. // Add the pool to the appropriate pools collection
  293. pools_writable.push_back(pool);
  294. // Sort pools by first address.
  295. std::sort(pools_writable.begin(), pools_writable.end(),
  296. comparePoolFirstAddress);
  297. }
  298. void
  299. Subnet::delPools(Lease::Type type) {
  300. getPoolsWritable(type).clear();
  301. }
  302. void
  303. Subnet::setIface(const std::string& iface_name) {
  304. iface_ = iface_name;
  305. }
  306. std::string
  307. Subnet::getIface() const {
  308. return (iface_);
  309. }
  310. bool
  311. Subnet::inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const {
  312. // Let's start with checking if it even belongs to that subnet.
  313. if ((type != Lease::TYPE_PD) && !inRange(addr)) {
  314. return (false);
  315. }
  316. const PoolCollection& pools = getPools(type);
  317. for (PoolCollection::const_iterator pool = pools.begin();
  318. pool != pools.end(); ++pool) {
  319. if ((*pool)->inRange(addr)) {
  320. return (true);
  321. }
  322. }
  323. // There's no pool that address belongs to
  324. return (false);
  325. }
  326. bool
  327. Subnet::poolOverlaps(const Lease::Type& pool_type, const PoolPtr& pool) const {
  328. const PoolCollection& pools = getPools(pool_type);
  329. // If no pools, we don't overlap. Nothing to do.
  330. if (pools.empty()) {
  331. return (false);
  332. }
  333. // We're going to insert a new pool, likely between two existing pools.
  334. // So we're going to end up with the following case:
  335. // |<---- pool1 ---->| |<-------- pool2 ------>| |<-- pool3 -->|
  336. // F1 L1 F2 L2 F3 L3
  337. // where pool1 and pool3 are existing pools, pool2 is a pool being
  338. // inserted and "F"/"L" mark first and last address in the pools
  339. // respectively. So the following conditions must be fulfilled:
  340. // F2 > L1 and L2 < F3. Obviously, for any pool: F < L.
  341. // Search for pool3. We use F2 and upper_bound to find the F3 (upper_bound
  342. // returns first pool in the sorted container which first address is
  343. // greater than F2). prefixLessThanPoolAddress with the first argument
  344. // set to "true" is the custom comparison function for upper_bound, which
  345. // compares F2 with the first addresses of the existing pools.
  346. PoolCollection::const_iterator pool3_it =
  347. std::upper_bound(pools.begin(), pools.end(), pool->getFirstAddress(),
  348. prefixLessThanFirstAddress);
  349. // upper_bound returns a first pool which first address is greater than the
  350. // address F2. However, it is also possible that there is a pool which first
  351. // address is equal to F2. Such pool is also in conflict with a new pool.
  352. // If the returned value is pools.begin() it means that all pools have greater
  353. // first address than F2, thus none of the pools can have first address equal
  354. // to F2. Otherwise, we'd need to check them for equality.
  355. if (pool3_it != pools.begin()) {
  356. // Go back one pool and check if addresses are equal.
  357. PoolPtr pool3 = *(pool3_it - 1);
  358. if (pool3->getFirstAddress() == pool->getFirstAddress()) {
  359. return (true);
  360. }
  361. }
  362. // If returned value is unequal pools.end() it means that there is a pool3,
  363. // with F3 > F2.
  364. if (pool3_it != pools.end()) {
  365. // Let's store the pointer to this pool.
  366. PoolPtr pool3 = *pool3_it;
  367. // F3 must be greater than L2, otherwise pools will overlap.
  368. if (pool3->getFirstAddress() <= pool->getLastAddress()) {
  369. return (true);
  370. }
  371. }
  372. // If L2 is ok, we now have to find the pool1. This pool should be
  373. // right before the pool3 if there is any pool before pool3.
  374. if (pool3_it != pools.begin()) {
  375. PoolPtr pool1 = *(pool3_it - 1);
  376. // F2 must be greater than L1.
  377. if (pool->getFirstAddress() <= pool1->getLastAddress()) {
  378. return (true);
  379. }
  380. }
  381. return (false);
  382. }
  383. Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
  384. const Triplet<uint32_t>& t1,
  385. const Triplet<uint32_t>& t2,
  386. const Triplet<uint32_t>& preferred_lifetime,
  387. const Triplet<uint32_t>& valid_lifetime,
  388. const SubnetID id)
  389. :Subnet(prefix, length, t1, t2, valid_lifetime, RelayInfo(IOAddress("::")), id),
  390. preferred_(preferred_lifetime), rapid_commit_(false) {
  391. if (!prefix.isV6()) {
  392. isc_throw(BadValue, "Non IPv6 prefix " << prefix
  393. << " specified in subnet6");
  394. }
  395. }
  396. void Subnet6::checkType(Lease::Type type) const {
  397. if ( (type != Lease::TYPE_NA) && (type != Lease::TYPE_TA) &&
  398. (type != Lease::TYPE_PD)) {
  399. isc_throw(BadValue, "Invalid Pool type: " << Lease::typeToText(type)
  400. << "(" << static_cast<int>(type)
  401. << "), must be TYPE_NA, TYPE_TA or TYPE_PD for Subnet6");
  402. }
  403. }
  404. data::ElementPtr
  405. Subnet::toElement() const {
  406. // Prepare the map
  407. ElementPtr map = Element::createMap();
  408. // Set subnet id
  409. SubnetID id = getID();
  410. map->set("id", Element::create(static_cast<long long>(id)));
  411. // Set relay info
  412. const Subnet::RelayInfo& relay_info = getRelayInfo();
  413. ElementPtr relay = Element::createMap();
  414. relay->set("ip-address", Element::create(relay_info.addr_.toText()));
  415. map->set("relay", relay);
  416. // Set subnet
  417. map->set("subnet", Element::create(toText()));
  418. // Set interface
  419. const std::string& iface = getIface();
  420. if (!iface.empty()) {
  421. map->set("interface", Element::create(iface));
  422. }
  423. // Set renew-timer
  424. map->set("renew-timer",
  425. Element::create(static_cast<long long>
  426. (getT1().get())));
  427. // Set rebind-timer
  428. map->set("rebind-timer",
  429. Element::create(static_cast<long long>
  430. (getT2().get())));
  431. // Set valid-lifetime
  432. map->set("valid-lifetime",
  433. Element::create(static_cast<long long>
  434. (getValid().get())));
  435. // Set reservation mode
  436. Subnet::HRMode hrmode = getHostReservationMode();
  437. std::string mode;
  438. switch (hrmode) {
  439. case Subnet::HR_DISABLED:
  440. mode = "disabled";
  441. break;
  442. case Subnet::HR_OUT_OF_POOL:
  443. mode = "out-of-pool";
  444. break;
  445. case Subnet::HR_ALL:
  446. mode = "all";
  447. break;
  448. default:
  449. isc_throw(ToElementError,
  450. "invalid host reservation mode: " << hrmode);
  451. }
  452. map->set("reservation-mode", Element::create(mode));
  453. // Set client-class
  454. const ClientClasses& cclasses = getClientClasses();
  455. if (cclasses.size() > 1) {
  456. isc_throw(ToElementError, "client-class has too many items: "
  457. << cclasses.size());
  458. } else if (!cclasses.empty()) {
  459. map->set("client-class", Element::create(*cclasses.cbegin()));
  460. }
  461. // Set options
  462. ConstCfgOptionPtr opts = getCfgOption();
  463. map->set("option-data", opts->toElement());
  464. // Add user-context, but only if defined. Omit if it was not.
  465. ConstElementPtr ctx = getContext();
  466. if (ctx) {
  467. map->set("user-context", ctx);
  468. }
  469. return (map);
  470. }
  471. data::ElementPtr
  472. Subnet4::toElement() const {
  473. // Prepare the map
  474. ElementPtr map = Subnet::toElement();
  475. // Set match-client-id
  476. map->set("match-client-id", Element::create(getMatchClientId()));
  477. // Set DHCP4o6
  478. const Cfg4o6& d4o6 = get4o6();
  479. isc::data::merge(map, d4o6.toElement());
  480. // Set next-server
  481. map->set("next-server", Element::create(getSiaddr().toText()));
  482. // Set pools
  483. const PoolCollection& pools = getPools(Lease::TYPE_V4);
  484. ElementPtr pool_list = Element::createList();
  485. for (PoolCollection::const_iterator pool = pools.cbegin();
  486. pool != pools.cend(); ++pool) {
  487. // Add the elementized pool to the list
  488. pool_list->add((*pool)->toElement());
  489. }
  490. map->set("pools", pool_list);
  491. return (map);
  492. }
  493. data::ElementPtr
  494. Subnet6::toElement() const {
  495. // Prepare the map
  496. ElementPtr map = Subnet::toElement();
  497. // Set interface-id
  498. const OptionPtr& ifaceid = getInterfaceId();
  499. if (ifaceid) {
  500. std::vector<uint8_t> bin = ifaceid->getData();
  501. std::string ifid;
  502. ifid.resize(bin.size());
  503. if (!bin.empty()) {
  504. std::memcpy(&ifid[0], &bin[0], bin.size());
  505. }
  506. map->set("interface-id", Element::create(ifid));
  507. }
  508. // Set preferred-lifetime
  509. map->set("preferred-lifetime",
  510. Element::create(static_cast<long long>
  511. (getPreferred().get())));
  512. // Set rapid-commit
  513. bool rapid_commit = getRapidCommit();
  514. map->set("rapid-commit", Element::create(rapid_commit));
  515. // Set pools
  516. const PoolCollection& pools = getPools(Lease::TYPE_NA);
  517. ElementPtr pool_list = Element::createList();
  518. for (PoolCollection::const_iterator pool = pools.cbegin();
  519. pool != pools.cend(); ++pool) {
  520. // Prepare the map for a pool (@todo move this code to pool.cc)
  521. ElementPtr pool_map = Element::createMap();
  522. // Set pool
  523. const IOAddress& first = (*pool)->getFirstAddress();
  524. const IOAddress& last = (*pool)->getLastAddress();
  525. std::string range = first.toText() + "-" + last.toText();
  526. // Try to output a prefix (vs a range)
  527. int prefix_len = prefixLengthFromRange(first, last);
  528. if (prefix_len >= 0) {
  529. std::ostringstream oss;
  530. oss << first.toText() << "/" << prefix_len;
  531. range = oss.str();
  532. }
  533. pool_map->set("pool", Element::create(range));
  534. // Set user-context
  535. ConstElementPtr context = (*pool)->getContext();
  536. if (!isNull(context)) {
  537. pool_map->set("user-context", context);
  538. }
  539. // Set pool options
  540. ConstCfgOptionPtr opts = (*pool)->getCfgOption();
  541. pool_map->set("option-data", opts->toElement());
  542. // Push on the pool list
  543. pool_list->add(pool_map);
  544. }
  545. map->set("pools", pool_list);
  546. // Set pd-pools
  547. const PoolCollection& pdpools = getPools(Lease::TYPE_PD);
  548. ElementPtr pdpool_list = Element::createList();
  549. for (PoolCollection::const_iterator pool = pdpools.cbegin();
  550. pool != pdpools.cend(); ++pool) {
  551. // Get it as a Pool6 (@todo move this code to pool.cc)
  552. const Pool6* pdpool = dynamic_cast<Pool6*>(pool->get());
  553. if (!pdpool) {
  554. isc_throw(ToElementError, "invalid pd-pool pointer");
  555. }
  556. // Prepare the map for a pd-pool
  557. ElementPtr pool_map = Element::createMap();
  558. // Set prefix
  559. const IOAddress& prefix = pdpool->getFirstAddress();
  560. pool_map->set("prefix", Element::create(prefix.toText()));
  561. // Set prefix-len (get it from min - max)
  562. const IOAddress& last = pdpool->getLastAddress();
  563. int prefix_len = prefixLengthFromRange(prefix, last);
  564. if (prefix_len < 0) {
  565. // The pool is bad: give up
  566. isc_throw(ToElementError, "invalid prefix range "
  567. << prefix.toText() << "-" << last.toText());
  568. }
  569. pool_map->set("prefix-len", Element::create(prefix_len));
  570. // Set delegated-len
  571. uint8_t len = pdpool->getLength();
  572. pool_map->set("delegated-len",
  573. Element::create(static_cast<int>(len)));
  574. // Set excluded prefix
  575. const Option6PDExcludePtr& xopt =
  576. pdpool->getPrefixExcludeOption();
  577. if (xopt) {
  578. const IOAddress& xprefix =
  579. xopt->getExcludedPrefix(prefix, len);
  580. pool_map->set("excluded-prefix",
  581. Element::create(xprefix.toText()));
  582. uint8_t xlen = xopt->getExcludedPrefixLength();
  583. pool_map->set("excluded-prefix-len",
  584. Element::create(static_cast<int>(xlen)));
  585. }
  586. // Set user-context
  587. ConstElementPtr context = pdpool->getContext();
  588. if (!isNull(context)) {
  589. pool_map->set("user-context", context);
  590. }
  591. // Set pool options
  592. ConstCfgOptionPtr opts = pdpool->getCfgOption();
  593. pool_map->set("option-data", opts->toElement());
  594. // Push on the pool list
  595. pdpool_list->add(pool_map);
  596. }
  597. map->set("pd-pools", pdpool_list);
  598. return (map);
  599. }
  600. } // end of isc::dhcp namespace
  601. } // end of isc namespace