cfg_subnets4.cc 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright (C) 2014, 2015 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 <config.h>
  15. #include <dhcp/iface_mgr.h>
  16. #include <dhcpsrv/cfg_subnets4.h>
  17. #include <dhcpsrv/dhcpsrv_log.h>
  18. #include <dhcpsrv/subnet_id.h>
  19. #include <stats/stats_mgr.h>
  20. using namespace isc::asiolink;
  21. namespace isc {
  22. namespace dhcp {
  23. void
  24. CfgSubnets4::add(const Subnet4Ptr& subnet) {
  25. /// @todo: Check that this new subnet does not cross boundaries of any
  26. /// other already defined subnet.
  27. if (isDuplicate(*subnet)) {
  28. isc_throw(isc::dhcp::DuplicateSubnetID, "ID of the new IPv4 subnet '"
  29. << subnet->getID() << "' is already in use");
  30. }
  31. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_SUBNET4)
  32. .arg(subnet->toText());
  33. subnets_.push_back(subnet);
  34. }
  35. Subnet4Ptr
  36. CfgSubnets4::selectSubnet(const SubnetSelector& selector) const {
  37. // First use RAI link select sub-option or subnet select option
  38. if (!selector.option_select_.isV4Zero()) {
  39. return (selectSubnet(selector.option_select_,
  40. selector.client_classes_));
  41. }
  42. // If relayed message has been received, try to match the giaddr with the
  43. // relay address specified for a subnet. It is also possible that the relay
  44. // address will not match with any of the relay addresses accross all
  45. // subnets, but we need to verify that for all subnets before we can try
  46. // to use the giaddr to match with the subnet prefix.
  47. if (!selector.giaddr_.isV4Zero()) {
  48. for (Subnet4Collection::const_iterator subnet = subnets_.begin();
  49. subnet != subnets_.end(); ++subnet) {
  50. // Check if the giaddr is equal to the one defined for the subnet.
  51. if (selector.giaddr_ != (*subnet)->getRelayInfo().addr_) {
  52. continue;
  53. }
  54. // Eliminate those subnets that do not meet client class criteria.
  55. if ((*subnet)->clientSupported(selector.client_classes_)) {
  56. return (*subnet);
  57. }
  58. }
  59. }
  60. // If we got to this point it means that we were not able to match the
  61. // giaddr with any of the addresses specified for subnets. Let's determine
  62. // what address from the client's packet to use to match with the
  63. // subnets' prefixes.
  64. IOAddress address = IOAddress::IPV4_ZERO_ADDRESS();
  65. // If there is a giaddr, use it for subnet selection.
  66. if (!selector.giaddr_.isV4Zero()) {
  67. address = selector.giaddr_;
  68. // If it is a Renew or Rebind, use the ciaddr.
  69. } else if (!selector.ciaddr_.isV4Zero() &&
  70. !selector.local_address_.isV4Bcast()) {
  71. address = selector.ciaddr_;
  72. // If ciaddr is not specified, use the source address.
  73. } else if (!selector.remote_address_.isV4Zero() &&
  74. !selector.local_address_.isV4Bcast()) {
  75. address = selector.remote_address_;
  76. // If local interface name is known, use the local address on this
  77. // interface.
  78. } else if (!selector.iface_name_.empty()) {
  79. IfacePtr iface = IfaceMgr::instance().getIface(selector.iface_name_);
  80. // This should never happen in the real life. Hence we throw an
  81. // exception.
  82. if (iface == NULL) {
  83. isc_throw(isc::BadValue, "interface " << selector.iface_name_
  84. << " doesn't exist and therefore it is impossible"
  85. " to find a suitable subnet for its IPv4 address");
  86. }
  87. iface->getAddress4(address);
  88. }
  89. // Unable to find a suitable address to use for subnet selection.
  90. if (address.isV4Zero()) {
  91. return (Subnet4Ptr());
  92. }
  93. // We have identified an address in the client's packet that can be
  94. // used for subnet selection. Match this packet with the subnets.
  95. return (selectSubnet(address, selector.client_classes_));
  96. }
  97. Subnet4Ptr
  98. CfgSubnets4::selectSubnet(const IOAddress& address,
  99. const ClientClasses& client_classes) const {
  100. for (Subnet4Collection::const_iterator subnet = subnets_.begin();
  101. subnet != subnets_.end(); ++subnet) {
  102. // Address is in range for the subnet prefix, so return it.
  103. if (!(*subnet)->inRange(address)) {
  104. continue;
  105. }
  106. // Eliminate those subnets that do not meet client class criteria.
  107. if ((*subnet)->clientSupported(client_classes)) {
  108. return (*subnet);
  109. }
  110. }
  111. // Failed to find a subnet.
  112. return (Subnet4Ptr());
  113. }
  114. bool
  115. CfgSubnets4::isDuplicate(const Subnet4& subnet) const {
  116. for (Subnet4Collection::const_iterator subnet_it = subnets_.begin();
  117. subnet_it != subnets_.end(); ++subnet_it) {
  118. if ((*subnet_it)->getID() == subnet.getID()) {
  119. return (true);
  120. }
  121. }
  122. return (false);
  123. }
  124. void
  125. CfgSubnets4::removeStatistics() {
  126. using namespace isc::stats;
  127. // For each v4 subnet currently configured, remove the statistic.
  128. /// @todo: May move this to CfgSubnets4 class if there will be more
  129. /// statistics here.
  130. for (Subnet4Collection::const_iterator subnet4 = subnets_.begin();
  131. subnet4 != subnets_.end(); ++subnet4) {
  132. StatsMgr::instance().del(StatsMgr::generateName("subnet",
  133. (*subnet4)->getID(),
  134. "total-addresses"));
  135. StatsMgr::instance().del(StatsMgr::generateName("subnet",
  136. (*subnet4)->getID(),
  137. "assigned-addresses"));
  138. }
  139. }
  140. void
  141. CfgSubnets4::updateStatistics() {
  142. using namespace isc::stats;
  143. /// @todo: May move this to CfgSubnets4 class if there will be more
  144. /// statistics here.
  145. for (Subnet4Collection::const_iterator subnet = subnets_.begin();
  146. subnet != subnets_.end(); ++subnet) {
  147. StatsMgr::instance().setValue(
  148. StatsMgr::generateName("subnet", (*subnet)->getID(), "total-addresses"),
  149. static_cast<int64_t>((*subnet)->getPoolCapacity(Lease::TYPE_V4)));
  150. }
  151. }
  152. } // end of namespace isc::dhcp
  153. } // end of namespace isc