Kea 2.6.2
ctrl_dhcp6_srv.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2025 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) {
84 } else if ((signo == SIGTERM) || (signo == SIGINT)) {
86 }
87}
88
89}
90
91namespace isc {
92namespace dhcp {
93
94ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL;
95
96void
97ControlledDhcpv6Srv::init(const std::string& file_name) {
98 // Keep the call timestamp.
99 start_ = boost::posix_time::second_clock::universal_time();
100
101 // Configure the server using JSON file.
103
104 int rcode;
106 if (rcode != CONTROL_RESULT_SUCCESS) {
107 string reason = comment ? comment->stringValue() :
108 "no details available";
109 isc_throw(isc::BadValue, reason);
110 }
111
112 // Set signal handlers. When the SIGHUP is received by the process
113 // the server reconfiguration will be triggered. When SIGTERM or
114 // SIGINT will be received, the server will start shutting down.
115 signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
116
117 signal_set_->add(SIGINT);
118 signal_set_->add(SIGHUP);
119 signal_set_->add(SIGTERM);
120}
121
123 signal_set_.reset();
124 getIOService()->poll();
125}
126
128ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
129 // This is a configuration backend implementation that reads the
130 // configuration from a JSON file.
131
134
135 // Basic sanity check: file name must not be empty.
136 try {
137 if (file_name.empty()) {
138 // Basic sanity check: file name must not be empty.
139 isc_throw(isc::BadValue, "JSON configuration file not specified."
140 " Please use -c command line option.");
141 }
142
143 // Read contents of the file and parse it as JSON
144 Parser6Context parser;
145 json = parser.parseFile(file_name, Parser6Context::PARSER_DHCP6);
146 if (!json) {
147 isc_throw(isc::BadValue, "no configuration found");
148 }
149
150 // Let's do sanity check before we call json->get() which
151 // works only for map.
152 if (json->getType() != isc::data::Element::map) {
153 isc_throw(isc::BadValue, "Configuration file is expected to be "
154 "a map, i.e., start with { and end with } and contain "
155 "at least an entry called 'Dhcp6' that itself is a map. "
156 << file_name
157 << " is a valid JSON, but its top element is not a map."
158 " Did you forget to add { } around your configuration?");
159 }
160
161 // Use parsed JSON structures to configure the server
163 if (!result) {
164 // Undetermined status of the configuration. This should never
165 // happen, but as the configureDhcp6Server returns a pointer, it is
166 // theoretically possible that it will return NULL.
167 isc_throw(isc::BadValue, "undefined result of "
168 "process command \"config-set\"");
169 }
170
171 // Now check is the returned result is successful (rcode=0) or not
172 // (see @ref isc::config::parseAnswer).
173 int rcode;
175 if (rcode != CONTROL_RESULT_SUCCESS) {
176 string reason = comment ? comment->stringValue() :
177 "no details available";
178 isc_throw(isc::BadValue, reason);
179 }
180 } catch (const std::exception& ex) {
181 // If configuration failed at any stage, we drop the staging
182 // configuration and continue to use the previous one.
184
186 .arg(file_name).arg(ex.what());
187 isc_throw(isc::BadValue, "configuration error using file '"
188 << file_name << "': " << ex.what());
189 }
190
192 .arg(MultiThreadingMgr::instance().getMode() ? "yes" : "no")
193 .arg(MultiThreadingMgr::instance().getThreadPoolSize())
194 .arg(MultiThreadingMgr::instance().getPacketQueueSize());
195
196 return (result);
197}
198
200ControlledDhcpv6Srv::commandShutdownHandler(const string&, ConstElementPtr args) {
203 return (createAnswer(CONTROL_RESULT_ERROR, "Shutdown failure."));
204 }
205
206 int exit_value = 0;
207 if (args) {
208 // @todo Should we go ahead and shutdown even if the args are invalid?
209 if (args->getType() != Element::map) {
210 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
211 }
212
213 ConstElementPtr param = args->get("exit-value");
214 if (param) {
215 if (param->getType() != Element::integer) {
217 "parameter 'exit-value' is not an integer"));
218 }
219
220 exit_value = param->intValue();
221 }
222 }
223
225 return (createAnswer(CONTROL_RESULT_SUCCESS, "Shutting down."));
226}
227
229ControlledDhcpv6Srv::commandConfigReloadHandler(const string&,
230 ConstElementPtr /*args*/) {
231 // Get configuration file name.
233 try {
235 auto result = loadConfigFile(file);
237 return (result);
238 } catch (const std::exception& ex) {
239 // Log the unsuccessful reconfiguration. The reason for failure
240 // should be already logged. Don't rethrow an exception so as
241 // the server keeps working.
243 .arg(file);
245 "Config reload failed: " + string(ex.what())));
246 }
247}
248
250ControlledDhcpv6Srv::commandConfigGetHandler(const string&,
251 ConstElementPtr /*args*/) {
252 ElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
253 string hash = BaseCommandMgr::getHash(config);
254 config->set("hash", Element::create(hash));
255
256 return (createAnswer(CONTROL_RESULT_SUCCESS, config));
257}
258
260ControlledDhcpv6Srv::commandConfigHashGetHandler(const string&,
261 ConstElementPtr /*args*/) {
262 ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
263
264 string hash = BaseCommandMgr::getHash(config);
265
267 params->set("hash", Element::create(hash));
268 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
269}
270
272ControlledDhcpv6Srv::commandConfigWriteHandler(const string&,
273 ConstElementPtr args) {
274 string filename;
275
276 if (args) {
277 if (args->getType() != Element::map) {
278 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
279 }
280 ConstElementPtr filename_param = args->get("filename");
281 if (filename_param) {
282 if (filename_param->getType() != Element::string) {
284 "passed parameter 'filename' is not a string"));
285 }
286 filename = filename_param->stringValue();
287 }
288 }
289
290 if (filename.empty()) {
291 // filename parameter was not specified, so let's use whatever we remember
292 // from the command-line
293 filename = getConfigFile();
294 }
295
296 if (filename.empty()) {
297 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
298 "Please specify filename explicitly."));
299 }
300
301 // Ok, it's time to write the file.
302 size_t size = 0;
303 try {
304 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
305 size = writeConfigFile(filename, cfg);
306 } catch (const isc::Exception& ex) {
307 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during config-write: ")
308 + ex.what()));
309 }
310 if (size == 0) {
311 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
312 + filename));
313 }
314
315 // Ok, it's time to return the successful response.
317 params->set("size", Element::create(static_cast<long long>(size)));
318 params->set("filename", Element::create(filename));
319
320 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
321 + filename + " successful", params));
322}
323
325ControlledDhcpv6Srv::commandConfigSetHandler(const string&,
326 ConstElementPtr args) {
327 const int status_code = CONTROL_RESULT_ERROR;
328 ConstElementPtr dhcp6;
329 string message;
330
331 // Command arguments are expected to be:
332 // { "Dhcp6": { ... } }
333 if (!args) {
334 message = "Missing mandatory 'arguments' parameter.";
335 } else {
336 dhcp6 = args->get("Dhcp6");
337 if (!dhcp6) {
338 message = "Missing mandatory 'Dhcp6' parameter.";
339 } else if (dhcp6->getType() != Element::map) {
340 message = "'Dhcp6' parameter expected to be a map.";
341 }
342 }
343
344 // Check unsupported objects.
345 if (message.empty()) {
346 for (auto const& obj : args->mapValue()) {
347 const string& obj_name = obj.first;
348 if (obj_name != "Dhcp6") {
350 .arg(obj_name);
351 if (message.empty()) {
352 message = "Unsupported '" + obj_name + "' parameter";
353 } else {
354 message += " (and '" + obj_name + "')";
355 }
356 }
357 }
358 if (!message.empty()) {
359 message += ".";
360 }
361 }
362
363 if (!message.empty()) {
364 // Something is amiss with arguments, return a failure response.
366 message);
367 return (result);
368 }
369
370 // stop thread pool (if running)
371 MultiThreadingCriticalSection cs;
372
373 // We are starting the configuration process so we should remove any
374 // staging configuration that has been created during previous
375 // configuration attempts.
377
378 // Parse the logger configuration explicitly into the staging config.
379 // Note this does not alter the current loggers, they remain in
380 // effect until we apply the logging config below. If no logging
381 // is supplied logging will revert to default logging.
382 Daemon::configureLogger(dhcp6, CfgMgr::instance().getStagingCfg());
383
384 // Let's apply the new logging. We do it early, so we'll be able to print
385 // out what exactly is wrong with the new config in case of problems.
386 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
387
388 // Now we configure the server proper.
390
391 // If the configuration parsed successfully, apply the new logger
392 // configuration and the commit the new configuration. We apply
393 // the logging first in case there's a configuration failure.
394 int rcode = 0;
396 if (rcode == CONTROL_RESULT_SUCCESS) {
397 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
398
399 // Use new configuration.
401 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
402 // Ok, we applied the logging from the upcoming configuration, but
403 // there were problems with the config. As such, we need to back off
404 // and revert to the previous logging configuration. This is not done if
405 // sequence == 0, because that would mean always reverting to stdout by
406 // default, and it is arguably more helpful to have the error in a
407 // potential file or syslog configured in the upcoming configuration.
408 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
409
410 // Not initial configuration so someone can believe we reverted
411 // to the previous configuration. It is not the case so be clear
412 // about this.
414 }
415
417 try {
418 // Handle events registered by hooks using external IOService objects.
420 } catch (const std::exception& ex) {
421 std::ostringstream err;
422 err << "Error initializing hooks: "
423 << ex.what();
425 }
426
427 return (result);
428}
429
431ControlledDhcpv6Srv::commandConfigTestHandler(const string&,
432 ConstElementPtr args) {
433 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
434 ConstElementPtr dhcp6;
435 string message;
436
437 // Command arguments are expected to be:
438 // { "Dhcp6": { ... } }
439 if (!args) {
440 message = "Missing mandatory 'arguments' parameter.";
441 } else {
442 dhcp6 = args->get("Dhcp6");
443 if (!dhcp6) {
444 message = "Missing mandatory 'Dhcp6' parameter.";
445 } else if (dhcp6->getType() != Element::map) {
446 message = "'Dhcp6' parameter expected to be a map.";
447 }
448 }
449
450 // Check unsupported objects.
451 if (message.empty()) {
452 for (auto const& obj : args->mapValue()) {
453 const string& obj_name = obj.first;
454 if (obj_name != "Dhcp6") {
456 .arg(obj_name);
457 if (message.empty()) {
458 message = "Unsupported '" + obj_name + "' parameter";
459 } else {
460 message += " (and '" + obj_name + "')";
461 }
462 }
463 }
464 if (!message.empty()) {
465 message += ".";
466 }
467 }
468
469 if (!message.empty()) {
470 // Something is amiss with arguments, return a failure response.
472 message);
473 return (result);
474 }
475
476 // stop thread pool (if running)
477 MultiThreadingCriticalSection cs;
478
479 // We are starting the configuration process so we should remove any
480 // staging configuration that has been created during previous
481 // configuration attempts.
483
484 // Now we check the server proper.
485 return (checkConfig(dhcp6));
486}
487
489ControlledDhcpv6Srv::commandDhcpDisableHandler(const std::string&,
490 ConstElementPtr args) {
491 std::ostringstream message;
492 int64_t max_period = 0;
493 std::string origin;
494
495 // If the args map does not contain 'origin' parameter, the default type
496 // will be used (user command).
497 auto type = NetworkState::USER_COMMAND;
498
499 // Parse arguments to see if the 'max-period' or 'origin' parameters have
500 // been specified.
501 if (args) {
502 // Arguments must be a map.
503 if (args->getType() != Element::map) {
504 message << "arguments for the 'dhcp-disable' command must be a map";
505
506 } else {
507 ConstElementPtr max_period_element = args->get("max-period");
508 // max-period is optional.
509 if (max_period_element) {
510 // It must be an integer, if specified.
511 if (max_period_element->getType() != Element::integer) {
512 message << "'max-period' argument must be a number";
513
514 } else {
515 // It must be positive integer.
516 max_period = max_period_element->intValue();
517 if (max_period <= 0) {
518 message << "'max-period' must be positive integer";
519 }
520 }
521 }
522 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
523 // stable release. However, the 'origin' is kept for backward compatibility
524 // with Kea versions before 2.5.8. It is common to receive both parameters
525 // because HA hook library sends both in case the partner server hasn't been
526 // upgraded to the new version. The 'origin-id' takes precedence over the
527 // 'origin'.
528 ConstElementPtr origin_id_element = args->get("origin-id");
529 ConstElementPtr origin_element = args->get("origin");
530 // The 'origin-id' and 'origin' arguments are optional.
531 if (origin_id_element) {
532 if (origin_id_element->getType() == Element::integer) {
533 type = origin_id_element->intValue();
534 } else {
535 message << "'origin-id' argument must be a number";
536 }
537 } else if (origin_element) {
538 switch (origin_element->getType()) {
539 case Element::string:
540 origin = origin_element->stringValue();
541 if (origin == "ha-partner") {
543 } else if (origin != "user") {
544 if (origin.empty()) {
545 origin = "(empty string)";
546 }
547 message << "invalid value used for 'origin' parameter: "
548 << origin;
549 }
550 break;
551 case Element::integer:
552 type = origin_element->intValue();
553 break;
554 default:
555 // It must be a string or a number, if specified.
556 message << "'origin' argument must be a string or a number";
557 }
558 }
559 }
560 }
561
562 // No error occurred, so let's disable the service.
563 if (message.tellp() == 0) {
564 message << "DHCPv6 service disabled";
565 if (max_period > 0) {
566 message << " for " << max_period << " seconds";
567
568 // The user specified that the DHCP service should resume not
569 // later than in max-period seconds. If the 'dhcp-enable' command
570 // is not sent, the DHCP service will resume automatically.
571 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
572 type);
573 }
574 network_state_->disableService(type);
575
576 // Success.
577 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
578 }
579
580 // Failure.
581 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
582}
583
585ControlledDhcpv6Srv::commandDhcpEnableHandler(const std::string&,
586 ConstElementPtr args) {
587 std::ostringstream message;
588 std::string origin;
589
590 // If the args map does not contain 'origin' parameter, the default type
591 // will be used (user command).
592 auto type = NetworkState::USER_COMMAND;
593
594 // Parse arguments to see if the 'origin' parameter has been specified.
595 if (args) {
596 // Arguments must be a map.
597 if (args->getType() != Element::map) {
598 message << "arguments for the 'dhcp-enable' command must be a map";
599
600 } else {
601 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
602 // stable release. However, the 'origin' is kept for backward compatibility
603 // with Kea versions before 2.5.8. It is common to receive both parameters
604 // because HA hook library sends both in case the partner server hasn't been
605 // upgraded to the new version. The 'origin-id' takes precedence over the
606 // 'origin'.
607 ConstElementPtr origin_id_element = args->get("origin-id");
608 ConstElementPtr origin_element = args->get("origin");
609 // The 'origin-id' and 'origin' arguments are optional.
610 if (origin_id_element) {
611 if (origin_id_element->getType() == Element::integer) {
612 type = origin_id_element->intValue();
613 } else {
614 message << "'origin-id' argument must be a number";
615 }
616 } else if (origin_element) {
617 switch (origin_element->getType()) {
618 case Element::string:
619 origin = origin_element->stringValue();
620 if (origin == "ha-partner") {
622 } else if (origin != "user") {
623 if (origin.empty()) {
624 origin = "(empty string)";
625 }
626 message << "invalid value used for 'origin' parameter: "
627 << origin;
628 }
629 break;
630 case Element::integer:
631 type = origin_element->intValue();
632 break;
633 default:
634 // It must be a string or a number, if specified.
635 message << "'origin' argument must be a string or a number";
636 }
637 }
638 }
639 }
640
641 // No error occurred, so let's enable the service.
642 if (message.tellp() == 0) {
643 network_state_->enableService(type);
644
645 // Success.
647 "DHCP service successfully enabled"));
648 }
649
650 // Failure.
651 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
652}
653
655ControlledDhcpv6Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
657 ElementPtr arguments = Element::createMap();
658 arguments->set("extended", extended);
661 arguments);
662 return (answer);
663}
664
666ControlledDhcpv6Srv::commandBuildReportHandler(const string&,
670 return (answer);
671}
672
674ControlledDhcpv6Srv::commandLeasesReclaimHandler(const string&,
675 ConstElementPtr args) {
676 int status_code = CONTROL_RESULT_ERROR;
677 string message;
678
679 // args must be { "remove": <bool> }
680 if (!args) {
681 message = "Missing mandatory 'remove' parameter.";
682 } else {
683 ConstElementPtr remove_name = args->get("remove");
684 if (!remove_name) {
685 message = "Missing mandatory 'remove' parameter.";
686 } else if (remove_name->getType() != Element::boolean) {
687 message = "'remove' parameter expected to be a boolean.";
688 } else {
689 bool remove_lease = remove_name->boolValue();
690 server_->alloc_engine_->reclaimExpiredLeases6(0, 0, remove_lease);
691 status_code = 0;
692 message = "Reclamation of expired leases is complete.";
693 }
694 }
695 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
696 return (answer);
697}
698
700ControlledDhcpv6Srv::commandServerTagGetHandler(const std::string&,
702 const std::string& tag =
703 CfgMgr::instance().getCurrentCfg()->getServerTag();
704 ElementPtr response = Element::createMap();
705 response->set("server-tag", Element::create(tag));
706
707 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
708}
709
711ControlledDhcpv6Srv::commandConfigBackendPullHandler(const std::string&,
713 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
714 if (!ctl_info) {
715 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
716 }
717
718 // stop thread pool (if running)
719 MultiThreadingCriticalSection cs;
720
721 // Reschedule the periodic CB fetch.
722 if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
723 TimerMgr::instance()->cancel("Dhcp6CBFetchTimer");
724 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
725 }
726
727 // Code from cbFetchUpdates.
728 // The configuration to use is the current one because this is called
729 // after the configuration manager commit.
730 try {
731 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
732 auto mode = CBControlDHCPv6::FetchMode::FETCH_UPDATE;
733 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
734 } catch (const std::exception& ex) {
736 .arg(ex.what());
738 "On demand configuration update failed: " +
739 string(ex.what())));
740 }
742 "On demand configuration update successful."));
743}
744
746ControlledDhcpv6Srv::commandStatusGetHandler(const string&,
747 ConstElementPtr /*args*/) {
749 status->set("pid", Element::create(static_cast<int>(getpid())));
750
751 auto now = boost::posix_time::second_clock::universal_time();
752 // Sanity check: start_ is always initialized.
753 if (!start_.is_not_a_date_time()) {
754 auto uptime = now - start_;
755 status->set("uptime", Element::create(uptime.total_seconds()));
756 }
757
758 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
759 if (!last_commit.is_not_a_date_time()) {
760 auto reload = now - last_commit;
761 status->set("reload", Element::create(reload.total_seconds()));
762 }
763
764 auto& mt_mgr = MultiThreadingMgr::instance();
765 if (mt_mgr.getMode()) {
766 status->set("multi-threading-enabled", Element::create(true));
767 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
768 MultiThreadingMgr::instance().getThreadPoolSize())));
769 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
770 MultiThreadingMgr::instance().getPacketQueueSize())));
771 ElementPtr queue_stats = Element::createList();
772 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
773 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
774 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
775 status->set("packet-queue-statistics", queue_stats);
776
777 } else {
778 status->set("multi-threading-enabled", Element::create(false));
779 }
780
781 status->set("extended-info-tables", Element::create(
782 CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->getExtendedInfoTablesEnabled()));
783
784 // Iterate through the interfaces and get all the errors.
785 ElementPtr socket_errors(Element::createList());
786 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
787 for (std::string const& error : interface->getErrors()) {
788 socket_errors->add(Element::create(error));
789 }
790 }
791
792 // Abstract the information from all sockets into a single status.
794 if (socket_errors->empty()) {
795 sockets->set("status", Element::create("ready"));
796 } else {
797 ReconnectCtlPtr const reconnect_ctl(
798 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
799 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
800 sockets->set("status", Element::create("retrying"));
801 } else {
802 sockets->set("status", Element::create("failed"));
803 }
804 sockets->set("errors", socket_errors);
805 }
806 status->set("sockets", sockets);
807
808 status->set("dhcp-state", network_state_->toElement());
809
810 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
811}
812
814ControlledDhcpv6Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
815 ConstElementPtr args) {
816 StatsMgr& stats_mgr = StatsMgr::instance();
818 // Update the default parameter.
819 long max_samples = stats_mgr.getMaxSampleCountDefault();
820 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
821 "statistic-default-sample-count", Element::create(max_samples));
822 return (answer);
823}
824
826ControlledDhcpv6Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
827 ConstElementPtr args) {
828 StatsMgr& stats_mgr = StatsMgr::instance();
830 // Update the default parameter.
831 auto duration = stats_mgr.getMaxSampleAgeDefault();
832 long max_age = toSeconds(duration);
833 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
834 "statistic-default-sample-age", Element::create(max_age));
835 return (answer);
836}
837
841
842 // Allow DB reconnect on startup. The database connection parameters specify
843 // respective details.
845
846 // Single stream instance used in all error clauses
847 std::ostringstream err;
848
849 if (!srv) {
850 err << "Server object not initialized, can't process config.";
852 }
853
855 .arg(srv->redactConfig(config)->str());
856
858
859 // Check that configuration was successful. If not, do not reopen sockets
860 // and don't bother with DDNS stuff.
861 try {
862 int rcode = 0;
864 if (rcode != 0) {
865 return (answer);
866 }
867 } catch (const std::exception& ex) {
868 err << "Failed to process configuration:" << ex.what();
870 }
871
872 // Re-open lease and host database with new parameters.
873 try {
875 std::bind(&ControlledDhcpv6Srv::dbLostCallback, srv, ph::_1);
876
878 std::bind(&ControlledDhcpv6Srv::dbRecoveredCallback, srv, ph::_1);
879
881 std::bind(&ControlledDhcpv6Srv::dbFailedCallback, srv, ph::_1);
882
883 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
884 string params = "universe=6";
885 if (cfg_db->getExtendedInfoTablesEnabled()) {
886 params += " extended-info-tables=true";
887 }
888 cfg_db->setAppendedParameters(params);
889 cfg_db->createManagers();
890 // Reset counters related to connections as all managers have been recreated.
891 srv->getNetworkState()->resetForDbConnection();
892 srv->getNetworkState()->resetForLocalCommands();
893 srv->getNetworkState()->resetForRemoteCommands();
894 } catch (const std::exception& ex) {
895 err << "Unable to open database: " << ex.what();
897 }
898
899 // Regenerate server identifier if needed.
900 try {
901 const std::string duid_file =
902 std::string(CfgMgr::instance().getDataDir()) + "/" +
903 std::string(SERVER_DUID_FILE);
904 DuidPtr duid = CfgMgr::instance().getStagingCfg()->getCfgDUID()->create(duid_file);
905 server_->serverid_.reset(new Option(Option::V6, D6O_SERVERID, duid->getDuid()));
906 if (duid) {
908 .arg(duid->toText())
909 .arg(duid_file);
910 }
911
912 } catch (const std::exception& ex) {
913 err << "unable to configure server identifier: " << ex.what();
915 }
916
917 // Server will start DDNS communications if its enabled.
918 try {
919 srv->startD2();
920 } catch (const std::exception& ex) {
921 err << "Error starting DHCP_DDNS client after server reconfiguration: "
922 << ex.what();
924 }
925
926 // Setup DHCPv4-over-DHCPv6 IPC
927 try {
929 } catch (const std::exception& ex) {
930 err << "error starting DHCPv4-over-DHCPv6 IPC "
931 " after server reconfiguration: " << ex.what();
933 }
934
935 // Configure DHCP packet queueing
936 try {
938 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
939 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, qc)) {
941 .arg(IfaceMgr::instance().getPacketQueue6()->getInfoStr());
942 }
943
944 } catch (const std::exception& ex) {
945 err << "Error setting packet queue controls after server reconfiguration: "
946 << ex.what();
948 }
949
950 // Configure a callback to shut down the server when the bind socket
951 // attempts exceeded.
953 std::bind(&ControlledDhcpv6Srv::openSocketsFailedCallback, srv, ph::_1);
954
955 // Configuration may change active interfaces. Therefore, we have to reopen
956 // sockets according to new configuration. It is possible that this
957 // operation will fail for some interfaces but the openSockets function
958 // guards against exceptions and invokes a callback function to
959 // log warnings. Since we allow that this fails for some interfaces there
960 // is no need to rollback configuration if socket fails to open on any
961 // of the interfaces.
962 CfgMgr::instance().getStagingCfg()->getCfgIface()->
963 openSockets(AF_INET6, srv->getServerPort());
964
965 // Install the timers for handling leases reclamation.
966 try {
967 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
968 setupTimers(&ControlledDhcpv6Srv::reclaimExpiredLeases,
969 &ControlledDhcpv6Srv::deleteExpiredReclaimedLeases,
970 server_);
971
972 } catch (const std::exception& ex) {
973 err << "unable to setup timers for periodically running the"
974 " reclamation of the expired leases: "
975 << ex.what() << ".";
977 }
978
979 // Setup config backend polling, if configured for it.
980 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
981 if (ctl_info) {
982 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
983 // Only schedule the CB fetch timer if the fetch wait time is greater
984 // than 0.
985 if (fetch_time > 0) {
986 // When we run unit tests, we want to use milliseconds unit for the
987 // specified interval. Otherwise, we use seconds. Note that using
988 // milliseconds as a unit in unit tests prevents us from waiting 1
989 // second on more before the timer goes off. Instead, we wait one
990 // millisecond which significantly reduces the test time.
991 if (!server_->inTestMode()) {
992 fetch_time = 1000 * fetch_time;
993 }
994
995 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
997 registerTimer("Dhcp6CBFetchTimer",
998 std::bind(&ControlledDhcpv6Srv::cbFetchUpdates,
999 server_, CfgMgr::instance().getStagingCfg(),
1000 failure_count),
1001 fetch_time,
1003 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
1004 }
1005 }
1006
1007 // Finally, we can commit runtime option definitions in libdhcp++. This is
1008 // exception free.
1010
1012 if (notify_libraries) {
1013 return (notify_libraries);
1014 }
1015
1016 // Initialize the allocators. If the user selected a Free Lease Queue Allocator
1017 // for any of the subnets, the server will now populate free leases to the queue.
1018 // It may take a while!
1019 try {
1020 CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->initAllocatorsAfterConfigure();
1021
1022 } catch (const std::exception& ex) {
1023 err << "Error initializing the lease allocators: "
1024 << ex.what();
1026 }
1027
1028 // Apply multi threading settings.
1029 // @note These settings are applied/updated only if no errors occur while
1030 // applying the new configuration.
1031 // @todo This should be fixed.
1032 try {
1033 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1034 } catch (const std::exception& ex) {
1035 err << "Error applying multi threading settings: "
1036 << ex.what();
1038 }
1039
1040 return (answer);
1041}
1042
1046 // This hook point notifies hooks libraries that the configuration of the
1047 // DHCPv6 server has completed. It provides the hook library with the pointer
1048 // to the common IO service object, new server configuration in the JSON
1049 // format and with the pointer to the configuration storage where the
1050 // parsed configuration is stored.
1051 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp6_srv_configured_)) {
1053
1054 callout_handle->setArgument("io_context", srv->getIOService());
1055 callout_handle->setArgument("network_state", srv->getNetworkState());
1056 callout_handle->setArgument("json_config", config);
1057 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1058
1059 HooksManager::callCallouts(Hooks.hooks_index_dhcp6_srv_configured_,
1060 *callout_handle);
1061
1062 // If next step is DROP, report a configuration error.
1063 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1064 string error;
1065 try {
1066 callout_handle->getArgument("error", error);
1067 } catch (NoSuchArgument const& ex) {
1068 error = "unknown error";
1069 }
1071 }
1072 }
1073
1074 return (ConstElementPtr());
1075}
1076
1080
1081 if (!srv) {
1083 "Server object not initialized, can't process config.");
1084 return (no_srv);
1085 }
1086
1088 .arg(srv->redactConfig(config)->str());
1089
1090 return (configureDhcp6Server(*srv, config, true));
1091}
1092
1093ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port /*= DHCP6_SERVER_PORT*/,
1094 uint16_t client_port /*= 0*/)
1095 : Dhcpv6Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1096 if (getInstance()) {
1098 "There is another Dhcpv6Srv instance already.");
1099 }
1100 server_ = this; // remember this instance for later use in handlers
1101
1102 // ProcessSpawn uses IO service to handle signal set events.
1104
1105 // TimerMgr uses IO service to run asynchronous timers.
1106 TimerMgr::instance()->setIOService(getIOService());
1107
1108 // CommandMgr uses IO service to run asynchronous socket operations.
1110
1111 // DatabaseConnection uses IO service to run asynchronous timers.
1113
1114 // These are the commands always supported by the DHCPv6 server.
1115 // Please keep the list in alphabetic order.
1116 CommandMgr::instance().registerCommand("build-report",
1117 std::bind(&ControlledDhcpv6Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1118
1119 CommandMgr::instance().registerCommand("config-backend-pull",
1120 std::bind(&ControlledDhcpv6Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1121
1123 std::bind(&ControlledDhcpv6Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1124
1125 CommandMgr::instance().registerCommand("config-hash-get",
1126 std::bind(&ControlledDhcpv6Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1127
1128 CommandMgr::instance().registerCommand("config-reload",
1129 std::bind(&ControlledDhcpv6Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1130
1132 std::bind(&ControlledDhcpv6Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1133
1134 CommandMgr::instance().registerCommand("config-test",
1135 std::bind(&ControlledDhcpv6Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1136
1137 CommandMgr::instance().registerCommand("config-write",
1138 std::bind(&ControlledDhcpv6Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1139
1140 CommandMgr::instance().registerCommand("dhcp-enable",
1141 std::bind(&ControlledDhcpv6Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1142
1143 CommandMgr::instance().registerCommand("dhcp-disable",
1144 std::bind(&ControlledDhcpv6Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1145
1146 CommandMgr::instance().registerCommand("leases-reclaim",
1147 std::bind(&ControlledDhcpv6Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1148
1149 CommandMgr::instance().registerCommand("server-tag-get",
1150 std::bind(&ControlledDhcpv6Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1151
1153 std::bind(&ControlledDhcpv6Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1154
1156 std::bind(&ControlledDhcpv6Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1157
1158 CommandMgr::instance().registerCommand("version-get",
1159 std::bind(&ControlledDhcpv6Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1160
1161 // Register statistic related commands
1162 CommandMgr::instance().registerCommand("statistic-get",
1163 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1164
1165 CommandMgr::instance().registerCommand("statistic-reset",
1166 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1167
1168 CommandMgr::instance().registerCommand("statistic-remove",
1169 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1170
1171 CommandMgr::instance().registerCommand("statistic-get-all",
1172 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1173
1174 CommandMgr::instance().registerCommand("statistic-reset-all",
1175 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1176
1177 CommandMgr::instance().registerCommand("statistic-remove-all",
1178 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1179
1180 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1181 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1182
1183 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1184 std::bind(&ControlledDhcpv6Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1185
1186 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1187 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1188
1189 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1190 std::bind(&ControlledDhcpv6Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1191}
1192
1194 setExitValue(exit_value);
1195 getIOService()->stop(); // Stop ASIO transmissions
1196 shutdown(); // Initiate DHCPv6 shutdown procedure.
1197}
1198
1200 try {
1201 MultiThreadingMgr::instance().apply(false, 0, 0);
1204
1205 // The closure captures either a shared pointer (memory leak)
1206 // or a raw pointer (pointing to a deleted object).
1210
1211 timer_mgr_->unregisterTimers();
1212
1213 cleanup();
1214
1215 // Close the command socket (if it exists).
1217
1218 // Deregister any registered commands (please keep in alphabetic order)
1219 CommandMgr::instance().deregisterCommand("build-report");
1220 CommandMgr::instance().deregisterCommand("config-backend-pull");
1222 CommandMgr::instance().deregisterCommand("config-hash-get");
1223 CommandMgr::instance().deregisterCommand("config-reload");
1225 CommandMgr::instance().deregisterCommand("config-test");
1226 CommandMgr::instance().deregisterCommand("config-write");
1227 CommandMgr::instance().deregisterCommand("dhcp-disable");
1228 CommandMgr::instance().deregisterCommand("dhcp-enable");
1229 CommandMgr::instance().deregisterCommand("leases-reclaim");
1230 CommandMgr::instance().deregisterCommand("server-tag-get");
1232 CommandMgr::instance().deregisterCommand("statistic-get");
1233 CommandMgr::instance().deregisterCommand("statistic-get-all");
1234 CommandMgr::instance().deregisterCommand("statistic-remove");
1235 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1236 CommandMgr::instance().deregisterCommand("statistic-reset");
1237 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1238 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1239 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1240 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1241 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1243 CommandMgr::instance().deregisterCommand("version-get");
1244
1245 // Reset DatabaseConnection IO service.
1247 } catch (...) {
1248 // Don't want to throw exceptions from the destructor. The server
1249 // is shutting down anyway.
1250 }
1251
1252 server_ = NULL; // forget this instance. There should be no callback anymore
1253 // at this stage anyway.
1254}
1255
1256void
1257ControlledDhcpv6Srv::reclaimExpiredLeases(const size_t max_leases,
1258 const uint16_t timeout,
1259 const bool remove_lease,
1260 const uint16_t max_unwarned_cycles) {
1261 try {
1262 server_->alloc_engine_->reclaimExpiredLeases6(max_leases, timeout,
1263 remove_lease,
1264 max_unwarned_cycles);
1265 } catch (const std::exception& ex) {
1267 .arg(ex.what());
1268 }
1269 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1271}
1272
1273void
1274ControlledDhcpv6Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1275 server_->alloc_engine_->deleteExpiredReclaimedLeases6(secs);
1276 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1278}
1279
1280bool
1281ControlledDhcpv6Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1282 if (!db_reconnect_ctl) {
1283 // This should never happen
1285 return (false);
1286 }
1287
1288 // Disable service until the connection is recovered.
1289 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1290 db_reconnect_ctl->alterServiceState()) {
1291 network_state_->disableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1292 }
1293
1295 .arg(db_reconnect_ctl->id())
1296 .arg(db_reconnect_ctl->timerName());
1297
1298 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1299 // return false.
1300 if (!db_reconnect_ctl->retriesLeft() ||
1301 !db_reconnect_ctl->retryInterval()) {
1303 .arg(db_reconnect_ctl->retriesLeft())
1304 .arg(db_reconnect_ctl->retryInterval())
1305 .arg(db_reconnect_ctl->id())
1306 .arg(db_reconnect_ctl->timerName());
1307 if (db_reconnect_ctl->exitOnFailure()) {
1308 shutdownServer(EXIT_FAILURE);
1309 }
1310 return (false);
1311 }
1312
1313 return (true);
1314}
1315
1316bool
1317ControlledDhcpv6Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1318 if (!db_reconnect_ctl) {
1319 // This should never happen
1321 return (false);
1322 }
1323
1324 // Enable service after the connection is recovered.
1325 if (db_reconnect_ctl->retriesLeft() != db_reconnect_ctl->maxRetries() &&
1326 db_reconnect_ctl->alterServiceState()) {
1327 network_state_->enableService(NetworkState::DB_CONNECTION + db_reconnect_ctl->id());
1328 }
1329
1331 .arg(db_reconnect_ctl->id())
1332 .arg(db_reconnect_ctl->timerName());
1333
1334 db_reconnect_ctl->resetRetries();
1335
1336 return (true);
1337}
1338
1339bool
1340ControlledDhcpv6Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1341 if (!db_reconnect_ctl) {
1342 // This should never happen
1344 return (false);
1345 }
1346
1348 .arg(db_reconnect_ctl->maxRetries())
1349 .arg(db_reconnect_ctl->id())
1350 .arg(db_reconnect_ctl->timerName());
1351
1352 if (db_reconnect_ctl->exitOnFailure()) {
1353 shutdownServer(EXIT_FAILURE);
1354 }
1355
1356 return (true);
1357}
1358
1359void
1360ControlledDhcpv6Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1361 if (!reconnect_ctl) {
1362 // This should never happen
1364 return;
1365 }
1366
1368 .arg(reconnect_ctl->maxRetries());
1369
1370 if (reconnect_ctl->exitOnFailure()) {
1371 shutdownServer(EXIT_FAILURE);
1372 }
1373}
1374
1375void
1376ControlledDhcpv6Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1377 boost::shared_ptr<unsigned> failure_count) {
1378 // stop thread pool (if running)
1379 MultiThreadingCriticalSection cs;
1380
1381 try {
1382 // Fetch any configuration backend updates since our last fetch.
1383 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1384 CBControlDHCPv6::FetchMode::FETCH_UPDATE);
1385 (*failure_count) = 0;
1386
1387 } catch (const std::exception& ex) {
1389 .arg(ex.what());
1390
1391 // We allow at most 10 consecutive failures after which we stop
1392 // making further attempts to fetch the configuration updates.
1393 // Let's return without re-scheduling the timer.
1394 if (++(*failure_count) > 10) {
1397 return;
1398 }
1399 }
1400
1401 // Reschedule the timer to fetch new updates or re-try if
1402 // the previous attempt resulted in an error.
1403 if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
1404 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
1405 }
1406}
1407
1408} // namespace dhcp
1409} // namespace isc
when the call the UDPServer carries on at the same position As a result
Definition asiodns.dox:16
it forwards queries to a single upstream resolver and passes the answers back to the client It is constructed with the address of the forward server Queries are initiated with the question to ask the forward a buffer into which to write the answer
Definition asiodns.dox:60
CtrlAgentHooks Hooks
@ map
Definition data.h:147
@ integer
Definition data.h:140
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
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.
virtual isc::data::ConstElementPtr processCommand(const isc::data::ConstElementPtr &cmd)
Triggers command processing.
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.
static CommandMgr & instance()
CommandMgr is a singleton class.
void setIOService(const asiolink::IOServicePtr &io_service)
Sets IO service to be used by the command manager.
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
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:28
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition cfgmgr.cc:120
void commit()
Commits the staging configuration.
Definition cfgmgr.cc:92
void clearStagingConfiguration()
Remove staging configuration.
Definition cfgmgr.cc:87
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:115
static void apply(data::ConstElementPtr value)
apply multi threading 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.
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.
static Dhcp6to4Ipc & instance()
Returns pointer to the sole instance of Dhcp6to4Ipc.
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
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
Dhcpv6Srv(uint16_t server_port=DHCP6_SERVER_PORT, uint16_t client_port=0)
Default constructor.
Definition dhcp6_srv.cc:217
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
Definition dhcp6_srv.h:110
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
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 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.
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 boost::shared_ptr< CalloutHandle > createCalloutHandle()
Return callout handle.
static void callCallouts(int index, CalloutHandle &handle)
Calls the callouts for a given hook.
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
static StatsMgr & instance()
Statistics Manager accessor method.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
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 ...
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Parses a standard config/command level answer and returns arguments or text status code.
ConstElementPtr createCommand(const std::string &command)
Creates a standard command message with no argument (of the form { "command": "my_command" }...
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
Creates a standard config/command level answer message.
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
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.
const isc::log::MessageID DHCP6_DYNAMIC_RECONFIGURATION_SUCCESS
const isc::log::MessageID DHCP6_CB_ON_DEMAND_FETCH_UPDATES_FAIL
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_DB_RECONNECT_LOST_CONNECTION
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
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.