namespace isc {
namespace dhcp {
-
ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL;
+ ConstElementPtr
+ ControlledDhcpv6Srv::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
ControlledDhcpv6Srv::dhcp6ConfigHandler(ConstElementPtr new_config) {
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_UPDATE)
- .arg(new_config->str());
- if (server_) {
- return (configureDhcp6Server(*server_, new_config));
+ if (!server_ || !server_->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);
}
- // 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 = server_->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 (configureDhcp6Server(*server_, merged_config));
}
ConstElementPtr