123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- // Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <config.h>
- #include <asiolink/asiolink.h>
- #include <cc/data.h>
- #include <cc/session.h>
- #include <config/ccsession.h>
- #include <dhcp/iface_mgr.h>
- #include <dhcpsrv/dhcp_config_parser.h>
- #include <dhcpsrv/cfgmgr.h>
- #include <dhcp6/json_config_parser.h>
- #include <dhcp6/ctrl_dhcp6_srv.h>
- #include <dhcp6/dhcp6_log.h>
- #include <dhcp6/spec_config.h>
- #include <exceptions/exceptions.h>
- #include <hooks/hooks_manager.h>
- #include <util/buffer.h>
- #include <cassert>
- #include <iostream>
- #include <string>
- #include <vector>
- using namespace isc::asiolink;
- using namespace isc::cc;
- using namespace isc::config;
- using namespace isc::data;
- using namespace isc::dhcp;
- using namespace isc::hooks;
- using namespace isc::log;
- using namespace isc::util;
- using namespace std;
- namespace isc {
- namespace dhcp {
- /// @brief Helper session object that represents raw connection to msgq.
- isc::cc::Session* cc_session_ = NULL;
- /// @brief Session that receives configuration and commands
- isc::config::ModuleCCSession* config_session_ = NULL;
- /// @brief A dummy configuration handler that always returns success.
- ///
- /// This configuration handler does not perform configuration
- /// parsing and always returns success. A dummy handler should
- /// be installed using \ref isc::config::ModuleCCSession ctor
- /// to get the initial configuration. This initial configuration
- /// comprises values for only those elements that were modified
- /// the previous session. The \ref dhcp6ConfigHandler can't be
- /// used to parse the initial configuration because it needs the
- /// full configuration to satisfy dependencies between the
- /// various configuration values. Installing the dummy handler
- /// that guarantees to return success causes initial configuration
- /// to be stored for the session being created and that it can
- /// be later accessed with
- /// \ref isc::config::ConfigData::getFullConfig().
- ///
- /// @param new_config new configuration.
- ///
- /// @return success configuration status.
- ConstElementPtr
- dhcp6StubConfigHandler(ConstElementPtr) {
- // This configuration handler is intended to be used only
- // when the initial configuration comes in. To receive this
- // configuration a pointer to this handler must be passed
- // using ModuleCCSession constructor. This constructor will
- // invoke the handler and will store the configuration for
- // the configuration session when the handler returns success.
- // Since this configuration is partial we just pretend to
- // parse it and always return success. The function that
- // initiates the session must get the configuration on its
- // own using getFullConfig.
- return (isc::config::createAnswer(0, "Configuration accepted."));
- }
- ConstElementPtr
- bundyConfigHandler(ConstElementPtr new_config) {
- if (!ControlledDhcpv6Srv::getInstance() || !config_session_) {
- // That should never happen as we install config_handler
- // after we instantiate the server.
- ConstElementPtr answer =
- isc::config::createAnswer(1, "Configuration rejected,"
- " server is during startup/shutdown phase.");
- return (answer);
- }
- // The configuration passed to this handler function is partial.
- // In other words, it just includes the values being modified.
- // In the same time, there are dependencies between various
- // DHCP configuration parsers. For example: the option value can
- // be set if the definition of this option is set. If someone removes
- // an existing option definition then the partial configuration that
- // removes that definition is triggered while a relevant option value
- // may remain configured. This eventually results in the DHCP server
- // configuration being in the inconsistent state.
- // In order to work around this problem we need to merge the new
- // configuration with the existing (full) configuration.
- // Let's create a new object that will hold the merged configuration.
- boost::shared_ptr<MapElement> merged_config(new MapElement());
- // Let's get the existing configuration.
- ConstElementPtr full_config = config_session_->getFullConfig();
- // The full_config and merged_config should be always non-NULL
- // but to provide some level of exception safety we check that they
- // really are (in case we go out of memory).
- if (full_config && merged_config) {
- merged_config->setValue(full_config->mapValue());
- // Merge an existing and new configuration.
- isc::data::merge(merged_config, new_config);
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_UPDATE)
- .arg(merged_config->str());
- }
- // Configure the server.
- return (ControlledDhcpv6Srv::processConfig(merged_config));
- }
- void
- ControlledDhcpv6Srv::init(const std::string& config_file) {
- // Call base class's init.
- Daemon::init(config_file);
- // This is Bundy configuration backed. It established control session
- // that is used to connect to Bundy framework.
- //
- // Creates session that will be used to receive commands and updated
- // configuration from cfgmgr (or indirectly from user via bindctl).
- string specfile;
- if (getenv("B10_FROM_BUILD")) {
- specfile = string(getenv("B10_FROM_BUILD")) +
- "/src/bin/dhcp6/dhcp6.spec";
- } else {
- specfile = string(DHCP6_SPECFILE_LOCATION);
- }
- /// @todo: Check if session is not established already. Throw, if it is.
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_CCSESSION_STARTING)
- .arg(specfile);
- cc_session_ = new Session(io_service_.get_io_service());
- // Create a session with the dummy configuration handler.
- // Dumy configuration handler is internally invoked by the
- // constructor and on success the constructor updates
- // the current session with the configuration that had been
- // committed in the previous session. If we did not install
- // the dummy handler, the previous configuration would have
- // been lost.
- config_session_ = new ModuleCCSession(specfile, *cc_session_,
- dhcp6StubConfigHandler,
- processCommand, false);
- config_session_->start();
- // The constructor already pulled the configuration that had
- // been created in the previous session thanks to the dummy
- // handler. We can switch to the handler that will be
- // parsing future changes to the configuration.
- config_session_->setConfigHandler(bundyConfigHandler);
- try {
- // Pull the full configuration out from the session.
- processConfig(config_session_->getFullConfig());
- // Server will start DDNS communications if its enabled.
- server_->startD2();
- // Configuration may disable or enable interfaces so we have to
- // reopen sockets according to new configuration.
- openActiveSockets(getPort());
- } catch (const std::exception& ex) {
- LOG_ERROR(dhcp6_logger, DHCP6_CONFIG_LOAD_FAIL).arg(ex.what());
- }
- /// Integrate the asynchronous I/O model of Bundy configuration
- /// control with the "select" model of the DHCP server. This is
- /// fully explained in \ref dhcpv6Session.
- int ctrl_socket = cc_session_->getSocketDesc();
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_CCSESSION_STARTED)
- .arg(ctrl_socket);
- IfaceMgr::instance().addExternalSocket(ctrl_socket, sessionReader);
- return;
- }
- void ControlledDhcpv6Srv::cleanup() {
- if (config_session_) {
- delete config_session_;
- config_session_ = NULL;
- }
- if (cc_session_) {
- int ctrl_socket = cc_session_->getSocketDesc();
- cc_session_->disconnect();
- // deregister session socket
- IfaceMgr::instance().deleteExternalSocket(ctrl_socket);
- delete cc_session_;
- cc_session_ = NULL;
- }
- }
- void
- Daemon::loggerInit(const char* log_name, bool verbose, bool stand_alone) {
- isc::log::initLogger(log_name,
- (verbose ? isc::log::DEBUG : isc::log::INFO),
- isc::log::MAX_DEBUG_LEVEL, NULL, !stand_alone);
- }
- }; // end of isc::dhcp namespace
- }; // end of isc namespace
|