Kea 2.6.0
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) {
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.
102 ConstElementPtr result = loadConfigFile(file_name);
103
104 int rcode;
105 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
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
162 result = CommandMgr::instance().processCommand(createCommand("config-set", json));
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;
174 ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
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 string hash = BaseCommandMgr::getHash(config);
264
266 params->set("hash", Element::create(hash));
267 return (createAnswer(CONTROL_RESULT_SUCCESS, params));
268}
269
271ControlledDhcpv6Srv::commandConfigWriteHandler(const string&,
272 ConstElementPtr args) {
273 string filename;
274
275 if (args) {
276 if (args->getType() != Element::map) {
277 return (createAnswer(CONTROL_RESULT_ERROR, "Argument must be a map"));
278 }
279 ConstElementPtr filename_param = args->get("filename");
280 if (filename_param) {
281 if (filename_param->getType() != Element::string) {
283 "passed parameter 'filename' is not a string"));
284 }
285 filename = filename_param->stringValue();
286 }
287 }
288
289 if (filename.empty()) {
290 // filename parameter was not specified, so let's use whatever we remember
291 // from the command-line
292 filename = getConfigFile();
293 }
294
295 if (filename.empty()) {
296 return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
297 "Please specify filename explicitly."));
298 }
299
300 // Ok, it's time to write the file.
301 size_t size = 0;
302 try {
303 ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
304 size = writeConfigFile(filename, cfg);
305 } catch (const isc::Exception& ex) {
306 return (createAnswer(CONTROL_RESULT_ERROR, string("Error during write-config: ")
307 + ex.what()));
308 }
309 if (size == 0) {
310 return (createAnswer(CONTROL_RESULT_ERROR, "Error writing configuration to "
311 + filename));
312 }
313
314 // Ok, it's time to return the successful response.
316 params->set("size", Element::create(static_cast<long long>(size)));
317 params->set("filename", Element::create(filename));
318
319 return (createAnswer(CONTROL_RESULT_SUCCESS, "Configuration written to "
320 + filename + " successful", params));
321}
322
324ControlledDhcpv6Srv::commandConfigSetHandler(const string&,
325 ConstElementPtr args) {
326 const int status_code = CONTROL_RESULT_ERROR;
327 ConstElementPtr dhcp6;
328 string message;
329
330 // Command arguments are expected to be:
331 // { "Dhcp6": { ... } }
332 if (!args) {
333 message = "Missing mandatory 'arguments' parameter.";
334 } else {
335 dhcp6 = args->get("Dhcp6");
336 if (!dhcp6) {
337 message = "Missing mandatory 'Dhcp6' parameter.";
338 } else if (dhcp6->getType() != Element::map) {
339 message = "'Dhcp6' parameter expected to be a map.";
340 }
341 }
342
343 // Check unsupported objects.
344 if (message.empty()) {
345 for (auto const& obj : args->mapValue()) {
346 const string& obj_name = obj.first;
347 if (obj_name != "Dhcp6") {
349 .arg(obj_name);
350 if (message.empty()) {
351 message = "Unsupported '" + obj_name + "' parameter";
352 } else {
353 message += " (and '" + obj_name + "')";
354 }
355 }
356 }
357 if (!message.empty()) {
358 message += ".";
359 }
360 }
361
362 if (!message.empty()) {
363 // Something is amiss with arguments, return a failure response.
364 ConstElementPtr result = isc::config::createAnswer(status_code,
365 message);
366 return (result);
367 }
368
369 // stop thread pool (if running)
371
372 // We are starting the configuration process so we should remove any
373 // staging configuration that has been created during previous
374 // configuration attempts.
376
377 // Parse the logger configuration explicitly into the staging config.
378 // Note this does not alter the current loggers, they remain in
379 // effect until we apply the logging config below. If no logging
380 // is supplied logging will revert to default logging.
381 Daemon::configureLogger(dhcp6, CfgMgr::instance().getStagingCfg());
382
383 // Let's apply the new logging. We do it early, so we'll be able to print
384 // out what exactly is wrong with the new config in case of problems.
385 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
386
387 // Now we configure the server proper.
388 ConstElementPtr result = processConfig(dhcp6);
389
390 // If the configuration parsed successfully, apply the new logger
391 // configuration and the commit the new configuration. We apply
392 // the logging first in case there's a configuration failure.
393 int rcode = 0;
394 isc::config::parseAnswer(rcode, result);
395 if (rcode == CONTROL_RESULT_SUCCESS) {
396 CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
397
398 // Use new configuration.
400 } else if (CfgMgr::instance().getCurrentCfg()->getSequence() != 0) {
401 // Ok, we applied the logging from the upcoming configuration, but
402 // there were problems with the config. As such, we need to back off
403 // and revert to the previous logging configuration. This is not done if
404 // sequence == 0, because that would mean always reverting to stdout by
405 // default, and it is arguably more helpful to have the error in a
406 // potential file or syslog configured in the upcoming configuration.
407 CfgMgr::instance().getCurrentCfg()->applyLoggingCfg();
408
409 // Not initial configuration so someone can believe we reverted
410 // to the previous configuration. It is not the case so be clear
411 // about this.
413 }
414
416 try {
417 // Handle events registered by hooks using external IOService objects.
419 } catch (const std::exception& ex) {
420 std::ostringstream err;
421 err << "Error initializing hooks: "
422 << ex.what();
424 }
425
426 return (result);
427}
428
430ControlledDhcpv6Srv::commandConfigTestHandler(const string&,
431 ConstElementPtr args) {
432 const int status_code = CONTROL_RESULT_ERROR; // 1 indicates an error
433 ConstElementPtr dhcp6;
434 string message;
435
436 // Command arguments are expected to be:
437 // { "Dhcp6": { ... } }
438 if (!args) {
439 message = "Missing mandatory 'arguments' parameter.";
440 } else {
441 dhcp6 = args->get("Dhcp6");
442 if (!dhcp6) {
443 message = "Missing mandatory 'Dhcp6' parameter.";
444 } else if (dhcp6->getType() != Element::map) {
445 message = "'Dhcp6' parameter expected to be a map.";
446 }
447 }
448
449 // Check unsupported objects.
450 if (message.empty()) {
451 for (auto const& obj : args->mapValue()) {
452 const string& obj_name = obj.first;
453 if (obj_name != "Dhcp6") {
455 .arg(obj_name);
456 if (message.empty()) {
457 message = "Unsupported '" + obj_name + "' parameter";
458 } else {
459 message += " (and '" + obj_name + "')";
460 }
461 }
462 }
463 if (!message.empty()) {
464 message += ".";
465 }
466 }
467
468 if (!message.empty()) {
469 // Something is amiss with arguments, return a failure response.
470 ConstElementPtr result = isc::config::createAnswer(status_code,
471 message);
472 return (result);
473 }
474
475 // stop thread pool (if running)
477
478 // We are starting the configuration process so we should remove any
479 // staging configuration that has been created during previous
480 // configuration attempts.
482
483 // Now we check the server proper.
484 return (checkConfig(dhcp6));
485}
486
488ControlledDhcpv6Srv::commandDhcpDisableHandler(const std::string&,
489 ConstElementPtr args) {
490 std::ostringstream message;
491 int64_t max_period = 0;
492 std::string origin;
493
494 // If the args map does not contain 'origin' parameter, the default type
495 // will be used (user command).
496 auto type = NetworkState::USER_COMMAND;
497
498 // Parse arguments to see if the 'max-period' or 'origin' parameters have
499 // been specified.
500 if (args) {
501 // Arguments must be a map.
502 if (args->getType() != Element::map) {
503 message << "arguments for the 'dhcp-disable' command must be a map";
504
505 } else {
506 ConstElementPtr max_period_element = args->get("max-period");
507 // max-period is optional.
508 if (max_period_element) {
509 // It must be an integer, if specified.
510 if (max_period_element->getType() != Element::integer) {
511 message << "'max-period' argument must be a number";
512
513 } else {
514 // It must be positive integer.
515 max_period = max_period_element->intValue();
516 if (max_period <= 0) {
517 message << "'max-period' must be positive integer";
518 }
519 }
520 }
521 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
522 // stable release. However, the 'origin' is kept for backward compatibility
523 // with Kea versions before 2.5.8. It is common to receive both parameters
524 // because HA hook library sends both in case the partner server hasn't been
525 // upgraded to the new version. The 'origin-id' takes precedence over the
526 // 'origin'.
527 ConstElementPtr origin_id_element = args->get("origin-id");
528 ConstElementPtr origin_element = args->get("origin");
529 // The 'origin-id' and 'origin' arguments are optional.
530 if (origin_id_element) {
531 if (origin_id_element->getType() == Element::integer) {
532 type = origin_id_element->intValue();
533 } else {
534 message << "'origin-id' argument must be a number";
535 }
536 } else if (origin_element) {
537 switch (origin_element->getType()) {
538 case Element::string:
539 origin = origin_element->stringValue();
540 if (origin == "ha-partner") {
542 } else if (origin != "user") {
543 if (origin.empty()) {
544 origin = "(empty string)";
545 }
546 message << "invalid value used for 'origin' parameter: "
547 << origin;
548 }
549 break;
550 case Element::integer:
551 type = origin_element->intValue();
552 break;
553 default:
554 // It must be a string or a number, if specified.
555 message << "'origin' argument must be a string or a number";
556 }
557 }
558 }
559 }
560
561 // No error occurred, so let's disable the service.
562 if (message.tellp() == 0) {
563 message << "DHCPv6 service disabled";
564 if (max_period > 0) {
565 message << " for " << max_period << " seconds";
566
567 // The user specified that the DHCP service should resume not
568 // later than in max-period seconds. If the 'dhcp-enable' command
569 // is not sent, the DHCP service will resume automatically.
570 network_state_->delayedEnableService(static_cast<unsigned>(max_period),
571 type);
572 }
573 network_state_->disableService(type);
574
575 // Success.
576 return (config::createAnswer(CONTROL_RESULT_SUCCESS, message.str()));
577 }
578
579 // Failure.
580 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
581}
582
584ControlledDhcpv6Srv::commandDhcpEnableHandler(const std::string&,
585 ConstElementPtr args) {
586 std::ostringstream message;
587 std::string origin;
588
589 // If the args map does not contain 'origin' parameter, the default type
590 // will be used (user command).
591 auto type = NetworkState::USER_COMMAND;
592
593 // Parse arguments to see if the 'origin' parameter has been specified.
594 if (args) {
595 // Arguments must be a map.
596 if (args->getType() != Element::map) {
597 message << "arguments for the 'dhcp-enable' command must be a map";
598
599 } else {
600 // 'origin-id' replaces the older parameter 'origin' since Kea 2.5.8
601 // stable release. However, the 'origin' is kept for backward compatibility
602 // with Kea versions before 2.5.8. It is common to receive both parameters
603 // because HA hook library sends both in case the partner server hasn't been
604 // upgraded to the new version. The 'origin-id' takes precedence over the
605 // 'origin'.
606 ConstElementPtr origin_id_element = args->get("origin-id");
607 ConstElementPtr origin_element = args->get("origin");
608 // The 'origin-id' and 'origin' arguments are optional.
609 if (origin_id_element) {
610 if (origin_id_element->getType() == Element::integer) {
611 type = origin_id_element->intValue();
612 } else {
613 message << "'origin-id' argument must be a number";
614 }
615 } else if (origin_element) {
616 switch (origin_element->getType()) {
617 case Element::string:
618 origin = origin_element->stringValue();
619 if (origin == "ha-partner") {
621 } else if (origin != "user") {
622 if (origin.empty()) {
623 origin = "(empty string)";
624 }
625 message << "invalid value used for 'origin' parameter: "
626 << origin;
627 }
628 break;
629 case Element::integer:
630 type = origin_element->intValue();
631 break;
632 default:
633 // It must be a string or a number, if specified.
634 message << "'origin' argument must be a string or a number";
635 }
636 }
637 }
638 }
639
640 // No error occurred, so let's enable the service.
641 if (message.tellp() == 0) {
642 network_state_->enableService(type);
643
644 // Success.
646 "DHCP service successfully enabled"));
647 }
648
649 // Failure.
650 return (config::createAnswer(CONTROL_RESULT_ERROR, message.str()));
651}
652
654ControlledDhcpv6Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
656 ElementPtr arguments = Element::createMap();
657 arguments->set("extended", extended);
660 arguments);
661 return (answer);
662}
663
665ControlledDhcpv6Srv::commandBuildReportHandler(const string&,
667 ConstElementPtr answer =
669 return (answer);
670}
671
673ControlledDhcpv6Srv::commandLeasesReclaimHandler(const string&,
674 ConstElementPtr args) {
675 int status_code = CONTROL_RESULT_ERROR;
676 string message;
677
678 // args must be { "remove": <bool> }
679 if (!args) {
680 message = "Missing mandatory 'remove' parameter.";
681 } else {
682 ConstElementPtr remove_name = args->get("remove");
683 if (!remove_name) {
684 message = "Missing mandatory 'remove' parameter.";
685 } else if (remove_name->getType() != Element::boolean) {
686 message = "'remove' parameter expected to be a boolean.";
687 } else {
688 bool remove_lease = remove_name->boolValue();
689 server_->alloc_engine_->reclaimExpiredLeases6(0, 0, remove_lease);
690 status_code = 0;
691 message = "Reclamation of expired leases is complete.";
692 }
693 }
694 ConstElementPtr answer = isc::config::createAnswer(status_code, message);
695 return (answer);
696}
697
699ControlledDhcpv6Srv::commandServerTagGetHandler(const std::string&,
701 const std::string& tag =
702 CfgMgr::instance().getCurrentCfg()->getServerTag();
703 ElementPtr response = Element::createMap();
704 response->set("server-tag", Element::create(tag));
705
706 return (createAnswer(CONTROL_RESULT_SUCCESS, response));
707}
708
710ControlledDhcpv6Srv::commandConfigBackendPullHandler(const std::string&,
712 auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
713 if (!ctl_info) {
714 return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
715 }
716
717 // stop thread pool (if running)
719
720 // Reschedule the periodic CB fetch.
721 if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
722 TimerMgr::instance()->cancel("Dhcp6CBFetchTimer");
723 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
724 }
725
726 // Code from cbFetchUpdates.
727 // The configuration to use is the current one because this is called
728 // after the configuration manager commit.
729 try {
730 auto srv_cfg = CfgMgr::instance().getCurrentCfg();
732 server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
733 } catch (const std::exception& ex) {
735 .arg(ex.what());
737 "On demand configuration update failed: " +
738 string(ex.what())));
739 }
741 "On demand configuration update successful."));
742}
743
745ControlledDhcpv6Srv::commandStatusGetHandler(const string&,
746 ConstElementPtr /*args*/) {
748 status->set("pid", Element::create(static_cast<int>(getpid())));
749
750 auto now = boost::posix_time::second_clock::universal_time();
751 // Sanity check: start_ is always initialized.
752 if (!start_.is_not_a_date_time()) {
753 auto uptime = now - start_;
754 status->set("uptime", Element::create(uptime.total_seconds()));
755 }
756
757 auto last_commit = CfgMgr::instance().getCurrentCfg()->getLastCommitTime();
758 if (!last_commit.is_not_a_date_time()) {
759 auto reload = now - last_commit;
760 status->set("reload", Element::create(reload.total_seconds()));
761 }
762
763 auto& mt_mgr = MultiThreadingMgr::instance();
764 if (mt_mgr.getMode()) {
765 status->set("multi-threading-enabled", Element::create(true));
766 status->set("thread-pool-size", Element::create(static_cast<int32_t>(
767 MultiThreadingMgr::instance().getThreadPoolSize())));
768 status->set("packet-queue-size", Element::create(static_cast<int32_t>(
769 MultiThreadingMgr::instance().getPacketQueueSize())));
770 ElementPtr queue_stats = Element::createList();
771 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(10)));
772 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(100)));
773 queue_stats->add(Element::create(mt_mgr.getThreadPool().getQueueStat(1000)));
774 status->set("packet-queue-statistics", queue_stats);
775
776 } else {
777 status->set("multi-threading-enabled", Element::create(false));
778 }
779
780 status->set("extended-info-tables", Element::create(
781 CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->getExtendedInfoTablesEnabled()));
782
783 // Iterate through the interfaces and get all the errors.
784 ElementPtr socket_errors(Element::createList());
785 for (IfacePtr const& interface : IfaceMgr::instance().getIfaces()) {
786 for (std::string const& error : interface->getErrors()) {
787 socket_errors->add(Element::create(error));
788 }
789 }
790
791 // Abstract the information from all sockets into a single status.
793 if (socket_errors->empty()) {
794 sockets->set("status", Element::create("ready"));
795 } else {
796 ReconnectCtlPtr const reconnect_ctl(
797 CfgMgr::instance().getCurrentCfg()->getCfgIface()->getReconnectCtl());
798 if (reconnect_ctl && reconnect_ctl->retriesLeft()) {
799 sockets->set("status", Element::create("retrying"));
800 } else {
801 sockets->set("status", Element::create("failed"));
802 }
803 sockets->set("errors", socket_errors);
804 }
805 status->set("sockets", sockets);
806
807 return (createAnswer(CONTROL_RESULT_SUCCESS, status));
808}
809
811ControlledDhcpv6Srv::commandStatisticSetMaxSampleCountAllHandler(const string&,
812 ConstElementPtr args) {
813 StatsMgr& stats_mgr = StatsMgr::instance();
815 // Update the default parameter.
816 long max_samples = stats_mgr.getMaxSampleCountDefault();
817 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
818 "statistic-default-sample-count", Element::create(max_samples));
819 return (answer);
820}
821
823ControlledDhcpv6Srv::commandStatisticSetMaxSampleAgeAllHandler(const string&,
824 ConstElementPtr args) {
825 StatsMgr& stats_mgr = StatsMgr::instance();
827 // Update the default parameter.
828 auto duration = stats_mgr.getMaxSampleAgeDefault();
829 long max_age = toSeconds(duration);
830 CfgMgr::instance().getCurrentCfg()->addConfiguredGlobal(
831 "statistic-default-sample-age", Element::create(max_age));
832 return (answer);
833}
834
838
839 // Allow DB reconnect on startup. The database connection parameters specify
840 // respective details.
842
843 // Single stream instance used in all error clauses
844 std::ostringstream err;
845
846 if (!srv) {
847 err << "Server object not initialized, can't process config.";
849 }
850
852 .arg(srv->redactConfig(config)->str());
853
854 ConstElementPtr answer = configureDhcp6Server(*srv, config);
855
856 // Check that configuration was successful. If not, do not reopen sockets
857 // and don't bother with DDNS stuff.
858 try {
859 int rcode = 0;
860 isc::config::parseAnswer(rcode, answer);
861 if (rcode != 0) {
862 return (answer);
863 }
864 } catch (const std::exception& ex) {
865 err << "Failed to process configuration:" << ex.what();
867 }
868
869 // Re-open lease and host database with new parameters.
870 try {
872 std::bind(&ControlledDhcpv6Srv::dbLostCallback, srv, ph::_1);
873
875 std::bind(&ControlledDhcpv6Srv::dbRecoveredCallback, srv, ph::_1);
876
878 std::bind(&ControlledDhcpv6Srv::dbFailedCallback, srv, ph::_1);
879
880 CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
881 string params = "universe=6";
882 if (cfg_db->getExtendedInfoTablesEnabled()) {
883 params += " extended-info-tables=true";
884 }
885 cfg_db->setAppendedParameters(params);
886 cfg_db->createManagers();
887 // Reset counters related to connections as all managers have been recreated.
888 srv->getNetworkState()->resetForDbConnection();
889 } catch (const std::exception& ex) {
890 err << "Unable to open database: " << ex.what();
892 }
893
894 // Regenerate server identifier if needed.
895 try {
896 const std::string duid_file =
897 std::string(CfgMgr::instance().getDataDir()) + "/" +
898 std::string(SERVER_DUID_FILE);
899 DuidPtr duid = CfgMgr::instance().getStagingCfg()->getCfgDUID()->create(duid_file);
900 server_->serverid_.reset(new Option(Option::V6, D6O_SERVERID, duid->getDuid()));
901 if (duid) {
903 .arg(duid->toText())
904 .arg(duid_file);
905 }
906
907 } catch (const std::exception& ex) {
908 err << "unable to configure server identifier: " << ex.what();
910 }
911
912 // Server will start DDNS communications if its enabled.
913 try {
914 srv->startD2();
915 } catch (const std::exception& ex) {
916 err << "Error starting DHCP_DDNS client after server reconfiguration: "
917 << ex.what();
919 }
920
921 // Setup DHCPv4-over-DHCPv6 IPC
922 try {
924 } catch (const std::exception& ex) {
925 err << "error starting DHCPv4-over-DHCPv6 IPC "
926 " after server reconfiguration: " << ex.what();
928 }
929
930 // Configure DHCP packet queueing
931 try {
933 qc = CfgMgr::instance().getStagingCfg()->getDHCPQueueControl();
934 if (IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, qc)) {
936 .arg(IfaceMgr::instance().getPacketQueue6()->getInfoStr());
937 }
938
939 } catch (const std::exception& ex) {
940 err << "Error setting packet queue controls after server reconfiguration: "
941 << ex.what();
943 }
944
945 // Configure a callback to shut down the server when the bind socket
946 // attempts exceeded.
948 std::bind(&ControlledDhcpv6Srv::openSocketsFailedCallback, srv, ph::_1);
949
950 // Configuration may change active interfaces. Therefore, we have to reopen
951 // sockets according to new configuration. It is possible that this
952 // operation will fail for some interfaces but the openSockets function
953 // guards against exceptions and invokes a callback function to
954 // log warnings. Since we allow that this fails for some interfaces there
955 // is no need to rollback configuration if socket fails to open on any
956 // of the interfaces.
957 CfgMgr::instance().getStagingCfg()->getCfgIface()->
958 openSockets(AF_INET6, srv->getServerPort());
959
960 // Install the timers for handling leases reclamation.
961 try {
962 CfgMgr::instance().getStagingCfg()->getCfgExpiration()->
963 setupTimers(&ControlledDhcpv6Srv::reclaimExpiredLeases,
964 &ControlledDhcpv6Srv::deleteExpiredReclaimedLeases,
965 server_);
966
967 } catch (const std::exception& ex) {
968 err << "unable to setup timers for periodically running the"
969 " reclamation of the expired leases: "
970 << ex.what() << ".";
972 }
973
974 // Setup config backend polling, if configured for it.
975 auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
976 if (ctl_info) {
977 long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
978 // Only schedule the CB fetch timer if the fetch wait time is greater
979 // than 0.
980 if (fetch_time > 0) {
981 // When we run unit tests, we want to use milliseconds unit for the
982 // specified interval. Otherwise, we use seconds. Note that using
983 // milliseconds as a unit in unit tests prevents us from waiting 1
984 // second on more before the timer goes off. Instead, we wait one
985 // millisecond which significantly reduces the test time.
986 if (!server_->inTestMode()) {
987 fetch_time = 1000 * fetch_time;
988 }
989
990 boost::shared_ptr<unsigned> failure_count(new unsigned(0));
992 registerTimer("Dhcp6CBFetchTimer",
993 std::bind(&ControlledDhcpv6Srv::cbFetchUpdates,
994 server_, CfgMgr::instance().getStagingCfg(),
995 failure_count),
996 fetch_time,
998 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
999 }
1000 }
1001
1002 // Finally, we can commit runtime option definitions in libdhcp++. This is
1003 // exception free.
1005
1006 auto notify_libraries = ControlledDhcpv6Srv::finishConfigHookLibraries(config);
1007 if (notify_libraries) {
1008 return (notify_libraries);
1009 }
1010
1011 // Initialize the allocators. If the user selected a Free Lease Queue Allocator
1012 // for any of the subnets, the server will now populate free leases to the queue.
1013 // It may take a while!
1014 try {
1015 CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->initAllocatorsAfterConfigure();
1016
1017 } catch (const std::exception& ex) {
1018 err << "Error initializing the lease allocators: "
1019 << ex.what();
1021 }
1022
1023 // Apply multi threading settings.
1024 // @note These settings are applied/updated only if no errors occur while
1025 // applying the new configuration.
1026 // @todo This should be fixed.
1027 try {
1028 CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
1029 } catch (const std::exception& ex) {
1030 err << "Error applying multi threading settings: "
1031 << ex.what();
1033 }
1034
1035 return (answer);
1036}
1037
1041 // This hook point notifies hooks libraries that the configuration of the
1042 // DHCPv6 server has completed. It provides the hook library with the pointer
1043 // to the common IO service object, new server configuration in the JSON
1044 // format and with the pointer to the configuration storage where the
1045 // parsed configuration is stored.
1046 if (HooksManager::calloutsPresent(Hooks.hooks_index_dhcp6_srv_configured_)) {
1048
1049 callout_handle->setArgument("io_context", srv->getIOService());
1050 callout_handle->setArgument("network_state", srv->getNetworkState());
1051 callout_handle->setArgument("json_config", config);
1052 callout_handle->setArgument("server_config", CfgMgr::instance().getStagingCfg());
1053
1054 HooksManager::callCallouts(Hooks.hooks_index_dhcp6_srv_configured_,
1055 *callout_handle);
1056
1057 // If next step is DROP, report a configuration error.
1058 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1059 string error;
1060 try {
1061 callout_handle->getArgument("error", error);
1062 } catch (NoSuchArgument const& ex) {
1063 error = "unknown error";
1064 }
1066 }
1067 }
1068
1069 return (ConstElementPtr());
1070}
1071
1075
1076 if (!srv) {
1078 "Server object not initialized, can't process config.");
1079 return (no_srv);
1080 }
1081
1083 .arg(srv->redactConfig(config)->str());
1084
1085 return (configureDhcp6Server(*srv, config, true));
1086}
1087
1088ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port /*= DHCP6_SERVER_PORT*/,
1089 uint16_t client_port /*= 0*/)
1090 : Dhcpv6Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
1091 if (getInstance()) {
1093 "There is another Dhcpv6Srv instance already.");
1094 }
1095 server_ = this; // remember this instance for later use in handlers
1096
1097 // ProcessSpawn uses IO service to handle signal set events.
1099
1100 // TimerMgr uses IO service to run asynchronous timers.
1101 TimerMgr::instance()->setIOService(getIOService());
1102
1103 // CommandMgr uses IO service to run asynchronous socket operations.
1105
1106 // DatabaseConnection uses IO service to run asynchronous timers.
1108
1109 // These are the commands always supported by the DHCPv6 server.
1110 // Please keep the list in alphabetic order.
1111 CommandMgr::instance().registerCommand("build-report",
1112 std::bind(&ControlledDhcpv6Srv::commandBuildReportHandler, this, ph::_1, ph::_2));
1113
1114 CommandMgr::instance().registerCommand("config-backend-pull",
1115 std::bind(&ControlledDhcpv6Srv::commandConfigBackendPullHandler, this, ph::_1, ph::_2));
1116
1118 std::bind(&ControlledDhcpv6Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
1119
1120 CommandMgr::instance().registerCommand("config-hash-get",
1121 std::bind(&ControlledDhcpv6Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
1122
1123 CommandMgr::instance().registerCommand("config-reload",
1124 std::bind(&ControlledDhcpv6Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
1125
1127 std::bind(&ControlledDhcpv6Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
1128
1129 CommandMgr::instance().registerCommand("config-test",
1130 std::bind(&ControlledDhcpv6Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
1131
1132 CommandMgr::instance().registerCommand("config-write",
1133 std::bind(&ControlledDhcpv6Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
1134
1135 CommandMgr::instance().registerCommand("dhcp-enable",
1136 std::bind(&ControlledDhcpv6Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
1137
1138 CommandMgr::instance().registerCommand("dhcp-disable",
1139 std::bind(&ControlledDhcpv6Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
1140
1141 CommandMgr::instance().registerCommand("leases-reclaim",
1142 std::bind(&ControlledDhcpv6Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
1143
1144 CommandMgr::instance().registerCommand("server-tag-get",
1145 std::bind(&ControlledDhcpv6Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
1146
1148 std::bind(&ControlledDhcpv6Srv::commandShutdownHandler, this, ph::_1, ph::_2));
1149
1151 std::bind(&ControlledDhcpv6Srv::commandStatusGetHandler, this, ph::_1, ph::_2));
1152
1153 CommandMgr::instance().registerCommand("version-get",
1154 std::bind(&ControlledDhcpv6Srv::commandVersionGetHandler, this, ph::_1, ph::_2));
1155
1156 // Register statistic related commands
1157 CommandMgr::instance().registerCommand("statistic-get",
1158 std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
1159
1160 CommandMgr::instance().registerCommand("statistic-reset",
1161 std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
1162
1163 CommandMgr::instance().registerCommand("statistic-remove",
1164 std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
1165
1166 CommandMgr::instance().registerCommand("statistic-get-all",
1167 std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
1168
1169 CommandMgr::instance().registerCommand("statistic-reset-all",
1170 std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
1171
1172 CommandMgr::instance().registerCommand("statistic-remove-all",
1173 std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
1174
1175 CommandMgr::instance().registerCommand("statistic-sample-age-set",
1176 std::bind(&StatsMgr::statisticSetMaxSampleAgeHandler, ph::_1, ph::_2));
1177
1178 CommandMgr::instance().registerCommand("statistic-sample-age-set-all",
1179 std::bind(&ControlledDhcpv6Srv::commandStatisticSetMaxSampleAgeAllHandler, this, ph::_1, ph::_2));
1180
1181 CommandMgr::instance().registerCommand("statistic-sample-count-set",
1182 std::bind(&StatsMgr::statisticSetMaxSampleCountHandler, ph::_1, ph::_2));
1183
1184 CommandMgr::instance().registerCommand("statistic-sample-count-set-all",
1185 std::bind(&ControlledDhcpv6Srv::commandStatisticSetMaxSampleCountAllHandler, this, ph::_1, ph::_2));
1186}
1187
1189 setExitValue(exit_value);
1190 getIOService()->stop(); // Stop ASIO transmissions
1191 shutdown(); // Initiate DHCPv6 shutdown procedure.
1192}
1193
1195 try {
1196 MultiThreadingMgr::instance().apply(false, 0, 0);
1199
1200 // The closure captures either a shared pointer (memory leak)
1201 // or a raw pointer (pointing to a deleted object).
1205
1206 timer_mgr_->unregisterTimers();
1207
1208 cleanup();
1209
1210 // Close the command socket (if it exists).
1212
1213 // Deregister any registered commands (please keep in alphabetic order)
1214 CommandMgr::instance().deregisterCommand("build-report");
1215 CommandMgr::instance().deregisterCommand("config-backend-pull");
1217 CommandMgr::instance().deregisterCommand("config-hash-get");
1218 CommandMgr::instance().deregisterCommand("config-reload");
1220 CommandMgr::instance().deregisterCommand("config-test");
1221 CommandMgr::instance().deregisterCommand("config-write");
1222 CommandMgr::instance().deregisterCommand("dhcp-disable");
1223 CommandMgr::instance().deregisterCommand("dhcp-enable");
1224 CommandMgr::instance().deregisterCommand("leases-reclaim");
1225 CommandMgr::instance().deregisterCommand("server-tag-get");
1227 CommandMgr::instance().deregisterCommand("statistic-get");
1228 CommandMgr::instance().deregisterCommand("statistic-get-all");
1229 CommandMgr::instance().deregisterCommand("statistic-remove");
1230 CommandMgr::instance().deregisterCommand("statistic-remove-all");
1231 CommandMgr::instance().deregisterCommand("statistic-reset");
1232 CommandMgr::instance().deregisterCommand("statistic-reset-all");
1233 CommandMgr::instance().deregisterCommand("statistic-sample-age-set");
1234 CommandMgr::instance().deregisterCommand("statistic-sample-age-set-all");
1235 CommandMgr::instance().deregisterCommand("statistic-sample-count-set");
1236 CommandMgr::instance().deregisterCommand("statistic-sample-count-set-all");
1238 CommandMgr::instance().deregisterCommand("version-get");
1239
1240 // Reset DatabaseConnection IO service.
1242 } catch (...) {
1243 // Don't want to throw exceptions from the destructor. The server
1244 // is shutting down anyway.
1245 }
1246
1247 server_ = NULL; // forget this instance. There should be no callback anymore
1248 // at this stage anyway.
1249}
1250
1251void
1252ControlledDhcpv6Srv::reclaimExpiredLeases(const size_t max_leases,
1253 const uint16_t timeout,
1254 const bool remove_lease,
1255 const uint16_t max_unwarned_cycles) {
1256 try {
1257 server_->alloc_engine_->reclaimExpiredLeases6(max_leases, timeout,
1258 remove_lease,
1259 max_unwarned_cycles);
1260 } catch (const std::exception& ex) {
1262 .arg(ex.what());
1263 }
1264 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1266}
1267
1268void
1269ControlledDhcpv6Srv::deleteExpiredReclaimedLeases(const uint32_t secs) {
1270 server_->alloc_engine_->deleteExpiredReclaimedLeases6(secs);
1271 // We're using the ONE_SHOT timer so there is a need to re-schedule it.
1273}
1274
1275bool
1276ControlledDhcpv6Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
1277 if (!db_reconnect_ctl) {
1278 // This should never happen
1280 return (false);
1281 }
1282
1283 // Disable service until the connection is recovered.
1284 if (db_reconnect_ctl->retriesLeft() == db_reconnect_ctl->maxRetries() &&
1285 db_reconnect_ctl->alterServiceState()) {
1287 }
1288
1290
1291 // If reconnect isn't enabled log it, initiate a shutdown if needed and
1292 // return false.
1293 if (!db_reconnect_ctl->retriesLeft() ||
1294 !db_reconnect_ctl->retryInterval()) {
1296 .arg(db_reconnect_ctl->retriesLeft())
1297 .arg(db_reconnect_ctl->retryInterval());
1298 if (db_reconnect_ctl->exitOnFailure()) {
1299 shutdownServer(EXIT_FAILURE);
1300 }
1301 return (false);
1302 }
1303
1304 return (true);
1305}
1306
1307bool
1308ControlledDhcpv6Srv::dbRecoveredCallback(ReconnectCtlPtr db_reconnect_ctl) {
1309 if (!db_reconnect_ctl) {
1310 // This should never happen
1312 return (false);
1313 }
1314
1315 // Enable service after the connection is recovered.
1316 if (db_reconnect_ctl->alterServiceState()) {
1318 }
1319
1321
1322 db_reconnect_ctl->resetRetries();
1323
1324 return (true);
1325}
1326
1327bool
1328ControlledDhcpv6Srv::dbFailedCallback(ReconnectCtlPtr db_reconnect_ctl) {
1329 if (!db_reconnect_ctl) {
1330 // This should never happen
1332 return (false);
1333 }
1334
1336 .arg(db_reconnect_ctl->maxRetries());
1337
1338 if (db_reconnect_ctl->exitOnFailure()) {
1339 shutdownServer(EXIT_FAILURE);
1340 }
1341
1342 return (true);
1343}
1344
1345void
1346ControlledDhcpv6Srv::openSocketsFailedCallback(ReconnectCtlPtr reconnect_ctl) {
1347 if (!reconnect_ctl) {
1348 // This should never happen
1350 return;
1351 }
1352
1354 .arg(reconnect_ctl->maxRetries());
1355
1356 if (reconnect_ctl->exitOnFailure()) {
1357 shutdownServer(EXIT_FAILURE);
1358 }
1359}
1360
1361void
1362ControlledDhcpv6Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
1363 boost::shared_ptr<unsigned> failure_count) {
1364 // stop thread pool (if running)
1366
1367 try {
1368 // Fetch any configuration backend updates since our last fetch.
1369 server_->getCBControl()->databaseConfigFetch(srv_cfg,
1371 (*failure_count) = 0;
1372
1373 } catch (const std::exception& ex) {
1375 .arg(ex.what());
1376
1377 // We allow at most 10 consecutive failures after which we stop
1378 // making further attempts to fetch the configuration updates.
1379 // Let's return without re-scheduling the timer.
1380 if (++(*failure_count) > 10) {
1383 return;
1384 }
1385 }
1386
1387 // Reschedule the timer to fetch new updates or re-try if
1388 // the previous attempt resulted in an error.
1389 if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
1390 TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
1391 }
1392}
1393
1394} // namespace dhcp
1395} // 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.
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.
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
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.
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:4674
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:4640
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.
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 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
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.
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 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()
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:1242
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.