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);