Commit 4a6553ba authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[2269] DHCPv6 startup phase is now handled properly by the config parser.

parent e2a552fc
......@@ -22,12 +22,15 @@
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <cc/data.h>
#include <config/ccsession.h>
#include <asiolink/io_address.h>
#include <dhcp6/config_parser.h>
#include <dhcp/triplet.h>
#include <dhcp/pool.h>
#include <dhcp/subnet.h>
#include <dhcp/cfgmgr.h>
#include <dhcp6/dhcp6_log.h>
#include <log/logger_support.h>
using namespace std;
using namespace isc::data;
......@@ -64,12 +67,14 @@ public:
:param_name_(param_name) {
}
virtual void build(ConstElementPtr new_config) {
std::cout << "Build for token: [" << param_name_ << "] = ["
<< value_->str() << "]" << std::endl;
value_ = new_config;
}
virtual void commit() {
// debug message. The whole DummyParser class is used only for parser
// Debug message. The whole DummyParser class is used only for parser
// debugging, and is not used in production code. It is very convenient
// to keep it around. Please do not turn this cout into logger calls
// to keep it around. Please do not turn this cout into logger calls.
std::cout << "Commit for token: [" << param_name_ << "] = ["
<< value_->str() << "]" << std::endl;
}
......@@ -96,8 +101,6 @@ public:
isc_throw(BadValue, "Failed to parse value " << value->str()
<< " as unsigned 32-bit integer.");
}
cout << "### storing " << param_name_ << "=" << value_ <<
" in " << storage_ << endl;
storage_->insert(pair<string, uint32_t>(param_name_, value_));
}
......@@ -158,7 +161,6 @@ public:
virtual void build(ConstElementPtr value) {
BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
interfaces_.push_back(iface->str());
cout << "#### Configured to listen on interface " << iface->str() << endl;
}
}
......@@ -201,6 +203,7 @@ public:
boost::erase_all(txt, " ");
boost::erase_all(txt, "\t");
// Is this prefix/len notation?
size_t pos = txt.find("/");
if (pos != string::npos) {
IOAddress addr("::");
......@@ -220,22 +223,18 @@ public:
"definition: " << text_pool->stringValue());
}
cout << "#### Creating Pool6(TYPE_IA, " << addr.toText() << "/"
<< (int)len << ")" << endl;
// using prefix/len notation
Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, addr, len));
pools_->push_back(pool);
continue;
}
// Is this min-max notation?
pos = txt.find("-");
if (pos != string::npos) {
// using min-max notation
IOAddress min(txt.substr(0,pos-1));
IOAddress max(txt.substr(pos+1));
cout << "#### Creating Pool6(TYPE_IA, " << min.toText() << ","
<< max.toText() << ")" << endl;
Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, min, max));
pools_->push_back(pool);
......@@ -270,7 +269,6 @@ public:
void build(ConstElementPtr subnet) {
cout << "#### Subnet6ConfigParser::build(): parsing: [" << subnet->str() << "]" << endl;
BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
ParserPtr parser(createSubnet6ConfigParser(param.first));
......@@ -305,8 +303,6 @@ public:
void commit() {
StringStorage::const_iterator it = string_values_.find("subnet");
cout << "#### Subnet6ConfigParser::commit() string_values_.size()="
<< string_values_.size() << endl;
if (it == string_values_.end()) {
isc_throw(Dhcp6ConfigError,
"Mandatory subnet definition in subnet missing");
......@@ -328,7 +324,8 @@ public:
Triplet<uint32_t> pref = getParam("preferred-lifetime");
Triplet<uint32_t> valid = getParam("valid-lifetime");
cout << "#### Adding subnet " << addr.toText() << "/" << (int)len
/// @todo: Convert this to logger once the parser is working reliably
cout << "Adding subnet " << addr.toText() << "/" << (int)len
<< " with params t1=" << t1 << ", t2=" << t2 << ", pref="
<< pref << ", valid=" << valid << endl;
......@@ -471,13 +468,18 @@ Dhcp6ConfigParser* createGlobalDhcp6ConfigParser(const std::string& config_id) {
return (f->second(config_id));
}
void
ConstElementPtr
configureDhcp6Server(Dhcpv6Srv& server, ConstElementPtr config_set) {
if (!config_set) {
isc_throw(Dhcp6ConfigError,
"Null pointer is passed to configuration parser");
}
/// @todo: append most essential info here (like "2 new subnets configured")
string config_details;
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_START).arg(config_set->str());
ParserCollection parsers;
try {
BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
......@@ -501,6 +503,11 @@ configureDhcp6Server(Dhcpv6Srv& server, ConstElementPtr config_set) {
isc_throw(Dhcp6ConfigError, "Unrecoverable error: "
"a configuration parser threw in commit");
}
LOG_INFO(dhcp6_logger, DHCP6_CONFIG_COMPLETE).arg(config_details);
ConstElementPtr answer = isc::config::createAnswer(0, "Configuration commited.");
return (answer);
}
}; // end of isc::dhcp namespace
......
......@@ -128,8 +128,9 @@ public:
///
/// \param server The \c Dhcpv6Srv object to be configured.
/// \param config_set A JSON style configuration to apply to \c server.
void configureDhcp6Server(Dhcpv6Srv& server,
isc::data::ConstElementPtr config_set);
isc::data::ConstElementPtr
configureDhcp6Server(Dhcpv6Srv& server,
isc::data::ConstElementPtr config_set);
/// Create a new \c Dhcp6ConfigParser object for a given configuration
......
......@@ -49,14 +49,13 @@ ControlledDhcpv6Srv::dhcp6ConfigHandler(ConstElementPtr new_config) {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_UPDATE)
.arg(new_config->str());
/// @todo: commented out as server is not able to understand partial
/// configuration (only the diff and not the whole configuration)
/* if (server_) {
configureDhcp6Server(*server_, new_config);
} */
ConstElementPtr answer = isc::config::createAnswer(0,
"Thank you for sending config.");
if (server_) {
return (configureDhcp6Server(*server_, new_config));
}
// that should never happen as we install config_handler after we
ConstElementPtr answer = isc::config::createAnswer(1,
"Configuration rejected, server is during startup/shutdown phase.");
return (answer);
}
......@@ -94,7 +93,7 @@ void ControlledDhcpv6Srv::sessionReader(void) {
}
void ControlledDhcpv6Srv::establishSession() {
string specfile;
if (getenv("B10_FROM_BUILD")) {
specfile = string(getenv("B10_FROM_BUILD")) +
......@@ -104,15 +103,21 @@ void ControlledDhcpv6Srv::establishSession() {
}
/// @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());
config_session_ = new ModuleCCSession(specfile, *cc_session_,
dhcp6ConfigHandler,
NULL,
dhcp6CommandHandler, false);
config_session_->start();
// We initially create ModuleCCSession() without configHandler, as
// the session module is too eager to send partial configuration.
// We want to get the full configuration, so we explicitly call
// getFullConfig() and then pass it to our configHandler.
config_session_->setConfigHandler(dhcp6ConfigHandler);
try {
configureDhcp6Server(*this, config_session_->getFullConfig());
} catch (const Dhcp6ConfigError& ex) {
......
......@@ -105,3 +105,14 @@ This critical error message indicates that the initial DHCPv6
configuration has failed. The server will continue to run, but
administrator's intervention is required. The server's configuration
must be fixed before it can become usable.
% DHCP6_CONFIG_START DHCPv6 server is processing the following configuration: %1
This is a debug message that is issued every time the server receives
configuration. That happens during every start up and also when server
configuration change is committed by the administrator.
% DHCP6_CONFIG_COMPLETE DHCPv6 server has completed configuration: %1
This is an informational message that announces successful processing
of a new configuration. That may happen as a result of one of two
events: server startup or commit of configuration change, done by the
administrator. Additional information may be provided.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment