subnet.cc 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. // Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <asiolink/io_address.h>
  15. #include <dhcp/option_space.h>
  16. #include <dhcpsrv/addr_utilities.h>
  17. #include <dhcpsrv/subnet.h>
  18. #include <sstream>
  19. using namespace isc::asiolink;
  20. namespace isc {
  21. namespace dhcp {
  22. Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
  23. const Triplet<uint32_t>& t1,
  24. const Triplet<uint32_t>& t2,
  25. const Triplet<uint32_t>& valid_lifetime)
  26. :id_(getNextID()), prefix_(prefix), prefix_len_(len), t1_(t1),
  27. t2_(t2), valid_(valid_lifetime),
  28. last_allocated_ia_(lastAddrInPrefix(prefix, len)),
  29. last_allocated_ta_(lastAddrInPrefix(prefix, len)),
  30. last_allocated_pd_(lastAddrInPrefix(prefix, len)) {
  31. if ((prefix.isV6() && len > 128) ||
  32. (prefix.isV4() && len > 32)) {
  33. isc_throw(BadValue,
  34. "Invalid prefix length specified for subnet: " << len);
  35. }
  36. }
  37. bool
  38. Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
  39. IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
  40. IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
  41. return ((first <= addr) && (addr <= last));
  42. }
  43. void
  44. Subnet::addOption(const OptionPtr& option, bool persistent,
  45. const std::string& option_space) {
  46. // Check that the option space name is valid.
  47. if (!OptionSpace::validateName(option_space)) {
  48. isc_throw(isc::BadValue, "invalid option space name: '"
  49. << option_space << "'");
  50. }
  51. validateOption(option);
  52. // Actually add new option descriptor.
  53. option_spaces_.addItem(OptionDescriptor(option, persistent), option_space);
  54. }
  55. void
  56. Subnet::delOptions() {
  57. option_spaces_.clearItems();
  58. }
  59. Subnet::OptionContainerPtr
  60. Subnet::getOptionDescriptors(const std::string& option_space) const {
  61. return (option_spaces_.getItems(option_space));
  62. }
  63. Subnet::OptionDescriptor
  64. Subnet::getOptionDescriptor(const std::string& option_space,
  65. const uint16_t option_code) {
  66. OptionContainerPtr options = getOptionDescriptors(option_space);
  67. if (!options || options->empty()) {
  68. return (OptionDescriptor(false));
  69. }
  70. const OptionContainerTypeIndex& idx = options->get<1>();
  71. const OptionContainerTypeRange& range = idx.equal_range(option_code);
  72. if (std::distance(range.first, range.second) == 0) {
  73. return (OptionDescriptor(false));
  74. }
  75. return (*range.first);
  76. }
  77. isc::asiolink::IOAddress Subnet::getLastAllocated(Lease::Type type) const {
  78. // check if the type is valid (and throw if it isn't)
  79. checkType(type);
  80. switch (type) {
  81. case Lease::TYPE_V4:
  82. case Lease::TYPE_NA:
  83. return last_allocated_ia_;
  84. case Lease::TYPE_TA:
  85. return last_allocated_ta_;
  86. case Lease::TYPE_PD:
  87. return last_allocated_pd_;
  88. default:
  89. isc_throw(BadValue, "Pool type " << type << " not supported");
  90. }
  91. }
  92. void Subnet::setLastAllocated(Lease::Type type,
  93. const isc::asiolink::IOAddress& addr) {
  94. // check if the type is valid (and throw if it isn't)
  95. checkType(type);
  96. switch (type) {
  97. case Lease::TYPE_V4:
  98. case Lease::TYPE_NA:
  99. last_allocated_ia_ = addr;
  100. return;
  101. case Lease::TYPE_TA:
  102. last_allocated_ta_ = addr;
  103. return;
  104. case Lease::TYPE_PD:
  105. last_allocated_pd_ = addr;
  106. return;
  107. default:
  108. isc_throw(BadValue, "Pool type " << type << " not supported");
  109. }
  110. }
  111. std::string
  112. Subnet::toText() const {
  113. std::stringstream tmp;
  114. tmp << prefix_.toText() << "/" << static_cast<unsigned int>(prefix_len_);
  115. return (tmp.str());
  116. }
  117. void Subnet4::checkType(Lease::Type type) const {
  118. if (type != Lease::TYPE_V4) {
  119. isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
  120. }
  121. }
  122. Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
  123. const Triplet<uint32_t>& t1,
  124. const Triplet<uint32_t>& t2,
  125. const Triplet<uint32_t>& valid_lifetime)
  126. :Subnet(prefix, length, t1, t2, valid_lifetime) {
  127. if (!prefix.isV4()) {
  128. isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
  129. << " specified in subnet4");
  130. }
  131. }
  132. const PoolCollection& Subnet::getPools(Lease::Type type) const {
  133. // check if the type is valid (and throw if it isn't)
  134. checkType(type);
  135. switch (type) {
  136. case Lease::TYPE_V4:
  137. case Lease::TYPE_NA:
  138. return (pools_);
  139. case Lease::TYPE_TA:
  140. return (pools_ta_);
  141. case Lease::TYPE_PD:
  142. return (pools_pd_);
  143. default:
  144. isc_throw(BadValue, "Unsupported pool type: " << type);
  145. }
  146. }
  147. PoolCollection& Subnet::getPools(Lease::Type type) {
  148. switch (type) {
  149. case Lease::TYPE_V4:
  150. case Lease::TYPE_NA:
  151. return (pools_);
  152. case Lease::TYPE_TA:
  153. return (pools_);
  154. case Lease::TYPE_PD:
  155. return (pools_pd_);
  156. default:
  157. isc_throw(BadValue, "Invalid pool type specified: "
  158. << static_cast<int>(type));
  159. }
  160. }
  161. #if 0
  162. const PoolCollection& Subnet::getConstPools(Lease::Type type) const {
  163. switch (type) {
  164. case Lease::TYPE_V4:
  165. case Lease::TYPE_NA:
  166. return (pools_);
  167. case Lease::TYPE_TA:
  168. return (pools_);
  169. case Lease::TYPE_PD:
  170. return (pools_pd_);
  171. default:
  172. isc_throw(BadValue, "Invalid pool type specified: "
  173. << static_cast<int>(type));
  174. }
  175. }
  176. #endif
  177. PoolPtr Subnet::getPool(Lease::Type type, isc::asiolink::IOAddress hint,
  178. bool anypool /* true */) {
  179. // check if the type is valid (and throw if it isn't)
  180. checkType(type);
  181. const PoolCollection& pools = getPools(type);
  182. PoolPtr candidate;
  183. for (PoolCollection::const_iterator pool = pools.begin();
  184. pool != pools.end(); ++pool) {
  185. // if we won't find anything better, then let's just use the first pool
  186. if (anypool && !candidate) {
  187. candidate = *pool;
  188. }
  189. // if the client provided a pool and there's a pool that hint is valid
  190. // in, then let's use that pool
  191. if ((*pool)->inRange(hint)) {
  192. return (*pool);
  193. }
  194. }
  195. return (candidate);
  196. }
  197. void
  198. Subnet::addPool(const PoolPtr& pool) {
  199. IOAddress first_addr = pool->getFirstAddress();
  200. IOAddress last_addr = pool->getLastAddress();
  201. if (!inRange(first_addr) || !inRange(last_addr)) {
  202. isc_throw(BadValue, "Pool (" << first_addr.toText() << "-"
  203. << last_addr.toText()
  204. << " does not belong in this (" << prefix_.toText() << "/"
  205. << static_cast<int>(prefix_len_) << ") subnet");
  206. }
  207. /// @todo: Check that pools do not overlap
  208. // check if the type is valid (and throw if it isn't)
  209. checkType(pool->getType());
  210. // Add the pool to the appropriate pools collection
  211. getPools(pool->getType()).push_back(pool);
  212. }
  213. void
  214. Subnet::delPools(Lease::Type type) {
  215. getPools(type).clear();
  216. }
  217. void
  218. Subnet::setIface(const std::string& iface_name) {
  219. iface_ = iface_name;
  220. }
  221. std::string
  222. Subnet::getIface() const {
  223. return (iface_);
  224. }
  225. void
  226. Subnet4::validateOption(const OptionPtr& option) const {
  227. if (!option) {
  228. isc_throw(isc::BadValue,
  229. "option configured for subnet must not be NULL");
  230. } else if (option->getUniverse() != Option::V4) {
  231. isc_throw(isc::BadValue,
  232. "expected V4 option to be added to the subnet");
  233. }
  234. }
  235. bool
  236. Subnet::inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const {
  237. // Let's start with checking if it even belongs to that subnet.
  238. if (!inRange(addr)) {
  239. return (false);
  240. }
  241. const PoolCollection& pools = getPools(type);
  242. for (PoolCollection::const_iterator pool = pools.begin();
  243. pool != pools.end(); ++pool) {
  244. if ((*pool)->inRange(addr)) {
  245. return (true);
  246. }
  247. }
  248. // There's no pool that address belongs to
  249. return (false);
  250. }
  251. Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
  252. const Triplet<uint32_t>& t1,
  253. const Triplet<uint32_t>& t2,
  254. const Triplet<uint32_t>& preferred_lifetime,
  255. const Triplet<uint32_t>& valid_lifetime)
  256. :Subnet(prefix, length, t1, t2, valid_lifetime),
  257. preferred_(preferred_lifetime){
  258. if (!prefix.isV6()) {
  259. isc_throw(BadValue, "Non IPv6 prefix " << prefix.toText()
  260. << " specified in subnet6");
  261. }
  262. }
  263. void Subnet6::checkType(Lease::Type type) const {
  264. if ( (type != Lease::TYPE_NA) && (type != Lease::TYPE_TA) &&
  265. (type != Lease::TYPE_PD)) {
  266. isc_throw(BadValue, "Invalid Pool type: " << Lease::typeToText(type)
  267. << "(" << static_cast<int>(type)
  268. << "), must be TYPE_NA, TYPE_TA or TYPE_PD for Subnet6");
  269. }
  270. }
  271. void
  272. Subnet6::validateOption(const OptionPtr& option) const {
  273. if (!option) {
  274. isc_throw(isc::BadValue,
  275. "option configured for subnet must not be NULL");
  276. } else if (option->getUniverse() != Option::V6) {
  277. isc_throw(isc::BadValue,
  278. "expected V6 option to be added to the subnet");
  279. }
  280. }
  281. } // end of isc::dhcp namespace
  282. } // end of isc namespace