Kea 2.5.8
ctrl_dhcp6_srv.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
12#include <cc/data.h>
13#include <config/command_mgr.h>
15#include <dhcp/libdhcp++.h>
17#include <dhcp6/dhcp6_log.h>
18#include <dhcp6/dhcp6to4_ipc.h>
23#include <dhcpsrv/cfgmgr.h>
24#include <dhcpsrv/db_type.h>
25#include <dhcpsrv/host_mgr.h>
27#include <hooks/hooks.h>
28#include <hooks/hooks_manager.h>
30#include <stats/stats_mgr.h>
31#include <util/encode/encode.h>
33
34#include <signal.h>
35
36#include <sstream>
37
38using namespace isc::asiolink;
39using namespace isc::config;
40using namespace isc::data;
41using namespace isc::db;
42using namespace isc::dhcp;
43using namespace isc::hooks;
44using namespace isc::stats;
45using namespace isc::util;
46using namespace std;
47namespace ph = std::placeholders;
48
49namespace {
50
52struct CtrlDhcp6Hooks {
53 int hooks_index_dhcp6_srv_configured_;
54
56 CtrlDhcp6Hooks() {
57 hooks_index_dhcp6_srv_configured_ = HooksManager::registerHook("dhcp6_srv_configured");
58 }
59
60};
61
62// Declare a Hooks object. As this is outside any function or method, it
63// will be instantiated (and the constructor run) when the module is loaded.
64// As a result, the hook indexes will be defined before any method in this
65// module is called.
66CtrlDhcp6Hooks Hooks;
67
68// Name of the file holding server identifier.
69static const char* SERVER_DUID_FILE = "kea-dhcp6-serverid";
70
80void signalHandler(int signo) {
81 // SIGHUP signals a request to reconfigure the server.
82 if (signo == SIGHUP) {
85 } else if ((signo == SIGTERM) || (signo == SIGINT)) {
88 }
89}
90
91}
92
93namespace isc {
94namespace dhcp {
95
96ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL;
97
98void
99ControlledDhcpv6Srv::init(const std::string& file_name) {
100 // Keep the call timestamp.
101 start_ = boost::posix_time::second_clock::universal_time();
102
103 // Configure the server using JSON file.
104 ConstElementPtr result = loadConfigFile(file_name);
105
106 int rcode;
107 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
108 if (rcode != CONTROL_RESULT_SUCCESS) {
109 string reason = comment ? comment->stringValue() :
110 "no details available";
111 isc_throw(isc::BadValue, reason);
112 }
113
114 // We don't need to call openActiveSockets() or startD2() as these
115 // methods are called in processConfig() which is called by
116 // processCommand("config-set", ...)
117
118 // Set signal handlers. When the SIGHUP is received by the process
119 // the server reconfiguration will be triggered. When SIGTERM or
120 // SIGINT will be received, the server will start shutting down.
121 signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
122
123 signal_set_->add(SIGINT);
124 signal_set_->add(SIGHUP);
125 signal_set_->add(SIGTERM);
126}
127
129 signal_set_.reset();
130 getIOService()->poll();
131}
132
134ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
135 // This is a configuration backend implementation that reads the
136 // configuration from a JSON file.
137
140
141 // Basic sanity check: file name must not be empty.
142 try {
143 if (file_name.empty()) {
144 // Basic sanity check: file name must not be empty.
145 isc_throw(isc::BadValue, "JSON configuration file not specified."
146 " Please use -c command line option.");
147 }
148
149 // Read contents of the file and parse it as JSON
150 Parser6Context parser;
151 json = parser.parseFile(file_name, Parser6Context::PARSER_DHCP6);
152 if (!json) {
153 isc_throw(isc::BadValue, "no configuration found");
154 }
155
156 // Let's do sanity check before we call json->get() which
157 // works only for map.
158 if (json->getType() != isc::data::Element::map) {
159 isc_throw(isc::BadValue, "Configuration file is expected to be "
160 "a map, i.e., start with { and end with } and contain "
161 "at least an entry called 'Dhcp6' that itself is a map. "
162 << file_name
163 << " is a valid JSON, but its top element is not a map."
164 " Did you forget to add { } around your configuration?");
165 }
166
167 // Use parsed JSON structures to configure the server
168 result = ControlledDhcpv6Srv::processCommand("config-set", json);
169 if (!result) {
170 // Undetermined status of the configuration. This should never
171 // happen, but as the configureDhcp6Server returns a pointer, it is
172 // theoretically possible that it will return NULL.
173 isc_throw(isc::BadValue, "undefined result of "
174 "processCommand(\"config-set\", json)");
175 }
176
177 // Now check is the returned result is successful (rcode=0) or not
178 // (see @ref isc::config::parseAnswer).
179 int rcode;
180 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
181 if (rcode != CONTROL_RESULT_SUCCESS) {
182 string reason = comment ? comment->stringValue() :
183 "no details available";
184 isc_throw(isc::BadValue, reason);
185 }
186 } catch (const std::exception& ex) {
187 // If configuration failed at any stage, we drop the staging
188 // configuration and continue to use the previous one.
190
192 .arg(file_name).arg(ex.what());
193 isc_throw(isc::BadValue, "configuration error using file '"
194 << file_name << "': " << ex.what());
195 }
196
198 .arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
199 .arg(MultiThreadingMgr::instance().getThreadPoolSize())
200 .arg(MultiThreadingMgr::instance().getPacketQueueSize());
201
202 return (result);
203}
204
206ControlledDhcpv6Srv::commandShutdownHandler(const string&, ConstElementPtr args) {
209 return (createAnswer(CONTROL_RESULT_ERROR, "Shutdown failure."));
210 }
211
212 int exit_value = 0;
213 if (args) {
214 // @todo Should we go ahead and shutdown even if the args are invalid?
215 if (args->getType() != Element::map) {
216 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
217 }
218
219 ConstElementPtr param = args->get("exit-value");
220 if (param) {
221 if (param->getType() != Element::integer) {
223 "parameter 'exit-value' is not an integer"));
224 }
225
226 exit_value = param->intValue();
227 }
228 }
229
231 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
232}
233
235ControlledDhcpv6Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
236 LOG_WARN(dhcp6_logger, DHCP6_DEPRECATED).arg("libreload command");
237
238 // stop thread pool (if running)
240
241 // Clear the packet queue.
243
244 try {
248 static_cast<void>(HooksManager::unloadLibraries());
250 bool multi_threading_enabled = true;
251 uint32_t thread_count = 0;
252 uint32_t queue_size = 0;
253 CfgMultiThreading::extract(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading(),
254 multi_threading_enabled, thread_count, queue_size);
255 bool status = HooksManager::loadLibraries(loaded, multi_threading_enabled);
256 if (!status) {
257 isc_throw(Unexpected, "Failed to reload hooks libraries "
258 "(WARNING: libreload is deprecated).");
259 }
260 } catch (const std::exception& ex) {
263 return (answer);
264 }
266 "Hooks libraries successfully reloaded "
267 "(WARNING: libreload is deprecated).");
268 return (answer);
269}
270
272ControlledDhcpv6Srv::commandConfigReloadHandler(const string&,
273 ConstElementPtr /*args*/) {
274 // Get configuration file name.
276 try {
278 auto result = loadConfigFile(file);
280 return (result);
281 } catch (const std::exception& ex) {
282 // Log the unsuccessful reconfiguration. The reason for failure
283 // should be already logged. Don't rethrow an exception so as
284 // the server keeps working.
286 .arg(file);
288 "Config reload failed: " + string(ex.what())));
289 }
290}
291
293ControlledDhcpv6Srv::commandConfigGetHandler(const string&,
294 ConstElementPtr /*args*/) {
295 ElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
296 string hash = BaseCommandMgr::getHash(config);
297 config->set("hash", Element::create(hash));
298
299 return (createAnswer(CONTROL_RESULT_SUCCESS, config));
300}
301
303ControlledDhcpv6Srv::commandConfigHashGetHandler(const string&,
304 ConstElementPtr /*args*/) {
305 ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
306 string hash = BaseCommandMgr::getHash(config);
307
309 params->set("hash", Element::create(hash));
310 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
311}
312
314ControlledDhcpv6Srv::commandConfigWriteHandler(const string&,
315 ConstElementPtr args) {
316 string filename;
317
318 if (args) {
319 if (args->getType() != Element::map) {
320 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
321 }
322 ConstElementPtr filename_param = args->get("filename");
323 if (filename_param) {
324 if (filename_param->getType() != Element::string) {
326 "passed parameter 'filename' is not a string"));
327 }
328 filename = filename_param->stringValue();
329 }
330 }
331
332 if (filename.empty()) {
333 // filename parameter was not specified, so let's use whatever we remember
334 // from the command-line
335 filename = getConfigFile();
336 }
337
338 if (filename.empty()) {
339 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
340 "Please specify filename explicitly."));
341 }
342
343 // Ok, it's time to write the file.
344 size_t size = 0;
345 try {
346 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
347 size = writeConfigFile(filename, cfg);
348 } catch (const isc::Exception& ex) {
349 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during write-config: ")
350 + ex.what()));
351 }
352 if (size == 0) {
353 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
354 + filename));
355 }
356
357 // Ok, it's time to return the successful response.
359 params->set("size", Element::create(static_cast<long long>(size)));
360 params->set("filename", Element::create(filename));
361
362 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
363 + filename + " successful", params));
364}
365
367ControlledDhcpv6Srv::commandConfigSetHandler(const string&,
368 ConstElementPtr args) {
369 const int status_code = CONTROL_RESULT_ERROR;
370 ConstElementPtr dhcp6;
371 string message;
372
373 // Command arguments are expected to be:
374 // { "Dhcp6": { ... } }
375 if (!args) {
376 message = "Missing mandatory 'arguments' parameter.";
377 } else {
378 dhcp6 = args->get("Dhcp6");
379 if (!dhcp6) {
380 message = "Missing mandatory 'Dhcp6' parameter.";
381 } else if (dhcp6->getType() != Element::map) {
382 message = "'Dhcp6' parameter expected to be a map.";
383 }
384 }
385
386 // Check unsupported objects.
387 if (message.empty()) {
388 for (auto const& obj : args->mapValue()) {
389 const string& obj_name = obj.first;
390 if (obj_name != "Dhcp6") {
392 .arg(obj_name);
393 if (message.empty()) {
394 message = "Unsupported '" + obj_name + "' parameter";
395 } else {
396 message += " (and '" + obj_name + "')";
397 }
398 }
399 }
400 if (!message.empty()) {
401 message += ".";
402 }
403 }
404
405 if (!message.empty()) {
406 // Something is amiss with arguments, return a failure response.
407 ConstElementPtr result = isc::config::createAnswer(status_code,
408 message);
409 return (result);
410 }
411
412 // stop thread pool (if running)
414
415 // We are starting the configuration process so we should remove any
416 // staging configuration that has been created during previous
417 // configuration attempts.
419
420 // Parse the logger configuration explicitly into the staging config.
421 // Note this does not alter the current loggers, they remain in
422 // effect until we apply the logging config below. If no logging
423 // is supplied logging will revert to default logging.
424 Daemon::configureLogger(dhcp6, CfgMgr::instance().getStagingCfg());
425
426 // Let's apply the new logging. We do it early, so we'll be able to print
427 // out what exactly is wrong with the new config in case of problems.
428 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
429
430 // Now we configure the server proper.
431 ConstElementPtr result = processConfig(dhcp6);
432
433 // If the configuration parsed successfully, apply the new logger
434 // configuration and the commit the new configuration. We apply
435 // the logging first in case there's a configuration failure.
436 int rcode = 0;
437 isc::config::parseAnswer(rcode, result);
438 if (rcode == CONTROL_RESULT_SUCCESS) {
439 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
440
441 // Use new configuration.
443 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
444 // Ok, we applied the logging from the upcoming configuration, but
445 // there were problems with the config. As such, we need to back off
446 // and revert to the previous logging configuration. This is not done if
447 // sequence == 0, because that would mean always reverting to stdout by
448 // default, and it is arguably more helpful to have the error in a
449 // potential file or syslog configured in the upcoming configuration.
450 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
451
452 // Not initial configuration so someone can believe we reverted
453 // to the previous configuration. It is not the case so be clear
454 // about this.
456 }
457
459 try {
460 // Handle events registered by hooks using external IOService objects.
462 } catch (const std::exception& ex) {
463 std::ostringstream err;
464 err << "Error initializing hooks: "
465 << ex.what();
467 }
468
469 return (result);
470}
471
473ControlledDhcpv6Srv::commandConfigTestHandler(const string&,
474 ConstElementPtr args) {
475 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
476 ConstElementPtr dhcp6;
477 string message;
478
479 // Command arguments are expected to be:
480 // { "Dhcp6": { ... } }
481 if (!args) {
482 message = "Missing mandatory 'arguments' parameter.";
483 } else {
484 dhcp6 = args->get("Dhcp6");
485 if (!dhcp6) {
486 message = "Missing mandatory 'Dhcp6' parameter.";
487 } else if (dhcp6->getType() != Element::map) {
488 message = "'Dhcp6' parameter expected to be a map.";
489 }
490 }
491
492 // Check unsupported objects.
493 if (message.empty()) {
494 for (auto const& obj : args->mapValue()) {
495 const string& obj_name = obj.first;
496 if (obj_name != "Dhcp6") {
498 .arg(obj_name);
499 if (message.empty()) {
500 message = "Unsupported '" + obj_name + "' parameter";
501 } else {
502 message += " (and '" + obj_name + "')";
503 }
504 }
505 }
506 if (!message.empty()) {
507 message += ".";
508 }
509 }
510
511 if (!message.empty()) {
512 // Something is amiss with arguments, return a failure response.
513 ConstElementPtr result = isc::config::createAnswer(status_code,
514 message);
515 return (result);
516 }
517
518 // stop thread pool (if running)
520
521 // We are starting the configuration process so we should remove any
522 // staging configuration that has been created during previous
523 // configuration attempts.
525
526 // Now we check the server proper.
527 return (checkConfig(dhcp6));
528}
529
531ControlledDhcpv6Srv::commandDhcpDisableHandler(const std::string&,
532 ConstElementPtr args) {
533 std::ostringstream message;
534 int64_t max_period = 0;
535 std::string origin;
536
537 // If the args map does not contain 'origin' parameter, the default type
538 // will be used (user command).
539 auto type = NetworkState::USER_COMMAND;
540
541 // Parse arguments to see if the 'max-period' or 'origin' parameters have
542 // been specified.
543 if (args) {
544 // Arguments must be a map.
545 if (args->getType() != Element::map) {
546 message << "arguments for the 'dhcp-disable' command must be a map";
547
548 } else {
549 ConstElementPtr max_period_element = args->get("max-period");
550 // max-period is optional.
551 if (max_period_element) {
552 // It must be an integer, if specified.
553 if (max_period_element->getType() != Element::integer) {
554 message << "'max-period' argument must be a number";
555
556 } else {
557 // It must be positive integer.
558 max_period = max_period_element->intValue();
559 if (max_period <= 0) {
560 message << "'max-period' must be positive integer";
561 }
562 }
563 }
564 ConstElementPtr origin_element = args->get("origin");
565 // The 'origin' parameter is optional.
566 if (origin_element) {
567 switch (origin_element->getType()) {
568 case Element::string:
569 origin = origin_element->stringValue();
570 if (origin == "ha-partner") {
572 } else if (origin != "user") {
573 if (origin.empty()) {
574 origin = "(empty string)";
575 }
576 message << "invalid value used for 'origin' parameter: "
577 << origin;
578 }
579 break;
580 case Element::integer:
581 type = origin_element->intValue();
582 break;
583 default:
584 // It must be a string or a number, if specified.
585 message << "'origin' argument must be a string or a number";
586 }
587 }
588 }
589 }
590
591 // No error occurred, so let's disable the service.
592 if (message.tellp() == 0) {
593 message << "DHCPv6 service disabled";
594 if (max_period > 0) {
595 message << " for " << max_period << " seconds";
596
597 // The user specified that the DHCP service should resume not
598 // later than in max-period seconds. If the 'dhcp-enable' command
599 // is not sent, the DHCP service will resume automatically.
600 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
601 type);
602 }
603 network_state_->disableService(type);
604
605 // Success.
606 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
607 }
608
609 // Failure.
610 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
611}
612
614ControlledDhcpv6Srv::commandDhcpEnableHandler(const std::string&,
615 ConstElementPtr args) {
616 std::ostringstream message;
617 std::string origin;
618
619 // If the args map does not contain 'origin' parameter, the default type
620 // will be used (user command).
621 auto type = NetworkState::USER_COMMAND;
622
623 // Parse arguments to see if the 'origin' parameter has been specified.
624 if (args) {
625 // Arguments must be a map.
626 if (args->getType() != Element::map) {
627 message << "arguments for the 'dhcp-enable' command must be a map";
628
629 } else {
630 ConstElementPtr origin_element = args->get("origin");
631 // The 'origin' parameter is optional.
632 if (origin_element) {
633 switch (origin_element->getType()) {
634 case Element::string:
635 origin = origin_element->stringValue();
636 if (origin == "ha-partner") {
638 } else if (origin != "user") {
639 if (origin.empty()) {
640 origin = "(empty string)";
641 }
642 message << "invalid value used for 'origin' parameter: "
643 << origin;
644 }
645 break;
646 case Element::integer:
647 type = origin_element->intValue();
648 break;
649 default:
650 // It must be a string or a number, if specified.
651 message << "'origin' argument must be a string or a number";
652 }
653 }
654 }
655 }
656
657 // No error occurred, so let's enable the service.
658 if (message.tellp() == 0) {
659 network_state_->enableService(type);
660
661 // Success.
663 "DHCP service successfully enabled"));
664 }
665
666 // Failure.
667 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
668}
669
671ControlledDhcpv6Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
673 ElementPtr arguments = Element::createMap();
674 arguments->set("extended", extended);
677 arguments);
678 return (answer);
679}
680
682ControlledDhcpv6Srv::commandBuildReportHandler(const string&,
684 ConstElementPtr answer =
686 return (answer);
687}
688
690ControlledDhcpv6Srv::commandLeasesReclaimHandler(const string&,
691 ConstElementPtr args) {
692 int status_code = CONTROL_RESULT_ERROR;
693 string message;
694
695 // args must be { "remove": <bool> }
696 if (!args) {
697 message = "Missing mandatory 'remove' parameter.";
698 } else {
699 ConstElementPtr remove_name = args->get("remove");
700 if (!remove_name) {
701 message = "Missing mandatory 'remove' parameter.";
702 } else if (remove_name->getType() != Element::boolean) {
703 message = "'remove' parameter expected to be a boolean.";
704 } else {
705 bool remove_lease = remove_name->boolValue();
706 server_->alloc_engine_->reclaimExpiredLeases6(0, 0, remove_lease);
707 status_code = 0;
708 message = "Reclamation of expired leases is complete.";
709 }
710 }
711 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
712 return (answer);
713}
714
716ControlledDhcpv6Srv::commandServerTagGetHandler(const std::string&,
718 const std::string& tag =
719 CfgMgr::instance().getCurrentCfg()->getServerTag();
720 ElementPtr response = Element::createMap();
721 response->set("server-tag", Element::create(tag));
722
723 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
724}
725
727ControlledDhcpv6Srv::commandConfigBackendPullHandler(const std::string&,
729 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
730 if (!ctl_info) {
731 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
732 }
733
734 // stop thread pool (if running)
736
737 // Reschedule the periodic CB fetch.
738 if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
739 TimerMgr::instance()->cancel("Dhcp6CBFetchTimer");
740 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
741 }
742
743 // Code from cbFetchUpdates.
744 // The configuration to use is the current one because this is called
745 // after the configuration manager commit.
746 try {
747 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
749 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
750 } catch (const std::exception& ex) {
752 .arg(ex.what());
754 "On demand configuration update failed: " +
755 string(ex.what())));
756 }
758 "On demand configuration update successful."));
759}
760
762ControlledDhcpv6Srv::commandStatusGetHandler(const string&,
763 ConstElementPtr /*args*/) {
765 status->set("pid", Element::create(static_cast<int>(getpid())));
766
767 auto now = boost::posix_time::second_clock::universal_time();
768 // Sanity check: start_ is always initialized.
769 if (!start_.is_not_a_date_time()) {
770 auto uptime = now - start_;
771 status->set("uptime", Element::create(uptime.total_seconds()));
772 }
773
774 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
775 if (!last_commit.is_not_a_date_time()) {
776 auto reload = now - last_commit;
777 status->set("reload", Element::create(reload.total_seconds()));
778 }
779
780 auto& mt_mgr = MultiThreadingMgr::instance();
781 if (mt_mgr.getMode()) {
782 status->set("multi-threading-enabled", Element::create(true));
783 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
784 MultiThreadingMgr::instance().getThreadPoolSize())));
785 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
786 MultiThreadingMgr::instance().getPacketQueueSize())));
787 ElementPtr queue_stats = Element::createList();
788 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
789 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
790 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
791 status->set("packet-queue-statistics", queue_stats);
792
793 } else {
794 status->set("multi-threading-enabled", Element::create(false));
795 }
796
797 status->set("extended-info-tables",
798 Element::create(LeaseMgrFactory::instance().getExtendedInfoTablesEnabled()));
799
800 // Iterate through the interfaces and get all the errors.
801 ElementPtr socket_errors(Element::createList());
802 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
803 for (std::string const& error : interface->getErrors()) {
804 socket_errors->add(Element::create(error));
805 }
806 }
807
808 // Abstract the information from all sockets into a single status.
810 if (socket_errors->empty()) {
811 sockets->set("status", Element::create("ready"));
812 } else {
813 ReconnectCtlPtr const reconnect_ctl(
814 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
815 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
816 sockets->set("status", Element::create("retrying"));
817 } else {
818 sockets->set("status", Element::create("failed"));
819 }
820 sockets->set("errors", socket_errors);
821 }
822 status->set("sockets", sockets);
823
824 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
825}
826
828ControlledDhcpv6Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
829 ConstElementPtr args) {
830 StatsMgr& stats_mgr = StatsMgr::instance();
832 // Update the default parameter.
833 long max_samples = stats_mgr.getMaxSampleCountDefault();
834 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
835 "statistic-default-sample-count", Element::create(max_samples));
836 return (answer);
837}
838
840ControlledDhcpv6Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
841 ConstElementPtr args) {
842 StatsMgr& stats_mgr = StatsMgr::instance();
844 // Update the default parameter.
845 auto duration = stats_mgr.getMaxSampleAgeDefault();
846 long max_age = toSeconds(duration);
847 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
848 "statistic-default-sample-age", Element::create(max_age));
849 return (answer);
850}
851
854 ConstElementPtr args) {
855 string txt = args ? args->str() : "(none)";
856
858 .arg(command).arg(txt);
859
861
862 if (!srv) {
864 "Server object not initialized, so can't process command '" +
865 command + "', arguments: '" + txt + "'.");
866 return (no_srv);
867 }
868
869 try {
870 if (command == "shutdown") {
871 return (srv->commandShutdownHandler(command, args));
872
873 } else if (command == "libreload") {
874 return (srv->commandLibReloadHandler(command, args));
875
876 } else if (command == "config-reload") {
877 return (srv->commandConfigReloadHandler(command, args));
878
879 } else if (command == "config-set") {
880 return (srv->commandConfigSetHandler(command, args));
881
882 } else if (command == "config-get") {
883 return (srv->commandConfigGetHandler(command, args));
884
885 } else if (command == "config-hash-get") {
886 return (srv->commandConfigHashGetHandler(command, args));
887
888 } else if (command == "config-test") {
889 return (srv->commandConfigTestHandler(command, args));
890
891 } else if (command == "dhcp-disable") {
892 return (srv->commandDhcpDisableHandler(command, args));
893
894 } else if (command == "dhcp-enable") {
895 return (srv->commandDhcpEnableHandler(command, args));
896
897 } else if (command == "version-get") {
898 return (srv->commandVersionGetHandler(command, args));
899
900 } else if (command == "build-report") {
901 return (srv->commandBuildReportHandler(command, args));
902
903 } else if (command == "leases-reclaim") {
904 return (srv->commandLeasesReclaimHandler(command, args));
905
906 } else if (command == "config-write") {
907 return (srv->commandConfigWriteHandler(command, args));
908
909 } else if (command == "server-tag-get") {
910 return (srv->commandServerTagGetHandler(command, args));
911
912 } else if (command == "config-backend-pull") {
913 return (srv->commandConfigBackendPullHandler(command, args));
914
915 } else if (command == "status-get") {
916 return (srv->commandStatusGetHandler(command, args));
917 }
918
919 return (isc::config::createAnswer(CONTROL_RESULT_ERROR, "Unrecognized command:"
920 + command));
921
922 } catch (const isc::Exception& ex) {
923 return (isc::config::createAnswer(CONTROL_RESULT_ERROR, "Error while processing command '"
924 + command + "': " + ex.what() +
925 ", params: '" + txt + "'"));
926 }
927}
928
932
933 // Allow DB reconnect on startup. The database connection parameters specify
934 // respective details.
936
937 // Single stream instance used in all error clauses
938 std::ostringstream err;
939
940 if (!srv) {
941 err << "Server object not initialized, can't process config.";
943 }
944
946 .arg(srv->redactConfig(config)->str());
947
948 ConstElementPtr answer = configureDhcp6Server(*srv, config);
949
950 // Check that configuration was successful. If not, do not reopen sockets
951 // and don't bother with DDNS stuff.
952 try {
953 int rcode = 0;
954 isc::config::parseAnswer(rcode, answer);
955 if (rcode != 0) {
956 return (answer);
957 }
958 } catch (const std::exception& ex) {
959 err << "Failed to process configuration:" << ex.what();
961 }
962
963 // Re-open lease and host database with new parameters.
964 try {
966 std::bind(&ControlledDhcpv6Srv::dbLostCallback, srv, ph::_1);
967
969 std::bind(&ControlledDhcpv6Srv::dbRecoveredCallback, srv, ph::_1);
970
972 std::bind(&ControlledDhcpv6Srv::dbFailedCallback, srv, ph::_1);
973
974 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
975 string params = "universe=6";
976 if (cfg_db->getExtendedInfoTablesEnabled()) {
977 params += " extended-info-tables=true";
978 }
979 cfg_db->setAppendedParameters(params);
980 cfg_db->createManagers();
981 // Reset counters related to connections as all managers have been recreated.
982 srv->getNetworkState()->resetForDbConnection();
983 } catch (const std::exception& ex) {
984 err << "Unable to open database: " << ex.what();
986 }
987
988 // Regenerate server identifier if needed.
989 try {
990 const std::string duid_file =
991 std::string(CfgMgr::instance().getDataDir()) + "/" +
992 std::string(SERVER_DUID_FILE);
993 DuidPtr duid = CfgMgr::instance().getStagingCfg()->getCfgDUID()->create(duid_file);
994 server_->serverid_.reset(new Option(Option::V6, D6O_SERVERID, duid->getDuid()));
995 if (duid) {
997 .arg(duid->toText())
998 .arg(duid_file);
999 }
1000
1001 } catch (const std::exception& ex) {
1002 err << "unable to configure server identifier: " << ex.what();
1004 }
1005
1006 // Server will start DDNS communications if its enabled.
1007 try {
1008 srv->startD2();
1009 } catch (const std::exception& ex) {
1010 err << "Error starting DHCP_DDNS client after server reconfiguration: "
1011 << ex.what();
1013 }
1014
1015 // Setup DHCPv4-over-DHCPv6 IPC
1016 try {
1018 } catch (const std::exception& ex) {
1019 err << "error starting DHCPv4-over-DHCPv6 IPC "
1020 " after server reconfiguration: " << ex.what();
1022 }
1023
1024 // Configure DHCP packet queueing
1025 try {
1027 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
1028 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, qc)) {
1030 .arg(IfaceMgr::instance().getPacketQueue6()->getInfoStr());
1031 }
1032
1033 } catch (const std::exception& ex) {
1034 err << "Error setting packet queue controls after server reconfiguration: "
1035 << ex.what();
1037 }
1038
1039 // Configure a callback to shut down the server when the bind socket
1040 // attempts exceeded.
1042 std::bind(&ControlledDhcpv6Srv::openSocketsFailedCallback, srv, ph::_1);
1043
1044 // Configuration may change active interfaces. Therefore, we have to reopen
1045 // sockets according to new configuration. It is possible that this
1046 // operation will fail for some interfaces but the openSockets function
1047 // guards against exceptions and invokes a callback function to
1048 // log warnings. Since we allow that this fails for some interfaces there
1049 // is no need to rollback configuration if socket fails to open on any
1050 // of the interfaces.
1051 CfgMgr::instance().getStagingCfg()->getCfgIface()->
1052 openSockets(AF_INET6, srv->getServerPort());
1053
1054 // Install the timers for handling leases reclamation.
1055 try {
1056 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
1057 setupTimers(&ControlledDhcpv6Srv::reclaimExpiredLeases,
1058 &ControlledDhcpv6Srv::deleteExpiredReclaimedLeases,
1059 server_);
1060
1061 } catch (const std::exception& ex) {
1062 err << "unable to setup timers for periodically running the"
1063 " reclamation of the expired leases: "
1064 << ex.what() << ".";
1066 }
1067
1068 // Setup config backend polling, if configured for it.
1069 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
1070 if (ctl_info) {
1071 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
1072 // Only schedule the CB fetch timer if the fetch wait time is greater
1073 // than 0.
1074 if (fetch_time > 0) {
1075 // When we run unit tests, we want to use milliseconds unit for the
1076 // specified interval. Otherwise, we use seconds. Note that using
1077 // milliseconds as a unit in unit tests prevents us from waiting 1
1078 // second on more before the timer goes off. Instead, we wait one
1079 // millisecond which significantly reduces the test time.
1080 if (!server_->inTestMode()) {
1081 fetch_time = 1000 * fetch_time;
1082 }
1083
1084 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
1086 registerTimer("Dhcp6CBFetchTimer",
1087 std::bind(&ControlledDhcpv6Srv::cbFetchUpdates,
1088 server_, CfgMgr::instance().getStagingCfg(),
1089 failure_count),
1090 fetch_time,
1092 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
1093 }
1094 }
1095
1096 // Finally, we can commit runtime option definitions in libdhcp++. This is
1097 // exception free.
1099
1100 auto notify_libraries = ControlledDhcpv6Srv::finishConfigHookLibraries(config);
1101 if (notify_libraries) {
1102 return (notify_libraries);
1103 }
1104
1105 // Initialize the allocators. If the user selected a Free Lease Queue Allocator
1106 // for any of the subnets, the server will now populate free leases to the queue.
1107 // It may take a while!
1108 try {
1109 CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->initAllocatorsAfterConfigure();
1110
1111 } catch (const std::exception& ex) {
1112 err << "Error initializing the lease allocators: "
1113 << ex.what();
1115 }
1116
1117 // Apply multi threading settings.
1118 // @note These settings are applied/updated only if no errors occur while
1119 // applying the new configuration.
1120 // @todo This should be fixed.
1121 try {
1122 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1123 } catch (const std::exception& ex) {
1124 err << "Error applying multi threading settings: "
1125 << ex.what();
1127 }
1128
1129 return (answer);
1130}
1131
1135 // This hook point notifies hooks libraries that the configuration of the
1136 // DHCPv6 server has completed. It provides the hook library with the pointer
1137 // to the common IO service object, new server configuration in the JSON
1138 // format and with the pointer to the configuration storage where the
1139 // parsed configuration is stored.
1140 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp6_srv_configured_)) {
1142
1143 callout_handle->setArgument("io_context", srv->getIOService());
1144 callout_handle->setArgument("network_state", srv->getNetworkState());
1145 callout_handle->setArgument("json_config", config);
1146 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1147
1148 HooksManager::callCallouts(Hooks.hooks_index_dhcp6_srv_configured_,
1149 *callout_handle);
1150
1151 // If next step is DROP, report a configuration error.
1152 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1153 string error;
1154 try {
1155 callout_handle->getArgument("error", error);
1156 } catch (NoSuchArgument const& ex) {
1157 error = "unknown error";
1158 }
1160 }
1161 }
1162
1163 return (ConstElementPtr());
1164}
1165
1169
1170 if (!srv) {
1172 "Server object not initialized, can't process config.");
1173 return (no_srv);
1174 }
1175
1177 .arg(srv->redactConfig(config)->str());
1178
1179 return (configureDhcp6Server(*srv, config, true));
1180}
1181
1182ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port /*= DHCP6_SERVER_PORT*/,
1183 uint16_t client_port /*= 0*/)
1184 : Dhcpv6Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1185 if (getInstance()) {
1187 "There is another Dhcpv6Srv instance already.");
1188 }
1189 server_ = this; // remember this instance for later use in handlers
1190
1191 // ProcessSpawn uses IO service to handle signal set events.
1193
1194 // TimerMgr uses IO service to run asynchronous timers.
1195 TimerMgr::instance()->setIOService(getIOService());
1196
1197 // CommandMgr uses IO service to run asynchronous socket operations.
1199
1200 // DatabaseConnection uses IO service to run asynchronous timers.
1202
1203 // These are the commands always supported by the DHCPv6 server.
1204 // Please keep the list in alphabetic order.
1205 CommandMgr::instance().registerCommand("build-report",
1206 std::bind(&ControlledDhcpv6Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1207
1208 CommandMgr::instance().registerCommand("config-backend-pull",
1209 std::bind(&ControlledDhcpv6Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1210
1212 std::bind(&ControlledDhcpv6Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1213
1214 CommandMgr::instance().registerCommand("config-hash-get",
1215 std::bind(&ControlledDhcpv6Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1216
1217 CommandMgr::instance().registerCommand("config-reload",
1218 std::bind(&ControlledDhcpv6Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1219
1221 std::bind(&ControlledDhcpv6Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1222
1223 CommandMgr::instance().registerCommand("config-test",
1224 std::bind(&ControlledDhcpv6Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1225
1226 CommandMgr::instance().registerCommand("config-write",
1227 std::bind(&ControlledDhcpv6Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1228
1229 CommandMgr::instance().registerCommand("dhcp-enable",
1230 std::bind(&ControlledDhcpv6Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1231
1232 CommandMgr::instance().registerCommand("dhcp-disable",
1233 std::bind(&ControlledDhcpv6Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1234
1236 std::bind(&ControlledDhcpv6Srv::commandLibReloadHandler, this, ph::_1, ph::_2));
1237
1238 CommandMgr::instance().registerCommand("leases-reclaim",
1239 std::bind(&ControlledDhcpv6Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1240
1241 CommandMgr::instance().registerCommand("server-tag-get",
1242 std::bind(&ControlledDhcpv6Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1243
1245 std::bind(&ControlledDhcpv6Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1246
1248 std::bind(&ControlledDhcpv6Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1249
1250 CommandMgr::instance().registerCommand("version-get",
1251 std::bind(&ControlledDhcpv6Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1252
1253 // Register statistic related commands
1254 CommandMgr::instance().registerCommand("statistic-get",
1255 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1256
1257 CommandMgr::instance().registerCommand("statistic-reset",
1258 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1259
1260 CommandMgr::instance().registerCommand("statistic-remove",
1261 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1262
1263 CommandMgr::instance().registerCommand("statistic-get-all",
1264 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1265
1266 CommandMgr::instance().registerCommand("statistic-reset-all",
1267 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1268
1269 CommandMgr::instance().registerCommand("statistic-remove-all",
1270 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1271
1272 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1273 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1274
1275 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1276 std::bind(&ControlledDhcpv6Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1277
1278 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1279 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1280
1281 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1282 std::bind(&ControlledDhcpv6Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1283}
1284
1286 setExitValue(exit_value);
1287 getIOService()->stop(); // Stop ASIO transmissions
1288 shutdown(); // Initiate DHCPv6 shutdown procedure.
1289}
1290
1292 try {
1293 MultiThreadingMgr::instance().apply(false, 0, 0);
1296
1297 // The closure captures either a shared pointer (memory leak)
1298 // or a raw pointer (pointing to a deleted object).
1302
1303 timer_mgr_->unregisterTimers();
1304
1305 cleanup();
1306
1307 // Close the command socket (if it exists).
1309
1310 // Deregister any registered commands (please keep in alphabetic order)
1311 CommandMgr::instance().deregisterCommand("build-report");
1312 CommandMgr::instance().deregisterCommand("config-backend-pull");
1314 CommandMgr::instance().deregisterCommand("config-hash-get");
1315 CommandMgr::instance().deregisterCommand("config-reload");
1317 CommandMgr::instance().deregisterCommand("config-test");
1318 CommandMgr::instance().deregisterCommand("config-write");
1319 CommandMgr::instance().deregisterCommand("dhcp-disable");
1320 CommandMgr::instance().deregisterCommand("dhcp-enable");
1321 CommandMgr::instance().deregisterCommand("leases-reclaim");
1323 CommandMgr::instance().deregisterCommand("server-tag-get");
1325 CommandMgr::instance().deregisterCommand("statistic-get");
1326 CommandMgr::instance().deregisterCommand("statistic-get-all");
1327 CommandMgr::instance().deregisterCommand("statistic-remove");
1328 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1329 CommandMgr::instance().deregisterCommand("statistic-reset");
1330 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1331 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1332 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1333 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1334 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1336 CommandMgr::instance().deregisterCommand("version-get");
1337
1338 // Reset DatabaseConnection IO service.
1340 } catch (...) {
1341 // Don't want to throw exceptions from the destructor. The server
1342 // is shutting down anyway.
1343 }
1344
1345 server_ = NULL; // forget this instance. There should be no callback anymore
1346 // at this stage anyway.
1347}
1348
1349void
1350ControlledDhcpv6Srv::reclaimExpiredLeases(const size_t max_leases,
1351 const uint16_t timeout,
1352 const bool remove_lease,
1353 const uint16_t max_unwarned_cycles) {
1354 try {
1355 server_->alloc_engine_->reclaimExpiredLeases6(max_leases, timeout,
1356 remove_lease,
1357 max_unwarned_cycles);
1358 } catch (const std::exception& ex) {
1360 .arg(ex.what());
1361 }
1362 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1364}
1365
1366void
1367ControlledDhcpv6Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1368 server_->alloc_engine_->deleteExpiredReclaimedLeases6(secs);
1369 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1371}
1372
1373bool
1374ControlledDhcpv6Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1375 if (!db_reconnect_ctl) {
1376 // This should never happen
1378 return (false);
1379 }
1380
1381 // Disable service until the connection is recovered.
1382 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1383 db_reconnect_ctl->alterServiceState()) {
1385 }
1386
1388
1389 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1390 // return false.
1391 if (!db_reconnect_ctl->retriesLeft() ||
1392 !db_reconnect_ctl->retryInterval()) {
1394 .arg(db_reconnect_ctl->retriesLeft())
1395 .arg(db_reconnect_ctl->retryInterval());
1396 if (db_reconnect_ctl->exitOnFailure()) {
1397 shutdownServer(EXIT_FAILURE);
1398 }
1399 return (false);
1400 }
1401
1402 return (true);
1403}
1404
1405bool
1406ControlledDhcpv6Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1407 if (!db_reconnect_ctl) {
1408 // This should never happen
1410 return (false);
1411 }
1412
1413 // Enable service after the connection is recovered.
1414 if (db_reconnect_ctl->alterServiceState()) {
1416 }
1417
1419
1420 db_reconnect_ctl->resetRetries();
1421
1422 return (true);
1423}
1424
1425bool
1426ControlledDhcpv6Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1427 if (!db_reconnect_ctl) {
1428 // This should never happen
1430 return (false);
1431 }
1432
1434 .arg(db_reconnect_ctl->maxRetries());
1435
1436 if (db_reconnect_ctl->exitOnFailure()) {
1437 shutdownServer(EXIT_FAILURE);
1438 }
1439
1440 return (true);
1441}
1442
1443void
1444ControlledDhcpv6Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1445 if (!reconnect_ctl) {
1446 // This should never happen
1448 return;
1449 }
1450
1452 .arg(reconnect_ctl->maxRetries());
1453
1454 if (reconnect_ctl->exitOnFailure()) {
1455 shutdownServer(EXIT_FAILURE);
1456 }
1457}
1458
1459void
1460ControlledDhcpv6Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1461 boost::shared_ptr<unsigned> failure_count) {
1462 // stop thread pool (if running)
1464
1465 try {
1466 // Fetch any configuration backend updates since our last fetch.
1467 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1469 (*failure_count) = 0;
1470
1471 } catch (const std::exception& ex) {
1473 .arg(ex.what());
1474
1475 // We allow at most 10 consecutive failures after which we stop
1476 // making further attempts to fetch the configuration updates.
1477 // Let's return without re-scheduling the timer.
1478 if (++(*failure_count) > 10) {
1481 return;
1482 }
1483 }
1484
1485 // Reschedule the timer to fetch new updates or re-try if
1486 // the previous attempt resulted in an error.
1487 if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
1488 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
1489 }
1490}
1491
1492} // namespace dhcp
1493} // namespace isc
CtrlAgentHooks Hooks
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown when an unexpected error condition occurs.
void registerCommand(const std::string &cmd, CommandHandler handler)
Registers specified command handler for a given command.
static std::string getHash(const isc::data::ConstElementPtr &config)
returns a hash of a given Element structure
void deregisterCommand(const std::string &cmd)
Deregisters specified command handler.
void closeCommandSocket()
Shuts down any open control sockets.
Definition: command_mgr.cc:624
static CommandMgr & instance()
CommandMgr is a singleton class.
Definition: command_mgr.cc:646
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the command manager.
Definition: command_mgr.cc:652
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:249
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:304
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:299
static void setIOService(const isc::asiolink::IOServicePtr &io_service)
Sets IO service to be used by the database backends.
static DbCallback db_recovered_callback_
Optional callback function to invoke if an opened connection recovery succeeded.
static DbCallback db_failed_callback_
Optional callback function to invoke if an opened connection recovery failed.
static DbCallback db_lost_callback_
Optional callback function to invoke if an opened connection is lost.
RAII class to enable DB reconnect retries on server startup.
static const std::string FLUSH_RECLAIMED_TIMER_NAME
Name of the timer for flushing reclaimed leases.
static const std::string RECLAIM_EXPIRED_TIMER_NAME
Name of the timer for reclaiming expired leases.
static OpenSocketsFailedCallback open_sockets_failed_callback_
Optional callback function to invoke if all retries of the opening sockets fail.
Definition: cfg_iface.h:361
void rollback()
Removes staging configuration.
Definition: cfgmgr.cc:120
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition: cfgmgr.cc:167
void commit()
Commits the staging configuration.
Definition: cfgmgr.cc:90
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
static void apply(data::ConstElementPtr value)
apply multi threading configuration
static void extract(data::ConstElementPtr value, bool &enabled, uint32_t &thread_count, uint32_t &queue_size)
Extract multi-threading parameters from a given configuration.
Controlled version of the DHCPv6 server.
void init(const std::string &config_file)
Initializes the server.
void cleanup()
Performs cleanup, immediately before termination.
static isc::data::ConstElementPtr finishConfigHookLibraries(isc::data::ConstElementPtr config)
Configuration checker for hook libraries.
virtual ~ControlledDhcpv6Srv()
Destructor.
static isc::data::ConstElementPtr processConfig(isc::data::ConstElementPtr config)
Configuration processor.
static isc::data::ConstElementPtr processCommand(const std::string &command, isc::data::ConstElementPtr args)
Command processor.
virtual void shutdownServer(int exit_value)
Initiates shutdown procedure for the whole DHCPv6 server.
static ControlledDhcpv6Srv * getInstance()
Returns pointer to the sole instance of Dhcpv6Srv.
isc::data::ConstElementPtr loadConfigFile(const std::string &file_name)
Configure DHCPv6 server using the configuration file specified.
static isc::data::ConstElementPtr checkConfig(isc::data::ConstElementPtr config)
Configuration checker.
ControlledDhcpv6Srv(uint16_t server_port=DHCP6_SERVER_PORT, uint16_t client_port=0)
Constructor.
virtual void open()
Open communication socket.
Definition: dhcp6to4_ipc.cc:39
static Dhcp6to4Ipc & instance()
Returns pointer to the sole instance of Dhcp6to4Ipc.
Definition: dhcp6to4_ipc.cc:34
DHCPv6 server service.
Definition: dhcp6_srv.h:66
void shutdown() override
Instructs the server to shut down.
Definition: dhcp6_srv.cc:310
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
Definition: dhcp6_srv.h:1221
uint16_t getServerPort() const
Get UDP port on which server should listen.
Definition: dhcp6_srv.h:243
OptionPtr serverid_
Server DUID (to be sent in server-identifier option)
Definition: dhcp6_srv.h:1202
NetworkStatePtr & getNetworkState()
Returns pointer to the network state used by the server.
Definition: dhcp6_srv.h:115
NetworkStatePtr network_state_
Holds information about disabled DHCP service and/or disabled subnet/network scopes.
Definition: dhcp6_srv.h:1229
CBControlDHCPv6Ptr getCBControl() const
Returns an object which controls access to the configuration backends.
Definition: dhcp6_srv.h:124
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
Definition: dhcp6_srv.cc:4651
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
Definition: dhcp6_srv.h:110
bool inTestMode() const
Checks if the server is running in unit test mode.
Definition: dhcp6_srv.h:105
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
Definition: dhcp6_srv.cc:4617
static void create()
Creates new instance of the HostMgr.
Definition: host_mgr.cc:52
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:54
static TrackingLeaseMgr & instance()
Return current lease manager.
static void destroy()
Destroy lease manager.
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition: libdhcp++.cc:242
static const unsigned int DB_CONNECTION
The network state is being altered by the DB connection recovery mechanics.
static const unsigned int USER_COMMAND
Origin of the network state transition.
Definition: network_state.h:90
static const unsigned int HA_REMOTE_COMMAND
The network state is being altered by a "dhcp-disable" or "dhcp-enable" command sent by a HA partner.
Evaluation context, an interface to the expression evaluation.
isc::data::ElementPtr parseFile(const std::string &filename, ParserType parser_type)
Run the parser on the file specified.
@ PARSER_DHCP6
This parser will parse the content as Dhcp6 config wrapped in a map (that's the regular config file)
Manages a pool of asynchronous interval timers.
Definition: timer_mgr.h:62
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:446
@ NEXT_STEP_DROP
drop the packet
static int registerHook(const std::string &name)
Register Hook.
static bool calloutsPresent(int index)
Are callouts present?
static bool unloadLibraries()
Unload libraries.
static bool loadLibraries(const HookLibsCollection &libraries, bool multi_threading_enabled=false)
Load and reload libraries.
static boost::shared_ptr< CalloutHandle > createCalloutHandle()
Return callout handle.
static void callCallouts(int index, CalloutHandle &handle)
Calls the callouts for a given hook.
static HookLibsCollection getLibraryInfo()
Return list of loaded libraries with its parameters.
static void prepareUnloadLibraries()
Prepare the unloading of libraries.
std::string getConfigFile() const
Returns config file name.
Definition: daemon.cc:104
virtual size_t writeConfigFile(const std::string &config_file, isc::data::ConstElementPtr cfg=isc::data::ConstElementPtr()) const
Writes current configuration to specified file.
Definition: daemon.cc:228
isc::asiolink::IOSignalSetPtr signal_set_
A pointer to the object installing custom signal handlers.
Definition: daemon.h:257
boost::posix_time::ptime start_
Timestamp of the start of the daemon.
Definition: daemon.h:263
void setExitValue(int value)
Sets the exit value.
Definition: daemon.h:227
isc::data::ConstElementPtr redactConfig(isc::data::ConstElementPtr const &config)
Redact a configuration.
Definition: daemon.cc:256
Statistics Manager class.
static StatsMgr & instance()
Statistics Manager accessor method.
RAII class creating a critical section.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
ThreadPool< std::function< void()> > & getThreadPool()
Get the dhcp thread pool.
void apply(bool enabled, uint32_t thread_count, uint32_t queue_size)
Apply the multi-threading related settings.
This file contains several functions and constants that are used for handling commands and responses ...
@ D6O_SERVERID
Definition: dhcp6.h:22
Defines the Dhcp6to4Ipc class.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
isc::data::ConstElementPtr statisticSetMaxSampleCountAllHandler(const isc::data::ConstElementPtr &params)
Handles statistic-sample-count-set-all command.
static isc::data::ConstElementPtr statisticResetHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-reset command.
static isc::data::ConstElementPtr statisticGetAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-get-all command.
static isc::data::ConstElementPtr statisticRemoveHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-remove command.
static isc::data::ConstElementPtr statisticGetHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-get command.
isc::data::ConstElementPtr statisticSetMaxSampleAgeAllHandler(const isc::data::ConstElementPtr &params)
Handles statistic-sample-age-set-all command.
static isc::data::ConstElementPtr statisticResetAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-reset-all command.
static isc::data::ConstElementPtr statisticSetMaxSampleAgeHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-sample-age-set command.
static isc::data::ConstElementPtr statisticRemoveAllHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-remove-all command.
static isc::data::ConstElementPtr statisticSetMaxSampleCountHandler(const std::string &name, const isc::data::ConstElementPtr &params)
Handles statistic-sample-count-set command.
uint32_t getMaxSampleCountDefault() const
Get default count limit.
const StatsDuration & getMaxSampleAgeDefault() const
Get default duration limit.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_FATAL(LOGGER, MESSAGE)
Macro to conveniently test fatal output and log it.
Definition: macros.h:38
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:29
boost::shared_ptr< Element > ElementPtr
Definition: data.h:28
@ error
Definition: db_log.h:118
std::string getConfigReport()
Definition: cfgrpt.cc:20
const isc::log::MessageID DHCP6_DB_RECONNECT_NO_DB_CTL
const isc::log::MessageID DHCP6_OPEN_SOCKETS_NO_RECONNECT_CTL
const isc::log::MessageID DHCP6_USING_SERVERID
const isc::log::MessageID DHCP6_CONFIG_LOAD_FAIL
const isc::log::MessageID DHCP6_DB_RECONNECT_SUCCEEDED
isc::data::ConstElementPtr configureDhcp6Server(Dhcpv6Srv &server, isc::data::ConstElementPtr config_set, bool check_only, bool extra_checks)
Configure DHCPv6 server (Dhcpv6Srv) with a set of configuration values.
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition: iface_mgr.h:487
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:136
const int DBG_DHCP6_COMMAND
Debug level used to log receiving commands.
Definition: dhcp6_log.h:28
const isc::log::MessageID DHCP6_CB_PERIODIC_FETCH_UPDATES_FAIL
const isc::log::MessageID DHCP6_RECLAIM_EXPIRED_LEASES_FAIL
const isc::log::MessageID DHCP6_OPEN_SOCKETS_FAILED
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
Definition: srv_config.h:1267
const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION_SUCCESS
const isc::log::MessageID DHCP6_CB_ON_DEMAND_FETCH_UPDATES_FAIL
const isc::log::MessageID DHCP6_COMMAND_RECEIVED
const isc::log::MessageID DHCP6_CB_PERIODIC_FETCH_UPDATES_RETRIES_EXHAUSTED
const isc::log::MessageID DHCP6_NOT_RUNNING
const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION_FAIL
const isc::log::MessageID DHCP6_CONFIG_UNSUPPORTED_OBJECT
const isc::log::MessageID DHCP6_CONFIG_UNRECOVERABLE_ERROR
const isc::log::MessageID DHCP6_CONFIG_RECEIVED
const isc::log::MessageID DHCP6_DB_RECONNECT_DISABLED
const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION
const isc::log::MessageID DHCP6_DEPRECATED
const isc::log::MessageID DHCP6_DB_RECONNECT_LOST_CONNECTION
const isc::log::MessageID DHCP6_HOOKS_LIBS_RELOAD_FAIL
isc::log::Logger dhcp6_logger(DHCP6_APP_LOGGER_NAME)
Base logger for DHCPv6 server.
Definition: dhcp6_log.h:88
const isc::log::MessageID DHCP6_MULTI_THREADING_INFO
const isc::log::MessageID DHCP6_DB_RECONNECT_FAILED
const isc::log::MessageID DHCP6_CONFIG_PACKET_QUEUE
std::vector< HookLibInfo > HookLibsCollection
A storage for information about hook libraries.
Definition: libinfo.h:31
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
long toSeconds(const StatsDuration &dur)
Returns the number of seconds in a duration.
Definition: observation.h:49
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
Defines the logger used by the top-level component of kea-lfc.
void reset()
reset the thread pool stopping threads and clearing the internal queue
Definition: thread_pool.h:60