bundy_controller.cc 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Copyright (C) 2012-2014 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 <asiolink/asiolink.h>
  16. #include <cc/data.h>
  17. #include <cc/session.h>
  18. #include <config/ccsession.h>
  19. #include <dhcp/iface_mgr.h>
  20. #include <dhcpsrv/dhcp_config_parser.h>
  21. #include <dhcpsrv/cfgmgr.h>
  22. #include <dhcp6/json_config_parser.h>
  23. #include <dhcp6/ctrl_dhcp6_srv.h>
  24. #include <dhcp6/dhcp6_log.h>
  25. #include <dhcp6/spec_config.h>
  26. #include <exceptions/exceptions.h>
  27. #include <hooks/hooks_manager.h>
  28. #include <util/buffer.h>
  29. #include <cassert>
  30. #include <iostream>
  31. #include <string>
  32. #include <vector>
  33. using namespace isc::asiolink;
  34. using namespace isc::cc;
  35. using namespace isc::config;
  36. using namespace isc::data;
  37. using namespace isc::dhcp;
  38. using namespace isc::hooks;
  39. using namespace isc::log;
  40. using namespace isc::util;
  41. using namespace std;
  42. namespace isc {
  43. namespace dhcp {
  44. /// @brief Helper session object that represents raw connection to msgq.
  45. isc::cc::Session* cc_session_ = NULL;
  46. /// @brief Session that receives configuration and commands
  47. isc::config::ModuleCCSession* config_session_ = NULL;
  48. /// @brief A dummy configuration handler that always returns success.
  49. ///
  50. /// This configuration handler does not perform configuration
  51. /// parsing and always returns success. A dummy handler should
  52. /// be installed using \ref isc::config::ModuleCCSession ctor
  53. /// to get the initial configuration. This initial configuration
  54. /// comprises values for only those elements that were modified
  55. /// the previous session. The \ref dhcp6ConfigHandler can't be
  56. /// used to parse the initial configuration because it needs the
  57. /// full configuration to satisfy dependencies between the
  58. /// various configuration values. Installing the dummy handler
  59. /// that guarantees to return success causes initial configuration
  60. /// to be stored for the session being created and that it can
  61. /// be later accessed with
  62. /// \ref isc::config::ConfigData::getFullConfig().
  63. ///
  64. /// @param new_config new configuration.
  65. ///
  66. /// @return success configuration status.
  67. ConstElementPtr
  68. dhcp6StubConfigHandler(ConstElementPtr) {
  69. // This configuration handler is intended to be used only
  70. // when the initial configuration comes in. To receive this
  71. // configuration a pointer to this handler must be passed
  72. // using ModuleCCSession constructor. This constructor will
  73. // invoke the handler and will store the configuration for
  74. // the configuration session when the handler returns success.
  75. // Since this configuration is partial we just pretend to
  76. // parse it and always return success. The function that
  77. // initiates the session must get the configuration on its
  78. // own using getFullConfig.
  79. return (isc::config::createAnswer(0, "Configuration accepted."));
  80. }
  81. ConstElementPtr
  82. bundyConfigHandler(ConstElementPtr new_config) {
  83. if (!ControlledDhcpv6Srv::getInstance() || !config_session_) {
  84. // That should never happen as we install config_handler
  85. // after we instantiate the server.
  86. ConstElementPtr answer =
  87. isc::config::createAnswer(1, "Configuration rejected,"
  88. " server is during startup/shutdown phase.");
  89. return (answer);
  90. }
  91. // The configuration passed to this handler function is partial.
  92. // In other words, it just includes the values being modified.
  93. // In the same time, there are dependencies between various
  94. // DHCP configuration parsers. For example: the option value can
  95. // be set if the definition of this option is set. If someone removes
  96. // an existing option definition then the partial configuration that
  97. // removes that definition is triggered while a relevant option value
  98. // may remain configured. This eventually results in the DHCP server
  99. // configuration being in the inconsistent state.
  100. // In order to work around this problem we need to merge the new
  101. // configuration with the existing (full) configuration.
  102. // Let's create a new object that will hold the merged configuration.
  103. boost::shared_ptr<MapElement> merged_config(new MapElement());
  104. // Let's get the existing configuration.
  105. ConstElementPtr full_config = config_session_->getFullConfig();
  106. // The full_config and merged_config should be always non-NULL
  107. // but to provide some level of exception safety we check that they
  108. // really are (in case we go out of memory).
  109. if (full_config && merged_config) {
  110. merged_config->setValue(full_config->mapValue());
  111. // Merge an existing and new configuration.
  112. isc::data::merge(merged_config, new_config);
  113. LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_UPDATE)
  114. .arg(merged_config->str());
  115. }
  116. // Configure the server.
  117. return (ControlledDhcpv6Srv::processConfig(merged_config));
  118. }
  119. void
  120. ControlledDhcpv6Srv::init(const std::string& config_file) {
  121. // Call base class's init.
  122. Daemon::init(config_file);
  123. // This is Bundy configuration backed. It established control session
  124. // that is used to connect to Bundy framework.
  125. //
  126. // Creates session that will be used to receive commands and updated
  127. // configuration from cfgmgr (or indirectly from user via bindctl).
  128. string specfile;
  129. if (getenv("B10_FROM_BUILD")) {
  130. specfile = string(getenv("B10_FROM_BUILD")) +
  131. "/src/bin/dhcp6/dhcp6.spec";
  132. } else {
  133. specfile = string(DHCP6_SPECFILE_LOCATION);
  134. }
  135. /// @todo: Check if session is not established already. Throw, if it is.
  136. LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_CCSESSION_STARTING)
  137. .arg(specfile);
  138. cc_session_ = new Session(io_service_.get_io_service());
  139. // Create a session with the dummy configuration handler.
  140. // Dumy configuration handler is internally invoked by the
  141. // constructor and on success the constructor updates
  142. // the current session with the configuration that had been
  143. // committed in the previous session. If we did not install
  144. // the dummy handler, the previous configuration would have
  145. // been lost.
  146. config_session_ = new ModuleCCSession(specfile, *cc_session_,
  147. dhcp6StubConfigHandler,
  148. processCommand, false);
  149. config_session_->start();
  150. // The constructor already pulled the configuration that had
  151. // been created in the previous session thanks to the dummy
  152. // handler. We can switch to the handler that will be
  153. // parsing future changes to the configuration.
  154. config_session_->setConfigHandler(bundyConfigHandler);
  155. try {
  156. // Pull the full configuration out from the session.
  157. processConfig(config_session_->getFullConfig());
  158. // Server will start DDNS communications if its enabled.
  159. server_->startD2();
  160. // Configuration may disable or enable interfaces so we have to
  161. // reopen sockets according to new configuration.
  162. openActiveSockets(getPort());
  163. } catch (const std::exception& ex) {
  164. LOG_ERROR(dhcp6_logger, DHCP6_CONFIG_LOAD_FAIL).arg(ex.what());
  165. }
  166. /// Integrate the asynchronous I/O model of Bundy configuration
  167. /// control with the "select" model of the DHCP server. This is
  168. /// fully explained in \ref dhcpv6Session.
  169. int ctrl_socket = cc_session_->getSocketDesc();
  170. LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_CCSESSION_STARTED)
  171. .arg(ctrl_socket);
  172. IfaceMgr::instance().addExternalSocket(ctrl_socket, sessionReader);
  173. return;
  174. }
  175. void ControlledDhcpv6Srv::cleanup() {
  176. if (config_session_) {
  177. delete config_session_;
  178. config_session_ = NULL;
  179. }
  180. if (cc_session_) {
  181. int ctrl_socket = cc_session_->getSocketDesc();
  182. cc_session_->disconnect();
  183. // deregister session socket
  184. IfaceMgr::instance().deleteExternalSocket(ctrl_socket);
  185. delete cc_session_;
  186. cc_session_ = NULL;
  187. }
  188. }
  189. void
  190. Daemon::loggerInit(const char* log_name, bool verbose, bool stand_alone) {
  191. isc::log::initLogger(log_name,
  192. (verbose ? isc::log::DEBUG : isc::log::INFO),
  193. isc::log::MAX_DEBUG_LEVEL, NULL, !stand_alone);
  194. }
  195. }; // end of isc::dhcp namespace
  196. }; // end of isc namespace