subnet.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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. void Subnet::addVendorOption(const OptionPtr& option, bool persistent,
  78. uint32_t vendor_id){
  79. validateOption(option);
  80. vendor_option_spaces_.addItem(OptionDescriptor(option, persistent), vendor_id);
  81. }
  82. Subnet::OptionContainerPtr
  83. Subnet::getVendorOptionDescriptors(uint32_t vendor_id) const {
  84. return (vendor_option_spaces_.getItems(vendor_id));
  85. }
  86. Subnet::OptionDescriptor
  87. Subnet::getVendorOptionDescriptor(uint32_t vendor_id, uint16_t option_code) {
  88. OptionContainerPtr options = getVendorOptionDescriptors(vendor_id);
  89. if (!options || options->empty()) {
  90. return (OptionDescriptor(false));
  91. }
  92. const OptionContainerTypeIndex& idx = options->get<1>();
  93. const OptionContainerTypeRange& range = idx.equal_range(option_code);
  94. if (std::distance(range.first, range.second) == 0) {
  95. return (OptionDescriptor(false));
  96. }
  97. return (*range.first);
  98. }
  99. void Subnet::delVendorOptions() {
  100. vendor_option_spaces_.clearItems();
  101. }
  102. isc::asiolink::IOAddress Subnet::getLastAllocated(Lease::Type type) const {
  103. // check if the type is valid (and throw if it isn't)
  104. checkType(type);
  105. switch (type) {
  106. case Lease::TYPE_V4:
  107. case Lease::TYPE_NA:
  108. return last_allocated_ia_;
  109. case Lease::TYPE_TA:
  110. return last_allocated_ta_;
  111. case Lease::TYPE_PD:
  112. return last_allocated_pd_;
  113. default:
  114. isc_throw(BadValue, "Pool type " << type << " not supported");
  115. }
  116. }
  117. void Subnet::setLastAllocated(Lease::Type type,
  118. const isc::asiolink::IOAddress& addr) {
  119. // check if the type is valid (and throw if it isn't)
  120. checkType(type);
  121. switch (type) {
  122. case Lease::TYPE_V4:
  123. case Lease::TYPE_NA:
  124. last_allocated_ia_ = addr;
  125. return;
  126. case Lease::TYPE_TA:
  127. last_allocated_ta_ = addr;
  128. return;
  129. case Lease::TYPE_PD:
  130. last_allocated_pd_ = addr;
  131. return;
  132. default:
  133. isc_throw(BadValue, "Pool type " << type << " not supported");
  134. }
  135. }
  136. std::string
  137. Subnet::toText() const {
  138. std::stringstream tmp;
  139. tmp << prefix_.toText() << "/" << static_cast<unsigned int>(prefix_len_);
  140. return (tmp.str());
  141. }
  142. void Subnet4::checkType(Lease::Type type) const {
  143. if (type != Lease::TYPE_V4) {
  144. isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
  145. }
  146. }
  147. Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
  148. const Triplet<uint32_t>& t1,
  149. const Triplet<uint32_t>& t2,
  150. const Triplet<uint32_t>& valid_lifetime)
  151. :Subnet(prefix, length, t1, t2, valid_lifetime),
  152. siaddr_(IOAddress("0.0.0.0")) {
  153. if (!prefix.isV4()) {
  154. isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
  155. << " specified in subnet4");
  156. }
  157. }
  158. void Subnet4::setSiaddr(const isc::asiolink::IOAddress& siaddr) {
  159. if (!siaddr.isV4()) {
  160. isc_throw(BadValue, "Can't set siaddr to non-IPv4 address "
  161. << siaddr.toText());
  162. }
  163. siaddr_ = siaddr;
  164. }
  165. isc::asiolink::IOAddress Subnet4::getSiaddr() const {
  166. return (siaddr_);
  167. }
  168. const PoolCollection& Subnet::getPools(Lease::Type type) const {
  169. // check if the type is valid (and throw if it isn't)
  170. checkType(type);
  171. switch (type) {
  172. case Lease::TYPE_V4:
  173. case Lease::TYPE_NA:
  174. return (pools_);
  175. case Lease::TYPE_TA:
  176. return (pools_ta_);
  177. case Lease::TYPE_PD:
  178. return (pools_pd_);
  179. default:
  180. isc_throw(BadValue, "Unsupported pool type: "
  181. << static_cast<int>(type));
  182. }
  183. }
  184. PoolCollection& Subnet::getPoolsWritable(Lease::Type type) {
  185. // check if the type is valid (and throw if it isn't)
  186. checkType(type);
  187. switch (type) {
  188. case Lease::TYPE_V4:
  189. case Lease::TYPE_NA:
  190. return (pools_);
  191. case Lease::TYPE_TA:
  192. return (pools_ta_);
  193. case Lease::TYPE_PD:
  194. return (pools_pd_);
  195. default:
  196. isc_throw(BadValue, "Invalid pool type specified: "
  197. << static_cast<int>(type));
  198. }
  199. }
  200. const PoolPtr Subnet::getPool(Lease::Type type, const isc::asiolink::IOAddress& hint,
  201. bool anypool /* true */) const {
  202. // check if the type is valid (and throw if it isn't)
  203. checkType(type);
  204. const PoolCollection& pools = getPools(type);
  205. PoolPtr candidate;
  206. for (PoolCollection::const_iterator pool = pools.begin();
  207. pool != pools.end(); ++pool) {
  208. // if we won't find anything better, then let's just use the first pool
  209. if (anypool && !candidate) {
  210. candidate = *pool;
  211. }
  212. // if the client provided a pool and there's a pool that hint is valid
  213. // in, then let's use that pool
  214. if ((*pool)->inRange(hint)) {
  215. return (*pool);
  216. }
  217. }
  218. return (candidate);
  219. }
  220. void
  221. Subnet::addPool(const PoolPtr& pool) {
  222. IOAddress first_addr = pool->getFirstAddress();
  223. IOAddress last_addr = pool->getLastAddress();
  224. if (!inRange(first_addr) || !inRange(last_addr)) {
  225. isc_throw(BadValue, "Pool (" << first_addr.toText() << "-"
  226. << last_addr.toText()
  227. << " does not belong in this (" << prefix_.toText() << "/"
  228. << static_cast<int>(prefix_len_) << ") subnet");
  229. }
  230. /// @todo: Check that pools do not overlap
  231. // check if the type is valid (and throw if it isn't)
  232. checkType(pool->getType());
  233. // Add the pool to the appropriate pools collection
  234. getPoolsWritable(pool->getType()).push_back(pool);
  235. }
  236. void
  237. Subnet::delPools(Lease::Type type) {
  238. getPoolsWritable(type).clear();
  239. }
  240. void
  241. Subnet::setIface(const std::string& iface_name) {
  242. iface_ = iface_name;
  243. }
  244. std::string
  245. Subnet::getIface() const {
  246. return (iface_);
  247. }
  248. void
  249. Subnet4::validateOption(const OptionPtr& option) const {
  250. if (!option) {
  251. isc_throw(isc::BadValue,
  252. "option configured for subnet must not be NULL");
  253. } else if (option->getUniverse() != Option::V4) {
  254. isc_throw(isc::BadValue,
  255. "expected V4 option to be added to the subnet");
  256. }
  257. }
  258. bool
  259. Subnet::inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const {
  260. // Let's start with checking if it even belongs to that subnet.
  261. if (!inRange(addr)) {
  262. return (false);
  263. }
  264. const PoolCollection& pools = getPools(type);
  265. for (PoolCollection::const_iterator pool = pools.begin();
  266. pool != pools.end(); ++pool) {
  267. if ((*pool)->inRange(addr)) {
  268. return (true);
  269. }
  270. }
  271. // There's no pool that address belongs to
  272. return (false);
  273. }
  274. Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
  275. const Triplet<uint32_t>& t1,
  276. const Triplet<uint32_t>& t2,
  277. const Triplet<uint32_t>& preferred_lifetime,
  278. const Triplet<uint32_t>& valid_lifetime)
  279. :Subnet(prefix, length, t1, t2, valid_lifetime),
  280. preferred_(preferred_lifetime){
  281. if (!prefix.isV6()) {
  282. isc_throw(BadValue, "Non IPv6 prefix " << prefix.toText()
  283. << " specified in subnet6");
  284. }
  285. }
  286. void Subnet6::checkType(Lease::Type type) const {
  287. if ( (type != Lease::TYPE_NA) && (type != Lease::TYPE_TA) &&
  288. (type != Lease::TYPE_PD)) {
  289. isc_throw(BadValue, "Invalid Pool type: " << Lease::typeToText(type)
  290. << "(" << static_cast<int>(type)
  291. << "), must be TYPE_NA, TYPE_TA or TYPE_PD for Subnet6");
  292. }
  293. }
  294. void
  295. Subnet6::validateOption(const OptionPtr& option) const {
  296. if (!option) {
  297. isc_throw(isc::BadValue,
  298. "option configured for subnet must not be NULL");
  299. } else if (option->getUniverse() != Option::V6) {
  300. isc_throw(isc::BadValue,
  301. "expected V6 option to be added to the subnet");
  302. }
  303. }
  304. } // end of isc::dhcp namespace
  305. } // end of isc namespace