cfgmgr.cc 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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/libdhcp++.h>
  16. #include <dhcpsrv/cfgmgr.h>
  17. #include <dhcpsrv/dhcpsrv_log.h>
  18. using namespace isc::asiolink;
  19. using namespace isc::util;
  20. namespace isc {
  21. namespace dhcp {
  22. CfgMgr&
  23. CfgMgr::instance() {
  24. static CfgMgr cfg_mgr;
  25. return (cfg_mgr);
  26. }
  27. void
  28. CfgMgr::addOptionSpace4(const OptionSpacePtr& space) {
  29. if (!space) {
  30. isc_throw(InvalidOptionSpace,
  31. "provided option space object is NULL.");
  32. }
  33. OptionSpaceCollection::iterator it = spaces4_.find(space->getName());
  34. if (it != spaces4_.end()) {
  35. isc_throw(InvalidOptionSpace, "option space " << space->getName()
  36. << " already added.");
  37. }
  38. spaces4_.insert(std::pair<std::string,
  39. OptionSpacePtr>(space->getName(), space));
  40. }
  41. void
  42. CfgMgr::addOptionSpace6(const OptionSpacePtr& space) {
  43. if (!space) {
  44. isc_throw(InvalidOptionSpace,
  45. "provided option space object is NULL.");
  46. }
  47. OptionSpaceCollection::iterator it = spaces6_.find(space->getName());
  48. if (it != spaces6_.end()) {
  49. isc_throw(InvalidOptionSpace, "option space " << space->getName()
  50. << " already added.");
  51. }
  52. spaces6_.insert(std::pair<std::string,
  53. OptionSpacePtr>(space->getName(), space));
  54. }
  55. void
  56. CfgMgr::addOptionDef(const OptionDefinitionPtr& def,
  57. const std::string& option_space) {
  58. // @todo we need better validation of the provided option space name here.
  59. // This will be implemented when #2313 is merged.
  60. if (option_space.empty()) {
  61. isc_throw(BadValue, "option space name must not be empty");
  62. } else if (!def) {
  63. // Option definition must point to a valid object.
  64. isc_throw(MalformedOptionDefinition, "option definition must not be NULL");
  65. } else if (getOptionDef(option_space, def->getCode())) {
  66. // Option definition must not be overriden.
  67. isc_throw(DuplicateOptionDefinition, "option definition already added"
  68. << " to option space " << option_space);
  69. } else if ((option_space == "dhcp4" &&
  70. LibDHCP::isStandardOption(Option::V4, def->getCode())) ||
  71. (option_space == "dhcp6" &&
  72. LibDHCP::isStandardOption(Option::V6, def->getCode()))) {
  73. // We must not override standard (assigned) option. The standard options
  74. // belong to dhcp4 or dhcp6 option space.
  75. isc_throw(BadValue, "unable to override definition of option '"
  76. << def->getCode() << "' in standard option space '"
  77. << option_space << "'.");
  78. }
  79. // Get existing option definitions for the option space.
  80. OptionDefContainerPtr defs = getOptionDefs(option_space);
  81. // getOptionDefs always returns a valid pointer to
  82. // the container. Let's make an assert to make sure.
  83. assert(defs);
  84. // Actually add the new definition.
  85. defs->push_back(def);
  86. option_def_spaces_[option_space] = defs;
  87. }
  88. OptionDefContainerPtr
  89. CfgMgr::getOptionDefs(const std::string& option_space) const {
  90. // @todo Validate the option space once the #2313 is implemented.
  91. // Get all option definitions for the particular option space.
  92. const OptionDefsMap::const_iterator& defs =
  93. option_def_spaces_.find(option_space);
  94. // If there are no option definitions for the particular option space
  95. // then return empty container.
  96. if (defs == option_def_spaces_.end()) {
  97. return (OptionDefContainerPtr(new OptionDefContainer()));
  98. }
  99. // If option definitions found, return them.
  100. return (defs->second);
  101. }
  102. OptionDefinitionPtr
  103. CfgMgr::getOptionDef(const std::string& option_space,
  104. const uint16_t option_code) const {
  105. // @todo Validate the option space once the #2313 is implemented.
  106. // Get a reference to option definitions for a particular option space.
  107. OptionDefContainerPtr defs = getOptionDefs(option_space);
  108. // If there are no matching option definitions then return the empty pointer.
  109. if (!defs || defs->empty()) {
  110. return (OptionDefinitionPtr());
  111. }
  112. // If there are some option definitions for a particular option space
  113. // use an option code to get the one we want.
  114. const OptionDefContainerTypeIndex& idx = defs->get<1>();
  115. const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
  116. // If there is no definition that matches option code, return empty pointer.
  117. if (std::distance(range.first, range.second) == 0) {
  118. return (OptionDefinitionPtr());
  119. }
  120. // If there is more than one definition matching an option code, return
  121. // the first one. This should not happen because we check for duplicates
  122. // when addOptionDef is called.
  123. return (*range.first);
  124. }
  125. Subnet6Ptr
  126. CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
  127. // If there's only one subnet configured, let's just use it
  128. // The idea is to keep small deployments easy. In a small network - one
  129. // router that also runs DHCPv6 server. Users specifies a single pool and
  130. // expects it to just work. Without this, the server would complain that it
  131. // doesn't have IP address on its interfaces that matches that
  132. // configuration. Such requirement makes sense in IPv4, but not in IPv6.
  133. // The server does not need to have a global address (using just link-local
  134. // is ok for DHCPv6 server) from the pool it serves.
  135. if ((subnets6_.size() == 1) && hint.getAddress().to_v6().is_link_local()) {
  136. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  137. DHCPSRV_CFGMGR_ONLY_SUBNET6)
  138. .arg(subnets6_[0]->toText()).arg(hint.toText());
  139. return (subnets6_[0]);
  140. }
  141. // If there is more than one, we need to choose the proper one
  142. for (Subnet6Collection::iterator subnet = subnets6_.begin();
  143. subnet != subnets6_.end(); ++subnet) {
  144. if ((*subnet)->inRange(hint)) {
  145. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  146. DHCPSRV_CFGMGR_SUBNET6)
  147. .arg((*subnet)->toText()).arg(hint.toText());
  148. return (*subnet);
  149. }
  150. }
  151. // sorry, we don't support that subnet
  152. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_NO_SUBNET6)
  153. .arg(hint.toText());
  154. return (Subnet6Ptr());
  155. }
  156. Subnet6Ptr CfgMgr::getSubnet6(OptionPtr /*interfaceId*/) {
  157. /// @todo: Implement get subnet6 by interface-id (for relayed traffic)
  158. isc_throw(NotImplemented, "Relayed DHCPv6 traffic is not supported yet.");
  159. }
  160. void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
  161. /// @todo: Check that this new subnet does not cross boundaries of any
  162. /// other already defined subnet.
  163. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_SUBNET6)
  164. .arg(subnet->toText());
  165. subnets6_.push_back(subnet);
  166. }
  167. Subnet4Ptr
  168. CfgMgr::getSubnet4(const isc::asiolink::IOAddress& hint) {
  169. // If there's only one subnet configured, let's just use it
  170. // The idea is to keep small deployments easy. In a small network - one
  171. // router that also runs DHCPv6 server. Users specifies a single pool and
  172. // expects it to just work. Without this, the server would complain that it
  173. // doesn't have IP address on its interfaces that matches that
  174. // configuration. Such requirement makes sense in IPv4, but not in IPv6.
  175. // The server does not need to have a global address (using just link-local
  176. // is ok for DHCPv6 server) from the pool it serves.
  177. if (subnets4_.size() == 1) {
  178. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  179. DHCPSRV_CFGMGR_ONLY_SUBNET4)
  180. .arg(subnets4_[0]->toText()).arg(hint.toText());
  181. return (subnets4_[0]);
  182. }
  183. // If there is more than one, we need to choose the proper one
  184. for (Subnet4Collection::iterator subnet = subnets4_.begin();
  185. subnet != subnets4_.end(); ++subnet) {
  186. if ((*subnet)->inRange(hint)) {
  187. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  188. DHCPSRV_CFGMGR_SUBNET4)
  189. .arg((*subnet)->toText()).arg(hint.toText());
  190. return (*subnet);
  191. }
  192. }
  193. // sorry, we don't support that subnet
  194. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_NO_SUBNET4)
  195. .arg(hint.toText());
  196. return (Subnet4Ptr());
  197. }
  198. void CfgMgr::addSubnet4(const Subnet4Ptr& subnet) {
  199. /// @todo: Check that this new subnet does not cross boundaries of any
  200. /// other already defined subnet.
  201. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_SUBNET4)
  202. .arg(subnet->toText());
  203. subnets4_.push_back(subnet);
  204. }
  205. void CfgMgr::deleteOptionDefs() {
  206. option_def_spaces_.clear();
  207. }
  208. void CfgMgr::deleteSubnets4() {
  209. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_DELETE_SUBNET4);
  210. subnets4_.clear();
  211. }
  212. void CfgMgr::deleteSubnets6() {
  213. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_DELETE_SUBNET6);
  214. subnets6_.clear();
  215. }
  216. std::string CfgMgr::getDataDir() {
  217. return (datadir_);
  218. }
  219. CfgMgr::CfgMgr()
  220. :datadir_(DHCP_DATA_DIR) {
  221. // DHCP_DATA_DIR is set with -DDHCP_DATA_DIR in Makefile.am
  222. }
  223. CfgMgr::~CfgMgr() {
  224. }
  225. }; // end of isc::dhcp namespace
  226. }; // end of isc namespace