36 struct CtrlDhcp6Hooks {
37 int hooks_index_dhcp6_srv_configured_;
41 hooks_index_dhcp6_srv_configured_ = HooksManager::registerHook(
"dhcp6_srv_configured");
53 static const char* SERVER_DUID_FILE =
"kea-dhcp6-serverid";
64 void signalHandler(
int signo) {
66 if (signo == SIGHUP) {
67 ControlledDhcpv6Srv::processCommand(
"config-reload",
69 }
else if ((signo == SIGTERM) || (signo == SIGINT)) {
70 ControlledDhcpv6Srv::processCommand(
"shutdown",
93 ControlledDhcpv6Srv::loadConfigFile(
const std::string& file_name) {
104 if (file_name.empty()) {
107 "use -c command line option.");
112 json = parser.
parseFile(file_name, Parser6Context::PARSER_DHCP6);
121 "a map, i.e., start with { and end with } and contain " 122 "at least an entry called 'Dhcp6' that itself is a map. " 124 <<
" is a valid JSON, but its top element is not a map." 125 " Did you forget to add { } around your configuration?");
129 result = ControlledDhcpv6Srv::processCommand(
"config-set", json);
135 "processCommand(\"config-set\", json)");
144 string reason = comment ? comment->stringValue() :
145 "no details available";
148 }
catch (
const std::exception& ex) {
151 CfgMgr::instance().rollback();
154 .arg(file_name).arg(ex.what());
156 << file_name <<
"': " << ex.
what());
164 ControlledDhcpv6Srv::init(
const std::string& file_name) {
170 string reason = comment ? comment->stringValue() :
171 "no details available";
184 signal_handler_ = signalHandler;
187 void ControlledDhcpv6Srv::cleanup() {
193 ControlledDhcpv6Srv::commandShutdownHandler(
const string&,
ConstElementPtr) {
194 if (ControlledDhcpv6Srv::server_) {
195 ControlledDhcpv6Srv::server_->
shutdown();
206 ControlledDhcpv6Srv::commandLibReloadHandler(
const string&,
ConstElementPtr) {
210 bool status = HooksManager::loadLibraries(loaded);
214 "Failed to reload hooks libraries.");
218 "Hooks libraries successfully reloaded.");
223 ControlledDhcpv6Srv::commandConfigReloadHandler(
const string&,
226 std::string file = ControlledDhcpv6Srv::getInstance()->getConfigFile();
229 return (loadConfigFile(file));
230 }
catch (
const std::exception& ex) {
237 "Config reload failed:" +
string(ex.what())));
242 ControlledDhcpv6Srv::commandConfigGetHandler(
const string&,
244 ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
250 ControlledDhcpv6Srv::commandConfigWriteHandler(
const string&,
ConstElementPtr args) {
254 if (args->getType() != Element::map) {
258 if (filename_param) {
259 if (filename_param->getType() != Element::string) {
261 "passed parameter 'filename' is not a string"));
263 filename = filename_param->stringValue();
267 if (filename.empty()) {
270 filename = getConfigFile();
273 if (filename.empty()) {
275 "Please specify filename explicitly."));
282 size = writeConfigFile(filename, cfg);
294 params->set(
"size", Element::create(static_cast<long long>(size)));
295 params->set(
"filename", Element::create(filename));
298 + filename +
" successful", params));
302 ControlledDhcpv6Srv::commandConfigSetHandler(
const string&,
313 message =
"Missing mandatory 'arguments' parameter.";
315 dhcp6 = args->get(
"Dhcp6");
317 message =
"Missing mandatory 'Dhcp6' parameter.";
318 }
else if (dhcp6->getType() != Element::map) {
319 message =
"'Dhcp6' parameter expected to be a map.";
323 if (!message.empty()) {
333 CfgMgr::instance().rollback();
341 Daemon::configureLogger(args->get(
"Logging"),
342 CfgMgr::instance().getStagingCfg());
346 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
357 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
360 CfgMgr::instance().commit();
365 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
372 ControlledDhcpv6Srv::commandConfigTestHandler(
const string&,
383 message =
"Missing mandatory 'arguments' parameter.";
385 dhcp6 = args->get(
"Dhcp6");
387 message =
"Missing mandatory 'Dhcp6' parameter.";
388 }
else if (dhcp6->getType() != Element::map) {
389 message =
"'Dhcp6' parameter expected to be a map.";
393 if (!message.empty()) {
403 CfgMgr::instance().rollback();
406 return (checkConfig(dhcp6));
410 ControlledDhcpv6Srv::commandDhcpDisableHandler(
const std::string&,
412 std::ostringstream message;
413 int64_t max_period = 0;
418 if (args->getType() != Element::map) {
419 message <<
"arguments for the 'dhcp-disable' command must be a map";
424 if (max_period_element) {
426 if (max_period_element->getType() != Element::integer) {
427 message <<
"'max-period' argument must be a number";
431 max_period = max_period_element->intValue();
432 if (max_period <= 0) {
433 message <<
"'max-period' must be positive integer";
439 network_state_->delayedEnableAll(static_cast<unsigned>(max_period));
446 if (message.tellp() == 0) {
447 network_state_->disableService();
449 message <<
"DHCPv6 service disabled";
450 if (max_period > 0) {
451 message <<
" for " << max_period <<
" seconds";
462 ControlledDhcpv6Srv::commandDhcpEnableHandler(
const std::string&,
ConstElementPtr) {
463 network_state_->enableService();
468 ControlledDhcpv6Srv::commandVersionGetHandler(
const string&,
ConstElementPtr) {
469 ElementPtr extended = Element::create(Dhcpv6Srv::getVersion(
true));
471 arguments->set(
"extended", extended);
473 Dhcpv6Srv::getVersion(
false),
479 ControlledDhcpv6Srv::commandBuildReportHandler(
const string&,
ConstElementPtr) {
486 ControlledDhcpv6Srv::commandLeasesReclaimHandler(
const string&,
493 message =
"Missing mandatory 'remove' parameter.";
497 message =
"Missing mandatory 'remove' parameter.";
498 }
else if (remove_name->getType() != Element::boolean) {
499 message =
"'remove' parameter expected to be a boolean.";
501 bool remove_lease = remove_name->boolValue();
502 server_->alloc_engine_->reclaimExpiredLeases6(0, 0, remove_lease);
504 message =
"Reclamation of expired leases is complete.";
512 ControlledDhcpv6Srv::processCommand(
const std::string& command,
514 string txt = args ? args->str() :
"(none)";
517 .arg(command).arg(txt);
523 "Server object not initialized, can't process command '" +
524 command +
"', arguments: '" + txt +
"'.");
529 if (command ==
"shutdown") {
530 return (srv->commandShutdownHandler(command, args));
532 }
else if (command ==
"libreload") {
533 return (srv->commandLibReloadHandler(command, args));
535 }
else if (command ==
"config-reload") {
536 return (srv->commandConfigReloadHandler(command, args));
538 }
else if (command ==
"config-set") {
539 return (srv->commandConfigSetHandler(command, args));
541 }
else if (command ==
"config-get") {
542 return (srv->commandConfigGetHandler(command, args));
544 }
else if (command ==
"config-test") {
545 return (srv->commandConfigTestHandler(command, args));
547 }
else if (command ==
"dhcp-disable") {
548 return (srv->commandDhcpDisableHandler(command, args));
550 }
else if (command ==
"dhcp-enable") {
551 return (srv->commandDhcpEnableHandler(command, args));
553 }
else if (command ==
"version-get") {
554 return (srv->commandVersionGetHandler(command, args));
556 }
else if (command ==
"build-report") {
557 return (srv->commandBuildReportHandler(command, args));
559 }
else if (command ==
"leases-reclaim") {
560 return (srv->commandLeasesReclaimHandler(command, args));
562 }
else if (command ==
"config-write") {
563 return (srv->commandConfigWriteHandler(command, args));
572 + command +
"':" + ex.
what()));
587 "Server object not initialized, can't process config.");
601 }
catch (
const std::exception& ex) {
603 +
string(ex.what())));
608 DatabaseConnection::db_lost_callback =
609 boost::bind(&ControlledDhcpv6Srv::dbLostCallback, srv, _1);
610 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
611 cfg_db->setAppendedParameters(
"universe=6");
612 cfg_db->createManagers();
613 }
catch (
const std::exception& ex) {
615 + std::string(ex.what())));
620 const std::string duid_file = CfgMgr::instance().getDataDir() +
"/" +
621 std::string(SERVER_DUID_FILE);
622 DuidPtr duid = CfgMgr::instance().getStagingCfg()->getCfgDUID()->create(duid_file);
630 }
catch (
const std::exception& ex) {
631 std::ostringstream err;
632 err <<
"unable to configure server identifier: " << ex.what();
639 }
catch (
const std::exception& ex) {
640 std::ostringstream err;
641 err <<
"error starting DHCP_DDNS client " 642 " after server reconfiguration: " << ex.what();
648 Dhcp6to4Ipc::instance().open();
649 }
catch (
const std::exception& ex) {
650 std::ostringstream err;
651 err <<
"error starting DHCPv4-over-DHCPv6 IPC " 652 " after server reconfiguration: " << ex.what();
659 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
660 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, qc)) {
662 .arg(IfaceMgr::instance().getPacketQueue6()->getInfoStr());
665 }
catch (
const std::exception& ex) {
666 std::ostringstream err;
667 err <<
"Error setting packet queue controls after server reconfiguration: " 679 CfgMgr::instance().getStagingCfg()->getCfgIface()->openSockets(AF_INET6, srv->
getPort());
683 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
684 setupTimers(&ControlledDhcpv6Srv::reclaimExpiredLeases,
685 &ControlledDhcpv6Srv::deleteExpiredReclaimedLeases,
688 }
catch (
const std::exception& ex) {
689 std::ostringstream err;
690 err <<
"unable to setup timers for periodically running the" 691 " reclamation of the expired leases: " 698 LibDHCP::commitRuntimeOptionDefs();
705 if (HooksManager::calloutsPresent(
Hooks.hooks_index_dhcp6_srv_configured_)) {
708 callout_handle->setArgument(
"io_context", srv->
getIOService());
710 callout_handle->setArgument(
"json_config", config);
711 callout_handle->setArgument(
"server_config", CfgMgr::instance().getStagingCfg());
713 HooksManager::callCallouts(
Hooks.hooks_index_dhcp6_srv_configured_,
733 "Server object not initialized, can't process config.");
740 ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port)
744 "There is another Dhcpv6Srv instance already.");
756 CommandMgr::instance().registerCommand(
"build-report",
757 boost::bind(&ControlledDhcpv6Srv::commandBuildReportHandler,
this, _1, _2));
759 CommandMgr::instance().registerCommand(
"config-get",
760 boost::bind(&ControlledDhcpv6Srv::commandConfigGetHandler,
this, _1, _2));
762 CommandMgr::instance().registerCommand(
"config-reload",
763 boost::bind(&ControlledDhcpv6Srv::commandConfigReloadHandler,
this, _1, _2));
765 CommandMgr::instance().registerCommand(
"config-test",
766 boost::bind(&ControlledDhcpv6Srv::commandConfigTestHandler,
this, _1, _2));
768 CommandMgr::instance().registerCommand(
"config-write",
769 boost::bind(&ControlledDhcpv6Srv::commandConfigWriteHandler,
this, _1, _2));
771 CommandMgr::instance().registerCommand(
"dhcp-disable",
772 boost::bind(&ControlledDhcpv6Srv::commandDhcpDisableHandler,
this, _1, _2));
774 CommandMgr::instance().registerCommand(
"dhcp-enable",
775 boost::bind(&ControlledDhcpv6Srv::commandDhcpEnableHandler,
this, _1, _2));
777 CommandMgr::instance().registerCommand(
"leases-reclaim",
778 boost::bind(&ControlledDhcpv6Srv::commandLeasesReclaimHandler,
this, _1, _2));
780 CommandMgr::instance().registerCommand(
"libreload",
781 boost::bind(&ControlledDhcpv6Srv::commandLibReloadHandler,
this, _1, _2));
783 CommandMgr::instance().registerCommand(
"config-set",
784 boost::bind(&ControlledDhcpv6Srv::commandConfigSetHandler,
this, _1, _2));
786 CommandMgr::instance().registerCommand(
"shutdown",
787 boost::bind(&ControlledDhcpv6Srv::commandShutdownHandler,
this, _1, _2));
789 CommandMgr::instance().registerCommand(
"version-get",
790 boost::bind(&ControlledDhcpv6Srv::commandVersionGetHandler,
this, _1, _2));
793 CommandMgr::instance().registerCommand(
"statistic-get",
794 boost::bind(&StatsMgr::statisticGetHandler, _1, _2));
796 CommandMgr::instance().registerCommand(
"statistic-get-all",
797 boost::bind(&StatsMgr::statisticGetAllHandler, _1, _2));
799 CommandMgr::instance().registerCommand(
"statistic-reset",
800 boost::bind(&StatsMgr::statisticResetHandler, _1, _2));
802 CommandMgr::instance().registerCommand(
"statistic-reset-all",
803 boost::bind(&StatsMgr::statisticResetAllHandler, _1, _2));
805 CommandMgr::instance().registerCommand(
"statistic-remove",
806 boost::bind(&StatsMgr::statisticRemoveHandler, _1, _2));
808 CommandMgr::instance().registerCommand(
"statistic-remove-all",
809 boost::bind(&StatsMgr::statisticRemoveAllHandler, _1, _2));
823 DatabaseConnection::db_lost_callback = 0;
825 timer_mgr_->unregisterTimers();
828 CommandMgr::instance().closeCommandSocket();
831 CommandMgr::instance().deregisterCommand(
"build-report");
832 CommandMgr::instance().deregisterCommand(
"config-get");
833 CommandMgr::instance().deregisterCommand(
"config-set");
834 CommandMgr::instance().deregisterCommand(
"config-reload");
835 CommandMgr::instance().deregisterCommand(
"config-test");
836 CommandMgr::instance().deregisterCommand(
"config-write");
837 CommandMgr::instance().deregisterCommand(
"dhcp-disable");
838 CommandMgr::instance().deregisterCommand(
"dhcp-enable");
839 CommandMgr::instance().deregisterCommand(
"leases-reclaim");
840 CommandMgr::instance().deregisterCommand(
"libreload");
841 CommandMgr::instance().deregisterCommand(
"shutdown");
842 CommandMgr::instance().deregisterCommand(
"statistic-get");
843 CommandMgr::instance().deregisterCommand(
"statistic-get-all");
844 CommandMgr::instance().deregisterCommand(
"statistic-remove");
845 CommandMgr::instance().deregisterCommand(
"statistic-remove-all");
846 CommandMgr::instance().deregisterCommand(
"statistic-reset");
847 CommandMgr::instance().deregisterCommand(
"statistic-reset-all");
848 CommandMgr::instance().deregisterCommand(
"version-get");
860 void ControlledDhcpv6Srv::sessionReader(
void) {
864 server_->io_service_.
run_one();
869 ControlledDhcpv6Srv::reclaimExpiredLeases(
const size_t max_leases,
870 const uint16_t timeout,
871 const bool remove_lease,
872 const uint16_t max_unwarned_cycles) {
873 server_->
alloc_engine_->reclaimExpiredLeases6(max_leases, timeout,
875 max_unwarned_cycles);
881 ControlledDhcpv6Srv::deleteExpiredReclaimedLeases(
const uint32_t secs) {
889 bool reopened =
false;
894 cfg_db->createManagers();
896 }
catch (
const std::exception& ex) {
909 db_reconnect_ctl.reset();
911 if (!db_reconnect_ctl->checkRetries()) {
913 .arg(db_reconnect_ctl->maxRetries());
919 .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
920 .arg(db_reconnect_ctl->maxRetries())
921 .arg(db_reconnect_ctl->retryInterval());
925 boost::bind(&ControlledDhcpv6Srv::dbReconnect,
this,
927 db_reconnect_ctl->retryInterval(),
936 ControlledDhcpv6Srv::dbLostCallback(
ReconnectCtlPtr db_reconnect_ctl) {
940 if (!db_reconnect_ctl) {
947 if (!db_reconnect_ctl->retriesLeft() ||
948 !db_reconnect_ctl->retryInterval()) {
950 .arg(db_reconnect_ctl->retriesLeft())
951 .arg(db_reconnect_ctl->retryInterval());
956 dbReconnect(db_reconnect_ctl);
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
boost::shared_ptr< DUID > DuidPtr
virtual ~ControlledDhcpv6Srv()
Destructor.
isc::data::ConstElementPtr configureDhcp6Server(Dhcpv6Srv &server, isc::data::ConstElementPtr config_set, bool check_only)
Configures DHCPv6 server.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
isc::data::ElementPtr parseFile(const std::string &filename, ParserType parser_type)
Run the parser on the file specified.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Manages a pool of asynchronous interval timers.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
boost::shared_ptr< Element > ElementPtr
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Evaluation context, an interface to the expression evaluation.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
std::vector< HookLibInfo > HookLibsCollection
A storage for information about hook libraries.
NetworkStatePtr & getNetworkState()
Returns pointer to the network state used by the server.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
static const std::string FLUSH_RECLAIMED_TIMER_NAME
Name of the timer for flushing reclaimed leases.
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
const int DBG_DHCP6_COMMAND
Debug level used to log receiving commands.
void shutdown()
Initiates shutdown procedure for the whole DHCPv6 server.
void shutdown()
Instructs the server to shut down.
void stop()
Stop the underlying event loop.
boost::shared_ptr< const Element > ConstElementPtr
Defines the Dhcp6to4Ipc class.
NetworkStatePtr network_state_
Holds information about disabled DHCP service and/or disabled subnet/network scopes.
Represents a collection of signals handled in a customized way.
void run_one()
Run the underlying event loop for a single event.
This is a base class for exceptions thrown from the DNS library module.
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Defines the logger used by the top-level component of kea-dhcp-ddns.
isc::log::Logger logger("asiodns")
Use the ASIO logger.
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
static const std::string RECLAIM_EXPIRED_TIMER_NAME
Name of the timer for reclaiming expired leases.
This file contains several functions and constants that are used for handling commands and responses ...
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
A generic exception that is thrown if a function is called in a prohibited way.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
void cleanup()
Performs cleanup, immediately before termination.
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
std::string getConfigReport()
Controlled version of the DHCPv6 server.
uint16_t getPort() const
Get UDP port on which server should listen.
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
isc::log::Logger dhcp6_logger(DHCP6_APP_LOGGER_NAME)
Base logger for DHCPv6 server.