cfg_subnets6.cc 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Copyright (C) 2014-2016 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 <dhcpsrv/cfg_subnets6.h>
  8. #include <dhcpsrv/dhcpsrv_log.h>
  9. #include <dhcpsrv/lease_mgr_factory.h>
  10. #include <dhcpsrv/subnet_id.h>
  11. #include <stats/stats_mgr.h>
  12. using namespace isc::asiolink;
  13. namespace isc {
  14. namespace dhcp {
  15. void
  16. CfgSubnets6::add(const Subnet6Ptr& subnet) {
  17. /// @todo: Check that this new subnet does not cross boundaries of any
  18. /// other already defined subnet.
  19. if (isDuplicate(*subnet)) {
  20. isc_throw(isc::dhcp::DuplicateSubnetID, "ID of the new IPv6 subnet '"
  21. << subnet->getID() << "' is already in use");
  22. }
  23. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_SUBNET6)
  24. .arg(subnet->toText());
  25. subnets_.push_back(subnet);
  26. }
  27. Subnet6Ptr
  28. CfgSubnets6::selectSubnet(const SubnetSelector& selector) const {
  29. Subnet6Ptr subnet;
  30. // If relay agent link address is set to zero it means that we're dealing
  31. // with a directly connected client.
  32. if (selector.first_relay_linkaddr_ == IOAddress("::")) {
  33. // If interface name is known try to match it with interface names
  34. // specified for configured subnets.
  35. if (!selector.iface_name_.empty()) {
  36. subnet = selectSubnet(selector.iface_name_,
  37. selector.client_classes_);
  38. }
  39. // If interface name didn't match, try the client's address.
  40. if (!subnet && selector.remote_address_ != IOAddress("::")) {
  41. subnet = selectSubnet(selector.remote_address_,
  42. selector.client_classes_);
  43. }
  44. // If relay agent link address is set, we're dealing with a relayed message.
  45. } else {
  46. // Find the subnet using the Interface Id option, if present.
  47. subnet = selectSubnet(selector.interface_id_, selector.client_classes_);
  48. // If Interface ID option could not be matched for any subnet, try
  49. // the relay agent link address.
  50. if (!subnet) {
  51. subnet = selectSubnet(selector.first_relay_linkaddr_,
  52. selector.client_classes_,
  53. true);
  54. }
  55. }
  56. // Return subnet found, or NULL if not found.
  57. return (subnet);
  58. }
  59. Subnet6Ptr
  60. CfgSubnets6::selectSubnet(const asiolink::IOAddress& address,
  61. const ClientClasses& client_classes,
  62. const bool is_relay_address) const {
  63. // If the specified address is a relay address we first need to match
  64. // it with the relay addresses specified for all subnets.
  65. if (is_relay_address) {
  66. for (Subnet6Collection::const_iterator subnet = subnets_.begin();
  67. subnet != subnets_.end(); ++subnet) {
  68. // If the specified address matches the relay address, return this
  69. // subnet.
  70. if (is_relay_address &&
  71. ((*subnet)->getRelayInfo().addr_ == address) &&
  72. (*subnet)->clientSupported(client_classes)) {
  73. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  74. DHCPSRV_CFGMGR_SUBNET6_RELAY)
  75. .arg((*subnet)->toText()).arg(address.toText());
  76. return (*subnet);
  77. }
  78. }
  79. }
  80. // No success so far. Check if the specified address is in range
  81. // with any subnet.
  82. for (Subnet6Collection::const_iterator subnet = subnets_.begin();
  83. subnet != subnets_.end(); ++subnet) {
  84. if ((*subnet)->inRange(address) &&
  85. (*subnet)->clientSupported(client_classes)) {
  86. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_SUBNET6)
  87. .arg((*subnet)->toText()).arg(address.toText());
  88. return (*subnet);
  89. }
  90. }
  91. // Nothing found.
  92. return (Subnet6Ptr());
  93. }
  94. Subnet6Ptr
  95. CfgSubnets6::selectSubnet(const std::string& iface_name,
  96. const ClientClasses& client_classes) const {
  97. // If empty interface specified, we can't select subnet by interface.
  98. if (!iface_name.empty()) {
  99. for (Subnet6Collection::const_iterator subnet = subnets_.begin();
  100. subnet != subnets_.end(); ++subnet) {
  101. // If interface name matches with the one specified for the subnet
  102. // and the client is not rejected based on the classification,
  103. // return the subnet.
  104. if ((iface_name == (*subnet)->getIface()) &&
  105. (*subnet)->clientSupported(client_classes)) {
  106. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  107. DHCPSRV_CFGMGR_SUBNET6_IFACE)
  108. .arg((*subnet)->toText()).arg(iface_name);
  109. return (*subnet);
  110. }
  111. }
  112. }
  113. // No subnet found for this interface name.
  114. return (Subnet6Ptr());
  115. }
  116. Subnet6Ptr
  117. CfgSubnets6::selectSubnet(const OptionPtr& interface_id,
  118. const ClientClasses& client_classes) const {
  119. // We can only select subnet using an interface id, if the interface
  120. // id is known.
  121. if (interface_id) {
  122. for (Subnet6Collection::const_iterator subnet = subnets_.begin();
  123. subnet != subnets_.end(); ++subnet) {
  124. // If interface id matches for the subnet and the subnet is not
  125. // rejected based on the classification.
  126. if ((*subnet)->getInterfaceId() &&
  127. (*subnet)->getInterfaceId()->equals(interface_id) &&
  128. (*subnet)->clientSupported(client_classes)) {
  129. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  130. DHCPSRV_CFGMGR_SUBNET6_IFACE_ID)
  131. .arg((*subnet)->toText());
  132. return (*subnet);
  133. }
  134. }
  135. }
  136. // No subnet found.
  137. return (Subnet6Ptr());
  138. }
  139. bool
  140. CfgSubnets6::isDuplicate(const Subnet6& subnet) const {
  141. for (Subnet6Collection::const_iterator subnet_it = subnets_.begin();
  142. subnet_it != subnets_.end(); ++subnet_it) {
  143. if ((*subnet_it)->getID() == subnet.getID()) {
  144. return (true);
  145. }
  146. }
  147. return (false);
  148. }
  149. void
  150. CfgSubnets6::removeStatistics() {
  151. using namespace isc::stats;
  152. StatsMgr& stats_mgr = StatsMgr::instance();
  153. // For each v6 subnet currently configured, remove the statistics.
  154. for (Subnet6Collection::const_iterator subnet6 = subnets_.begin();
  155. subnet6 != subnets_.end(); ++subnet6) {
  156. SubnetID subnet_id = (*subnet6)->getID();
  157. stats_mgr.del(StatsMgr::generateName("subnet", subnet_id, "total-nas"));
  158. stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
  159. "assigned-nas"));
  160. stats_mgr.del(StatsMgr::generateName("subnet", subnet_id, "total-pds"));
  161. stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
  162. "assigned-pds"));
  163. stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
  164. "declined-addresses"));
  165. stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
  166. "declined-reclaimed-addresses"));
  167. }
  168. }
  169. void
  170. CfgSubnets6::updateStatistics() {
  171. using namespace isc::stats;
  172. StatsMgr& stats_mgr = StatsMgr::instance();
  173. // For each v6 subnet currently configured, calculate totals
  174. for (Subnet6Collection::const_iterator subnet6 = subnets_.begin();
  175. subnet6 != subnets_.end(); ++subnet6) {
  176. SubnetID subnet_id = (*subnet6)->getID();
  177. stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
  178. "total-nas"),
  179. static_cast<int64_t>
  180. ((*subnet6)->getPoolCapacity(Lease::TYPE_NA)));
  181. stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
  182. "total-pds"),
  183. static_cast<int64_t>
  184. ((*subnet6)->getPoolCapacity(Lease::TYPE_PD)));
  185. }
  186. // Only recount the stats if we have subnets.
  187. if (subnets_.begin() != subnets_.end()) {
  188. LeaseMgrFactory::instance().recountLeaseStats6();
  189. }
  190. }
  191. } // end of namespace isc::dhcp
  192. } // end of namespace isc