cfgmgr.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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(make_pair(space->getName(), space));
  39. }
  40. void
  41. CfgMgr::addOptionSpace6(const OptionSpacePtr& space) {
  42. if (!space) {
  43. isc_throw(InvalidOptionSpace,
  44. "provided option space object is NULL.");
  45. }
  46. OptionSpaceCollection::iterator it = spaces6_.find(space->getName());
  47. if (it != spaces6_.end()) {
  48. isc_throw(InvalidOptionSpace, "option space " << space->getName()
  49. << " already added.");
  50. }
  51. spaces6_.insert(make_pair(space->getName(), space));
  52. }
  53. void
  54. CfgMgr::addOptionDef(const OptionDefinitionPtr& def,
  55. const std::string& option_space) {
  56. // @todo we need better validation of the provided option space name here.
  57. // This will be implemented when #2313 is merged.
  58. if (option_space.empty()) {
  59. isc_throw(BadValue, "option space name must not be empty");
  60. } else if (!def) {
  61. // Option definition must point to a valid object.
  62. isc_throw(MalformedOptionDefinition, "option definition must not be NULL");
  63. } else if (getOptionDef(option_space, def->getCode())) {
  64. // Option definition must not be overriden.
  65. isc_throw(DuplicateOptionDefinition, "option definition already added"
  66. << " to option space " << option_space);
  67. } else if ((option_space == "dhcp4" &&
  68. LibDHCP::isStandardOption(Option::V4, def->getCode())) ||
  69. (option_space == "dhcp6" &&
  70. LibDHCP::isStandardOption(Option::V6, def->getCode()))) {
  71. // We must not override standard (assigned) option. The standard options
  72. // belong to dhcp4 or dhcp6 option space.
  73. isc_throw(BadValue, "unable to override definition of option '"
  74. << def->getCode() << "' in standard option space '"
  75. << option_space << "'.");
  76. }
  77. // Actually add a new item.
  78. option_def_spaces_.addItem(def, option_space);
  79. }
  80. OptionDefContainerPtr
  81. CfgMgr::getOptionDefs(const std::string& option_space) const {
  82. // @todo Validate the option space once the #2313 is implemented.
  83. return (option_def_spaces_.getItems(option_space));
  84. }
  85. OptionDefinitionPtr
  86. CfgMgr::getOptionDef(const std::string& option_space,
  87. const uint16_t option_code) const {
  88. // @todo Validate the option space once the #2313 is implemented.
  89. // Get a reference to option definitions for a particular option space.
  90. OptionDefContainerPtr defs = getOptionDefs(option_space);
  91. // If there are no matching option definitions then return the empty pointer.
  92. if (!defs || defs->empty()) {
  93. return (OptionDefinitionPtr());
  94. }
  95. // If there are some option definitions for a particular option space
  96. // use an option code to get the one we want.
  97. const OptionDefContainerTypeIndex& idx = defs->get<1>();
  98. const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
  99. // If there is no definition that matches option code, return empty pointer.
  100. if (std::distance(range.first, range.second) == 0) {
  101. return (OptionDefinitionPtr());
  102. }
  103. // If there is more than one definition matching an option code, return
  104. // the first one. This should not happen because we check for duplicates
  105. // when addOptionDef is called.
  106. return (*range.first);
  107. }
  108. Subnet6Ptr
  109. CfgMgr::getSubnet6(const std::string& iface) {
  110. if (!iface.length()) {
  111. return (Subnet6Ptr());
  112. }
  113. // If there is more than one, we need to choose the proper one
  114. for (Subnet6Collection::iterator subnet = subnets6_.begin();
  115. subnet != subnets6_.end(); ++subnet) {
  116. if (iface == (*subnet)->getIface()) {
  117. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  118. DHCPSRV_CFGMGR_SUBNET6_IFACE)
  119. .arg((*subnet)->toText()).arg(iface);
  120. return (*subnet);
  121. }
  122. }
  123. return (Subnet6Ptr());
  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. User 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 iface_id_option) {
  157. if (!iface_id_option) {
  158. return (Subnet6Ptr());
  159. }
  160. // Let's iterate over all subnets and for those that have interface-id
  161. // defined, check if the interface-id is equal to what we are looking for
  162. for (Subnet6Collection::iterator subnet = subnets6_.begin();
  163. subnet != subnets6_.end(); ++subnet) {
  164. if ( (*subnet)->getInterfaceId() &&
  165. ((*subnet)->getInterfaceId()->equal(iface_id_option))) {
  166. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  167. DHCPSRV_CFGMGR_SUBNET6_IFACE_ID)
  168. .arg((*subnet)->toText());
  169. return (*subnet);
  170. }
  171. }
  172. return (Subnet6Ptr());
  173. }
  174. void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
  175. /// @todo: Check that this new subnet does not cross boundaries of any
  176. /// other already defined subnet.
  177. /// @todo: Check that there is no subnet with the same interface-id
  178. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_SUBNET6)
  179. .arg(subnet->toText());
  180. subnets6_.push_back(subnet);
  181. }
  182. Subnet4Ptr
  183. CfgMgr::getSubnet4(const isc::asiolink::IOAddress& hint) {
  184. // If there's only one subnet configured, let's just use it
  185. // The idea is to keep small deployments easy. In a small network - one
  186. // router that also runs DHCPv6 server. Users specifies a single pool and
  187. // expects it to just work. Without this, the server would complain that it
  188. // doesn't have IP address on its interfaces that matches that
  189. // configuration. Such requirement makes sense in IPv4, but not in IPv6.
  190. // The server does not need to have a global address (using just link-local
  191. // is ok for DHCPv6 server) from the pool it serves.
  192. if (subnets4_.size() == 1) {
  193. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  194. DHCPSRV_CFGMGR_ONLY_SUBNET4)
  195. .arg(subnets4_[0]->toText()).arg(hint.toText());
  196. return (subnets4_[0]);
  197. }
  198. // If there is more than one, we need to choose the proper one
  199. for (Subnet4Collection::iterator subnet = subnets4_.begin();
  200. subnet != subnets4_.end(); ++subnet) {
  201. if ((*subnet)->inRange(hint)) {
  202. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  203. DHCPSRV_CFGMGR_SUBNET4)
  204. .arg((*subnet)->toText()).arg(hint.toText());
  205. return (*subnet);
  206. }
  207. }
  208. // sorry, we don't support that subnet
  209. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_NO_SUBNET4)
  210. .arg(hint.toText());
  211. return (Subnet4Ptr());
  212. }
  213. void CfgMgr::addSubnet4(const Subnet4Ptr& subnet) {
  214. /// @todo: Check that this new subnet does not cross boundaries of any
  215. /// other already defined subnet.
  216. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_SUBNET4)
  217. .arg(subnet->toText());
  218. subnets4_.push_back(subnet);
  219. }
  220. void CfgMgr::deleteOptionDefs() {
  221. option_def_spaces_.clearItems();
  222. }
  223. void CfgMgr::deleteSubnets4() {
  224. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_DELETE_SUBNET4);
  225. subnets4_.clear();
  226. }
  227. void CfgMgr::deleteSubnets6() {
  228. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_DELETE_SUBNET6);
  229. subnets6_.clear();
  230. }
  231. std::string CfgMgr::getDataDir() {
  232. return (datadir_);
  233. }
  234. CfgMgr::CfgMgr()
  235. :datadir_(DHCP_DATA_DIR) {
  236. // DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
  237. // Note: the definition of DHCP_DATA_DIR needs to include quotation marks
  238. // See AM_CPPFLAGS definition in Makefile.am
  239. }
  240. CfgMgr::~CfgMgr() {
  241. }
  242. }; // end of isc::dhcp namespace
  243. }; // end of isc namespace